145 lines
4.1 KiB
C
145 lines
4.1 KiB
C
#include <common/compiler.h>
|
|
#include <kernel/alloc.h>
|
|
#include <kernel/assert.h>
|
|
#include <kernel/channel.h>
|
|
#include <kernel/clock.h>
|
|
#include <kernel/cmdline.h>
|
|
#include <kernel/console.h>
|
|
#include <kernel/elf.h>
|
|
#include <kernel/futex.h>
|
|
#include <kernel/init.h>
|
|
#include <kernel/irq.h>
|
|
#include <kernel/namespace.h>
|
|
#include <kernel/percpu.h>
|
|
#include <kernel/print.h>
|
|
#include <kernel/sched.h>
|
|
#include <kernel/vas.h>
|
|
#include <kernel/vmo.h>
|
|
#include <config.h>
|
|
#include <stdint.h>
|
|
|
|
static zn_status_t load_server(
|
|
struct boot_file* file,
|
|
const char** argv,
|
|
const char** envp,
|
|
struct namespace_desc* init_handle,
|
|
struct task** out
|
|
) {
|
|
struct vas* space;
|
|
zn_status_t status = vma_new(&space);
|
|
if (status != ZN_OK)
|
|
return status;
|
|
|
|
struct paged_vmo* file_vmo;
|
|
status = vmo_new_phys(&file_vmo);
|
|
if (status != ZN_OK)
|
|
return status;
|
|
vmo_write(&file_vmo->object, 0, HHDM_PTR(file->data), file->length, nullptr);
|
|
|
|
struct namespace* ns;
|
|
status = namespace_new(&ns);
|
|
if (status != ZN_OK)
|
|
return status;
|
|
|
|
struct exec_info info = {
|
|
.file_obj = &file_vmo->object,
|
|
.ns = ns,
|
|
.space = space,
|
|
.argv = argv,
|
|
.envp = envp,
|
|
.init_handle = init_handle,
|
|
};
|
|
|
|
kprintf("Loading executable \"%s\"\n", file->path);
|
|
return elf_load(&info, out);
|
|
}
|
|
|
|
static const char zinnia_banner[] =
|
|
"Zinnia " ZINNIA_VERSION " (" ZINNIA_ARCH ", " ZINNIA_COMPILER_ID ", " ZINNIA_LINKER_ID ")";
|
|
|
|
static void kernel_main_task(uintptr_t arg0) {
|
|
struct boot_info* info = (struct boot_info*)arg0;
|
|
kprintf("%s\n", zinnia_banner); // Say hello!
|
|
|
|
assert(info->num_files >= 1, "No init executable provided\n");
|
|
|
|
struct channel* init_ep;
|
|
struct channel* other_ep;
|
|
assert(channel_create(&init_ep, &other_ep) == ZN_OK, "Failed to create init channel\n");
|
|
|
|
struct vas* init_space;
|
|
assert(vma_new(&init_space) == ZN_OK, "");
|
|
|
|
struct boot_file* file_data = &info->files[0];
|
|
struct paged_vmo* init_file;
|
|
assert(vmo_new_phys(&init_file) == ZN_OK, "");
|
|
vmo_write(&init_file->object, 0, HHDM_PTR(file_data->data), file_data->length, nullptr);
|
|
|
|
struct namespace* ns;
|
|
assert(namespace_new(&ns) == ZN_OK, "");
|
|
|
|
struct namespace_desc init_ch_desc = {
|
|
.type = NAMESPACE_DESC_CHANNEL,
|
|
.rights = ZN_RIGHTS_ALL,
|
|
.value.channel = init_ep,
|
|
};
|
|
|
|
// Load init.
|
|
const char* init_argv[] = {"init", nullptr};
|
|
const char* init_envp[] = {nullptr};
|
|
|
|
struct task* init_task;
|
|
zn_status_t status = load_server(&info->files[0], init_argv, init_envp, &init_ch_desc, &init_task);
|
|
assert(status == ZN_OK, "Failed to load init process (%i)\n", status);
|
|
sched_add_task(&percpu_get()->sched, init_task);
|
|
|
|
// Load other daemons.
|
|
for (size_t i = 1; i < info->num_files; i++) {
|
|
struct namespace_desc ch_desc = {
|
|
.type = NAMESPACE_DESC_CHANNEL,
|
|
.rights = ZN_RIGHTS_ALL,
|
|
.value.channel = other_ep,
|
|
};
|
|
|
|
const char* argv[] = {info->files[i].path, nullptr};
|
|
const char* envp[] = {nullptr};
|
|
|
|
struct task* task;
|
|
status = load_server(&info->files[i], argv, envp, &ch_desc, &task);
|
|
assert(status == ZN_OK, "Failed to load server \"%s\": (%i)\n", info->files[i].path, status);
|
|
sched_add_task(&percpu_get()->sched, task);
|
|
}
|
|
|
|
while (true) {
|
|
arch_irq_wait();
|
|
}
|
|
}
|
|
|
|
[[noreturn]]
|
|
void kernel_main(struct boot_info* info) {
|
|
cmdline_parse(info->cmdline);
|
|
|
|
console_init();
|
|
mem_init(info->mem_map, info->num_mem_maps, info->virt_base, info->phys_base, info->hhdm_base);
|
|
rsdp_addr = info->rsdp; // TODO
|
|
percpu_init();
|
|
sched_init(&percpu_get()->sched);
|
|
futex_init();
|
|
|
|
struct task* main_task;
|
|
task_create("main", &kernel_vas, nullptr, kernel_main_task, (uintptr_t)info, &main_task);
|
|
sched_add_task(&percpu_get()->sched, main_task);
|
|
|
|
irq_unlock();
|
|
sched_yield(&percpu_get()->sched);
|
|
|
|
unreachable();
|
|
}
|
|
|
|
[[__init]]
|
|
void kernel_early_init() {
|
|
percpu_bsp_init();
|
|
percpu_get()->online = true;
|
|
irq_lock();
|
|
}
|