vm: replace vm-region with address-space

address-space is a non-recursive data structure, which contains a flat list of vm_areas representing
mapped vm-objects.

userspace programs can no longer create sub-address-spaces. instead, they can reserve portions of
the address space, and use that reserved space to create mappings.
This commit is contained in:
2026-03-13 19:44:50 +00:00
parent c6b0bee827
commit c628390f4a
28 changed files with 1719 additions and 2612 deletions

View File

@@ -1,134 +1,13 @@
#include <kernel/address-space.h>
#include <kernel/printk.h>
#include <kernel/sched.h>
#include <kernel/syscall.h>
#include <kernel/vm-object.h>
#include <kernel/vm-region.h>
kern_status_t sys_vm_region_create(
kern_handle_t parent,
const char *name,
size_t name_len,
off_t offset,
size_t region_len,
vm_prot_t prot,
kern_handle_t *out,
virt_addr_t *out_base_address)
{
struct task *self = current_task();
if (name_len && !validate_access_r(self, name, name_len)) {
return KERN_MEMORY_FAULT;
}
if (!validate_access_w(self, out, sizeof *out)) {
return KERN_MEMORY_FAULT;
}
if (!validate_access_w(
self,
out_base_address,
sizeof *out_base_address)) {
return KERN_MEMORY_FAULT;
}
unsigned long flags;
task_lock_irqsave(self, &flags);
struct object *obj = NULL;
handle_flags_t handle_flags = 0;
kern_status_t status
= task_resolve_handle(self, parent, &obj, &handle_flags);
if (status != KERN_OK) {
task_unlock_irqrestore(self, flags);
return status;
}
struct vm_region *parent_region = vm_region_cast(obj);
if (!parent_region) {
task_unlock_irqrestore(self, flags);
return KERN_INVALID_ARGUMENT;
}
struct handle *child_handle_slot = NULL;
kern_handle_t child_handle = KERN_HANDLE_INVALID;
status = handle_table_alloc_handle(
self->t_handles,
&child_handle_slot,
&child_handle);
if (status != KERN_OK) {
task_unlock_irqrestore(self, flags);
return status;
}
task_unlock_irqrestore(self, flags);
vm_region_lock_irqsave(parent_region, &flags);
struct vm_region *child = NULL;
status = vm_region_create(
parent_region,
name,
name_len,
offset,
region_len,
prot,
&child);
vm_region_unlock_irqrestore(parent_region, flags);
object_unref(obj);
if (status != KERN_OK) {
task_lock_irqsave(self, &flags);
handle_table_free_handle(self->t_handles, child_handle);
task_unlock_irqrestore(self, flags);
return status;
}
child_handle_slot->h_object = &child->vr_base;
object_add_handle(&child->vr_base);
object_unref(&child->vr_base);
*out = child_handle;
*out_base_address = vm_region_get_base_address(child);
return KERN_OK;
}
kern_status_t sys_vm_region_kill(kern_handle_t region_handle)
{
struct task *self = current_task();
unsigned long flags;
task_lock_irqsave(self, &flags);
struct object *obj = NULL;
handle_flags_t handle_flags = 0;
kern_status_t status
= task_resolve_handle(self, region_handle, &obj, &handle_flags);
if (status != KERN_OK) {
task_unlock_irqrestore(self, flags);
return status;
}
struct vm_region *region = vm_region_cast(obj);
if (!region) {
task_unlock_irqrestore(self, flags);
return KERN_INVALID_ARGUMENT;
}
task_unlock_irqrestore(self, flags);
vm_region_lock_irqsave(region, &flags);
status = vm_region_kill(region, &flags);
vm_region_unlock_irqrestore(region, flags);
object_unref(obj);
return status;
}
kern_status_t sys_vm_region_read(
kern_status_t sys_address_space_read(
kern_handle_t region_handle,
void *dst,
off_t offset,
virt_addr_t base,
size_t count,
size_t *nr_read)
{
@@ -154,7 +33,7 @@ kern_status_t sys_vm_region_read(
return status;
}
struct vm_region *region = vm_region_cast(obj);
struct address_space *region = address_space_cast(obj);
if (!region) {
task_unlock_irqrestore(self, flags);
return KERN_INVALID_ARGUMENT;
@@ -162,23 +41,25 @@ kern_status_t sys_vm_region_read(
task_unlock_irqrestore(self, flags);
virt_addr_t src_address = vm_region_get_base_address(region) + offset;
status = vm_region_memmove(
address_space_lock_irqsave(region, &flags);
status = address_space_memmove(
self->t_address_space,
(virt_addr_t)dst,
region,
src_address,
base,
count,
nr_read);
address_space_unlock_irqrestore(region, flags);
object_unref(obj);
return status;
}
kern_status_t sys_vm_region_write(
kern_status_t sys_address_space_write(
kern_handle_t region_handle,
const void *src,
off_t offset,
virt_addr_t base,
size_t count,
size_t *nr_written)
{
@@ -205,7 +86,7 @@ kern_status_t sys_vm_region_write(
return status;
}
struct vm_region *region = vm_region_cast(obj);
struct address_space *region = address_space_cast(obj);
if (!region) {
task_unlock_irqrestore(self, flags);
return KERN_INVALID_ARGUMENT;
@@ -213,20 +94,22 @@ kern_status_t sys_vm_region_write(
task_unlock_irqrestore(self, flags);
virt_addr_t dst_address = vm_region_get_base_address(region) + offset;
status = vm_region_memmove(
address_space_lock_irqsave(region, &flags);
status = address_space_memmove(
region,
dst_address,
base,
self->t_address_space,
(virt_addr_t)src,
count,
nr_written);
address_space_unlock_irqrestore(region, flags);
object_unref(obj);
return status;
}
kern_status_t sys_vm_region_map_absolute(
kern_status_t sys_address_space_map(
kern_handle_t region_handle,
virt_addr_t map_address,
kern_handle_t object_handle,
@@ -267,7 +150,7 @@ kern_status_t sys_vm_region_map_absolute(
return status;
}
struct vm_region *region = vm_region_cast(region_obj);
struct address_space *region = address_space_cast(region_obj);
if (!region) {
task_unlock_irqrestore(self, flags);
return KERN_INVALID_ARGUMENT;
@@ -280,21 +163,17 @@ kern_status_t sys_vm_region_map_absolute(
}
task_unlock_irqrestore(self, flags);
off_t region_offset = VM_REGION_ANY_OFFSET;
if (map_address != VM_REGION_ANY_OFFSET) {
region_offset
= map_address - vm_region_get_base_address(region);
}
status = vm_region_map_object(
address_space_lock_irqsave(region, &flags);
/* address_space_map will take care of locking `vmo` */
status = address_space_map(
region,
region_offset,
map_address,
vmo,
object_offset,
length,
prot,
out_base_address);
address_space_unlock_irqrestore(region, flags);
object_unref(vmo_obj);
object_unref(region_obj);
@@ -302,23 +181,50 @@ kern_status_t sys_vm_region_map_absolute(
return status;
}
kern_status_t sys_vm_region_map_relative(
kern_status_t sys_address_space_unmap(
kern_handle_t region_handle,
off_t region_offset,
kern_handle_t object_handle,
off_t object_offset,
virt_addr_t base,
size_t length)
{
struct task *self = current_task();
kern_status_t status = KERN_OK;
unsigned long flags;
task_lock_irqsave(self, &flags);
struct object *region_obj = NULL;
handle_flags_t region_flags = 0;
status = task_resolve_handle(
self,
region_handle,
&region_obj,
&region_flags);
if (status != KERN_OK) {
task_unlock_irqrestore(self, flags);
return status;
}
struct address_space *region = address_space_cast(region_obj);
if (!region) {
task_unlock_irqrestore(self, flags);
return KERN_INVALID_ARGUMENT;
}
task_unlock_irqrestore(self, flags);
status = address_space_unmap(region, base, length);
object_unref(region_obj);
return status;
}
kern_status_t sys_address_space_reserve(
kern_handle_t region_handle,
virt_addr_t map_address,
size_t length,
vm_prot_t prot,
virt_addr_t *out_base_address)
{
tracek("vm_region_map_relative(%x, %x, %x, %x, %x, %x, %p)",
region_handle,
region_offset,
object_handle,
object_offset,
length,
prot,
out_base_address);
struct task *self = current_task();
if (out_base_address
@@ -333,8 +239,8 @@ kern_status_t sys_vm_region_map_relative(
unsigned long flags;
task_lock_irqsave(self, &flags);
struct object *region_obj = NULL, *vmo_obj = NULL;
handle_flags_t region_flags = 0, vmo_flags = 0;
struct object *region_obj = NULL;
handle_flags_t region_flags = 0;
status = task_resolve_handle(
self,
region_handle,
@@ -345,45 +251,30 @@ kern_status_t sys_vm_region_map_relative(
return status;
}
status = task_resolve_handle(self, object_handle, &vmo_obj, &vmo_flags);
if (status != KERN_OK) {
task_unlock_irqrestore(self, flags);
return status;
}
struct vm_region *region = vm_region_cast(region_obj);
struct address_space *region = address_space_cast(region_obj);
if (!region) {
task_unlock_irqrestore(self, flags);
return KERN_INVALID_ARGUMENT;
}
struct vm_object *vmo = vm_object_cast(vmo_obj);
if (!vmo) {
task_unlock_irqrestore(self, flags);
return KERN_INVALID_ARGUMENT;
}
task_unlock_irqrestore(self, flags);
status = vm_region_map_object(
address_space_lock_irqsave(region, &flags);
status = address_space_reserve(
region,
region_offset,
vmo,
object_offset,
map_address,
length,
prot,
out_base_address);
address_space_unlock_irqrestore(region, flags);
object_unref(vmo_obj);
object_unref(region_obj);
tracek("result: %u", status);
return status;
}
kern_status_t sys_vm_region_unmap_absolute(
kern_status_t sys_address_space_release(
kern_handle_t region_handle,
virt_addr_t address,
virt_addr_t base,
size_t length)
{
struct task *self = current_task();
@@ -404,7 +295,7 @@ kern_status_t sys_vm_region_unmap_absolute(
return status;
}
struct vm_region *region = vm_region_cast(region_obj);
struct address_space *region = address_space_cast(region_obj);
if (!region) {
task_unlock_irqrestore(self, flags);
return KERN_INVALID_ARGUMENT;
@@ -412,46 +303,9 @@ kern_status_t sys_vm_region_unmap_absolute(
task_unlock_irqrestore(self, flags);
off_t region_offset = address - vm_region_get_base_address(region);
status = vm_region_unmap(region, region_offset, length);
object_unref(region_obj);
return status;
}
kern_status_t sys_vm_region_unmap_relative(
kern_handle_t region_handle,
off_t offset,
size_t length)
{
struct task *self = current_task();
kern_status_t status = KERN_OK;
unsigned long flags;
task_lock_irqsave(self, &flags);
struct object *region_obj = NULL;
handle_flags_t region_flags = 0;
status = task_resolve_handle(
self,
region_handle,
&region_obj,
&region_flags);
if (status != KERN_OK) {
task_unlock_irqrestore(self, flags);
return status;
}
struct vm_region *region = vm_region_cast(region_obj);
if (!region) {
task_unlock_irqrestore(self, flags);
return KERN_INVALID_ARGUMENT;
}
task_unlock_irqrestore(self, flags);
status = vm_region_unmap(region, offset, length);
address_space_lock_irqsave(region, &flags);
status = address_space_unmap(region, base, length);
address_space_unlock_irqrestore(region, flags);
object_unref(region_obj);

View File

@@ -1,6 +1,5 @@
#include <kernel/sched.h>
#include <kernel/syscall.h>
#include <kernel/vm-region.h>
kern_status_t sys_kern_config_get(kern_config_key_t key, void *ptr, size_t len)
{

View File

@@ -15,14 +15,12 @@ static const virt_addr_t syscall_table[] = {
SYSCALL_TABLE_ENTRY(VM_OBJECT_READ, vm_object_read),
SYSCALL_TABLE_ENTRY(VM_OBJECT_WRITE, vm_object_write),
SYSCALL_TABLE_ENTRY(VM_OBJECT_COPY, vm_object_copy),
SYSCALL_TABLE_ENTRY(VM_REGION_CREATE, vm_region_create),
SYSCALL_TABLE_ENTRY(VM_REGION_KILL, vm_region_kill),
SYSCALL_TABLE_ENTRY(VM_REGION_READ, vm_region_read),
SYSCALL_TABLE_ENTRY(VM_REGION_WRITE, vm_region_write),
SYSCALL_TABLE_ENTRY(VM_REGION_MAP_ABSOLUTE, vm_region_map_absolute),
SYSCALL_TABLE_ENTRY(VM_REGION_MAP_RELATIVE, vm_region_map_relative),
SYSCALL_TABLE_ENTRY(VM_REGION_UNMAP_ABSOLUTE, vm_region_unmap_absolute),
SYSCALL_TABLE_ENTRY(VM_REGION_UNMAP_RELATIVE, vm_region_unmap_relative),
SYSCALL_TABLE_ENTRY(ADDRESS_SPACE_READ, address_space_read),
SYSCALL_TABLE_ENTRY(ADDRESS_SPACE_WRITE, address_space_write),
SYSCALL_TABLE_ENTRY(ADDRESS_SPACE_MAP, address_space_map),
SYSCALL_TABLE_ENTRY(ADDRESS_SPACE_UNMAP, address_space_unmap),
SYSCALL_TABLE_ENTRY(ADDRESS_SPACE_RESERVE, address_space_reserve),
SYSCALL_TABLE_ENTRY(ADDRESS_SPACE_RELEASE, address_space_release),
SYSCALL_TABLE_ENTRY(KERN_LOG, kern_log),
SYSCALL_TABLE_ENTRY(KERN_HANDLE_CLOSE, kern_handle_close),
SYSCALL_TABLE_ENTRY(KERN_CONFIG_GET, kern_config_get),

View File

@@ -4,7 +4,6 @@
#include <kernel/sched.h>
#include <kernel/syscall.h>
#include <kernel/task.h>
#include <kernel/vm-region.h>
kern_status_t sys_channel_create(unsigned int id, kern_handle_t *out)
{

View File

@@ -1,10 +1,10 @@
#include <kernel/address-space.h>
#include <kernel/machine/cpu.h>
#include <kernel/printk.h>
#include <kernel/sched.h>
#include <kernel/syscall.h>
#include <kernel/task.h>
#include <kernel/thread.h>
#include <kernel/vm-region.h>
extern kern_status_t sys_task_exit(int status)
{
@@ -128,10 +128,10 @@ kern_status_t sys_task_create(
task_unlock_irqrestore(parent, flags);
child_handle_slot->h_object = &child->t_base;
space_handle_slot->h_object = &child->t_address_space->vr_base;
space_handle_slot->h_object = &child->t_address_space->s_base;
object_add_handle(&child->t_base);
object_add_handle(&child->t_address_space->vr_base);
object_add_handle(&child->t_address_space->s_base);
object_unref(parent_obj);
@@ -252,8 +252,8 @@ kern_status_t sys_task_get_address_space(
return KERN_INVALID_ARGUMENT;
}
handle_slot->h_object = &task->t_address_space->vr_base;
object_add_handle(&task->t_address_space->vr_base);
handle_slot->h_object = &task->t_address_space->s_base;
object_add_handle(&task->t_address_space->s_base);
task_unlock_irqrestore(self, flags);
object_unref(task_obj);

View File

@@ -3,7 +3,6 @@
#include <kernel/sched.h>
#include <kernel/syscall.h>
#include <kernel/vm-object.h>
#include <kernel/vm-region.h>
kern_status_t sys_vm_object_create(
const char *name,