kernel: implementing mapping and execution of bsp executable
This commit is contained in:
@@ -7,7 +7,32 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define BSP_MAGIC 0xcafebabe
|
||||
|
||||
struct task;
|
||||
|
||||
struct bsp_trailer {
|
||||
/* these fields are stored in big endian in the package itself */
|
||||
uint32_t bsp_magic;
|
||||
uint64_t bsp_fs_offset;
|
||||
uint32_t bsp_fs_len;
|
||||
uint64_t bsp_exec_offset;
|
||||
uint32_t bsp_exec_len;
|
||||
uint64_t bsp_text_faddr, bsp_text_vaddr, bsp_text_size;
|
||||
uint64_t bsp_data_faddr, bsp_data_vaddr, bsp_data_size;
|
||||
uint64_t bsp_exec_entry;
|
||||
} __packed;
|
||||
|
||||
struct bsp {
|
||||
/* the values in this struct are stored in host byte order */
|
||||
struct bsp_trailer bsp_trailer;
|
||||
struct vm_object *bsp_vmo;
|
||||
};
|
||||
|
||||
extern void bsp_set_location(const struct boot_module *mod);
|
||||
extern void bsp_get_location(struct boot_module *out);
|
||||
|
||||
extern kern_status_t bsp_load(struct bsp *bsp, const struct boot_module *mod);
|
||||
extern kern_status_t bsp_launch_async(struct bsp *bsp, struct task *task);
|
||||
|
||||
#endif
|
||||
|
||||
44
init/main.c
44
init/main.c
@@ -1,6 +1,8 @@
|
||||
#include <mango/arg.h>
|
||||
#include <mango/bsp.h>
|
||||
#include <mango/clock.h>
|
||||
#include <mango/cpu.h>
|
||||
#include <mango/handle.h>
|
||||
#include <mango/init.h>
|
||||
#include <mango/input.h>
|
||||
#include <mango/libc/stdio.h>
|
||||
@@ -10,6 +12,7 @@
|
||||
#include <mango/printk.h>
|
||||
#include <mango/sched.h>
|
||||
#include <mango/test.h>
|
||||
#include <mango/vm-object.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern unsigned long get_rflags(void);
|
||||
@@ -23,14 +26,16 @@ void print_kernel_banner(void)
|
||||
|
||||
static void hang(void)
|
||||
{
|
||||
struct task *self = current_task();
|
||||
struct thread *thread = current_thread();
|
||||
// struct task *self = current_task();
|
||||
// struct thread *thread = current_thread();
|
||||
|
||||
while (1) {
|
||||
#if 0
|
||||
printk("[cpu %u, task %u, thread %u]: tick",
|
||||
this_cpu(),
|
||||
self->t_id,
|
||||
thread->tr_id);
|
||||
#endif
|
||||
milli_sleep(2000);
|
||||
}
|
||||
}
|
||||
@@ -67,9 +72,40 @@ void kernel_init(uintptr_t arg)
|
||||
{
|
||||
ml_init(arg);
|
||||
|
||||
printk("kernel_init() running on processor %u", this_cpu());
|
||||
struct boot_module bsp_image = {0};
|
||||
bsp_get_location(&bsp_image);
|
||||
|
||||
create_kernel_thread(background_thread);
|
||||
tracek("kernel_init() running on processor %u", this_cpu());
|
||||
|
||||
if (!bsp_image.mod_base) {
|
||||
printk("FATAL: no bsp image specified");
|
||||
hang();
|
||||
}
|
||||
|
||||
tracek("bsp image at [0x%llx-0x%llx]",
|
||||
bsp_image.mod_base,
|
||||
bsp_image.mod_base + bsp_image.mod_size);
|
||||
|
||||
struct bsp bsp;
|
||||
kern_status_t status = bsp_load(&bsp, &bsp_image);
|
||||
if (status != KERN_OK) {
|
||||
printk("FATAL: bsp image is corrupt/invalid");
|
||||
hang();
|
||||
}
|
||||
|
||||
tracek("bsp image loaded. text=[%06llx-%06llx], data=[%06llx-%06llx], "
|
||||
"entry=%06llx, vmo=%p",
|
||||
bsp.bsp_trailer.bsp_text_vaddr,
|
||||
bsp.bsp_trailer.bsp_text_size + bsp.bsp_trailer.bsp_text_vaddr,
|
||||
bsp.bsp_trailer.bsp_data_vaddr,
|
||||
bsp.bsp_trailer.bsp_data_size + bsp.bsp_trailer.bsp_data_vaddr,
|
||||
bsp.bsp_trailer.bsp_exec_entry,
|
||||
bsp.bsp_vmo);
|
||||
|
||||
struct task *bootstrap_task = task_create(kernel_task(), "bootstrap");
|
||||
tracek("created bootstrap task (pid=%u)", bootstrap_task->t_id);
|
||||
|
||||
bsp_launch_async(&bsp, bootstrap_task);
|
||||
|
||||
hang();
|
||||
}
|
||||
|
||||
172
kernel/bsp.c
172
kernel/bsp.c
@@ -5,6 +5,8 @@
|
||||
#include <mango/vm-object.h>
|
||||
#include <mango/vm-region.h>
|
||||
|
||||
#define BOOTSTRAP_STACK_SIZE 0x10000
|
||||
|
||||
static struct boot_module bsp_location = {0};
|
||||
|
||||
void bsp_set_location(const struct boot_module *mod)
|
||||
@@ -16,3 +18,173 @@ void bsp_get_location(struct boot_module *out)
|
||||
{
|
||||
memcpy(out, &bsp_location, sizeof bsp_location);
|
||||
}
|
||||
|
||||
kern_status_t bsp_load(struct bsp *bsp, const struct boot_module *mod)
|
||||
{
|
||||
size_t trailer_offset = mod->mod_size - sizeof(struct bsp_trailer);
|
||||
const char *p = vm_phys_to_virt(mod->mod_base);
|
||||
const struct bsp_trailer *trailer_bigendian
|
||||
= (const struct bsp_trailer *)(p + trailer_offset);
|
||||
|
||||
bsp->bsp_trailer.bsp_magic
|
||||
= big_to_host_u32(trailer_bigendian->bsp_magic);
|
||||
bsp->bsp_trailer.bsp_fs_offset
|
||||
= big_to_host_u64(trailer_bigendian->bsp_fs_offset);
|
||||
bsp->bsp_trailer.bsp_fs_len
|
||||
= big_to_host_u32(trailer_bigendian->bsp_fs_len);
|
||||
bsp->bsp_trailer.bsp_exec_offset
|
||||
= big_to_host_u64(trailer_bigendian->bsp_exec_offset);
|
||||
bsp->bsp_trailer.bsp_exec_len
|
||||
= big_to_host_u32(trailer_bigendian->bsp_exec_len);
|
||||
bsp->bsp_trailer.bsp_text_faddr
|
||||
= big_to_host_u64(trailer_bigendian->bsp_text_faddr);
|
||||
bsp->bsp_trailer.bsp_text_vaddr
|
||||
= big_to_host_u64(trailer_bigendian->bsp_text_vaddr);
|
||||
bsp->bsp_trailer.bsp_text_size
|
||||
= big_to_host_u64(trailer_bigendian->bsp_text_size);
|
||||
bsp->bsp_trailer.bsp_data_faddr
|
||||
= big_to_host_u64(trailer_bigendian->bsp_data_faddr);
|
||||
bsp->bsp_trailer.bsp_data_vaddr
|
||||
= big_to_host_u64(trailer_bigendian->bsp_data_vaddr);
|
||||
bsp->bsp_trailer.bsp_data_size
|
||||
= big_to_host_u64(trailer_bigendian->bsp_data_size);
|
||||
bsp->bsp_trailer.bsp_exec_entry
|
||||
= big_to_host_u64(trailer_bigendian->bsp_exec_entry);
|
||||
|
||||
if (bsp->bsp_trailer.bsp_magic != BSP_MAGIC) {
|
||||
return KERN_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
bsp->bsp_vmo = vm_object_create_in_place(
|
||||
"bsp",
|
||||
mod->mod_base,
|
||||
mod->mod_size,
|
||||
VM_PROT_READ | VM_PROT_EXEC | VM_PROT_USER);
|
||||
if (!bsp->bsp_vmo) {
|
||||
return KERN_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return KERN_OK;
|
||||
}
|
||||
|
||||
static kern_status_t map_executable(
|
||||
struct bsp *bsp,
|
||||
struct task *task,
|
||||
virt_addr_t *entry)
|
||||
{
|
||||
kern_status_t status = KERN_OK;
|
||||
size_t exec_size = 0;
|
||||
if (bsp->bsp_trailer.bsp_text_vaddr > bsp->bsp_trailer.bsp_data_vaddr) {
|
||||
exec_size = bsp->bsp_trailer.bsp_text_vaddr
|
||||
+ bsp->bsp_trailer.bsp_text_size;
|
||||
} else {
|
||||
exec_size = bsp->bsp_trailer.bsp_data_vaddr
|
||||
+ bsp->bsp_trailer.bsp_data_size;
|
||||
}
|
||||
|
||||
struct vm_region *region;
|
||||
status = vm_region_create(
|
||||
task->t_address_space,
|
||||
"exec",
|
||||
VM_REGION_ANY_MAP_ADDRESS,
|
||||
exec_size,
|
||||
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXEC | VM_PROT_USER,
|
||||
®ion);
|
||||
if (status != KERN_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
struct vm_object *data = vm_object_create(
|
||||
".data",
|
||||
bsp->bsp_trailer.bsp_data_size,
|
||||
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER);
|
||||
/* TODO copy .data from executable to memory */
|
||||
if (!data) {
|
||||
return KERN_NO_MEMORY;
|
||||
}
|
||||
|
||||
off_t text_offset = bsp->bsp_trailer.bsp_exec_offset
|
||||
+ bsp->bsp_trailer.bsp_text_faddr;
|
||||
off_t data_offset = 0;
|
||||
virt_addr_t text_base = region->vr_entry.e_base_address
|
||||
+ bsp->bsp_trailer.bsp_text_vaddr;
|
||||
virt_addr_t data_base = region->vr_entry.e_base_address
|
||||
+ bsp->bsp_trailer.bsp_data_vaddr;
|
||||
|
||||
tracek("exec_offset=%llx, text_faddr=%llx",
|
||||
bsp->bsp_trailer.bsp_exec_offset,
|
||||
bsp->bsp_trailer.bsp_text_faddr);
|
||||
tracek("text_offset=%llx, data_offset=%llx", text_offset, data_offset);
|
||||
tracek("text_base=%llx, data_base=%llx", text_base, data_base);
|
||||
|
||||
status = vm_region_map_object(
|
||||
region,
|
||||
text_base,
|
||||
bsp->bsp_vmo,
|
||||
text_offset,
|
||||
bsp->bsp_trailer.bsp_text_size,
|
||||
VM_PROT_READ | VM_PROT_EXEC | VM_PROT_USER,
|
||||
&text_base);
|
||||
if (status != KERN_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = vm_region_map_object(
|
||||
region,
|
||||
data_base,
|
||||
data,
|
||||
data_offset,
|
||||
bsp->bsp_trailer.bsp_data_size,
|
||||
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
|
||||
&data_base);
|
||||
if (status != KERN_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
*entry = text_base + bsp->bsp_trailer.bsp_exec_entry;
|
||||
return KERN_OK;
|
||||
}
|
||||
|
||||
kern_status_t bsp_launch_async(struct bsp *bsp, struct task *task)
|
||||
{
|
||||
virt_addr_t stack_buffer;
|
||||
virt_addr_t entry, sp;
|
||||
kern_status_t status = map_executable(bsp, task, &entry);
|
||||
if (status != KERN_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
struct vm_object *user_stack = vm_object_create(
|
||||
"stack",
|
||||
BOOTSTRAP_STACK_SIZE,
|
||||
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER);
|
||||
if (!user_stack) {
|
||||
return KERN_NO_ENTRY;
|
||||
}
|
||||
|
||||
status = vm_region_map_object(
|
||||
task->t_address_space,
|
||||
VM_REGION_ANY_MAP_ADDRESS,
|
||||
user_stack,
|
||||
0,
|
||||
BOOTSTRAP_STACK_SIZE,
|
||||
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
|
||||
&stack_buffer);
|
||||
|
||||
if (status != KERN_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef TRACE
|
||||
vm_region_dump(task->t_address_space, 0);
|
||||
#endif
|
||||
|
||||
sp = stack_buffer + BOOTSTRAP_STACK_SIZE;
|
||||
tracek("bootstrap: entry=%llx, sp=%llx", entry, sp);
|
||||
|
||||
struct thread *init_thread = task_create_thread(task);
|
||||
thread_init_user(init_thread, entry, sp);
|
||||
schedule_thread_on_cpu(init_thread);
|
||||
|
||||
return KERN_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user