3 #include "entry_frame.h"
6 pagefault_entry(Address, Mword, Mword, Return_frame *);
8 EXTENSION class Mem_space
12 typedef Pdir Dir_type;
14 /** Return status of v_insert. */
17 Insert_ok = 0, ///< Mapping was added successfully.
18 Insert_warn_exists, ///< Mapping already existed
19 Insert_warn_attrib_upgrade, ///< Mapping already existed, attribs upgrade
20 Insert_err_nomem, ///< Couldn't alloc new page table
21 Insert_err_exists ///< A mapping already exists at the target addr
24 /** Attribute masks for page mappings. */
29 Page_writable = Pt_entry::Writable,
31 /// Page is noncacheable.
32 Page_noncacheable = Pt_entry::Noncacheable | Pt_entry::Write_through,
34 Page_user_accessible = Pt_entry::User,
35 /// Page has been referenced
36 Page_referenced = Pt_entry::Referenced,
38 Page_dirty = Pt_entry::Dirty,
39 Page_references = Page_referenced | Page_dirty,
40 /// A mask which contains all mask bits
41 Page_all_attribs = Page_writable | Page_noncacheable |
42 Page_user_accessible | Page_referenced | Page_dirty,
46 enum // Definitions for map_util
48 Need_insert_tlb_flush = 0,
49 Map_page_size = Config::PAGE_SIZE,
50 Page_shift = Config::PAGE_SHIFT,
51 Map_superpage_size = Config::SUPERPAGE_SIZE,
52 Map_max_address = Mem_layout::User_max,
53 Whole_space = MWORD_BITS,
57 bool try_htab_fault(Address virt);
58 Address lookup( void *);
65 //----------------------------------------------------------------------------
66 IMPLEMENTATION [ppc32]:
73 #include "mem_layout.h"
75 #include "std_macros.h"
79 #include "lock_guard.h"
83 Per_cpu<Mem_space *> DEFINE_PER_CPU Mem_space::_current;
86 Mem_space::Mem_space(Ram_quota *q) //, bool sync_kernel = true)
91 if (EXPECT_FALSE(!(b = Mapped_allocator::allocator()
92 ->q_alloc(_quota, Config::PAGE_SHIFT))))
95 _dir = static_cast<Dir_type*>(b);
96 _dir->clear(); // initialize to zero
100 Mem_space::Mem_space(Ram_quota *q, Dir_type* pdir)
101 : _quota(q), _dir (pdir)
103 _kernel_space = this;
104 _current.cpu(0) = this;
110 Mem_space::xlate_flush(unsigned char rights)
112 Mword a = Page_references;
113 if (rights & L4_fpage::RX)
114 a |= Page_all_attribs;
115 else if (rights & L4_fpage::W)
123 Mem_space::xlate_flush_result(Mword attribs)
126 if (attribs & Page_referenced)
129 if (attribs & Page_dirty)
135 PUBLIC inline NEEDS["cpu.h"]
137 Mem_space::has_superpages()
139 return Cpu::have_superpages();
142 //we flush tlb in htab implementation
143 PUBLIC static inline NEEDS["mem_unit.h"]
145 Mem_space::tlb_flush(bool = false)
147 //Mem_unit::tlb_flush();
154 Mem_space::set_attributes(Address virt, unsigned page_attribs)
157 Pdir::Iter i = _dir->walk(virt);
159 if (!i.e->valid() || i.shift() != Config::PAGE_SHIFT)
162 i.e->del_attr(Page::MAX_ATTRIBS);
163 i.e->add_attr(page_attribs);
172 * Destructor. Deletes the address space and unregisters it from
177 Mem_space::dir_shutdown()
180 // free ldt memory if it was allocated
183 // free all page tables we have allocated for this address space
184 // except the ones in kernel space which are always shared
186 _dir->alloc_cast<Mem_space_q_alloc>()
187 ->destroy(0, Kmem::mem_user_max, Pdir::Depth - 1,
188 Mem_space_q_alloc(_quota, Mapped_allocator::allocator()));
195 Mem_space::current_mem_space(unsigned cpu) /// XXX: do not fix, deprecated, remove!
197 return _current.cpu(cpu);
200 /** Insert a page-table entry, or upgrade an existing entry with new
202 @param phys Physical address (page-aligned).
203 @param virt Virtual address for which an entry should be created.
204 @param size Size of the page frame -- 4KB or 4MB.
205 @param page_attribs Attributes for the mapping (see
206 Mem_space::Page_attrib).
207 @return Insert_ok if a new mapping was created;
208 Insert_warn_exists if the mapping already exists;
209 Insert_warn_attrib_upgrade if the mapping already existed but
210 attributes could be upgraded;
211 Insert_err_nomem if the mapping could not be inserted because
212 the kernel is out of memory;
213 Insert_err_exists if the mapping could not be inserted because
214 another mapping occupies the virtual-address
216 @pre phys and virt need to be size-aligned according to the size argument.
220 Mem_space::v_insert(Phys_addr phys, Vaddr virt, Vsize size,
221 unsigned page_attribs, bool /*upgrade_ignore_size*/)
223 assert(size == Size(Config::PAGE_SIZE)
224 || size == Size(Config::SUPERPAGE_SIZE));
226 printf("v_insert: phys %08lx virt %08lx (%s) %p\n", phys, virt,
227 page_attribs & Page_writable?"rw":"ro", this);*/
228 Pte_base e(phys.value());
229 unsigned attribs = e.to_htab_entry(page_attribs);
231 Status status = v_insert_cache(&e, Virt_addr(virt).value(),
232 Virt_size(size).value(), attribs);
238 Mem_space::try_htab_fault(Address virt)
242 Address pte_ptr, phys;
243 Dir_type *dir = _dir;
245 if(virt >= Mem_layout::User_max)
248 Pdir::Iter i = dir->walk(Addr(virt), Pdir::Super_level);
253 super = i.e->is_super_page();
255 i = dir->walk(Addr(virt));
257 if(!i.e->is_htab_entry() && !super)
260 if(super && !i.e->valid())
262 i = dir->walk(Addr(virt & Config::SUPERPAGE_MASK));
263 phys = Pte_htab::pte_to_addr(i.e);
264 phys += (virt & Config::PAGE_MASK) - (phys & Config::PAGE_MASK);
272 Lock_guard<Cpu_lock> guard(&cpu_lock);
274 status = v_insert_htab(phys, virt, &pte_ptr, &evict);
276 // something had to be replaced update in cache-page table
277 if(EXPECT_FALSE(status == Insert_err_nomem))
279 Pte_base e(evict.phys);
281 //printf("EVICTING: virt: %lx phys: %lx\n", evict.virt, e.raw());
282 status = v_insert_cache(&e, evict.virt, Config::PAGE_SIZE, 0, evict.dir);
287 if(EXPECT_FALSE(status != Insert_ok))
290 // set pointer in cache
295 status = v_insert_cache(&e, virt, Config::PAGE_SIZE, 0, dir);
297 if(EXPECT_FALSE(status != Insert_ok))
304 * Simple page-table lookup.
306 * @param virt Virtual address. This address does not need to be page-aligned.
307 * @return Physical address corresponding to a.
309 PUBLIC inline NEEDS ["paging.h"]
311 Mem_space::virt_to_phys (Address virt) const
313 return dir()->virt_to_phys(virt);
318 Mem_space::virt_to_phys_s0(void *a) const
320 return dir()->virt_to_phys((Address)a);
325 Mem_space::pmem_to_phys (Address virt) const
332 /** Look up a page-table entry.
333 @param virt Virtual address for which we try the look up.
334 @param phys Meaningful only if we find something (and return true).
335 If not 0, we fill in the physical address of the found page
337 @param page_attribs Meaningful only if we find something (and return true).
338 If not 0, we fill in the page attributes for the found page
339 frame (see Mem_space::Page_attrib).
340 @param size If not 0, we fill in the size of the page-table slot. If an
341 entry was found (and we return true), this is the size
342 of the page frame. If no entry was found (and we
343 return false), this is the size of the free slot. In
344 either case, it is either 4KB or 4MB.
345 @return True if an entry was found, false otherwise.
349 Mem_space::v_lookup(Vaddr virt, Phys_addr *phys = 0, Size *size = 0,
350 unsigned *page_attribs = 0)
352 Pdir::Iter i = _dir->walk(virt, Pdir::Super_level);
354 if(size) *size = Size(1UL << i.shift());
359 unsigned shift = i.e->is_super_page() ? Config::SUPERPAGE_SHIFT
360 : Config::PAGE_SHIFT;
361 unsigned mask = (~0UL << shift);
363 i = _dir->walk(virt & Addr(mask));
368 if(size) *size = Size(1UL << i.shift());
370 if(phys || page_attribs)
372 Address addr = phys->value();
373 Pte_htab::pte_lookup(i.e, &addr, page_attribs);
374 *phys = Phys_addr(addr);
377 *page_attribs = to_kernel_fmt(*page_attribs, i.e->is_htab_entry());
382 /** v_lookup wrapper */
385 Mem_space::lookup(void *a)
389 if(!v_lookup(Vaddr((Address)a), &phys))
395 /** Delete page-table entries, or some of the entries' attributes. This
396 function works for one or multiple mappings (in contrast to v_insert!).
397 @param virt Virtual address of the memory region that should be changed.
398 @param size Size of the memory region that should be changed.
399 @param page_attribs If nonzero, delete only the given page attributes.
400 Otherwise, delete the whole entries.
401 @return Combined (bit-ORed) page attributes that were removed. In
402 case of errors, ~Page_all_attribs is additionally bit-ORed in.
406 Mem_space::v_delete(Vaddr virt, Vsize size,
407 unsigned long page_attribs = Page_all_attribs)
410 // delete pages from page tables
411 //printf("v_delete: %lx dir: %p\n", virt, _dir);
412 assert (size == Size(Config::PAGE_SIZE)
413 || size == Size(Config::SUPERPAGE_SIZE));
415 unsigned shift = (size == Virt_size(Config::SUPERPAGE_SIZE)) ?
416 Config::SUPERPAGE_SHIFT : Config::PAGE_SHIFT;
418 Address offs = Virt_addr(virt).value() & (~0UL << shift);
419 Pdir::Iter i = _dir->walk(Addr(offs));
420 Pt_entry *e = nonull_static_cast<Pt_entry*>(i.e);
422 offs < ((Virt_size(size).value() / Config::PAGE_SIZE) *sizeof(Mword));
423 offs += sizeof(Mword))
425 e = reinterpret_cast<Pt_entry*>(e + offs);
431 if(!e->is_htab_entry())
433 ret = v_delete_htab(e->raw(), page_attribs);
435 if(page_attribs & Page_user_accessible)
436 v_delete_cache(e, page_attribs);
439 ret = v_delete_cache(e, page_attribs);
442 if(size != Virt_size(Config::SUPERPAGE_SIZE) && !(page_attribs & Page_user_accessible))
445 //check for and delete super page
446 i = _dir->walk(virt, Pdir::Super_level);
453 /** we assume that v_lookup was called on kernel_space beforehand */
456 Mem_space::kmem_update(void * /* *addr */)
463 Mem_space::canonize(Page_number v)