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 | |
parent | 435231378798819304eef427bad8e77dffea85df (diff) | |
parent | b96c27bba0b242fc860fc9a2fcb63f121312fa7e (diff) |
Merged ELF loading
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/Makefile | 4 | ||||
-rw-r--r-- | kernel/drivers/fb.c | 12 | ||||
-rw-r--r-- | kernel/drivers/interrupts.c | 1 | ||||
-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 | ||||
-rw-r--r-- | kernel/inc/fb.h | 2 | ||||
-rw-r--r-- | kernel/inc/load.h | 100 | ||||
-rw-r--r-- | kernel/inc/mm.h | 9 | ||||
-rw-r--r-- | kernel/link.ld | 2 | ||||
-rw-r--r-- | kernel/main.c | 6 |
13 files changed, 267 insertions, 62 deletions
diff --git a/kernel/Makefile b/kernel/Makefile index e9ade73..64035e5 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -36,5 +36,5 @@ all: compile compile: $(COBJS) @mkdir -p ../build/ - @$(LD) -N -z undefs -ekernel_main -Ttext 0x00050000 -o ../build/kernel.elf -L../build/ $+ -lk - @$(LD) -N -Tlink.ld -o ../build/kernel.bin -L../build/ $+ -lk + @$(LD) -N -z undefs -ekernel_main -Ttext 0x00009000 -o ../build/kernel.elf -L../build/ $+ -lk + @$(LD) -N -z max-page-size=0x1000 -Tlink.ld -o ../build/kernel.bin -L../build/ $+ -lk diff --git a/kernel/drivers/fb.c b/kernel/drivers/fb.c index af8a830..2db05f2 100644 --- a/kernel/drivers/fb.c +++ b/kernel/drivers/fb.c @@ -33,11 +33,8 @@ static s32 fb_ioctl(u32 request, void *arg1, void *arg2, void *arg3, struct devi case IO_FB_GET: { if (!info) return -1; - struct vbe_basic *vbe = (struct vbe_basic *)info->vbe; memcpy(arg1, info->vbe, sizeof(struct vbe_basic)); - u32 size = vbe->height * vbe->pitch; - memory_map_identity(proc_current()->page_dir, - memory_range_around((u32)vbe->fb, size), MEMORY_USER); + fb_map_buffer(proc_current()->page_dir, info); return 0; } default: @@ -50,6 +47,13 @@ static s32 fb_ready(void) return 1; } +void fb_map_buffer(struct page_dir *dir, struct vid_info *boot) +{ + struct vbe_basic *vbe = (struct vbe_basic *)boot->vbe; + u32 size = vbe->height * vbe->pitch; + memory_map_identity(dir, memory_range_around((u32)vbe->fb, size), MEMORY_USER); +} + void fb_install(struct vid_info *boot) { info = boot; diff --git a/kernel/drivers/interrupts.c b/kernel/drivers/interrupts.c index 2e1444f..255f976 100644 --- a/kernel/drivers/interrupts.c +++ b/kernel/drivers/interrupts.c @@ -179,6 +179,7 @@ void isr_panic(struct regs *r) printf("\t-> Exception occurred in %s at addr 0x%x\n", proc->name, r->eip - proc->entry); proc_exit(proc, 1); + proc_yield(r); } else { __asm__ volatile("cli\nhlt"); } 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 diff --git a/kernel/inc/fb.h b/kernel/inc/fb.h index 212230b..3b545fd 100644 --- a/kernel/inc/fb.h +++ b/kernel/inc/fb.h @@ -4,7 +4,9 @@ #define FB_H #include <boot.h> +#include <mm.h> +void fb_map_buffer(struct page_dir *dir, struct vid_info *boot); void fb_install(struct vid_info *boot); #endif diff --git a/kernel/inc/load.h b/kernel/inc/load.h index bd3b10d..28bdc54 100644 --- a/kernel/inc/load.h +++ b/kernel/inc/load.h @@ -6,6 +6,106 @@ #include <def.h> #include <proc.h> +/** + * ELF + */ + +#define ELF_MAG0 0x7F +#define ELF_MAG1 'E' +#define ELF_MAG2 'L' +#define ELF_MAG3 'F' + +#define ELF_IDENT_COUNT 16 +#define ELF_IDENT_MAG0 0 +#define ELF_IDENT_MAG1 1 +#define ELF_IDENT_MAG2 2 +#define ELF_IDENT_MAG3 3 + +#define ELF_IDENT_CLASS 4 +#define ELF_IDENT_CLASS_NONE 0 +#define ELF_IDENT_CLASS_32 1 +#define ELF_IDENT_CLASS_64 2 + +#define ELF_IDENT_DATA 5 +#define ELF_IDENT_DATA_NONE 0 +#define ELF_IDENT_DATA_LSB 1 +#define ELF_IDENT_DATA_MSB 2 + +#define ELF_IDENT_VERSION 6 +#define ELF_IDENT_OSABI 7 +#define ELF_IDENT_ABIVERSION 8 +#define ELF_IDENT_PAD 9 + +#define ELF_ETYPE_NONE 0 +#define ELF_ETYPE_REL 1 +#define ELF_ETYPE_EXEC 2 +#define ELF_ETYPE_DYN 3 +#define ELF_ETYPE_CORE 4 + +#define ELF_MACHINE_NONE 0 +#define ELF_MACHINE_SPARC 2 +#define ELF_MACHINE_386 3 +#define ELF_MACHINE_SPARC32PLUS 18 +#define ELF_MACHINE_SPARCV9 43 +#define ELF_MACHINE_AMD64 62 + +#define ELF_FLAG_SPARC_EXT_MASK 0xffff00 +#define ELF_FLAG_SPARC_32PLUS 0x000100 +#define ELF_FLAG_SPARC_SUN_US1 0x000200 +#define ELF_FLAG_SPARC_HAL_R1 0x000400 +#define ELF_FLAG_SPARC_SUN_US3 0x000800 +#define ELF_FLAG_SPARCV9_MM 0x3 +#define ELF_FLAG_SPARCV9_TSO 0x0 +#define ELF_FLAG_SPARCV9_PSO 0x1 +#define ELF_FLAG_SPARCV9_RMO 0x2 + +#define ELF_PROGRAM_X 0x1 +#define ELF_PROGRAM_W 0x2 +#define ELF_PROGRAM_R 0x4 + +#define ELF_SECTION_TYPE_NULL 0 +#define ELF_SECTION_TYPE_PROGBITS 1 +#define ELF_SECTION_TYPE_SYMTAB 2 +#define ELF_SECTION_TYPE_STRTAB 3 +#define ELF_SECTION_TYPE_RELA 4 +#define ELF_SECTION_TYPE_HASH 5 +#define ELF_SECTION_TYPE_DYNAMIC 6 +#define ELF_SECTION_TYPE_NOTE 7 +#define ELF_SECTION_TYPE_NOBITS 8 +#define ELF_SECTION_TYPE_REL 9 +#define ELF_SECTION_TYPE_SHLIB 10 +#define ELF_SECTION_TYPE_DYNSYM 11 +#define ELF_SECTION_TYPE_COUNT 12 + +struct PACKED elf_header { + u8 ident[ELF_IDENT_COUNT]; + u16 type; + u16 machine; + u32 version; + u32 entry; + u32 phoff; + u32 shoff; + u32 flags; + u16 ehsize; + u16 phentsize; + u16 phnum; + u16 shentsize; + u16 shnum; + u16 shstrndx; +}; + +struct elf_program { + u32 type; + u32 offset; + u32 vaddr; + u32 paddr; + u32 filesz; + u32 memsz; + u32 flags; + u32 align; +}; + s32 bin_load(const char *path, struct proc *proc); +s32 elf_load(const char *path, struct proc *proc); #endif diff --git a/kernel/inc/mm.h b/kernel/inc/mm.h index 98dcf46..5a307b2 100644 --- a/kernel/inc/mm.h +++ b/kernel/inc/mm.h @@ -13,6 +13,13 @@ struct memory_range { }; /** + * Lowlevel paging + */ + +void paging_enable(void); +void page_fault_handler(struct regs *r); + +/** * Physical */ @@ -109,6 +116,4 @@ u8 memory_valid(const void *addr); void memory_install(struct mem_info *mem_info, struct vid_info *vid_info); -void page_fault_handler(struct regs *r); - #endif diff --git a/kernel/link.ld b/kernel/link.ld index 5a63e33..fbe8a8c 100644 --- a/kernel/link.ld +++ b/kernel/link.ld @@ -1,7 +1,7 @@ OUTPUT_FORMAT("binary") OUTPUT_ARCH(i386) ENTRY(kernel_main) -phys = 0x00050000; +phys = 0x00009000; SECTIONS { diff --git a/kernel/main.c b/kernel/main.c index 3b75c7d..3ff0463 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -21,16 +21,14 @@ void kernel_main(struct mem_info *mem_info, struct vid_info *vid_info); // Decl void kernel_main(struct mem_info *mem_info, struct vid_info *vid_info) { - // Clear stack - for (u32 i = 0; i < STACK_SIZE; i++) - ((u8 *)STACK_START)[-i] = 0; - // Serial connection serial_install(); serial_print("\nKernel was compiled at " __TIME__ " on " __DATE__ "\n"); serial_print("Serial connected.\n"); memory_install(mem_info, vid_info); + memory_switch_dir(virtual_kernel_dir()); + paging_enable(); cpu_enable_features(); cpu_print(); |