memmap
| Number | 0x30 |
|---|---|
| Signature | (handle | HANDLE_ANON, size, prot, flags) -> va or -err |
| Group | memory |
| Since | 1.0 |
Map memory into the caller. The first argument selects the backing: HANDLE_ANON for
fresh anonymous pages, or a shared-memory or device handle for an existing object. This one
call replaces the old attach and mapdev.
The three backings behave differently in ways the signature does not show.
Anonymous: size is required, must be non-zero and a multiple of PAGE_SIZE, and is
capped at 32 MB. Pages are demand-paged: the region is recorded with no physical backing and
frames are allocated on fault, one page at a time.
Shared memory: size must be 0; the object’s own page count determines the mapping size,
so it is page-aligned by construction. EXEC is permitted.
Device: size must be 0 and EXEC is rejected. The capability’s size is rounded up to a
page boundary, and the range is mapped eagerly as device memory rather than faulted in.
Anonymous and shared mappings are carved from one address-space cursor; device mappings come
from a second, bounded by USER_DEVICE_LIMIT. The two never interleave.
Pitfalls
The kernel ORs in VM_PROT_USER itself, so a process cannot mint a kernel-privileged
mapping through prot. Passing that bit explicitly is rejected as ERR_BADARG.
Both cursors are bump allocators. Address space is never reclaimed: memunmap releases the
frames but not the virtual range, so a process that maps and unmaps in a loop will eventually
return ERR_NOMEM with most of its address space unused. Long-lived services should reserve
one large region up front and sub-allocate inside it rather than calling memmap repeatedly.
A handle can only be mapped once. A second memmap on the same device or shared-memory
handle returns ERR_BUSY, and it stays busy until memunmap. Two handles to one shared
object map independently, because grant clears the mapped address on the copy it creates.
Anonymous sizes are rejected if they are not page multiples, but device sizes are rounded up
silently. Do not assume the mapping is exactly cap->size bytes.
See Memory for the full model.
Arguments
| Register | Name | Description |
|---|---|---|
r0 | handle | `HANDLE_ANON` for fresh anonymous pages, or a shared-memory or device handle |
r1 | size | Anonymous: non-zero, a multiple of `PAGE_SIZE`, at most 32 MB. Device/SHM: must be 0 |
r2 | prot | `VM_PROT_READ` / `VM_PROT_WRITE` / `VM_PROT_EXEC` only. No other bits, including `VM_PROT_USER` |
r3 | flags | Must be 0 |
Returns
The virtual address of the mapping.
Errors
| Code | Condition |
|---|---|
ERR_BADARG | Non-zero `flags`; `prot` outside READ/WRITE/EXEC; W+X; `EXEC` on a device; anonymous size of 0 or not a multiple of `PAGE_SIZE`; non-zero size for a device or SHM handle |
ERR_OVERFLOW | Anonymous size exceeds 32 MB |
ERR_BADHANDLE | No such handle, or the backing object is null |
ERR_BADTYPE | Handle is neither a device nor a shared-memory object |
ERR_BUSY | That handle is already mapped |
ERR_NOMEM | Address-space cursor exhausted, or the region could not be inserted |