9 /** Wrapper class for io_{map,unmap}. This class serves as an adapter
10 for map<Generic_io_space> to Mem_space.
12 template< typename SPACE >
13 class Generic_io_space
15 friend class Jdb_iomap;
18 static char const * const name;
20 typedef void Reap_list;
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;
31 Need_insert_tlb_flush = 0,
32 Need_xcpu_tlb_flush = 0,
35 Map_superpage_shift = 16,
36 Map_superpage_size = 0x10000,
37 Map_max_address = 0x10000,
44 Page_order operator () (Page_order o) const
46 return o >= Order(Map_superpage_shift)
47 ? Order(Map_superpage_shift)
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.
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
64 static V_pfn map_max_address()
65 { return V_pfn(Map_max_address); }
67 static Phys_addr page_address(Phys_addr o, Page_order s)
68 { return cxx::mask_lsb(o, s); }
70 static Phys_addr subpage_address(Phys_addr addr, V_pfc offset)
71 { return addr | offset; }
73 static V_pfn subpage_offset(V_pfn addr, Page_order size)
74 { return cxx::get_lsb(addr, size); }
76 static Mdb_types::Pfn to_pfn(V_pfn p)
77 { return Mdb_types::Pfn(cxx::int_value<V_pfn>(p)); }
79 static V_pfn to_virt(Mdb_types::Pfn p)
80 { return V_pfn(cxx::int_value<Mdb_types::Pfn>(p)); }
82 static Mdb_types::Pcnt to_pcnt(Page_order s)
83 { return Mdb_types::Pcnt(cxx::int_value<V_pfc>(V_pfc(1) << s)); }
85 static Page_order to_order(Mdb_types::Order p)
86 { return Page_order(cxx::int_value<Mdb_types::Order>(p) + Config::PAGE_SHIFT); }
88 static V_pfc to_size(Page_order p)
89 { return V_pfc(1) << p; }
93 Status v_insert(Phys_addr phys, V_pfn virt, Order size, Attr page_attribs);
96 bool v_lookup(V_pfn virt, Phys_addr *phys = 0, Page_order *order = 0,
99 bool v_fabricate(V_pfn address, Phys_addr *phys, Page_order *order,
102 Rights v_delete(V_pfn virt, Order size, Rights page_attribs);
108 Mem_space const *mem_space() const
109 { return static_cast<SPACE const *>(this); }
111 Mem_space *mem_space()
112 { return static_cast<SPACE *>(this); }
115 template< typename SPACE>
116 char const * const Generic_io_space<SPACE>::name = "Io_space";
119 //----------------------------------------------------------------------------
127 #include "l4_types.h"
128 #include "kmem_alloc.h"
133 PUBLIC template< typename SPACE > inline
134 typename Generic_io_space<SPACE>::Fit_size
135 Generic_io_space<SPACE>::fitting_sizes() const
140 PUBLIC template< typename SPACE >
143 Generic_io_space<SPACE>::is_full_flush(L4_fpage::Rights rights)
148 PUBLIC template< typename SPACE >
150 Generic_io_space<SPACE>::Generic_io_space()
155 PUBLIC template< typename SPACE >
156 Generic_io_space<SPACE>::~Generic_io_space()
158 if (!mem_space()->dir())
161 auto iopte = mem_space()->dir()->walk(Virt_addr(Mem_layout::Io_bitmap));
163 // do we have an IO bitmap?
164 if (iopte.is_valid())
167 assert (iopte.level != Pdir::Super_level);
169 Kmem_alloc::allocator()->q_free_phys(ram_quota(), Config::PAGE_SHIFT,
172 // switch to next page-table entry
175 if (iopte.is_valid())
176 Kmem_alloc::allocator()->q_free_phys(ram_quota(), Config::PAGE_SHIFT,
179 auto iopde = mem_space()->dir()->walk(Virt_addr(Mem_layout::Io_bitmap),
182 // free the page table
183 Kmem_alloc::allocator()->q_free_phys(ram_quota(), Config::PAGE_SHIFT,
191 PUBLIC template< typename SPACE >
194 Generic_io_space<SPACE>::ram_quota() const
195 { return static_cast<SPACE const *>(this)->ram_quota(); }
197 PRIVATE template< typename SPACE >
200 Generic_io_space<SPACE>::is_superpage()
201 { return _io_counter & 0x10000000; }
205 // Utilities for map<Generic_io_space> and unmap<Generic_io_space>
208 IMPLEMENT template< typename SPACE >
210 Generic_io_space<SPACE>::v_fabricate(V_pfn address, Phys_addr *phys,
211 Page_order *order, Attr *attribs)
213 return this->v_lookup(address, phys, order, attribs);
216 IMPLEMENT template< typename SPACE >
217 inline NEEDS[Generic_io_space::is_superpage]
219 Generic_io_space<SPACE>::v_lookup(V_pfn virt, Phys_addr *phys,
220 Page_order *order, Attr *attribs)
224 if (order) *order = Order(Map_superpage_shift);
225 if (phys) *phys = Phys_addr(0);
226 if (attribs) *attribs = Attr::URW();
230 if (order) *order = Order(0);
232 if (io_lookup(cxx::int_value<V_pfn>(virt)))
234 if (phys) *phys = virt;
235 if (attribs) *attribs = Attr::URW();
239 if (get_io_counter() == 0)
241 if (order) *order = Order(Map_superpage_shift);
242 if (phys) *phys = Phys_addr(0);
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)
253 if (!(page_attribs & L4_fpage::Rights::FULL()))
254 return L4_fpage::Rights(0);
258 assert (size == Order(Map_superpage_shift));
260 for (unsigned p = 0; p < Map_max_address; ++p)
264 return L4_fpage::Rights(0);
268 assert (size == Order(0));
270 io_delete(cxx::int_value<V_pfn>(virt));
271 return L4_fpage::Rights(0);
274 IMPLEMENT template< typename SPACE >
276 typename Generic_io_space<SPACE>::Status FIASCO_FLATTEN
277 Generic_io_space<SPACE>::v_insert(Phys_addr phys, V_pfn virt, Order size,
283 assert (phys == virt);
284 if (is_superpage() && size == Order(Map_superpage_shift))
285 return Insert_warn_exists;
287 if (get_io_counter() == 0 && size == Order(Map_superpage_shift))
289 for (unsigned p = 0; p < Map_max_address; ++p)
291 _io_counter |= 0x10000000;
296 assert (size == Order(0));
298 return typename Generic_io_space::Status(io_insert(cxx::int_value<V_pfn>(virt)));
302 PUBLIC template< typename SPACE >
305 Generic_io_space<SPACE>::tlb_flush()
308 PUBLIC template< typename SPACE >
311 Generic_io_space<SPACE>::tlb_flush_spaces(bool, Generic_io_space<SPACE> *,
312 Generic_io_space<SPACE> *)
315 PUBLIC template< typename SPACE >
318 Generic_io_space<SPACE>::need_tlb_flush()
322 // IO lookup / insert / delete / counting
325 /** return the IO counter.
326 * @return number of IO ports mapped / 0 if not mapped
328 PUBLIC template< typename SPACE >
329 inline NEEDS["paging.h"]
331 Generic_io_space<SPACE>::get_io_counter() const
333 return _io_counter & ~0x10000000;
337 /** Add something the the IO counter.
338 @param incr number to add
339 @pre 2nd level page table for IO bitmap is present
341 template< typename SPACE >
342 inline NEEDS["paging.h"]
344 Generic_io_space<SPACE>::addto_io_counter(int incr)
346 atomic_add (&_io_counter, incr);
350 /** Lookup one IO port in the IO space.
351 @param port_number port address to lookup;
352 @return true if mapped
355 PROTECTED template< typename SPACE > inline
357 Generic_io_space<SPACE>::io_lookup(Address port_number)
359 assert(port_number < Mem_layout::Io_port_max);
361 // be careful, do not cause page faults here
362 // there might be nothing mapped in the IO bitmap
364 Address port_addr = get_phys_port_addr(port_number);
366 if(port_addr == ~0UL)
367 return false; // no bitmap -> no ports
369 // so there is memory mapped in the IO bitmap
370 char *port = static_cast<char *>(Kmem::phys_to_virt(port_addr));
372 // bit == 1 disables the port
373 // bit == 0 enables the port
374 return !(*port & get_port_bit(port_number));
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
385 PROTECTED template< typename SPACE > inline
386 typename Generic_io_space<SPACE>::Status
387 Generic_io_space<SPACE>::io_insert(Address port_number)
389 assert(port_number < Mem_layout::Io_port_max);
391 Address port_virt = Mem_layout::Io_bitmap + (port_number >> 3);
392 Address port_phys = mem_space()->virt_to_phys(port_virt);
394 if (port_phys == ~0UL)
396 // nothing mapped! Get a page and map it in the IO bitmap
398 if (!(page = Kmem_alloc::allocator()->q_alloc(ram_quota(),
399 Config::PAGE_SHIFT)))
400 return Insert_err_nomem;
402 // clear all IO ports
403 // bit == 1 disables the port
404 // bit == 0 enables the port
405 memset(page, 0xff, Config::PAGE_SIZE);
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()));
414 if (status == Mem_space::Insert_err_nomem)
416 Kmem_alloc::allocator()->free(Config::PAGE_SHIFT, page);
417 ram_quota()->free(Config::PAGE_SIZE);
418 return Insert_err_nomem;
421 // we've been careful, so insertion should have succeeded
422 assert(status == Mem_space::Insert_ok);
424 port_phys = mem_space()->virt_to_phys(port_virt);
425 assert(port_phys != ~0UL);
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));
431 if (*port & get_port_bit(port_number)) // port disabled?
433 *port &= ~get_port_bit(port_number);
439 return Insert_warn_exists;
443 /** Disable one IO port in the IO space.
444 @param port_number port to disable
446 PROTECTED template< typename SPACE > inline
448 Generic_io_space<SPACE>::io_delete(Address port_number)
450 assert(port_number < Mem_layout::Io_port_max);
452 // be careful, do not cause page faults here
453 // there might be nothing mapped in the IO bitmap
455 Address port_addr = get_phys_port_addr(port_number);
457 if (port_addr == ~0UL)
458 // nothing mapped -> nothing to delete
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));
464 // bit == 1 disables the port
465 // bit == 0 enables the port
466 if(!(*port & get_port_bit(port_number))) // port enabled ??
468 *port |= get_port_bit(port_number);
469 addto_io_counter(-1);
473 template< typename SPACE >
474 INLINE NEEDS["config.h"]
476 Generic_io_space<SPACE>::get_phys_port_addr(Address const port_number) const
478 return mem_space()->virt_to_phys(Mem_layout::Io_bitmap + (port_number >> 3));
481 template< typename SPACE >
484 Generic_io_space<SPACE>::get_port_bit(Address const port_number) const
486 return 1 << (port_number & 7);
490 PUBLIC template< typename SPACE >
492 typename Generic_io_space<SPACE>::V_pfn
493 Generic_io_space<SPACE>::canonize(V_pfn v)