diff --git a/include/mango/bsp.h b/include/mango/bsp.h index 9e3ba7f..7aa219b 100644 --- a/include/mango/bsp.h +++ b/include/mango/bsp.h @@ -7,7 +7,32 @@ #include #include +#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 diff --git a/init/main.c b/init/main.c index 6e0ac32..c0d269f 100644 --- a/init/main.c +++ b/init/main.c @@ -1,6 +1,8 @@ #include +#include #include #include +#include #include #include #include @@ -10,6 +12,7 @@ #include #include #include +#include #include 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(); } diff --git a/kernel/bsp.c b/kernel/bsp.c index 180ff8f..ebffc79 100644 --- a/kernel/bsp.c +++ b/kernel/bsp.c @@ -5,6 +5,8 @@ #include #include +#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; +}