3 #include "entry_frame.h"
7 pagefault_entry(Address, Mword, Mword, Return_frame *);
9 EXTENSION class Mem_space
13 typedef Pdir Dir_type;
15 /** Return status of v_insert. */
18 Insert_ok = 0, ///< Mapping was added successfully.
19 Insert_warn_exists, ///< Mapping already existed
20 Insert_warn_attrib_upgrade, ///< Mapping already existed, attribs upgrade
21 Insert_err_nomem, ///< Couldn't alloc new page table
22 Insert_err_exists ///< A mapping already exists at the target addr
25 /** Attribute masks for page mappings. */
30 Page_writable = Pt_entry::Writable,
32 /// Page is noncacheable.
33 Page_noncacheable = Pt_entry::Noncacheable | Pt_entry::Write_through,
35 Page_user_accessible = Pt_entry::User,
36 /// Page has been referenced
37 Page_referenced = Pt_entry::Referenced,
39 Page_dirty = Pt_entry::Dirty,
40 Page_references = Page_referenced | Page_dirty,
41 /// A mask which contains all mask bits
42 Page_all_attribs = Page_writable | Page_noncacheable |
43 Page_user_accessible | Page_referenced | Page_dirty,
47 enum // Definitions for map_util
49 Need_insert_tlb_flush = 0,
50 Map_page_size = Config::PAGE_SIZE,
51 Page_shift = Config::PAGE_SHIFT,
52 Map_superpage_size = Config::SUPERPAGE_SIZE,
53 Map_max_address = Mem_layout::User_max,
54 Whole_space = MWORD_BITS,
58 bool try_htab_fault(Address virt);
65 //----------------------------------------------------------------------------
66 IMPLEMENTATION [ppc32]:
73 #include "mem_layout.h"
75 #include "std_macros.h"
79 #include "lock_guard.h"
86 PUBLIC explicit inline
87 Mem_space::Mem_space(Ram_quota *q) : _quota(q), _dir(0) {}
91 Mem_space::initialize()
94 if (EXPECT_FALSE(!(b = Kmem_alloc::allocator()
95 ->q_alloc(_quota, Config::PAGE_SHIFT))))
98 _dir = static_cast<Dir_type*>(b);
99 _dir->clear(); // initialize to zero
100 return true; // success
105 Mem_space::sync_kernel()
110 Mem_space::Mem_space(Ram_quota *q, Dir_type* pdir)
111 : _quota(q), _dir(pdir)
113 _kernel_space = this;
114 _current.cpu(0) = this;
120 Mem_space::xlate_flush(unsigned char rights)
122 Mword a = Page_references;
123 if (rights & L4_fpage::RX)
124 a |= Page_all_attribs;
125 else if (rights & L4_fpage::W)
134 Mem_space::is_full_flush(unsigned char rights)
136 return rights & L4_fpage::RX;
141 Mem_space::xlate_flush_result(Mword attribs)
144 if (attribs & Page_referenced)
147 if (attribs & Page_dirty)
153 PUBLIC inline NEEDS["cpu.h"]
155 Mem_space::has_superpages()
157 return Cpu::have_superpages();
160 //we flush tlb in htab implementation
161 PUBLIC static inline NEEDS["mem_unit.h"]
163 Mem_space::tlb_flush(bool = false)
165 //Mem_unit::tlb_flush();
171 Mem_space::set_attributes(Address virt, unsigned page_attribs)
174 Pdir::Iter i = _dir->walk(virt);
176 if (!i.e->valid() || i.shift() != Config::PAGE_SHIFT)
179 i.e->del_attr(Page::MAX_ATTRIBS);
180 i.e->add_attr(page_attribs);
184 (void)virt; (void)page_attribs;
195 * Destructor. Deletes the address space and unregisters it from
200 Mem_space::dir_shutdown()
203 // free ldt memory if it was allocated
206 // free all page tables we have allocated for this address space
207 // except the ones in kernel space which are always shared
209 _dir->alloc_cast<Mem_space_q_alloc>()
210 ->destroy(0, Kmem::mem_user_max, Pdir::Depth - 1,
211 Mem_space_q_alloc(_quota, Kmem_alloc::allocator()));
218 Mem_space::current_mem_space(unsigned cpu) /// XXX: do not fix, deprecated, remove!
220 return _current.cpu(cpu);
223 /** Insert a page-table entry, or upgrade an existing entry with new
225 @param phys Physical address (page-aligned).
226 @param virt Virtual address for which an entry should be created.
227 @param size Size of the page frame -- 4KB or 4MB.
228 @param page_attribs Attributes for the mapping (see
229 Mem_space::Page_attrib).
230 @return Insert_ok if a new mapping was created;
231 Insert_warn_exists if the mapping already exists;
232 Insert_warn_attrib_upgrade if the mapping already existed but
233 attributes could be upgraded;
234 Insert_err_nomem if the mapping could not be inserted because
235 the kernel is out of memory;
236 Insert_err_exists if the mapping could not be inserted because
237 another mapping occupies the virtual-address
239 @pre phys and virt need to be size-aligned according to the size argument.
243 Mem_space::v_insert(Phys_addr phys, Vaddr virt, Vsize size,
244 unsigned page_attribs, bool /*upgrade_ignore_size*/)
246 assert(size == Size(Config::PAGE_SIZE)
247 || size == Size(Config::SUPERPAGE_SIZE));
249 printf("v_insert: phys %08lx virt %08lx (%s) %p\n", phys, virt,
250 page_attribs & Page_writable?"rw":"ro", this);*/
251 Pte_base e(phys.value());
252 unsigned attribs = e.to_htab_entry(page_attribs);
254 Status status = v_insert_cache(&e, Virt_addr(virt).value(),
255 Virt_size(size).value(), attribs);
261 Mem_space::try_htab_fault(Address virt)
265 Address pte_ptr, phys;
266 Dir_type *dir = _dir;
268 if(virt >= Mem_layout::User_max)
271 Pdir::Iter i = dir->walk(Addr(virt), Pdir::Super_level);
276 super = i.e->is_super_page();
278 i = dir->walk(Addr(virt));
280 if(!i.e->is_htab_entry() && !super)
283 if(super && !i.e->valid())
285 i = dir->walk(Addr(virt & Config::SUPERPAGE_MASK));
286 phys = Pte_htab::pte_to_addr(i.e);
287 phys += (virt & Config::PAGE_MASK) - (phys & Config::PAGE_MASK);
295 auto guard = lock_guard(cpu_lock);
297 status = v_insert_htab(phys, virt, &pte_ptr, &evict);
299 // something had to be replaced update in cache-page table
300 if(EXPECT_FALSE(status == Insert_err_nomem))
302 Pte_base e(evict.phys);
304 //printf("EVICTING: virt: %lx phys: %lx\n", evict.virt, e.raw());
305 status = v_insert_cache(&e, evict.virt, Config::PAGE_SIZE, 0, evict.dir);
310 if(EXPECT_FALSE(status != Insert_ok))
313 // set pointer in cache
318 status = v_insert_cache(&e, virt, Config::PAGE_SIZE, 0, dir);
320 if(EXPECT_FALSE(status != Insert_ok))
327 * Simple page-table lookup.
329 * @param virt Virtual address. This address does not need to be page-aligned.
330 * @return Physical address corresponding to a.
332 PUBLIC inline NEEDS ["paging.h"]
334 Mem_space::virt_to_phys (Address virt) const
336 return dir()->virt_to_phys(virt);
341 Mem_space::virt_to_phys_s0(void *a) const
343 return dir()->virt_to_phys((Address)a);
348 Mem_space::pmem_to_phys (Address virt) const
355 /** Look up a page-table entry.
356 @param virt Virtual address for which we try the look up.
357 @param phys Meaningful only if we find something (and return true).
358 If not 0, we fill in the physical address of the found page
360 @param page_attribs Meaningful only if we find something (and return true).
361 If not 0, we fill in the page attributes for the found page
362 frame (see Mem_space::Page_attrib).
363 @param size If not 0, we fill in the size of the page-table slot. If an
364 entry was found (and we return true), this is the size
365 of the page frame. If no entry was found (and we
366 return false), this is the size of the free slot. In
367 either case, it is either 4KB or 4MB.
368 @return True if an entry was found, false otherwise.
372 Mem_space::v_lookup(Vaddr virt, Phys_addr *phys = 0, Size *size = 0,
373 unsigned *page_attribs = 0)
375 Pdir::Iter i = _dir->walk(virt, Pdir::Super_level);
377 if(size) *size = Size(1UL << i.shift());
382 unsigned shift = i.e->is_super_page() ? Config::SUPERPAGE_SHIFT
383 : Config::PAGE_SHIFT;
384 unsigned mask = (~0UL << shift);
386 i = _dir->walk(virt & Addr(mask));
391 if(size) *size = Size(1UL << i.shift());
393 if(phys || page_attribs)
395 Address addr = phys->value();
396 Pte_htab::pte_lookup(i.e, &addr, page_attribs);
397 *phys = Phys_addr(addr);
400 *page_attribs = to_kernel_fmt(*page_attribs, i.e->is_htab_entry());
405 /** Delete page-table entries, or some of the entries' attributes. This
406 function works for one or multiple mappings (in contrast to v_insert!).
407 @param virt Virtual address of the memory region that should be changed.
408 @param size Size of the memory region that should be changed.
409 @param page_attribs If nonzero, delete only the given page attributes.
410 Otherwise, delete the whole entries.
411 @return Combined (bit-ORed) page attributes that were removed. In
412 case of errors, ~Page_all_attribs is additionally bit-ORed in.
416 Mem_space::v_delete(Vaddr virt, Vsize size,
417 unsigned long page_attribs = Page_all_attribs)
420 // delete pages from page tables
421 //printf("v_delete: %lx dir: %p\n", virt, _dir);
422 assert (size == Size(Config::PAGE_SIZE)
423 || size == Size(Config::SUPERPAGE_SIZE));
425 unsigned shift = (size == Virt_size(Config::SUPERPAGE_SIZE)) ?
426 Config::SUPERPAGE_SHIFT : Config::PAGE_SHIFT;
428 Address offs = Virt_addr(virt).value() & (~0UL << shift);
429 Pdir::Iter i = _dir->walk(Addr(offs));
430 Pt_entry *e = nonull_static_cast<Pt_entry*>(i.e);
432 offs < ((Virt_size(size).value() / Config::PAGE_SIZE) *sizeof(Mword));
433 offs += sizeof(Mword))
435 e = reinterpret_cast<Pt_entry*>(e + offs);
441 if(!e->is_htab_entry())
443 ret = v_delete_htab(e->raw(), page_attribs);
445 if(page_attribs & Page_user_accessible)
446 v_delete_cache(e, page_attribs);
449 ret = v_delete_cache(e, page_attribs);
452 if(size != Virt_size(Config::SUPERPAGE_SIZE) && !(page_attribs & Page_user_accessible))
455 //check for and delete super page
456 i = _dir->walk(virt, Pdir::Super_level);
464 Mem_space::canonize(Page_number v)