diff options
author | Marvin Borner | 2021-03-20 19:55:51 +0100 |
---|---|---|
committer | GitHub | 2021-03-20 19:55:51 +0100 |
commit | 5132bac014d63331acf61bb60b9254023f76b869 (patch) | |
tree | 8e2946b7a6630da13ee403c787f77270aeb6185d /kernel/features | |
parent | 435231378798819304eef427bad8e77dffea85df (diff) | |
parent | b96c27bba0b242fc860fc9a2fcb63f121312fa7e (diff) |
Merged ELF loading
Diffstat (limited to 'kernel/features')
-rw-r--r-- | kernel/features/fs.c | 47 | ||||
-rw-r--r-- | kernel/features/load.c | 77 | ||||
-rw-r--r-- | kernel/features/mm.c | 37 | ||||
-rw-r--r-- | kernel/features/proc.c | 19 | ||||
-rw-r--r-- | kernel/features/syscall.c | 13 |
5 files changed, 144 insertions, 49 deletions
diff --git a/kernel/features/fs.c b/kernel/features/fs.c index 56d253a..920add1 100644 --- a/kernel/features/fs.c +++ b/kernel/features/fs.c @@ -136,9 +136,6 @@ s32 vfs_read(const char *path, void *buf, u32 offset, u32 count) if (!buf || !memory_valid(buf)) return -EFAULT; - if (offset > count) - return -EINVAL; - struct mount_info *m = vfs_find_mount_info(path); if (!m || !m->dev || !m->dev->vfs) return -ENOENT; @@ -168,9 +165,6 @@ s32 vfs_write(const char *path, void *buf, u32 offset, u32 count) if (!buf || !memory_valid(buf)) return -EFAULT; - if (offset > count) - return -EINVAL; - struct mount_info *m = vfs_find_mount_info(path); if (!m || !m->dev || !m->dev->vfs) return -ENOENT; @@ -485,25 +479,31 @@ static u32 read_indirect(u32 indirect, u32 block_num, struct device *dev) static s32 read_inode(struct ext2_inode *in, void *buf, u32 offset, u32 count, struct device *dev) { - // TODO: Support read offset - UNUSED(offset); - if (!in || !buf) return -EINVAL; - u32 num_blocks = in->blocks / (BLOCK_SIZE / SECTOR_SIZE); + if (in->size == 0) + return 0; + + u32 num_blocks = in->blocks / (BLOCK_SIZE / SECTOR_SIZE) + 1; if (!num_blocks) return -EINVAL; - // TODO: memcpy block chunks until count is copied - while (BLOCK_SIZE * num_blocks > count) - num_blocks--; + u32 first_block = offset / BLOCK_SIZE; + u32 last_block = (offset + count) / BLOCK_SIZE; + if (last_block >= num_blocks) + last_block = num_blocks - 1; + u32 first_block_offset = offset % BLOCK_SIZE; + + u32 remaining = MIN(count, in->size - offset); + u32 copied = 0; u32 indirect = 0; u32 blocknum = 0; + // TODO: Support triply indirect pointers - for (u32 i = 0; i < num_blocks; i++) { + for (u32 i = first_block; i <= last_block; i++) { if (i < 12) { blocknum = in->block[i]; } else if (i < BLOCK_COUNT + 12) { @@ -518,9 +518,16 @@ static s32 read_inode(struct ext2_inode *in, void *buf, u32 offset, u32 count, s } char *data = buffer_read(blocknum, dev); - memcpy((u32 *)((u32)buf + i * BLOCK_SIZE), data, BLOCK_SIZE); + u32 block_offset = (i == first_block) ? first_block_offset : 0; + u32 byte_count = MIN(BLOCK_SIZE - block_offset, remaining); + + memcpy((u8 *)buf + copied, data + block_offset, byte_count); + + copied += byte_count; + remaining -= byte_count; + free(data); - /* printf("Loaded %d of %d\n", i + 1, num_blocks); */ + /* printf("Loaded %d of %d\n", i + 1, last_block); */ } if (indirect_cache) { @@ -534,7 +541,7 @@ static s32 read_inode(struct ext2_inode *in, void *buf, u32 offset, u32 count, s indirect_cache = NULL; } - return count; + return copied; } static u32 find_inode(const char *name, u32 dir_inode, struct device *dev) @@ -627,11 +634,11 @@ s32 ext2_stat(const char *path, struct stat *buf, struct device *dev) if (find_inode_by_path(path, &in, dev) != &in) return -ENOENT; - u32 num_blocks = in.blocks / (BLOCK_SIZE / SECTOR_SIZE); - u32 sz = BLOCK_SIZE * num_blocks; + //u32 num_blocks = in.blocks / (BLOCK_SIZE / SECTOR_SIZE); + //u32 sz = BLOCK_SIZE * num_blocks; buf->dev_id = dev->id; - buf->size = sz; // Actually in->size but ext2.. + buf->size = in.size; return 0; } diff --git a/kernel/features/load.c b/kernel/features/load.c index 65d76d4..3430a75 100644 --- a/kernel/features/load.c +++ b/kernel/features/load.c @@ -13,6 +13,10 @@ s32 bin_load(const char *path, struct proc *proc) { + UNUSED(path); + UNUSED(proc); + panic("Deprecated!\n"); +#if 0 if (!path || !memory_valid(path) || !proc) return -EFAULT; @@ -48,4 +52,77 @@ s32 bin_load(const char *path, struct proc *proc) memory_switch_dir(prev); return 0; +#endif +} + +s32 elf_load(const char *path, struct proc *proc) +{ + if (!path || !memory_valid(path) || !proc) + return -EFAULT; + + struct stat s = { 0 }; + s32 stat = vfs_stat(path, &s); + if (stat != 0) + return stat; + + struct elf_header header = { 0 }; + s32 read = vfs_read(path, &header, 0, sizeof(header)); + if (read < 0) + return read; + if (read != sizeof(header)) + return -ENOEXEC; + + strcpy(proc->name, path); + + // Valid? + u8 *magic = header.ident; + u8 valid_magic = magic[ELF_IDENT_MAG0] == ELF_MAG0 && magic[ELF_IDENT_MAG1] == ELF_MAG1 && + magic[ELF_IDENT_MAG2] == ELF_MAG2 && magic[ELF_IDENT_MAG3] == ELF_MAG3 && + magic[ELF_IDENT_CLASS] == ELF_IDENT_CLASS_32 && + magic[ELF_IDENT_DATA] == ELF_IDENT_DATA_LSB; + if (!valid_magic || (header.type != ELF_ETYPE_REL && header.type != ELF_ETYPE_EXEC) || + header.version != 1 || header.machine != ELF_MACHINE_386) + return -ENOEXEC; + + for (u32 i = 0; i < header.phnum; i++) { + struct elf_program program = { 0 }; + if (vfs_read(path, &program, header.phoff + header.phentsize * i, + sizeof(program)) != sizeof(program)) + return -ENOEXEC; + + if (program.vaddr == 0) + continue; + + if (program.vaddr <= 0x100000) + return -ENOEXEC; + + struct page_dir *prev; + memory_backup_dir(&prev); + memory_switch_dir(proc->page_dir); + + struct memory_range vrange = memory_range_around(program.vaddr, program.memsz); + struct memory_range prange = physical_alloc(vrange.size); + virtual_map(proc->page_dir, prange, vrange.base, MEMORY_CLEAR | MEMORY_USER); + + if ((u32)vfs_read(proc->name, (void *)program.vaddr, program.offset, + program.filesz) != program.filesz) { + memory_switch_dir(prev); + return -ENOEXEC; + } + + memory_switch_dir(prev); + } + + struct page_dir *prev; + memory_backup_dir(&prev); + memory_switch_dir(proc->page_dir); + + u32 stack = (u32)memory_alloc(proc->page_dir, PROC_STACK_SIZE, MEMORY_USER | MEMORY_CLEAR); + proc->regs.ebp = stack + PROC_STACK_SIZE; + proc->regs.useresp = stack + PROC_STACK_SIZE; + proc->regs.eip = header.entry; + proc->entry = header.entry; + + memory_switch_dir(prev); + return 0; } diff --git a/kernel/features/mm.c b/kernel/features/mm.c index d007039..b804076 100644 --- a/kernel/features/mm.c +++ b/kernel/features/mm.c @@ -4,6 +4,7 @@ #include <assert.h> #include <cpu.h> #include <def.h> +#include <fb.h> #include <mem.h> #include <mm.h> #include <print.h> @@ -15,25 +16,27 @@ static struct page_table kernel_tables[PAGE_KERNEL_COUNT] ALIGNED(PAGE_SIZE) = { * Lowlevel paging */ -/*static void paging_disable(void) +static void paging_switch_dir(u32 dir) +{ + cr3_set(dir); +} + +extern void paging_invalidate_tlb(void); + +/*void paging_disable(void) { cr0_set(cr0_get() | 0x7fffffff); }*/ -static void paging_enable(void) +void paging_enable(void) { cr0_set(cr0_get() | 0x80000000); } -static void paging_switch_dir(u32 dir) -{ - cr3_set(dir); -} - -extern void paging_invalidate_tlb(void); - void page_fault_handler(struct regs *r) { + print("--- PAGE FAULT! ---\n"); + // Check error code const char *type = (r->err_code & 1) ? "present" : "non-present"; const char *operation = (r->err_code & 2) ? "write" : "read"; @@ -46,8 +49,8 @@ void page_fault_handler(struct regs *r) struct page_dir *dir = NULL; if (proc && proc->page_dir) { dir = proc->page_dir; - printf("Stack is at %x, entry at %x\n", virtual_to_physical(dir, proc->regs.ebp), - virtual_to_physical(dir, proc->entry)); + /* printf("Stack is at %x, entry at %x\n", virtual_to_physical(dir, proc->regs.ebp), */ + /* virtual_to_physical(dir, proc->entry)); */ } else { dir = &kernel_dir; } @@ -163,7 +166,7 @@ void physical_free(struct memory_range range) * Virtual */ -#define PDI(vaddr) (((vaddr) >> 22) & 0x03ff) +#define PDI(vaddr) ((vaddr) >> 22) #define PTI(vaddr) (((vaddr) >> 12) & 0x03ff) u8 virtual_present(struct page_dir *dir, u32 vaddr) @@ -413,19 +416,20 @@ void memory_backup_dir(struct page_dir **backup) static u8 memory_bypass_validity = 0; void memory_bypass_enable(void) { - memory_bypass_validity = 1; + /* memory_bypass_validity = 1; */ } void memory_bypass_disable(void) { - memory_bypass_validity = 0; + /* memory_bypass_validity = 0; */ } // TODO: Limit by proc stack and data range u8 memory_valid(const void *addr) { + /* return ((u32)addr) / PAGE_SIZE / PAGE_COUNT >= PAGE_KERNEL_COUNT; */ if (proc_current() && !memory_bypass_validity) - return ((u32)addr) / PAGE_SIZE / PAGE_COUNT >= PAGE_KERNEL_COUNT; + return (u32)addr >= 0x100000; else return 1; } @@ -503,9 +507,10 @@ void memory_install(struct mem_info *mem_info, struct vid_info *vid_info) memory_map_identity(&kernel_dir, memory_range_around(STACK_START - STACK_SIZE, STACK_SIZE), MEMORY_NONE); - // Map VBE data + // Map framebuffer memory_map_identity(&kernel_dir, memory_range_around((u32)vid_info->vbe, 0x1000), MEMORY_NONE); + fb_map_buffer(virtual_kernel_dir(), vid_info); // Unmap NULL byte/page struct memory_range zero = memory_range(0, PAGE_SIZE); diff --git a/kernel/features/proc.c b/kernel/features/proc.c index cd0fc8d..5d3c8aa 100644 --- a/kernel/features/proc.c +++ b/kernel/features/proc.c @@ -59,7 +59,7 @@ void scheduler(struct regs *regs) } memory_switch_dir(((struct proc *)current->data)->page_dir); - memcpy(regs, &((struct proc *)current->data)->regs, sizeof(struct regs)); + memcpy(regs, &((struct proc *)current->data)->regs, sizeof(*regs)); if (regs->cs != GDT_USER_CODE_OFFSET) { regs->gs = GDT_USER_DATA_OFFSET; @@ -81,11 +81,13 @@ void proc_print(void) { struct node *node = proc_list->head; - printf("\nPROCESSES\n"); + printf("--- PROCESSES ---\n"); struct proc *proc = NULL; while (node && (proc = node->data)) { - printf("Process %d: %s [%s]\n", proc->pid, proc->name, - proc->state == PROC_RUNNING ? "RUNNING" : "SLEEPING"); + printf("Process %d: %s [%s] [entry: %x; stack: %x]\n", proc->pid, proc->name, + proc->state == PROC_RUNNING ? "RUNNING" : "SLEEPING", + virtual_to_physical(proc->page_dir, proc->entry), + virtual_to_physical(proc->page_dir, proc->regs.ebp)); node = node->next; } printf("\n"); @@ -145,9 +147,10 @@ void proc_exit(struct proc *proc, int status) printf("Process %s exited with status %d (%s)\n", proc->name, status, status == 0 ? "success" : "error"); + virtual_destroy_dir(proc->page_dir); proc_clear_quantum(); // TODO: Add quantum to each process struct? - sti(); - hlt(); + + // The caller has to yield itself } void proc_yield(struct regs *r) @@ -497,13 +500,13 @@ void proc_init(void) // Idle proc struct proc *kernel_proc = proc_make(PROC_PRIV_NONE); - assert(bin_load("/bin/idle", kernel_proc) == 0); + assert(elf_load("/bin/idle", kernel_proc) == 0); kernel_proc->state = PROC_SLEEPING; idle_proc = list_add(proc_list, kernel_proc); // Init proc (root) struct node *new = list_add(proc_list, proc_make(PROC_PRIV_ROOT)); - assert(bin_load("/bin/init", new->data) == 0); + assert(elf_load("/bin/init", new->data) == 0); current = new; proc_stack_push(new->data, 0); diff --git a/kernel/features/syscall.c b/kernel/features/syscall.c index b0b37ac..7d68d93 100644 --- a/kernel/features/syscall.c +++ b/kernel/features/syscall.c @@ -72,16 +72,19 @@ static void syscall_handler(struct regs *r) case SYS_EXEC: { char *path = (char *)r->ebx; struct proc *proc = proc_make(PROC_PRIV_NONE); - r->eax = (u32)bin_load(path, proc); - if (r->eax != 0) + r->eax = (u32)elf_load(path, proc); + if (r->eax != 0) { proc_exit(proc, -r->eax); - // TODO: Reimplement argc,argv - proc_stack_push(proc, 0); - proc_yield(r); + } else { + // TODO: Reimplement argc,argv + proc_stack_push(proc, 0); + proc_yield(r); + } break; } case SYS_EXIT: { proc_exit(proc_current(), (int)r->ebx); + proc_yield(r); break; } case SYS_BOOT: { // TODO: Move |