1 /*
2  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *               Alexander Warg <warg@os.inf.tu-dresden.de>
4  *     economic rights: Technische Universität Dresden (Germany)
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  */
10 #include <l4/cxx/minmax>
11 
12 #include "dataspace_cont.h"
13 #include "pages.h"
14 
Dataspace_cont(void * start,unsigned long size,Flags flags,unsigned char page_shift)15 Moe::Dataspace_cont::Dataspace_cont(void *start, unsigned long size,
16                                     Flags flags,
17                                     unsigned char page_shift)
18 : Dataspace(size, flags, page_shift), _start((char*)start)
19 {
20   if (!can_cow())
21     return;
22 
23   char *end = _start + l4_round_page(this->size());
24   for (char *x = (char *)l4_trunc_page((l4_addr_t)_start); x < end;
25        x += L4_PAGESIZE)
26     Moe::Pages::share(x);
27 }
28 
29 
30 Moe::Dataspace::Address
address(l4_addr_t offset,Flags flags,l4_addr_t hot_spot,l4_addr_t min,l4_addr_t max) const31 Moe::Dataspace_cont::address(l4_addr_t offset,
32                              Flags flags, l4_addr_t hot_spot,
33                              l4_addr_t min, l4_addr_t max) const
34 {
35   if (!check_limit(offset))
36     return Address(-L4_ERANGE);
37 
38   min = l4_trunc_page(min);
39   //max = l4_round_page(max);
40 
41   l4_addr_t adr = l4_addr_t(_start) + offset;
42   unsigned char order = L4_PAGESHIFT;
43 
44   while (order < 30 /* limit to 1GB flexpage */)
45     {
46       l4_addr_t map_base = l4_trunc_size(adr, order + 1);
47       if (map_base < l4_addr_t(_start))
48         break;
49 
50       if (map_base + (1UL << (order + 1)) -1 > (l4_addr_t(_start) + round_size() - 1))
51         break;
52 
53       map_base = l4_trunc_size(hot_spot, order + 1);
54       if (map_base < min)
55         break;
56 
57       if (map_base + (1UL << (order + 1)) -1 > max)
58         break;
59 
60       l4_addr_t mask = ~(~0UL << (order + 1));
61       if (hot_spot == ~0UL || ((adr ^ hot_spot) & mask))
62         break;
63 
64       ++order;
65     }
66 
67   l4_addr_t map_base = l4_trunc_size(adr, order);
68   l4_addr_t offs = adr & ~(~0UL << order);
69 
70   return Address(map_base, order, flags & map_flags(), offs);
71 }
72 
73 int
copy_address(l4_addr_t offset,Flags,l4_addr_t * addr,unsigned long * size) const74 Moe::Dataspace_cont::copy_address(l4_addr_t offset, Flags, l4_addr_t *addr,
75                                   unsigned long *size) const
76 {
77   if (!check_limit(offset))
78     return -L4_ERANGE;
79 
80   *addr = l4_addr_t(_start) + offset;
81   *size = this->size() - offset;
82   return 0;
83 }
84 
unmap() const85 void Moe::Dataspace_cont::unmap() const throw()
86 {
87   unsigned long size = round_size();
88   l4_addr_t offs = 0;
89 
90   while (size)
91     {
92       Address addr = address(offs, L4Re::Dataspace::F::RWX, ~0);
93       l4_task_unmap(L4_BASE_TASK_CAP, addr.fp(), L4_FP_OTHER_SPACES);
94       size -= (1UL << l4_fpage_size(addr.fp()));
95       offs  += (1UL << l4_fpage_size(addr.fp()));
96     }
97 }
98 
99 int
dma_map(Dma_space * dma,l4_addr_t offset,l4_size_t * size,Dma_attribs dma_attr,Dma_space::Direction dir,Dma_space::Dma_addr * dma_addr)100 Moe::Dataspace_cont::dma_map(Dma_space *dma, l4_addr_t offset, l4_size_t *size,
101                              Dma_attribs dma_attr, Dma_space::Direction dir,
102                              Dma_space::Dma_addr *dma_addr)
103 {
104   (void)dma;
105   (void)dma_attr;
106   (void)dir;
107 
108   if (offset >= this->size())
109     return -L4_ERANGE;
110 
111   *dma_addr = (l4_addr_t)start() + offset;
112   *size = cxx::min(*size, (l4_size_t)(this->size() - offset));
113   return 0;
114 }
115