Browse Source

Refactor pk, bbl, machine into separate libraries

Yuck.
pull/17/head
Andrew Waterman 11 years ago
parent
commit
b94c7a4b07
  1. 7
      Makefile.in
  2. 8
      bbl/bbl.ac
  3. 76
      bbl/bbl.c
  4. 23
      bbl/bbl.h
  5. 100
      bbl/bbl.lds
  6. 22
      bbl/bbl.mk.in
  7. 54
      bbl/kernel_elf.c
  8. 4
      bbl/logo.c
  9. 7
      bbl/payload.S
  10. 12
      config.h.in
  11. 223
      configure
  12. 2
      configure.ac
  13. 0
      dummy_payload/dummy_payload.ac
  14. 21
      dummy_payload/dummy_payload.c
  15. 3
      dummy_payload/dummy_payload.lds
  16. 13
      dummy_payload/dummy_payload.mk.in
  17. 1
      dummy_payload/dummy_sbi.S
  18. 2
      machine/atomic.h
  19. 33
      machine/bits.h
  20. 0
      machine/configstring.c
  21. 0
      machine/emulation.c
  22. 0
      machine/emulation.h
  23. 0
      machine/encoding.h
  24. 0
      machine/fp_asm.S
  25. 0
      machine/fp_emulation.c
  26. 0
      machine/fp_emulation.h
  27. 18
      machine/htif.h
  28. 4
      machine/machine.ac
  29. 29
      machine/machine.mk.in
  30. 4
      machine/mcall.h
  31. 1
      machine/mentry.S
  32. 38
      machine/minit.c
  33. 14
      machine/mtrap.c
  34. 20
      machine/mtrap.h
  35. 0
      machine/sbi.S
  36. 0
      machine/sbi.h
  37. 8
      machine/sbi_entry.S
  38. 3
      machine/sbi_impl.c
  39. 0
      machine/unprivileged_memory.h
  40. 35
      machine/vm.h
  41. 36
      pk/bbl.c
  42. 45
      pk/bits.h
  43. 10
      pk/boot.h
  44. 137
      pk/elf.c
  45. 8
      pk/elf.h
  46. 10
      pk/file.c
  47. 1
      pk/file.h
  48. 12
      pk/frontend.h
  49. 8
      pk/handlers.c
  50. 82
      pk/init.c
  51. 186
      pk/mmap.c
  52. 31
      pk/mmap.h
  53. 10
      pk/pk.ac
  54. 95
      pk/pk.c
  55. 17
      pk/pk.h
  56. 5
      pk/pk.lds
  57. 30
      pk/pk.mk.in
  58. 2
      pk/syscall.c
  59. 0
      util/snprintf.c
  60. 0
      util/string.c
  61. 0
      util/util.ac
  62. 9
      util/util.mk.in

7
Makefile.in

@ -35,6 +35,7 @@ default : all
project_name := @PACKAGE_TARNAME@ project_name := @PACKAGE_TARNAME@
src_dir := @srcdir@ src_dir := @srcdir@
scripts_dir := $(src_dir)/scripts scripts_dir := $(src_dir)/scripts
bbl_payload := @BBL_PAYLOAD@
# If the version information is not in the configure script, then we # If the version information is not in the configure script, then we
# assume that we are in a working directory. We use the vcs-version.sh # assume that we are in a working directory. We use the vcs-version.sh
@ -83,7 +84,7 @@ VPATH := $(addprefix $(src_dir)/, $(sprojs_enabled))
# - CXXFLAGS : flags for C++ compiler (eg. -Wall,-g,-O3) # - CXXFLAGS : flags for C++ compiler (eg. -Wall,-g,-O3)
CC := @CC@ CC := @CC@
CFLAGS := @CFLAGS@ $(CFLAGS) CFLAGS := @CFLAGS@ $(CFLAGS) -DBBL_PAYLOAD=\"$(bbl_payload)\"
COMPILE := $(CC) -MMD -MP $(CFLAGS) \ COMPILE := $(CC) -MMD -MP $(CFLAGS) \
$(sprojs_include) $(sprojs_include)
# Linker # Linker
@ -93,7 +94,7 @@ COMPILE := $(CC) -MMD -MP $(CFLAGS) \
LD := $(CC) LD := $(CC)
LDFLAGS := @LDFLAGS@ -nostartfiles -nostdlib -static $(LDFLAGS) LDFLAGS := @LDFLAGS@ -nostartfiles -nostdlib -static $(LDFLAGS)
LIBS := @LIBS@ LIBS := @LIBS@
LINK := $(LD) $(LDFLAGS) -T $(src_dir)/pk/pk.ld LINK := $(LD) $(LDFLAGS)
# Library creation # Library creation
@ -258,7 +259,7 @@ $$($(2)_install_prog_objs) : %.o : %.c
$(COMPILE) -c $$< $(COMPILE) -c $$<
$$($(2)_install_prog_exes) : % : %.o $$($(2)_prog_libnames) $$($(2)_install_prog_exes) : % : %.o $$($(2)_prog_libnames)
$(LINK) -o $$@ $$< $$($(2)_prog_libarg) $(LIBS) $(LINK) -o $$@ $$< $$($(2)_prog_libarg) $(LIBS) -T $(src_dir)/$(2)/$(2).lds
$(2)_c_deps += $$($(2)_install_prog_deps) $(2)_c_deps += $$($(2)_install_prog_deps)
$(2)_junk += \ $(2)_junk += \

8
bbl/bbl.ac

@ -0,0 +1,8 @@
AC_ARG_ENABLE([logo], AS_HELP_STRING([--disable-logo], [Disable boot logo]))
AS_IF([test "x$enable_logo" != "xno"], [
AC_DEFINE([PK_ENABLE_LOGO],,[Define if the RISC-V logo is to be displayed])
])
AC_ARG_WITH([payload], AS_HELP_STRING([--with-payload], [Set ELF payload for bbl]),
[AC_SUBST([BBL_PAYLOAD], $with_payload, [Kernel payload for bbl])],
[AC_SUBST([BBL_PAYLOAD], [dummy_payload], [Kernel payload for bbl])])

76
bbl/bbl.c

@ -0,0 +1,76 @@
#include "bbl.h"
#include "mtrap.h"
#include "atomic.h"
#include "vm.h"
#include "bits.h"
#include "config.h"
#include <string.h>
static kernel_elf_info info;
static volatile int elf_loaded;
static void supervisor_vm_init()
{
uintptr_t highest_va = -first_free_paddr;
mem_size = MIN(mem_size, highest_va - info.first_user_vaddr) & -MEGAPAGE_SIZE;
pte_t* sbi_pt = (pte_t*)(info.first_vaddr_after_user + info.load_offset);
memset(sbi_pt, 0, RISCV_PGSIZE);
pte_t* middle_pt = (void*)sbi_pt + RISCV_PGSIZE;
#ifndef __riscv64
size_t num_middle_pts = 1;
pte_t* root_pt = middle_pt;
memset(root_pt, 0, RISCV_PGSIZE);
#else
size_t num_middle_pts = (-info.first_user_vaddr - 1) / GIGAPAGE_SIZE + 1;
pte_t* root_pt = (void*)middle_pt + num_middle_pts * RISCV_PGSIZE;
memset(middle_pt, 0, (num_middle_pts + 1) * RISCV_PGSIZE);
for (size_t i = 0; i < num_middle_pts; i++)
root_pt[(1<<RISCV_PGLEVEL_BITS)-num_middle_pts+i] = ptd_create(((uintptr_t)middle_pt >> RISCV_PGSHIFT) + i);
#endif
for (uintptr_t vaddr = info.first_user_vaddr, paddr = vaddr + info.load_offset, end = info.first_vaddr_after_user;
paddr < mem_size; vaddr += MEGAPAGE_SIZE, paddr += MEGAPAGE_SIZE) {
int l2_shift = RISCV_PGLEVEL_BITS + RISCV_PGSHIFT;
size_t l2_idx = (info.first_user_vaddr >> l2_shift) & ((1 << RISCV_PGLEVEL_BITS)-1);
l2_idx += ((vaddr - info.first_user_vaddr) >> l2_shift);
middle_pt[l2_idx] = pte_create(paddr >> RISCV_PGSHIFT, PTE_TYPE_SRWX_GLOBAL);
}
// map SBI at top of vaddr space
extern char _sbi_end;
uintptr_t num_sbi_pages = ((uintptr_t)&_sbi_end - 1) / RISCV_PGSIZE + 1;
assert(num_sbi_pages <= (1 << RISCV_PGLEVEL_BITS));
for (uintptr_t i = 0; i < num_sbi_pages; i++) {
uintptr_t idx = (1 << RISCV_PGLEVEL_BITS) - num_sbi_pages + i;
sbi_pt[idx] = pte_create(i, PTE_TYPE_SRX_GLOBAL);
}
pte_t* sbi_pte = middle_pt + ((num_middle_pts << RISCV_PGLEVEL_BITS)-1);
assert(!*sbi_pte);
*sbi_pte = ptd_create((uintptr_t)sbi_pt >> RISCV_PGSHIFT);
mb();
root_page_table = root_pt;
write_csr(sptbr, (uintptr_t)root_pt >> RISCV_PGSHIFT);
}
void boot_loader()
{
extern char _payload_start, _payload_end;
load_kernel_elf(&_payload_start, &_payload_end - &_payload_start, &info);
supervisor_vm_init();
#ifdef PK_ENABLE_LOGO
print_logo();
#endif
mb();
elf_loaded = 1;
enter_supervisor_mode((void *)info.entry, 0);
}
void boot_other_hart()
{
while (!elf_loaded)
;
mb();
enter_supervisor_mode((void *)info.entry, 0);
}

23
bbl/bbl.h

@ -0,0 +1,23 @@
// See LICENSE for license details.
#ifndef _BBL_H
#define _BBL_H
#ifndef __ASSEMBLER__
#include <stdint.h>
#include <stddef.h>
typedef struct {
uintptr_t entry;
uintptr_t first_user_vaddr;
uintptr_t first_vaddr_after_user;
uintptr_t load_offset;
} kernel_elf_info;
void load_kernel_elf(void* blob, size_t size, kernel_elf_info* info);
void print_logo();
#endif // !__ASSEMBLER__
#endif

100
bbl/bbl.lds

@ -0,0 +1,100 @@
OUTPUT_ARCH( "riscv" )
ENTRY( reset_vector )
SECTIONS
{
/*--------------------------------------------------------------------*/
/* Code and read-only segment */
/*--------------------------------------------------------------------*/
/* Begining of code and text segment */
. = 0;
_ftext = .;
PROVIDE( eprol = . );
.text :
{
*(.text.init)
}
/* text: Program code section */
.text :
{
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
}
/* rodata: Read-only data */
.rodata :
{
*(.rdata)
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
}
/* End of code and read-only segment */
PROVIDE( etext = . );
_etext = .;
/*--------------------------------------------------------------------*/
/* Initialized data segment */
/*--------------------------------------------------------------------*/
/* Start of initialized data segment */
. = ALIGN(16);
_fdata = .;
/* data: Writable data */
.data :
{
*(.data)
*(.data.*)
*(.srodata*)
*(.gnu.linkonce.d.*)
*(.comment)
}
/* End of initialized data segment */
. = ALIGN(4);
PROVIDE( edata = . );
_edata = .;
/*--------------------------------------------------------------------*/
/* Uninitialized data segment */
/*--------------------------------------------------------------------*/
/* Start of uninitialized data segment */
. = .;
_fbss = .;
/* sbss: Uninitialized writeable small data section */
. = .;
/* bss: Uninitialized writeable data section */
. = .;
_bss_start = .;
.bss :
{
*(.bss)
*(.bss.*)
*(.sbss*)
*(.gnu.linkonce.b.*)
*(COMMON)
}
.sbi :
{
*(.sbi)
}
.payload :
{
*(.payload)
}
_end = .;
}

22
bbl/bbl.mk.in

@ -0,0 +1,22 @@
bbl_subproject_deps = \
util \
softfloat \
machine \
dummy_payload \
bbl_hdrs = \
bbl.h \
bbl_c_srcs = \
kernel_elf.c \
logo.c \
bbl_asm_srcs = \
payload.S \
payload.o: $(bbl_payload)
bbl_test_srcs =
bbl_install_prog_srcs = \
bbl.c \

54
bbl/kernel_elf.c

@ -0,0 +1,54 @@
// See LICENSE for license details.
#include "mtrap.h"
#include "bbl.h"
#include "bits.h"
#include "vm.h"
#include <elf.h>
#include <string.h>
void load_kernel_elf(void* blob, size_t size, kernel_elf_info* info)
{
Elf_Ehdr* eh = blob;
if (sizeof(*eh) > size ||
!(eh->e_ident[0] == '\177' && eh->e_ident[1] == 'E' &&
eh->e_ident[2] == 'L' && eh->e_ident[3] == 'F'))
goto fail;
if (IS_ELF64(*eh) != (sizeof(uintptr_t) == 8))
goto fail;
uintptr_t min_vaddr = -1, max_vaddr = 0;
size_t phdr_size = eh->e_phnum * sizeof(Elf_Ehdr);
Elf_Phdr* ph = blob + eh->e_phoff;
if (eh->e_phoff + phdr_size > size)
goto fail;
first_free_paddr = ROUNDUP(first_free_paddr, MEGAPAGE_SIZE);
for (int i = 0; i < eh->e_phnum; i++)
if (ph[i].p_type == PT_LOAD && ph[i].p_memsz && ph[i].p_vaddr < min_vaddr)
min_vaddr = ph[i].p_vaddr;
min_vaddr = ROUNDDOWN(min_vaddr, MEGAPAGE_SIZE);
uintptr_t bias = first_free_paddr - min_vaddr;
for (int i = eh->e_phnum - 1; i >= 0; i--) {
if(ph[i].p_type == PT_LOAD && ph[i].p_memsz) {
uintptr_t prepad = ph[i].p_vaddr % RISCV_PGSIZE;
uintptr_t vaddr = ph[i].p_vaddr + bias;
if (vaddr + ph[i].p_memsz > max_vaddr)
max_vaddr = vaddr + ph[i].p_memsz;
if (ph[i].p_offset + ph[i].p_filesz > size)
goto fail;
memcpy((void*)vaddr, blob + ph[i].p_offset, ph[i].p_filesz);
memset((void*)vaddr - prepad, 0, prepad);
memset((void*)vaddr + ph[i].p_filesz, 0, ph[i].p_memsz - ph[i].p_filesz);
}
}
info->entry = eh->e_entry;
info->load_offset = bias;
info->first_user_vaddr = min_vaddr;
info->first_vaddr_after_user = ROUNDUP(max_vaddr - bias, RISCV_PGSIZE);
return;
fail:
die("failed to load payload");
}

4
pk/logo.c → bbl/logo.c

@ -1,5 +1,5 @@
#include <string.h> #include <string.h>
#include "file.h" #include "mtrap.h"
static const char logo[] = static const char logo[] =
" vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n" " vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n"
@ -28,5 +28,5 @@ static const char logo[] =
void print_logo() void print_logo()
{ {
file_write(stderr, logo, sizeof logo); putstring(logo);
} }

7
bbl/payload.S

@ -0,0 +1,7 @@
.section ".payload","a",@progbits
.align 3
.globl _payload_start, _payload_end
_payload_start:
.incbin BBL_PAYLOAD
_payload_end:

12
config.h.in

@ -1,5 +1,14 @@
/* config.h.in. Generated from configure.ac by autoheader. */ /* config.h.in. Generated from configure.ac by autoheader. */
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef BBL_ENABLED
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef DUMMY_PAYLOAD_ENABLED
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef MACHINE_ENABLED
/* Define to the address where bug reports for this package should be sent. */ /* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT #undef PACKAGE_BUGREPORT
@ -35,3 +44,6 @@
/* Define to 1 if you have the ANSI C header files. */ /* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS #undef STDC_HEADERS
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef UTIL_ENABLED

223
configure

@ -590,6 +590,7 @@ ac_subst_vars='LTLIBOBJS
LIBOBJS LIBOBJS
subprojects_enabled subprojects_enabled
subprojects subprojects
BBL_PAYLOAD
EGREP EGREP
GREP GREP
CPP CPP
@ -667,6 +668,8 @@ enable_option_checking
enable_stow enable_stow
enable_optional_subprojects enable_optional_subprojects
enable_vm enable_vm
enable_logo
with_payload
enable_fp_emulation enable_fp_emulation
' '
ac_precious_vars='build_alias ac_precious_vars='build_alias
@ -1303,6 +1306,11 @@ Optional Features:
--disable-logo Disable boot logo --disable-logo Disable boot logo
--disable-fp-emulation Disable floating-point emulation --disable-fp-emulation Disable floating-point emulation
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-payload Set ELF payload for bbl
Some influential environment variables: Some influential environment variables:
CC C compiler command CC C compiler command
CFLAGS C compiler flags CFLAGS C compiler flags
@ -4046,9 +4054,53 @@ $as_echo "#define PK_ENABLE_VM /**/" >>confdefs.h
fi fi
# Check whether --enable-vm was given.
if test "${enable_vm+set}" = set; then :
enableval=$enable_vm;
# Determine if this is a required or an optional subproject
# Determine if there is a group with the same name
# Create variations of the subproject name suitable for use as a CPP
# enabled define, a shell enabled variable, and a shell function
# Add subproject to our running list
subprojects="$subprojects bbl"
# Process the subproject appropriately. If enabled add it to the
# $enabled_subprojects running shell variable, set a
# SUBPROJECT_ENABLED C define, and include the appropriate
# 'subproject.ac'.
{ $as_echo "$as_me:${as_lineno-$LINENO}: configuring default subproject : bbl" >&5
$as_echo "$as_me: configuring default subproject : bbl" >&6;}
ac_config_files="$ac_config_files bbl.mk:bbl/bbl.mk.in"
enable_bbl_sproj="yes"
subprojects_enabled="$subprojects_enabled bbl"
$as_echo "#define BBL_ENABLED /**/" >>confdefs.h
# Check whether --enable-logo was given.
if test "${enable_logo+set}" = set; then :
enableval=$enable_logo;
fi fi
if test "x$enable_logo" != "xno"; then : if test "x$enable_logo" != "xno"; then :
@ -4059,16 +4111,13 @@ $as_echo "#define PK_ENABLE_LOGO /**/" >>confdefs.h
fi fi
# Check whether --enable-fp-emulation was given.
if test "${enable_fp_emulation+set}" = set; then :
enableval=$enable_fp_emulation;
fi
if test "x$enable_fp_emulation" != "xno"; then : # Check whether --with-payload was given.
if test "${with_payload+set}" = set; then :
withval=$with_payload; BBL_PAYLOAD=$with_payload
$as_echo "#define PK_ENABLE_FP_EMULATION /**/" >>confdefs.h
else
BBL_PAYLOAD=dummy_payload
fi fi
@ -4076,6 +4125,7 @@ fi
# Determine if this is a required or an optional subproject # Determine if this is a required or an optional subproject
@ -4121,6 +4171,153 @@ $as_echo "#define SOFTFLOAT_ENABLED /**/" >>confdefs.h
# Determine if this is a required or an optional subproject
# Determine if there is a group with the same name
# Create variations of the subproject name suitable for use as a CPP
# enabled define, a shell enabled variable, and a shell function
# Add subproject to our running list
subprojects="$subprojects dummy_payload"
# Process the subproject appropriately. If enabled add it to the
# $enabled_subprojects running shell variable, set a
# SUBPROJECT_ENABLED C define, and include the appropriate
# 'subproject.ac'.
{ $as_echo "$as_me:${as_lineno-$LINENO}: configuring default subproject : dummy_payload" >&5
$as_echo "$as_me: configuring default subproject : dummy_payload" >&6;}
ac_config_files="$ac_config_files dummy_payload.mk:dummy_payload/dummy_payload.mk.in"
enable_dummy_payload_sproj="yes"
subprojects_enabled="$subprojects_enabled dummy_payload"
$as_echo "#define DUMMY_PAYLOAD_ENABLED /**/" >>confdefs.h
# Determine if this is a required or an optional subproject
# Determine if there is a group with the same name
# Create variations of the subproject name suitable for use as a CPP
# enabled define, a shell enabled variable, and a shell function
# Add subproject to our running list
subprojects="$subprojects machine"
# Process the subproject appropriately. If enabled add it to the
# $enabled_subprojects running shell variable, set a
# SUBPROJECT_ENABLED C define, and include the appropriate
# 'subproject.ac'.
{ $as_echo "$as_me:${as_lineno-$LINENO}: configuring default subproject : machine" >&5
$as_echo "$as_me: configuring default subproject : machine" >&6;}
ac_config_files="$ac_config_files machine.mk:machine/machine.mk.in"
enable_machine_sproj="yes"
subprojects_enabled="$subprojects_enabled machine"
$as_echo "#define MACHINE_ENABLED /**/" >>confdefs.h
# Check whether --enable-fp-emulation was given.
if test "${enable_fp_emulation+set}" = set; then :
enableval=$enable_fp_emulation;
fi
if test "x$enable_fp_emulation" != "xno"; then :
$as_echo "#define PK_ENABLE_FP_EMULATION /**/" >>confdefs.h
fi
# Determine if this is a required or an optional subproject
# Determine if there is a group with the same name
# Create variations of the subproject name suitable for use as a CPP
# enabled define, a shell enabled variable, and a shell function
# Add subproject to our running list
subprojects="$subprojects util"
# Process the subproject appropriately. If enabled add it to the
# $enabled_subprojects running shell variable, set a
# SUBPROJECT_ENABLED C define, and include the appropriate
# 'subproject.ac'.
{ $as_echo "$as_me:${as_lineno-$LINENO}: configuring default subproject : util" >&5
$as_echo "$as_me: configuring default subproject : util" >&6;}
ac_config_files="$ac_config_files util.mk:util/util.mk.in"
enable_util_sproj="yes"
subprojects_enabled="$subprojects_enabled util"
$as_echo "#define UTIL_ENABLED /**/" >>confdefs.h
# Output make variables # Output make variables
@ -4838,7 +5035,11 @@ for ac_config_target in $ac_config_targets
do do
case $ac_config_target in case $ac_config_target in
"pk.mk") CONFIG_FILES="$CONFIG_FILES pk.mk:pk/pk.mk.in" ;; "pk.mk") CONFIG_FILES="$CONFIG_FILES pk.mk:pk/pk.mk.in" ;;
"bbl.mk") CONFIG_FILES="$CONFIG_FILES bbl.mk:bbl/bbl.mk.in" ;;
"softfloat.mk") CONFIG_FILES="$CONFIG_FILES softfloat.mk:softfloat/softfloat.mk.in" ;; "softfloat.mk") CONFIG_FILES="$CONFIG_FILES softfloat.mk:softfloat/softfloat.mk.in" ;;
"dummy_payload.mk") CONFIG_FILES="$CONFIG_FILES dummy_payload.mk:dummy_payload/dummy_payload.mk.in" ;;
"machine.mk") CONFIG_FILES="$CONFIG_FILES machine.mk:machine/machine.mk.in" ;;
"util.mk") CONFIG_FILES="$CONFIG_FILES util.mk:util/util.mk.in" ;;
"config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;

2
configure.ac

@ -81,7 +81,7 @@ AC_SUBST([LIBS], ["-lgcc"])
# The '*' suffix indicates an optional subproject. The '**' suffix # The '*' suffix indicates an optional subproject. The '**' suffix
# indicates an optional subproject which is also the name of a group. # indicates an optional subproject which is also the name of a group.
MCPPBS_SUBPROJECTS([ pk, softfloat ]) MCPPBS_SUBPROJECTS([ pk, bbl, softfloat, dummy_payload, machine, util ])
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# MCPPBS subproject groups # MCPPBS subproject groups

0
dummy_payload/dummy_payload.ac

21
dummy_payload/dummy_payload.c

@ -0,0 +1,21 @@
#include <stdint.h>
#include "sbi.h"
asm (".globl _start\n\
_start: la sp, stack\n\
j entry\n\
.pushsection .rodata\n\
.align 4\n\
.skip 4096\n\
stack:\n\
.popsection");
void entry()
{
const char* message =
"This is bbl's dummy_payload. To boot a real kernel, reconfigure\n\
bbl with the flag --with-payload=PATH, then rebuild bbl.\n";
while (*message)
sbi_console_putchar(*message++);
sbi_shutdown();
}

3
dummy_payload/dummy_payload.lds

@ -0,0 +1,3 @@
SECTIONS {
. = -0x80000000;
}

13
dummy_payload/dummy_payload.mk.in

@ -0,0 +1,13 @@
dummy_payload_subproject_deps = \
dummy_payload_hdrs = \
dummy_payload_c_srcs = \
dummy_payload_asm_srcs = \
dummy_sbi.S \
dummy_payload_test_srcs =
dummy_payload_install_prog_srcs = \
dummy_payload.c \

1
dummy_payload/dummy_sbi.S

@ -0,0 +1 @@
../machine/sbi.S

2
pk/atomic.h → machine/atomic.h

@ -6,7 +6,7 @@
#include "config.h" #include "config.h"
#include "encoding.h" #include "encoding.h"
// Currently, interrupts are always disabled when in pk/bbl. // Currently, interrupts are always disabled in M-mode.
#define disable_irqsave() (0) #define disable_irqsave() (0)
#define enable_irqrestore(flags) ((void) (flags)) #define enable_irqrestore(flags) ((void) (flags))

33
machine/bits.h

@ -0,0 +1,33 @@
#ifndef _RISCV_BITS_H
#define _RISCV_BITS_H
#define likely(x) __builtin_expect((x), 1)
#define unlikely(x) __builtin_expect((x), 0)
#define ROUNDUP(a, b) ((((a)-1)/(b)+1)*(b))
#define ROUNDDOWN(a, b) ((a)/(b)*(b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1)))
#define INSERT_FIELD(val, which, fieldval) (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
#define STR(x) XSTR(x)
#define XSTR(x) #x
#ifdef __riscv64
# define SLL32 sllw
# define STORE sd
# define LOAD ld
# define LOG_REGBYTES 3
#else
# define SLL32 sll
# define STORE sw
# define LOAD lw
# define LOG_REGBYTES 2
#endif
#define REGBYTES (1 << LOG_REGBYTES)
#endif

0
pk/configstring.c → machine/configstring.c

0
pk/emulation.c → machine/emulation.c

0
pk/emulation.h → machine/emulation.h

0
pk/encoding.h → machine/encoding.h

0
pk/fp_asm.S → machine/fp_asm.S

0
pk/fp_emulation.c → machine/fp_emulation.c

0
pk/fp_emulation.h → machine/fp_emulation.h

18
machine/htif.h

@ -0,0 +1,18 @@
#ifndef _RISCV_HTIF_H
#define _RISCV_HTIF_H
#include <stdint.h>
#ifdef __riscv64
# define TOHOST_CMD(dev, cmd, payload) \
(((uint64_t)(dev) << 56) | ((uint64_t)(cmd) << 48) | (uint64_t)(payload))
#else
# define TOHOST_CMD(dev, cmd, payload) ({ \
if ((dev) || (cmd)) __builtin_trap(); \
(payload); })
#endif
#define FROMHOST_DEV(fromhost_value) ((uint64_t)(fromhost_value) >> 56)
#define FROMHOST_CMD(fromhost_value) ((uint64_t)(fromhost_value) << 8 >> 56)
#define FROMHOST_DATA(fromhost_value) ((uint64_t)(fromhost_value) << 16 >> 16)
#endif

4
machine/machine.ac

@ -0,0 +1,4 @@
AC_ARG_ENABLE([fp-emulation], AS_HELP_STRING([--disable-fp-emulation], [Disable floating-point emulation]))
AS_IF([test "x$enable_fp_emulation" != "xno"], [
AC_DEFINE([PK_ENABLE_FP_EMULATION],,[Define if floating-point emulation is enabled])
])

29
machine/machine.mk.in

@ -0,0 +1,29 @@
machine_subproject_deps = \
softfloat \
machine_hdrs = \
atomic.h \
bits.h \
emulation.h \
encoding.h \
fp_emulation.h \
htif.h \
mcall.h \
mtrap.h \
sbi.h \
unprivileged_memory.h \
vm.h \
machine_c_srcs = \
mtrap.c \
minit.c \
emulation.c \
fp_emulation.c \
sbi_impl.c \
configstring.c \
machine_asm_srcs = \
mentry.S \
fp_asm.S \
sbi_entry.S \
sbi.S \

4
pk/mcall.h → machine/mcall.h

@ -1,5 +1,5 @@
#ifndef _PK_MCALL_H #ifndef _RISCV_MCALL_H
#define _PK_MCALL_H #define _RISCV_MCALL_H
#define MCALL_HART_ID 0 #define MCALL_HART_ID 0
#define MCALL_CONSOLE_PUTCHAR 1 #define MCALL_CONSOLE_PUTCHAR 1

1
pk/mentry.S → machine/mentry.S

@ -1,6 +1,7 @@
// See LICENSE for license details. // See LICENSE for license details.
#include "mtrap.h" #include "mtrap.h"
#include "bits.h"
.data .data
.align 6 .align 6

38
pk/minit.c → machine/minit.c

@ -1,8 +1,11 @@
#include "vm.h"
#include "mtrap.h" #include "mtrap.h"
#include "atomic.h"
#include "vm.h"
#include "fp_emulation.h" #include "fp_emulation.h"
#include "boot.h" #include <string.h>
pte_t* root_page_table;
uintptr_t first_free_paddr;
uintptr_t mem_size; uintptr_t mem_size;
uint32_t num_harts; uint32_t num_harts;
@ -64,6 +67,18 @@ void hls_init(uint32_t id, csr_t* csrs)
hls->csrs = csrs; hls->csrs = csrs;
} }
static uintptr_t sbi_top_paddr()
{
extern char _end;
return ROUNDUP((uintptr_t)&_end, RISCV_PGSIZE);
}
static void memory_init()
{
mem_size = mem_size / MEGAPAGE_SIZE * MEGAPAGE_SIZE;
first_free_paddr = sbi_top_paddr() + num_harts * RISCV_PGSIZE;
}
static void hart_init() static void hart_init()
{ {
mstatus_init(); mstatus_init();
@ -73,12 +88,10 @@ static void hart_init()
void init_first_hart() void init_first_hart()
{ {
file_init();
hart_init(); hart_init();
memset(HLS(), 0, sizeof(*HLS())); memset(HLS(), 0, sizeof(*HLS()));
parse_config_string(); parse_config_string();
vm_init(); memory_init();
boot_loader(); boot_loader();
} }
@ -86,23 +99,22 @@ void init_other_hart()
{ {
hart_init(); hart_init();
// wait until virtual memory is enabled // wait until hart 0 discovers us
while (*(pte_t* volatile*)&root_page_table == NULL) while (*(csr_t * volatile *)&HLS()->csrs == NULL)
; ;
mb();
write_csr(sptbr, (uintptr_t)root_page_table >> RISCV_PGSHIFT);
// make sure hart 0 has discovered us
assert(HLS()->csrs != NULL);
boot_other_hart(); boot_other_hart();
} }
void prepare_supervisor_mode() void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t stack)
{ {
uintptr_t mstatus = read_csr(mstatus); uintptr_t mstatus = read_csr(mstatus);
mstatus = INSERT_FIELD(mstatus, MSTATUS_MPP, PRV_S); mstatus = INSERT_FIELD(mstatus, MSTATUS_MPP, PRV_S);
mstatus = INSERT_FIELD(mstatus, MSTATUS_MPIE, 0); mstatus = INSERT_FIELD(mstatus, MSTATUS_MPIE, 0);
write_csr(mstatus, mstatus); write_csr(mstatus, mstatus);
write_csr(mscratch, MACHINE_STACK_TOP() - MENTRY_FRAME_SIZE); write_csr(mscratch, MACHINE_STACK_TOP() - MENTRY_FRAME_SIZE);
write_csr(mepc, fn);
write_csr(sptbr, (uintptr_t)root_page_table >> RISCV_PGSHIFT);
asm volatile ("mv a0, %0; mv sp, %0; eret" : : "r" (stack));
__builtin_unreachable();
} }

14
pk/mtrap.c → machine/mtrap.c

@ -1,7 +1,8 @@
#include "mtrap.h" #include "mtrap.h"
#include "frontend.h"
#include "mcall.h" #include "mcall.h"
#include "vm.h" #include "htif.h"
#include "atomic.h"
#include "bits.h"
#include <errno.h> #include <errno.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
@ -68,6 +69,12 @@ void poweroff()
write_csr(mtohost, 1); write_csr(mtohost, 1);
} }
void putstring(const char* s)
{
while (*s)
mcall_console_putchar(*s++);
}
void printm(const char* s, ...) void printm(const char* s, ...)
{ {
char buf[256]; char buf[256];
@ -77,8 +84,7 @@ void printm(const char* s, ...)
vsnprintf(buf, sizeof buf, s, vl); vsnprintf(buf, sizeof buf, s, vl);
va_end(vl); va_end(vl);
for (const char* p = buf; *p; p++) putstring(buf);
mcall_console_putchar(*p);
} }
static void send_ipi(uintptr_t recipient, int event) static void send_ipi(uintptr_t recipient, int event)

20
pk/mtrap.h → machine/mtrap.h

@ -1,7 +1,6 @@
#ifndef _PK_MTRAP_H #ifndef _RISCV_MTRAP_H
#define _PK_MTRAP_H #define _RISCV_MTRAP_H
#include "bits.h"
#include "encoding.h" #include "encoding.h"
#ifdef __riscv_atomic #ifdef __riscv_atomic
@ -29,6 +28,7 @@ static inline int xlen()
return read_const_csr(misa) < 0 ? 64 : 32; return read_const_csr(misa) < 0 ? 64 : 32;
} }
extern uintptr_t first_free_paddr;
extern uintptr_t mem_size; extern uintptr_t mem_size;
extern uint32_t num_harts; extern uint32_t num_harts;
@ -52,8 +52,6 @@ typedef struct {
#define IPI_FENCE_I 0x2 #define IPI_FENCE_I 0x2
#define IPI_SFENCE_VM 0x4 #define IPI_SFENCE_VM 0x4
void hls_init(uint32_t hart_id, csr_t* csrs);
#define MACHINE_STACK_TOP() ({ \ #define MACHINE_STACK_TOP() ({ \
register uintptr_t sp asm ("sp"); \ register uintptr_t sp asm ("sp"); \
(void*)((sp + RISCV_PGSIZE) & -RISCV_PGSIZE); }) (void*)((sp + RISCV_PGSIZE) & -RISCV_PGSIZE); })
@ -62,13 +60,25 @@ void hls_init(uint32_t hart_id, csr_t* csrs);
#define HLS() ((hls_t*)(MACHINE_STACK_TOP() - HLS_SIZE)) #define HLS() ((hls_t*)(MACHINE_STACK_TOP() - HLS_SIZE))
#define OTHER_HLS(id) ((hls_t*)((void*)HLS() + RISCV_PGSIZE * ((id) - read_const_csr(mhartid)))) #define OTHER_HLS(id) ((hls_t*)((void*)HLS() + RISCV_PGSIZE * ((id) - read_const_csr(mhartid))))
void hls_init(uint32_t hart_id, csr_t* csrs);
void parse_config_string(); void parse_config_string();
void poweroff(void) __attribute((noreturn)); void poweroff(void) __attribute((noreturn));
void printm(const char* s, ...); void printm(const char* s, ...);
void putstring(const char* s);
#define assert(x) ({ if (!(x)) die("assertion failed: %s", #x); }) #define assert(x) ({ if (!(x)) die("assertion failed: %s", #x); })
#define die(str, ...) ({ printm("%s:%d: " str "\n", __FILE__, __LINE__, ##__VA_ARGS__); poweroff(); }) #define die(str, ...) ({ printm("%s:%d: " str "\n", __FILE__, __LINE__, ##__VA_ARGS__); poweroff(); })
#define printk(...) die("printk") #define printk(...) die("printk")
void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t stack)
__attribute__((noreturn));
void boot_loader();
void boot_other_hart();
static inline void wfi()
{
asm volatile ("wfi" ::: "memory");
}
#endif // !__ASSEMBLER__ #endif // !__ASSEMBLER__
#define MACHINE_STACK_SIZE RISCV_PGSIZE #define MACHINE_STACK_SIZE RISCV_PGSIZE

0
pk/sbi.S → machine/sbi.S

0
pk/sbi.h → machine/sbi.h

8
pk/sbi_entry.S → machine/sbi_entry.S

@ -24,7 +24,7 @@ sbi_base:
# query_memory # query_memory
.align 4 .align 4
j __sbi_query_memory tail __sbi_query_memory
# console_putchar # console_putchar
.align 4 .align 4
@ -72,11 +72,11 @@ sbi_base:
# mask_interrupt # mask_interrupt
.align 4 .align 4
j __sbi_mask_interrupt tail __sbi_mask_interrupt
# unmask_interrupt # unmask_interrupt
.align 4 .align 4
j __sbi_unmask_interrupt tail __sbi_unmask_interrupt
# remote_sfence_vm # remote_sfence_vm
.align 4 .align 4
@ -107,3 +107,5 @@ do_mcall:
ret ret
.align RISCV_PGSHIFT .align RISCV_PGSHIFT
.globl _sbi_end
_sbi_end:

3
pk/sbi_impl.c → machine/sbi_impl.c

@ -1,11 +1,10 @@
#include "mtrap.h" #include "mtrap.h"
#include "sbi.h" #include "sbi.h"
#include "boot.h"
uintptr_t __sbi_query_memory(uintptr_t id, memory_block_info *p) uintptr_t __sbi_query_memory(uintptr_t id, memory_block_info *p)
{ {
if (id == 0) { if (id == 0) {
p->base = current.first_free_paddr; p->base = first_free_paddr;
p->size = mem_size - p->base; p->size = mem_size - p->base;
return 0; return 0;
} }

0
pk/unprivileged_memory.h → machine/unprivileged_memory.h

35
machine/vm.h

@ -0,0 +1,35 @@
#ifndef _VM_H
#define _VM_H
#include "encoding.h"
#include <stdint.h>
#define MEGAPAGE_SIZE ((uintptr_t)(RISCV_PGSIZE << RISCV_PGLEVEL_BITS))
#ifdef __riscv64
# define VM_CHOICE VM_SV39
# define VA_BITS 39
# define GIGAPAGE_SIZE (MEGAPAGE_SIZE << RISCV_PGLEVEL_BITS)
#else
# define VM_CHOICE VM_SV32
# define VA_BITS 32
#endif
typedef uintptr_t pte_t;
extern pte_t* root_page_table;
static inline void flush_tlb()
{
asm volatile("sfence.vm");
}
static inline pte_t pte_create(uintptr_t ppn, int type)
{
return (ppn << PTE_PPN_SHIFT) | PTE_V | type;
}
static inline pte_t ptd_create(uintptr_t ppn)
{
return pte_create(ppn, PTE_TYPE_TABLE);
}
#endif

36
pk/bbl.c

@ -1,36 +0,0 @@
#include "boot.h"
#include "mtrap.h"
#include "vm.h"
#include "config.h"
static volatile int elf_loaded;
static void enter_entry_point()
{
prepare_supervisor_mode();
write_csr(mepc, current.entry);
asm volatile("eret");
__builtin_unreachable();
}
void run_loaded_program(size_t argc, char** argv)
{
if (!current.is_supervisor)
die("bbl can't run user binaries; try using pk instead");
supervisor_vm_init();
#ifdef PK_ENABLE_LOGO
print_logo();
#endif
mb();
elf_loaded = 1;
enter_entry_point();
}
void boot_other_hart()
{
while (!elf_loaded)
;
mb();
enter_entry_point();
}

45
pk/bits.h

@ -1,45 +0,0 @@
#ifndef PK_BITS_H
#define PK_BITS_H
#define likely(x) __builtin_expect((x), 1)
#define unlikely(x) __builtin_expect((x), 0)
#define ROUNDUP(a, b) ((((a)-1)/(b)+1)*(b))
#define ROUNDDOWN(a, b) ((a)/(b)*(b))
#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1)))
#define INSERT_FIELD(val, which, fieldval) (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
#define CONST_POPCOUNT2(x) ((((x) >> 0) & 1) + (((x) >> 1) & 1))
#define CONST_POPCOUNT4(x) (CONST_POPCOUNT2(x) + CONST_POPCOUNT2((x)>>2))
#define CONST_POPCOUNT8(x) (CONST_POPCOUNT4(x) + CONST_POPCOUNT4((x)>>4))
#define CONST_POPCOUNT16(x) (CONST_POPCOUNT8(x) + CONST_POPCOUNT8((x)>>8))
#define CONST_POPCOUNT32(x) (CONST_POPCOUNT16(x) + CONST_POPCOUNT16((x)>>16))
#define CONST_POPCOUNT64(x) (CONST_POPCOUNT32(x) + CONST_POPCOUNT32((x)>>32))
#define CONST_POPCOUNT(x) CONST_POPCOUNT64(x)
#define CONST_CTZ2(x) CONST_POPCOUNT2(((x) & -(x))-1)
#define CONST_CTZ4(x) CONST_POPCOUNT4(((x) & -(x))-1)
#define CONST_CTZ8(x) CONST_POPCOUNT8(((x) & -(x))-1)
#define CONST_CTZ16(x) CONST_POPCOUNT16(((x) & -(x))-1)
#define CONST_CTZ32(x) CONST_POPCOUNT32(((x) & -(x))-1)
#define CONST_CTZ64(x) CONST_POPCOUNT64(((x) & -(x))-1)
#define CONST_CTZ(x) CONST_CTZ64(x)
#define STR(x) XSTR(x)
#define XSTR(x) #x
#ifdef __riscv64
# define SLL32 sllw
# define STORE sd
# define LOAD ld
# define LOG_REGBYTES 3
#else
# define SLL32 sll
# define STORE sw
# define LOAD lw
# define LOG_REGBYTES 2
#endif
#define REGBYTES (1 << LOG_REGBYTES)
#endif

10
pk/boot.h

@ -5,7 +5,6 @@
#ifndef __ASSEMBLER__ #ifndef __ASSEMBLER__
#include <stdint.h>
#include <stddef.h> #include <stddef.h>
typedef struct { typedef struct {
@ -14,28 +13,19 @@ typedef struct {
int is_supervisor; int is_supervisor;
size_t phdr; size_t phdr;
size_t phdr_size; size_t phdr_size;
size_t first_free_paddr;
size_t first_user_vaddr;
size_t first_vaddr_after_user;
size_t bias; size_t bias;
size_t entry; size_t entry;
size_t brk_min; size_t brk_min;
size_t brk; size_t brk;
size_t brk_max; size_t brk_max;
size_t mmap_max; size_t mmap_max;
size_t stack_bottom;
size_t stack_top; size_t stack_top;
size_t t0; size_t t0;
} elf_info; } elf_info;
extern elf_info current; extern elf_info current;
void prepare_supervisor_mode();
void run_loaded_program(size_t argc, char** argv);
void boot_loader();
void boot_other_hart();
void load_elf(const char* fn, elf_info* info); void load_elf(const char* fn, elf_info* info);
void print_logo();
#endif // !__ASSEMBLER__ #endif // !__ASSEMBLER__

137
pk/elf.c

@ -1,9 +1,9 @@
// See LICENSE for license details. // See LICENSE for license details.
#include "file.h" #include "mmap.h"
#include "vm.h"
#include "mtrap.h" #include "mtrap.h"
#include "boot.h" #include "boot.h"
#include "bits.h"
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <elf.h> #include <elf.h>
@ -15,100 +15,55 @@ void load_elf(const char* fn, elf_info* info)
if (IS_ERR_VALUE(file)) if (IS_ERR_VALUE(file))
goto fail; goto fail;
Elf64_Ehdr eh64; Elf_Ehdr eh;
ssize_t ehdr_size = file_pread(file, &eh64, sizeof(eh64), 0); ssize_t ehdr_size = file_pread(file, &eh, sizeof(eh), 0);
if (ehdr_size < (ssize_t)sizeof(eh64) || if (ehdr_size < (ssize_t)sizeof(eh) ||
!(eh64.e_ident[0] == '\177' && eh64.e_ident[1] == 'E' && !(eh.e_ident[0] == '\177' && eh.e_ident[1] == 'E' &&
eh64.e_ident[2] == 'L' && eh64.e_ident[3] == 'F')) eh.e_ident[2] == 'L' && eh.e_ident[3] == 'F'))
goto fail; goto fail;
uintptr_t min_vaddr = -1, max_vaddr = 0;
#define LOAD_ELF do { \
eh = (typeof(eh))&eh64; \
size_t phdr_size = eh->e_phnum*sizeof(*ph); \
if (phdr_size > info->phdr_size) \
goto fail; \
ssize_t ret = file_pread(file, (void*)info->phdr, phdr_size, eh->e_phoff); \
if (ret < (ssize_t)phdr_size) \
goto fail; \
info->phnum = eh->e_phnum; \
info->phent = sizeof(*ph); \
ph = (typeof(ph))info->phdr; \
info->is_supervisor = (eh->e_entry >> (8*sizeof(eh->e_entry)-1)) != 0; \
if (info->is_supervisor) \
info->first_free_paddr = ROUNDUP(info->first_free_paddr, SUPERPAGE_SIZE); \
for (int i = 0; i < eh->e_phnum; i++) \
if (ph[i].p_type == PT_LOAD && ph[i].p_memsz && ph[i].p_vaddr < min_vaddr) \
min_vaddr = ph[i].p_vaddr; \
if (info->is_supervisor) \
min_vaddr = ROUNDDOWN(min_vaddr, SUPERPAGE_SIZE); \
else \
min_vaddr = ROUNDDOWN(min_vaddr, RISCV_PGSIZE); \
uintptr_t bias = 0; \
if (info->is_supervisor || eh->e_type == ET_DYN) \
bias = info->first_free_paddr - min_vaddr; \
info->entry = eh->e_entry; \
if (!info->is_supervisor) { \
info->entry += bias; \
min_vaddr += bias; \
} \
info->bias = bias; \
int flags = MAP_FIXED | MAP_PRIVATE; \
if (info->is_supervisor) \
flags |= MAP_POPULATE; \
for (int i = eh->e_phnum - 1; i >= 0; i--) { \
if(ph[i].p_type == PT_LOAD && ph[i].p_memsz) { \
uintptr_t prepad = ph[i].p_vaddr % RISCV_PGSIZE; \
uintptr_t vaddr = ph[i].p_vaddr + bias; \
if (vaddr + ph[i].p_memsz > max_vaddr) \
max_vaddr = vaddr + ph[i].p_memsz; \
if (info->is_supervisor) { \
if (!__valid_user_range(vaddr - prepad, vaddr + ph[i].p_memsz)) \
goto fail; \
ret = file_pread(file, (void*)vaddr, ph[i].p_filesz, ph[i].p_offset); \
if (ret < (ssize_t)ph[i].p_filesz) \
goto fail; \
memset((void*)vaddr - prepad, 0, prepad); \
memset((void*)vaddr + ph[i].p_filesz, 0, ph[i].p_memsz - ph[i].p_filesz); \
} else { \
int flags2 = flags | (prepad ? MAP_POPULATE : 0); \
if (__do_mmap(vaddr - prepad, ph[i].p_filesz + prepad, -1, flags2, file, ph[i].p_offset - prepad) != vaddr - prepad) \
goto fail; \
memset((void*)vaddr - prepad, 0, prepad); \
size_t mapped = ROUNDUP(ph[i].p_filesz + prepad, RISCV_PGSIZE) - prepad; \
if (ph[i].p_memsz > mapped) \
if (__do_mmap(vaddr + mapped, ph[i].p_memsz - mapped, -1, flags|MAP_ANONYMOUS, 0, 0) != vaddr + mapped) \
goto fail; \
} \
} \
} \
} while(0)
if (IS_ELF64(eh64))
{
#ifndef __riscv64
die("can't run 64-bit ELF on 32-bit arch");
#endif
Elf64_Ehdr* eh;
Elf64_Phdr* ph;
LOAD_ELF;
}
else if (IS_ELF32(eh64))
{
#ifdef __riscv64 #ifdef __riscv64
die("can't run 32-bit ELF on 64-bit arch"); assert(IS_ELF64(eh));
#else
assert(IS_ELF32(eh));
#endif #endif
Elf32_Ehdr* eh;
Elf32_Phdr* ph;
LOAD_ELF;
}
else
goto fail;
info->first_user_vaddr = min_vaddr; uintptr_t min_vaddr = -1;
info->first_vaddr_after_user = ROUNDUP(max_vaddr - info->bias, RISCV_PGSIZE); size_t phdr_size = eh.e_phnum * sizeof(Elf_Phdr);
info->brk_min = max_vaddr; if (phdr_size > info->phdr_size)
goto fail;
ssize_t ret = file_pread(file, (void*)info->phdr, phdr_size, eh.e_phoff);
if (ret < (ssize_t)phdr_size)
goto fail;
info->phnum = eh.e_phnum;
info->phent = sizeof(Elf_Phdr);
Elf_Phdr* ph = (typeof(ph))info->phdr;
for (int i = 0; i < eh.e_phnum; i++)
if (ph[i].p_type == PT_LOAD && ph[i].p_memsz && ph[i].p_vaddr < min_vaddr)
min_vaddr = ph[i].p_vaddr;
min_vaddr = ROUNDDOWN(min_vaddr, RISCV_PGSIZE);
uintptr_t bias = 0;
if (eh.e_type == ET_DYN)
bias = first_free_paddr - min_vaddr;
min_vaddr += bias;
info->entry = eh.e_entry + bias;
int flags = MAP_FIXED | MAP_PRIVATE;
for (int i = eh.e_phnum - 1; i >= 0; i--) {
if(ph[i].p_type == PT_LOAD && ph[i].p_memsz) {
uintptr_t prepad = ph[i].p_vaddr % RISCV_PGSIZE;
uintptr_t vaddr = ph[i].p_vaddr + bias;
if (vaddr + ph[i].p_memsz > info->brk_min)
info->brk_min = vaddr + ph[i].p_memsz;
int flags2 = flags | (prepad ? MAP_POPULATE : 0);
if (__do_mmap(vaddr - prepad, ph[i].p_filesz + prepad, -1, flags2, file, ph[i].p_offset - prepad) != vaddr - prepad)
goto fail;
memset((void*)vaddr - prepad, 0, prepad);
size_t mapped = ROUNDUP(ph[i].p_filesz + prepad, RISCV_PGSIZE) - prepad;
if (ph[i].p_memsz > mapped)
if (__do_mmap(vaddr + mapped, ph[i].p_memsz - mapped, -1, flags|MAP_ANONYMOUS, 0, 0) != vaddr + mapped)
goto fail;
}
}
file_decref(file); file_decref(file);
return; return;

8
pk/elf.h

@ -12,6 +12,14 @@
#define IS_ELF32(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 1) #define IS_ELF32(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 1)
#define IS_ELF64(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 2) #define IS_ELF64(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 2)
#ifdef __riscv64
# define Elf_Ehdr Elf64_Ehdr
# define Elf_Phdr Elf64_Phdr
#else
# define Elf_Ehdr Elf32_Ehdr
# define Elf_Phdr Elf32_Phdr
#endif
#define ET_EXEC 2 #define ET_EXEC 2
#define ET_DYN 3 #define ET_DYN 3

10
pk/file.c

@ -1,11 +1,13 @@
// See LICENSE for license details. // See LICENSE for license details.
#include <string.h>
#include <errno.h>
#include "file.h" #include "file.h"
#include "pk.h" #include "atomic.h"
#include "mmap.h"
#include "frontend.h" #include "frontend.h"
#include "vm.h" #include "syscall.h"
#include "pk.h"
#include <string.h>
#include <errno.h>
#define MAX_FDS 128 #define MAX_FDS 128
static file_t* fds[MAX_FDS]; static file_t* fds[MAX_FDS];

1
pk/file.h

@ -6,7 +6,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <stdint.h> #include <stdint.h>
#include "atomic.h"
typedef struct file typedef struct file
{ {

12
pk/frontend.h

@ -6,18 +6,6 @@
#include <stdint.h> #include <stdint.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifdef __riscv64
# define TOHOST_CMD(dev, cmd, payload) \
(((uint64_t)(dev) << 56) | ((uint64_t)(cmd) << 48) | (uint64_t)(payload))
#else
# define TOHOST_CMD(dev, cmd, payload) ({ \
if ((dev) || (cmd)) __builtin_trap(); \
(payload); })
#endif
#define FROMHOST_DEV(fromhost_value) ((uint64_t)(fromhost_value) >> 56)
#define FROMHOST_CMD(fromhost_value) ((uint64_t)(fromhost_value) << 8 >> 56)
#define FROMHOST_DATA(fromhost_value) ((uint64_t)(fromhost_value) << 16 >> 16)
void shutdown(int) __attribute__((noreturn)); void shutdown(int) __attribute__((noreturn));
long frontend_syscall(long n, long a0, long a1, long a2, long a3, long a4, long a5, long a6); long frontend_syscall(long n, long a0, long a1, long a2, long a3, long a4, long a5, long a6);

8
pk/handlers.c

@ -3,7 +3,7 @@
#include "pk.h" #include "pk.h"
#include "config.h" #include "config.h"
#include "syscall.h" #include "syscall.h"
#include "vm.h" #include "mmap.h"
static void handle_illegal_instruction(trapframe_t* tf) static void handle_illegal_instruction(trapframe_t* tf)
{ {
@ -31,7 +31,7 @@ static void handle_misaligned_fetch(trapframe_t* tf)
panic("Misaligned instruction access!"); panic("Misaligned instruction access!");
} }
void handle_misaligned_store(trapframe_t* tf) static void handle_misaligned_store(trapframe_t* tf)
{ {
dump_tf(tf); dump_tf(tf);
panic("Misaligned AMO!"); panic("Misaligned AMO!");
@ -50,13 +50,13 @@ static void handle_fault_fetch(trapframe_t* tf)
segfault(tf, tf->badvaddr, "fetch"); segfault(tf, tf->badvaddr, "fetch");
} }
void handle_fault_load(trapframe_t* tf) static void handle_fault_load(trapframe_t* tf)
{ {
if (handle_page_fault(tf->badvaddr, PROT_READ) != 0) if (handle_page_fault(tf->badvaddr, PROT_READ) != 0)
segfault(tf, tf->badvaddr, "load"); segfault(tf, tf->badvaddr, "load");
} }
void handle_fault_store(trapframe_t* tf) static void handle_fault_store(trapframe_t* tf)
{ {
if (handle_page_fault(tf->badvaddr, PROT_WRITE) != 0) if (handle_page_fault(tf->badvaddr, PROT_WRITE) != 0)
segfault(tf, tf->badvaddr, "store"); segfault(tf, tf->badvaddr, "store");

82
pk/init.c

@ -1,82 +0,0 @@
// See LICENSE for license details.
#include "pk.h"
#include "boot.h"
#include "file.h"
#include "vm.h"
#include "frontend.h"
#include "elf.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
elf_info current;
int have_vm = 1; // unless -p flag is given
int uarch_counters_enabled;
long uarch_counters[NUM_COUNTERS];
char* uarch_counter_names[NUM_COUNTERS];
void init_tf(trapframe_t* tf, long pc, long sp)
{
memset(tf, 0, sizeof(*tf));
tf->status = (read_csr(sstatus) &~ SSTATUS_SPP &~ SSTATUS_SIE) | SSTATUS_SPIE;
tf->gpr[2] = sp;
tf->epc = pc;
}
static void handle_option(const char* s)
{
switch (s[1])
{
case 's': // print cycle count upon termination
current.t0 = 1;
break;
case 'c': // print uarch counters upon termination
// If your HW doesn't support uarch counters, then don't use this flag!
uarch_counters_enabled = 1;
break;
default:
panic("unrecognized option: `%c'", s[1]);
break;
}
}
#define MAX_ARGS 64
typedef union {
uint64_t buf[MAX_ARGS];
char* argv[MAX_ARGS];
} arg_buf;
static size_t parse_args(arg_buf* args)
{
long r = frontend_syscall(SYS_getmainvars, (uintptr_t)args, sizeof(*args), 0, 0, 0, 0, 0);
kassert(r == 0);
uint64_t* pk_argv = &args->buf[1];
// pk_argv[0] is the proxy kernel itself. skip it and any flags.
size_t pk_argc = args->buf[0], arg = 1;
for ( ; arg < pk_argc && *(char*)(uintptr_t)pk_argv[arg] == '-'; arg++)
handle_option((const char*)(uintptr_t)pk_argv[arg]);
for (size_t i = 0; arg + i < pk_argc; i++)
args->argv[i] = (char*)(uintptr_t)pk_argv[arg + i];
return pk_argc - arg;
}
void boot_loader()
{
arg_buf args;
size_t argc = parse_args(&args);
if (!argc)
panic("tell me what ELF to load!");
// load program named by argv[0]
long phdrs[128];
current.phdr = (uintptr_t)phdrs;
current.phdr_size = sizeof(phdrs);
load_elf(args.argv[0], &current);
run_loaded_program(argc, args.argv);
}

186
pk/vm.c → pk/mmap.c

@ -1,8 +1,8 @@
#include "vm.h" #include "mmap.h"
#include "file.h"
#include "atomic.h" #include "atomic.h"
#include "pk.h" #include "pk.h"
#include "boot.h" #include "boot.h"
#include "bits.h"
#include "mtrap.h" #include "mtrap.h"
#include <stdint.h> #include <stdint.h>
#include <errno.h> #include <errno.h>
@ -17,14 +17,15 @@ typedef struct {
} vmr_t; } vmr_t;
#define MAX_VMR (RISCV_PGSIZE / sizeof(vmr_t)) #define MAX_VMR (RISCV_PGSIZE / sizeof(vmr_t))
spinlock_t vm_lock = SPINLOCK_INIT; static spinlock_t vm_lock = SPINLOCK_INIT;
static vmr_t* vmrs; static vmr_t* vmrs;
pte_t* root_page_table;
static uintptr_t first_free_page; static uintptr_t first_free_page;
static size_t next_free_page; static size_t next_free_page;
static size_t free_pages; static size_t free_pages;
int have_vm = 1; // unless -p flag is given
static uintptr_t __page_alloc() static uintptr_t __page_alloc()
{ {
kassert(next_free_page != free_pages); kassert(next_free_page != free_pages);
@ -73,41 +74,6 @@ static size_t pte_ppn(pte_t pte)
return pte >> PTE_PPN_SHIFT; return pte >> PTE_PPN_SHIFT;
} }
static pte_t ptd_create(uintptr_t ppn)
{
return (ppn << PTE_PPN_SHIFT) | PTE_V | PTE_TYPE_TABLE;
}
static inline pte_t pte_create(uintptr_t ppn, int prot, int user)
{
pte_t pte = (ppn << PTE_PPN_SHIFT) | PTE_V;
prot &= PROT_READ|PROT_WRITE|PROT_EXEC;
if (user) {
switch (prot) {
case PROT_NONE: pte |= PTE_TYPE_SR; break;
case PROT_READ: pte |= PTE_TYPE_UR_SR; break;
case PROT_WRITE: pte |= PTE_TYPE_URW_SRW; break;
case PROT_EXEC: pte |= PTE_TYPE_URX_SRX; break;
case PROT_READ|PROT_WRITE: pte |= PTE_TYPE_URW_SRW; break;
case PROT_READ|PROT_EXEC: pte |= PTE_TYPE_URX_SRX; break;
case PROT_WRITE|PROT_EXEC: pte |= PTE_TYPE_URWX_SRWX; break;
case PROT_READ|PROT_WRITE|PROT_EXEC: pte |= PTE_TYPE_URWX_SRWX; break;
}
} else {
switch (prot) {
case PROT_NONE: kassert(0); break;
case PROT_READ: pte |= PTE_TYPE_SR; break;
case PROT_WRITE: pte |= PTE_TYPE_SRW; break;
case PROT_EXEC: pte |= PTE_TYPE_SRX; break;
case PROT_READ|PROT_WRITE: pte |= PTE_TYPE_SRW; break;
case PROT_READ|PROT_EXEC: pte |= PTE_TYPE_SRX; break;
case PROT_WRITE|PROT_EXEC: pte |= PTE_TYPE_SRWX; break;
case PROT_READ|PROT_WRITE|PROT_EXEC: pte |= PTE_TYPE_SRWX; break;
}
}
return pte;
}
static uintptr_t ppn(uintptr_t addr) static uintptr_t ppn(uintptr_t addr)
{ {
return addr >> RISCV_PGSHIFT; return addr >> RISCV_PGSHIFT;
@ -119,27 +85,19 @@ static size_t pt_idx(uintptr_t addr, int level)
return idx & ((1 << RISCV_PGLEVEL_BITS) - 1); return idx & ((1 << RISCV_PGLEVEL_BITS) - 1);
} }
static void __maybe_create_root_page_table() static pte_t* __maybe_create_root_page_table()
{ {
if (root_page_table) if (!root_page_table)
return; root_page_table = (void*)__page_alloc();
root_page_table = (void*)__page_alloc(); return root_page_table;
if (have_vm)
write_csr(sptbr, (uintptr_t)root_page_table >> RISCV_PGSHIFT);
} }
static pte_t* __walk_internal(uintptr_t addr, int create) static pte_t* __walk_internal(uintptr_t addr, int create)
{ {
const size_t pte_per_page = RISCV_PGSIZE/sizeof(void*); pte_t* t = __maybe_create_root_page_table();
__maybe_create_root_page_table(); for (int i = (VA_BITS - RISCV_PGSHIFT) / RISCV_PGLEVEL_BITS - 1; i > 0; i--) {
pte_t* t = root_page_table;
unsigned levels = (VA_BITS - RISCV_PGSHIFT) / RISCV_PGLEVEL_BITS;
for (unsigned i = levels-1; i > 0; i--)
{
size_t idx = pt_idx(addr, i); size_t idx = pt_idx(addr, i);
if (!(t[idx] & PTE_V)) if (!(t[idx] & PTE_V)) {
{
if (!create) if (!create)
return 0; return 0;
uintptr_t page = __page_alloc(); uintptr_t page = __page_alloc();
@ -185,11 +143,40 @@ static uintptr_t __vm_alloc(size_t npage)
return 0; return 0;
} }
static inline pte_t prot_to_type(int prot, int user)
{
prot &= PROT_READ|PROT_WRITE|PROT_EXEC;
if (user) {
switch (prot) {
case PROT_NONE: return PTE_TYPE_SR;
case PROT_READ: return PTE_TYPE_UR_SR;
case PROT_WRITE: return PTE_TYPE_URW_SRW;
case PROT_EXEC: return PTE_TYPE_URX_SRX;
case PROT_READ|PROT_WRITE: return PTE_TYPE_URW_SRW;
case PROT_READ|PROT_EXEC: return PTE_TYPE_URX_SRX;
case PROT_WRITE|PROT_EXEC: return PTE_TYPE_URWX_SRWX;
case PROT_READ|PROT_WRITE|PROT_EXEC: return PTE_TYPE_URWX_SRWX;
}
} else {
switch (prot) {
case PROT_NONE:
case PROT_READ: return PTE_TYPE_SR;
case PROT_WRITE: return PTE_TYPE_SRW;
case PROT_EXEC: return PTE_TYPE_SRX;
case PROT_READ|PROT_WRITE: return PTE_TYPE_SRW;
case PROT_READ|PROT_EXEC: return PTE_TYPE_SRX;
case PROT_WRITE|PROT_EXEC: return PTE_TYPE_SRWX;
case PROT_READ|PROT_WRITE|PROT_EXEC: return PTE_TYPE_SRWX;
}
}
__builtin_unreachable();
}
int __valid_user_range(uintptr_t vaddr, size_t len) int __valid_user_range(uintptr_t vaddr, size_t len)
{ {
if (vaddr + len < vaddr) if (vaddr + len < vaddr)
return 0; return 0;
return vaddr >= current.first_free_paddr && vaddr + len <= current.mmap_max; return vaddr >= first_free_paddr && vaddr + len <= current.mmap_max;
} }
static int __handle_page_fault(uintptr_t vaddr, int prot) static int __handle_page_fault(uintptr_t vaddr, int prot)
@ -206,7 +193,7 @@ static int __handle_page_fault(uintptr_t vaddr, int prot)
uintptr_t ppn = vpn; uintptr_t ppn = vpn;
vmr_t* v = (vmr_t*)*pte; vmr_t* v = (vmr_t*)*pte;
*pte = pte_create(ppn, PROT_READ|PROT_WRITE, 0); *pte = pte_create(ppn, prot_to_type(PROT_READ|PROT_WRITE, 0));
flush_tlb(); flush_tlb();
if (v->file) if (v->file)
{ {
@ -219,10 +206,10 @@ static int __handle_page_fault(uintptr_t vaddr, int prot)
else else
memset((void*)vaddr, 0, RISCV_PGSIZE); memset((void*)vaddr, 0, RISCV_PGSIZE);
__vmr_decref(v, 1); __vmr_decref(v, 1);
*pte = pte_create(ppn, v->prot, 1); *pte = pte_create(ppn, prot_to_type(v->prot, 1));
} }
pte_t perms = pte_create(0, prot, 1); pte_t perms = pte_create(0, prot_to_type(prot, 1));
if ((*pte & perms) != perms) if ((*pte & perms) != perms)
return -1; return -1;
@ -384,7 +371,7 @@ uintptr_t do_mprotect(uintptr_t addr, size_t length, int prot)
res = -EACCES; res = -EACCES;
break; break;
} }
*pte = pte_create(pte_ppn(*pte), prot, 1); *pte = pte_create(pte_ppn(*pte), prot_to_type(prot, 1));
} }
} }
spinlock_unlock(&vm_lock); spinlock_unlock(&vm_lock);
@ -395,11 +382,12 @@ uintptr_t do_mprotect(uintptr_t addr, size_t length, int prot)
void __map_kernel_range(uintptr_t vaddr, uintptr_t paddr, size_t len, int prot) void __map_kernel_range(uintptr_t vaddr, uintptr_t paddr, size_t len, int prot)
{ {
uintptr_t n = ROUNDUP(len, RISCV_PGSIZE) / RISCV_PGSIZE; uintptr_t n = ROUNDUP(len, RISCV_PGSIZE) / RISCV_PGSIZE;
uintptr_t offset = paddr - vaddr;
for (uintptr_t a = vaddr, i = 0; i < n; i++, a += RISCV_PGSIZE) for (uintptr_t a = vaddr, i = 0; i < n; i++, a += RISCV_PGSIZE)
{ {
pte_t* pte = __walk_create(a); pte_t* pte = __walk_create(a);
kassert(pte); kassert(pte);
*pte = pte_create((a - vaddr + paddr) >> RISCV_PGSHIFT, prot, 0); *pte = pte_create((a + offset) >> RISCV_PGSHIFT, prot_to_type(prot, 0));
} }
} }
@ -415,85 +403,23 @@ void populate_mapping(const void* start, size_t size, int prot)
} }
} }
static uintptr_t sbi_top_paddr() uintptr_t pk_vm_init()
{
extern char _end;
return ROUNDUP((uintptr_t)&_end, RISCV_PGSIZE);
}
#define first_free_paddr() (sbi_top_paddr() + num_harts * RISCV_PGSIZE)
void vm_init()
{ {
mem_size = mem_size / SUPERPAGE_SIZE * SUPERPAGE_SIZE;
current.first_free_paddr = first_free_paddr();
size_t mem_pages = mem_size >> RISCV_PGSHIFT; size_t mem_pages = mem_size >> RISCV_PGSHIFT;
free_pages = MAX(8, mem_pages >> (RISCV_PGLEVEL_BITS-1)); free_pages = MAX(8, mem_pages >> (RISCV_PGLEVEL_BITS-1));
first_free_page = mem_size - free_pages * RISCV_PGSIZE; first_free_page = mem_size - free_pages * RISCV_PGSIZE;
current.mmap_max = current.brk_max = first_free_page;
}
void supervisor_vm_init() __map_kernel_range(0, 0, first_free_paddr, PROT_READ|PROT_WRITE|PROT_EXEC);
{ __map_kernel_range(first_free_page, first_free_page, free_pages * RISCV_PGSIZE, PROT_READ|PROT_WRITE);
uintptr_t highest_va = -current.first_free_paddr;
mem_size = MIN(mem_size, highest_va - current.first_user_vaddr) & -SUPERPAGE_SIZE;
pte_t* sbi_pt = (pte_t*)(current.first_vaddr_after_user + current.bias);
memset(sbi_pt, 0, RISCV_PGSIZE);
pte_t* middle_pt = (void*)sbi_pt + RISCV_PGSIZE;
#ifndef __riscv64
size_t num_middle_pts = 1;
pte_t* root_pt = middle_pt;
memset(root_pt, 0, RISCV_PGSIZE);
#else
size_t num_middle_pts = (-current.first_user_vaddr - 1) / MEGAPAGE_SIZE + 1;
pte_t* root_pt = (void*)middle_pt + num_middle_pts * RISCV_PGSIZE;
memset(middle_pt, 0, (num_middle_pts + 1) * RISCV_PGSIZE);
for (size_t i = 0; i < num_middle_pts; i++)
root_pt[(1<<RISCV_PGLEVEL_BITS)-num_middle_pts+i] = ptd_create(((uintptr_t)middle_pt >> RISCV_PGSHIFT) + i);
#endif
for (uintptr_t vaddr = current.first_user_vaddr, paddr = vaddr + current.bias, end = current.first_vaddr_after_user;
paddr < mem_size; vaddr += SUPERPAGE_SIZE, paddr += SUPERPAGE_SIZE) {
int l2_shift = RISCV_PGLEVEL_BITS + RISCV_PGSHIFT;
size_t l2_idx = (current.first_user_vaddr >> l2_shift) & ((1 << RISCV_PGLEVEL_BITS)-1);
l2_idx += ((vaddr - current.first_user_vaddr) >> l2_shift);
middle_pt[l2_idx] = pte_create(paddr >> RISCV_PGSHIFT, PROT_READ|PROT_WRITE|PROT_EXEC, 0);
}
current.first_vaddr_after_user += (void*)root_pt + RISCV_PGSIZE - (void*)sbi_pt;
// map SBI at top of vaddr space
uintptr_t num_sbi_pages = sbi_top_paddr() / RISCV_PGSIZE;
for (uintptr_t i = 0; i < num_sbi_pages; i++) {
uintptr_t idx = (1 << RISCV_PGLEVEL_BITS) - num_sbi_pages + i;
sbi_pt[idx] = pte_create(i, PROT_READ|PROT_EXEC, 0);
}
pte_t* sbi_pte = middle_pt + ((num_middle_pts << RISCV_PGLEVEL_BITS)-1);
kassert(!*sbi_pte);
*sbi_pte = ptd_create((uintptr_t)sbi_pt >> RISCV_PGSHIFT);
// disable our allocator
kassert(next_free_page == 0);
free_pages = 0;
mb();
root_page_table = root_pt;
write_csr(sptbr, (uintptr_t)root_pt >> RISCV_PGSHIFT);
}
uintptr_t pk_vm_init()
{
// keep user addresses positive // keep user addresses positive
current.mmap_max = MIN(current.mmap_max, (uintptr_t)INTPTR_MAX + 1); current.mmap_max = MIN(first_free_page, (uintptr_t)INTPTR_MAX + 1);
current.brk_max = current.mmap_max;
__map_kernel_range(0, 0, current.first_free_paddr, PROT_READ|PROT_WRITE|PROT_EXEC);
__map_kernel_range(first_free_page, first_free_page, free_pages * RISCV_PGSIZE, PROT_READ|PROT_WRITE);
size_t stack_size = RISCV_PGSIZE * CLAMP(mem_size/(RISCV_PGSIZE*32), 1, 256); size_t stack_size = RISCV_PGSIZE * CLAMP(mem_size/(RISCV_PGSIZE*32), 1, 256);
current.stack_bottom = __do_mmap(current.mmap_max - stack_size, stack_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0); size_t stack_bottom = __do_mmap(current.mmap_max - stack_size, stack_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
current.stack_top = current.stack_bottom + stack_size; kassert(stack_bottom != (uintptr_t)-1);
kassert(current.stack_bottom != (uintptr_t)-1); current.stack_top = stack_bottom + stack_size;
uintptr_t kernel_stack_top = __page_alloc() + RISCV_PGSIZE; uintptr_t kernel_stack_top = __page_alloc() + RISCV_PGSIZE;
return kernel_stack_top; return kernel_stack_top;

31
pk/vm.h → pk/mmap.h

@ -1,21 +1,11 @@
#ifndef _VM_H #ifndef _MMAP_H
#define _VM_H #define _MMAP_H
#include "vm.h"
#include "syscall.h" #include "syscall.h"
#include "encoding.h"
#include "file.h" #include "file.h"
#include <string.h> #include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
#define SUPERPAGE_SIZE ((uintptr_t)(RISCV_PGSIZE << RISCV_PGLEVEL_BITS))
#ifdef __riscv64
# define VM_CHOICE VM_SV39
# define VA_BITS 39
# define MEGAPAGE_SIZE (SUPERPAGE_SIZE << RISCV_PGLEVEL_BITS)
#else
# define VM_CHOICE VM_SV32
# define VA_BITS 32
#endif
#define PROT_NONE 0 #define PROT_NONE 0
#define PROT_READ 1 #define PROT_READ 1
@ -28,8 +18,7 @@
#define MAP_POPULATE 0x8000 #define MAP_POPULATE 0x8000
#define MREMAP_FIXED 0x2 #define MREMAP_FIXED 0x2
void vm_init(); extern int have_vm;
void supervisor_vm_init();
uintptr_t pk_vm_init(); uintptr_t pk_vm_init();
int handle_page_fault(uintptr_t vaddr, int prot); int handle_page_fault(uintptr_t vaddr, int prot);
void populate_mapping(const void* start, size_t size, int prot); void populate_mapping(const void* start, size_t size, int prot);
@ -42,12 +31,4 @@ uintptr_t do_mremap(uintptr_t addr, size_t old_size, size_t new_size, int flags)
uintptr_t do_mprotect(uintptr_t addr, size_t length, int prot); uintptr_t do_mprotect(uintptr_t addr, size_t length, int prot);
uintptr_t do_brk(uintptr_t addr); uintptr_t do_brk(uintptr_t addr);
typedef uintptr_t pte_t;
extern pte_t* root_page_table;
static inline void flush_tlb()
{
asm volatile("sfence.vm");
}
#endif #endif

10
pk/pk.ac

@ -2,13 +2,3 @@ AC_ARG_ENABLE([vm], AS_HELP_STRING([--disable-vm], [Disable virtual memory]))
AS_IF([test "x$enable_vm" != "xno"], [ AS_IF([test "x$enable_vm" != "xno"], [
AC_DEFINE([PK_ENABLE_VM],,[Define if virtual memory support is enabled]) AC_DEFINE([PK_ENABLE_VM],,[Define if virtual memory support is enabled])
]) ])
AC_ARG_ENABLE([vm], AS_HELP_STRING([--disable-logo], [Disable boot logo]))
AS_IF([test "x$enable_logo" != "xno"], [
AC_DEFINE([PK_ENABLE_LOGO],,[Define if the RISC-V logo is to be displayed])
])
AC_ARG_ENABLE([fp-emulation], AS_HELP_STRING([--disable-fp-emulation], [Disable floating-point emulation]))
AS_IF([test "x$enable_fp_emulation" != "xno"], [
AC_DEFINE([PK_ENABLE_FP_EMULATION],,[Define if floating-point emulation is enabled])
])

95
pk/pk.c

@ -1,24 +1,66 @@
#include "pk.h" #include "pk.h"
#include "mmap.h"
#include "boot.h" #include "boot.h"
#include "vm.h"
#include "elf.h" #include "elf.h"
#include "mtrap.h"
#include "frontend.h"
void run_loaded_program(size_t argc, char** argv) elf_info current;
int uarch_counters_enabled;
long uarch_counters[NUM_COUNTERS];
char* uarch_counter_names[NUM_COUNTERS];
static void handle_option(const char* s)
{ {
if (current.is_supervisor) switch (s[1])
panic("pk can't run kernel binaries; try using bbl instead"); {
case 's': // print cycle count upon termination
current.t0 = 1;
break;
uintptr_t kernel_stack_top = pk_vm_init(); case 'c': // print uarch counters upon termination
// If your HW doesn't support uarch counters, then don't use this flag!
uarch_counters_enabled = 1;
break;
extern char trap_entry; default:
write_csr(stvec, &trap_entry); panic("unrecognized option: `%c'", s[1]);
write_csr(sscratch, 0); break;
clear_csr(sie, SIP_STIP | SIP_SSIP); }
}
// enter supervisor mode #define MAX_ARGS 64
prepare_supervisor_mode(); typedef union {
asm volatile("la t0, 1f; csrw mepc, t0; eret; 1:" ::: "t0"); uint64_t buf[MAX_ARGS];
char* argv[MAX_ARGS];
} arg_buf;
static size_t parse_args(arg_buf* args)
{
long r = frontend_syscall(SYS_getmainvars, (uintptr_t)args, sizeof(*args), 0, 0, 0, 0, 0);
kassert(r == 0);
uint64_t* pk_argv = &args->buf[1];
// pk_argv[0] is the proxy kernel itself. skip it and any flags.
size_t pk_argc = args->buf[0], arg = 1;
for ( ; arg < pk_argc && *(char*)(uintptr_t)pk_argv[arg] == '-'; arg++)
handle_option((const char*)(uintptr_t)pk_argv[arg]);
for (size_t i = 0; arg + i < pk_argc; i++)
args->argv[i] = (char*)(uintptr_t)pk_argv[arg + i];
return pk_argc - arg;
}
static void init_tf(trapframe_t* tf, long pc, long sp)
{
memset(tf, 0, sizeof(*tf));
tf->status = (read_csr(sstatus) &~ SSTATUS_SPP &~ SSTATUS_SIE) | SSTATUS_SPIE;
tf->gpr[2] = sp;
tf->epc = pc;
}
static void run_loaded_program(size_t argc, char** argv, uintptr_t kstack_top)
{
// copy phdrs to user stack // copy phdrs to user stack
size_t stack_top = current.stack_top - current.phdr_size; size_t stack_top = current.stack_top - current.phdr_size;
memcpy((void*)stack_top, (void*)current.phdr, current.phdr_size); memcpy((void*)stack_top, (void*)current.phdr, current.phdr_size);
@ -94,10 +136,37 @@ void run_loaded_program(size_t argc, char** argv)
trapframe_t tf; trapframe_t tf;
init_tf(&tf, current.entry, stack_top); init_tf(&tf, current.entry, stack_top);
__clear_cache(0, 0); __clear_cache(0, 0);
write_csr(sscratch, kernel_stack_top); write_csr(sscratch, kstack_top);
start_user(&tf); start_user(&tf);
} }
static void rest_of_boot_loader(uintptr_t kstack_top)
{
arg_buf args;
size_t argc = parse_args(&args);
if (!argc)
panic("tell me what ELF to load!");
// load program named by argv[0]
long phdrs[128];
current.phdr = (uintptr_t)phdrs;
current.phdr_size = sizeof(phdrs);
load_elf(args.argv[0], &current);
run_loaded_program(argc, args.argv, kstack_top);
}
void boot_loader()
{
extern char trap_entry;
write_csr(stvec, &trap_entry);
write_csr(sscratch, 0);
write_csr(sie, 0);
file_init();
enter_supervisor_mode(rest_of_boot_loader, pk_vm_init());
}
void boot_other_hart() void boot_other_hart()
{ {
// stall all harts besides hart 0 // stall all harts besides hart 0

17
pk/pk.h

@ -24,30 +24,18 @@ typedef struct
#define kassert(cond) do { if(!(cond)) kassert_fail(""#cond); } while(0) #define kassert(cond) do { if(!(cond)) kassert_fail(""#cond); } while(0)
void do_panic(const char* s, ...) __attribute__((noreturn)); void do_panic(const char* s, ...) __attribute__((noreturn));
void kassert_fail(const char* s) __attribute__((noreturn)); void kassert_fail(const char* s) __attribute__((noreturn));
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
extern int have_vm;
void printk(const char* s, ...); void printk(const char* s, ...);
void printm(const char* s, ...); void printm(const char* s, ...);
int vsnprintf(char* out, size_t n, const char* s, va_list vl); int vsnprintf(char* out, size_t n, const char* s, va_list vl);
int snprintf(char* out, size_t n, const char* s, ...); int snprintf(char* out, size_t n, const char* s, ...);
void init_tf(trapframe_t*, long pc, long sp);
void start_user(trapframe_t* tf) __attribute__((noreturn)); void start_user(trapframe_t* tf) __attribute__((noreturn));
void dump_tf(trapframe_t*); void dump_tf(trapframe_t*);
void unhandled_trap(trapframe_t*);
void handle_misaligned_load(trapframe_t*);
void handle_misaligned_store(trapframe_t*);
void handle_fault_load(trapframe_t*);
void handle_fault_store(trapframe_t*);
static inline int insn_len(long insn) static inline int insn_len(long insn)
{ {
return (insn & 0x3) < 0x3 ? 2 : 4; return (insn & 0x3) < 0x3 ? 2 : 4;
@ -60,11 +48,6 @@ extern int uarch_counters_enabled;
extern long uarch_counters[NUM_COUNTERS]; extern long uarch_counters[NUM_COUNTERS];
extern char* uarch_counter_names[NUM_COUNTERS]; extern char* uarch_counter_names[NUM_COUNTERS];
static inline void wfi()
{
asm volatile ("wfi" ::: "memory");
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

5
pk/pk.ld → pk/pk.lds

@ -86,10 +86,5 @@ SECTIONS
*(COMMON) *(COMMON)
} }
.sbi :
{
sbi.o(.sbi)
}
_end = .; _end = .;
} }

30
pk/pk.mk.in

@ -1,52 +1,30 @@
pk_subproject_deps = \ pk_subproject_deps = \
util \
softfloat \ softfloat \
machine \
pk_hdrs = \ pk_hdrs = \
atomic.h \
bits.h \
boot.h \ boot.h \
elf.h \ elf.h \
emulation.h \
encoding.h \
file.h \ file.h \
fp_emulation.h \
frontend.h \ frontend.h \
mcall.h \ mmap.h \
mtrap.h \
pk.h \ pk.h \
sbi.h \
syscall.h \ syscall.h \
unprivileged_memory.h \
vm.h \
pk_c_srcs = \ pk_c_srcs = \
snprintf.c \
mtrap.c \
minit.c \
emulation.c \
fp_emulation.c \
sbi_impl.c \
init.c \
file.c \ file.c \
syscall.c \ syscall.c \
handlers.c \ handlers.c \
frontend.c \ frontend.c \
elf.c \ elf.c \
console.c \ console.c \
vm.c \ mmap.c \
string.c \
logo.c \
configstring.c \
pk_asm_srcs = \ pk_asm_srcs = \
mentry.S \
entry.S \ entry.S \
fp_asm.S \
sbi_entry.S \
sbi.S \
pk_test_srcs = pk_test_srcs =
pk_install_prog_srcs = \ pk_install_prog_srcs = \
pk.c \ pk.c \
bbl.c \

2
pk/syscall.c

@ -4,7 +4,7 @@
#include "pk.h" #include "pk.h"
#include "file.h" #include "file.h"
#include "frontend.h" #include "frontend.h"
#include "vm.h" #include "mmap.h"
#include "boot.h" #include "boot.h"
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>

0
pk/snprintf.c → util/snprintf.c

0
pk/string.c → util/string.c

0
util/util.ac

9
util/util.mk.in

@ -0,0 +1,9 @@
util_subproject_deps = \
util_hdrs = \
util_c_srcs = \
snprintf.c \
string.c \
util_asm_srcs = \
Loading…
Cancel
Save