From 0e80c19d3dd7fe6f6c4550de0c4d5d9edd2ba763 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Thu, 3 Feb 2022 19:45:46 -0800 Subject: [PATCH] [kernel] Add test mode, controlled by manifest The manifest can now supply a list of boot flags, including "test". Those get turned into the bootproto::args::flags field by the bootloader. The kernel takes those and uses the test flag to control enabling syscalls with the new "test" attribute, like the new test_finish syscall, which lets automated tests call back to the kernel to shut down the system. --- assets/manifests/test.yaml | 8 ++++++++ definitions/syscalls.def | 5 +++++ scripts/bonnibel/manifest.py | 11 ++++++++++- src/boot/bootconfig.cpp | 3 ++- src/boot/bootconfig.h | 6 ++++-- src/boot/main.cpp | 1 + src/kernel/cpu.cpp | 2 -- src/kernel/main.cpp | 5 +++++ src/kernel/syscall.cpp.cog | 15 ++++++++++++--- src/kernel/syscall.h.cog | 2 +- src/kernel/syscalls/system.cpp | 8 ++++++++ .../bootproto/include/bootproto/kernel.h | 4 +++- 12 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 assets/manifests/test.yaml diff --git a/assets/manifests/test.yaml b/assets/manifests/test.yaml new file mode 100644 index 0000000..55cb4f7 --- /dev/null +++ b/assets/manifests/test.yaml @@ -0,0 +1,8 @@ +--- +init: srv.init +flags: ["test"] +programs: + - name: panic.serial + target: kernel + flags: panic + - name: drv.uart diff --git a/definitions/syscalls.def b/definitions/syscalls.def index 42dbfde..67b7fb6 100644 --- a/definitions/syscalls.def +++ b/definitions/syscalls.def @@ -42,4 +42,9 @@ interface syscalls [syscall] { param clone ref object [out] # The new handle param mask uint32 # The capability bitmask } + + # Testing mode only: Have the kernel finish and exit QEMU with the given exit code + function test_finish [test] { + param exit_code uint32 + } } diff --git a/scripts/bonnibel/manifest.py b/scripts/bonnibel/manifest.py index 70d4902..6ca161f 100644 --- a/scripts/bonnibel/manifest.py +++ b/scripts/bonnibel/manifest.py @@ -10,6 +10,11 @@ class Manifest: "symbols": 0x04, } + boot_flags = { + "debug": 0x01, + "test": 0x02, + } + def __init__(self, path, modules): from . import load_config @@ -25,6 +30,8 @@ class Manifest: self.programs = [self.__build_entry(modules, i) for i in config.get("programs", tuple())] + self.flags = config.get("flags", tuple()) + self.data = [] for d in config.get("data", tuple()): self.add_data(**d) @@ -65,10 +72,12 @@ class Manifest: version = 0 reserved = 0 + bootflags = sum([Manifest.boot_flags.get(s, 0) for s in self.flags]) + outfile.write(struct.pack("<8sBBHHH", magic, version, reserved, len(self.programs), len(self.data), - reserved)) + bootflags)) def write_str(s): outfile.write(struct.pack("(data); uint16_t num_data = *util::read(data); - data += 2; // reserved short + + m_flags = *util::read(data); read_descriptor(m_kernel, data); read_descriptor(m_init, data); diff --git a/src/boot/bootconfig.h b/src/boot/bootconfig.h index 588510d..a5a8cf5 100644 --- a/src/boot/bootconfig.h +++ b/src/boot/bootconfig.h @@ -28,12 +28,14 @@ public: /// Constructor. Loads bootconfig from the given buffer. bootconfig(util::buffer data, uefi::boot_services *bs); - inline const descriptor & kernel() { return m_kernel; } - inline const descriptor & init() { return m_init; } + inline uint16_t flags() const { return m_flags; } + inline const descriptor & kernel() const { return m_kernel; } + inline const descriptor & init() const { return m_init; } descriptors programs() { return m_programs; } descriptors data() { return m_data; } private: + uint16_t m_flags; descriptor m_kernel; descriptor m_init; descriptors m_programs; diff --git a/src/boot/main.cpp b/src/boot/main.cpp index a31d5aa..30c30af 100644 --- a/src/boot/main.cpp +++ b/src/boot/main.cpp @@ -77,6 +77,7 @@ load_resources(bootproto::args *args, video::screen *screen, uefi::handle image, args->kernel = loader::load_program(disk, bc.kernel(), true); args->init = loader::load_program(disk, bc.init()); + args->flags = static_cast(bc.flags()); namespace bits = util::bits; using bootproto::desc_flags; diff --git a/src/kernel/cpu.cpp b/src/kernel/cpu.cpp index db1da47..9859a8c 100644 --- a/src/kernel/cpu.cpp +++ b/src/kernel/cpu.cpp @@ -98,8 +98,6 @@ bsp_late_init() asm ("mov %%cr4, %0" : "=r"(cr4)); uint64_t efer = rdmsr(msr::ia32_efer); log::debug(logs::boot, "Control regs: cr0:%lx cr4:%lx efer:%lx", cr0, cr4, efer); - - syscall_initialize(); } cpu_data * diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 0588122..7755d1b 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -18,6 +18,7 @@ #include "objects/vm_area.h" #include "scheduler.h" #include "smp.h" +#include "syscall.h" #include "sysconf.h" extern "C" { @@ -55,6 +56,10 @@ kernel_main(bootproto::args *args) bsp_late_init(); + using bootproto::boot_flags; + bool enable_test = util::bits::has(args->flags, boot_flags::test); + syscall_initialize(enable_test); + device_manager &devices = device_manager::get(); devices.parse_acpi(args->acpi_table); diff --git a/src/kernel/syscall.cpp.cog b/src/kernel/syscall.cpp.cog index e93acd2..8556f6a 100644 --- a/src/kernel/syscall.cpp.cog +++ b/src/kernel/syscall.cpp.cog @@ -66,7 +66,7 @@ syscall_invalid(uint64_t call) } void -syscall_initialize() +syscall_initialize(bool enable_test) { memset(&syscall_registry, 0, sizeof(syscall_registry)); @@ -77,8 +77,17 @@ syscall_initialize() else: name = method.name - cog.outl(f"syscall_registry[{id}] = reinterpret_cast(syscalls::_syscall_verify_{name});") - cog.outl(f"""log::debug(logs::syscall, "Enabling syscall {id:02x} as {name}");""") + indent = "" + if "test" in method.options: + cog.outl("if (enable_test) {") + indent = " " + + cog.outl(f"{indent}syscall_registry[{id}] = reinterpret_cast(syscalls::_syscall_verify_{name});") + cog.outl(f"""{indent}log::debug(logs::syscall, "Enabling syscall {id:02x} as {name}");""") + + if "test" in method.options: + cog.outl("}") + cog.outl("") ]]]*/ //[[[end]]] diff --git a/src/kernel/syscall.h.cog b/src/kernel/syscall.h.cog index c56d120..57d7d9d 100644 --- a/src/kernel/syscall.h.cog +++ b/src/kernel/syscall.h.cog @@ -17,5 +17,5 @@ cog.outl(f"constexpr size_t num_syscalls = {len(syscalls.methods)};") ]]]*/ /// [[[end]]] -void syscall_initialize(); +void syscall_initialize(bool enable_test); extern "C" void syscall_enable(); diff --git a/src/kernel/syscalls/system.cpp b/src/kernel/syscalls/system.cpp index b22df5b..7f1d5ed 100644 --- a/src/kernel/syscalls/system.cpp +++ b/src/kernel/syscalls/system.cpp @@ -36,6 +36,14 @@ noop() return j6_status_ok; } +[[ noreturn ]] j6_status_t +test_finish(uint32_t exit_code) +{ + // Tell QEMU to exit + asm ( "out %0, %1" :: "a"(exit_code), "Nd"(0xf4) ); + while (1) asm ("hlt"); +} + j6_status_t system_get_log(system *self, void *buffer, size_t *buffer_len) { diff --git a/src/libraries/bootproto/include/bootproto/kernel.h b/src/libraries/bootproto/include/bootproto/kernel.h index c5c9d97..f00fa42 100644 --- a/src/libraries/bootproto/include/bootproto/kernel.h +++ b/src/libraries/bootproto/include/bootproto/kernel.h @@ -114,8 +114,10 @@ struct frame_block enum class boot_flags : uint16_t { none = 0x0000, - debug = 0x0001 + debug = 0x0001, + test = 0x0002, }; +is_bitfield(boot_flags); struct args {