aboutsummaryrefslogtreecommitdiff
path: root/pk/pk.c
blob: cc2a7612997195eec753762f8eff396085775588 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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);
}