|
PatchworkOS
c9fea19
A non-POSIX operating system.
|
Address Space handling. More...
Address Space handling.
Data Structures | |
| struct | space_callback_t |
| struct | space_pinned_page_t |
| Pinned page structure. More... | |
| struct | space_t |
| Virtual address space structure. More... | |
| struct | space_mapping_t |
| Helper structure for managing address space mappings. More... | |
| struct | vmm_callback_t |
| Space callback structure. More... | |
Macros | |
| #define | SPACE_TLB_SHOOTDOWN_TIMEOUT (CLOCKS_PER_SEC) |
| The maximum time to wait for the acknowledgements from other CPU's before panicking. | |
Typedefs | |
| typedef void(* | space_callback_func_t) (void *private) |
| Space callback function. | |
Enumerations | |
| enum | space_flags_t { SPACE_NONE = 0 , SPACE_USE_PMM_BITMAP = 1 << 0 , SPACE_MAP_KERNEL_BINARY = 1 << 1 , SPACE_MAP_KERNEL_HEAP = 1 << 2 , SPACE_MAP_IDENTITY = 1 << 3 } |
| Flags for space initialization. More... | |
Functions | |
| uint64_t | space_init (space_t *space, uintptr_t startAddress, uintptr_t endAddress, space_flags_t flags) |
| Initializes a virtual address space. | |
| void | space_deinit (space_t *space) |
| Deinitializes a virtual address space. | |
| void | space_load (space_t *space) |
| Loads a virtual address space. | |
| uint64_t | space_pin (space_t *space, const void *address, uint64_t length, stack_pointer_t *userStack) |
| Pins pages within a region of the address space. | |
| uint64_t | space_pin_terminated (space_t *space, const void *address, const void *terminator, uint8_t objectSize, uint64_t maxCount, stack_pointer_t *userStack) |
| Pins a region of memory terminated by a terminator value. | |
| void | space_unpin (space_t *space, const void *address, uint64_t length) |
Unpins pages in a region previously pinned with space_pin() or space_pin_string(). | |
| uint64_t | space_check_access (space_t *space, const void *addr, uint64_t length) |
| Checks if a virtual memory region is within the allowed address range of the space. | |
| uint64_t | space_mapping_start (space_t *space, space_mapping_t *mapping, void *virtAddr, void *physAddr, uint64_t length, pml_flags_t flags) |
| Prepare for changes to the address space mappings. | |
| pml_callback_id_t | space_alloc_callback (space_t *space, uint64_t pageAmount, space_callback_func_t func, void *private) |
| Allocate a callback. | |
| void | space_free_callback (space_t *space, pml_callback_id_t callbackId) |
| Free a callback. | |
| void | space_tlb_shootdown (space_t *space, void *virtAddr, uint64_t pageAmount) |
| Performs a TLB shootdown for a region of the address space, and wait for acknowledgements. | |
| void * | space_mapping_end (space_t *space, space_mapping_t *mapping, errno_t err) |
| Performs cleanup after changes to the address space mappings. | |
| bool | space_is_mapped (space_t *space, const void *virtAddr, uint64_t length) |
| Checks if a virtual memory region is fully mapped. | |
| uint64_t | space_user_page_count (space_t *space) |
| Get the number of user pages allocated in the address space. | |
| #define SPACE_TLB_SHOOTDOWN_TIMEOUT (CLOCKS_PER_SEC) |
| typedef void(* space_callback_func_t) (void *private) |
| enum space_flags_t |
Flags for space initialization.
| uint64_t space_init | ( | space_t * | space, |
| uintptr_t | startAddress, | ||
| uintptr_t | endAddress, | ||
| space_flags_t | flags | ||
| ) |
Initializes a virtual address space.
| space | The address space to initialize. |
| startAddress | The starting address for allocations in this address space. |
| endAddress | The ending address for allocations in this address space. |
| flags | Flags to control the initialization behavior. |
0. On failure, ERR and errno is set to:EINVAL: Invalid parameters.ENOMEM: Not enough memory to initialize the address space. Definition at line 64 of file space.c.
| void space_deinit | ( | space_t * | space | ) |
| void space_load | ( | space_t * | space | ) |
| uint64_t space_pin | ( | space_t * | space, |
| const void * | address, | ||
| uint64_t | length, | ||
| stack_pointer_t * | userStack | ||
| ) |
Pins pages within a region of the address space.
Used to prevent TOCTOU attacks, where a system call provides some user space region, the kernel then checks that its mapped and after that check a seperate thread in the user space process unmaps or modifies that regions mappings while the kernel is still using it.
Our solution is to pin any user space pages that are accessed or modified during the syscall, meaning that a special flag is set in the address spaces page tables that prevent those pages from being unmapped or modified until they are unpinned which happens when the syscall is finished in space_unpin().
If the region is not fully mapped, or the region is not within the spaces startAddress and endAddress range, the function will fail.
If any page in the region is already at its maximum pin depth, the calling thread will block until the page is unpinned by another thread.
If a user stack is provided and the region to pin is both unmapped and within the stack region, memory will be allocated and mapped to the relevant region in the user stack. This is needed as its possible for a user space process to pass an address to a system call that is in its user stack but not yet mapped. For example, it could create a big buffer on its stack then pass it to a syscall without first accessing it, meaning no page fault would have occurred to map the pages.
| space | The target address space. |
| address | The address to pin, can be NULL if length is 0. |
| length | The length of the region pointed to by address, in bytes. |
| userStack | Pointer to the user stack of the calling thread, can be NULL, see above. @return On success,0. On failure,ERRanderrnois set to: -EINVAL: Invalid parameters. -EOVERFLOW: Address overflow. -EFAULT: The region is not fully mapped or within the provided user stack. -ENOMEM`: Not enough memory. |
Definition at line 330 of file space.c.
| uint64_t space_pin_terminated | ( | space_t * | space, |
| const void * | address, | ||
| const void * | terminator, | ||
| uint8_t | objectSize, | ||
| uint64_t | maxCount, | ||
| stack_pointer_t * | userStack | ||
| ) |
Pins a region of memory terminated by a terminator value.
Pins pages in the address space starting from address up to maxSize bytes or until the specified terminator is found.
Used for null-terminated strings or other buffers that have a specific terminator.
| space | The target address space. |
| address | The starting address of the region to pin. |
| terminator | The terminator value to search for. |
| objectSize | The size of each object to compare against the terminator, in bytes. |
| maxCount | The maximum number of objects to scan before failing. |
| userStack | Pointer to the user stack of the calling thread, can be NULL, see space_pin(). |
ERR and errno is set to:EINVAL: Invalid parameters.EOVERFLOW: Address overflow.EFAULT: The region is not fully mapped or within the provided user stack.ENOMEM: Not enough memory. Definition at line 379 of file space.c.
Unpins pages in a region previously pinned with space_pin() or space_pin_string().
Will wake up any threads waiting to pin the same pages.
| space | The target address space. |
| address | The address of the region to unpin, can be NULL if length is 0. |
| length | The length of the region pointed to by address, in bytes. |
Definition at line 452 of file space.c.
Checks if a virtual memory region is within the allowed address range of the space.
Checks that the given memory region is within the startAddress and endAddress range of the space, really only used in system calls that might access unmapped user space memory for example mmap(), in such cases we dont want to pin the "buffer" since we expect that it is not yet mapped.
| space | The target address space. |
| addr | The starting address of the memory region, can be NULL if length is 0. |
| length | The length of the memory region, in bytes. |
0. On failure, ERR and errno is set to:EINVAL: Invalid parameters.EOVERFLOW: Address overflow.EFAULT: The region is outside the allowed address range. Definition at line 478 of file space.c.
| uint64_t space_mapping_start | ( | space_t * | space, |
| space_mapping_t * | mapping, | ||
| void * | virtAddr, | ||
| void * | physAddr, | ||
| uint64_t | length, | ||
| pml_flags_t | flags | ||
| ) |
Prepare for changes to the address space mappings.
Will return with the spaces mutex acquired for writing, which must be released by calling space_mapping_end().
If flags & PML_USER then the addresses must be in the user space range.
stack_pointer_poke() to ensure that sufficient stack space is available.| space | The target address space. |
| mapping | Will be filled with parsed information about the mapping. |
| virtAddr | The virtual address the mapping will apply to. Can be NULL to let the kernel choose an address. |
| physAddr | The physical address to map from. Can be NULL. |
| length | The length of the virtual memory region to modify, in bytes. |
| flags | The page table flags for the mapping. |
0. On failure, ERR and errno is set to:EINVAL: Invalid parameters.EOVERFLOW: Address overflow.EFAULT: The addresses are outside the allowed range.ENOMEM: Not enough memory. Definition at line 528 of file space.c.
| pml_callback_id_t space_alloc_callback | ( | space_t * | space, |
| uint64_t | pageAmount, | ||
| space_callback_func_t | func, | ||
| void * | private | ||
| ) |
Allocate a callback.
Must be called between space_mapping_start() and space_mapping_end().
When pageAmount number of pages with this callback ID are unmapped or the address space is freed, the callback function will be called with the provided private data.
| space | The target address space. |
| pageAmount | The number of pages the callback is responsible for. |
| func | The callback function. |
| private | Private data to pass to the callback function. |
PML_MAX_CALLBACK. Definition at line 598 of file space.c.
| void space_free_callback | ( | space_t * | space, |
| pml_callback_id_t | callbackId | ||
| ) |
Free a callback.
Must be called between space_mapping_start() and space_mapping_end().
Allows the callback ID to be reused. The callback function will not be called.
| space | The target address space. |
| callbackId | The callback ID to free. |
Definition at line 639 of file space.c.
Performs a TLB shootdown for a region of the address space, and wait for acknowledgements.
Must be called between space_mapping_start() and space_mapping_end().
This will cause all CPUs that have the address space loaded to invalidate their TLB entries for the specified region.
Will not affect the current CPU's TLB, that is handled by the page_table_t directly when modifying page table entries.
| space | The target address space. |
| virtAddr | The starting virtual address of the region. |
| pageAmount | The number of pages in the region. |
Definition at line 669 of file space.c.
| void * space_mapping_end | ( | space_t * | space, |
| space_mapping_t * | mapping, | ||
| errno_t | err | ||
| ) |
Performs cleanup after changes to the address space mappings.
Must be called after space_mapping_start().
| space | The target address space. |
| mapping | The parsed information about the mapping. |
| err | The error code, if 0 then no error. |
err is EOK, returns the virtual address of the mapping. If err is not EOK, returns NULL and errno is set to err. Definition at line 739 of file space.c.
Checks if a virtual memory region is fully mapped.
| space | The target address space. |
| virtAddr | The virtual address of the memory region. |
| length | The length of the memory region, in bytes. |
true if the entire region is mapped, false otherwise. Definition at line 759 of file space.c.
Get the number of user pages allocated in the address space.
Will count the number of pages with the PML_OWNED flag set in user space.
| space | The target address space. |
Definition at line 766 of file space.c.