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;
27 Need_insert_tlb_flush = 0,
28 Need_xcpu_tlb_flush = 0,
31 Map_superpage_shift = 16,
32 Map_superpage_size = 0x10000,
33 Map_max_address = 0x10000,
38 // We'd rather like to use a "using Mem_space::Status" declaration here,
39 // but that wouldn't make the enum values accessible as
40 // Generic_io_space::Insert_ok and so on.
43 Insert_ok = 0, ///< Mapping was added successfully.
44 Insert_warn_exists, ///< Mapping already existed
45 Insert_warn_attrib_upgrade, ///< Mapping already existed, attribs upgrade
46 Insert_err_nomem, ///< Couldn't alloc new page table
47 Insert_err_exists ///< A mapping already exists at the target addr
52 Page_writable = Mem_space::Page_writable,
53 Page_user_accessible = Mem_space::Page_user_accessible,
55 Page_all_attribs = Page_writable | Page_user_accessible
58 static Addr map_max_address()
59 { return Addr(Map_max_address); }
61 static Address superpage_size()
62 { return Map_superpage_size; }
64 static bool has_superpages()
67 static Phys_addr page_address(Phys_addr o, Size s)
68 { return o.trunc(s); }
70 static Phys_addr subpage_address(Phys_addr addr, Size offset)
71 { return addr | offset; }
77 Mem_space const *mem_space() const
78 { return static_cast<SPACE const *>(this); }
80 Mem_space *mem_space()
81 { return static_cast<SPACE *>(this); }
84 template< typename SPACE>
85 char const * const Generic_io_space<SPACE>::name = "Io_space";
88 //----------------------------------------------------------------------------
97 #include "kmem_alloc.h"
102 PUBLIC template< typename SPACE >
105 Generic_io_space<SPACE>::xlate_flush(unsigned char rights)
108 return Page_all_attribs;
113 PUBLIC template< typename SPACE >
116 Generic_io_space<SPACE>::is_full_flush(unsigned char rights)
121 PUBLIC template< typename SPACE >
124 Generic_io_space<SPACE>::xlate_flush_result(Mword /*attribs*/)
127 PUBLIC template< typename SPACE >
129 Generic_io_space<SPACE>::Generic_io_space()
134 PUBLIC template< typename SPACE >
135 Generic_io_space<SPACE>::~Generic_io_space()
137 if (!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 Kmem_alloc::allocator()
149 ->q_free_phys(ram_quota(), Config::PAGE_SHIFT,
152 if (iopte.e[1].valid())
153 Kmem_alloc::allocator()
154 ->q_free_phys(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 Kmem_alloc::allocator()
161 ->q_free_phys(ram_quota(), Config::PAGE_SHIFT,
169 PUBLIC template< typename SPACE >
172 Generic_io_space<SPACE>::ram_quota() const
173 { return static_cast<SPACE const *>(this)->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);
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 for (unsigned p = 0; p < Map_max_address; ++p)
273 _io_counter |= 0x10000000;
278 assert (size.value() == 1);
280 return typename Generic_io_space::Status(io_insert(virt.value()));
284 PUBLIC template< typename SPACE >
287 Generic_io_space<SPACE>::tlb_flush()
290 PUBLIC template< typename SPACE >
293 Generic_io_space<SPACE>::need_tlb_flush()
297 // IO lookup / insert / delete / counting
300 /** return the IO counter.
301 * @return number of IO ports mapped / 0 if not mapped
303 PUBLIC template< typename SPACE >
304 inline NEEDS["paging.h"]
306 Generic_io_space<SPACE>::get_io_counter() const
308 return _io_counter & ~0x10000000;
312 /** Add something the the IO counter.
313 @param incr number to add
314 @pre 2nd level page table for IO bitmap is present
316 template< typename SPACE >
317 inline NEEDS["paging.h"]
319 Generic_io_space<SPACE>::addto_io_counter(int incr)
321 atomic_add (&_io_counter, incr);
325 /** Lookup one IO port in the IO space.
326 @param port_number port address to lookup;
327 @return true if mapped
330 PROTECTED template< typename SPACE >
332 Generic_io_space<SPACE>::io_lookup(Address port_number)
334 assert(port_number < Mem_layout::Io_port_max);
336 // be careful, do not cause page faults here
337 // there might be nothing mapped in the IO bitmap
339 Address port_addr = get_phys_port_addr(port_number);
341 if(port_addr == ~0UL)
342 return false; // no bitmap -> no ports
344 // so there is memory mapped in the IO bitmap
345 char * port = static_cast<char *>(Kmem::phys_to_virt(port_addr));
347 // bit == 1 disables the port
348 // bit == 0 enables the port
349 return !(*port & get_port_bit(port_number));
353 /** Enable one IO port in the IO space.
354 This function is called in the context of the IPC sender!
355 @param port_number address of the port
356 @return Insert_warn_exists if some ports were mapped in that IO page
357 Insert_err_nomem if memory allocation failed
358 Insert_ok if otherwise insertion succeeded
360 PROTECTED template< typename SPACE >
361 typename Generic_io_space<SPACE>::Status
362 Generic_io_space<SPACE>::io_insert(Address port_number)
364 assert(port_number < Mem_layout::Io_port_max);
366 Address port_virt = Mem_layout::Io_bitmap + (port_number >> 3);
367 Address port_phys = mem_space()->virt_to_phys(port_virt);
369 if (port_phys == ~0UL)
371 // nothing mapped! Get a page and map it in the IO bitmap
373 if (!(page=Kmem_alloc::allocator()->q_alloc(ram_quota(),
374 Config::PAGE_SHIFT)))
375 return Insert_err_nomem;
377 // clear all IO ports
378 // bit == 1 disables the port
379 // bit == 0 enables the port
380 memset(page, 0xff, Config::PAGE_SIZE);
382 Mem_space::Status status =
383 mem_space()->v_insert(
384 Mem_space::Phys_addr(Mem_layout::pmem_to_phys(page)),
385 Mem_space::Addr(port_virt & Config::PAGE_MASK),
386 Mem_space::Size(Config::PAGE_SIZE), Page_writable);
388 if (status == Mem_space::Insert_err_nomem)
390 Kmem_alloc::allocator()->free(Config::PAGE_SHIFT,page);
391 ram_quota()->free(Config::PAGE_SIZE);
392 return Insert_err_nomem;
395 // we've been careful, so insertion should have succeeded
396 assert(status == Mem_space::Insert_ok);
398 port_phys = mem_space()->virt_to_phys(port_virt);
399 assert(port_phys != ~0UL);
402 // so there is memory mapped in the IO bitmap -- write the bits now
403 Unsigned8 *port = static_cast<Unsigned8 *> (Kmem::phys_to_virt(port_phys));
405 if (*port & get_port_bit(port_number)) // port disabled?
407 *port &= ~ get_port_bit(port_number);
413 return Insert_warn_exists;
417 /** Disable one IO port in the IO space.
418 @param port_number port to disable
420 PROTECTED template< typename SPACE >
422 Generic_io_space<SPACE>::io_delete(Address port_number)
424 assert(port_number < Mem_layout::Io_port_max);
426 // be careful, do not cause page faults here
427 // there might be nothing mapped in the IO bitmap
429 Address port_addr = get_phys_port_addr(port_number);
431 if (port_addr == ~0UL)
432 // nothing mapped -> nothing to delete
435 // so there is memory mapped in the IO bitmap -> disable the ports
436 char * port = static_cast<char *> (Kmem::phys_to_virt(port_addr));
438 // bit == 1 disables the port
439 // bit == 0 enables the port
440 if(!(*port & get_port_bit(port_number))) // port enabled ??
442 *port |= get_port_bit(port_number);
443 addto_io_counter(-1);
445 return Page_writable | Page_user_accessible;
451 template< typename SPACE >
452 INLINE NEEDS["config.h"]
454 Generic_io_space<SPACE>::get_phys_port_addr(Address const port_number) const
456 return mem_space()->virt_to_phys(Mem_layout::Io_bitmap + (port_number >> 3));
459 template< typename SPACE >
462 Generic_io_space<SPACE>::get_port_bit(Address const port_number) const
464 return 1 << (port_number & 7);
468 PUBLIC template< typename SPACE >
471 Generic_io_space<SPACE>::canonize(Page_number v)