Repository navigation
Expand file tree
/
Copy pathmain.cc
More file actions
93 lines (83 loc) · 3.53 KB
/
Copy pathmain.cc
File metadata and controls
93 lines (83 loc) · 3.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <cxx/string.h>
#include <cxx/units.h>
#include <libkernel/assert.h>
#include <libkernel/print.h>
#include <tar/tar.h>
#include "core/constants.h"
#include "core/loader.h"
#include "core/slab.h"
#include "core/thread.h"
#include "core/vm.h"
#include "core/event.h"
#include "platform/arch.h"
static loader::LoaderData gLoaderData;
extern "C" int __init_array_start;
extern "C" int __init_array_end;
[[noreturn]]
static void jump_to_el1(uint64_t entry, uint64_t sp) {
// Set the stack pointer for EL0
platform::arch::write_sp_el0(sp);
// Clear the lower 4 bits of SPSR_EL1 => Switch to EL0 on eret
// NOTE(kevin): We want to overwrite the entire SPSR register because in
// real hardware, this is filled with garbage. This was a nightmare.
platform::arch::write_spsr_el1(0);
// Set the ELR_EL1 to the entry point of the userspace program
platform::arch::write_elr_el1(entry);
// Jump!
asm volatile("eret");
// This is needed for the compiler to not complain about missing return
__builtin_unreachable();
}
extern "C" [[noreturn]]
void kernel_main(loader::LoaderData& args) {
libkernel::log("Hello from the kernel!\r\n");
// 1. Save the data passed in by the loader using the copy constructor
assert(args.magic == loader::LoaderData::MAGIC_VALUE, "Loader data is corrupted");
gLoaderData = loader::LoaderData{args};
libkernel::set_log_mask(gLoaderData.kernel_log_mask);
// 2. We need to clean up the loader's mess
libkernel::log("Freeing loader resources and reverting mappings...\r\n");
// a) Free loader pages + rebuild the PFN DB + init PFN allocator
core::mem::init(gLoaderData);
// b) Unmap all of the loader pages
platform::arch::write_ttbr0_el1(gLoaderData.zero_page_addr);
platform::arch::flush_tlb();
// 3. Initialize the rest of the kernel here
libkernel::log("Starting kernel initialization...\r\n");
// Run .init_array
uint64_t ctor_start_addr = reinterpret_cast<uint64_t>(&__init_array_start);
uint64_t ctor_end_addr = reinterpret_cast<uint64_t>(&__init_array_end);
for (auto p = ctor_start_addr; p < ctor_end_addr; p += sizeof(void*)) {
uint64_t fn_addr = *reinterpret_cast<uint64_t*>(p);
reinterpret_cast<void (*)()>(fn_addr)();
}
platform::exception::init();
core::slab::init();
core::thread::init();
core::event::init();
libkernel::log("Done!\r\n");
// 4. Go through the INITRD and parse the TAR & ELF files
libkernel::log("Looking for %s in INITRD...\r\n", gLoaderData.init_image);
auto rd = reinterpret_cast<void*>(gLoaderData.initrd_range.start + core::KernelOffset);
const char* init_file_name = nullptr;
void* init_file_ptr = nullptr;
for (auto& file : tar::Parser{rd}) {
if (!cxx::strcmp(file.header->name, gLoaderData.init_image)) {
init_file_ptr = file.file;
init_file_name = file.header->name;
break;
}
}
assert(init_file_ptr, "Cannot find init binary");
libkernel::log("Found the userspace init binary\r\n");
// 5. Create the init thread and jump to userspace
auto thread_result = core::thread::create(init_file_name, init_file_ptr, 1);
assert(thread_result, "Cannot create the init thread");
core::thread::schedule();
libkernel::log("Init thread %d created successfully\r\n", thread_result.unwrap());
auto entry = core::thread::cur_thread()->entry_address;
auto sp = core::thread::cur_thread()->saved_context.sp_elx;
jump_to_el1(entry, sp);
// In case the jump fails, the system will panic
panic("Failed to jump to usersace! Halting now...\r\n");
}