]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/io_space.cpp
update
[l4.git] / kernel / fiasco / src / kern / io_space.cpp
1 INTERFACE [io]:
2
3 #include "types.h"
4 #include "mem_space.h"
5
6 class Mem_space;
7 class Space;
8
9 /** Wrapper class for io_{map,unmap}.  This class serves as an adapter
10     for map<Generic_io_space> to Mem_space.
11  */
12 template< typename SPACE >
13 class Generic_io_space
14 {
15   friend class Jdb_iomap;
16
17 public:
18   static char const * const name;
19
20   typedef void Reap_list;
21
22   typedef Port_number V_pfn;
23   typedef Port_number V_pfc;
24   typedef Port_number Phys_addr;
25   typedef Order Page_order;
26   typedef L4_fpage::Rights Attr;
27   typedef L4_fpage::Rights Rights;
28
29   enum
30   {
31     Need_insert_tlb_flush = 0,
32     Need_xcpu_tlb_flush = 0,
33     Map_page_size = 1,
34     Page_shift = 0,
35     Map_superpage_shift = 16,
36     Map_superpage_size = 0x10000,
37     Map_max_address = 0x10000,
38     Whole_space = 16,
39     Identity_map = 1,
40   };
41
42   struct Fit_size
43   {
44     Page_order operator () (Page_order o) const
45     {
46       return o >= Order(Map_superpage_shift)
47              ? Order(Map_superpage_shift)
48              : Order(0);
49     }
50   };
51
52   // We'd rather like to use a "using Mem_space::Status" declaration here,
53   // but that wouldn't make the enum values accessible as
54   // Generic_io_space::Insert_ok and so on.
55   enum Status
56   {
57     Insert_ok = 0,              ///< Mapping was added successfully.
58     Insert_warn_exists,         ///< Mapping already existed
59     Insert_warn_attrib_upgrade, ///< Mapping already existed, attribs upgrade
60     Insert_err_nomem,           ///< Couldn't alloc new page table
61     Insert_err_exists           ///< A mapping already exists at the target addr
62   };
63
64   static V_pfn map_max_address()
65   { return V_pfn(Map_max_address); }
66
67   static Phys_addr page_address(Phys_addr o, Page_order s)
68   { return cxx::mask_lsb(o, s); }
69
70   static Phys_addr subpage_address(Phys_addr addr, V_pfc offset)
71   { return addr | offset; }
72
73   static V_pfn subpage_offset(V_pfn addr, Page_order size)
74   { return cxx::get_lsb(addr, size); }
75
76   static Mdb_types::Pfn to_pfn(V_pfn p)
77   { return Mdb_types::Pfn(cxx::int_value<V_pfn>(p)); }
78
79   static V_pfn to_virt(Mdb_types::Pfn p)
80   { return V_pfn(cxx::int_value<Mdb_types::Pfn>(p)); }
81
82   static Mdb_types::Pcnt to_pcnt(Page_order s)
83   { return Mdb_types::Pcnt(cxx::int_value<V_pfc>(V_pfc(1) << s)); }
84
85   static Page_order to_order(Mdb_types::Order p)
86   { return Page_order(cxx::int_value<Mdb_types::Order>(p) + Config::PAGE_SHIFT); }
87
88   static V_pfc to_size(Page_order p)
89   { return V_pfc(1) << p; }
90
91
92   FIASCO_SPACE_VIRTUAL
93   Status v_insert(Phys_addr phys, V_pfn virt, Order size, Attr page_attribs);
94
95   FIASCO_SPACE_VIRTUAL
96   bool v_lookup(V_pfn virt, Phys_addr *phys = 0, Page_order *order = 0,
97                 Attr *attribs = 0);
98   virtual
99   bool v_fabricate(V_pfn address, Phys_addr *phys, Page_order *order,
100                    Attr *attribs = 0);
101   FIASCO_SPACE_VIRTUAL
102   Rights v_delete(V_pfn virt, Order size, Rights page_attribs);
103
104 private:
105   // DATA
106   Mword _io_counter;
107
108   Mem_space const *mem_space() const
109   { return static_cast<SPACE const *>(this); }
110
111   Mem_space *mem_space()
112   { return static_cast<SPACE *>(this); }
113 };
114
115 template< typename SPACE>
116 char const * const Generic_io_space<SPACE>::name = "Io_space";
117
118
119 //----------------------------------------------------------------------------
120 IMPLEMENTATION [io]:
121
122 #include <cassert>
123 #include <cstring>
124
125 #include "atomic.h"
126 #include "config.h"
127 #include "l4_types.h"
128 #include "kmem_alloc.h"
129 #include "panic.h"
130 #include "paging.h"
131
132
133 PUBLIC template< typename SPACE > inline
134 typename Generic_io_space<SPACE>::Fit_size
135 Generic_io_space<SPACE>::fitting_sizes() const
136 {
137   return Fit_size();
138 }
139
140 PUBLIC template< typename SPACE >
141 static inline
142 bool
143 Generic_io_space<SPACE>::is_full_flush(L4_fpage::Rights rights)
144 {
145   return rights;
146 }
147
148 PUBLIC template< typename SPACE >
149 inline
150 Generic_io_space<SPACE>::Generic_io_space()
151   : _io_counter(0)
152 {}
153
154
155 PUBLIC template< typename SPACE >
156 Generic_io_space<SPACE>::~Generic_io_space()
157 {
158   if (!mem_space()->dir())
159     return;
160
161   auto iopte = mem_space()->dir()->walk(Virt_addr(Mem_layout::Io_bitmap));
162
163   // do we have an IO bitmap?
164   if (iopte.is_valid())
165     {
166       // sanity check
167       assert (iopte.level != Pdir::Super_level);
168
169       Kmem_alloc::allocator()->q_free_phys(ram_quota(), Config::PAGE_SHIFT,
170                                            iopte.page_addr());
171
172       // switch to next page-table entry
173       ++iopte;
174
175       if (iopte.is_valid())
176         Kmem_alloc::allocator()->q_free_phys(ram_quota(), Config::PAGE_SHIFT,
177                                              iopte.page_addr());
178
179       auto iopde = mem_space()->dir()->walk(Virt_addr(Mem_layout::Io_bitmap),
180                                             Pdir::Super_level);
181
182       // free the page table
183       Kmem_alloc::allocator()->q_free_phys(ram_quota(), Config::PAGE_SHIFT,
184                                            iopde.next_level());
185
186       // free reference
187       *iopde.pte = 0;
188     }
189 }
190
191 PUBLIC template< typename SPACE >
192 inline
193 Ram_quota *
194 Generic_io_space<SPACE>::ram_quota() const
195 { return static_cast<SPACE const *>(this)->ram_quota(); }
196
197 PRIVATE template< typename SPACE >
198 inline
199 bool
200 Generic_io_space<SPACE>::is_superpage()
201 { return _io_counter & 0x10000000; }
202
203
204 //
205 // Utilities for map<Generic_io_space> and unmap<Generic_io_space>
206 //
207
208 IMPLEMENT template< typename SPACE >
209 bool
210 Generic_io_space<SPACE>::v_fabricate(V_pfn address, Phys_addr *phys,
211                                      Page_order *order, Attr *attribs)
212 {
213   return this->v_lookup(address, phys, order, attribs);
214 }
215
216 IMPLEMENT template< typename SPACE >
217 inline NEEDS[Generic_io_space::is_superpage]
218 bool FIASCO_FLATTEN
219 Generic_io_space<SPACE>::v_lookup(V_pfn virt, Phys_addr *phys,
220                                   Page_order *order, Attr *attribs)
221 {
222   if (is_superpage())
223     {
224       if (order) *order = Order(Map_superpage_shift);
225       if (phys) *phys = Phys_addr(0);
226       if (attribs) *attribs = Attr::URW();
227       return true;
228     }
229
230   if (order) *order = Order(0);
231
232   if (io_lookup(cxx::int_value<V_pfn>(virt)))
233     {
234       if (phys) *phys = virt;
235       if (attribs) *attribs = Attr::URW();
236       return true;
237     }
238
239   if (get_io_counter() == 0)
240     {
241       if (order) *order = Order(Map_superpage_shift);
242       if (phys) *phys = Phys_addr(0);
243     }
244
245   return false;
246 }
247
248 IMPLEMENT template< typename SPACE >
249 inline NEEDS [Generic_io_space::is_superpage]
250 L4_fpage::Rights FIASCO_FLATTEN
251 Generic_io_space<SPACE>::v_delete(V_pfn virt, Order size, Rights page_attribs)
252 {
253   if (!(page_attribs & L4_fpage::Rights::FULL()))
254     return L4_fpage::Rights(0);
255
256   if (is_superpage())
257     {
258       assert (size == Order(Map_superpage_shift));
259
260       for (unsigned p = 0; p < Map_max_address; ++p)
261         io_delete(p);
262
263       _io_counter = 0;
264       return L4_fpage::Rights(0);
265     }
266
267   (void)size;
268   assert (size == Order(0));
269
270   io_delete(cxx::int_value<V_pfn>(virt));
271   return L4_fpage::Rights(0);
272 }
273
274 IMPLEMENT template< typename SPACE >
275 inline
276 typename Generic_io_space<SPACE>::Status FIASCO_FLATTEN
277 Generic_io_space<SPACE>::v_insert(Phys_addr phys, V_pfn virt, Order size,
278                                   Attr page_attribs)
279 {
280   (void)phys;
281   (void)page_attribs;
282
283   assert (phys == virt);
284   if (is_superpage() && size == Order(Map_superpage_shift))
285     return Insert_warn_exists;
286
287   if (get_io_counter() == 0 && size == Order(Map_superpage_shift))
288     {
289       for (unsigned p = 0; p < Map_max_address; ++p)
290         io_insert(p);
291       _io_counter |= 0x10000000;
292
293       return Insert_ok;
294     }
295
296   assert (size == Order(0));
297
298   return typename Generic_io_space::Status(io_insert(cxx::int_value<V_pfn>(virt)));
299 }
300
301
302 PUBLIC template< typename SPACE >
303 inline static
304 void
305 Generic_io_space<SPACE>::tlb_flush()
306 {}
307
308 PUBLIC template< typename SPACE >
309 inline static
310 void
311 Generic_io_space<SPACE>::tlb_flush_spaces(bool, Generic_io_space<SPACE> *,
312                                           Generic_io_space<SPACE> *)
313 {}
314
315 PUBLIC template< typename SPACE >
316 inline static
317 bool
318 Generic_io_space<SPACE>::need_tlb_flush()
319 { return false; }
320
321 //
322 // IO lookup / insert / delete / counting
323 //
324
325 /** return the IO counter.
326  *  @return number of IO ports mapped / 0 if not mapped
327  */
328 PUBLIC template< typename SPACE >
329 inline NEEDS["paging.h"]
330 Mword
331 Generic_io_space<SPACE>::get_io_counter() const
332 {
333   return _io_counter & ~0x10000000;
334 }
335
336
337 /** Add something the the IO counter.
338     @param incr number to add
339     @pre 2nd level page table for IO bitmap is present
340 */
341 template< typename SPACE >
342 inline NEEDS["paging.h"]
343 void
344 Generic_io_space<SPACE>::addto_io_counter(int incr)
345 {
346   atomic_add (&_io_counter, incr);
347 }
348
349
350 /** Lookup one IO port in the IO space.
351     @param port_number port address to lookup;
352     @return true if mapped
353      false if not
354  */
355 PROTECTED template< typename SPACE > inline
356 bool
357 Generic_io_space<SPACE>::io_lookup(Address port_number)
358 {
359   assert(port_number < Mem_layout::Io_port_max);
360
361   // be careful, do not cause page faults here
362   // there might be nothing mapped in the IO bitmap
363
364   Address port_addr = get_phys_port_addr(port_number);
365
366   if(port_addr == ~0UL)
367     return false;               // no bitmap -> no ports
368
369   // so there is memory mapped in the IO bitmap
370   char *port = static_cast<char *>(Kmem::phys_to_virt(port_addr));
371
372   // bit == 1 disables the port
373   // bit == 0 enables the port
374   return !(*port & get_port_bit(port_number));
375 }
376
377
378 /** Enable one IO port in the IO space.
379     This function is called in the context of the IPC sender!
380     @param port_number address of the port
381     @return Insert_warn_exists if some ports were mapped in that IO page
382        Insert_err_nomem if memory allocation failed
383        Insert_ok if otherwise insertion succeeded
384  */
385 PROTECTED template< typename SPACE > inline
386 typename Generic_io_space<SPACE>::Status
387 Generic_io_space<SPACE>::io_insert(Address port_number)
388 {
389   assert(port_number < Mem_layout::Io_port_max);
390
391   Address port_virt = Mem_layout::Io_bitmap + (port_number >> 3);
392   Address port_phys = mem_space()->virt_to_phys(port_virt);
393
394   if (port_phys == ~0UL)
395     {
396       // nothing mapped! Get a page and map it in the IO bitmap
397       void *page;
398       if (!(page = Kmem_alloc::allocator()->q_alloc(ram_quota(),
399                                                     Config::PAGE_SHIFT)))
400         return Insert_err_nomem;
401
402       // clear all IO ports
403       // bit == 1 disables the port
404       // bit == 0 enables the port
405       memset(page, 0xff, Config::PAGE_SIZE);
406
407       Mem_space::Status status =
408         mem_space()->v_insert(
409             Mem_space::Phys_addr(Mem_layout::pmem_to_phys(page)),
410             Virt_addr(port_virt & Config::PAGE_MASK),
411             Mem_space::Page_order(Config::PAGE_SHIFT),
412             Mem_space::Attr(L4_fpage::Rights::RW()));
413
414       if (status == Mem_space::Insert_err_nomem)
415         {
416           Kmem_alloc::allocator()->free(Config::PAGE_SHIFT, page);
417           ram_quota()->free(Config::PAGE_SIZE);
418           return Insert_err_nomem;
419         }
420
421       // we've been careful, so insertion should have succeeded
422       assert(status == Mem_space::Insert_ok);
423
424       port_phys = mem_space()->virt_to_phys(port_virt);
425       assert(port_phys != ~0UL);
426     }
427
428   // so there is memory mapped in the IO bitmap -- write the bits now
429   Unsigned8 *port = static_cast<Unsigned8 *> (Kmem::phys_to_virt(port_phys));
430
431   if (*port & get_port_bit(port_number)) // port disabled?
432     {
433       *port &= ~get_port_bit(port_number);
434       addto_io_counter(1);
435       return Insert_ok;
436     }
437
438   // already enabled
439   return Insert_warn_exists;
440 }
441
442
443 /** Disable one IO port in the IO space.
444     @param port_number port to disable
445  */
446 PROTECTED template< typename SPACE > inline
447 void
448 Generic_io_space<SPACE>::io_delete(Address port_number)
449 {
450   assert(port_number < Mem_layout::Io_port_max);
451
452   // be careful, do not cause page faults here
453   // there might be nothing mapped in the IO bitmap
454
455   Address port_addr = get_phys_port_addr(port_number);
456
457   if (port_addr == ~0UL)
458     // nothing mapped -> nothing to delete
459     return;
460
461   // so there is memory mapped in the IO bitmap -> disable the ports
462   char *port = static_cast<char *>(Kmem::phys_to_virt(port_addr));
463
464   // bit == 1 disables the port
465   // bit == 0 enables the port
466   if(!(*port & get_port_bit(port_number)))    // port enabled ??
467     {
468       *port |= get_port_bit(port_number);
469       addto_io_counter(-1);
470     }
471 }
472
473 template< typename SPACE >
474 INLINE NEEDS["config.h"]
475 Address
476 Generic_io_space<SPACE>::get_phys_port_addr(Address const port_number) const
477 {
478   return mem_space()->virt_to_phys(Mem_layout::Io_bitmap + (port_number >> 3));
479 }
480
481 template< typename SPACE >
482 INLINE
483 Unsigned8
484 Generic_io_space<SPACE>::get_port_bit(Address const port_number) const
485 {
486   return 1 << (port_number & 7);
487 }
488
489
490 PUBLIC template< typename SPACE >
491 inline static
492 typename Generic_io_space<SPACE>::V_pfn
493 Generic_io_space<SPACE>::canonize(V_pfn v)
494 { return v; }