diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2021-12-26 17:50:11 +0200 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2021-12-26 17:50:11 +0200 |
| commit | d98ec57128628b81fcd32269a92742a037b7f713 (patch) | |
| tree | 0e3f8d78d8347ef0a6e69d41b9d9be20c822b642 | |
| parent | a64f3588ff5da7f148659ccb0eff844ccfb57088 (diff) | |
| download | kmi-d98ec57128628b81fcd32269a92742a037b7f713.tar.gz kmi-d98ec57128628b81fcd32269a92742a037b7f713.zip | |
First useful jump to userspace!
| -rw-r--r-- | TODO.txt | 4 | ||||
| -rwxr-xr-x | arch/riscv/conf/init | bin | 1032 -> 1040 bytes | |||
| -rw-r--r-- | arch/riscv/conf/initrd | bin | 1536 -> 1536 bytes | |||
| -rw-r--r-- | arch/riscv/conf/s.S | 5 | ||||
| -rw-r--r-- | arch/riscv/include/csr.h | 1 | ||||
| -rw-r--r-- | arch/riscv/kernel/main.c | 11 | ||||
| -rw-r--r-- | arch/riscv/kernel/proc.c | 4 | ||||
| -rw-r--r-- | arch/riscv/kernel/vmem.c | 5 | ||||
| -rw-r--r-- | common/elf.c | 85 | ||||
| -rw-r--r-- | common/initrd.c | 8 | ||||
| -rw-r--r-- | common/vmem.c | 9 | ||||
| -rw-r--r-- | include/apos/elf.h | 170 | ||||
| -rw-r--r-- | include/apos/initrd.h | 3 | ||||
| -rw-r--r-- | include/apos/proc.h | 2 | ||||
| -rw-r--r-- | include/apos/utils.h | 2 | ||||
| -rw-r--r-- | include/apos/vmem.h | 8 |
16 files changed, 283 insertions, 34 deletions
@@ -3,9 +3,9 @@ + Add in mapping the same memory to two different processes + Create sensible thread handling + Add in init process loading -+ Make sure vmap is in 4K increments or whatever ++ Make sure vmap is in 4K increments or whatever (fuck it, sure) + Remove/converge convnum and debugging __atoi -+ Create actual init program ++ Create actual init program (meh, sort of) + Add in (attempting) to map into specific region of memory, see phone for details dumbass diff --git a/arch/riscv/conf/init b/arch/riscv/conf/init Binary files differindex 06e61e0..43a179c 100755 --- a/arch/riscv/conf/init +++ b/arch/riscv/conf/init diff --git a/arch/riscv/conf/initrd b/arch/riscv/conf/initrd Binary files differindex 8dc931b..e3704f2 100644 --- a/arch/riscv/conf/initrd +++ b/arch/riscv/conf/initrd diff --git a/arch/riscv/conf/s.S b/arch/riscv/conf/s.S index 7b796ce..e6997ac 100644 --- a/arch/riscv/conf/s.S +++ b/arch/riscv/conf/s.S @@ -1,4 +1,7 @@ .text .global _start _start: -loop: j loop +li a1, 1 +loop: +add a0, a0, a1 +jal loop diff --git a/arch/riscv/include/csr.h b/arch/riscv/include/csr.h index bd02b04..b309f0b 100644 --- a/arch/riscv/include/csr.h +++ b/arch/riscv/include/csr.h @@ -39,6 +39,7 @@ /* status CSR bits */ #define SSTATUS_SUM (1 << 18) +#define SSTATUS_SPP (1 << 8) /* directly lifted from Linux:/arch/riscv/include/asm/asm.h:9-13 */ #ifdef __ASSEMBLY__ diff --git a/arch/riscv/kernel/main.c b/arch/riscv/kernel/main.c index 914dcba..1964514 100644 --- a/arch/riscv/kernel/main.c +++ b/arch/riscv/kernel/main.c @@ -252,17 +252,13 @@ static void init_proc(void *fdt, struct vm_branch_t *b) /* binary itself */ size_t sz = get_init_size(fdt); - /* these need to be fixed and actually map the addresses that the ELF - * binary wants, instead of willy nilly */ - t->bin = alloc_uvmem(t, sz, VM_V | VM_X | VM_R | VM_W | VM_U); - /* stack */ + /* stack (?) */ t->stack = alloc_uvmem(t, SZ_2M, VM_V | VM_R | VM_W | VM_U); /* should probably wrap this in like tlb_flush_all() or something */ __asm__ ("sfence.vma" : : : "memory"); - move_init(fdt, (void *)t->bin); - jump_to_userspace(t, 0, 0); + jump_to_userspace(t, get_init_base(fdt), 0, 0); } #define __va_reg(reg)\ @@ -292,6 +288,9 @@ void __main main(void *fdt) /* allow supervisor code to touch user data */ csr_set(CSR_SSTATUS, SSTATUS_SUM); + /* maybe this is too early but mark that we want to jump to user mode + * eventually*/ + csr_clear(CSR_SSTATUS, SSTATUS_SPP); struct vm_branch_t *b = init_vmem(fdt); init_mem_blocks(); init_irq(fdt); diff --git a/arch/riscv/kernel/proc.c b/arch/riscv/kernel/proc.c index 3a39dd3..6d351bc 100644 --- a/arch/riscv/kernel/proc.c +++ b/arch/riscv/kernel/proc.c @@ -2,9 +2,9 @@ #include <apos/elf.h> #include <csr.h> -void jump_to_userspace(struct tcb *t, char **argv, int argc) +void jump_to_userspace(struct tcb *t, vm_t bin, int argc, char **argv) { - csr_write(CSR_SEPC, bin_entry(t->bin)); + csr_write(CSR_SEPC, prepare_proc(t, bin)); __asm__("mv sp, %0\n" : "=r" (t->stack) :: "memory"); __asm__("sret\n" ::: "memory"); } diff --git a/arch/riscv/kernel/vmem.c b/arch/riscv/kernel/vmem.c index bf49716..e3680b3 100644 --- a/arch/riscv/kernel/vmem.c +++ b/arch/riscv/kernel/vmem.c @@ -19,7 +19,8 @@ static pm_t *__find_vmem(struct vm_branch_t *b, vm_t v, enum mm_order_t *o) { enum mm_order_t top = __mm_max_order; - *o = MM_O0; + if(o) + *o = MM_O0; do { size_t idx = vm_to_index(v, top); pm_t pte = (pm_t)b->leaf[idx]; @@ -59,7 +60,7 @@ int stat_vmem(struct vm_branch_t *branch, vm_t vaddr, pm_t *paddr, pm_t *pte = __find_vmem(branch, vaddr, order); if(pte){ if(paddr) - *paddr = pte_paddr(*pte); + *paddr = (pm_t)pte_addr(*pte); if(flags) *flags = pte_flags(*pte); diff --git a/common/elf.c b/common/elf.c index c6a37e0..c73d56c 100644 --- a/common/elf.c +++ b/common/elf.c @@ -1,12 +1,83 @@ #include <apos/elf.h> #include <apos/vmem.h> +#include <apos/bytes.h> +#include <apos/string.h> -vm_t bin_entry(vm_t bin) +static void __map_exec(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart, size_t phnum, size_t phsize) { - struct elf_header *e = (struct elf_header *)bin; - /* TODO: check that address points to a valid ELF executable */ - /* oh yeah, this only works for DYN objects, fuck */ - /* eh, fuck it, I'll fix this later, today has been a decently - * productive day as is */ - return ((vm_t)e->e_entry) + bin; + /* TODO: take alignment into consideration? */ + vm_t runner = phstart; + for(size_t i = 0; i < phnum; ++i, runner += phsize){ + if(program_header_prop(ei_c, runner, p_type) != PT_LOAD) + continue; + + vm_t va = program_header_prop(ei_c, runner, p_vaddr); + size_t vsz = program_header_prop(ei_c, runner, p_memsz); + + vm_t start = 0; + if(!(start = alloc_fixed_region(&t->sp_r, va, vsz, 0))) + return; /* out of memory or something */ + + uint8_t vflags = VM_V | VM_U; + uint8_t bflags = program_header_prop(ei_c, runner, p_flags); + if(bflags & PF_X) + vflags |= VM_X; + + if(bflags & PF_W) + vflags |= VM_W; + + if(bflags & PF_R) + vflags |= VM_R; + + map_fill_region(t->b_r, start, vsz, VM_V | VM_X | VM_R | VM_W | VM_U); + + vm_t vo = bin + program_header_prop(ei_c, runner, p_offset); + vm_t vfz = program_header_prop(ei_c, runner, p_filesz); + memcpy((void *)va, (void *)vo, vfz); + + /* skip while testing + pm_t paddr = 0; + stat_vmem(t->b_r, va, &paddr, 0, 0); + mod_vmem(t->b_r, va, paddr, vflags); + */ + } +} + +static vm_t __map_dyn(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart, size_t phnum, size_t phsize) +{ + /* TODO */ +} + +static vm_t __prepare_proc(struct tcb *t, uint8_t ei_c, vm_t elf) +{ + short e_type = elf_header_prop(ei_c, elf, e_type); + if(e_type != ET_DYN && e_type != ET_EXEC) + return 0; + + vm_t phstart = ptradd(elf, elf_header_prop(ei_c, elf, e_phoff)); + size_t phnum = elf_header_prop(ei_c, elf, e_phnum); + size_t phsize = elf_header_prop(ei_c, elf, e_phentsize); + + vm_t entry = elf_header_prop(ei_c, elf, e_entry); + if(e_type == ET_EXEC){ + __map_exec(t, elf, ei_c, phstart, phnum, phsize); + return entry; + } else { + vm_t o = __map_dyn(t, elf, ei_c, phstart, phnum, phsize); + return o + entry; + } +} + +/* sets up all memory regions etc, returns the entry address */ +vm_t prepare_proc(struct tcb *t, vm_t p) +{ + struct elf_ident *i = (struct elf_ident *)p; + if(i->ei_magic != cpu_to_be32(EI_MAGIC)) + return 0; + + if(i->ei_class != ELFCLASS32 && i->ei_class != ELFCLASS64) + return 0; + + /* more sanity checks? */ + return __prepare_proc(t, i->ei_class, p); } diff --git a/common/initrd.c b/common/initrd.c index 61aaaff..18db836 100644 --- a/common/initrd.c +++ b/common/initrd.c @@ -86,6 +86,14 @@ size_t get_init_size(void *fdt) return convnum(cp->c_filesize, 8, 16); } +vm_t get_init_base(void *fdt) +{ + char *c = (char *)get_initrdbase(fdt); + struct cpio_header *cp = find_file(c, init_n, init_nlen); + size_t name_len = convnum(cp->c_namesize, 8, 16); + return ((vm_t)cp) + align_up(sizeof(struct cpio_header) + name_len, 4); +} + void move_init(void *fdt, void *target) { char *c = (char *)get_initrdbase(fdt); diff --git a/common/vmem.c b/common/vmem.c index 7b1fa4f..229963c 100644 --- a/common/vmem.c +++ b/common/vmem.c @@ -299,8 +299,11 @@ vm_t alloc_region(struct sp_reg_root *r, vm_t alloc_fixed_region(struct sp_reg_root *r, vm_t start, size_t size, size_t *actual_size) { - *actual_size = align_up(size, BASE_PAGE_SIZE); - size_t pages = __page(*actual_size); + size_t asize = align_up(size, BASE_PAGE_SIZE); + if(actual_size) + *actual_size = asize; + + size_t pages = __page(asize); start = __page(start); struct sp_mem *m = sp_find_used_closest(r, start); @@ -309,7 +312,7 @@ vm_t alloc_fixed_region(struct sp_reg_root *r, /* locate actual region where start is between the region start and end */ while(!((m->start <= start) && (start <= m->end))){ - if(start < m->start) + if(start > m->start) m = m->next; else m = m->prev; diff --git a/include/apos/elf.h b/include/apos/elf.h index 492c414..df07b7f 100644 --- a/include/apos/elf.h +++ b/include/apos/elf.h @@ -5,20 +5,67 @@ #include <apos/types.h> #include <apos/vmem.h> -__packed struct elf_header { - uint64_t ei_magic; +#define EI_MAGIC 0x7f454c46 + +#define ELFCLASSNONE 0x0 +#define ELFCLASS32 0x1 +#define ELFCLASS64 0x2 + +#define ELFDATANONE 0x0 +#define ELFDATA2LSB 0x1 +#define ELFDATA2MSB 0x2 + +#define ELFOSABI_NONE 0x0 +#define ELFOSABI_SYSV 0x0 +#define ELFOSABI_NETBSD 0x2 +#define ELFOSABI_LINUX 0x3 +#define ELFOSABI_HURD 0x4 +#define ELFOSABI_FREEBSD 0x9 +#define ELFOSABI_OPENBSD 0xc + +#define ET_NONE 0x0 +#define ET_REL 0x1 +#define ET_EXEC 0x2 +#define ET_DYN 0x3 +#define ET_CORE 0x4 + +#define EM_RISCV 0xf3 + +__packed struct elf_ident { + uint32_t ei_magic; uint8_t ei_class; uint8_t ei_data; uint8_t ei_version; uint8_t ei_osabi; uint8_t ei_abiversion; - uint8_t e_pad; + uint8_t ei_pad[7]; +}; + +__packed struct elf32_header { + struct elf_ident e_ident; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint32_t e_entry; + uint32_t e_phoff; + uint32_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +}; + +__packed struct elf64_header { + struct elf_ident e_ident; uint16_t e_type; uint16_t e_machine; uint32_t e_version; - void *e_entry; - void *e_phoff; - void *e_shoff; + uint64_t e_entry; + uint64_t e_phoff; + uint64_t e_shoff; uint32_t e_flags; uint16_t e_ehsize; uint16_t e_phentsize; @@ -28,6 +75,115 @@ __packed struct elf_header { uint16_t e_shstrndx; }; -vm_t bin_entry(vm_t bin); +#define PT_NULL 0x0 +#define PT_LOAD 0x1 +#define PT_DYNAMIC 0x2 +#define PT_INTERP 0x3 +#define PT_NOTE 0x4 +#define PT_SHLIB 0x5 +#define PT_PHDR 0x6 +#define PT_TLS 0x7 +#define PT_LOOS 0x60000000 +#define PT_HIOS 0x6fffffff +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +#define PF_X (1 << 0) +#define PF_W (1 << 1) +#define PF_R (1 << 2) + +__packed struct program32_header { + uint32_t p_type; + uint32_t p_offset; + uint32_t p_vaddr; + uint32_t p_paddr; + uint32_t p_filesz; + uint32_t p_memsz; + uint32_t p_flags; + uint32_t p_align; +}; + +__packed struct program64_header { + uint32_t p_type; + uint32_t p_flags; + uint64_t p_offset; + uint64_t p_vaddr; + uint64_t p_paddr; + uint64_t p_filesz; + uint64_t p_memsz; + uint64_t p_align; +}; + +#define SHT_NULL 0x0 +#define SH_PROGBITS 0x1 +#define SHT_SYMTAB 0x2 +#define SHT_STRTAB 0x3 +#define SHT_RELA 0x4 +#define SHT_HASH 0x5 +#define SHT_DYNAMIC 0x6 +#define SHT_NOTE 0x7 +#define SHT_NOBITS 0x8 +#define SHT_REL 0x9 +#define SHT_SHLIB 0x0a +#define SHT_DYNSYM 0x0b +#define SHT_INIT_ARRAY 0x0e +#define SHT_FINI_ARRAY 0x0f +#define SHT_PREINIT_ARRAY 0x10 +#define SHT_GROUP 0x11 +#define SHT_SYMTAB_SHNDX 0x12 +#define SHT_NUM 0x13 + +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MERGE 0x10 +#define SHF_STRINGS 0x20 +#define SHF_INFO_LINK 0x40 +#define SHF_LINK_ODER 0x80 +#define SHF_OS_NONCONFORMING 0x100 +#define SHF_GROUP 0x200 +#define SHF_TLS 0x400 +#define SHF_MASKOS 0x0ff00000 +#define SHF_MASKPROC 0xf0000000 + +__packed struct section32_header { + uint32_t sh_name; + uint32_t sh_type; + uint32_t sh_flags; + uint32_t sh_addr; + uint32_t sh_offset; + uint32_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint32_t sh_addralign; + uint32_t sh_entsize; +}; + +__packed struct section64_header { + uint32_t sh_name; + uint32_t sh_type; + uint64_t sh_flags; + uint64_t sh_addr; + uint64_t sh_offset; + uint64_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint64_t sh_addralign; + uint64_t s_entsize; +}; + +#define elf_indent(e) ((struct elf_ident *)e) +#define elf64_header(e) ((struct elf64_header *)e) +#define elf32_header(e) ((struct elf32_header *)e) +#define program64_header(p) ((struct program64_header *)p) +#define program32_header(p) ((struct program32_header *)p) +#define section64_header(s) ((struct section64_header *)s) +#define section32_header(s) ((struct section32_header *)s) + +#define elf_header_prop(c, e, p) (c == ELFCLASS64 ? elf64_header(e)->p : elf32_header(e)->p) +#define program_header_prop(c, e, p) (c == ELFCLASS64 ? program64_header(e)->p : program32_header(e)->p) +#define section_header_prop(c, e, p) (c == ELFCLASS64 ? section64_header(e)->p : section32_header(e)->p) + +vm_t prepare_proc(struct tcb *t, vm_t p); #endif /* APOS_ELF_H */ diff --git a/include/apos/initrd.h b/include/apos/initrd.h index 1e1129c..4b28ba8 100644 --- a/include/apos/initrd.h +++ b/include/apos/initrd.h @@ -3,9 +3,10 @@ #include <apos/types.h> #include <apos/pmem.h> +#include <apos/vmem.h> size_t get_init_size(void *fdt); -void move_init(void *fdt, void *target); +vm_t get_init_base(void *fdt); pm_t get_initrdtop(void *fdt); pm_t get_initrdbase(void *fdt); diff --git a/include/apos/proc.h b/include/apos/proc.h index 7506b10..8071dda 100644 --- a/include/apos/proc.h +++ b/include/apos/proc.h @@ -2,6 +2,6 @@ #define APOS_PROC_H #include <apos/tcb.h> -void jump_to_userspace(struct tcb *t, char **argv, int argc); +void jump_to_userspace(struct tcb *t, vm_t bin, int argc, char **argv); #endif /* APOS_PROC_H */ diff --git a/include/apos/utils.h b/include/apos/utils.h index f1e79fa..eff473f 100644 --- a/include/apos/utils.h +++ b/include/apos/utils.h @@ -33,6 +33,8 @@ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define ALIGNED(x, a) ((x) % a == 0) +#define ptradd(x, y) (((vm_t)(x)) + ((vm_t)(y))) + #include <apos/types.h> static inline size_t align_up(size_t val, size_t a) diff --git a/include/apos/vmem.h b/include/apos/vmem.h index 4cc4895..b7522d2 100644 --- a/include/apos/vmem.h +++ b/include/apos/vmem.h @@ -30,7 +30,7 @@ struct sp_mem { #define __pa(x) (((char *)(x)) + RAM_BASE - VM_DMAP) #define __page(x) ((x) / BASE_PAGE_SIZE) #define __addr(x) ((x) * BASE_PAGE_SIZE) -#define __pages(x) (__page(x)) +#define __pages(x) (aligned((x), BASE_PAGE_SIZE) ? __page((x)) : __page((x) + BASE_PAGE_SIZE)) #define __bytes(x) (__addr(x)) /* general overview of the different functions: @@ -49,7 +49,11 @@ int stat_vmem(struct vm_branch_t *branch, vm_t vaddr, pm_t *paddr, int sp_mem_init(struct sp_reg_root *r, vm_t start, size_t nums); -vm_t alloc_uvmem(struct tcb *r, size_t s, uint8_t flags); +vm_t alloc_region(struct sp_reg_root *r, size_t size, size_t *actual_size); +vm_t alloc_fixed_region(struct sp_reg_root *r, vm_t start, size_t size, size_t *actual_size); +void free_region(struct sp_reg_root *r, vm_t start); + +vm_t alloc_uvmem(struct tcb *r, size_t size, uint8_t flags); void free_uvmem(struct tcb *r, vm_t a); vm_t map_fill_region(struct vm_branch_t *b, vm_t start, size_t bytes, uint8_t flags); |
