mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
[boot] Load programs in boot, not kernel
Remove ELF and initrd loading from the kernel. The bootloader now loads the initial programs, as it does with the kernel. Other files that were in the initrd are now on the ESP, and non-program files are just passed as modules.
This commit is contained in:
34
modules.yaml
34
modules.yaml
@@ -6,8 +6,6 @@ modules:
|
|||||||
output: jsix.elf
|
output: jsix.elf
|
||||||
target: host
|
target: host
|
||||||
deps:
|
deps:
|
||||||
- elf
|
|
||||||
- initrd
|
|
||||||
- kutil
|
- kutil
|
||||||
includes:
|
includes:
|
||||||
- src/kernel
|
- src/kernel
|
||||||
@@ -81,33 +79,13 @@ modules:
|
|||||||
nulldrv:
|
nulldrv:
|
||||||
kind: exe
|
kind: exe
|
||||||
target: user
|
target: user
|
||||||
output: nulldrv
|
output: nulldrv.elf
|
||||||
deps:
|
deps:
|
||||||
- libc
|
- libc
|
||||||
source:
|
source:
|
||||||
- src/drivers/nulldrv/main.cpp
|
- src/drivers/nulldrv/main.cpp
|
||||||
- src/drivers/nulldrv/main.s
|
- src/drivers/nulldrv/main.s
|
||||||
|
|
||||||
elf:
|
|
||||||
kind: lib
|
|
||||||
output: libelf.a
|
|
||||||
deps:
|
|
||||||
- kutil
|
|
||||||
includes:
|
|
||||||
- src/libraries/elf/include
|
|
||||||
source:
|
|
||||||
- src/libraries/elf/elf.cpp
|
|
||||||
|
|
||||||
initrd:
|
|
||||||
kind: lib
|
|
||||||
output: libinitrd.a
|
|
||||||
deps:
|
|
||||||
- kutil
|
|
||||||
includes:
|
|
||||||
- src/libraries/initrd/include
|
|
||||||
source:
|
|
||||||
- src/libraries/initrd/initrd.cpp
|
|
||||||
|
|
||||||
kutil:
|
kutil:
|
||||||
kind: lib
|
kind: lib
|
||||||
output: libkutil.a
|
output: libkutil.a
|
||||||
@@ -298,16 +276,6 @@ modules:
|
|||||||
- src/libraries/libc/time/time.c
|
- src/libraries/libc/time/time.c
|
||||||
- src/libraries/libc/time/timespec_get.c
|
- src/libraries/libc/time/timespec_get.c
|
||||||
|
|
||||||
makerd:
|
|
||||||
kind: exe
|
|
||||||
target: native
|
|
||||||
output: makerd
|
|
||||||
deps:
|
|
||||||
- initrd
|
|
||||||
source:
|
|
||||||
- src/tools/makerd/entry.cpp
|
|
||||||
- src/tools/makerd/main.cpp
|
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
kind: exe
|
kind: exe
|
||||||
target: native
|
target: native
|
||||||
|
|||||||
@@ -119,10 +119,6 @@ rule dump
|
|||||||
description = Dumping decompiled $name
|
description = Dumping decompiled $name
|
||||||
command = objdump -DSC -M intel $in > $out
|
command = objdump -DSC -M intel $in > $out
|
||||||
|
|
||||||
rule makerd
|
|
||||||
description = Making init ramdisk
|
|
||||||
command = $builddir/native/makerd $in $out
|
|
||||||
|
|
||||||
rule makest
|
rule makest
|
||||||
description = Making symbol table
|
description = Making symbol table
|
||||||
command = nm $in | ${srcroot}/scripts/build_symbol_table.py $out
|
command = nm $in | ${srcroot}/scripts/build_symbol_table.py $out
|
||||||
@@ -191,15 +187,18 @@ build $builddir/fatroot/jsix.elf : cp $builddir/jsix.elf
|
|||||||
build $builddir/fatroot/efi/boot/bootx64.efi : cp $builddir/boot/boot.efi
|
build $builddir/fatroot/efi/boot/bootx64.efi : cp $builddir/boot/boot.efi
|
||||||
name = bootloader to FAT image
|
name = bootloader to FAT image
|
||||||
|
|
||||||
build ${builddir}/symbol_table.dat : makest ${builddir}/jsix.elf
|
build $builddir/fatroot/nulldrv.elf : cp $builddir/user/nulldrv.elf
|
||||||
|
name = null driver to FAT image
|
||||||
|
|
||||||
build $builddir/fatroot/initrd.img : makerd ${srcroot}/assets/initrd.toml | $
|
build $builddir/fatroot/terminal.elf : cp $builddir/user/nulldrv.elf
|
||||||
${builddir}/native/makerd $
|
name = terminal driver to FAT image
|
||||||
${builddir}/user/nulldrv $
|
|
||||||
${builddir}/symbol_table.dat
|
build ${builddir}/fatroot/symbol_table.dat : makest ${builddir}/jsix.elf
|
||||||
|
|
||||||
build $builddir/jsix.img : makefat | $
|
build $builddir/jsix.img : makefat | $
|
||||||
$builddir/fatroot/initrd.img $
|
$builddir/fatroot/symbol_table.dat $
|
||||||
|
$builddir/fatroot/nulldrv.elf $
|
||||||
|
$builddir/fatroot/terminal.elf $
|
||||||
$builddir/fatroot/jsix.elf $
|
$builddir/fatroot/jsix.elf $
|
||||||
$builddir/fatroot/efi/boot/bootx64.efi
|
$builddir/fatroot/efi/boot/bootx64.efi
|
||||||
name = jsix.img
|
name = jsix.img
|
||||||
|
|||||||
@@ -50,19 +50,19 @@ file::open(const wchar_t *path)
|
|||||||
return file(fh, m_bs);
|
return file(fh, m_bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
buffer
|
||||||
file::load(size_t *out_size, uefi::memory_type mem_type)
|
file::load(uefi::memory_type mem_type)
|
||||||
{
|
{
|
||||||
uint8_t buffer[sizeof(uefi::protos::file_info) + 100];
|
uint8_t info_buf[sizeof(uefi::protos::file_info) + 100];
|
||||||
size_t size = sizeof(buffer);
|
size_t size = sizeof(info_buf);
|
||||||
uefi::guid info_guid = uefi::protos::file_info::guid;
|
uefi::guid info_guid = uefi::protos::file_info::guid;
|
||||||
|
|
||||||
try_or_raise(
|
try_or_raise(
|
||||||
m_file->get_info(&info_guid, &size, &buffer),
|
m_file->get_info(&info_guid, &size, &info_buf),
|
||||||
L"Could not get file info");
|
L"Could not get file info");
|
||||||
|
|
||||||
uefi::protos::file_info *info =
|
uefi::protos::file_info *info =
|
||||||
reinterpret_cast<uefi::protos::file_info*>(&buffer);
|
reinterpret_cast<uefi::protos::file_info*>(&info_buf);
|
||||||
|
|
||||||
size_t pages = memory::bytes_to_pages(info->file_size);
|
size_t pages = memory::bytes_to_pages(info->file_size);
|
||||||
void *data = nullptr;
|
void *data = nullptr;
|
||||||
@@ -77,8 +77,7 @@ file::load(size_t *out_size, uefi::memory_type mem_type)
|
|||||||
m_file->read(&size, data),
|
m_file->read(&size, data),
|
||||||
L"Could not read from file");
|
L"Could not read from file");
|
||||||
|
|
||||||
*out_size = size;
|
return { .data = data, .size = size };
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
file
|
file
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <uefi/types.h>
|
#include <uefi/types.h>
|
||||||
#include <uefi/boot_services.h>
|
#include <uefi/boot_services.h>
|
||||||
#include <uefi/protos/file.h>
|
#include <uefi/protos/file.h>
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
namespace boot {
|
namespace boot {
|
||||||
namespace fs {
|
namespace fs {
|
||||||
@@ -22,13 +23,10 @@ public:
|
|||||||
file open(const wchar_t *path);
|
file open(const wchar_t *path);
|
||||||
|
|
||||||
/// Load the contents of this file into memory.
|
/// Load the contents of this file into memory.
|
||||||
/// \arg out_size _out:_ The number of bytes loaded
|
|
||||||
/// \arg mem_type The UEFI memory type to use for allocation
|
/// \arg mem_type The UEFI memory type to use for allocation
|
||||||
/// \returns A pointer to the loaded memory. Memory will be
|
/// \returns A buffer describing the loaded memory. The
|
||||||
/// page-aligned.
|
/// memory will be page-aligned.
|
||||||
void * load(
|
buffer load(uefi::memory_type mem_type = uefi::memory_type::loader_data);
|
||||||
size_t *out_size,
|
|
||||||
uefi::memory_type mem_type = uefi::memory_type::loader_data);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend file get_boot_volume(uefi::handle, uefi::boot_services*);
|
friend file get_boot_volume(uefi::handle, uefi::boot_services*);
|
||||||
|
|||||||
@@ -5,12 +5,32 @@
|
|||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "fs.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
|
|
||||||
|
namespace args = kernel::args;
|
||||||
|
|
||||||
namespace boot {
|
namespace boot {
|
||||||
namespace loader {
|
namespace loader {
|
||||||
|
|
||||||
|
buffer
|
||||||
|
load_file(
|
||||||
|
fs::file &disk,
|
||||||
|
const wchar_t *name,
|
||||||
|
const wchar_t *path,
|
||||||
|
uefi::memory_type type)
|
||||||
|
{
|
||||||
|
status_line status(L"Loading file", name);
|
||||||
|
|
||||||
|
fs::file file = disk.open(path);
|
||||||
|
buffer b = file.load(type);
|
||||||
|
|
||||||
|
console::print(L" Loaded at: 0x%lx, %d bytes\r\n", b.data, b.size);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
is_elfheader_valid(const elf::header *header)
|
is_elfheader_valid(const elf::header *header)
|
||||||
{
|
{
|
||||||
@@ -26,54 +46,68 @@ is_elfheader_valid(const elf::header *header)
|
|||||||
header->header_version == elf::version;
|
header->header_version == elf::version;
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel::entrypoint
|
void
|
||||||
load(
|
load_program(
|
||||||
const void *data, size_t size,
|
args::program &program,
|
||||||
kernel::args::header *args,
|
const wchar_t *name,
|
||||||
|
buffer data,
|
||||||
uefi::boot_services *bs)
|
uefi::boot_services *bs)
|
||||||
{
|
{
|
||||||
status_line status(L"Loading kernel ELF binary");
|
status_line status(L"Loading program:", name);
|
||||||
const elf::header *header = reinterpret_cast<const elf::header*>(data);
|
const elf::header *header = reinterpret_cast<const elf::header*>(data.data);
|
||||||
|
|
||||||
if (size < sizeof(elf::header) || !is_elfheader_valid(header))
|
if (data.size < sizeof(elf::header) || !is_elfheader_valid(header))
|
||||||
error::raise(uefi::status::load_error, L"Kernel ELF not valid");
|
error::raise(uefi::status::load_error, L"ELF file not valid");
|
||||||
|
|
||||||
paging::page_table *pml4 = reinterpret_cast<paging::page_table*>(args->pml4);
|
uintptr_t prog_base = uintptr_t(-1);
|
||||||
|
uintptr_t prog_end = 0;
|
||||||
|
|
||||||
for (int i = 0; i < header->ph_num; ++i) {
|
for (int i = 0; i < header->ph_num; ++i) {
|
||||||
ptrdiff_t offset = header->ph_offset + i * header->ph_entsize;
|
ptrdiff_t offset = header->ph_offset + i * header->ph_entsize;
|
||||||
const elf::program_header *pheader =
|
const elf::program_header *pheader =
|
||||||
offset_ptr<elf::program_header>(data, offset);
|
offset_ptr<elf::program_header>(data.data, offset);
|
||||||
|
|
||||||
if (pheader->type != elf::PT_LOAD)
|
if (pheader->type != elf::PT_LOAD)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
size_t num_pages = memory::bytes_to_pages(pheader->mem_size);
|
uintptr_t end = pheader->vaddr + pheader->mem_size;
|
||||||
|
if (pheader->vaddr < prog_base) prog_base = pheader->vaddr;
|
||||||
|
if (end > prog_end) prog_end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t total_size = prog_end - prog_base;
|
||||||
|
size_t num_pages = memory::bytes_to_pages(total_size);
|
||||||
void *pages = nullptr;
|
void *pages = nullptr;
|
||||||
|
|
||||||
try_or_raise(
|
try_or_raise(
|
||||||
bs->allocate_pages(uefi::allocate_type::any_pages,
|
bs->allocate_pages(uefi::allocate_type::any_pages,
|
||||||
memory::kernel_type, num_pages, &pages),
|
memory::program_type, num_pages, &pages),
|
||||||
L"Failed allocating space for kernel code");
|
L"Failed allocating space for program");
|
||||||
|
|
||||||
void *data_start = offset_ptr<void>(data, pheader->offset);
|
bs->set_mem(pages, total_size, 0);
|
||||||
bs->copy_mem(pages, data_start, pheader->file_size);
|
|
||||||
|
|
||||||
if (pheader->mem_size > pheader->file_size) {
|
for (int i = 0; i < header->ph_num; ++i) {
|
||||||
void *extra = offset_ptr<void>(pages, pheader->file_size);
|
ptrdiff_t offset = header->ph_offset + i * header->ph_entsize;
|
||||||
size_t size = pheader->mem_size - pheader->file_size;
|
const elf::program_header *pheader =
|
||||||
bs->set_mem(extra, size, 0);
|
offset_ptr<elf::program_header>(data.data, offset);
|
||||||
}
|
|
||||||
|
if (pheader->type != elf::PT_LOAD)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
void *src_start = offset_ptr<void>(data.data, pheader->offset);
|
||||||
|
void *dest_start = offset_ptr<void>(pages, pheader->vaddr - prog_base);
|
||||||
|
bs->copy_mem(dest_start, src_start, pheader->file_size);
|
||||||
|
|
||||||
console::print(L" section %d phys: 0x%lx\r\n", i, pages);
|
console::print(L" section %d phys: 0x%lx\r\n", i, pages);
|
||||||
console::print(L" section %d virt: 0x%lx\r\n", i, pheader->vaddr);
|
console::print(L" section %d virt: 0x%lx\r\n", i, pheader->vaddr);
|
||||||
|
|
||||||
// TODO: set appropriate RWX permissions
|
|
||||||
paging::map_pages(pml4, args, reinterpret_cast<uintptr_t>(pages), pheader->vaddr, pheader->mem_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console::print(L" entrypoint: 0x%lx\r\n", header->entrypoint);
|
console::print(L" entrypoint: 0x%lx\r\n", header->entrypoint);
|
||||||
return reinterpret_cast<kernel::entrypoint>(header->entrypoint);
|
|
||||||
|
program.phys_addr = reinterpret_cast<uintptr_t>(pages);
|
||||||
|
program.size = total_size;
|
||||||
|
program.virt_addr = prog_base;
|
||||||
|
program.entrypoint = header->entrypoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace loader
|
} // namespace loader
|
||||||
|
|||||||
@@ -5,18 +5,36 @@
|
|||||||
#include <uefi/boot_services.h>
|
#include <uefi/boot_services.h>
|
||||||
|
|
||||||
#include "kernel_args.h"
|
#include "kernel_args.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
namespace boot {
|
namespace boot {
|
||||||
|
|
||||||
|
namespace fs { class file; }
|
||||||
|
|
||||||
namespace loader {
|
namespace loader {
|
||||||
|
|
||||||
|
/// 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 type Memory type to use for allocation
|
||||||
|
buffer
|
||||||
|
load_file(
|
||||||
|
fs::file &disk,
|
||||||
|
const wchar_t *name,
|
||||||
|
const wchar_t *path,
|
||||||
|
uefi::memory_type type = uefi::memory_type::loader_data);
|
||||||
|
|
||||||
/// Parse and load an ELF file in memory into a loaded image.
|
/// Parse and load an ELF file in memory into a loaded image.
|
||||||
/// \arg data The start of the ELF file in memory
|
/// \arg program The program structure to fill
|
||||||
/// \arg size The size of the ELF file in memory
|
/// \arg data Buffer of the ELF file in memory
|
||||||
/// \arg args The kernel args, used for modifying page tables
|
/// \arg bs Boot services
|
||||||
/// \returns A descriptor defining the loaded image
|
void
|
||||||
kernel::entrypoint load(
|
load_program(
|
||||||
const void *data, size_t size,
|
kernel::args::program &program,
|
||||||
kernel::args::header *args,
|
const wchar_t *name,
|
||||||
|
buffer data,
|
||||||
uefi::boot_services *bs);
|
uefi::boot_services *bs);
|
||||||
|
|
||||||
} // namespace loader
|
} // namespace loader
|
||||||
|
|||||||
@@ -21,9 +21,24 @@ namespace kernel {
|
|||||||
#include "kernel_memory.h"
|
#include "kernel_memory.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace args = kernel::args;
|
||||||
|
|
||||||
namespace boot {
|
namespace boot {
|
||||||
|
|
||||||
constexpr int max_modules = 10; // Max modules to allocate room for
|
constexpr int max_modules = 5; // Max modules to allocate room for
|
||||||
|
constexpr int max_programs = 5; // Max programs to allocate room for
|
||||||
|
|
||||||
|
struct program_desc
|
||||||
|
{
|
||||||
|
const wchar_t *name;
|
||||||
|
const wchar_t *path;
|
||||||
|
};
|
||||||
|
|
||||||
|
const program_desc program_list[] = {
|
||||||
|
{L"kernel", L"jsix.elf"},
|
||||||
|
{L"null driver", L"nulldrv.elf"},
|
||||||
|
{L"terminal driver", L"terminal.elf"},
|
||||||
|
};
|
||||||
|
|
||||||
/// Change a pointer to point to the higher-half linear-offset version
|
/// Change a pointer to point to the higher-half linear-offset version
|
||||||
/// of the address it points to.
|
/// of the address it points to.
|
||||||
@@ -34,19 +49,21 @@ void change_pointer(T *&pointer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate space for kernel args. Allocates enough space from pool
|
/// Allocate space for kernel args. Allocates enough space from pool
|
||||||
/// memory for the args header and `max_modules` module headers.
|
/// memory for the args header and the module and program headers.
|
||||||
kernel::args::header *
|
args::header *
|
||||||
allocate_args_structure(
|
allocate_args_structure(
|
||||||
uefi::boot_services *bs,
|
uefi::boot_services *bs,
|
||||||
size_t max_modules)
|
size_t max_modules,
|
||||||
|
size_t max_programs)
|
||||||
{
|
{
|
||||||
status_line status(L"Setting up kernel args memory");
|
status_line status(L"Setting up kernel args memory");
|
||||||
|
|
||||||
kernel::args::header *args = nullptr;
|
args::header *args = nullptr;
|
||||||
|
|
||||||
size_t args_size =
|
size_t args_size =
|
||||||
sizeof(kernel::args::header) + // The header itself
|
sizeof(args::header) + // The header itself
|
||||||
max_modules * sizeof(kernel::args::module); // The module structures
|
max_modules * sizeof(args::module) + // The module structures
|
||||||
|
max_programs * sizeof(args::program); // The program structures
|
||||||
|
|
||||||
try_or_raise(
|
try_or_raise(
|
||||||
bs->allocate_pool(memory::args_type, args_size,
|
bs->allocate_pool(memory::args_type, args_size,
|
||||||
@@ -56,47 +73,34 @@ allocate_args_structure(
|
|||||||
bs->set_mem(args, args_size, 0);
|
bs->set_mem(args, args_size, 0);
|
||||||
|
|
||||||
args->modules =
|
args->modules =
|
||||||
reinterpret_cast<kernel::args::module*>(args + 1);
|
reinterpret_cast<args::module*>(args + 1);
|
||||||
args->num_modules = 0;
|
args->num_modules = 0;
|
||||||
|
|
||||||
|
args->programs =
|
||||||
|
reinterpret_cast<args::program*>(args->modules + max_modules);
|
||||||
|
args->num_programs = 0;
|
||||||
|
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load a file from disk into memory. Also adds an entry to the kernel
|
/// Add a module to the kernel args list
|
||||||
/// args module headers pointing at the loaded data.
|
inline void
|
||||||
/// \arg disk The opened UEFI filesystem to load from
|
add_module(args::header *args, args::mod_type type, buffer &data)
|
||||||
/// \arg args The kernel args header to update with module information
|
|
||||||
/// \arg name Name of the module (informational only)
|
|
||||||
/// \arg path Path on `disk` of the file to load
|
|
||||||
/// \arg type Type specifier of this module (eg, initrd or kernel)
|
|
||||||
kernel::args::module *
|
|
||||||
load_module(
|
|
||||||
fs::file &disk,
|
|
||||||
kernel::args::header *args,
|
|
||||||
const wchar_t *name,
|
|
||||||
const wchar_t *path,
|
|
||||||
kernel::args::mod_type type)
|
|
||||||
{
|
{
|
||||||
status_line status(L"Loading module", name);
|
args::module &m = args->modules[args->num_modules++];
|
||||||
|
m.type = type;
|
||||||
fs::file file = disk.open(path);
|
m.location = data.data;
|
||||||
kernel::args::module &module = args->modules[args->num_modules++];
|
m.size = data.size;
|
||||||
module.type = type;
|
|
||||||
module.location = file.load(&module.size, memory::module_type);
|
|
||||||
|
|
||||||
console::print(L" Loaded at: 0x%lx, %d bytes\r\n", module.location, module.size);
|
|
||||||
return &module;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The main procedure for the portion of the loader that runs while
|
/// 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
|
/// UEFI is still in control of the machine. (ie, while the loader still
|
||||||
/// has access to boot services.
|
/// has access to boot services.
|
||||||
kernel::args::header *
|
args::header *
|
||||||
bootloader_main_uefi(
|
bootloader_main_uefi(
|
||||||
uefi::handle image,
|
uefi::handle image,
|
||||||
uefi::system_table *st,
|
uefi::system_table *st,
|
||||||
console &con,
|
console &con)
|
||||||
kernel::entrypoint *kentry)
|
|
||||||
{
|
{
|
||||||
error::uefi_handler handler(con);
|
error::uefi_handler handler(con);
|
||||||
status_line status(L"Performing UEFI pre-boot");
|
status_line status(L"Performing UEFI pre-boot");
|
||||||
@@ -105,27 +109,32 @@ bootloader_main_uefi(
|
|||||||
uefi::runtime_services *rs = st->runtime_services;
|
uefi::runtime_services *rs = st->runtime_services;
|
||||||
memory::init_pointer_fixup(bs, rs);
|
memory::init_pointer_fixup(bs, rs);
|
||||||
|
|
||||||
kernel::args::header *args =
|
args::header *args =
|
||||||
allocate_args_structure(bs, max_modules);
|
allocate_args_structure(bs, max_modules, max_programs);
|
||||||
|
|
||||||
args->magic = kernel::args::magic;
|
args->magic = args::magic;
|
||||||
args->version = kernel::args::version;
|
args->version = args::version;
|
||||||
args->runtime_services = rs;
|
args->runtime_services = rs;
|
||||||
args->acpi_table = hw::find_acpi_table(st);
|
args->acpi_table = hw::find_acpi_table(st);
|
||||||
|
paging::allocate_tables(args, bs);
|
||||||
|
|
||||||
memory::mark_pointer_fixup(&args->runtime_services);
|
memory::mark_pointer_fixup(&args->runtime_services);
|
||||||
|
|
||||||
fs::file disk = fs::get_boot_volume(image, bs);
|
fs::file disk = fs::get_boot_volume(image, bs);
|
||||||
load_module(disk, args, L"initrd", L"initrd.img", kernel::args::mod_type::initrd);
|
|
||||||
|
|
||||||
kernel::args::module *kernel =
|
const uefi::memory_type mod_type = memory::module_type;
|
||||||
load_module(disk, args, L"kernel", L"jsix.elf", kernel::args::mod_type::kernel);
|
buffer symbols = loader::load_file(disk, L"symbol table", L"symbol_table.dat",
|
||||||
|
memory::module_type);
|
||||||
|
add_module(args, args::mod_type::symbol_table, symbols);
|
||||||
|
|
||||||
paging::allocate_tables(args, bs);
|
for (auto &desc : program_list) {
|
||||||
*kentry = loader::load(kernel->location, kernel->size, args, bs);
|
buffer buf = loader::load_file(disk, desc.name, desc.path);
|
||||||
|
args::program &program = args->programs[args->num_programs++];
|
||||||
|
loader::load_program(program, desc.name, buf, bs);
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < args->num_modules; ++i) {
|
for (unsigned i = 0; i < args->num_modules; ++i) {
|
||||||
kernel::args::module &mod = args->modules[i];
|
args::module &mod = args->modules[i];
|
||||||
change_pointer(mod.location);
|
change_pointer(mod.location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,9 +152,13 @@ efi_main(uefi::handle image_handle, uefi::system_table *st)
|
|||||||
error::cpu_assert_handler handler;
|
error::cpu_assert_handler handler;
|
||||||
console con(st->boot_services, st->con_out);
|
console con(st->boot_services, st->con_out);
|
||||||
|
|
||||||
kernel::entrypoint kentry = nullptr;
|
args::header *args =
|
||||||
kernel::args::header *args =
|
bootloader_main_uefi(image_handle, st, con);
|
||||||
bootloader_main_uefi(image_handle, st, con, &kentry);
|
|
||||||
|
args::program &kernel = args->programs[0];
|
||||||
|
paging::map_pages(args, kernel.phys_addr, kernel.virt_addr, kernel.size);
|
||||||
|
kernel::entrypoint kentry =
|
||||||
|
reinterpret_cast<kernel::entrypoint>(kernel.entrypoint);
|
||||||
|
|
||||||
memory::efi_mem_map map =
|
memory::efi_mem_map map =
|
||||||
memory::build_kernel_mem_map(args, st->boot_services);
|
memory::build_kernel_mem_map(args, st->boot_services);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ memory_type_name(uefi::memory_type t)
|
|||||||
switch(t) {
|
switch(t) {
|
||||||
case args_type: return L"jsix kernel args";
|
case args_type: return L"jsix kernel args";
|
||||||
case module_type: return L"jsix bootloader module";
|
case module_type: return L"jsix bootloader module";
|
||||||
case kernel_type: return L"jsix kernel code";
|
case program_type: return L"jsix kernel or program code";
|
||||||
case table_type: return L"jsix page tables";
|
case table_type: return L"jsix page tables";
|
||||||
default: return L"Bad Type Value";
|
default: return L"Bad Type Value";
|
||||||
}
|
}
|
||||||
@@ -195,8 +195,8 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs)
|
|||||||
type = mem_type::module;
|
type = mem_type::module;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kernel_type:
|
case program_type:
|
||||||
type = mem_type::kernel;
|
type = mem_type::program;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case table_type:
|
case table_type:
|
||||||
@@ -233,21 +233,7 @@ build_kernel_mem_map(kernel::args::header *args, uefi::boot_services *bs)
|
|||||||
|
|
||||||
// Give just the actually-set entries in the header
|
// Give just the actually-set entries in the header
|
||||||
args->mem_map = kernel_map;
|
args->mem_map = kernel_map;
|
||||||
args->num_map_entries = i;
|
args->map_count = i;
|
||||||
|
|
||||||
// But pass the entire allocated area in a module as well
|
|
||||||
kernel::args::module &module = args->modules[args->num_modules++];
|
|
||||||
module.location = reinterpret_cast<void*>(kernel_map);
|
|
||||||
module.size = map_size;
|
|
||||||
module.type = kernel::args::mod_type::memory_map;
|
|
||||||
|
|
||||||
/*
|
|
||||||
for (size_t i = 0; i<map.num_entries(); ++i) {
|
|
||||||
mem_entry &ent = kernel_map[i];
|
|
||||||
console::print(L" Range %lx (%x) %d [%lu]\r\n",
|
|
||||||
ent.start, ent.attr, ent.type, ent.pages);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
return efi_map;
|
return efi_map;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ constexpr uefi::memory_type args_type =
|
|||||||
constexpr uefi::memory_type module_type =
|
constexpr uefi::memory_type module_type =
|
||||||
static_cast<uefi::memory_type>(0x80000001);
|
static_cast<uefi::memory_type>(0x80000001);
|
||||||
|
|
||||||
/// Memory containing loaded kernel code and data sections
|
/// Memory containing loaded kernel or program code and data sections
|
||||||
constexpr uefi::memory_type kernel_type =
|
constexpr uefi::memory_type program_type =
|
||||||
static_cast<uefi::memory_type>(0x80000002);
|
static_cast<uefi::memory_type>(0x80000002);
|
||||||
|
|
||||||
/// Memory containing page tables set up by the loader
|
/// Memory containing page tables set up by the loader
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ public:
|
|||||||
uintptr_t virt,
|
uintptr_t virt,
|
||||||
page_table *pml4,
|
page_table *pml4,
|
||||||
void *&page_cache,
|
void *&page_cache,
|
||||||
uint32_t &cache_count) :
|
size_t &cache_count) :
|
||||||
m_page_cache(page_cache),
|
m_page_cache(page_cache),
|
||||||
m_cache_count(cache_count)
|
m_cache_count(cache_count)
|
||||||
{
|
{
|
||||||
@@ -130,14 +130,14 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *&m_page_cache;
|
void *&m_page_cache;
|
||||||
uint32_t &m_cache_count;
|
size_t &m_cache_count;
|
||||||
page_table *m_table[D];
|
page_table *m_table[D];
|
||||||
uint16_t m_index[D];
|
uint16_t m_index[D];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_offset_mappings(page_table *pml4, void *&page_cache, uint32_t &num_pages)
|
add_offset_mappings(page_table *pml4, void *&page_cache, size_t &num_pages)
|
||||||
{
|
{
|
||||||
uintptr_t phys = 0;
|
uintptr_t phys = 0;
|
||||||
uintptr_t virt = ::memory::page_offset; // Start of offset-mapped area
|
uintptr_t virt = ::memory::page_offset; // Start of offset-mapped area
|
||||||
@@ -160,7 +160,7 @@ add_offset_mappings(page_table *pml4, void *&page_cache, uint32_t &num_pages)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_kernel_pds(page_table *pml4, void *&page_cache, uint32_t &num_pages)
|
add_kernel_pds(page_table *pml4, void *&page_cache, size_t &num_pages)
|
||||||
{
|
{
|
||||||
for (unsigned i = pml4e_kernel; i < table_entries; ++i) {
|
for (unsigned i = pml4e_kernel; i < table_entries; ++i) {
|
||||||
pml4->set(i, page_cache, table_flags);
|
pml4->set(i, page_cache, table_flags);
|
||||||
@@ -208,34 +208,31 @@ allocate_tables(kernel::args::header *args, uefi::boot_services *bs)
|
|||||||
|
|
||||||
bs->set_mem(addr, tables_needed*page_size, 0);
|
bs->set_mem(addr, tables_needed*page_size, 0);
|
||||||
|
|
||||||
kernel::args::module &mod = args->modules[++args->num_modules];
|
|
||||||
mod.type = kernel::args::mod_type::page_tables;
|
|
||||||
mod.location = addr;
|
|
||||||
mod.size = tables_needed*page_size;
|
|
||||||
|
|
||||||
args->pml4 = addr;
|
args->pml4 = addr;
|
||||||
args->num_free_tables = tables_needed - 1;
|
args->table_count = tables_needed - 1;
|
||||||
args->page_table_cache = offset_ptr<void>(addr, page_size);
|
args->page_tables = offset_ptr<void>(addr, page_size);
|
||||||
|
|
||||||
page_table *pml4 = reinterpret_cast<page_table*>(addr);
|
page_table *pml4 = reinterpret_cast<page_table*>(addr);
|
||||||
add_kernel_pds(pml4, args->page_table_cache, args->num_free_tables);
|
add_kernel_pds(pml4, args->page_tables, args->table_count);
|
||||||
add_offset_mappings(pml4, args->page_table_cache, args->num_free_tables);
|
add_offset_mappings(pml4, args->page_tables, args->table_count);
|
||||||
|
|
||||||
console::print(L" Set up initial mappings, %d spare tables.\r\n", args->num_free_tables);
|
console::print(L" Set up initial mappings, %d spare tables.\r\n", args->table_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
map_pages(
|
map_pages(
|
||||||
page_table *pml4,
|
|
||||||
kernel::args::header *args,
|
kernel::args::header *args,
|
||||||
uintptr_t phys, uintptr_t virt,
|
uintptr_t phys, uintptr_t virt,
|
||||||
size_t size)
|
size_t size)
|
||||||
{
|
{
|
||||||
|
paging::page_table *pml4 =
|
||||||
|
reinterpret_cast<paging::page_table*>(args->pml4);
|
||||||
|
|
||||||
size_t pages = memory::bytes_to_pages(size);
|
size_t pages = memory::bytes_to_pages(size);
|
||||||
page_entry_iterator<4> iterator{
|
page_entry_iterator<4> iterator{
|
||||||
virt, pml4,
|
virt, pml4,
|
||||||
args->page_table_cache,
|
args->page_tables,
|
||||||
args->num_free_tables};
|
args->table_count};
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
*iterator = phys | page_flags;
|
*iterator = phys | page_flags;
|
||||||
|
|||||||
@@ -39,13 +39,11 @@ void allocate_tables(
|
|||||||
void add_current_mappings(page_table *new_pml4);
|
void add_current_mappings(page_table *new_pml4);
|
||||||
|
|
||||||
/// Map a physical address to a virtual address in the given page tables.
|
/// Map a physical address to a virtual address in the given page tables.
|
||||||
/// \arg pml4 The root of the set of page tables to be updated
|
/// \arg args The kernel args header, used for the page table cache and pml4
|
||||||
/// \arg args The kernel args header, used for the page table cache
|
|
||||||
/// \arg phys The phyiscal address to map in
|
/// \arg phys The phyiscal address to map in
|
||||||
/// \arg virt The virtual address to map in
|
/// \arg virt The virtual address to map in
|
||||||
/// \arg size The size in bytes of the mapping
|
/// \arg size The size in bytes of the mapping
|
||||||
void map_pages(
|
void map_pages(
|
||||||
page_table *pml4,
|
|
||||||
kernel::args::header *args,
|
kernel::args::header *args,
|
||||||
uintptr_t phys, uintptr_t virt,
|
uintptr_t phys, uintptr_t virt,
|
||||||
size_t bytes);
|
size_t bytes);
|
||||||
|
|||||||
13
src/boot/types.h
Normal file
13
src/boot/types.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/// \file types.h
|
||||||
|
/// Definitions of shared types used throughout the bootloader
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace boot {
|
||||||
|
|
||||||
|
struct buffer
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace boot
|
||||||
@@ -10,42 +10,28 @@ namespace args {
|
|||||||
constexpr uint32_t magic = 0x600dda7a;
|
constexpr uint32_t magic = 0x600dda7a;
|
||||||
constexpr uint16_t version = 1;
|
constexpr uint16_t version = 1;
|
||||||
|
|
||||||
enum class mod_flags : uint32_t
|
|
||||||
{
|
|
||||||
debug = 0x00000001
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class mod_type : uint32_t {
|
enum class mod_type : uint32_t {
|
||||||
unknown,
|
symbol_table,
|
||||||
|
framebuffer
|
||||||
kernel,
|
|
||||||
initrd,
|
|
||||||
|
|
||||||
memory_map,
|
|
||||||
page_tables,
|
|
||||||
framebuffer,
|
|
||||||
|
|
||||||
max
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class mode : uint8_t {
|
|
||||||
normal,
|
|
||||||
debug
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct module {
|
struct module {
|
||||||
void *location;
|
void *location;
|
||||||
size_t size;
|
size_t size;
|
||||||
mod_type type;
|
mod_type type;
|
||||||
mod_flags flags;
|
};
|
||||||
}
|
|
||||||
__attribute__((packed));
|
|
||||||
|
|
||||||
|
struct program {
|
||||||
|
uintptr_t phys_addr;
|
||||||
|
uintptr_t virt_addr;
|
||||||
|
uintptr_t entrypoint;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
enum class mem_type : uint32_t {
|
enum class mem_type : uint32_t {
|
||||||
free,
|
free,
|
||||||
args,
|
args,
|
||||||
kernel,
|
program,
|
||||||
module,
|
module,
|
||||||
table,
|
table,
|
||||||
acpi,
|
acpi,
|
||||||
@@ -61,33 +47,35 @@ struct mem_entry
|
|||||||
size_t pages;
|
size_t pages;
|
||||||
mem_type type;
|
mem_type type;
|
||||||
uint32_t attr;
|
uint32_t attr;
|
||||||
}
|
};
|
||||||
__attribute__((packed));
|
|
||||||
|
|
||||||
|
enum class boot_flags : uint16_t {
|
||||||
|
none = 0x0000,
|
||||||
|
debug = 0x0001
|
||||||
|
};
|
||||||
|
|
||||||
struct header {
|
struct header {
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
uint16_t version;
|
uint16_t version;
|
||||||
|
boot_flags flags;
|
||||||
mode mode;
|
|
||||||
|
|
||||||
uint8_t _reserved0;
|
|
||||||
|
|
||||||
void *pml4;
|
void *pml4;
|
||||||
void *page_table_cache;
|
void *page_tables;
|
||||||
uint32_t num_free_tables;
|
size_t table_count;
|
||||||
|
|
||||||
|
program *programs;
|
||||||
|
size_t num_programs;
|
||||||
|
|
||||||
uint32_t num_modules;
|
|
||||||
module *modules;
|
module *modules;
|
||||||
|
size_t num_modules;
|
||||||
|
|
||||||
mem_entry *mem_map;
|
mem_entry *mem_map;
|
||||||
size_t num_map_entries;
|
size_t map_count;
|
||||||
|
|
||||||
void *runtime_services;
|
void *runtime_services;
|
||||||
void *acpi_table;
|
void *acpi_table;
|
||||||
}
|
}
|
||||||
__attribute__((aligned(alignof(max_align_t))));
|
__attribute__((aligned(alignof(max_align_t))));
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
} // namespace args
|
} // namespace args
|
||||||
|
|
||||||
|
|||||||
@@ -2,21 +2,20 @@
|
|||||||
|
|
||||||
extern load_process_image
|
extern load_process_image
|
||||||
|
|
||||||
global ramdisk_process_loader
|
global preloaded_process_init
|
||||||
ramdisk_process_loader:
|
preloaded_process_init:
|
||||||
|
|
||||||
; create_process already pushed a cpu_state onto the stack for us, this
|
; create_process already pushed the arguments for load_process_image and
|
||||||
; acts both as the cpu_state parameter to load_process_image, and the
|
; the following iretq onto the stack for us
|
||||||
; saved state for the following iretq
|
|
||||||
|
|
||||||
pop rdi ; the address of the program image
|
pop rdi ; the physical address of the program image
|
||||||
pop rsi ; the size of the program image
|
pop rsi ; the virtual address of the program image
|
||||||
pop rdx ; the address of this thread's TCB
|
pop rdx ; the size in bytes of the program image
|
||||||
|
pop rcx ; the address of this thread's TCB
|
||||||
|
|
||||||
call load_process_image
|
call load_process_image
|
||||||
|
|
||||||
push rax ; load_process_image returns the process entrypoint
|
; the entrypoint should already be on the stack
|
||||||
|
|
||||||
swapgs
|
swapgs
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include "j6/signals.h"
|
#include "j6/signals.h"
|
||||||
|
|
||||||
#include "initrd/initrd.h"
|
|
||||||
#include "kutil/assert.h"
|
#include "kutil/assert.h"
|
||||||
#include "apic.h"
|
#include "apic.h"
|
||||||
#include "block_device.h"
|
#include "block_device.h"
|
||||||
@@ -117,56 +116,31 @@ kernel_main(args::header *header)
|
|||||||
cpu_id cpu;
|
cpu_id cpu;
|
||||||
cpu.validate();
|
cpu.validate();
|
||||||
|
|
||||||
/*
|
for (size_t i = 0; i < header->num_modules; ++i) {
|
||||||
if (header->frame_buffer && header->frame_buffer_length) {
|
args::module &mod = header->modules[i];
|
||||||
page_manager::get()->map_offset_pointer(
|
switch (mod.type) {
|
||||||
&header->frame_buffer,
|
case args::mod_type::symbol_table:
|
||||||
header->frame_buffer_length);
|
new symbol_table {mod.location, mod.size};
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
log::debug(logs::boot, " jsix header is at: %016lx", header);
|
log::debug(logs::boot, " jsix header is at: %016lx", header);
|
||||||
log::debug(logs::boot, " Memory map is at: %016lx", header->mem_map);
|
log::debug(logs::boot, " Memory map is at: %016lx", header->mem_map);
|
||||||
log::debug(logs::boot, "ACPI root table is at: %016lx", header->acpi_table);
|
log::debug(logs::boot, "ACPI root table is at: %016lx", header->acpi_table);
|
||||||
log::debug(logs::boot, "Runtime service is at: %016lx", header->runtime_services);
|
log::debug(logs::boot, "Runtime service is at: %016lx", header->runtime_services);
|
||||||
|
|
||||||
// Load the module tagged as initrd
|
|
||||||
kutil::vector<initrd::disk> initrds;
|
|
||||||
for (unsigned i = 0; i < header->num_modules; ++i) {
|
|
||||||
args::module &mod = header->modules[i];
|
|
||||||
if (mod.type != args::mod_type::initrd)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
initrd::disk &ird = initrds.emplace(mod.location);
|
|
||||||
log::info(logs::boot, "initrd loaded with %d files.", ird.files().count());
|
|
||||||
for (auto &f : ird.files()) {
|
|
||||||
char type = f.executable() ? '*' :
|
|
||||||
f.symbols() ? '+' : ' ';
|
|
||||||
log::info(logs::boot, " %c%s (%d bytes).", type, f.name(), f.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
page_manager::get()->dump_pml4(nullptr, 0);
|
|
||||||
page_manager::get()->dump_blocks(true);
|
|
||||||
*/
|
|
||||||
|
|
||||||
device_manager &devices = device_manager::get();
|
device_manager &devices = device_manager::get();
|
||||||
devices.parse_acpi(header->acpi_table);
|
devices.parse_acpi(header->acpi_table);
|
||||||
|
|
||||||
interrupts_enable();
|
interrupts_enable();
|
||||||
|
|
||||||
/*
|
|
||||||
auto r = cpu.get(0x15);
|
|
||||||
log::info(logs::boot, "CPU Crystal: %dHz", r.ecx);
|
|
||||||
|
|
||||||
uintptr_t cr4 = 0;
|
|
||||||
__asm__ __volatile__ ( "mov %%cr4, %0" : "=r" (cr4) );
|
|
||||||
log::info(logs::boot, "cr4: %016x", cr4);
|
|
||||||
*/
|
|
||||||
|
|
||||||
devices.init_drivers();
|
devices.init_drivers();
|
||||||
|
|
||||||
|
devices.get_lapic()->calibrate_timer();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
block_device *disk = devices->get_block_device(0);
|
block_device *disk = devices->get_block_device(0);
|
||||||
if (disk) {
|
if (disk) {
|
||||||
@@ -191,22 +165,15 @@ kernel_main(args::header *header)
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
devices.get_lapic()->calibrate_timer();
|
|
||||||
devices.init_drivers();
|
|
||||||
|
|
||||||
syscall_enable();
|
syscall_enable();
|
||||||
scheduler *sched = new scheduler(devices.get_lapic());
|
scheduler *sched = new scheduler(devices.get_lapic());
|
||||||
|
|
||||||
std_out = new channel;
|
std_out = new channel;
|
||||||
|
|
||||||
for (auto &ird : initrds) {
|
// Skip program 0, which is the kernel itself
|
||||||
for (auto &f : ird.files()) {
|
for (size_t i = 1; i < header->num_programs; ++i) {
|
||||||
if (f.executable()) {
|
args::program &prog = header->programs[i];
|
||||||
sched->load_process(f.name(), f.data(), f.size());
|
sched->load_process(prog.phys_addr, prog.virt_addr, prog.size, prog.entrypoint);
|
||||||
} else if (f.symbols()) {
|
|
||||||
new symbol_table {f.data(), f.size()};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sched->create_kernel_task(logger_task, scheduler::max_priority-1, true);
|
sched->create_kernel_task(logger_task, scheduler::max_priority-1, true);
|
||||||
|
|||||||
@@ -103,20 +103,19 @@ void walk_page_table(
|
|||||||
void
|
void
|
||||||
memory_initialize_pre_ctors(args::header *kargs)
|
memory_initialize_pre_ctors(args::header *kargs)
|
||||||
{
|
{
|
||||||
args::mem_entry *entries = kargs->mem_map;
|
|
||||||
size_t entry_count = kargs->num_map_entries;
|
|
||||||
page_table *kpml4 = reinterpret_cast<page_table*>(kargs->pml4);
|
|
||||||
|
|
||||||
new (&g_kernel_heap) kutil::heap_allocator {heap_start, kernel_max_heap};
|
new (&g_kernel_heap) kutil::heap_allocator {heap_start, kernel_max_heap};
|
||||||
|
|
||||||
new (&g_frame_allocator) frame_allocator;
|
new (&g_frame_allocator) frame_allocator;
|
||||||
for (unsigned i = 0; i < entry_count; ++i) {
|
|
||||||
|
args::mem_entry *entries = kargs->mem_map;
|
||||||
|
const size_t count = kargs->map_count;
|
||||||
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
// TODO: use entry attributes
|
// TODO: use entry attributes
|
||||||
args::mem_entry &e = entries[i];
|
args::mem_entry &e = entries[i];
|
||||||
if (e.type == args::mem_type::free)
|
if (e.type == args::mem_type::free)
|
||||||
g_frame_allocator.free(e.start, e.pages);
|
g_frame_allocator.free(e.start, e.pages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
page_table *kpml4 = reinterpret_cast<page_table*>(kargs->pml4);
|
||||||
process *kp = process::create_kernel_process(kpml4);
|
process *kp = process::create_kernel_process(kpml4);
|
||||||
vm_space &vm = kp->space();
|
vm_space &vm = kp->space();
|
||||||
|
|
||||||
@@ -153,7 +152,7 @@ memory_initialize_post_ctors(args::header *kargs)
|
|||||||
vm.add(memory::buffers_start, &g_kernel_buffers);
|
vm.add(memory::buffers_start, &g_kernel_buffers);
|
||||||
|
|
||||||
g_frame_allocator.free(
|
g_frame_allocator.free(
|
||||||
reinterpret_cast<uintptr_t>(kargs->page_table_cache),
|
reinterpret_cast<uintptr_t>(kargs->page_tables),
|
||||||
kargs->num_free_tables);
|
kargs->table_count);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#include "objects/vm_area.h"
|
#include "objects/vm_area.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
|
|
||||||
#include "elf/elf.h"
|
|
||||||
#include "kutil/assert.h"
|
#include "kutil/assert.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -26,8 +25,8 @@ const uint64_t rflags_noint = 0x002;
|
|||||||
const uint64_t rflags_int = 0x202;
|
const uint64_t rflags_int = 0x202;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
void ramdisk_process_loader();
|
void preloaded_process_init();
|
||||||
uintptr_t load_process_image(const void *image_start, size_t bytes, TCB *tcb);
|
void load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern uint64_t idle_stack_end;
|
extern uint64_t idle_stack_end;
|
||||||
@@ -60,8 +59,8 @@ scheduler::scheduler(lapic *apic) :
|
|||||||
bsp_cpu_data.t = idle;
|
bsp_cpu_data.t = idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t
|
void
|
||||||
load_process_image(const void *image_start, size_t bytes, TCB *tcb)
|
load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb)
|
||||||
{
|
{
|
||||||
using memory::page_align_down;
|
using memory::page_align_down;
|
||||||
using memory::page_align_up;
|
using memory::page_align_up;
|
||||||
@@ -71,53 +70,9 @@ load_process_image(const void *image_start, size_t bytes, TCB *tcb)
|
|||||||
process &proc = process::current();
|
process &proc = process::current();
|
||||||
vm_space &space = proc.space();
|
vm_space &space = proc.space();
|
||||||
|
|
||||||
log::debug(logs::loader, "Loading task! ELF: %016lx [%d]", image_start, bytes);
|
vm_area *vma = new vm_area_open(bytes, space, vm_flags::zero|vm_flags::write);
|
||||||
|
space.add(virt, vma);
|
||||||
// TODO: Handle bad images gracefully
|
vma->commit(phys, 0, memory::page_count(bytes));
|
||||||
elf::elf image(image_start, bytes);
|
|
||||||
kassert(image.valid(), "Invalid ELF passed to load_process_image");
|
|
||||||
|
|
||||||
uintptr_t vma_base = -1;
|
|
||||||
uintptr_t vma_end = 0;
|
|
||||||
|
|
||||||
const unsigned program_count = image.program_count();
|
|
||||||
for (unsigned i = 0; i < program_count; ++i) {
|
|
||||||
const elf::program_header *header = image.program(i);
|
|
||||||
|
|
||||||
if (header->type != elf::segment_type::load)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
uintptr_t base = page_align_down(header->vaddr);
|
|
||||||
uintptr_t end = page_align_up(header->vaddr + header->mem_size);
|
|
||||||
if (base < vma_base) vma_base = base;
|
|
||||||
if (end > vma_end) vma_end = end;
|
|
||||||
|
|
||||||
log::debug(logs::loader, " Loadable segment %02u: vaddr %016lx size %016lx",
|
|
||||||
i, header->vaddr, header->mem_size);
|
|
||||||
|
|
||||||
log::debug(logs::loader, " - aligned to: vaddr %016lx pages %d",
|
|
||||||
base, memory::page_count(end-base));
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_area *vma = new vm_area_open(vma_end - vma_base, space,
|
|
||||||
vm_flags::zero|vm_flags::write);
|
|
||||||
space.add(vma_base, vma);
|
|
||||||
|
|
||||||
const unsigned section_count = image.section_count();
|
|
||||||
for (unsigned i = 0; i < section_count; ++i) {
|
|
||||||
const elf::section_header *header = image.section(i);
|
|
||||||
|
|
||||||
if (header->type != elf::section_type::progbits ||
|
|
||||||
!bitfield_has(header->flags, elf::section_flags::alloc))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
log::debug(logs::loader, " Loadable section %02u: vaddr %016lx size %016lx",
|
|
||||||
i, header->addr, header->size);
|
|
||||||
|
|
||||||
void *dest = reinterpret_cast<void *>(header->addr);
|
|
||||||
const void *src = kutil::offset_pointer(image_start, header->offset);
|
|
||||||
kutil::memcpy(dest, src, header->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
tcb->rsp3 -= 2 * sizeof(uint64_t);
|
tcb->rsp3 -= 2 * sizeof(uint64_t);
|
||||||
uint64_t *sentinel = reinterpret_cast<uint64_t*>(tcb->rsp3);
|
uint64_t *sentinel = reinterpret_cast<uint64_t*>(tcb->rsp3);
|
||||||
@@ -130,10 +85,6 @@ load_process_image(const void *image_start, size_t bytes, TCB *tcb)
|
|||||||
init->output = proc.add_handle(std_out);
|
init->output = proc.add_handle(std_out);
|
||||||
|
|
||||||
thread::current().clear_state(thread::state::loading);
|
thread::current().clear_state(thread::state::loading);
|
||||||
|
|
||||||
uintptr_t entrypoint = image.entrypoint();
|
|
||||||
log::debug(logs::loader, " Loaded! New thread rip: %016lx", entrypoint);
|
|
||||||
return entrypoint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
thread *
|
thread *
|
||||||
@@ -153,7 +104,7 @@ scheduler::create_process(bool user)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
scheduler::load_process(const char *name, const void *data, size_t size)
|
scheduler::load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t entry)
|
||||||
{
|
{
|
||||||
|
|
||||||
uint16_t kcs = (1 << 3) | 0; // Kernel CS is GDT entry 1, ring 0
|
uint16_t kcs = (1 << 3) | 0; // Kernel CS is GDT entry 1, ring 0
|
||||||
@@ -166,25 +117,27 @@ scheduler::load_process(const char *name, const void *data, size_t size)
|
|||||||
auto *tcb = th->tcb();
|
auto *tcb = th->tcb();
|
||||||
|
|
||||||
// Create an initial kernel stack space
|
// Create an initial kernel stack space
|
||||||
uintptr_t *stack = reinterpret_cast<uintptr_t *>(tcb->rsp0) - 7;
|
uintptr_t *stack = reinterpret_cast<uintptr_t *>(tcb->rsp0) - 9;
|
||||||
|
|
||||||
// Pass args to ramdisk_process_loader on the stack
|
// Pass args to preloaded_process_init on the stack
|
||||||
stack[0] = reinterpret_cast<uintptr_t>(data);
|
stack[0] = reinterpret_cast<uintptr_t>(phys);
|
||||||
stack[1] = reinterpret_cast<uintptr_t>(size);
|
stack[1] = reinterpret_cast<uintptr_t>(virt);
|
||||||
stack[2] = reinterpret_cast<uintptr_t>(tcb);
|
stack[2] = reinterpret_cast<uintptr_t>(size);
|
||||||
|
stack[3] = reinterpret_cast<uintptr_t>(tcb);
|
||||||
|
|
||||||
tcb->rsp = reinterpret_cast<uintptr_t>(stack);
|
tcb->rsp = reinterpret_cast<uintptr_t>(stack);
|
||||||
th->add_thunk_kernel(reinterpret_cast<uintptr_t>(ramdisk_process_loader));
|
th->add_thunk_kernel(reinterpret_cast<uintptr_t>(preloaded_process_init));
|
||||||
|
|
||||||
// Arguments for iret - rip will be pushed on before these
|
// Arguments for iret - rip will be pushed on before these
|
||||||
stack[3] = cs;
|
stack[4] = reinterpret_cast<uintptr_t>(entry);
|
||||||
stack[4] = rflags_int;
|
stack[5] = cs;
|
||||||
stack[5] = process::stacks_top;
|
stack[6] = rflags_int;
|
||||||
stack[6] = ss;
|
stack[7] = process::stacks_top;
|
||||||
|
stack[8] = ss;
|
||||||
|
|
||||||
tcb->rsp3 = process::stacks_top;
|
tcb->rsp3 = process::stacks_top;
|
||||||
|
|
||||||
log::debug(logs::task, "Loading thread %s: koid %llx pri %d", name, th->koid(), tcb->priority);
|
log::debug(logs::task, "Loading thread %llx pri %d", th->koid(), tcb->priority);
|
||||||
log::debug(logs::task, " RSP %016lx", tcb->rsp);
|
log::debug(logs::task, " RSP %016lx", tcb->rsp);
|
||||||
log::debug(logs::task, " RSP0 %016lx", tcb->rsp0);
|
log::debug(logs::task, " RSP0 %016lx", tcb->rsp0);
|
||||||
log::debug(logs::task, " PML4 %016lx", tcb->pml4);
|
log::debug(logs::task, " PML4 %016lx", tcb->pml4);
|
||||||
|
|||||||
@@ -41,10 +41,11 @@ public:
|
|||||||
scheduler(lapic *apic);
|
scheduler(lapic *apic);
|
||||||
|
|
||||||
/// Create a new process from a program image in memory.
|
/// Create a new process from a program image in memory.
|
||||||
/// \arg name Name of the program image
|
/// \arg phys Physical address of the loaded program image
|
||||||
/// \arg data Pointer to the image data
|
/// \arg virt Virtual address of the loaded program image
|
||||||
/// \arg size Size of the program image, in bytes
|
/// \arg size Size of the program image, in bytes
|
||||||
void load_process(const char *name, const void *data, size_t size);
|
/// \arg entry Virtual address of the program entrypoint
|
||||||
|
void load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t entry);
|
||||||
|
|
||||||
/// Create a new kernel task
|
/// Create a new kernel task
|
||||||
/// \arg proc Function to run as a kernel task
|
/// \arg proc Function to run as a kernel task
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
|
|
||||||
#include "kutil/printf.h"
|
#include "kutil/printf.h"
|
||||||
|
|
||||||
|
#define PRINTF_DISABLE_SUPPORT_FLOAT
|
||||||
|
|
||||||
// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
|
// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
|
||||||
// printf_config.h header file
|
// printf_config.h header file
|
||||||
|
|||||||
Reference in New Issue
Block a user