mirror of
https://github.com/justinian/jsix.git
synced 2025-12-09 16:04:32 -08:00
[srv.init] Create init server and read init args
Create a new usermode program, srv.init, and have it read the initial module_page args sent to it by the bootloader. Doesn't yet do anything useful but sets up the way for loading the rest of the programs from srv.init. Other (mostly) related changes: - bootloader: The allocator now has a function for allocating init modules out of a modules_page slab. Also changed how the allocator is initialized and passes the allocation register and modules_page list to efi_main(). - bootloader: Expose the simple wstrlen() to the rest of the program - bootloader: Move check_cpu_supported() to hardware.cpp - bootloader: Moved program_desc to loader.h and made the loader functions take it as an argument instead of paths. - kernel: Rename the system_map_mmio syscall to system_map_phys, and stop having it default those VMAs to having the vm_flags::mmio flag. Added a new flag mask, vm_flags::driver_mask, so that drivers can be allowed to ask for the MMIO flag. - kernel: Rename load_simple_process() to load_init_server() and got rid of all the stack setup routines in memory_bootstrap.cpp and task.s - Fixed formatting in config/debug.toml, undefined __linux and other linux-specific defines, and got rid of _LIBCPP_HAS_THREAD_API_EXTERNAL because that's just not true.
This commit is contained in:
@@ -45,12 +45,16 @@ build ${build_root}/fatroot/testapp.elf : cp ${build_root}/user/testapp.elf
|
||||
build ${build_root}/fatroot/drv.uefi_fb.elf : cp ${build_root}/user/drv.uefi_fb.elf
|
||||
name = UEFI framebuffer driver to FAT image
|
||||
|
||||
build ${build_root}/fatroot/srv.init.elf : cp ${build_root}/user/srv.init.elf
|
||||
name = Init server to FAT image
|
||||
|
||||
build ${build_root}/fatroot/symbol_table.dat : makest ${build_root}/jsix.elf
|
||||
|
||||
build ${build_root}/jsix.img : makefat | $
|
||||
${build_root}/fatroot/symbol_table.dat $
|
||||
${build_root}/fatroot/testapp.elf $
|
||||
${build_root}/fatroot/drv.uefi_fb.elf $
|
||||
${build_root}/fatroot/srv.init.elf $
|
||||
${build_root}/fatroot/jsix.elf $
|
||||
${build_root}/fatroot/efi/boot/bootx64.efi
|
||||
name = jsix.img
|
||||
|
||||
@@ -64,10 +64,11 @@ ccflags = [
|
||||
"-mcmodel=large",
|
||||
"-D__ELF__",
|
||||
"-D__JSIX__",
|
||||
"-D_LIBCPP_HAS_THREAD_API_EXTERNAL",
|
||||
"-isystem${source_root}/sysroot/include",
|
||||
"-isystem${source_root}/src/libraries/libc/include",
|
||||
"--sysroot='${source_root}/sysroot'"
|
||||
"--sysroot='${source_root}/sysroot'",
|
||||
"-U__linux",
|
||||
"-U__linux__",
|
||||
]
|
||||
|
||||
cxxflags = [
|
||||
@@ -103,21 +104,16 @@ asflags = [
|
||||
|
||||
ccflags = [
|
||||
"${ccflags}",
|
||||
"-nostdlib",
|
||||
"-ffreestanding",
|
||||
"-nodefaultlibs",
|
||||
"-fno-builtin",
|
||||
"-mno-sse",
|
||||
"-fno-omit-frame-pointer",
|
||||
"-mno-red-zone",
|
||||
"-g",
|
||||
"-mcmodel=large",
|
||||
"-D__ELF__",
|
||||
"-D__JSIX__",
|
||||
"-D_LIBCPP_HAS_THREAD_API_EXTERNAL",
|
||||
"-isystem${source_root}/sysroot/include",
|
||||
"-isystem${source_root}/src/libraries/libc/include",
|
||||
"--sysroot='${source_root}/sysroot'"
|
||||
"--sysroot='${source_root}/sysroot'",
|
||||
"-U__linux",
|
||||
"-U__linux__",
|
||||
]
|
||||
|
||||
cxxflags = [
|
||||
@@ -130,7 +126,6 @@ cxxflags = [
|
||||
ldflags = [
|
||||
"${ldflags}",
|
||||
"-g",
|
||||
"-nostdlib",
|
||||
"-Bstatic",
|
||||
"--sysroot='${source_root}/sysroot'",
|
||||
"-L", "${source_root}/sysroot/lib",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "kutil/no_construct.h"
|
||||
#include "allocator.h"
|
||||
#include "error.h"
|
||||
#include "init_args.h"
|
||||
#include "kernel_args.h"
|
||||
#include "memory.h"
|
||||
|
||||
@@ -15,23 +16,32 @@ memory::allocator &g_alloc = __g_alloc_storage.value;
|
||||
namespace memory {
|
||||
|
||||
using kernel::init::allocation_register;
|
||||
using kernel::init::module;
|
||||
using kernel::init::page_allocation;
|
||||
|
||||
static_assert(sizeof(allocation_register) == page_size);
|
||||
|
||||
|
||||
void
|
||||
init_allocator(uefi::boot_services *bs)
|
||||
allocator::init(
|
||||
allocation_register *&allocs,
|
||||
modules_page *&modules,
|
||||
uefi::boot_services *bs)
|
||||
{
|
||||
new (&g_alloc) allocator(*bs);
|
||||
allocs = g_alloc.m_register;
|
||||
modules = g_alloc.m_modules;
|
||||
}
|
||||
|
||||
|
||||
allocator::allocator(uefi::boot_services &bs) :
|
||||
m_bs(bs),
|
||||
m_register(nullptr),
|
||||
m_current(nullptr)
|
||||
{}
|
||||
m_modules(nullptr)
|
||||
{
|
||||
add_register();
|
||||
add_modules();
|
||||
}
|
||||
|
||||
void
|
||||
allocator::add_register()
|
||||
@@ -45,13 +55,25 @@ allocator::add_register()
|
||||
|
||||
m_bs.set_mem(reg, sizeof(allocation_register), 0);
|
||||
|
||||
if (!m_register) {
|
||||
m_register = m_current = reg;
|
||||
return;
|
||||
}
|
||||
if (m_register)
|
||||
m_register->next = reg;
|
||||
|
||||
m_current->next = reg;
|
||||
m_current = reg;
|
||||
m_register = reg;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
allocator::add_modules()
|
||||
{
|
||||
modules_page *mods = reinterpret_cast<modules_page*>(
|
||||
allocate_pages(1, alloc_type::init_args, true));
|
||||
|
||||
if (m_modules)
|
||||
m_modules->next = reinterpret_cast<uintptr_t>(mods);
|
||||
|
||||
mods->modules = reinterpret_cast<module*>(mods + 1);
|
||||
m_modules = mods;
|
||||
m_next_mod = mods->modules;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -64,7 +86,7 @@ allocator::allocate_pages(size_t count, alloc_type type, bool zero)
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
if (!m_current || m_current->count == 0xff)
|
||||
if (!m_register || m_register->count == 0xff)
|
||||
add_register();
|
||||
|
||||
void *pages = nullptr;
|
||||
@@ -74,7 +96,7 @@ allocator::allocate_pages(size_t count, alloc_type type, bool zero)
|
||||
uefi::memory_type::loader_data, count, &pages),
|
||||
L"Failed allocating usable pages");
|
||||
|
||||
page_allocation &ent = m_current->entries[m_current->count++];
|
||||
page_allocation &ent = m_register->entries[m_register->count++];
|
||||
ent.address = reinterpret_cast<uintptr_t>(pages);
|
||||
ent.count = count;
|
||||
ent.type = type;
|
||||
@@ -85,6 +107,24 @@ allocator::allocate_pages(size_t count, alloc_type type, bool zero)
|
||||
return pages;
|
||||
}
|
||||
|
||||
module *
|
||||
allocator::allocate_module_untyped(size_t size)
|
||||
{
|
||||
size_t remaining =
|
||||
reinterpret_cast<uintptr_t>(m_modules) + page_size
|
||||
- reinterpret_cast<uintptr_t>(m_next_mod);
|
||||
|
||||
if (size > remaining)
|
||||
add_modules();
|
||||
|
||||
++m_modules->count;
|
||||
module *m = m_next_mod;
|
||||
m_next_mod = offset_ptr<module>(m_next_mod, size);
|
||||
|
||||
m->mod_length = size;
|
||||
return m;
|
||||
}
|
||||
|
||||
void *
|
||||
allocator::allocate(size_t size, bool zero)
|
||||
{
|
||||
|
||||
@@ -2,12 +2,18 @@
|
||||
/// \file allocator.h
|
||||
/// Page allocator class definition
|
||||
|
||||
#include "kernel_args.h"
|
||||
|
||||
namespace uefi {
|
||||
class boot_services;
|
||||
}
|
||||
|
||||
namespace kernel {
|
||||
namespace init {
|
||||
enum class allocation_type : uint8_t;
|
||||
struct allocation_register;
|
||||
struct module;
|
||||
struct modules_page;
|
||||
}}
|
||||
|
||||
namespace boot {
|
||||
namespace memory {
|
||||
|
||||
@@ -17,6 +23,8 @@ class allocator
|
||||
{
|
||||
public:
|
||||
using allocation_register = kernel::init::allocation_register;
|
||||
using module = kernel::init::module;
|
||||
using modules_page = kernel::init::modules_page;
|
||||
|
||||
allocator(uefi::boot_services &bs);
|
||||
|
||||
@@ -25,25 +33,37 @@ public:
|
||||
|
||||
void * allocate_pages(size_t count, alloc_type type, bool zero = false);
|
||||
|
||||
template <typename M>
|
||||
M * allocate_module(size_t extra = 0) {
|
||||
return static_cast<M*>(allocate_module_untyped(sizeof(M) + extra));
|
||||
}
|
||||
|
||||
void memset(void *start, size_t size, uint8_t value);
|
||||
void copy(void *to, void *from, size_t size);
|
||||
|
||||
inline void zero(void *start, size_t size) { memset(start, size, 0); }
|
||||
|
||||
allocation_register * get_register() { return m_register; }
|
||||
/// Initialize the global allocator
|
||||
/// \arg allocs [out] Poiinter to the initial allocation register
|
||||
/// \arg modules [out] Pointer to the initial modules_page
|
||||
/// \arg bs UEFI boot services
|
||||
static void init(
|
||||
allocation_register *&allocs,
|
||||
modules_page *&modules,
|
||||
uefi::boot_services *bs);
|
||||
|
||||
private:
|
||||
void add_register();
|
||||
void add_modules();
|
||||
module * allocate_module_untyped(size_t size);
|
||||
|
||||
uefi::boot_services &m_bs;
|
||||
|
||||
allocation_register *m_register;
|
||||
allocation_register *m_current;
|
||||
modules_page *m_modules;
|
||||
module *m_next_mod;
|
||||
};
|
||||
|
||||
/// Initialize the global allocator
|
||||
void init_allocator(uefi::boot_services *bs);
|
||||
|
||||
} // namespace memory
|
||||
|
||||
extern memory::allocator &g_alloc;
|
||||
|
||||
@@ -22,7 +22,7 @@ static const wchar_t digits[] = {u'0', u'1', u'2', u'3', u'4', u'5',
|
||||
u'6', u'7', u'8', u'9', u'a', u'b', u'c', u'd', u'e', u'f'};
|
||||
|
||||
|
||||
static size_t
|
||||
size_t
|
||||
wstrlen(const wchar_t *s)
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace uefi {
|
||||
namespace protos {
|
||||
@@ -40,4 +41,6 @@ private:
|
||||
static console *s_console;
|
||||
};
|
||||
|
||||
size_t wstrlen(const wchar_t *s);
|
||||
|
||||
} // namespace boot
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "console.h"
|
||||
#include "error.h"
|
||||
#include "fs.h"
|
||||
#include "kernel_args.h"
|
||||
#include "memory.h"
|
||||
#include "status.h"
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "hardware.h"
|
||||
#include "console.h"
|
||||
#include "cpu/cpu_id.h"
|
||||
#include "error.h"
|
||||
#include "hardware.h"
|
||||
#include "status.h"
|
||||
|
||||
namespace boot {
|
||||
@@ -53,7 +54,6 @@ wrmsr(uint32_t addr, uint64_t value)
|
||||
__asm__ __volatile__ ("wrmsr" :: "c"(addr), "a"(low), "d"(high));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
setup_control_regs()
|
||||
{
|
||||
@@ -77,5 +77,27 @@ setup_control_regs()
|
||||
wrmsr(IA32_EFER, efer);
|
||||
}
|
||||
|
||||
void
|
||||
check_cpu_supported()
|
||||
{
|
||||
status_line status {L"Checking CPU features"};
|
||||
|
||||
cpu::cpu_id cpu;
|
||||
uint64_t missing = cpu.missing();
|
||||
if (missing) {
|
||||
#define CPU_FEATURE_OPT(...)
|
||||
#define CPU_FEATURE_REQ(name, ...) \
|
||||
if (!cpu.has_feature(cpu::feature::name)) { \
|
||||
status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \
|
||||
}
|
||||
#include "cpu/features.inc"
|
||||
#undef CPU_FEATURE_REQ
|
||||
#undef CPU_FEATURE_OPT
|
||||
|
||||
error::raise(uefi::status::unsupported, L"CPU not supported");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace hw
|
||||
} // namespace boot
|
||||
|
||||
@@ -16,5 +16,8 @@ void * find_acpi_table(uefi::system_table *st);
|
||||
/// Enable CPU options in CR4 etc for the kernel starting state.
|
||||
void setup_control_regs();
|
||||
|
||||
/// Check that all required cpu features are supported
|
||||
void check_cpu_supported();
|
||||
|
||||
} // namespace hw
|
||||
} // namespace boot
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "elf.h"
|
||||
#include "error.h"
|
||||
#include "fs.h"
|
||||
#include "init_args.h"
|
||||
#include "loader.h"
|
||||
#include "memory.h"
|
||||
#include "paging.h"
|
||||
@@ -22,12 +23,11 @@ using memory::alloc_type;
|
||||
buffer
|
||||
load_file(
|
||||
fs::file &disk,
|
||||
const wchar_t *name,
|
||||
const wchar_t *path)
|
||||
const program_desc &desc)
|
||||
{
|
||||
status_line status(L"Loading file", name);
|
||||
status_line status(L"Loading file", desc.path);
|
||||
|
||||
fs::file file = disk.open(path);
|
||||
fs::file file = disk.open(desc.path);
|
||||
buffer b = file.load();
|
||||
|
||||
//console::print(L" Loaded at: 0x%lx, %d bytes\r\n", b.data, b.size);
|
||||
@@ -50,13 +50,37 @@ is_elfheader_valid(const elf::header *header)
|
||||
header->header_version == elf::version;
|
||||
}
|
||||
|
||||
void
|
||||
load_program(
|
||||
init::program &program,
|
||||
const wchar_t *name,
|
||||
buffer data)
|
||||
static void
|
||||
create_module(buffer data, const program_desc &desc, bool loaded)
|
||||
{
|
||||
status_line status(L"Loading program:", name);
|
||||
size_t path_len = wstrlen(desc.path);
|
||||
init::module_program *mod = g_alloc.allocate_module<init::module_program>(path_len);
|
||||
mod->mod_type = init::module_type::program;
|
||||
mod->base_address = reinterpret_cast<uintptr_t>(data.pointer);
|
||||
if (loaded)
|
||||
mod->mod_flags = static_cast<init::module_flags>(
|
||||
static_cast<uint8_t>(mod->mod_flags) |
|
||||
static_cast<uint8_t>(init::module_flags::no_load));
|
||||
|
||||
// TODO: support non-ascii path characters and do real utf-16 to utf-8
|
||||
// conversion
|
||||
for (int i = 0; i < path_len; ++i)
|
||||
mod->filename[i] = desc.path[i];
|
||||
mod->filename[path_len] = 0;
|
||||
}
|
||||
|
||||
init::program *
|
||||
load_program(
|
||||
fs::file &disk,
|
||||
const program_desc &desc,
|
||||
bool add_module)
|
||||
{
|
||||
status_line status(L"Loading program", desc.name);
|
||||
|
||||
buffer data = load_file(disk, desc);
|
||||
|
||||
if (add_module)
|
||||
create_module(data, desc, true);
|
||||
|
||||
const elf::header *header = reinterpret_cast<const elf::header*>(data.pointer);
|
||||
uintptr_t program_base = reinterpret_cast<uintptr_t>(data.pointer);
|
||||
@@ -103,9 +127,22 @@ load_program(
|
||||
section.type = static_cast<init::section_flags>(pheader->flags);
|
||||
}
|
||||
|
||||
program.sections = { .pointer = sections, .count = num_sections };
|
||||
program.phys_base = program_base;
|
||||
program.entrypoint = header->entrypoint;
|
||||
init::program *prog = new init::program;
|
||||
prog->sections = { .pointer = sections, .count = num_sections };
|
||||
prog->phys_base = program_base;
|
||||
prog->entrypoint = header->entrypoint;
|
||||
return prog;
|
||||
}
|
||||
|
||||
void
|
||||
load_module(
|
||||
fs::file &disk,
|
||||
const program_desc &desc)
|
||||
{
|
||||
status_line status(L"Loading module", desc.name);
|
||||
|
||||
buffer data = load_file(disk, desc);
|
||||
create_module(data, desc, false);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
namespace kernel {
|
||||
namespace init {
|
||||
struct program;
|
||||
struct module;
|
||||
}}
|
||||
|
||||
namespace boot {
|
||||
@@ -17,25 +18,37 @@ namespace fs {
|
||||
|
||||
namespace loader {
|
||||
|
||||
struct program_desc
|
||||
{
|
||||
const wchar_t *name;
|
||||
const wchar_t *path;
|
||||
};
|
||||
|
||||
/// Load a file from disk into memory.
|
||||
/// \arg disk The opened UEFI filesystem to load from
|
||||
/// \arg name Name of the module (informational only)
|
||||
/// \arg path Path on `disk` of the file to load
|
||||
/// \arg desc The program descriptor identifying the file
|
||||
buffer
|
||||
load_file(
|
||||
fs::file &disk,
|
||||
const wchar_t *name,
|
||||
const wchar_t *path);
|
||||
const program_desc &desc);
|
||||
|
||||
/// Parse and load an ELF file in memory into a loaded image.
|
||||
/// \arg program The program structure to fill
|
||||
/// \arg name The name of the program being loaded
|
||||
/// \arg data Buffer of the ELF file in memory
|
||||
void
|
||||
/// \arg disk The opened UEFI filesystem to load from
|
||||
/// \arg desc The program descriptor identifying the program
|
||||
/// \arg add_module Also create a module for this loaded program
|
||||
kernel::init::program *
|
||||
load_program(
|
||||
kernel::init::program &program,
|
||||
const wchar_t *name,
|
||||
buffer data);
|
||||
fs::file &disk,
|
||||
const program_desc &desc,
|
||||
bool add_module = false);
|
||||
|
||||
/// Load a file from disk into memory, creating an init args module
|
||||
/// \arg disk The opened UEFI filesystem to load from
|
||||
/// \arg desc The program descriptor identifying the file
|
||||
void
|
||||
load_module(
|
||||
fs::file &disk,
|
||||
const program_desc &desc);
|
||||
|
||||
/// Verify that a loaded ELF has the j6 kernel header
|
||||
/// \arg program The program to check for a header
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include "allocator.h"
|
||||
#include "console.h"
|
||||
#include "cpu/cpu_id.h"
|
||||
#include "error.h"
|
||||
#include "fs.h"
|
||||
#include "hardware.h"
|
||||
@@ -30,19 +29,12 @@ namespace init = kernel::init;
|
||||
|
||||
namespace boot {
|
||||
|
||||
constexpr int max_modules = 5; // Max modules to allocate room for
|
||||
constexpr int max_programs = 5; // Max programs to allocate room for
|
||||
const loader::program_desc kern_desc = {L"kernel", L"jsix.elf"};
|
||||
const loader::program_desc init_desc = {L"init server", L"srv.init.elf"};
|
||||
const loader::program_desc fb_driver = {L"UEFI framebuffer driver", L"drv.uefi_fb.elf"};
|
||||
|
||||
struct program_desc
|
||||
{
|
||||
const wchar_t *name;
|
||||
const wchar_t *path;
|
||||
};
|
||||
|
||||
const program_desc program_list[] = {
|
||||
{L"kernel", L"jsix.elf"},
|
||||
const loader::program_desc extra_programs[] = {
|
||||
{L"test application", L"testapp.elf"},
|
||||
{L"UEFI framebuffer driver", L"drv.uefi_fb.elf"},
|
||||
};
|
||||
|
||||
/// Change a pointer to point to the higher-half linear-offset version
|
||||
@@ -53,40 +45,6 @@ void change_pointer(T *&pointer)
|
||||
pointer = offset_ptr<T>(pointer, kernel::memory::page_offset);
|
||||
}
|
||||
|
||||
/// Add a module to the kernel args list
|
||||
inline void
|
||||
add_module(init::args *args, init::mod_type type, buffer &data)
|
||||
{
|
||||
init::module &m = args->modules[args->modules.count++];
|
||||
m.type = type;
|
||||
m.location = data.pointer;
|
||||
m.size = data.count;
|
||||
|
||||
change_pointer(m.location);
|
||||
}
|
||||
|
||||
/// Check that all required cpu features are supported
|
||||
void
|
||||
check_cpu_supported()
|
||||
{
|
||||
status_line status {L"Checking CPU features"};
|
||||
|
||||
cpu::cpu_id cpu;
|
||||
uint64_t missing = cpu.missing();
|
||||
if (missing) {
|
||||
#define CPU_FEATURE_OPT(...)
|
||||
#define CPU_FEATURE_REQ(name, ...) \
|
||||
if (!cpu.has_feature(cpu::feature::name)) { \
|
||||
status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \
|
||||
}
|
||||
#include "cpu/features.inc"
|
||||
#undef CPU_FEATURE_REQ
|
||||
#undef CPU_FEATURE_OPT
|
||||
|
||||
error::raise(uefi::status::unsupported, L"CPU not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/// The main procedure for the portion of the loader that runs while
|
||||
/// UEFI is still in control of the machine. (ie, while the loader still
|
||||
/// has access to boot services.)
|
||||
@@ -98,13 +56,11 @@ uefi_preboot(uefi::handle image, uefi::system_table *st)
|
||||
|
||||
status_line status {L"Performing UEFI pre-boot"};
|
||||
|
||||
check_cpu_supported();
|
||||
hw::check_cpu_supported();
|
||||
memory::init_pointer_fixup(bs, rs);
|
||||
|
||||
init::args *args = new init::args;
|
||||
g_alloc.zero(args, sizeof(init::args));
|
||||
args->programs.pointer = new init::program[5];
|
||||
args->modules.pointer = new init::module[5];
|
||||
|
||||
args->magic = init::args_magic;
|
||||
args->version = init::args_version;
|
||||
@@ -114,21 +70,32 @@ uefi_preboot(uefi::handle image, uefi::system_table *st)
|
||||
|
||||
paging::allocate_tables(args);
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/// Load the kernel and other programs from disk
|
||||
void
|
||||
load_resources(init::args *args, video::screen *screen, uefi::handle image, uefi::boot_services *bs)
|
||||
{
|
||||
status_line status {L"Loading programs"};
|
||||
|
||||
fs::file disk = fs::get_boot_volume(image, bs);
|
||||
|
||||
buffer symbols = loader::load_file(disk, L"symbol table", L"symbol_table.dat");
|
||||
add_module(args, init::mod_type::symbol_table, symbols);
|
||||
|
||||
for (auto &desc : program_list) {
|
||||
buffer buf = loader::load_file(disk, desc.name, desc.path);
|
||||
init::program &program = args->programs[args->programs.count++];
|
||||
loader::load_program(program, desc.name, buf);
|
||||
if (screen) {
|
||||
video::make_module(screen);
|
||||
loader::load_module(disk, fb_driver);
|
||||
}
|
||||
|
||||
// First program *must* be the kernel
|
||||
loader::verify_kernel_header(args->programs[0]);
|
||||
args->symbol_table = loader::load_file(disk, {L"symbol table", L"symbol_table.dat"});
|
||||
|
||||
args->kernel = loader::load_program(disk, kern_desc, true);
|
||||
args->init = loader::load_program(disk, init_desc);
|
||||
|
||||
for (auto &desc : extra_programs)
|
||||
loader::load_module(disk, desc);
|
||||
|
||||
loader::verify_kernel_header(*args->kernel);
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
memory::efi_mem_map
|
||||
@@ -141,7 +108,6 @@ uefi_exit(init::args *args, uefi::handle image, uefi::boot_services *bs)
|
||||
|
||||
args->mem_map = memory::build_kernel_map(map);
|
||||
args->frame_blocks = memory::build_frame_blocks(args->mem_map);
|
||||
args->allocations = g_alloc.get_register();
|
||||
|
||||
map.update(*bs);
|
||||
try_or_raise(
|
||||
@@ -162,17 +128,24 @@ efi_main(uefi::handle image, uefi::system_table *st)
|
||||
uefi::boot_services *bs = st->boot_services;
|
||||
console con(st->con_out);
|
||||
|
||||
memory::init_allocator(bs);
|
||||
init::allocation_register *allocs = nullptr;
|
||||
init::modules_page *modules = nullptr;
|
||||
memory::allocator::init(allocs, modules, bs);
|
||||
|
||||
video::screen *screen = video::pick_mode(bs);
|
||||
con.announce();
|
||||
|
||||
init::args *args = uefi_preboot(image, st);
|
||||
load_resources(args, screen, image, bs);
|
||||
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
|
||||
|
||||
args->allocations = allocs;
|
||||
args->modules = reinterpret_cast<uintptr_t>(modules);
|
||||
|
||||
status_bar status {screen}; // Switch to fb status display
|
||||
|
||||
// Map the kernel to the appropriate address
|
||||
init::program &kernel = args->programs[0];
|
||||
init::program &kernel = *args->kernel;
|
||||
for (auto §ion : kernel.sections)
|
||||
paging::map_section(args, section);
|
||||
|
||||
@@ -180,20 +153,22 @@ efi_main(uefi::handle image, uefi::system_table *st)
|
||||
|
||||
init::entrypoint kentry =
|
||||
reinterpret_cast<init::entrypoint>(kernel.entrypoint);
|
||||
status.next();
|
||||
//status.next();
|
||||
|
||||
hw::setup_control_regs();
|
||||
memory::virtualize(args->pml4, map, st->runtime_services);
|
||||
status.next();
|
||||
//status.next();
|
||||
|
||||
change_pointer(args);
|
||||
change_pointer(args->pml4);
|
||||
change_pointer(args->modules.pointer);
|
||||
change_pointer(args->programs.pointer);
|
||||
for (auto &program : args->programs)
|
||||
change_pointer(program.sections.pointer);
|
||||
change_pointer(args->symbol_table.pointer);
|
||||
|
||||
status.next();
|
||||
change_pointer(args->kernel);
|
||||
change_pointer(args->kernel->sections.pointer);
|
||||
change_pointer(args->init);
|
||||
change_pointer(args->init->sections.pointer);
|
||||
|
||||
//status.next();
|
||||
|
||||
kentry(args);
|
||||
debug_break();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <uefi/graphics.h>
|
||||
#include <uefi/protos/graphics_output.h>
|
||||
|
||||
#include "allocator.h"
|
||||
#include "console.h"
|
||||
#include "error.h"
|
||||
#include "init_args.h"
|
||||
@@ -106,15 +107,15 @@ pick_mode(uefi::boot_services *bs)
|
||||
}
|
||||
|
||||
void
|
||||
make_module(screen *s, module_framebuffer *mod)
|
||||
make_module(screen *s)
|
||||
{
|
||||
mod->mod_type = module_type::framebuffer;
|
||||
mod->mod_flags = module_flags::none;
|
||||
mod->mod_length = sizeof(module_framebuffer);
|
||||
mod->type = fb_type::uefi;
|
||||
using kernel::init::module_framebuffer;
|
||||
module_framebuffer *modfb = g_alloc.allocate_module<module_framebuffer>();
|
||||
modfb->mod_type = module_type::framebuffer;
|
||||
modfb->type = fb_type::uefi;
|
||||
|
||||
mod->framebuffer = s->framebuffer;
|
||||
mod->mode = s->mode;
|
||||
modfb->framebuffer = s->framebuffer;
|
||||
modfb->mode = s->mode;
|
||||
}
|
||||
|
||||
} // namespace video
|
||||
|
||||
@@ -26,7 +26,7 @@ struct screen {
|
||||
screen * pick_mode(uefi::boot_services *bs);
|
||||
|
||||
/// Make an init arg module from the video mode
|
||||
void make_module(screen *s, kernel::init::module_framebuffer *mod);
|
||||
void make_module(screen *s);
|
||||
|
||||
} // namespace video
|
||||
} // namespace boot
|
||||
|
||||
@@ -9,11 +9,19 @@ namespace kernel {
|
||||
namespace init {
|
||||
|
||||
enum class module_type : uint8_t {
|
||||
none,
|
||||
program,
|
||||
framebuffer,
|
||||
};
|
||||
|
||||
enum class module_flags : uint8_t { none = 0 };
|
||||
enum class module_flags : uint8_t {
|
||||
none = 0x00,
|
||||
|
||||
/// This module was already handled by the bootloader,
|
||||
/// no action is needed. The module is included for
|
||||
/// informational purposes only.
|
||||
no_load = 0x01,
|
||||
};
|
||||
|
||||
struct module
|
||||
{
|
||||
@@ -52,7 +60,7 @@ struct modules_page
|
||||
{
|
||||
uint8_t count;
|
||||
module *modules;
|
||||
modules_page *next;
|
||||
uintptr_t next;
|
||||
};
|
||||
|
||||
} // namespace init
|
||||
|
||||
@@ -2,7 +2,7 @@ SYSCALL(0x00, system_log, const char *)
|
||||
SYSCALL(0x01, system_noop, void)
|
||||
SYSCALL(0x02, system_get_log, j6_handle_t, void *, size_t *)
|
||||
SYSCALL(0x03, system_bind_irq, j6_handle_t, j6_handle_t, unsigned)
|
||||
SYSCALL(0x04, system_map_mmio, j6_handle_t, j6_handle_t *, uintptr_t, size_t, uint32_t)
|
||||
SYSCALL(0x04, system_map_phys, j6_handle_t, j6_handle_t *, uintptr_t, size_t, uint32_t)
|
||||
|
||||
SYSCALL(0x08, object_koid, j6_handle_t, j6_koid_t *)
|
||||
SYSCALL(0x09, object_wait, j6_handle_t, j6_signal_t, j6_signal_t *)
|
||||
|
||||
@@ -15,16 +15,6 @@ constexpr uint64_t header_magic = 0x4c454e52454b366aull; // 'j6KERNEL'
|
||||
constexpr uint16_t header_version = 2;
|
||||
constexpr uint16_t min_header_version = 2;
|
||||
|
||||
enum class mod_type : uint32_t {
|
||||
symbol_table
|
||||
};
|
||||
|
||||
struct module {
|
||||
void *location;
|
||||
size_t size;
|
||||
mod_type type;
|
||||
};
|
||||
|
||||
enum class section_flags : uint32_t {
|
||||
none = 0,
|
||||
execute = 1,
|
||||
@@ -64,7 +54,7 @@ struct mem_entry
|
||||
};
|
||||
|
||||
enum class allocation_type : uint8_t {
|
||||
none, page_table, mem_map, frame_map, file, program,
|
||||
none, page_table, mem_map, frame_map, file, program, init_args,
|
||||
};
|
||||
|
||||
/// A single contiguous allocation of pages
|
||||
@@ -131,13 +121,14 @@ struct args
|
||||
|
||||
void *pml4;
|
||||
counted<void> page_tables;
|
||||
|
||||
counted<program> programs;
|
||||
counted<module> modules;
|
||||
counted<mem_entry> mem_map;
|
||||
counted<frame_block> frame_blocks;
|
||||
|
||||
program *kernel;
|
||||
program *init;
|
||||
counted<void> symbol_table;
|
||||
allocation_register *allocations;
|
||||
uintptr_t modules;
|
||||
|
||||
void *runtime_services;
|
||||
void *acpi_table;
|
||||
|
||||
@@ -53,7 +53,7 @@ static bool scheduler_ready = false;
|
||||
/// Bootstrap the memory managers.
|
||||
void memory_initialize_pre_ctors(init::args &kargs);
|
||||
void memory_initialize_post_ctors(init::args &kargs);
|
||||
process * load_simple_process(init::program &program);
|
||||
void load_init_server(init::program &program, uintptr_t modules_address);
|
||||
|
||||
unsigned start_aps(lapic &apic, const kutil::vector<uint8_t> &ids, void *kpml4);
|
||||
|
||||
@@ -128,17 +128,8 @@ kernel_main(init::args *args)
|
||||
|
||||
cpu->tss->create_ist_stacks(cpu->idt->used_ist_entries());
|
||||
|
||||
for (size_t i = 0; i < args->modules.count; ++i) {
|
||||
init::module &mod = args->modules[i];
|
||||
|
||||
switch (mod.type) {
|
||||
case init::mod_type::symbol_table:
|
||||
new symbol_table {mod.location, mod.size};
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (args->symbol_table.count) {
|
||||
new symbol_table {args->symbol_table.pointer, args->symbol_table.count};
|
||||
}
|
||||
|
||||
syscall_initialize();
|
||||
@@ -193,10 +184,8 @@ kernel_main(init::args *args)
|
||||
scheduler *sched = new scheduler {num_cpus};
|
||||
scheduler_ready = true;
|
||||
|
||||
// Skip program 0, which is the kernel itself
|
||||
for (unsigned i = 1; i < args->programs.count; ++i)
|
||||
load_simple_process(args->programs[i]);
|
||||
|
||||
// Load the init server
|
||||
load_init_server(*args->init, args->modules);
|
||||
|
||||
sched->create_kernel_task(logger_task, scheduler::max_priority/2, true);
|
||||
sched->start();
|
||||
|
||||
@@ -181,12 +181,13 @@ log_mtrrs()
|
||||
}
|
||||
|
||||
|
||||
process *
|
||||
load_simple_process(init::program &program)
|
||||
void
|
||||
load_init_server(init::program &program, uintptr_t modules_address)
|
||||
{
|
||||
process *p = new process;
|
||||
vm_space &space = p->space();
|
||||
p->add_handle(&system::get());
|
||||
|
||||
vm_space &space = p->space();
|
||||
for (const auto § : program.sections) {
|
||||
vm_flags flags =
|
||||
((sect.type && section_flags::execute) ? vm_flags::exec : vm_flags::none) |
|
||||
@@ -197,64 +198,14 @@ load_simple_process(init::program &program)
|
||||
}
|
||||
|
||||
uint64_t iopl = (3ull << 12);
|
||||
uintptr_t trampoline = reinterpret_cast<uintptr_t>(initialize_main_thread);
|
||||
|
||||
thread *main = p->create_thread();
|
||||
main->add_thunk_user(program.entrypoint, trampoline, iopl);
|
||||
main->add_thunk_user(program.entrypoint, 0, iopl);
|
||||
main->set_state(thread::state::ready);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T * push(uintptr_t &rsp, size_t size = sizeof(T)) {
|
||||
rsp -= size;
|
||||
T *p = reinterpret_cast<T*>(rsp);
|
||||
rsp &= ~(sizeof(uint64_t)-1); // Align the stack
|
||||
return p;
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
initialize_main_user_stack()
|
||||
{
|
||||
process &proc = process::current();
|
||||
thread &th = thread::current();
|
||||
TCB *tcb = th.tcb();
|
||||
|
||||
const char message[] = "Hello from the kernel!";
|
||||
char *message_arg = push<char>(tcb->rsp3, sizeof(message));
|
||||
kutil::memcpy(message_arg, message, sizeof(message));
|
||||
|
||||
j6_init_value *initv = nullptr;
|
||||
unsigned n = 0;
|
||||
|
||||
initv = push<j6_init_value>(tcb->rsp3);
|
||||
initv->type = j6_init_handle_other;
|
||||
initv->handle.type = j6_object_type_system;
|
||||
initv->handle.handle = proc.add_handle(&system::get());
|
||||
++n;
|
||||
|
||||
initv = push<j6_init_value>(tcb->rsp3);
|
||||
initv->type = j6_init_handle_self;
|
||||
initv->handle.type = j6_object_type_process;
|
||||
initv->handle.handle = proc.self_handle();
|
||||
++n;
|
||||
|
||||
initv = push<j6_init_value>(tcb->rsp3);
|
||||
initv->type = j6_init_handle_self;
|
||||
initv->handle.type = j6_object_type_thread;
|
||||
initv->handle.handle = th.self_handle();
|
||||
++n;
|
||||
|
||||
uint64_t *initc = push<uint64_t>(tcb->rsp3);
|
||||
*initc = n;
|
||||
|
||||
char **argv0 = push<char*>(tcb->rsp3);
|
||||
*argv0 = message_arg;
|
||||
|
||||
uint64_t *argc = push<uint64_t>(tcb->rsp3);
|
||||
*argc = 1;
|
||||
|
||||
th.clear_state(thread::state::loading);
|
||||
return tcb->rsp3;
|
||||
// Hacky: No process exists to have created a stack for init; it needs to create
|
||||
// its own stack. We take advantage of that to use rsp to pass it the init modules
|
||||
// address.
|
||||
auto *tcb = main->tcb();
|
||||
tcb->rsp3 = modules_address;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@ enum class vm_flags : uint32_t
|
||||
#define VM_FLAG(name, v) name = v,
|
||||
#include "j6/tables/vm_flags.inc"
|
||||
#undef VM_FLAG
|
||||
user_mask = 0x0000ffff ///< flags allowed via syscall
|
||||
driver_mask = 0x000fffff, ///< flags allowed via syscall for drivers
|
||||
user_mask = 0x0000ffff, ///< flags allowed via syscall for non-drivers
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "j6/types.h"
|
||||
|
||||
#include "device_manager.h"
|
||||
#include "frame_allocator.h"
|
||||
#include "log.h"
|
||||
#include "objects/endpoint.h"
|
||||
#include "objects/thread.h"
|
||||
@@ -60,12 +61,17 @@ system_bind_irq(j6_handle_t sys, j6_handle_t endp, unsigned irq)
|
||||
}
|
||||
|
||||
j6_status_t
|
||||
system_map_mmio(j6_handle_t sys, j6_handle_t *vma_handle, uintptr_t phys_addr, size_t size, uint32_t flags)
|
||||
system_map_phys(j6_handle_t sys, j6_handle_t *vma_handle, uintptr_t phys_addr, size_t size, uint32_t flags)
|
||||
{
|
||||
// TODO: check capabilities on sys handle
|
||||
if (!vma_handle) return j6_err_invalid_arg;
|
||||
|
||||
vm_flags vmf = vm_flags::mmio | (static_cast<vm_flags>(flags) & vm_flags::user_mask);
|
||||
// TODO: check to see if frames are already used? How would that collide with
|
||||
// the bootloader's allocated pages already being marked used?
|
||||
if (!(flags & vm_flags::mmio))
|
||||
frame_allocator::get().used(phys_addr, memory::page_count(size));
|
||||
|
||||
vm_flags vmf = (static_cast<vm_flags>(flags) & vm_flags::driver_mask);
|
||||
construct_handle<vm_area_fixed>(vma_handle, phys_addr, size, vmf);
|
||||
|
||||
return j6_status_ok;
|
||||
|
||||
@@ -53,20 +53,6 @@ task_switch:
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
|
||||
extern initialize_main_user_stack
|
||||
extern kernel_to_user_trampoline
|
||||
global initialize_main_thread
|
||||
initialize_main_thread:
|
||||
call initialize_main_user_stack
|
||||
|
||||
; user rsp is now in rax, put it in the right place for sysret
|
||||
mov [rsp + 0x30], rax
|
||||
mov [gs:CPU_DATA.rsp3], rax
|
||||
|
||||
; the entrypoint should already be on the stack
|
||||
jmp kernel_to_user_trampoline
|
||||
|
||||
global _current_gsbase
|
||||
_current_gsbase:
|
||||
mov rax, [gs:CPU_DATA.self]
|
||||
|
||||
@@ -55,8 +55,9 @@ main(int argc, const char **argv)
|
||||
j6_handle_t fb_handle = j6_handle_invalid;
|
||||
uint32_t flags =
|
||||
j6_vm_flag_write |
|
||||
j6_vm_flag_write_combine;
|
||||
j6_status_t s = j6_system_map_mmio(__handle_sys, &fb_handle, fb->addr, fb->size, flags);
|
||||
j6_vm_flag_write_combine |
|
||||
j6_vm_flag_mmio;
|
||||
j6_status_t s = j6_system_map_phys(__handle_sys, &fb_handle, fb->addr, fb->size, flags);
|
||||
if (s != j6_status_ok) {
|
||||
return s;
|
||||
}
|
||||
|
||||
20
src/user/srv.init/main.cpp
Normal file
20
src/user/srv.init/main.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "j6/syscalls.h"
|
||||
#include "modules.h"
|
||||
|
||||
extern "C" {
|
||||
int main(int, const char **);
|
||||
}
|
||||
|
||||
uintptr_t _arg_modules_phys; // This gets filled in in _start
|
||||
|
||||
j6_handle_t handle_self = 1; // Self program handle is always 1
|
||||
j6_handle_t handle_system = 2; // boot protocol is that init gets the system as handle 2
|
||||
|
||||
int
|
||||
main(int argc, const char **argv)
|
||||
{
|
||||
j6_system_log("srv.init starting");
|
||||
modules::load_all(_arg_modules_phys);
|
||||
|
||||
return 0;
|
||||
}
|
||||
8
src/user/srv.init/module.toml
Normal file
8
src/user/srv.init/module.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
name = "srv.init"
|
||||
targets = ["user"]
|
||||
deps = ["libc"]
|
||||
sources = [
|
||||
"main.cpp",
|
||||
"modules.cpp",
|
||||
"start.s",
|
||||
]
|
||||
70
src/user/srv.init/modules.cpp
Normal file
70
src/user/srv.init/modules.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "j6/errors.h"
|
||||
#include "j6/syscalls.h"
|
||||
#include "init_args.h"
|
||||
#include "pointer_manipulation.h"
|
||||
|
||||
#include "modules.h"
|
||||
|
||||
using namespace kernel::init;
|
||||
|
||||
extern j6_handle_t handle_self;
|
||||
extern j6_handle_t handle_system;
|
||||
|
||||
namespace modules {
|
||||
|
||||
static const modules_page *
|
||||
load_page(uintptr_t address)
|
||||
{
|
||||
j6_handle_t mods_vma = j6_handle_invalid;
|
||||
j6_status_t s = j6_system_map_phys(handle_system, &mods_vma, address, 0x1000, 0);
|
||||
if (s != j6_status_ok)
|
||||
exit(s);
|
||||
|
||||
s = j6_vma_map(mods_vma, handle_self, address);
|
||||
if (s != j6_status_ok)
|
||||
exit(s);
|
||||
|
||||
return reinterpret_cast<modules_page*>(address);
|
||||
}
|
||||
|
||||
void
|
||||
load_all(uintptr_t address)
|
||||
{
|
||||
module_framebuffer const *framebuffer = nullptr;
|
||||
|
||||
while (address) {
|
||||
const modules_page *page = load_page(address);
|
||||
|
||||
char message[100];
|
||||
sprintf(message, "srv.init loading %d modules from page at 0x%lx", page->count, address);
|
||||
j6_system_log(message);
|
||||
|
||||
module *mod = page->modules;
|
||||
size_t count = page->count;
|
||||
while (count--) {
|
||||
switch (mod->mod_type) {
|
||||
case module_type::framebuffer:
|
||||
framebuffer = reinterpret_cast<const module_framebuffer*>(mod);
|
||||
break;
|
||||
|
||||
case module_type::program:
|
||||
if (mod->mod_flags == module_flags::no_load)
|
||||
j6_system_log("Loaded program module");
|
||||
else
|
||||
j6_system_log("Non-loaded program module");
|
||||
break;
|
||||
|
||||
default:
|
||||
j6_system_log("Unknown module");
|
||||
}
|
||||
mod = offset_ptr<module>(mod, mod->mod_length);
|
||||
}
|
||||
|
||||
address = page->next;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace modules
|
||||
11
src/user/srv.init/modules.h
Normal file
11
src/user/srv.init/modules.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
/// \file modules.h
|
||||
/// Routines for loading initial argument modules
|
||||
|
||||
namespace modules {
|
||||
|
||||
/// Load all modules
|
||||
/// \arg address The physical address of the first page of modules
|
||||
void load_all(uintptr_t address);
|
||||
|
||||
} // namespace modules
|
||||
38
src/user/srv.init/start.s
Normal file
38
src/user/srv.init/start.s
Normal file
@@ -0,0 +1,38 @@
|
||||
extern main
|
||||
extern exit
|
||||
extern _init_libj6
|
||||
extern _arg_modules_phys
|
||||
|
||||
section .bss
|
||||
align 0x100
|
||||
init_stack_start:
|
||||
resb 0x8000 ; 16KiB stack space
|
||||
init_stack_top:
|
||||
|
||||
section .text
|
||||
|
||||
global _start:function (_start.end - _start)
|
||||
_start:
|
||||
|
||||
; No parent process exists to have created init's stack, so we override
|
||||
; _start to deal with that in two ways:
|
||||
|
||||
; 1. We create a stack in BSS and assign that to be init's first stack
|
||||
; 2. We take advantage of the fact that rsp is useless here as a way
|
||||
; for the kernel to tell init where its initial modules page is.
|
||||
mov [_arg_modules_phys], rsp
|
||||
mov rsp, init_stack_top
|
||||
push 0
|
||||
push 0
|
||||
|
||||
mov rbp, rsp
|
||||
mov rdi, rsp
|
||||
call _init_libj6
|
||||
|
||||
pop rdi
|
||||
mov rsi, rsp
|
||||
call main
|
||||
|
||||
mov rdi, rax
|
||||
call exit
|
||||
.end:
|
||||
Reference in New Issue
Block a user