]> 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 "res.h"
26 #include "cfg.h"
27
28 enum
29 {
30   Page_shift   = L4_PAGESHIFT,
31   Min_rs_bits = 10,
32   Min_rs_mul  = 1UL << Min_rs_bits,
33   Min_rs      = Page_shift + Min_rs_bits,
34 };
35
36
37 struct Phys_region
38 {
39   l4_addr_t phys;
40   l4_addr_t size;
41
42   bool operator < (Phys_region const &o) const throw()
43   { return phys + size - 1 < o.phys; }
44   bool contains(Phys_region const &o) const throw()
45   { return o.phys >= phys && o.phys + o.size -1 <= phys + size -1; }
46 };
47
48 struct Io_region : public Phys_region, public cxx::Avl_tree_node
49 {
50   l4_addr_t virt;
51
52   mutable cxx::Bitmap_base pages;
53
54   Io_region() : pages(0) {}
55 };
56
57 struct Io_region_get_key
58 {
59   typedef Phys_region Key_type;
60   static Phys_region const &key_of(Io_region const *o) { return *o; }
61
62 };
63
64 typedef cxx::Avl_tree<Io_region, Io_region_get_key> Io_set;
65
66 static Io_set io_set;
67
68 static L4::Cap<void> sigma0;
69
70 int res_init()
71 {
72   using L4Re::chkcap;
73   sigma0 = chkcap(L4Re::Env::env()->get_cap<void>("sigma0"), "getting sigma0 cap", 0);
74
75 #if 0
76   L4::Kip::Mem_desc *md = L4::Kip::Mem_desc::first(l4re_kip());
77   L4::Kip::Mem_desc *mde = md + L4::Kip::Mem_desc::count(l4re_kip());
78   for (; md < mde; ++md)
79     {
80       if (md->type() == L4::Kip::Mem_desc::Arch)
81         {
82           printf("ARCH REGION %014lx-%014lx (%02x:%02x)\n",
83                  md->start(), md->end(), md->type(), md->sub_type());
84           res_map_iomem(md->start(), md->size());
85         }
86     }
87 #endif
88   return 0;
89 };
90
91 static long
92 map_iomem_range(l4_addr_t phys, l4_addr_t virt, l4_addr_t size)
93 {
94   unsigned p2sz = L4_PAGESHIFT;
95   long res;
96
97   if ((phys & ~(~0UL << p2sz)) || (virt & ~(~0UL << p2sz))
98       || (size & ~(~0UL << p2sz)))
99     return -L4_ERANGE;
100
101   while (size)
102     {
103 #if 1
104       while (p2sz < 22)
105         {
106           unsigned n = p2sz + 1;
107           if ((phys & ~(~0UL << n)) || ((1UL << n) > size))
108             break;
109           ++p2sz;
110         }
111 #endif
112       l4_msg_regs_t *m = l4_utcb_mr_u(l4_utcb());
113       l4_buf_regs_t *b = l4_utcb_br_u(l4_utcb());
114       l4_msgtag_t tag = l4_msgtag(L4_PROTO_SIGMA0, 2, 0, 0);
115       m->mr[0] = SIGMA0_REQ_FPAGE_IOMEM;
116       m->mr[1] = l4_fpage(phys, p2sz, L4_FPAGE_RWX).raw;
117
118       b->bdr   = 0;
119       b->br[0] = L4_ITEM_MAP;
120       b->br[1] = l4_fpage(virt, p2sz, L4_FPAGE_RWX).raw;
121       tag = l4_ipc_call(sigma0.cap(), l4_utcb(), tag, L4_IPC_NEVER);
122
123       res = l4_error(tag);
124       if (res < 0)
125         return res;
126
127       phys += 1UL << p2sz;
128       virt += 1UL << p2sz;
129       size -= 1UL << p2sz;
130
131       if (!size)
132         break;
133
134       while ((1UL << p2sz) > size)
135         --p2sz;
136     }
137   return 0;
138 }
139
140 l4_addr_t res_map_iomem(l4_addr_t phys, l4_addr_t size)
141 {
142   int p2size = Min_rs;
143   while ((1UL << p2size) < (size + (phys - l4_trunc_size(phys, p2size))))
144     ++p2size;
145
146
147   Io_region *iomem = 0;
148   Phys_region r;
149   r.phys = l4_trunc_page(phys);
150   r.size = l4_round_page(size + phys - r.phys);
151
152   while (1)
153     {
154       Io_region *reg = io_set.find_node(r);
155       if (!reg)
156         {
157           iomem = new Io_region();
158
159           iomem->phys = l4_trunc_size(phys, p2size);
160           iomem->virt = L4_PAGESIZE;
161           iomem->size = 1UL << p2size;
162
163           int res = L4Re::Env::env()->rm()->reserve_area(&iomem->virt,
164               iomem->size, L4Re::Rm::Search_addr, p2size);
165
166           if (res < 0)
167             {
168               delete iomem;
169               return 0;
170             }
171
172           unsigned bytes
173             = cxx::Bitmap_base::bit_buffer_bytes(iomem->size >> Page_shift);
174           iomem->pages = cxx::Bitmap_base(malloc(bytes));
175           memset(iomem->pages.bit_buffer(), 0, bytes);
176
177           io_set.insert(iomem);
178
179           if (Io_config::cfg->verbose())
180             printf("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           if (Io_config::cfg->verbose() > 1)
219             printf("map mem: p=%lx v=%lx s=%lx: %s\n", iomem->phys + min,
220                    iomem->virt + min, max - min,
221                    res < 0 ? "failed" : "done");
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