diff options
Diffstat (limited to 'pk/pk.c')
-rw-r--r-- | pk/pk.c | 99 |
1 files changed, 99 insertions, 0 deletions
@@ -0,0 +1,99 @@ +#include "pk.h" +#include "vm.h" +#include "elf.h" + +void run_loaded_program(struct mainvars* args) +{ + if (current.is_supervisor) + panic("pk can't run kernel binaries; try using bbl instead"); + + uintptr_t kernel_stack_top = pk_vm_init(); + + extern char trap_entry; + write_csr(stvec, &trap_entry); + write_csr(sscratch, 0); + + // enter supervisor mode + asm volatile("la t0, 1f; csrw mepc, t0; eret; 1:" ::: "t0"); + + // copy phdrs to user stack + size_t stack_top = current.stack_top - current.phdr_size; + memcpy((void*)stack_top, (void*)current.phdr, current.phdr_size); + current.phdr = stack_top; + + // copy argv to user stack + for (size_t i = 0; i < args->argc; i++) { + size_t len = strlen((char*)(uintptr_t)args->argv[i])+1; + stack_top -= len; + memcpy((void*)stack_top, (void*)(uintptr_t)args->argv[i], len); + args->argv[i] = stack_top; + } + stack_top &= -sizeof(void*); + + struct { + long key; + long value; + } aux[] = { + {AT_ENTRY, current.entry}, + {AT_PHNUM, current.phnum}, + {AT_PHENT, current.phent}, + {AT_PHDR, current.phdr}, + {AT_PAGESZ, RISCV_PGSIZE}, + {AT_SECURE, 0}, + {AT_RANDOM, stack_top}, + {AT_NULL, 0} + }; + + // place argc, argv, envp, auxp on stack + #define PUSH_ARG(type, value) do { \ + *((type*)sp) = value; \ + sp += sizeof(type); \ + } while (0) + + #define STACK_INIT(type) do { \ + unsigned naux = sizeof(aux)/sizeof(aux[0]); \ + stack_top -= (1 + args->argc + 1 + 1 + 2*naux) * sizeof(type); \ + stack_top &= -16; \ + long sp = stack_top; \ + PUSH_ARG(type, args->argc); \ + for (unsigned i = 0; i < args->argc; i++) \ + PUSH_ARG(type, args->argv[i]); \ + PUSH_ARG(type, 0); /* argv[argc] = NULL */ \ + PUSH_ARG(type, 0); /* envp[0] = NULL */ \ + for (unsigned i = 0; i < naux; i++) { \ + PUSH_ARG(type, aux[i].key); \ + PUSH_ARG(type, aux[i].value); \ + } \ + } while (0) + + if (current.elf64) + STACK_INIT(uint64_t); + else + STACK_INIT(uint32_t); + + if (current.t0) // start timer if so requested + current.t0 = rdcycle(); + + if (uarch_counters_enabled) { // start tracking the uarch counters if requested + size_t i = 0; + #define READ_CTR_INIT(name) do { \ + while (i >= NUM_COUNTERS) ; \ + long csr = read_csr(name); \ + uarch_counters[i++] = csr; \ + } while (0) + READ_CTR_INIT(cycle); READ_CTR_INIT(instret); + READ_CTR_INIT(uarch0); READ_CTR_INIT(uarch1); READ_CTR_INIT(uarch2); + READ_CTR_INIT(uarch3); READ_CTR_INIT(uarch4); READ_CTR_INIT(uarch5); + READ_CTR_INIT(uarch6); READ_CTR_INIT(uarch7); READ_CTR_INIT(uarch8); + READ_CTR_INIT(uarch9); READ_CTR_INIT(uarch10); READ_CTR_INIT(uarch11); + READ_CTR_INIT(uarch12); READ_CTR_INIT(uarch13); READ_CTR_INIT(uarch14); + READ_CTR_INIT(uarch15); + #undef READ_CTR_INIT + } + + trapframe_t tf; + init_tf(&tf, current.entry, stack_top, current.elf64); + __clear_cache(0, 0); + write_csr(sscratch, kernel_stack_top); + start_user(&tf); +} |