4 #include <System/Mem.h>
6 #include <kern/kernel.h>
9 #include <arch/addrs.h>
11 #include <util/rbtree.h>
12 #include <util/list.h>
13 #include <util/lock.h>
14 #include <kernel/region.h>
15 #include <lowlevel/bitops.h>
18 // Used for allocating memory at boot time before the page allocator
19 // is running. Alignment must be a power of 2. Because nothing other
20 // than the kernel is guaranteed to be mapped from the beginning on
21 // all architectures, no generic code should use this until after
22 // Arch::arch_init() has run and set up physical memory mappings.
24 // This function may not be used after the page allocator has
25 // been initialized by architecture code.
27 // Architectures must provide Arch::next_free_bootmem initalized
28 // to the first free piece of bootmem.
30 static inline void *get_bootmem(size_t size, size_t align)
32 uintptr_t ret = (Arch::next_free_bootmem + align - 1) & ~(align - 1);
33 Arch::next_free_bootmem = ret + size;
34 return reinterpret_cast<void *>(ret);
37 typedef System::Mem::AddrSpace IAddrSpace;
38 typedef System::Mem::Mappable IMappable;
39 using System::Mem::Cacheable;
40 using System::Mem::Region;
41 using System::Mem::RegionWithOffset;
42 using System::Mem::AllocFlags;
43 using System::Mem::MapFlags;
44 using System::Mem::AccessFlags;
62 // This must be kept in sync with include/kern/generic-pte.h
65 // Readable, Writeable, and Executable are for permission only,
66 // not for implementing copy on write, swapping, etc.
77 // If set, then on a write access, the page is copied and this
78 // address space gets the new, anonymous version. The rmap list
79 // is then traversed; all downstream mappings will share the new
82 // For vareas that directly map something other than an address
83 // space, the action to be taken on a write fault is
88 // The address itself is being mapped, not the page located
89 // there. Do not manipulate page reference counts. This bit
90 // does not get propagated during copy-on-write.
95 // Do not allow the user to unmap or modify flags.
96 // Used for the shared user/kernel mappings.
100 #elif defined(BITFIELD_BE)
101 ulong pad:_LL_LONG_BYTES * 8 - 11;
104 ulong FaultOnWrite:1;
114 #error Unspecified/unrecognized bitfield endianness
120 PTEFlags(ulong init) : raw(init)
134 using Arch::kvirt_to_phys;
135 using Arch::phys_to_kvirt;
140 typedef Util::RBTree<VirtualArea, Region, u64> VirtualAreaTree;
144 // This linked list keeps track of the virtual areas that map this
145 // mappable (this is not transitive; vareas that map a varea that
146 // maps this mappable are not on this list).
148 // OPT: rbtree keyed on mapped address range?
151 Lock::SpinLock mappings_lock;
156 virtual void get_size(u64 *size) = 0;
158 virtual void get_block_size(u64 *block_size)
160 *block_size = Arch::page_size;
163 // Register/unregister varea as mapping this mappable.
165 virtual void map(VirtualArea *varea);
166 virtual void unmap(VirtualArea *varea);
168 // Make the specified page available for mapping. This must be
169 // done before map() will succeed. It is possible (though
170 // unlikely) that the pages will be removed before map() is called,
171 // causing map() to return false. In such a case, pagein should be
172 // called again by the fault handler. If the mapping fails for
173 // other reasons (such as lack of permission, a hole in a stacked
174 // aspace, or an I/O error) then pagein() will throw a BadPageFault
177 virtual void pagein(u64 vaddr, PTEFlags reqflags) = 0;
179 // Returns the physical address and flags associated with a given
180 // virtual address. If flags.Valid is not set, then phys and all
181 // other flags are undefined, and pagein() should be retried.
182 // rmap_lock must be held.
184 virtual void get_mapping(u64 vaddr, u64 *phys, PTEFlags *flags) = 0;
186 #include <servers/mem/addrspace/Mem/Mappable.h>
202 // The red/black tree is used to find a region based on address.
204 // The linked list is kept in order and is used to iterate over
205 // vmas in a region (after looking up the starting point in the
206 // tree, unless the region is the entire address space).
208 VirtualAreaTree::Node rbtree_node;
209 Util::List list_node;
210 Util::List mappings_node;
215 // This is added to the virtual address to get the offset
216 // into the mappable.
221 return rbtree_node.value;
226 struct BadPageFault {
227 MemoryFault_ns::Cause cause;
229 BadPageFault(MemoryFault_ns::Cause CAUSE) : cause(CAUSE)
234 class ASpaceMappable : public Mappable {
237 static bool rec_pagein(AddrSpace *aspace, u64 vaddr,
241 ASpaceMappable (AddrSpace *ASPACE) : aspace(ASPACE)
246 void get_size(u64 *size);
249 virtual void pagein(u64 vaddr, PTEFlags reqflags);
250 virtual void get_mapping(u64 vaddr, u64 *phys, PTEFlags *flags);
252 friend class AddrSpace;
256 // OPT: Coalesce vareas when possible (except when setting flags to
257 // match surrounding vareas, as the flags are likely to change
258 // again if they've already changed).
260 // OPT: A subclass of AddrSpace that doesn't use
261 // VirtualArea::offset, but rather has its own virtual method that
262 // figures out offsets to the next level using its own data
263 // structures (such as filesystem block tables). This would avoid
264 // excessive vareas for fragmented files. Whether the excess of
265 // vareas is significant enough for this to be worthwhile remains
268 VirtualAreaTree varea_tree;
269 Util::List varea_list;
272 // This defines the start and end of the aspace; mappings outside
273 // this range may not be done, and will not be returned by
274 // get_free_region(). For process aspaces, this goes from
275 // Arch::user_start to Arch::user_end. For non-proc aspaces, this
278 Region aspace_region;
280 // Returns true if there is a mapped region that overlaps the given
281 // region. If there is a collision, then the first overlapping
282 // varea is returned in va. Otherwise, it returns the last mapped
283 // area before the region in va (if there are no areas, or the
284 // region is before the first area, then prev is NULL). The aspace
285 // lock must be held.
287 bool check_overlap(Region region, VirtualArea *&va);
289 // Finds a free region of the requested length and puts it in
290 // region. Returns true if an appropriate area is found. The prev
291 // pointer is as in check_overlap. The aspace lock must be held.
293 bool get_free_region(ulong len, Region ®ion, VirtualArea *&prev);
295 // This is the value after the last region returned by
296 // get_free_region. If there was an intervening unmap for a lower
297 // address, then it is set to that address instead.
299 u64 cached_free_region;
301 static u64 rec_unmap(AddrSpace *aspace, Region region,
302 PTEFlags reqflags, VirtualArea *va);
304 // If there are multiple virtual areas that cover the specified region,
305 // split them at the region's boundaries. The first varea in the region
306 // (if any) is returned. The aspace lock must be held.
308 VirtualArea *split_varea(Region region);
310 void break_copy_on_write(VirtualArea *va, u64 vaddr, u64 phys);
311 bool map(VirtualArea *va, u64 vaddr, PTEFlags reqflags);
317 #include <servers/mem/addrspace/Mem/AddrSpace.h>
319 ASpaceMappable mappable;
320 PageTable *page_table;
322 AddrSpace(PageTable *ptbl = NULL);
324 // Returns negative if the fault was "good"; otherwise, a fault
325 // code corresponding to MemoryFault.Cause is returned. exec
326 // should only be set if the CPU implements per-page exec
327 // protection; otherwise, treat it as a read.
329 int handle_fault(ulong addr, bool write, bool exec, bool user);
331 void get_mappable(IMappable *ma);
332 void clone(IAddrSpace *addrspace, u8 clone_is_real);
334 void map(IMappable ma, Region region, u64 *vstart, MapFlags mflags,
335 PTEFlags set = 0, PTEFlags clear = 0);
336 void unmap(Region region, bool from_kernel = false);
338 void set_mapflags(Region region, MapFlags mflags);
339 void get_mapflags(Region region, MapFlags *mflags, uint8_t *all_same);
340 void get_mapping(Region region, IMappable *ma, u64 *offset);
342 void get_page_size(u32 *page_size);
343 void get_min_align(u32 *min_align);
344 void get_size(u64 *size);
346 friend class ASpaceMappable;
349 extern Factory addr_space_factory, proc_addr_space_factory;
351 static inline bool page_aligned(u64 addr)
353 return !(addr & (u64)(Arch::page_size - 1));
356 static inline u64 page_align(u64 addr)
358 return addr & ~(u64)(Arch::page_size - 1);
361 // FIXME: Valid user addr? Paging holes?
362 static inline bool valid_addr(uint64_t addr)
364 if (sizeof(void *) == 8)
367 return (addr >> 32) == 0;