aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2021-12-26 17:50:11 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2021-12-26 17:50:11 +0200
commitd98ec57128628b81fcd32269a92742a037b7f713 (patch)
tree0e3f8d78d8347ef0a6e69d41b9d9be20c822b642
parenta64f3588ff5da7f148659ccb0eff844ccfb57088 (diff)
downloadkmi-d98ec57128628b81fcd32269a92742a037b7f713.tar.gz
kmi-d98ec57128628b81fcd32269a92742a037b7f713.zip
First useful jump to userspace!
-rw-r--r--TODO.txt4
-rwxr-xr-xarch/riscv/conf/initbin1032 -> 1040 bytes
-rw-r--r--arch/riscv/conf/initrdbin1536 -> 1536 bytes
-rw-r--r--arch/riscv/conf/s.S5
-rw-r--r--arch/riscv/include/csr.h1
-rw-r--r--arch/riscv/kernel/main.c11
-rw-r--r--arch/riscv/kernel/proc.c4
-rw-r--r--arch/riscv/kernel/vmem.c5
-rw-r--r--common/elf.c85
-rw-r--r--common/initrd.c8
-rw-r--r--common/vmem.c9
-rw-r--r--include/apos/elf.h170
-rw-r--r--include/apos/initrd.h3
-rw-r--r--include/apos/proc.h2
-rw-r--r--include/apos/utils.h2
-rw-r--r--include/apos/vmem.h8
16 files changed, 283 insertions, 34 deletions
diff --git a/TODO.txt b/TODO.txt
index 464539f..dd2898a 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -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
index 06e61e0..43a179c 100755
--- a/arch/riscv/conf/init
+++ b/arch/riscv/conf/init
Binary files differ
diff --git a/arch/riscv/conf/initrd b/arch/riscv/conf/initrd
index 8dc931b..e3704f2 100644
--- a/arch/riscv/conf/initrd
+++ b/arch/riscv/conf/initrd
Binary files differ
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);