[kernel] Change VMA syscall addr param to inout

This change allows the `vma_map` and `vma_create_map` syscalls to map to
addresses other than the one specified, and therefore makes the address
parameter to those syscalls `inout` in order to return the mapped
address.

Also add the `exact` flag for specifying that mapping needs to be done
at the exact address given. If the mapping collides with another, the
new `j6_err_collision` error is returned.
This commit is contained in:
Justin C. Miller
2023-08-31 19:40:02 -07:00
parent 8cbde13139
commit fc16ed54b3
16 changed files with 93 additions and 69 deletions

View File

@@ -17,13 +17,14 @@ object vma : object {
method create_map [constructor cap:map] { method create_map [constructor cap:map] {
param size size param size size
param address address param address address [inout]
param flags uint32 param flags uint32
} }
method map [cap:map] { method map [cap:map] {
param process ref process [optional] param process ref process [optional]
param address address param address address [inout]
param flags uint32
} }
method unmap [cap:unmap] { method unmap [cap:unmap] {

View File

@@ -100,7 +100,7 @@ load_init_server(bootproto::program &program, uintptr_t modules_address)
((sect.type && section_flags::write) ? vm_flags::write : vm_flags::none); ((sect.type && section_flags::write) ? vm_flags::write : vm_flags::none);
obj::vm_area *vma = new obj::vm_area_fixed(sect.phys_addr, sect.size, flags); obj::vm_area *vma = new obj::vm_area_fixed(sect.phys_addr, sect.size, flags);
space.add(sect.virt_addr, vma); space.add(sect.virt_addr, vma, obj::vm_flags::exact);
} }
uint64_t iopl = (3ull << 12); uint64_t iopl = (3ull << 12);

View File

@@ -102,8 +102,8 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
obj::vm_area *heap_map = new (&g_kernel_heapmap_area) obj::vm_area *heap_map = new (&g_kernel_heapmap_area)
obj::vm_area_untracked(mem::heapmap_size, vm_flags::write); obj::vm_area_untracked(mem::heapmap_size, vm_flags::write);
vm.add(mem::heap_offset, heap); vm.add(mem::heap_offset, heap, vm_flags::exact);
vm.add(mem::heapmap_offset, heap_map); vm.add(mem::heapmap_offset, heap_map, vm_flags::exact);
new (&g_kernel_heap) heap_allocator {mem::heap_offset, mem::heap_size, mem::heapmap_offset}; new (&g_kernel_heap) heap_allocator {mem::heap_offset, mem::heap_size, mem::heapmap_offset};
@@ -111,7 +111,7 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
size_t log_buffer_size = log::log_pages * arch::frame_size; size_t log_buffer_size = log::log_pages * arch::frame_size;
obj::vm_area *logs = new (&g_kernel_log_area) obj::vm_area *logs = new (&g_kernel_log_area)
obj::vm_area_ring(log_buffer_size, vm_flags::write); obj::vm_area_ring(log_buffer_size, vm_flags::write);
vm.add(mem::logs_offset, logs); vm.add(mem::logs_offset, logs, vm_flags::exact);
new (&g_logger) log::logger( new (&g_logger) log::logger(
util::buffer::from(mem::logs_offset, log_buffer_size)); util::buffer::from(mem::logs_offset, log_buffer_size));
@@ -120,7 +120,7 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
obj::vm_area *caps = new (&g_cap_table_area) obj::vm_area *caps = new (&g_cap_table_area)
obj::vm_area_untracked(mem::caps_size, vm_flags::write); obj::vm_area_untracked(mem::caps_size, vm_flags::write);
vm.add(mem::caps_offset, caps); vm.add(mem::caps_offset, caps, vm_flags::exact);
new (&g_cap_table) cap_table {mem::caps_offset}; new (&g_cap_table) cap_table {mem::caps_offset};
@@ -129,7 +129,7 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
mem::kernel_stack_pages, mem::kernel_stack_pages,
mem::stacks_size, mem::stacks_size,
vm_flags::write}; vm_flags::write};
vm.add(mem::stacks_offset, &g_kernel_stacks); vm.add(mem::stacks_offset, &g_kernel_stacks, vm_flags::exact);
// Clean out any remaning bootloader page table entries // Clean out any remaning bootloader page table entries
for (unsigned i = 0; i < arch::kernel_root_index; ++i) for (unsigned i = 0; i < arch::kernel_root_index; ++i)
@@ -140,7 +140,7 @@ void
memory_initialize_post_ctors(bootproto::args &kargs) memory_initialize_post_ctors(bootproto::args &kargs)
{ {
vm_space &vm = vm_space::kernel_space(); vm_space &vm = vm_space::kernel_space();
vm.add(mem::buffers_offset, &g_kernel_buffers); vm.add(mem::buffers_offset, &g_kernel_buffers, vm_flags::exact);
g_frame_allocator.free( g_frame_allocator.free(
get_physical_page(kargs.page_tables.pointer), get_physical_page(kargs.page_tables.pointer),

View File

@@ -58,7 +58,7 @@ start(cpu_data &bsp, void *kpml4)
uintptr_t addr = 0x8000; // TODO: find a valid address, rewrite addresses uintptr_t addr = 0x8000; // TODO: find a valid address, rewrite addresses
isr vector = static_cast<isr>(addr >> 12); isr vector = static_cast<isr>(addr >> 12);
obj::vm_area *vma = new obj::vm_area_fixed(addr, 0x1000, vm_flags::write); obj::vm_area *vma = new obj::vm_area_fixed(addr, 0x1000, vm_flags::write);
vm_space::kernel_space().add(addr, vma); vm_space::kernel_space().add(addr, vma, obj::vm_flags::exact);
memcpy( memcpy(
reinterpret_cast<void*>(addr), reinterpret_cast<void*>(addr),
reinterpret_cast<void*>(&ap_startup), reinterpret_cast<void*>(&ap_startup),

View File

@@ -23,7 +23,7 @@ vma_create(j6_handle_t *self, size_t size, uint32_t flags)
} }
j6_status_t j6_status_t
vma_create_map(j6_handle_t *self, size_t size, uintptr_t base, uint32_t flags) vma_create_map(j6_handle_t *self, size_t size, uintptr_t *base, uint32_t flags)
{ {
vm_area *a = nullptr; vm_area *a = nullptr;
vm_flags f = vm_flags::user_mask & flags; vm_flags f = vm_flags::user_mask & flags;
@@ -32,16 +32,17 @@ vma_create_map(j6_handle_t *self, size_t size, uintptr_t base, uint32_t flags)
else else
a = construct_handle<vm_area_open>(self, size, f); a = construct_handle<vm_area_open>(self, size, f);
process::current().space().add(base, a); *base = process::current().space().add(*base, a, f);
return j6_status_ok; return *base ? j6_status_ok : j6_err_collision;
} }
j6_status_t j6_status_t
vma_map(vm_area *self, process *proc, uintptr_t base) vma_map(vm_area *self, process *proc, uintptr_t *base, uint32_t flags)
{ {
vm_space &space = proc ? proc->space() : process::current().space(); vm_space &space = proc ? proc->space() : process::current().space();
space.add(base, self); vm_flags f = vm_flags::user_mask & flags;
return j6_status_ok; *base = space.add(*base, self, f);
return *base ? j6_status_ok : j6_err_collision;
} }
j6_status_t j6_status_t

View File

@@ -57,7 +57,7 @@ vm_space::vm_space() :
sizeof(system_config), sizeof(system_config),
vm_flags::none); vm_flags::none);
add(sysconf_user_address, sysc); add(sysconf_user_address, sysc, vm_flags::exact);
} }
vm_space::~vm_space() vm_space::~vm_space()
@@ -80,14 +80,34 @@ vm_space::kernel_space()
return obj::process::kernel_process().space(); return obj::process::kernel_process().space();
} }
bool uintptr_t
vm_space::add(uintptr_t base, obj::vm_area *area) vm_space::add(uintptr_t base, obj::vm_area *area, obj::vm_flags flags)
{ {
//TODO: check for collisions if (!base)
base = min_auto_address;
uintptr_t end = base + area->size();
//TODO: optimize find/insert
bool exact = util::bits::has(flags, j6_vm_flag_exact);
for (size_t i = 0; i < m_areas.count(); ++i) {
const vm_space::area &a = m_areas[i];
uintptr_t aend = a.base + a.area->size();
if (base >= aend)
continue;
if (end <= a.base)
break;
else if (exact)
return 0;
else
base = aend;
}
m_areas.sorted_insert({base, area}); m_areas.sorted_insert({base, area});
area->add_to(this); area->add_to(this);
area->handle_retain(); area->handle_retain();
return true; return base;
} }
void void

View File

@@ -4,23 +4,27 @@
#include <stdint.h> #include <stdint.h>
#include <j6/flags.h>
#include <util/enum_bitfields.h> #include <util/enum_bitfields.h>
#include <util/spinlock.h> #include <util/spinlock.h>
#include <util/vector.h> #include <util/vector.h>
#include "objects/vm_area.h"
#include "page_table.h" #include "page_table.h"
struct TCB; struct TCB;
namespace obj { namespace obj {
class process; class process;
class vm_area;
} }
/// Tracks a region of virtual memory address space /// Tracks a region of virtual memory address space
class vm_space class vm_space
{ {
public: public:
/// Never map below this address unless explicitly asked.
static constexpr uintptr_t min_auto_address = 16 * 1024 * 1024; // 16 MiB
/// Constructor for the kernel address space /// Constructor for the kernel address space
/// \arg pml4 The existing kernel PML4 /// \arg pml4 The existing kernel PML4
vm_space(page_table *pml4); vm_space(page_table *pml4);
@@ -33,8 +37,9 @@ public:
/// Add a virtual memorty area to this address space /// Add a virtual memorty area to this address space
/// \arg base The starting address of the area /// \arg base The starting address of the area
/// \arg area The area to add /// \arg area The area to add
/// \returns True if the add succeeded /// \arg flags Flags for the operation (exact, clobber, etc)
bool add(uintptr_t base, obj::vm_area *area); /// \returns The base address the area was added at
uintptr_t add(uintptr_t base, obj::vm_area *area, obj::vm_flags flags);
/// Remove a virtual memory area from this address space /// Remove a virtual memory area from this address space
/// \arg area The area to remove /// \arg area The area to remove

View File

@@ -56,7 +56,7 @@ channel::create(size_t size)
channel_addr += size * 2; // account for ring buffer virtual space doubling channel_addr += size * 2; // account for ring buffer virtual space doubling
lock.release(); lock.release();
result = j6_vma_create_map(&vma, size, addr, j6_vm_flag_write|j6_vm_flag_ring); result = j6_vma_create_map(&vma, size, &addr, j6_vm_flag_write|j6_vm_flag_ring);
if (result != j6_status_ok) { if (result != j6_status_ok) {
syslog("Failed to create channel VMA. Error: %lx", result); syslog("Failed to create channel VMA. Error: %lx", result);
return nullptr; return nullptr;
@@ -77,7 +77,7 @@ channel::open(j6_handle_t vma)
util::scoped_lock lock {addr_spinlock}; util::scoped_lock lock {addr_spinlock};
uintptr_t addr = channel_addr; uintptr_t addr = channel_addr;
result = j6_vma_map(vma, 0, addr); result = j6_vma_map(vma, 0, &addr, 0);
if (result != j6_status_ok) { if (result != j6_status_ok) {
syslog("Failed to map channel VMA. Error: %lx", result); syslog("Failed to map channel VMA. Error: %lx", result);
return nullptr; return nullptr;

View File

@@ -24,4 +24,5 @@
#define j6_err_insufficient j6_err(0x0005) #define j6_err_insufficient j6_err(0x0005)
#define j6_err_timed_out j6_err(0x0006) #define j6_err_timed_out j6_err(0x0006)
#define j6_err_denied j6_err(0x0007) #define j6_err_denied j6_err(0x0007)
#define j6_err_collision j6_err(0x0008)

View File

@@ -12,5 +12,5 @@ enum j6_vm_flags {
enum j6_flags { enum j6_flags {
j6_flag_block = 0x01, j6_flag_block = 0x01,
j6_flags_COUNT // custom per-type flags should start here j6_flags_MAX // custom per-type flags should start here
}; };

View File

@@ -1,10 +1,15 @@
VM_FLAG( none, 0x00000000 ) VM_FLAG( none, 0x00000000 )
VM_FLAG( write, 0x00000001 ) VM_FLAG( write, 0x00000001 )
VM_FLAG( exec, 0x00000002 ) VM_FLAG( exec, 0x00000002 )
VM_FLAG( contiguous, 0x00000020 )
VM_FLAG( large_pages, 0x00000100 )
VM_FLAG( huge_pages, 0x00000200 )
VM_FLAG( write_combine, 0x00001000 )
VM_FLAG( ring, 0x00002000 )
VM_FLAG( mmio, 0x00010000 ) VM_FLAG( contiguous, 0x00000010 )
VM_FLAG( large_pages, 0x00000020 )
VM_FLAG( huge_pages, 0x00000040 )
VM_FLAG( write_combine, 0x00000100 )
VM_FLAG( mmio, 0x00001000 )
VM_FLAG( exact, 0x00010000 )
VM_FLAG( ring, 0x00020000 )

View File

@@ -19,22 +19,25 @@ template <typename Proc>
class thread class thread
{ {
public: public:
static constexpr uintptr_t stack_base_start = 0x7f0'0000'0000;
/// Constructor. Create a thread and its stack space, but /// Constructor. Create a thread and its stack space, but
/// do not start executing the thread. /// do not start executing the thread.
/// \arg p The function where the thread will begin execution /// \arg p The function where the thread will begin execution
/// \arg stack_top The address where the top of this thread's stack should be mapped /// \arg stack_top The address where the top of this thread's stack should be mapped
/// \arg stack_size Size of the stack, in bytes (default 64KiB) /// \arg stack_size Size of the stack, in bytes (default 16MiB)
thread(Proc p, uintptr_t stack_top, size_t stack_size = 0x10000) : thread(Proc p, size_t stack_size = 0x100'0000) :
m_stack {j6_handle_invalid}, m_stack {j6_handle_invalid},
m_thread {j6_handle_invalid}, m_thread {j6_handle_invalid},
m_stack_top {stack_top},
m_proc {p} m_proc {p}
{ {
uintptr_t stack_base = stack_top - stack_size; uintptr_t stack_base = stack_base_start;
m_status = j6_vma_create_map(&m_stack, stack_size, stack_base, j6_vm_flag_write); m_status = j6_vma_create_map(&m_stack, stack_size, &stack_base, j6_vm_flag_write);
if (m_status != j6_status_ok) if (m_status != j6_status_ok)
return; return;
m_stack_top = stack_base + stack_size;
static constexpr size_t zeros_size = 0x10; static constexpr size_t zeros_size = 0x10;
m_stack_top -= zeros_size; // Sentinel m_stack_top -= zeros_size; // Sentinel
memset(reinterpret_cast<void*>(m_stack_top), 0, zeros_size); memset(reinterpret_cast<void*>(m_stack_top), 0, zeros_size);

View File

@@ -1,26 +1,17 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <j6/errors.h>
#include <j6/syscalls.h>
namespace __j6libc { namespace __j6libc {
using j6_status_t = uint64_t;
using j6_handle_t = uint64_t;
constexpr j6_handle_t j6_handle_invalid = -1ull;
constexpr j6_status_t j6_status_ok = 0;
static j6_handle_t core_handle = j6_handle_invalid; static j6_handle_t core_handle = j6_handle_invalid;
static intptr_t core_size = 0; static intptr_t core_size = 0;
static const uintptr_t core_base = 0x1c0000000; static uintptr_t core_base = 0x1c0000000;
static const void *error_val = (void*)-1; static const void *error_val = (void*)-1;
extern "C" {
j6_status_t j6_vma_create_map(j6_handle_t *, size_t, uintptr_t, unsigned);
j6_status_t j6_vma_resize(j6_handle_t, size_t *);
}
void * increase_core(intptr_t i) void * increase_core(intptr_t i)
{ {
if (i == 0) if (i == 0)
@@ -30,7 +21,7 @@ void * increase_core(intptr_t i)
if (i < 0) if (i < 0)
return (void*)-1; return (void*)-1;
j6_status_t result = j6_vma_create_map(&core_handle, i, core_base, 1); j6_status_t result = j6_vma_create_map(&core_handle, i, &core_base, 1);
if (result != j6_status_ok) if (result != j6_status_ok)
return (void*)-1; return (void*)-1;

View File

@@ -55,7 +55,7 @@ main(int argc, const char **argv, const char **env)
return s; return s;
} }
s = j6_vma_map(fb_handle, 0, lfb_addr); s = j6_vma_map(fb_handle, 0, &lfb_addr, j6_vm_flag_exact);
if (s != j6_status_ok) { if (s != j6_status_ok) {
return s; return s;
} }

View File

@@ -10,7 +10,6 @@
static uint64_t initfs_running = 1; static uint64_t initfs_running = 1;
static constexpr size_t buffer_size = 2048; static constexpr size_t buffer_size = 2048;
static constexpr uintptr_t load_addr = 0xf00000000;
j6_status_t j6_status_t
handle_load_request(j6romfs::fs &fs, const char *path, j6_handle_t &vma) handle_load_request(j6romfs::fs &fs, const char *path, j6_handle_t &vma)
@@ -21,7 +20,8 @@ handle_load_request(j6romfs::fs &fs, const char *path, j6_handle_t &vma)
return j6_status_ok; return j6_status_ok;
} }
j6_vma_create_map(&vma, in->size, load_addr, j6_vm_flag_write); uintptr_t load_addr = 0;
j6_vma_create_map(&vma, in->size, &load_addr, j6_vm_flag_write);
util::buffer dest = util::buffer::from(load_addr, in->size); util::buffer dest = util::buffer::from(load_addr, in->size);
fs.load_inode_data(in, dest); fs.load_inode_data(in, dest);
j6_vma_unmap(vma, 0); j6_vma_unmap(vma, 0);

View File

@@ -16,10 +16,9 @@
using bootproto::module; using bootproto::module;
static uintptr_t load_addr = 0xf'000'0000;
static constexpr size_t stack_size = 0x10000;
static constexpr uintptr_t stack_top = 0x80000000000;
static constexpr size_t MiB = 0x10'0000ull; static constexpr size_t MiB = 0x10'0000ull;
static constexpr size_t stack_size = 16 * MiB;
static constexpr uintptr_t stack_top = 0x7f0'0000'0000;
inline uintptr_t align_up(uintptr_t a) { return ((a-1) & ~(MiB-1)) + MiB; } inline uintptr_t align_up(uintptr_t a) { return ((a-1) & ~(MiB-1)) + MiB; }
@@ -31,7 +30,7 @@ map_phys(j6_handle_t sys, uintptr_t phys, size_t len, j6_vm_flags flags)
if (res != j6_status_ok) if (res != j6_status_ok)
return j6_handle_invalid; return j6_handle_invalid;
res = j6_vma_map(vma, 0, phys); res = j6_vma_map(vma, 0, &phys, j6_vm_flag_exact);
if (res != j6_status_ok) if (res != j6_status_ok)
return j6_handle_invalid; return j6_handle_invalid;
@@ -72,8 +71,7 @@ load_program_into(j6_handle_t proc, elf::file &file, uintptr_t image_base, const
if (seg.type != elf::segment_type::load) if (seg.type != elf::segment_type::load)
continue; continue;
uintptr_t addr = load_addr; uintptr_t addr = 0;
load_addr = align_up(load_addr + seg.mem_size);
// TODO: way to remap VMA as read-only if there's no write flag on // TODO: way to remap VMA as read-only if there's no write flag on
// the segment // the segment
@@ -86,7 +84,7 @@ load_program_into(j6_handle_t proc, elf::file &file, uintptr_t image_base, const
size_t epilogue = seg.mem_size - seg.file_size; size_t epilogue = seg.mem_size - seg.file_size;
j6_handle_t sub_vma = j6_handle_invalid; j6_handle_t sub_vma = j6_handle_invalid;
j6_status_t res = j6_vma_create_map(&sub_vma, seg.mem_size+prologue, addr, flags); j6_status_t res = j6_vma_create_map(&sub_vma, seg.mem_size+prologue, &addr, flags);
if (res != j6_status_ok) { if (res != j6_status_ok) {
j6::syslog(" ** error loading ELF '%s': creating sub vma: %lx", path, res); j6::syslog(" ** error loading ELF '%s': creating sub vma: %lx", path, res);
return 0; return 0;
@@ -102,9 +100,9 @@ load_program_into(j6_handle_t proc, elf::file &file, uintptr_t image_base, const
if (eos > eop) if (eos > eop)
eop = eos; eop = eos;
uintptr_t start_addr = (image_base + seg.vaddr); uintptr_t start_addr = (image_base + seg.vaddr) & ~0xfffull;
j6::syslog("Mapping segment from %s at %012lx - %012lx", path, start_addr, start_addr+seg.mem_size); j6::syslog("Mapping segment from %s at %012lx - %012lx", path, start_addr, start_addr+seg.mem_size);
res = j6_vma_map(sub_vma, proc, start_addr & ~0xfffull); res = j6_vma_map(sub_vma, proc, &start_addr, j6_vm_flag_exact);
if (res != j6_status_ok) { if (res != j6_status_ok) {
j6::syslog(" ** error loading ELF '%s': mapping sub vma to child: %lx", path, res); j6::syslog(" ** error loading ELF '%s': mapping sub vma to child: %lx", path, res);
return 0; return 0;
@@ -193,10 +191,9 @@ load_program(
if (!eop) if (!eop)
return false; return false;
uintptr_t stack_addr = load_addr; uintptr_t stack_addr = 0;
load_addr = align_up(load_addr + stack_size);
j6_handle_t stack_vma = j6_handle_invalid; j6_handle_t stack_vma = j6_handle_invalid;
j6_status_t res = j6_vma_create_map(&stack_vma, stack_size, stack_addr, j6_vm_flag_write); j6_status_t res = j6_vma_create_map(&stack_vma, stack_size, &stack_addr, j6_vm_flag_write);
if (res != j6_status_ok) { if (res != j6_status_ok) {
j6::syslog(" ** error loading program '%s': creating stack vma: %lx", path, res); j6::syslog(" ** error loading program '%s': creating stack vma: %lx", path, res);
return false; return false;
@@ -223,9 +220,8 @@ load_program(
const elf::file_header *h = program_elf.header(); const elf::file_header *h = program_elf.header();
loader_arg->image_base = program_image_base; loader_arg->image_base = program_image_base;
loader_arg->phdr = h->ph_offset; loader_arg->phdr = h->ph_offset;
loader_arg->phdr_size = h->ph_entsize;
loader_arg->phdr_count = h->ph_num; loader_arg->phdr_count = h->ph_num;
loader_arg->entrypoint = program_elf.entrypoint(); loader_arg->entrypoint = entrypoint;
j6_arg_handles *handles_arg = stack_push<j6_arg_handles>(stack, 2 * sizeof(j6_arg_handle_entry)); j6_arg_handles *handles_arg = stack_push<j6_arg_handles>(stack, 2 * sizeof(j6_arg_handle_entry));
handles_arg->nhandles = 1; handles_arg->nhandles = 1;
@@ -258,7 +254,8 @@ load_program(
} }
} }
res = j6_vma_map(stack_vma, proc, stack_top-stack_size); uintptr_t stack_base = stack_top-stack_size;
res = j6_vma_map(stack_vma, proc, &stack_base, j6_vm_flag_exact);
if (res != j6_status_ok) { if (res != j6_status_ok) {
j6::syslog(" ** error loading program '%s': mapping stack vma: %lx", path, res); j6::syslog(" ** error loading program '%s': mapping stack vma: %lx", path, res);
return false; return false;