diff options
author | Andrew Waterman <waterman@cs.berkeley.edu> | 2016-03-09 23:58:17 -0800 |
---|---|---|
committer | Andrew Waterman <waterman@cs.berkeley.edu> | 2016-03-09 23:58:17 -0800 |
commit | b94c7a4b07f96f24ae7411780abf874416549f7b (patch) | |
tree | b94ca015e49392f52e5abf1209ee184fcf874db4 | |
parent | f5a96732cb81571a3ba6b081b8556187d564f678 (diff) | |
download | riscv-pk-b94c7a4b07f96f24ae7411780abf874416549f7b.zip riscv-pk-b94c7a4b07f96f24ae7411780abf874416549f7b.tar.gz riscv-pk-b94c7a4b07f96f24ae7411780abf874416549f7b.tar.bz2 |
Refactor pk, bbl, machine into separate libraries
Yuck.
-rw-r--r-- | Makefile.in | 7 | ||||
-rw-r--r-- | bbl/bbl.ac | 8 | ||||
-rw-r--r-- | bbl/bbl.c | 76 | ||||
-rw-r--r-- | bbl/bbl.h | 23 | ||||
-rw-r--r-- | bbl/bbl.lds | 100 | ||||
-rw-r--r-- | bbl/bbl.mk.in | 22 | ||||
-rw-r--r-- | bbl/kernel_elf.c | 54 | ||||
-rw-r--r-- | bbl/logo.c (renamed from pk/logo.c) | 4 | ||||
-rw-r--r-- | bbl/payload.S | 7 | ||||
-rw-r--r-- | config.h.in | 12 | ||||
-rwxr-xr-x | configure | 223 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | dummy_payload/dummy_payload.ac | 0 | ||||
-rw-r--r-- | dummy_payload/dummy_payload.c | 21 | ||||
-rw-r--r-- | dummy_payload/dummy_payload.lds | 3 | ||||
-rw-r--r-- | dummy_payload/dummy_payload.mk.in | 13 | ||||
l--------- | dummy_payload/dummy_sbi.S | 1 | ||||
-rw-r--r-- | machine/atomic.h (renamed from pk/atomic.h) | 2 | ||||
-rw-r--r-- | machine/bits.h | 33 | ||||
-rw-r--r-- | machine/configstring.c (renamed from pk/configstring.c) | 0 | ||||
-rw-r--r-- | machine/emulation.c (renamed from pk/emulation.c) | 0 | ||||
-rw-r--r-- | machine/emulation.h (renamed from pk/emulation.h) | 0 | ||||
-rw-r--r-- | machine/encoding.h (renamed from pk/encoding.h) | 0 | ||||
-rw-r--r-- | machine/fp_asm.S (renamed from pk/fp_asm.S) | 0 | ||||
-rw-r--r-- | machine/fp_emulation.c (renamed from pk/fp_emulation.c) | 0 | ||||
-rw-r--r-- | machine/fp_emulation.h (renamed from pk/fp_emulation.h) | 0 | ||||
-rw-r--r-- | machine/htif.h | 18 | ||||
-rw-r--r-- | machine/machine.ac | 4 | ||||
-rw-r--r-- | machine/machine.mk.in | 29 | ||||
-rw-r--r-- | machine/mcall.h (renamed from pk/mcall.h) | 4 | ||||
-rw-r--r-- | machine/mentry.S (renamed from pk/mentry.S) | 1 | ||||
-rw-r--r-- | machine/minit.c (renamed from pk/minit.c) | 38 | ||||
-rw-r--r-- | machine/mtrap.c (renamed from pk/mtrap.c) | 14 | ||||
-rw-r--r-- | machine/mtrap.h (renamed from pk/mtrap.h) | 20 | ||||
-rw-r--r-- | machine/sbi.S (renamed from pk/sbi.S) | 0 | ||||
-rw-r--r-- | machine/sbi.h (renamed from pk/sbi.h) | 0 | ||||
-rw-r--r-- | machine/sbi_entry.S (renamed from pk/sbi_entry.S) | 8 | ||||
-rw-r--r-- | machine/sbi_impl.c (renamed from pk/sbi_impl.c) | 3 | ||||
-rw-r--r-- | machine/unprivileged_memory.h (renamed from pk/unprivileged_memory.h) | 0 | ||||
-rw-r--r-- | machine/vm.h | 35 | ||||
-rw-r--r-- | pk/bbl.c | 36 | ||||
-rw-r--r-- | pk/bits.h | 45 | ||||
-rw-r--r-- | pk/boot.h | 10 | ||||
-rw-r--r-- | pk/elf.c | 137 | ||||
-rw-r--r-- | pk/elf.h | 8 | ||||
-rw-r--r-- | pk/file.c | 10 | ||||
-rw-r--r-- | pk/file.h | 1 | ||||
-rw-r--r-- | pk/frontend.h | 12 | ||||
-rw-r--r-- | pk/handlers.c | 8 | ||||
-rw-r--r-- | pk/init.c | 82 | ||||
-rw-r--r-- | pk/mmap.c (renamed from pk/vm.c) | 186 | ||||
-rw-r--r-- | pk/mmap.h (renamed from pk/vm.h) | 31 | ||||
-rw-r--r-- | pk/pk.ac | 10 | ||||
-rw-r--r-- | pk/pk.c | 95 | ||||
-rw-r--r-- | pk/pk.h | 17 | ||||
-rw-r--r-- | pk/pk.lds (renamed from pk/pk.ld) | 5 | ||||
-rw-r--r-- | pk/pk.mk.in | 30 | ||||
-rw-r--r-- | pk/syscall.c | 2 | ||||
-rw-r--r-- | util/snprintf.c (renamed from pk/snprintf.c) | 0 | ||||
-rw-r--r-- | util/string.c (renamed from pk/string.c) | 0 | ||||
-rw-r--r-- | util/util.ac | 0 | ||||
-rw-r--r-- | util/util.mk.in | 9 |
62 files changed, 960 insertions, 559 deletions
diff --git a/Makefile.in b/Makefile.in index 108d19d..8babada 100644 --- a/Makefile.in +++ b/Makefile.in @@ -35,6 +35,7 @@ default : all project_name := @PACKAGE_TARNAME@ src_dir := @srcdir@ scripts_dir := $(src_dir)/scripts +bbl_payload := @BBL_PAYLOAD@ # 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 @@ -83,7 +84,7 @@ VPATH := $(addprefix $(src_dir)/, $(sprojs_enabled)) # - CXXFLAGS : flags for C++ compiler (eg. -Wall,-g,-O3) CC := @CC@ -CFLAGS := @CFLAGS@ $(CFLAGS) +CFLAGS := @CFLAGS@ $(CFLAGS) -DBBL_PAYLOAD=\"$(bbl_payload)\" COMPILE := $(CC) -MMD -MP $(CFLAGS) \ $(sprojs_include) # Linker @@ -93,7 +94,7 @@ COMPILE := $(CC) -MMD -MP $(CFLAGS) \ LD := $(CC) LDFLAGS := @LDFLAGS@ -nostartfiles -nostdlib -static $(LDFLAGS) LIBS := @LIBS@ -LINK := $(LD) $(LDFLAGS) -T $(src_dir)/pk/pk.ld +LINK := $(LD) $(LDFLAGS) # Library creation @@ -258,7 +259,7 @@ $$($(2)_install_prog_objs) : %.o : %.c $(COMPILE) -c $$< $$($(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)_junk += \ diff --git a/bbl/bbl.ac b/bbl/bbl.ac new file mode 100644 index 0000000..51dcf01 --- /dev/null +++ b/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])]) diff --git a/bbl/bbl.c b/bbl/bbl.c new file mode 100644 index 0000000..cd52fc1 --- /dev/null +++ b/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); +} diff --git a/bbl/bbl.h b/bbl/bbl.h new file mode 100644 index 0000000..e9e1dab --- /dev/null +++ b/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 diff --git a/bbl/bbl.lds b/bbl/bbl.lds new file mode 100644 index 0000000..5ccdf22 --- /dev/null +++ b/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 = .; +} diff --git a/bbl/bbl.mk.in b/bbl/bbl.mk.in new file mode 100644 index 0000000..1bb4cd1 --- /dev/null +++ b/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 \ diff --git a/bbl/kernel_elf.c b/bbl/kernel_elf.c new file mode 100644 index 0000000..e22c35c --- /dev/null +++ b/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"); +} @@ -1,5 +1,5 @@ #include <string.h> -#include "file.h" +#include "mtrap.h" static const char logo[] = " vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n" @@ -28,5 +28,5 @@ static const char logo[] = void print_logo() { - file_write(stderr, logo, sizeof logo); + putstring(logo); } diff --git a/bbl/payload.S b/bbl/payload.S new file mode 100644 index 0000000..7ff1e58 --- /dev/null +++ b/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: diff --git a/config.h.in b/config.h.in index 3424ee6..bc6369e 100644 --- a/config.h.in +++ b/config.h.in @@ -1,5 +1,14 @@ /* 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. */ #undef PACKAGE_BUGREPORT @@ -35,3 +44,6 @@ /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS + +/* Define if subproject MCPPBS_SPROJ_NORM is enabled */ +#undef UTIL_ENABLED @@ -590,6 +590,7 @@ ac_subst_vars='LTLIBOBJS LIBOBJS subprojects_enabled subprojects +BBL_PAYLOAD EGREP GREP CPP @@ -667,6 +668,8 @@ enable_option_checking enable_stow enable_optional_subprojects enable_vm +enable_logo +with_payload enable_fp_emulation ' ac_precious_vars='build_alias @@ -1303,6 +1306,11 @@ Optional Features: --disable-logo Disable boot logo --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: CC C compiler command CFLAGS C compiler flags @@ -4046,9 +4054,53 @@ $as_echo "#define PK_ENABLE_VM /**/" >>confdefs.h 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 if test "x$enable_logo" != "xno"; then : @@ -4059,16 +4111,13 @@ $as_echo "#define PK_ENABLE_LOGO /**/" >>confdefs.h 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 : - - -$as_echo "#define PK_ENABLE_FP_EMULATION /**/" >>confdefs.h +# Check whether --with-payload was given. +if test "${with_payload+set}" = set; then : + withval=$with_payload; BBL_PAYLOAD=$with_payload +else + BBL_PAYLOAD=dummy_payload fi @@ -4076,6 +4125,7 @@ fi + # 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 @@ -4838,7 +5035,11 @@ for ac_config_target in $ac_config_targets do case $ac_config_target 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" ;; + "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" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; diff --git a/configure.ac b/configure.ac index 64ddc5f..6253228 100644 --- a/configure.ac +++ b/configure.ac @@ -81,7 +81,7 @@ AC_SUBST([LIBS], ["-lgcc"]) # The '*' suffix indicates an optional subproject. The '**' suffix # 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 diff --git a/dummy_payload/dummy_payload.ac b/dummy_payload/dummy_payload.ac new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/dummy_payload/dummy_payload.ac diff --git a/dummy_payload/dummy_payload.c b/dummy_payload/dummy_payload.c new file mode 100644 index 0000000..61ed59a --- /dev/null +++ b/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(); +} diff --git a/dummy_payload/dummy_payload.lds b/dummy_payload/dummy_payload.lds new file mode 100644 index 0000000..ee9410b --- /dev/null +++ b/dummy_payload/dummy_payload.lds @@ -0,0 +1,3 @@ +SECTIONS { + . = -0x80000000; +} diff --git a/dummy_payload/dummy_payload.mk.in b/dummy_payload/dummy_payload.mk.in new file mode 100644 index 0000000..b1d4ac7 --- /dev/null +++ b/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 \ diff --git a/dummy_payload/dummy_sbi.S b/dummy_payload/dummy_sbi.S new file mode 120000 index 0000000..2978a97 --- /dev/null +++ b/dummy_payload/dummy_sbi.S @@ -0,0 +1 @@ +../machine/sbi.S
\ No newline at end of file diff --git a/pk/atomic.h b/machine/atomic.h index e4610de..b23acae 100644 --- a/pk/atomic.h +++ b/machine/atomic.h @@ -6,7 +6,7 @@ #include "config.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 enable_irqrestore(flags) ((void) (flags)) diff --git a/machine/bits.h b/machine/bits.h new file mode 100644 index 0000000..72514ae --- /dev/null +++ b/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 diff --git a/pk/configstring.c b/machine/configstring.c index 847cd4d..847cd4d 100644 --- a/pk/configstring.c +++ b/machine/configstring.c diff --git a/pk/emulation.c b/machine/emulation.c index 5a66997..5a66997 100644 --- a/pk/emulation.c +++ b/machine/emulation.c diff --git a/pk/emulation.h b/machine/emulation.h index f1a71ec..f1a71ec 100644 --- a/pk/emulation.h +++ b/machine/emulation.h diff --git a/pk/encoding.h b/machine/encoding.h index f2fab36..f2fab36 100644 --- a/pk/encoding.h +++ b/machine/encoding.h diff --git a/pk/fp_asm.S b/machine/fp_asm.S index 4b8dce1..4b8dce1 100644 --- a/pk/fp_asm.S +++ b/machine/fp_asm.S diff --git a/pk/fp_emulation.c b/machine/fp_emulation.c index 536967f..536967f 100644 --- a/pk/fp_emulation.c +++ b/machine/fp_emulation.c diff --git a/pk/fp_emulation.h b/machine/fp_emulation.h index d2357b7..d2357b7 100644 --- a/pk/fp_emulation.h +++ b/machine/fp_emulation.h diff --git a/machine/htif.h b/machine/htif.h new file mode 100644 index 0000000..e66ad06 --- /dev/null +++ b/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 diff --git a/machine/machine.ac b/machine/machine.ac new file mode 100644 index 0000000..65acf04 --- /dev/null +++ b/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]) +]) diff --git a/machine/machine.mk.in b/machine/machine.mk.in new file mode 100644 index 0000000..a0b7ca9 --- /dev/null +++ b/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 \ diff --git a/pk/mcall.h b/machine/mcall.h index e612628..2096d16 100644 --- a/pk/mcall.h +++ b/machine/mcall.h @@ -1,5 +1,5 @@ -#ifndef _PK_MCALL_H -#define _PK_MCALL_H +#ifndef _RISCV_MCALL_H +#define _RISCV_MCALL_H #define MCALL_HART_ID 0 #define MCALL_CONSOLE_PUTCHAR 1 diff --git a/pk/mentry.S b/machine/mentry.S index 2ded375..50ce9ca 100644 --- a/pk/mentry.S +++ b/machine/mentry.S @@ -1,6 +1,7 @@ // See LICENSE for license details. #include "mtrap.h" +#include "bits.h" .data .align 6 diff --git a/pk/minit.c b/machine/minit.c index ad9598b..33b94c8 100644 --- a/pk/minit.c +++ b/machine/minit.c @@ -1,8 +1,11 @@ -#include "vm.h" #include "mtrap.h" +#include "atomic.h" +#include "vm.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; uint32_t num_harts; @@ -64,6 +67,18 @@ void hls_init(uint32_t id, csr_t* 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() { mstatus_init(); @@ -73,12 +88,10 @@ static void hart_init() void init_first_hart() { - file_init(); hart_init(); - memset(HLS(), 0, sizeof(*HLS())); parse_config_string(); - vm_init(); + memory_init(); boot_loader(); } @@ -86,23 +99,22 @@ void init_other_hart() { hart_init(); - // wait until virtual memory is enabled - while (*(pte_t* volatile*)&root_page_table == NULL) + // wait until hart 0 discovers us + 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(); } -void prepare_supervisor_mode() +void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t stack) { uintptr_t mstatus = read_csr(mstatus); mstatus = INSERT_FIELD(mstatus, MSTATUS_MPP, PRV_S); mstatus = INSERT_FIELD(mstatus, MSTATUS_MPIE, 0); write_csr(mstatus, mstatus); 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(); } diff --git a/pk/mtrap.c b/machine/mtrap.c index b64360e..6fc5476 100644 --- a/pk/mtrap.c +++ b/machine/mtrap.c @@ -1,7 +1,8 @@ #include "mtrap.h" -#include "frontend.h" #include "mcall.h" -#include "vm.h" +#include "htif.h" +#include "atomic.h" +#include "bits.h" #include <errno.h> #include <stdarg.h> #include <stdio.h> @@ -68,6 +69,12 @@ void poweroff() write_csr(mtohost, 1); } +void putstring(const char* s) +{ + while (*s) + mcall_console_putchar(*s++); +} + void printm(const char* s, ...) { char buf[256]; @@ -77,8 +84,7 @@ void printm(const char* s, ...) vsnprintf(buf, sizeof buf, s, vl); va_end(vl); - for (const char* p = buf; *p; p++) - mcall_console_putchar(*p); + putstring(buf); } static void send_ipi(uintptr_t recipient, int event) diff --git a/pk/mtrap.h b/machine/mtrap.h index b6ea1df..139f359 100644 --- a/pk/mtrap.h +++ b/machine/mtrap.h @@ -1,7 +1,6 @@ -#ifndef _PK_MTRAP_H -#define _PK_MTRAP_H +#ifndef _RISCV_MTRAP_H +#define _RISCV_MTRAP_H -#include "bits.h" #include "encoding.h" #ifdef __riscv_atomic @@ -29,6 +28,7 @@ static inline int xlen() return read_const_csr(misa) < 0 ? 64 : 32; } +extern uintptr_t first_free_paddr; extern uintptr_t mem_size; extern uint32_t num_harts; @@ -52,8 +52,6 @@ typedef struct { #define IPI_FENCE_I 0x2 #define IPI_SFENCE_VM 0x4 -void hls_init(uint32_t hart_id, csr_t* csrs); - #define MACHINE_STACK_TOP() ({ \ register uintptr_t sp asm ("sp"); \ (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 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 poweroff(void) __attribute((noreturn)); void printm(const char* s, ...); +void putstring(const char* s); #define assert(x) ({ if (!(x)) die("assertion failed: %s", #x); }) #define die(str, ...) ({ printm("%s:%d: " str "\n", __FILE__, __LINE__, ##__VA_ARGS__); poweroff(); }) #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__ #define MACHINE_STACK_SIZE RISCV_PGSIZE diff --git a/pk/sbi_entry.S b/machine/sbi_entry.S index bfb0703..a37dd25 100644 --- a/pk/sbi_entry.S +++ b/machine/sbi_entry.S @@ -24,7 +24,7 @@ sbi_base: # query_memory .align 4 - j __sbi_query_memory + tail __sbi_query_memory # console_putchar .align 4 @@ -72,11 +72,11 @@ sbi_base: # mask_interrupt .align 4 - j __sbi_mask_interrupt + tail __sbi_mask_interrupt # unmask_interrupt .align 4 - j __sbi_unmask_interrupt + tail __sbi_unmask_interrupt # remote_sfence_vm .align 4 @@ -107,3 +107,5 @@ do_mcall: ret .align RISCV_PGSHIFT + .globl _sbi_end +_sbi_end: diff --git a/pk/sbi_impl.c b/machine/sbi_impl.c index 4af0cd4..07844e0 100644 --- a/pk/sbi_impl.c +++ b/machine/sbi_impl.c @@ -1,11 +1,10 @@ #include "mtrap.h" #include "sbi.h" -#include "boot.h" uintptr_t __sbi_query_memory(uintptr_t id, memory_block_info *p) { if (id == 0) { - p->base = current.first_free_paddr; + p->base = first_free_paddr; p->size = mem_size - p->base; return 0; } diff --git a/pk/unprivileged_memory.h b/machine/unprivileged_memory.h index d03cc5e..d03cc5e 100644 --- a/pk/unprivileged_memory.h +++ b/machine/unprivileged_memory.h diff --git a/machine/vm.h b/machine/vm.h new file mode 100644 index 0000000..f51c639 --- /dev/null +++ b/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 diff --git a/pk/bbl.c b/pk/bbl.c deleted file mode 100644 index 5ace350..0000000 --- a/pk/bbl.c +++ /dev/null @@ -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(); -} diff --git a/pk/bits.h b/pk/bits.h deleted file mode 100644 index 10f9df3..0000000 --- a/pk/bits.h +++ /dev/null @@ -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 @@ -5,7 +5,6 @@ #ifndef __ASSEMBLER__ -#include <stdint.h> #include <stddef.h> typedef struct { @@ -14,28 +13,19 @@ typedef struct { int is_supervisor; size_t phdr; 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 entry; size_t brk_min; size_t brk; size_t brk_max; size_t mmap_max; - size_t stack_bottom; size_t stack_top; size_t t0; } elf_info; 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 print_logo(); #endif // !__ASSEMBLER__ @@ -1,9 +1,9 @@ // See LICENSE for license details. -#include "file.h" -#include "vm.h" +#include "mmap.h" #include "mtrap.h" #include "boot.h" +#include "bits.h" #include <sys/stat.h> #include <fcntl.h> #include <elf.h> @@ -15,100 +15,55 @@ void load_elf(const char* fn, elf_info* info) if (IS_ERR_VALUE(file)) goto fail; - Elf64_Ehdr eh64; - ssize_t ehdr_size = file_pread(file, &eh64, sizeof(eh64), 0); - if (ehdr_size < (ssize_t)sizeof(eh64) || - !(eh64.e_ident[0] == '\177' && eh64.e_ident[1] == 'E' && - eh64.e_ident[2] == 'L' && eh64.e_ident[3] == 'F')) + Elf_Ehdr eh; + ssize_t ehdr_size = file_pread(file, &eh, sizeof(eh), 0); + if (ehdr_size < (ssize_t)sizeof(eh) || + !(eh.e_ident[0] == '\177' && eh.e_ident[1] == 'E' && + eh.e_ident[2] == 'L' && eh.e_ident[3] == 'F')) 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 - die("can't run 32-bit ELF on 64-bit arch"); + assert(IS_ELF64(eh)); +#else + assert(IS_ELF32(eh)); #endif - Elf32_Ehdr* eh; - Elf32_Phdr* ph; - LOAD_ELF; - } - else - goto fail; - info->first_user_vaddr = min_vaddr; - info->first_vaddr_after_user = ROUNDUP(max_vaddr - info->bias, RISCV_PGSIZE); - info->brk_min = max_vaddr; + uintptr_t min_vaddr = -1; + size_t phdr_size = eh.e_phnum * sizeof(Elf_Phdr); + 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); return; @@ -12,6 +12,14 @@ #define IS_ELF32(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 1) #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_DYN 3 @@ -1,11 +1,13 @@ // See LICENSE for license details. -#include <string.h> -#include <errno.h> #include "file.h" -#include "pk.h" +#include "atomic.h" +#include "mmap.h" #include "frontend.h" -#include "vm.h" +#include "syscall.h" +#include "pk.h" +#include <string.h> +#include <errno.h> #define MAX_FDS 128 static file_t* fds[MAX_FDS]; @@ -6,7 +6,6 @@ #include <sys/stat.h> #include <unistd.h> #include <stdint.h> -#include "atomic.h" typedef struct file { diff --git a/pk/frontend.h b/pk/frontend.h index 2cf5f81..5b9df31 100644 --- a/pk/frontend.h +++ b/pk/frontend.h @@ -6,18 +6,6 @@ #include <stdint.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)); long frontend_syscall(long n, long a0, long a1, long a2, long a3, long a4, long a5, long a6); diff --git a/pk/handlers.c b/pk/handlers.c index bc82b5d..1961852 100644 --- a/pk/handlers.c +++ b/pk/handlers.c @@ -3,7 +3,7 @@ #include "pk.h" #include "config.h" #include "syscall.h" -#include "vm.h" +#include "mmap.h" static void handle_illegal_instruction(trapframe_t* tf) { @@ -31,7 +31,7 @@ static void handle_misaligned_fetch(trapframe_t* tf) panic("Misaligned instruction access!"); } -void handle_misaligned_store(trapframe_t* tf) +static void handle_misaligned_store(trapframe_t* tf) { dump_tf(tf); panic("Misaligned AMO!"); @@ -50,13 +50,13 @@ static void handle_fault_fetch(trapframe_t* tf) 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) 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) segfault(tf, tf->badvaddr, "store"); diff --git a/pk/init.c b/pk/init.c deleted file mode 100644 index 11e17bd..0000000 --- a/pk/init.c +++ /dev/null @@ -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], ¤t); - - run_loaded_program(argc, args.argv); -} @@ -1,8 +1,8 @@ -#include "vm.h" -#include "file.h" +#include "mmap.h" #include "atomic.h" #include "pk.h" #include "boot.h" +#include "bits.h" #include "mtrap.h" #include <stdint.h> #include <errno.h> @@ -17,14 +17,15 @@ typedef struct { } 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; -pte_t* root_page_table; static uintptr_t first_free_page; static size_t next_free_page; static size_t free_pages; +int have_vm = 1; // unless -p flag is given + static uintptr_t __page_alloc() { kassert(next_free_page != free_pages); @@ -73,41 +74,6 @@ static size_t pte_ppn(pte_t pte) 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) { 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); } -static void __maybe_create_root_page_table() +static pte_t* __maybe_create_root_page_table() { - if (root_page_table) - return; - root_page_table = (void*)__page_alloc(); - if (have_vm) - write_csr(sptbr, (uintptr_t)root_page_table >> RISCV_PGSHIFT); + if (!root_page_table) + root_page_table = (void*)__page_alloc(); + return root_page_table; } static pte_t* __walk_internal(uintptr_t addr, int create) { - const size_t pte_per_page = RISCV_PGSIZE/sizeof(void*); - __maybe_create_root_page_table(); - pte_t* t = root_page_table; - unsigned levels = (VA_BITS - RISCV_PGSHIFT) / RISCV_PGLEVEL_BITS; - - for (unsigned i = levels-1; i > 0; i--) - { + pte_t* t = __maybe_create_root_page_table(); + for (int i = (VA_BITS - RISCV_PGSHIFT) / RISCV_PGLEVEL_BITS - 1; i > 0; i--) { size_t idx = pt_idx(addr, i); - if (!(t[idx] & PTE_V)) - { + if (!(t[idx] & PTE_V)) { if (!create) return 0; uintptr_t page = __page_alloc(); @@ -185,11 +143,40 @@ static uintptr_t __vm_alloc(size_t npage) 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) { if (vaddr + len < vaddr) 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) @@ -206,7 +193,7 @@ static int __handle_page_fault(uintptr_t vaddr, int prot) uintptr_t ppn = vpn; 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(); if (v->file) { @@ -219,10 +206,10 @@ static int __handle_page_fault(uintptr_t vaddr, int prot) else memset((void*)vaddr, 0, RISCV_PGSIZE); __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) return -1; @@ -384,7 +371,7 @@ uintptr_t do_mprotect(uintptr_t addr, size_t length, int prot) res = -EACCES; break; } - *pte = pte_create(pte_ppn(*pte), prot, 1); + *pte = pte_create(pte_ppn(*pte), prot_to_type(prot, 1)); } } 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) { 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) { pte_t* pte = __walk_create(a); 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() -{ - extern char _end; - return ROUNDUP((uintptr_t)&_end, RISCV_PGSIZE); -} - -#define first_free_paddr() (sbi_top_paddr() + num_harts * RISCV_PGSIZE) - -void vm_init() +uintptr_t pk_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; free_pages = MAX(8, mem_pages >> (RISCV_PGLEVEL_BITS-1)); first_free_page = mem_size - free_pages * RISCV_PGSIZE; - current.mmap_max = current.brk_max = first_free_page; -} -void supervisor_vm_init() -{ - 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); -} + __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 pk_vm_init() -{ // keep user addresses positive - current.mmap_max = MIN(current.mmap_max, (uintptr_t)INTPTR_MAX + 1); - - __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); + current.mmap_max = MIN(first_free_page, (uintptr_t)INTPTR_MAX + 1); + current.brk_max = current.mmap_max; 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); - current.stack_top = current.stack_bottom + stack_size; - kassert(current.stack_bottom != (uintptr_t)-1); + 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); + kassert(stack_bottom != (uintptr_t)-1); + current.stack_top = stack_bottom + stack_size; uintptr_t kernel_stack_top = __page_alloc() + RISCV_PGSIZE; return kernel_stack_top; @@ -1,21 +1,11 @@ -#ifndef _VM_H -#define _VM_H +#ifndef _MMAP_H +#define _MMAP_H +#include "vm.h" #include "syscall.h" +#include "encoding.h" #include "file.h" -#include <string.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 +#include <stddef.h> #define PROT_NONE 0 #define PROT_READ 1 @@ -28,8 +18,7 @@ #define MAP_POPULATE 0x8000 #define MREMAP_FIXED 0x2 -void vm_init(); -void supervisor_vm_init(); +extern int have_vm; uintptr_t pk_vm_init(); int handle_page_fault(uintptr_t vaddr, 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_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 @@ -2,13 +2,3 @@ AC_ARG_ENABLE([vm], AS_HELP_STRING([--disable-vm], [Disable virtual memory])) AS_IF([test "x$enable_vm" != "xno"], [ 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]) -]) @@ -1,24 +1,66 @@ #include "pk.h" +#include "mmap.h" #include "boot.h" -#include "vm.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) - panic("pk can't run kernel binaries; try using bbl instead"); + switch (s[1]) + { + 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; - write_csr(stvec, &trap_entry); - write_csr(sscratch, 0); - clear_csr(sie, SIP_STIP | SIP_SSIP); + default: + panic("unrecognized option: `%c'", s[1]); + break; + } +} - // enter supervisor mode - prepare_supervisor_mode(); - asm volatile("la t0, 1f; csrw mepc, t0; eret; 1:" ::: "t0"); +#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; +} + +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 size_t stack_top = current.stack_top - 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; init_tf(&tf, current.entry, stack_top); __clear_cache(0, 0); - write_csr(sscratch, kernel_stack_top); + write_csr(sscratch, kstack_top); 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], ¤t); + + 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() { // stall all harts besides hart 0 @@ -24,30 +24,18 @@ typedef struct #define kassert(cond) do { if(!(cond)) kassert_fail(""#cond); } while(0) void do_panic(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 extern "C" { #endif -extern int have_vm; - void printk(const char* s, ...); void printm(const char* s, ...); int vsnprintf(char* out, size_t n, const char* s, va_list vl); 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 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) { return (insn & 0x3) < 0x3 ? 2 : 4; @@ -60,11 +48,6 @@ extern int uarch_counters_enabled; extern long uarch_counters[NUM_COUNTERS]; extern char* uarch_counter_names[NUM_COUNTERS]; -static inline void wfi() -{ - asm volatile ("wfi" ::: "memory"); -} - #ifdef __cplusplus } #endif @@ -86,10 +86,5 @@ SECTIONS *(COMMON) } - .sbi : - { - sbi.o(.sbi) - } - _end = .; } diff --git a/pk/pk.mk.in b/pk/pk.mk.in index 78f826e..3caa25d 100644 --- a/pk/pk.mk.in +++ b/pk/pk.mk.in @@ -1,52 +1,30 @@ pk_subproject_deps = \ + util \ softfloat \ + machine \ pk_hdrs = \ - atomic.h \ - bits.h \ boot.h \ elf.h \ - emulation.h \ - encoding.h \ file.h \ - fp_emulation.h \ frontend.h \ - mcall.h \ - mtrap.h \ + mmap.h \ pk.h \ - sbi.h \ syscall.h \ - unprivileged_memory.h \ - vm.h \ pk_c_srcs = \ - snprintf.c \ - mtrap.c \ - minit.c \ - emulation.c \ - fp_emulation.c \ - sbi_impl.c \ - init.c \ file.c \ syscall.c \ handlers.c \ frontend.c \ elf.c \ console.c \ - vm.c \ - string.c \ - logo.c \ - configstring.c \ + mmap.c \ pk_asm_srcs = \ - mentry.S \ entry.S \ - fp_asm.S \ - sbi_entry.S \ - sbi.S \ pk_test_srcs = pk_install_prog_srcs = \ pk.c \ - bbl.c \ diff --git a/pk/syscall.c b/pk/syscall.c index 17112d8..de11a0a 100644 --- a/pk/syscall.c +++ b/pk/syscall.c @@ -4,7 +4,7 @@ #include "pk.h" #include "file.h" #include "frontend.h" -#include "vm.h" +#include "mmap.h" #include "boot.h" #include <string.h> #include <errno.h> diff --git a/pk/snprintf.c b/util/snprintf.c index 1544a6c..1544a6c 100644 --- a/pk/snprintf.c +++ b/util/snprintf.c diff --git a/pk/string.c b/util/string.c index e896379..e896379 100644 --- a/pk/string.c +++ b/util/string.c diff --git a/util/util.ac b/util/util.ac new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/util/util.ac diff --git a/util/util.mk.in b/util/util.mk.in new file mode 100644 index 0000000..abbdbd1 --- /dev/null +++ b/util/util.mk.in @@ -0,0 +1,9 @@ +util_subproject_deps = \ + +util_hdrs = \ + +util_c_srcs = \ + snprintf.c \ + string.c \ + +util_asm_srcs = \ |