1// See LICENSE for license details. 2 3#include "pk.h" 4#include "mmap.h" 5#include "boot.h" 6#include "elf.h" 7#include "mtrap.h" 8#include "frontend.h" 9#include <stdbool.h> 10 11elf_info current; 12long disabled_hart_mask; 13 14static void handle_option(const char* s) 15{ 16 switch (s[1]) 17 { 18 case 's': // print cycle count upon termination 19 current.cycle0 = 1; 20 break; 21 22 case 'p': // disable demand paging 23 demand_paging = 0; 24 break; 25 26 default: 27 panic("unrecognized option: `%c'", s[1]); 28 break; 29 } 30} 31 32#define MAX_ARGS 256 33typedef union { 34 uint64_t buf[MAX_ARGS]; 35 char* argv[MAX_ARGS]; 36} arg_buf; 37 38static size_t parse_args(arg_buf* args) 39{ 40 long r = frontend_syscall(SYS_getmainvars, va2pa(args), sizeof(*args), 0, 0, 0, 0, 0); 41 if (r != 0) 42 panic("args must not exceed %d bytes", (int)sizeof(arg_buf)); 43 44 kassert(r == 0); 45 uint64_t* pk_argv = &args->buf[1]; 46 // pk_argv[0] is the proxy kernel itself. skip it and any flags. 47 size_t pk_argc = args->buf[0], arg = 1; 48 for ( ; arg < pk_argc && *(char*)(uintptr_t)pk_argv[arg] == '-'; arg++) 49 handle_option((const char*)(uintptr_t)pk_argv[arg]); 50 51 for (size_t i = 0; arg + i < pk_argc; i++) 52 args->argv[i] = (char*)(uintptr_t)pk_argv[arg + i]; 53 return pk_argc - arg; 54} 55 56static void init_tf(trapframe_t* tf, long pc, long sp) 57{ 58 memset(tf, 0, sizeof(*tf)); 59 tf->status = (read_csr(sstatus) &~ SSTATUS_SPP &~ SSTATUS_SIE) | SSTATUS_SPIE; 60 tf->gpr[2] = sp; 61 tf->epc = pc; 62} 63 64static void run_loaded_program(size_t argc, char** argv, uintptr_t kstack_top) 65{ 66 // copy phdrs to user stack 67 size_t stack_top = current.stack_top - current.phdr_size; 68 memcpy((void*)stack_top, (void*)current.phdr, current.phdr_size); 69 current.phdr = stack_top; 70 71 // copy argv to user stack 72 for (size_t i = 0; i < argc; i++) { 73 size_t len = strlen((char*)(uintptr_t)argv[i])+1; 74 stack_top -= len; 75 memcpy((void*)stack_top, (void*)(uintptr_t)argv[i], len); 76 argv[i] = (void*)stack_top; 77 } 78 79 // copy envp to user stack 80 const char* envp[] = { 81 // environment goes here 82 }; 83 size_t envc = sizeof(envp) / sizeof(envp[0]); 84 for (size_t i = 0; i < envc; i++) { 85 size_t len = strlen(envp[i]) + 1; 86 stack_top -= len; 87 memcpy((void*)stack_top, envp[i], len); 88 envp[i] = (void*)stack_top; 89 } 90 91 // align stack 92 stack_top &= -sizeof(void*); 93 94 struct { 95 long key; 96 long value; 97 } aux[] = { 98 {AT_ENTRY, current.entry}, 99 {AT_PHNUM, current.phnum}, 100 {AT_PHENT, current.phent}, 101 {AT_PHDR, current.phdr}, 102 {AT_PAGESZ, RISCV_PGSIZE}, 103 {AT_SECURE, 0}, 104 {AT_RANDOM, stack_top}, 105 {AT_NULL, 0} 106 }; 107 108 // place argc, argv, envp, auxp on stack 109 #define PUSH_ARG(type, value) do { \ 110 *((type*)sp) = (type)value; \ 111 sp += sizeof(type); \ 112 } while (0) 113 114 #define STACK_INIT(type) do { \ 115 unsigned naux = sizeof(aux)/sizeof(aux[0]); \ 116 stack_top -= (1 + argc + 1 + envc + 1 + 2*naux) * sizeof(type); \ 117 stack_top &= -16; \ 118 long sp = stack_top; \ 119 PUSH_ARG(type, argc); \ 120 for (unsigned i = 0; i < argc; i++) \ 121 PUSH_ARG(type, argv[i]); \ 122 PUSH_ARG(type, 0); /* argv[argc] = NULL */ \ 123 for (unsigned i = 0; i < envc; i++) \ 124 PUSH_ARG(type, envp[i]); \ 125 PUSH_ARG(type, 0); /* envp[envc] = NULL */ \ 126 for (unsigned i = 0; i < naux; i++) { \ 127 PUSH_ARG(type, aux[i].key); \ 128 PUSH_ARG(type, aux[i].value); \ 129 } \ 130 } while (0) 131 132 STACK_INIT(uintptr_t); 133 134 if (current.cycle0) { // start timer if so requested 135 current.time0 = rdtime(); 136 current.cycle0 = rdcycle(); 137 current.instret0 = rdinstret(); 138 } 139 140 trapframe_t tf; 141 init_tf(&tf, current.entry, stack_top); 142 __clear_cache(0, 0); 143 write_csr(sscratch, kstack_top); 144 start_user(&tf); 145} 146 147static void rest_of_boot_loader(uintptr_t kstack_top) 148{ 149 arg_buf args; 150 size_t argc = parse_args(&args); 151 if (!argc) 152 panic("tell me what ELF to load!"); 153 154 // load program named by argv[0] 155 long phdrs[128]; 156 current.phdr = (uintptr_t)phdrs; 157 current.phdr_size = sizeof(phdrs); 158 load_elf(args.argv[0], ¤t); 159 160 run_loaded_program(argc, args.argv, kstack_top); 161} 162 163void boot_loader(uintptr_t dtb) 164{ 165 extern char trap_entry; 166 write_csr(stvec, &trap_entry); 167 write_csr(sscratch, 0); 168 write_csr(sie, 0); 169 set_csr(sstatus, SSTATUS_SUM | SSTATUS_FS); 170 171 file_init(); 172 enter_supervisor_mode(rest_of_boot_loader, pk_vm_init(), 0); 173} 174 175void boot_other_hart(uintptr_t dtb) 176{ 177 // stall all harts besides hart 0 178 while (1) 179 wfi(); 180} 181