[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.
This commit is contained in:
8
assets/manifests/test.yaml
Normal file
8
assets/manifests/test.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
init: srv.init
|
||||
flags: ["test"]
|
||||
programs:
|
||||
- name: panic.serial
|
||||
target: kernel
|
||||
flags: panic
|
||||
- name: drv.uart
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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("<H", (len(s)+1)*2))
|
||||
|
||||
@@ -41,7 +41,8 @@ bootconfig::bootconfig(util::buffer data, uefi::boot_services *bs)
|
||||
data += 1; // reserved byte
|
||||
uint16_t num_programs = *util::read<uint16_t>(data);
|
||||
uint16_t num_data = *util::read<uint16_t>(data);
|
||||
data += 2; // reserved short
|
||||
|
||||
m_flags = *util::read<uint16_t>(data);
|
||||
|
||||
read_descriptor(m_kernel, data);
|
||||
read_descriptor(m_init, data);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<bootproto::boot_flags>(bc.flags());
|
||||
|
||||
namespace bits = util::bits;
|
||||
using bootproto::desc_flags;
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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<uintptr_t>(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<uintptr_t>(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]]]
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user