From fc16ed54b351aa61af45c9c28ba9bfa6da64dd55 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Thu, 31 Aug 2023 19:40:02 -0700 Subject: [PATCH] [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. --- definitions/objects/vma.def | 5 ++-- src/kernel/kernel_main.cpp | 2 +- src/kernel/memory_bootstrap.cpp | 12 ++++---- src/kernel/smp.cpp | 2 +- src/kernel/syscalls/vm_area.cpp | 13 ++++---- src/kernel/vm_space.cpp | 30 +++++++++++++++---- src/kernel/vm_space.h | 11 +++++-- src/libraries/j6/channel.cpp | 4 +-- src/libraries/j6/include/j6/errors.h | 1 + src/libraries/j6/include/j6/flags.h | 2 +- .../j6/include/j6/tables/vm_flags.inc | 17 +++++++---- src/libraries/j6/include/j6/thread.hh | 13 ++++---- src/libraries/libc/__j6libc/increase_core.cpp | 17 +++-------- src/user/drv.uefi_fb/main.cpp | 2 +- src/user/srv.init/initfs.cpp | 4 +-- src/user/srv.init/loader.cpp | 27 ++++++++--------- 16 files changed, 93 insertions(+), 69 deletions(-) diff --git a/definitions/objects/vma.def b/definitions/objects/vma.def index 52f9f4b..7a0dd28 100644 --- a/definitions/objects/vma.def +++ b/definitions/objects/vma.def @@ -17,13 +17,14 @@ object vma : object { method create_map [constructor cap:map] { param size size - param address address + param address address [inout] param flags uint32 } method map [cap:map] { param process ref process [optional] - param address address + param address address [inout] + param flags uint32 } method unmap [cap:unmap] { diff --git a/src/kernel/kernel_main.cpp b/src/kernel/kernel_main.cpp index 2947aa6..97b4198 100644 --- a/src/kernel/kernel_main.cpp +++ b/src/kernel/kernel_main.cpp @@ -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); 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); diff --git a/src/kernel/memory_bootstrap.cpp b/src/kernel/memory_bootstrap.cpp index c0fc967..d596192 100644 --- a/src/kernel/memory_bootstrap.cpp +++ b/src/kernel/memory_bootstrap.cpp @@ -102,8 +102,8 @@ memory_initialize_pre_ctors(bootproto::args &kargs) obj::vm_area *heap_map = new (&g_kernel_heapmap_area) obj::vm_area_untracked(mem::heapmap_size, vm_flags::write); - vm.add(mem::heap_offset, heap); - vm.add(mem::heapmap_offset, heap_map); + vm.add(mem::heap_offset, heap, vm_flags::exact); + 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}; @@ -111,7 +111,7 @@ memory_initialize_pre_ctors(bootproto::args &kargs) size_t log_buffer_size = log::log_pages * arch::frame_size; obj::vm_area *logs = new (&g_kernel_log_area) 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( 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_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}; @@ -129,7 +129,7 @@ memory_initialize_pre_ctors(bootproto::args &kargs) mem::kernel_stack_pages, mem::stacks_size, 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 for (unsigned i = 0; i < arch::kernel_root_index; ++i) @@ -140,7 +140,7 @@ void memory_initialize_post_ctors(bootproto::args &kargs) { 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( get_physical_page(kargs.page_tables.pointer), diff --git a/src/kernel/smp.cpp b/src/kernel/smp.cpp index 5eca86d..edebcb6 100644 --- a/src/kernel/smp.cpp +++ b/src/kernel/smp.cpp @@ -58,7 +58,7 @@ start(cpu_data &bsp, void *kpml4) uintptr_t addr = 0x8000; // TODO: find a valid address, rewrite addresses isr vector = static_cast(addr >> 12); 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( reinterpret_cast(addr), reinterpret_cast(&ap_startup), diff --git a/src/kernel/syscalls/vm_area.cpp b/src/kernel/syscalls/vm_area.cpp index 6cd874d..b7a21d2 100644 --- a/src/kernel/syscalls/vm_area.cpp +++ b/src/kernel/syscalls/vm_area.cpp @@ -23,7 +23,7 @@ vma_create(j6_handle_t *self, size_t size, uint32_t flags) } 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_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 a = construct_handle(self, size, f); - process::current().space().add(base, a); - return j6_status_ok; + *base = process::current().space().add(*base, a, f); + return *base ? j6_status_ok : j6_err_collision; } 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(); - space.add(base, self); - return j6_status_ok; + vm_flags f = vm_flags::user_mask & flags; + *base = space.add(*base, self, f); + return *base ? j6_status_ok : j6_err_collision; } j6_status_t diff --git a/src/kernel/vm_space.cpp b/src/kernel/vm_space.cpp index 9df3a5a..011b054 100644 --- a/src/kernel/vm_space.cpp +++ b/src/kernel/vm_space.cpp @@ -57,7 +57,7 @@ vm_space::vm_space() : sizeof(system_config), vm_flags::none); - add(sysconf_user_address, sysc); + add(sysconf_user_address, sysc, vm_flags::exact); } vm_space::~vm_space() @@ -80,14 +80,34 @@ vm_space::kernel_space() return obj::process::kernel_process().space(); } -bool -vm_space::add(uintptr_t base, obj::vm_area *area) +uintptr_t +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}); area->add_to(this); area->handle_retain(); - return true; + return base; } void diff --git a/src/kernel/vm_space.h b/src/kernel/vm_space.h index a83319f..ec5044e 100644 --- a/src/kernel/vm_space.h +++ b/src/kernel/vm_space.h @@ -4,23 +4,27 @@ #include +#include #include #include #include +#include "objects/vm_area.h" #include "page_table.h" struct TCB; namespace obj { class process; - class vm_area; } /// Tracks a region of virtual memory address space class vm_space { 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 /// \arg pml4 The existing kernel PML4 vm_space(page_table *pml4); @@ -33,8 +37,9 @@ public: /// Add a virtual memorty area to this address space /// \arg base The starting address of the area /// \arg area The area to add - /// \returns True if the add succeeded - bool add(uintptr_t base, obj::vm_area *area); + /// \arg flags Flags for the operation (exact, clobber, etc) + /// \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 /// \arg area The area to remove diff --git a/src/libraries/j6/channel.cpp b/src/libraries/j6/channel.cpp index d3e4ceb..2efe01e 100644 --- a/src/libraries/j6/channel.cpp +++ b/src/libraries/j6/channel.cpp @@ -56,7 +56,7 @@ channel::create(size_t size) channel_addr += size * 2; // account for ring buffer virtual space doubling 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) { syslog("Failed to create channel VMA. Error: %lx", result); return nullptr; @@ -77,7 +77,7 @@ channel::open(j6_handle_t vma) util::scoped_lock lock {addr_spinlock}; 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) { syslog("Failed to map channel VMA. Error: %lx", result); return nullptr; diff --git a/src/libraries/j6/include/j6/errors.h b/src/libraries/j6/include/j6/errors.h index e184950..01549b7 100644 --- a/src/libraries/j6/include/j6/errors.h +++ b/src/libraries/j6/include/j6/errors.h @@ -24,4 +24,5 @@ #define j6_err_insufficient j6_err(0x0005) #define j6_err_timed_out j6_err(0x0006) #define j6_err_denied j6_err(0x0007) +#define j6_err_collision j6_err(0x0008) diff --git a/src/libraries/j6/include/j6/flags.h b/src/libraries/j6/include/j6/flags.h index 66c3331..0d7e91c 100644 --- a/src/libraries/j6/include/j6/flags.h +++ b/src/libraries/j6/include/j6/flags.h @@ -12,5 +12,5 @@ enum j6_vm_flags { enum j6_flags { j6_flag_block = 0x01, - j6_flags_COUNT // custom per-type flags should start here + j6_flags_MAX // custom per-type flags should start here }; diff --git a/src/libraries/j6/include/j6/tables/vm_flags.inc b/src/libraries/j6/include/j6/tables/vm_flags.inc index 75be880..1ced26d 100644 --- a/src/libraries/j6/include/j6/tables/vm_flags.inc +++ b/src/libraries/j6/include/j6/tables/vm_flags.inc @@ -1,10 +1,15 @@ VM_FLAG( none, 0x00000000 ) + VM_FLAG( write, 0x00000001 ) 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 ) \ No newline at end of file diff --git a/src/libraries/j6/include/j6/thread.hh b/src/libraries/j6/include/j6/thread.hh index 615090b..f61f222 100644 --- a/src/libraries/j6/include/j6/thread.hh +++ b/src/libraries/j6/include/j6/thread.hh @@ -19,22 +19,25 @@ template class thread { public: + static constexpr uintptr_t stack_base_start = 0x7f0'0000'0000; + /// Constructor. Create a thread and its stack space, but /// do not start executing the thread. /// \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_size Size of the stack, in bytes (default 64KiB) - thread(Proc p, uintptr_t stack_top, size_t stack_size = 0x10000) : + /// \arg stack_size Size of the stack, in bytes (default 16MiB) + thread(Proc p, size_t stack_size = 0x100'0000) : m_stack {j6_handle_invalid}, m_thread {j6_handle_invalid}, - m_stack_top {stack_top}, m_proc {p} { - uintptr_t stack_base = stack_top - stack_size; - m_status = j6_vma_create_map(&m_stack, stack_size, stack_base, j6_vm_flag_write); + uintptr_t stack_base = stack_base_start; + m_status = j6_vma_create_map(&m_stack, stack_size, &stack_base, j6_vm_flag_write); if (m_status != j6_status_ok) return; + m_stack_top = stack_base + stack_size; + static constexpr size_t zeros_size = 0x10; m_stack_top -= zeros_size; // Sentinel memset(reinterpret_cast(m_stack_top), 0, zeros_size); diff --git a/src/libraries/libc/__j6libc/increase_core.cpp b/src/libraries/libc/__j6libc/increase_core.cpp index eb847ad..f23cb8c 100644 --- a/src/libraries/libc/__j6libc/increase_core.cpp +++ b/src/libraries/libc/__j6libc/increase_core.cpp @@ -1,26 +1,17 @@ #include #include +#include +#include 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 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; -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) { if (i == 0) @@ -30,7 +21,7 @@ void * increase_core(intptr_t i) if (i < 0) 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) return (void*)-1; diff --git a/src/user/drv.uefi_fb/main.cpp b/src/user/drv.uefi_fb/main.cpp index c28bdbe..27c9b30 100644 --- a/src/user/drv.uefi_fb/main.cpp +++ b/src/user/drv.uefi_fb/main.cpp @@ -55,7 +55,7 @@ main(int argc, const char **argv, const char **env) 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) { return s; } diff --git a/src/user/srv.init/initfs.cpp b/src/user/srv.init/initfs.cpp index 104f0be..4bd3a28 100644 --- a/src/user/srv.init/initfs.cpp +++ b/src/user/srv.init/initfs.cpp @@ -10,7 +10,6 @@ static uint64_t initfs_running = 1; static constexpr size_t buffer_size = 2048; -static constexpr uintptr_t load_addr = 0xf00000000; j6_status_t 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; } - 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); fs.load_inode_data(in, dest); j6_vma_unmap(vma, 0); diff --git a/src/user/srv.init/loader.cpp b/src/user/srv.init/loader.cpp index 5f00080..0cb0770 100644 --- a/src/user/srv.init/loader.cpp +++ b/src/user/srv.init/loader.cpp @@ -16,10 +16,9 @@ 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 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; } @@ -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) 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) 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) continue; - uintptr_t addr = load_addr; - load_addr = align_up(load_addr + seg.mem_size); + uintptr_t addr = 0; // TODO: way to remap VMA as read-only if there's no write flag on // 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; 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) { j6::syslog(" ** error loading ELF '%s': creating sub vma: %lx", path, res); return 0; @@ -102,9 +100,9 @@ load_program_into(j6_handle_t proc, elf::file &file, uintptr_t image_base, const if (eos > eop) 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); - 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) { j6::syslog(" ** error loading ELF '%s': mapping sub vma to child: %lx", path, res); return 0; @@ -193,10 +191,9 @@ load_program( if (!eop) return false; - uintptr_t stack_addr = load_addr; - load_addr = align_up(load_addr + stack_size); + uintptr_t stack_addr = 0; 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) { j6::syslog(" ** error loading program '%s': creating stack vma: %lx", path, res); return false; @@ -223,9 +220,8 @@ load_program( const elf::file_header *h = program_elf.header(); loader_arg->image_base = program_image_base; loader_arg->phdr = h->ph_offset; - loader_arg->phdr_size = h->ph_entsize; loader_arg->phdr_count = h->ph_num; - loader_arg->entrypoint = program_elf.entrypoint(); + loader_arg->entrypoint = entrypoint; j6_arg_handles *handles_arg = stack_push(stack, 2 * sizeof(j6_arg_handle_entry)); 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) { j6::syslog(" ** error loading program '%s': mapping stack vma: %lx", path, res); return false;