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 Page_number Addr;
21 typedef Page_count Size;
22 typedef Page_number Phys_addr;
23 typedef void Reap_list;
25 void *operator new (size_t, void *p)
28 void operator delete(void *)
32 Need_insert_tlb_flush = 0,
33 Need_xcpu_tlb_flush = 0,
36 Map_superpage_shift = 16,
37 Map_superpage_size = 0x10000,
38 Map_max_address = 0x10000,
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.
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
56 Page_writable = Mem_space::Page_writable,
57 Page_user_accessible = Mem_space::Page_user_accessible,
59 Page_all_attribs = Page_writable | Page_user_accessible
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); }
67 static Phys_addr subpage_address(Phys_addr addr, Size offset)
68 { return addr | offset; }
70 static Mword phys_to_word(Phys_addr a)
78 template< typename SPACE>
79 char const * const Generic_io_space<SPACE>::name = "Io_space";
82 //----------------------------------------------------------------------------
91 #include "mapped_alloc.h"
96 PUBLIC template< typename SPACE >
99 Generic_io_space<SPACE>::xlate_flush(unsigned char rights)
102 return Page_all_attribs;
107 PUBLIC template< typename SPACE >
110 Generic_io_space<SPACE>::is_full_flush(unsigned char rights)
115 PUBLIC template< typename SPACE >
118 Generic_io_space<SPACE>::xlate_flush_result(Mword /*attribs*/)
121 PUBLIC template< typename SPACE >
123 Generic_io_space<SPACE>::Generic_io_space ()
127 PRIVATE template< typename SPACE >
130 Generic_io_space<SPACE>::mem_space() const
131 { return SPACE::space(this)->mem_space(); }
134 PUBLIC template< typename SPACE >
135 Generic_io_space<SPACE>::~Generic_io_space()
137 if (! mem_space() || ! mem_space()->dir())
140 Pdir::Iter iopte = mem_space()->dir()->walk(Virt_addr(Mem_layout::Io_bitmap));
142 // do we have an IO bitmap?
143 if (iopte.e->valid())
146 assert (iopte.shift() != Config::SUPERPAGE_SHIFT);
148 Mapped_allocator::allocator()
149 ->q_free_phys(mem_space()->ram_quota(), Config::PAGE_SHIFT,
152 if (iopte.e[1].valid())
153 Mapped_allocator::allocator()
154 ->q_free_phys(mem_space()->ram_quota(), Config::PAGE_SHIFT,
157 Pdir::Iter iopde = mem_space()->dir()->walk(Virt_addr(Mem_layout::Io_bitmap), 0);
159 // free the page table
160 Mapped_allocator::allocator()
161 ->q_free_phys(mem_space()->ram_quota(), Config::PAGE_SHIFT,
169 PUBLIC template< typename SPACE >
172 Generic_io_space<SPACE>::ram_quota() const
173 { return mem_space()->ram_quota(); }
175 PRIVATE template< typename SPACE >
178 Generic_io_space<SPACE>::is_superpage()
179 { return _io_counter & 0x10000000; }
183 // Utilities for map<Generic_io_space> and unmap<Generic_io_space>
186 PUBLIC template< typename SPACE >
189 Generic_io_space<SPACE>::v_fabricate(Addr address, Phys_addr* phys,
190 Size* size, unsigned* attribs = 0)
192 return Generic_io_space::v_lookup(address.trunc(Size(Map_page_size)),
193 phys, size, attribs);
197 PUBLIC template< typename SPACE >
198 inline NEEDS[Generic_io_space::is_superpage]
200 Generic_io_space<SPACE>::v_lookup(Addr virt, Phys_addr *phys = 0,
201 Size *size = 0, unsigned *attribs = 0)
205 if (size) *size = Size(Map_superpage_size);
206 if (phys) *phys = Phys_addr(0);
207 if (attribs) *attribs = Page_writable | Page_user_accessible;
211 if (size) *size = Size(1);
213 if (io_lookup (virt.value()))
215 if (phys) *phys = virt;
216 if (attribs) *attribs = Page_writable | Page_user_accessible;
220 if (get_io_counter() == 0)
222 if (size) *size = Size(Map_superpage_size);
223 if (phys) *phys = Phys_addr(0);
229 PUBLIC template< typename SPACE >
230 inline NEEDS [Generic_io_space::is_superpage]
232 Generic_io_space<SPACE>::v_delete(Addr virt, Size size,
233 unsigned long page_attribs = Page_all_attribs)
237 assert (page_attribs == Page_all_attribs);
241 assert (size.value() == Map_superpage_size);
242 #ifndef CONFIG_IO_PROT_IOPL_3
243 for (unsigned p = 0; p < Map_max_address; ++p)
247 return Page_writable | Page_user_accessible;
250 assert (size.value() == 1);
252 return io_delete (virt.value());
255 PUBLIC template< typename SPACE >
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)
265 assert (phys == virt);
266 if (is_superpage() && size.value() == Map_superpage_size)
267 return Insert_warn_exists;
269 if (get_io_counter() == 0 && size.value() == Map_superpage_size)
271 #ifndef CONFIG_IO_PROT_IOPL_3
272 for (unsigned p = 0; p < Map_max_address; ++p)
274 _io_counter |= 0x10000000;
276 _io_counter = 0x10000000 | Map_superpage_size;
281 assert (size.value() == 1);
283 return typename Generic_io_space::Status(io_insert (virt.value()));
287 PUBLIC template< typename SPACE >
290 Generic_io_space<SPACE>::tlb_flush()
293 PUBLIC template< typename SPACE >
296 Generic_io_space<SPACE>::need_tlb_flush()
300 // IO lookup / insert / delete / counting
303 /** return the IO counter.
304 * @return number of IO ports mapped / 0 if not mapped
306 PUBLIC template< typename SPACE >
307 inline NEEDS["paging.h"]
309 Generic_io_space<SPACE>::get_io_counter() const
311 return _io_counter & ~0x10000000;
315 /** Add something the the IO counter.
316 @param incr number to add
317 @pre 2nd level page table for IO bitmap is present
319 template< typename SPACE >
320 inline NEEDS["paging.h"]
322 Generic_io_space<SPACE>::addto_io_counter(int incr)
324 atomic_add (&_io_counter, incr);
328 /** Lookup one IO port in the IO space.
329 @param port_number port address to lookup;
330 @return true if mapped
333 PROTECTED template< typename SPACE >
335 Generic_io_space<SPACE>::io_lookup(Address port_number)
337 assert(port_number < Mem_layout::Io_port_max);
339 // be careful, do not cause page faults here
340 // there might be nothing mapped in the IO bitmap
342 Address port_addr = get_phys_port_addr(port_number);
344 if(port_addr == ~0UL)
345 return false; // no bitmap -> no ports
347 // so there is memory mapped in the IO bitmap
348 char * port = static_cast<char *>(Kmem::phys_to_virt(port_addr));
350 // bit == 1 disables the port
351 // bit == 0 enables the port
352 return !(*port & get_port_bit(port_number));
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
363 PROTECTED template< typename SPACE >
364 typename Generic_io_space<SPACE>::Status
365 Generic_io_space<SPACE>::io_insert(Address port_number)
367 assert(port_number < Mem_layout::Io_port_max);
369 Address port_virt = Mem_layout::Io_bitmap + (port_number >> 3);
370 Address port_phys = mem_space()->virt_to_phys (port_virt);
372 if (port_phys == ~0UL)
374 // nothing mapped! Get a page and map it in the IO bitmap
376 if (!(page=Mapped_allocator::allocator()->q_alloc(ram_quota(),
377 Config::PAGE_SHIFT)))
378 return Insert_err_nomem;
380 // clear all IO ports
381 // bit == 1 disables the port
382 // bit == 0 enables the port
383 memset(page, 0xff, Config::PAGE_SIZE);
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);
391 if (status == Mem_space::Insert_err_nomem)
393 Mapped_allocator::allocator()->free(Config::PAGE_SHIFT,page);
394 mem_space()->ram_quota()->free(Config::PAGE_SIZE);
395 return Insert_err_nomem;
398 // we've been careful, so insertion should have succeeded
399 assert(status == Mem_space::Insert_ok);
401 port_phys = mem_space()->virt_to_phys (port_virt);
402 assert(port_phys != ~0UL);
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));
408 if (*port & get_port_bit(port_number)) // port disabled?
410 *port &= ~ get_port_bit(port_number);
416 return Insert_warn_exists;
420 /** Disable one IO port in the IO space.
421 @param port_number port to disable
423 PROTECTED template< typename SPACE >
425 Generic_io_space<SPACE>::io_delete(Address port_number)
427 assert(port_number < Mem_layout::Io_port_max);
429 // be careful, do not cause page faults here
430 // there might be nothing mapped in the IO bitmap
432 Address port_addr = get_phys_port_addr(port_number);
434 if (port_addr == ~0UL)
435 // nothing mapped -> nothing to delete
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));
441 // bit == 1 disables the port
442 // bit == 0 enables the port
443 if(!(*port & get_port_bit(port_number))) // port enabled ??
445 *port |= get_port_bit(port_number);
446 addto_io_counter(-1);
448 return Page_writable | Page_user_accessible;
454 template< typename SPACE >
455 INLINE NEEDS["config.h"]
457 Generic_io_space<SPACE>::get_phys_port_addr(Address const port_number) const
459 return mem_space()->virt_to_phys(Mem_layout::Io_bitmap + (port_number >> 3));
462 template< typename SPACE >
465 Generic_io_space<SPACE>::get_port_bit(Address const port_number) const
467 return 1 << (port_number & 7);
471 PUBLIC template< typename SPACE >
474 Generic_io_space<SPACE>::canonize(Page_number v)