3 // These are the interfaces through which operations are performed on
4 // virtual and physical address spaces.
9 // There are two main kinds of mappable objects:
10 // 1. Objects that can be mapped directly into physical address space.
11 // This includes memory, device I/O, nested AddrSpaces, etc. Objects
12 // with this capability implement the Mappable interface.
13 // 2. Objects that are mapped by copying the content into RAM
14 // (disks, remote objects, dynamically generated data, etc.)
15 // These objects implement the Cacheable interface.
17 // Type #1 is simple; all it needs to do is translate mappable offsets
18 // into physical. Type #2 requires an intervening Cache to manage the
19 // backing RAM store. Memory-like type #1 objects should also implement
20 // Cacheable so that they can be used remotely.
22 // Address spaces may be stacked, such that (for example) a debugger maps
23 // an application which maps a file which maps a filesystem which maps a
24 // RAID volume which maps several physical disks; only the disks would be
25 // represented by Caches, everything else by AddrSpaces. Changes at any
26 // level immediately (well, before the operation finishes) propagate up
27 // to the page tables higher levels, and clone() will work at any level
28 // (and can make either the old or new address space the anonymous-
29 // memory-using "shadow" object). Stacked address spaces can also be
30 // used to implement access control.
32 struct Region inline {
33 // Both bounds are inclusive
37 struct RegionWithOffset inline : Region {
41 bitfield AccessFlags:3 {
42 // Allow reads to this page. On some platforms, this is assumed
43 // if writes are allowed, due to hardware limitations.
46 // Allow writes to this page.
49 // Allow execution of code from this page. On some platforms,
50 // this is assumed if reads are allowed, due to hardware
55 interface BlockObject {
56 guid: "4425AF91-52BE-11DA-BD60-000A95BB581A";
58 // Returns the current size in blocks of the object.
60 get_size(ulong size out);
62 // Returns the object's block size in bytes. Requests to map, read,
63 // write, etc. this object must be done with this granularity. The
64 // block size must be a power of two.
66 get_block_size(ulong block_size out);
69 // Finer grained mapping than the block size may be done via the virtual
70 // address space, but the AddrSpace will always request object->physical
71 // mappings that are a multiple of the block size.
73 interface Mappable : BlockObject {
74 guid: "B8E7A0DF-EAB6-11D9-BEFB-000A95BB581A";
78 interface Cacheable : BlockObject {
79 guid: "BB4C729D-EAB6-11D9-ADA2-000A95BB581A";
81 // Add the pages in the specified region to the specified cache.
82 // The start and end of the region will be aligned to the larger
83 // of the page size and the block size.
85 fill(Cache cache, Region region) async;
88 // This is the Mappable used to map a Cacheable object.
89 // Calling get_subspace on a Cache returns a pure Mappable; holders of
90 // such a reference alone can only map it, not add or remove pages or
91 // change its cacheable.
93 interface Cache : Mappable {
94 guid: "BD9A04F5-EAB6-11D9-A420-000A95BB581A";
96 // Get and set the object mapped through this Cache. Any other
97 // methods when obj is null (or never set) throw an InvalidState
98 // exception. Calling set_cacheable while this Cache has any
99 // current mappings throws an InvalidState exception.
101 set_cacheable(Cacheable obj);
102 get_cacheable(Cacheable obj out);
104 // Add one or more pages to the cache. Addr must be page-aligned, and
105 // the size of buf must be a multiple of the page size.
107 fill(ulong addr, octet[] buf push) async;
109 // Add one or more zero-filled pages to the cache. The region must
110 // start and end on a page boundary.
112 fill_zero(Region region) async;
114 // Remove one or more pages from the cache. The region must start and
115 // end on a page boundary. It is not an error to remove pages that are
118 remove(Region region);
120 // Wait until all of the pages in the region have been added to the
121 // cache. It is the caller's responsibility to ensure that the adding
122 // has been requested, and that blocking will not cause a deadlock.
123 // If there are multiple pages in the region, it is as if this method
124 // were called sequentially on each page; the kernel will not check
125 // whether previously checked pages have been removed while waiting
128 block_on_region(Region region);
130 // Like block_on_region, but returning a blocker suitable for use
131 // with Thread.block_multi.
133 region_blocker(Region region, Proc.Blocker blocker out);
136 bitfield AllocFlags {
137 Zero, // Zero out any freshly allocated memory.
139 Insecure, // It is not necessary to zero out the page after it
140 // is freed, unless the next allocator requests it.
142 Commit, // Commit the allocation to actual memory or
143 // swap, failing if this cannot be done.
145 Lock, // Only allocate actual memory, and lock it against
146 // swapping. Fails if not enough actual RAM is
147 // available (either in general or in the caller's
148 // locked RAM quota). If Lock is set, Commit is
151 NoZeroLocal, // Accept secure pages from the current address
152 // space without first zeroing. Ignored if Zero is
153 // specified. Overmap should be set to None when
154 // this is used, and every byte should be
155 // overwritten before data in any such pages is
156 // passed to another address space.
158 Paranoid, // Zero pages even when going to a NoZeroLocal allocator
159 // in the current address space. Use this for pages which
160 // are particularly likely to contain sensitive data.
164 Fixed, // Fail if the exact starting address is unavailable.
165 // Otherwise, if the supplied starting address
166 // unavailable, the address space manager allocates a
167 // free region and returns it in "start". If this
168 // behavior is explicitly desired (as it ususally is),
169 // "start" should contain all bits set, which is always
170 // invalid. For non-process (stacked) address spaces,
171 // this flag is treated as always set.
173 Replace, // Atomically replace any existing mapping with the new
174 // mapping, rather than fail. This flag is only
175 // meaningful if Fixed is set.
177 CopyOnWrite, // Share the mapped object only until it is written to;
178 // then, before the write takes place, copy the object.
179 // It is undefined whether this mapping will receive
180 // the copy or the original.
182 Snapshot, // The mapped object will also be made CopyOnWrite, so
183 // that any writes to the mapped page via any mapping
184 // will cause a fault. Thus, after the snapshot, the
185 // only changes that will be visible will be through
186 // the new mapping. This is ideal for things like fork()
187 // and file versioning, and is used by AddrSpace.clone().
189 // If not set, then only the new mapping will be
190 // CopyOnWrite, so if another mapping updates the page
191 // before a write occurs through this mapping (thus
192 // breaking CopyOnWrite), the change will be visible in
193 // the new mapping. This is ideal for private
194 // mappings, where all that is desired is that the new
195 // mapping cannot change the underlying object (while
196 // keeping the mapping writeable).
198 // Ignored if CopyOnWrite is not set.
200 AccessFlags access:3,
201 // These are the requested read/write/execute
202 // permissions on the mapping. A missing permission (or
203 // unmapped page) at any level in an address space stack
204 // will cause a MemoryFault, even if the page is mapped
205 // with the needed permissions at the top level. The
206 // map() call will not fail due to such a condition.
209 None, // Never map non-argument memory to a callee's address
212 ReadOnly, // Allow read-only mappings of non-argument data within
213 // the same page as an argument into the callee's
216 ReadWrite // Allow all mappings of non-argument data within the
217 // same page as an argument into the callee's address
222 interface AddrSpace {
223 guid: "BF9D2070-EAB6-11D9-A2D2-000A95BB581A";
225 const ulong unspecified_start = 0xffffffffffffffff;
227 // Return the mappable associated with this address space, which can
228 // be used to allow another address space to stack with this one.
229 // The mappable handle only allows pages to be mapped; it does not
230 // allow any changes to the mappings, nor can a handle to the AddrSpace
231 // be obtained from it. This method must always return the same
232 // Mappable object when called on the same AddrSpace.
234 get_mappable(Mappable ma out);
236 // Create a new AddrSpace that is a copy-on-write clone of this AddrSpace.
237 // This method is used to implement fork() and in-memory file versioning,
238 // and could also be used to assist garbage collection and other purposes.
240 // By default, the old address space continues to be backed by
241 // whatever Mappables were in use, and pages in the new address space
242 // are backed by anonymous memory when a page in either is written to.
243 // If flags.Reverse is true, though, this is reversed, which is useful
244 // when versioning a file to make the new version the one that gets
247 // The upstream address space is also marked as copy-on
249 clone(AddrSpace addrspace out, CloneFlags flags);
251 bitfield CloneFlags {
255 // Mappable must be implemented by the local kernel, and must hold
256 // read/write/exec permissions appropriate for the MapFlags given.
258 map(Mappable ma, Region region, ulong vstart inout, MapFlags flags);
259 unmap(Region region);
261 // Set the flags on all pages in the region. CopyOnWrite can be
262 // set, but not cleared, using this method. Fixed is ignored.
264 set_mapflags(Region region, MapFlags flags);
266 // Returns the flags on the given region, if all pages have the
267 // same flags (except for CopyOnWrite, which is not returned by
268 // this method, as it can be asynchronously cleared).
270 get_mapflags(Region region, MapFlags flags out, bool all_same out);
272 // Returns the Mappable that covers the specified range, and the offset
273 // into the Mappable that corresponds to the first page in the region.
274 // If any pages within the range are not mapped, or if more than one
275 // Mappable is mapped within the region, or if the offsets into the
276 // Mappable are not contiguous, then NULL is returned in ma.
278 // This is used to implement mremap().
280 get_mapping(Region region, Mappable ma out, ulong offset out);
282 // Returns the minimum page size (and thus mapping size/alignment)
283 // supported in this address space. An attempt to create a mapping
284 // that violates this will result in an InvalidArgument exception.
286 get_page_size(uint page_size out);
288 // Returns the minimum alignment supported for mapping requests;
289 // (vstart % min_align) must equal (region.start % min_align). This
290 // is at least the minimum page size, but may be more on certain
291 // hardware, such as virtually-indexed-physically-tagged caches, where
292 // larger alignment is needed to ensure the absence of cache aliases.
293 // An attempt to create a mapping that violates this will result in an
294 // InvalidArgument exception.
296 get_min_align(uint min_align out);
299 interface AllocHandle {
300 guid: "CB029266-EAB6-11D9-BCA0-000A95BB581A";
302 get_regions(Region[] regions out);
304 // Free a portion of an allocation. To free all of an allocation,
305 // simply release all references to the handle. Each region shall
306 // start and end on block size boundaries. Throws OperationNotSupported
307 // if the allocator does not support partial frees.
309 free(Region[] regions);
312 interface Allocator {
313 guid: "CCF5D83C-EAB6-11D9-8BB7-000A95BB581A";
315 const ulong unspecified_start = 0xffffffffffffffff;
317 bitfield AllocFlags {
318 // If set, fail if the exact starting address is unavailable (or if
319 // the allocator does not support caller-supplied starting
322 // Otherwise, if the supplied starting address unavailable, the
323 // allocator allocates a free region and returns it in "start". If
324 // this behavior is explicitly desired (as it ususally is), "start"
325 // should be set to unspecified_start, which is always invalid.
326 // Using unspecified_start may be faster than specifying other
327 // invalid addresses (as the allocator can check for this value
328 // rather than checking address availability), and zero should not
329 // be used for this purpose as it may be a valid address.
334 alloc(ulong start inout, ulong len, AllocFlags flags,
335 AllocHandle handle out);
338 interface GenericAllocator : Allocator {
339 guid: "D033DD3A-EAB6-11D9-96E4-000A95BB581A";
341 // Set the minimal block size used by the allocator.
342 // This can only be done before any alloc() or
343 // add_regions() calls; an InvalidState exception may
344 // be thrown otherwise.
346 set_block_size(ulong block_size);
348 // Make one or more regions available for allocations.
349 // The regions may not overlap each other or any existing
350 // regions (whether or not allocated). Regions may not
351 // be removed once added using this interface; allocators
352 // may optionally provide a mechanism for doing so.
354 add_regions(Region[] regions);