]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/server/src/res.cc
update
[l4.git] / l4 / pkg / io / server / src / res.cc
1 /*
2  * (c) 2010 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/sys/capability>
11 #include <l4/sys/kip>
12 #include <l4/re/env>
13 #include <l4/re/error_helper>
14 #include <l4/re/util/cap_alloc>
15
16 #include <l4/cxx/avl_tree>
17 #include <l4/cxx/bitmap>
18 #include <l4/sys/ipc.h>
19 #include <l4/sigma0/sigma0.h>
20
21 #include <cstdlib>
22 #include <cstdio>
23 #include <cstring>
24
25 #include "debug.h"
26 #include "res.h"
27 #include "cfg.h"
28
29 enum
30 {
31   Page_shift   = L4_PAGESHIFT,
32   Min_rs_bits = 10,
33   Min_rs_mul  = 1UL << Min_rs_bits,
34   Min_rs      = Page_shift + Min_rs_bits,
35 };
36
37
38 struct Phys_region
39 {
40   l4_addr_t phys;
41   l4_addr_t size;
42
43   bool operator < (Phys_region const &o) const throw()
44   { return phys + size - 1 < o.phys; }
45   bool contains(Phys_region const &o) const throw()
46   { return o.phys >= phys && o.phys + o.size -1 <= phys + size -1; }
47 };
48
49 struct Io_region : public Phys_region, public cxx::Avl_tree_node
50 {
51   l4_addr_t virt;
52
53   mutable cxx::Bitmap_base pages;
54
55   Io_region() : pages(0) {}
56 };
57
58 struct Io_region_get_key
59 {
60   typedef Phys_region Key_type;
61   static Phys_region const &key_of(Io_region const *o) { return *o; }
62
63 };
64
65 typedef cxx::Avl_tree<Io_region, Io_region_get_key> Io_set;
66
67 static Io_set io_set;
68
69 static L4::Cap<void> sigma0;
70
71 int res_init()
72 {
73   using L4Re::chkcap;
74   sigma0 = chkcap(L4Re::Env::env()->get_cap<void>("sigma0"), "getting sigma0 cap", 0);
75
76 #if 0
77   L4::Kip::Mem_desc *md = L4::Kip::Mem_desc::first(l4re_kip());
78   L4::Kip::Mem_desc *mde = md + L4::Kip::Mem_desc::count(l4re_kip());
79   for (; md < mde; ++md)
80     {
81       if (md->type() == L4::Kip::Mem_desc::Arch)
82         {
83           printf("ARCH REGION %014lx-%014lx (%02x:%02x)\n",
84                  md->start(), md->end(), md->type(), md->sub_type());
85           res_map_iomem(md->start(), md->size());
86         }
87     }
88 #endif
89   return 0;
90 };
91
92 static long
93 map_iomem_range(l4_addr_t phys, l4_addr_t virt, l4_addr_t size)
94 {
95   unsigned p2sz = L4_PAGESHIFT;
96   long res;
97
98   if ((phys & ~(~0UL << p2sz)) || (virt & ~(~0UL << p2sz))
99       || (size & ~(~0UL << p2sz)))
100     return -L4_ERANGE;
101
102   while (size)
103     {
104 #if 1
105       while (p2sz < 22)
106         {
107           unsigned n = p2sz + 1;
108           if ((phys & ~(~0UL << n)) || ((1UL << n) > size))
109             break;
110           ++p2sz;
111         }
112 #endif
113       l4_msg_regs_t *m = l4_utcb_mr_u(l4_utcb());
114       l4_buf_regs_t *b = l4_utcb_br_u(l4_utcb());
115       l4_msgtag_t tag = l4_msgtag(L4_PROTO_SIGMA0, 2, 0, 0);
116       m->mr[0] = SIGMA0_REQ_FPAGE_IOMEM;
117       m->mr[1] = l4_fpage(phys, p2sz, L4_FPAGE_RWX).raw;
118
119       b->bdr   = 0;
120       b->br[0] = L4_ITEM_MAP;
121       b->br[1] = l4_fpage(virt, p2sz, L4_FPAGE_RWX).raw;
122       tag = l4_ipc_call(sigma0.cap(), l4_utcb(), tag, L4_IPC_NEVER);
123
124       res = l4_error(tag);
125       if (res < 0)
126         return res;
127
128       phys += 1UL << p2sz;
129       virt += 1UL << p2sz;
130       size -= 1UL << p2sz;
131
132       if (!size)
133         break;
134
135       while ((1UL << p2sz) > size)
136         --p2sz;
137     }
138   return 0;
139 }
140
141 l4_addr_t res_map_iomem(l4_addr_t phys, l4_addr_t size)
142 {
143   int p2size = Min_rs;
144   while ((1UL << p2size) < (size + (phys - l4_trunc_size(phys, p2size))))
145     ++p2size;
146
147
148   Io_region *iomem = 0;
149   Phys_region r;
150   r.phys = l4_trunc_page(phys);
151   r.size = l4_round_page(size + phys - r.phys);
152
153   while (1)
154     {
155       Io_region *reg = io_set.find_node(r);
156       if (!reg)
157         {
158           iomem = new Io_region();
159
160           iomem->phys = l4_trunc_size(phys, p2size);
161           iomem->virt = L4_PAGESIZE;
162           iomem->size = 1UL << p2size;
163
164           int res = L4Re::Env::env()->rm()->reserve_area(&iomem->virt,
165               iomem->size, L4Re::Rm::Search_addr, p2size);
166
167           if (res < 0)
168             {
169               delete iomem;
170               return 0;
171             }
172
173           unsigned bytes
174             = cxx::Bitmap_base::bit_buffer_bytes(iomem->size >> Page_shift);
175           iomem->pages = cxx::Bitmap_base(malloc(bytes));
176           memset(iomem->pages.bit_buffer(), 0, bytes);
177
178           io_set.insert(iomem);
179
180           d_printf(DBG_DEBUG, "new iomem region: p=%lx v=%lx s=%lx (bmb=%p)\n",
181                    iomem->phys, iomem->virt, iomem->size,
182                    iomem->pages.bit_buffer());
183           break;
184         }
185       else if (reg->contains(r))
186         {
187           iomem = reg;
188           break;
189         }
190       else
191         {
192           if (reg->pages.bit_buffer())
193             free(reg->pages.bit_buffer());
194
195           io_set.remove(*reg);
196           delete reg;
197         }
198     }
199
200   l4_addr_t p_virt   = iomem->virt + r.phys - l4_trunc_size(phys, p2size);
201   l4_addr_t min = 0, max;
202   bool not_mapped = false;
203   int all_ok = 0;
204
205   for (unsigned i = (r.phys - iomem->phys) >> Page_shift;
206        i <= ((r.size + r.phys - iomem->phys) >> Page_shift);
207        ++i)
208     {
209       if (not_mapped && (i == ((r.size + r.phys - iomem->phys) >> Page_shift)
210           || iomem->pages[i]))
211         {
212           max = i << Page_shift;
213           not_mapped = false;
214
215           int res = map_iomem_range(iomem->phys + min, iomem->virt + min,
216               max - min);
217
218           d_printf(DBG_DEBUG2, "map mem: p=%lx v=%lx s=%lx: %s(%d)\n",
219                    iomem->phys + min,
220                    iomem->virt + min, max - min,
221                    res < 0 ? "failed" : "done", res);
222
223           if (res >= 0)
224             {
225               for (unsigned x = min >> Page_shift; x < i; ++x)
226                 iomem->pages.set_bit(x);
227             }
228           else
229             all_ok = res;
230         }
231       else if (!not_mapped && !iomem->pages[i])
232         {
233           min = i << Page_shift;
234           not_mapped = true;
235         }
236     }
237
238   if (all_ok < 0)
239     return 0;
240
241   l4_addr_t ofs = phys - r.phys;
242   return p_virt + ofs;
243 }
244
245 #if defined(ARCH_amd64) || defined(ARCH_x86)
246
247 #include <l4/util/port_io.h>
248
249 static l4_umword_t iobitmap[0x10000 / L4_MWORD_BITS];
250
251 static l4_umword_t get_iobit(unsigned port)
252 {
253   return iobitmap[port / L4_MWORD_BITS] & (1UL << (port % L4_MWORD_BITS));
254 }
255
256 static void set_iobit(unsigned port)
257 {
258   iobitmap[port / L4_MWORD_BITS] |= (1UL << (port % L4_MWORD_BITS));
259 }
260
261
262 int res_get_ioport(unsigned port, int size)
263 {
264   bool map = false;
265   for (unsigned i = 0; i < (1UL << size); ++i)
266     if (!get_iobit(port + i))
267       {
268         map = true;
269         break;
270       }
271
272   if (!map)
273     return 0;
274
275   int res = l4util_ioport_map(sigma0.cap(), port, size);
276   if (res == 0)
277     {
278       for (unsigned i = 0; i < (1UL << size); ++i)
279         set_iobit(port + i);
280       return 0;
281     }
282
283   return res;
284 }
285
286 #endif
287
288