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