diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 6806081fd..2d17b4442 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -35,3 +35,4 @@ add_subdirectory(hello) add_subdirectory(hello-native) add_subdirectory(attestation) add_subdirectory(tests) +add_subdirectory(devshare) \ No newline at end of file diff --git a/examples/devshare/CMakeLists.txt b/examples/devshare/CMakeLists.txt new file mode 100644 index 000000000..4e8630754 --- /dev/null +++ b/examples/devshare/CMakeLists.txt @@ -0,0 +1,36 @@ +set(eapp_bin devshare) +set(eapp_src eapp/devshare.c) +set(host_bin devshare-runner) +set(host_src host/host.cpp) +set(package_name "devshare.ke") +set(package_script "./devshare-runner devshare eyrie-rt loader.bin") +set(eyrie_plugins "freemem io_syscall linux_syscall env_setup") + +# eapp + +add_executable(${eapp_bin} ${eapp_src}) +target_link_libraries(${eapp_bin} "-static" ${KEYSTONE_LIB_EAPP}) + +# host + +add_executable(${host_bin} ${host_src}) +target_link_libraries(${host_bin} ${KEYSTONE_LIB_HOST} ${KEYSTONE_LIB_EDGE}) + +# add target for Eyrie runtime (see keystone.cmake) + +set(eyrie_files_to_copy .options_log eyrie-rt loader.bin) +add_eyrie_runtime(${eapp_bin}-eyrie + ${eyrie_plugins} + ${eyrie_files_to_copy}) + +# add target for packaging (see keystone.cmake) + +add_keystone_package(${eapp_bin}-package + ${package_name} + ${package_script} + ${eyrie_files_to_copy} ${eapp_bin} ${host_bin}) + +add_dependencies(${eapp_bin}-package ${eapp_bin}-eyrie) + +# add package to the top-level target +add_dependencies(examples ${eapp_bin}-package) diff --git a/examples/devshare/eapp/devshare.c b/examples/devshare/eapp/devshare.c new file mode 100644 index 000000000..ce6b2ca7a --- /dev/null +++ b/examples/devshare/eapp/devshare.c @@ -0,0 +1,38 @@ +#include +#include + +#include "app/syscall.h" + +#define SECURE_DEVICE "uart@10001000" + +int main() +{ + int ret, fd, i; + ret = claim_mmio(SECURE_DEVICE, + strlen(SECURE_DEVICE)); + if(ret < 0) { + printf("Failed to claim " SECURE_DEVICE "\n"); + return -1; + } + + fd = openat(-2, "uart8250", 0, 0); + if(fd < 0) { + printf("Failed to get fd for device\n"); + return -1; + } + + for(i = 0; i < 1000; i++) { + fprintf(fd, "Writing to UART: %i!\n", i); + fflush(fd); + } + + // todo do something with the device + + ret = release_mmio(SECURE_DEVICE, + strlen(SECURE_DEVICE)); + if(ret < 0) { + printf("Failed to release " SECURE_DEVICE "\n"); + } + + return 0; +} diff --git a/examples/devshare/host/host.cpp b/examples/devshare/host/host.cpp new file mode 100644 index 000000000..be21f7e75 --- /dev/null +++ b/examples/devshare/host/host.cpp @@ -0,0 +1,22 @@ + +#include "edge/edge_call.h" +#include "host/keystone.h" + +using namespace Keystone; + +int main(int argc, char **argv) { + Enclave enclave; + Params params; + + params.setFreeMemSize(1024 * 1024); + params.setUntrustedSize(1024 * 1024); + + enclave.init(argv[1], argv[2], argv[3], params); + + enclave.registerOcallDispatch(incoming_call_dispatch); + edge_call_init_internals( + (uintptr_t)enclave.getSharedBuffer(), enclave.getSharedBufferSize()); + + enclave.run(); + return 0; +} \ No newline at end of file diff --git a/mkutils/plat/generic/run.mk b/mkutils/plat/generic/run.mk index f1c113f58..6b5f7ad7c 100644 --- a/mkutils/plat/generic/run.mk +++ b/mkutils/plat/generic/run.mk @@ -9,8 +9,7 @@ QEMU_DEBUG := -gdb tcp::$(QEMU_DBG_PORT) -S QEMU_MEM ?= 2G QEMU_SMP ?= 4 - -QEMU_FLAGS := -m $(QEMU_MEM) -smp $(QEMU_SMP) -nographic \ +QEMU_FLAGS := -m $(QEMU_MEM) -smp $(QEMU_SMP) -display none \ -machine virt,rom=$(BUILDROOT_BUILDDIR)/images/bootrom.bin \ -bios $(BUILDROOT_BUILDDIR)/images/fw_jump.elf \ -kernel $(BUILDROOT_BUILDDIR)/images/Image \ @@ -20,6 +19,7 @@ QEMU_FLAGS := -m $(QEMU_MEM) -smp $(QEMU_SMP) -nographic \ -netdev user,id=net0,net=192.168.100.1/24,dhcpstart=192.168.100.128,hostfwd=tcp::$(QEMU_PORT)-:22 \ -device virtio-net-device,netdev=net0 \ -device virtio-rng-pci \ + -serial mon:stdio -serial file:/tmp/serial.out ifneq ($(KEYSTONE_DEBUG),) QEMU_FLAGS += $(QEMU_DEBUG) diff --git a/overlays/keystone/boot/hss/0001-integrate-sm.patch b/overlays/keystone/boot/hss/0001-integrate-sm.patch index 4a889a611..4ed9a3715 100644 --- a/overlays/keystone/boot/hss/0001-integrate-sm.patch +++ b/overlays/keystone/boot/hss/0001-integrate-sm.patch @@ -1,5 +1,5 @@ diff --git a/application/crt.S b/application/crt.S -index 1475373..80f8c58 100644 +index 1475373..b47fa95 100644 --- a/application/crt.S +++ b/application/crt.S @@ -158,6 +158,7 @@ _start_hang: @@ -11,9 +11,9 @@ index 1475373..80f8c58 100644 // Swap TP and MSCRATCH csrrw tp, CSR_MSCRATCH, tp @@ -305,6 +306,52 @@ _trap_handler_all_mode: - + mret - + +_trap_exit: + /* Restore all general regisers except A0 and T0 */ + REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(a0) @@ -87,9 +87,9 @@ diff --git a/services/opensbi/Makefile b/services/opensbi/Makefile index 829c28a..acf19fd 100644 --- a/services/opensbi/Makefile +++ b/services/opensbi/Makefile -@@ -92,6 +92,27 @@ services/opensbi/opensbi_ecall_exts.c: $(OPENSBI_SRC_DIR)/lib/sbi/sbi_ecall_exts - echo " CARRAY $<" - $(OPENSBI_SRC_DIR)/scripts/carray.sh -i $< -l "$(carray-sbi_ecall_exts-y)" > $@ +@@ -72,6 +72,27 @@ SRCS-$(CONFIG_SERVICE_OPENSBI) += \ + thirdparty/opensbi/lib/utils/timer/aclint_mtimer.c \ + thirdparty/opensbi/lib/utils/ipi/aclint_mswi.c \ +ifneq ($(KEYSTONE_SM),) + @@ -115,7 +115,7 @@ index 829c28a..acf19fd 100644 ifdef CONFIG_USE_IHC SRCS-$(CONFIG_SERVICE_OPENSBI_IHC) += \ services/opensbi/opensbi_ihc_ecall.c \ -@@ -128,7 +149,7 @@ endif +@@ -108,7 +129,7 @@ endif services/opensbi/opensbi_service.o: CFLAGS=$(CFLAGS_GCCEXT) services/opensbi/opensbi_ihc_ecall.o: CFLAGS=$(CFLAGS_GCCEXT) @@ -131,31 +131,37 @@ index f8bb9f0..e72dba5 100644 @@ -84,6 +84,8 @@ static void opensbi_scratch_setup(enum HSSHartId hartid) pScratches[hartid].scratch.fw_start = (unsigned long)&_hss_start; pScratches[hartid].scratch.fw_size = (unsigned long)&_hss_end - (unsigned long)&_hss_start; - + + extern void _trap_exit(const struct sbi_trap_regs *regs); + pScratches[hartid].scratch.trap_exit = (unsigned long) &_trap_exit; sbi_hsm_set_device(&mpfs_hsm); } - + diff --git a/services/opensbi/platform.c b/services/opensbi/platform.c -index c31fe12..33ca22d 100644 +index b03f878..161b449 100644 --- a/services/opensbi/platform.c +++ b/services/opensbi/platform.c @@ -69,6 +69,8 @@ #include "reboot_service.h" #include "clocks/hw_mss_clks.h" // LIBERO_SETTING_MSS_RTC_TOGGLE_CLK - + +#include "sm.h" + #define MPFS_HART_COUNT 5 #define MPFS_HART_STACK_SIZE 8192 - -@@ -197,6 +199,8 @@ static int mpfs_early_init(bool cold_boot) - + +@@ -197,11 +199,13 @@ static int mpfs_early_init(bool cold_boot) + static int mpfs_final_init(bool cold_boot) { -+ sm_init(cold_boot); ++ void *fdt = sbi_scratch_thishart_arg1_ptr(); ++ sm_init(cold_boot, fdt); + if (!cold_boot) { return 0; } + +- void *fdt = sbi_scratch_thishart_arg1_ptr(); + if (fdt) { + mpfs_modify_dt(fdt); + } diff --git a/overlays/keystone/patches/qemu/qemu-rom.patch b/overlays/keystone/patches/qemu/0001-qemu-rom.patch similarity index 100% rename from overlays/keystone/patches/qemu/qemu-rom.patch rename to overlays/keystone/patches/qemu/0001-qemu-rom.patch diff --git a/overlays/keystone/patches/qemu/0002-qemu-add-uarts.patch b/overlays/keystone/patches/qemu/0002-qemu-add-uarts.patch new file mode 100644 index 000000000..91d274a63 --- /dev/null +++ b/overlays/keystone/patches/qemu/0002-qemu-add-uarts.patch @@ -0,0 +1,112 @@ +diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c +index a5bc7353b4..f61a6423b6 100644 +--- a/hw/riscv/virt.c ++++ b/hw/riscv/virt.c +@@ -85,7 +85,8 @@ static const MemMapEntry virt_memmap[] = { + [VIRT_APLIC_M] = { 0xc000000, APLIC_SIZE(VIRT_CPUS_MAX) }, + [VIRT_APLIC_S] = { 0xd000000, APLIC_SIZE(VIRT_CPUS_MAX) }, + [VIRT_UART0] = { 0x10000000, 0x100 }, +- [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, ++ [VIRT_UART1] = { 0x10001000, 0x100 }, ++ [VIRT_VIRTIO] = { 0x10002000, 0x1000 }, + [VIRT_FW_CFG] = { 0x10100000, 0x18 }, + [VIRT_FLASH] = { 0x20000000, 0x4000000 }, + [VIRT_IMSIC_M] = { 0x24000000, VIRT_IMSIC_MAX_SIZE }, +@@ -95,6 +96,11 @@ static const MemMapEntry virt_memmap[] = { + [VIRT_DRAM] = { 0x80000000, 0x0 }, + }; + ++static const int uart_irqs[] = { ++ [VIRT_UART0] = UART0_IRQ, ++ [VIRT_UART1] = UART1_IRQ ++}; ++ + /* PCIe high mmio is fixed for RV32 */ + #define VIRT32_HIGH_PCIE_MMIO_BASE 0x300000000ULL + #define VIRT32_HIGH_PCIE_MMIO_SIZE (4 * GiB) +@@ -921,27 +927,36 @@ static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, + } + + static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap, +- uint32_t irq_mmio_phandle) ++ uint32_t irq_mmio_phandle, int uart) + { + char *name; + MachineState *mc = MACHINE(s); + +- name = g_strdup_printf("/soc/serial@%lx", (long)memmap[VIRT_UART0].base); ++ name = g_strdup_printf("/soc/serial@%lx", (long)memmap[uart].base); + qemu_fdt_add_subnode(mc->fdt, name); + qemu_fdt_setprop_string(mc->fdt, name, "compatible", "ns16550a"); ++ ++ if(uart == VIRT_UART1) { ++ qemu_fdt_setprop_string(mc->fdt, name, "status", "disabled"); ++ qemu_fdt_setprop_string(mc->fdt, name, "secure-status", "okay"); ++ } ++ + qemu_fdt_setprop_cells(mc->fdt, name, "reg", +- 0x0, memmap[VIRT_UART0].base, +- 0x0, memmap[VIRT_UART0].size); ++ 0x0, memmap[uart].base, ++ 0x0, memmap[uart].size); + qemu_fdt_setprop_cell(mc->fdt, name, "clock-frequency", 3686400); + qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", irq_mmio_phandle); + if (s->aia_type == VIRT_AIA_TYPE_NONE) { +- qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", UART0_IRQ); ++ qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", uart_irqs[uart]); + } else { +- qemu_fdt_setprop_cells(mc->fdt, name, "interrupts", UART0_IRQ, 0x4); ++ qemu_fdt_setprop_cells(mc->fdt, name, "interrupts", uart_irqs[uart], 0x4); ++ } ++ ++ if(uart == VIRT_UART0) { ++ qemu_fdt_add_subnode(mc->fdt, "/chosen"); ++ qemu_fdt_setprop_string(mc->fdt, "/chosen", "stdout-path", name); + } + +- qemu_fdt_add_subnode(mc->fdt, "/chosen"); +- qemu_fdt_setprop_string(mc->fdt, "/chosen", "stdout-path", name); + g_free(name); + } + +@@ -1045,7 +1060,8 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, + + create_fdt_reset(s, memmap, &phandle); + +- create_fdt_uart(s, memmap, irq_mmio_phandle); ++ create_fdt_uart(s, memmap, irq_mmio_phandle, VIRT_UART0); ++ create_fdt_uart(s, memmap, irq_mmio_phandle, VIRT_UART1); + + create_fdt_rtc(s, memmap, irq_mmio_phandle); + +@@ -1510,6 +1526,10 @@ static void virt_machine_init(MachineState *machine) + 0, qdev_get_gpio_in(DEVICE(mmio_irqchip), UART0_IRQ), 399193, + serial_hd(0), DEVICE_LITTLE_ENDIAN); + ++ serial_mm_init(system_memory, memmap[VIRT_UART1].base, ++ 0, qdev_get_gpio_in(DEVICE(mmio_irqchip), UART1_IRQ), 399193, ++ serial_hd(1), DEVICE_LITTLE_ENDIAN); ++ + sysbus_create_simple("goldfish_rtc", memmap[VIRT_RTC].base, + qdev_get_gpio_in(DEVICE(mmio_irqchip), RTC_IRQ)); + +diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h +index be4ab8fe7f..8a01dab7fc 100644 +--- a/include/hw/riscv/virt.h ++++ b/include/hw/riscv/virt.h +@@ -69,6 +69,7 @@ enum { + VIRT_APLIC_M, + VIRT_APLIC_S, + VIRT_UART0, ++ VIRT_UART1, + VIRT_VIRTIO, + VIRT_FW_CFG, + VIRT_IMSIC_M, +@@ -83,6 +84,7 @@ enum { + + enum { + UART0_IRQ = 10, ++ UART1_IRQ = 9, + RTC_IRQ = 11, + VIRTIO_IRQ = 1, /* 1 to 8 */ + VIRTIO_COUNT = 8, diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 9be4575a8..b1af5d23b 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -37,6 +37,9 @@ rt_option(NET_SYSCALL "Wrap Linux net syscalls" OFF) # System options rt_option(ENV_SETUP "Set up stack environments like glibc expects" OFF) +# Driver options +rt_option(DRIVERS "Include support for hardware drivers" OFF) + # Debugging options rt_option(INTERNAL_STRACE "Debug syscalls" OFF) rt_option(DEBUG "Enable debugging" OFF) @@ -61,6 +64,7 @@ add_compile_options(-Wall -Werror -fno-builtin -static -mcmodel=medany -std=c11 # Generate all the library targets add_subdirectory(call) add_subdirectory(crypto) +add_subdirectory(drivers) add_subdirectory(loader) add_subdirectory(mm) add_subdirectory(tmplib) diff --git a/runtime/call/linux_wrap.c b/runtime/call/linux_wrap.c index 19dc912c7..263d4b819 100644 --- a/runtime/call/linux_wrap.c +++ b/runtime/call/linux_wrap.c @@ -138,21 +138,9 @@ uintptr_t syscall_mmap(void *addr, size_t length, int prot, int flags, } // Start looking at EYRIE_ANON_REGION_START for VA space - uintptr_t starting_vpn = vpn(EYRIE_ANON_REGION_START); - uintptr_t valid_pages; - while((starting_vpn + req_pages) <= EYRIE_ANON_REGION_END){ - valid_pages = test_va_range(starting_vpn, req_pages); - - if(req_pages == valid_pages){ - // Set a successful value if we allocate - // TODO free partial allocation on failure - if(alloc_pages(starting_vpn, req_pages, pte_flags) == req_pages){ - ret = starting_vpn << RISCV_PAGE_BITS; - } - break; - } - else - starting_vpn += valid_pages + 1; + uintptr_t vpn = find_va_range(req_pages); + if(vpn && alloc_pages(vpn, req_pages, pte_flags) == req_pages) { + ret = vpn << RISCV_PAGE_BITS; } done: diff --git a/runtime/call/sbi.c b/runtime/call/sbi.c index 41c89e78f..a675bcf9a 100644 --- a/runtime/call/sbi.c +++ b/runtime/call/sbi.c @@ -76,3 +76,13 @@ uintptr_t sbi_get_sealing_key(uintptr_t key_struct, uintptr_t key_ident, uintptr_t len) { return SBI_CALL_3(SBI_EXT_EXPERIMENTAL_KEYSTONE_ENCLAVE, SBI_SM_GET_SEALING_KEY, key_struct, key_ident, len); } + +uintptr_t +sbi_claim_mmio(uintptr_t dev_string) { + return SBI_CALL_1(SBI_EXT_EXPERIMENTAL_KEYSTONE_ENCLAVE, SBI_SM_CLAIM_MMIO, dev_string); +} + +uintptr_t +sbi_release_mmio(uintptr_t dev_string) { + return SBI_CALL_1(SBI_EXT_EXPERIMENTAL_KEYSTONE_ENCLAVE, SBI_SM_RELEASE_MMIO, dev_string); +} \ No newline at end of file diff --git a/runtime/call/syscall.c b/runtime/call/syscall.c index 3731f3ae8..fa9e4229b 100644 --- a/runtime/call/syscall.c +++ b/runtime/call/syscall.c @@ -26,6 +26,10 @@ #include "call/net_wrap.h" #endif /* USE_NET_SYSCALL */ +#ifdef USE_DRIVERS +#include "drivers/drivers.h" +#endif + extern void exit_enclave(uintptr_t arg0); uintptr_t dispatch_edgecall_syscall(struct edge_syscall* syscall_data_ptr, size_t data_len){ @@ -209,6 +213,42 @@ void handle_syscall(struct encl_ctx* ctx) break; + case(RUNTIME_SYSCALL_CLAIM_MMIO): + if(arg1 > sizeof(rt_copy_buffer_1)) { + ret = -1; + break; + } + + uintptr_t devstr_claim_pa = kernel_va_to_pa(rt_copy_buffer_1); + copy_from_user(rt_copy_buffer_1, (void *) arg0, arg1); + + ret = sbi_claim_mmio(devstr_claim_pa); + +#ifdef USE_DRIVERS + // Initialize the hardware + if(ret == 0) { + ret = init_driver((char *) rt_copy_buffer_1); + } +#endif + + break; + + case(RUNTIME_SYSCALL_RELEASE_MMIO): + if(arg1 > sizeof(rt_copy_buffer_1)) { + ret = -1; + break; + } + + uintptr_t devstr_release_pa = kernel_va_to_pa(rt_copy_buffer_1); + copy_from_user(rt_copy_buffer_1, (void *) arg0, arg1); + +#ifdef USE_DRIVERS + // Teardown the hardware + fini_driver((char *) rt_copy_buffer_1); +#endif + + ret = sbi_release_mmio(devstr_release_pa); + break; #ifdef USE_LINUX_SYSCALL case(SYS_clock_gettime): @@ -263,22 +303,44 @@ void handle_syscall(struct encl_ctx* ctx) break; #endif /* USE_LINUX_SYSCALL */ -#ifdef USE_IO_SYSCALL +#if defined(USE_IO_SYSCALL) || defined(USE_DRIVERS) case(SYS_read): +#ifdef USE_DRIVERS + ret = drivers_read_override((int)arg0, (void *)arg1, (size_t)arg2); +#else ret = io_syscall_read((int)arg0, (void*)arg1, (size_t)arg2); +#endif break; case(SYS_write): +#ifdef USE_DRIVERS + ret = drivers_write_override((int)arg0, (void *)arg1, (size_t)arg2); +#else ret = io_syscall_write((int)arg0, (void*)arg1, (size_t)arg2); +#endif + break; + case(SYS_openat): +#ifdef USE_DRIVERS + ret = drivers_openat_override((int)arg0, (char *)arg1, (int)arg2, (mode_t)arg3); +#else + ret = io_syscall_openat((int)arg0, (char*)arg1, (int)arg2, (mode_t)arg3); +#endif + break; + case(SYS_close): +#ifdef USE_DRIVERS + ret = drivers_close_override((int)arg0); +#else + ret = io_syscall_close((int)arg0); +#endif break; +#endif + +#ifdef USE_IO_SYSCALL case(SYS_writev): ret = io_syscall_writev((int)arg0, (const struct iovec*)arg1, (int)arg2); break; case(SYS_readv): ret = io_syscall_readv((int)arg0, (const struct iovec*)arg1, (int)arg2); break; - case(SYS_openat): - ret = io_syscall_openat((int)arg0, (char*)arg1, (int)arg2, (mode_t)arg3); - break; case(SYS_unlinkat): ret = io_syscall_unlinkat((int)arg0, (char*)arg1, (int)arg2); break; @@ -300,9 +362,6 @@ void handle_syscall(struct encl_ctx* ctx) case(SYS_fsync): ret = io_syscall_fsync((int)arg0); break; - case(SYS_close): - ret = io_syscall_close((int)arg0); - break; case(SYS_epoll_create1): ret = io_syscall_epoll_create((int) arg0); break; diff --git a/runtime/drivers/CMakeLists.txt b/runtime/drivers/CMakeLists.txt new file mode 100644 index 000000000..ae16590b7 --- /dev/null +++ b/runtime/drivers/CMakeLists.txt @@ -0,0 +1,3 @@ + +set(DRIVER_SOURCES drivers.c serial.c) +add_library(rt_drivers OBJECT ${DRIVER_SOURCES}) diff --git a/runtime/drivers/drivers.c b/runtime/drivers/drivers.c new file mode 100644 index 000000000..26c6f1d57 --- /dev/null +++ b/runtime/drivers/drivers.c @@ -0,0 +1,161 @@ +#include "drivers/drivers.h" + +#include +#include +#include + +#include "call/io_wrap.h" +#include "call/syscall.h" +#include "uaccess.h" +#include "util/string.h" + +#define FD_COUNT 64 +#define EYRIE_FD_OFFSET 10000 + +#define EYRIE_DEVICES_DIRFD -2 + +driver* drivers_head; +driver* drivers_tail; +uint32_t drivers_len; + +driver* fd_nodes[FD_COUNT]; + +#ifdef USE_DRIVERS +extern uintptr_t drivers_start; // defined in runtime.ld.S +extern uintptr_t drivers_end; // defined in runtime.ld.S + +int init_driver_subsystem() { + for (int i = 0; i < FD_COUNT; i += 1) + fd_nodes[i] = NULL; + + drivers_head = (driver*)&drivers_start; + drivers_tail = (driver*)&drivers_end; + drivers_len = drivers_tail - drivers_head; + return 1; +} +#endif + +driver* get_driver_from_name(char* name) { + // Get a local copy of the name so we can change it if we need + int i; + char name_local[DRIVER_NAME_MAX_LEN] = {0}; + + size_t name_len = MIN(strlen(name), DRIVER_NAME_MAX_LEN); + memcpy(name_local, name, name_len); + + // Check if we were passed a devicetree-style name, and fix it if so + for(i = 0; i < name_len; i++) { + if(name_local[i] == '@') { + name_local[i] = '\0'; + break; + } + } + + for (driver* curr_driver = drivers_head; curr_driver < drivers_tail; curr_driver += 1) { + if (strcmp(name_local, curr_driver->name) == 0) { + return curr_driver; + } + } + return NULL; +} + +int init_driver(char *name) { + driver *d = get_driver_from_name(name); + if(d) { + if(d->init) { + return d->init(); + } else { + return 0; + } + } + else return -1; +} + +int fini_driver(char *name) { + driver *d = get_driver_from_name(name); + if(d) { + if(d->fini) { + return d->fini(); + } else { + return 0; + } + } + else return -1; +} + +uintptr_t drivers_openat_override(int dirfd, char* path, int flags, mode_t mode) { + if (dirfd == EYRIE_DEVICES_DIRFD) { + char driver_name[DRIVER_NAME_MAX_LEN]; + copy_from_user((void*)driver_name, (void*)path, DRIVER_NAME_MAX_LEN); + + driver* matching_driver = get_driver_from_name(driver_name); + if (matching_driver == NULL) return -1; + + // find the first open fd node slot + for (int fd = 0; fd < FD_COUNT; fd += 1) { + if (fd_nodes[fd] == NULL) { + fd_nodes[fd] = matching_driver; + return fd + EYRIE_FD_OFFSET; + } + } + + return -1; + } else { +#ifdef USE_IO_SYSCALL + return io_syscall_openat(dirfd, path, flags, mode); +#else + return -1; +#endif + } +} + +uintptr_t drivers_close_override(int fd) { + if(fd >= EYRIE_FD_OFFSET) { + fd_nodes[fd - EYRIE_FD_OFFSET] = NULL; + return 0; + } else { +#ifdef USE_IO_SYSCALL + return io_syscall_close(fd); +#else + return -1; +#endif + } +} + +uintptr_t drivers_read_override(int fd, void* buf, size_t len) { + driver *d; + if (fd >= EYRIE_FD_OFFSET) { + d = fd_nodes[fd - EYRIE_FD_OFFSET]; + + if(d->read) { + return d->read(buf, len); + } else { + return 0; + } + } else { +#ifdef USE_IO_SYSCALL + return io_syscall_read(fd, buf, len); +#else + return -1; +#endif + } +} + +uintptr_t drivers_write_override(int fd, void* buf, size_t len) { + driver *d; + if (fd >= EYRIE_FD_OFFSET) { + d = fd_nodes[fd - EYRIE_FD_OFFSET]; + + if(d->write) { + return d->write(buf, len); + } else { + return 0; + } + } else { +#ifdef USE_IO_SYSCALL + return io_syscall_write(fd, buf, len); +#else + return -1; +#endif + } +} diff --git a/runtime/drivers/serial.c b/runtime/drivers/serial.c new file mode 100644 index 000000000..0215344a3 --- /dev/null +++ b/runtime/drivers/serial.c @@ -0,0 +1,275 @@ +/* +* SPDX-License-Identifier: BSD-2-Clause +* +* Copyright (c) 2019 Western Digital Corporation or its affiliates. +* +* Authors: +* Anup Patel +*/ + +#include "drivers/drivers.h" +#include "uaccess.h" + +#include "call/syscall.h" + +#include + +#include "mm/mm.h" +#include "mm/vm.h" + +/* clang-format off */ + +#define UART_RBR_OFFSET 0 /* In: Recieve Buffer Register */ +#define UART_THR_OFFSET 0 /* Out: Transmitter Holding Register */ +#define UART_DLL_OFFSET 0 /* Out: Divisor Latch Low */ +#define UART_IER_OFFSET 1 /* I/O: Interrupt Enable Register */ +#define UART_DLM_OFFSET 1 /* Out: Divisor Latch High */ +#define UART_FCR_OFFSET 2 /* Out: FIFO Control Register */ +#define UART_IIR_OFFSET 2 /* I/O: Interrupt Identification Register */ +#define UART_LCR_OFFSET 3 /* Out: Line Control Register */ +#define UART_MCR_OFFSET 4 /* Out: Modem Control Register */ +#define UART_LSR_OFFSET 5 /* In: Line Status Register */ +#define UART_MSR_OFFSET 6 /* In: Modem Status Register */ +#define UART_SCR_OFFSET 7 /* I/O: Scratch Register */ +#define UART_MDR1_OFFSET 8 /* I/O: Mode Register */ + +#define UART_LSR_FIFOE 0x80 /* Fifo error */ +#define UART_LSR_TEMT 0x40 /* Transmitter empty */ +#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ +#define UART_LSR_BI 0x10 /* Break interrupt indicator */ +#define UART_LSR_FE 0x08 /* Frame error indicator */ +#define UART_LSR_PE 0x04 /* Parity error indicator */ +#define UART_LSR_OE 0x02 /* Overrun error indicator */ +#define UART_LSR_DR 0x01 /* Receiver data ready */ +#define UART_LSR_BRK_ERROR_BITS 0x1E /* BI, FE, PE, OE bits */ + +static inline void __raw_writeb(uint8_t val, volatile void *addr) +{ + __asm__ volatile("sb %0, 0(%1)" : : "r"(val), "r"(addr)); +} + +static inline void __raw_writew(uint16_t val, volatile void *addr) +{ + __asm__ volatile("sh %0, 0(%1)" : : "r"(val), "r"(addr)); +} + +static inline void __raw_writel(uint32_t val, volatile void *addr) +{ + __asm__ volatile("sw %0, 0(%1)" : : "r"(val), "r"(addr)); +} + +#if __riscv_xlen != 32 +static inline void __raw_writeq(uint64_t val, volatile void *addr) +{ + __asm__ volatile("sd %0, 0(%1)" : : "r"(val), "r"(addr)); +} +#endif + +static inline uint8_t __raw_readb(const volatile void *addr) +{ + uint8_t val; + + __asm__ volatile("lb %0, 0(%1)" : "=r"(val) : "r"(addr)); + return val; +} + +static inline uint16_t __raw_readw(const volatile void *addr) +{ + uint16_t val; + + __asm__ volatile("lh %0, 0(%1)" : "=r"(val) : "r"(addr)); + return val; +} + +static inline uint32_t __raw_readl(const volatile void *addr) +{ + uint32_t val; + + __asm__ volatile("lw %0, 0(%1)" : "=r"(val) : "r"(addr)); + return val; +} + +#if __riscv_xlen != 32 +static inline uint64_t __raw_readq(const volatile void *addr) +{ + uint64_t val; + + __asm__ volatile("ld %0, 0(%1)" : "=r"(val) : "r"(addr)); + return val; +} +#endif + +#define __io_br() do {} while (0) +#define __io_ar() __asm__ __volatile__ ("fence i,r" : : : "memory"); +#define __io_bw() __asm__ __volatile__ ("fence w,o" : : : "memory"); +#define __io_aw() do {} while (0) + +#define readb(c) ({ uint8_t __v; __io_br(); __v = __raw_readb(c); __io_ar(); __v; }) +#define readw(c) ({ uint16_t __v; __io_br(); __v = __raw_readw(c); __io_ar(); __v; }) +#define readl(c) ({ uint32_t __v; __io_br(); __v = __raw_readl(c); __io_ar(); __v; }) + +#define writeb(v,c) ({ __io_bw(); __raw_writeb((v),(c)); __io_aw(); }) +#define writew(v,c) ({ __io_bw(); __raw_writew((v),(c)); __io_aw(); }) +#define writel(v,c) ({ __io_bw(); __raw_writel((v),(c)); __io_aw(); }) + +/* clang-format on */ + +static bool configured = false; +static volatile void *uart8250_base; +static uint32_t uart8250_in_freq; +static uint32_t uart8250_baudrate; +static uint32_t uart8250_reg_width; +static uint32_t uart8250_reg_shift; + +static uint32_t get_reg(uint32_t num) +{ + uint32_t offset = num << uart8250_reg_shift; + + if (uart8250_reg_width == 1) + return readb(uart8250_base + offset); + else if (uart8250_reg_width == 2) + return readw(uart8250_base + offset); + else + return readl(uart8250_base + offset); +} + +static void set_reg(uint32_t num, uint32_t val) +{ + uint32_t offset = num << uart8250_reg_shift; + + if (uart8250_reg_width == 1) + writeb(val, uart8250_base + offset); + else if (uart8250_reg_width == 2) + writew(val, uart8250_base + offset); + else + writel(val, uart8250_base + offset); +} + +void uart8250_configure() { + uint16_t bdiv; + bdiv = uart8250_in_freq / (16 * uart8250_baudrate); + + /* Map memory */ + uart8250_base = (void *) map_anywhere_with_dynamic_page_table((uintptr_t) uart8250_base, 0x1000); + + /* Disable all interrupts */ + set_reg(UART_IER_OFFSET, 0x00); + /* Enable DLAB */ + set_reg(UART_LCR_OFFSET, 0x80); + + if (bdiv) { + /* Set divisor low byte */ + set_reg(UART_DLL_OFFSET, bdiv & 0xff); + /* Set divisor high byte */ + set_reg(UART_DLM_OFFSET, (bdiv >> 8) & 0xff); + } + + /* 8 bits, no parity, one stop bit */ + set_reg(UART_LCR_OFFSET, 0x03); + /* Enable FIFO */ + set_reg(UART_FCR_OFFSET, 0x01); + /* No modem control DTR RTS */ + set_reg(UART_MCR_OFFSET, 0x00); + /* Clear line status */ + get_reg(UART_LSR_OFFSET); + /* Read receive buffer */ + get_reg(UART_RBR_OFFSET); + /* Set scratchpad */ + set_reg(UART_SCR_OFFSET, 0x00); +} + +void uart8250_putc(char ch) +{ + if(!configured) { + uart8250_configure(); + configured = true; + } + + while ((get_reg(UART_LSR_OFFSET) & UART_LSR_THRE) == 0) + ; + + set_reg(UART_THR_OFFSET, ch); +} + +int uart8250_getc(void) +{ + if(!configured) { + uart8250_configure(); + configured = true; + } + + if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR) + return get_reg(UART_RBR_OFFSET); + return -1; +} + +/** + * + * + * EAPP-DRIVER INTERFACE DEFINITION + * + * + */ +#define UART8250_BUF_SIZE 512 +char uart8250_buf[UART8250_BUF_SIZE]; + +int uart8250_init(void); +size_t uart8250_write(void* buf, size_t len); +size_t uart8250_read(void* buf, size_t len); + +driver_instance uart8250_driver = { + .name = "uart8250", + .init = uart8250_init, + .fini = NULL, + .read = uart8250_read, + .write = uart8250_write +}; + +int uart8250_init() { + /* + * initialize serial: + uart@10001000 { + interrupts = <0x09>; + interrupt-parent = <0x03>; + clock-frequency = "\08@"; + compatible = "ns16550a"; + status = "disabled"; + reg = <0x00 0x10001000 0x00 0x100>; + secure-status = "okay"; + }; + */ + + // constants for now, based on above + uart8250_base = (volatile void*)0x10001000; + uart8250_reg_shift = 0x0; + uart8250_reg_width = 0x1; + uart8250_in_freq = 0x384000; + uart8250_baudrate = 0x1c200; + + print_strace("!!! uart8250_init completed\n"); + return 0; +} + +size_t uart8250_write(void* buf, size_t len) { + size_t to_write = len >= UART8250_BUF_SIZE ? UART8250_BUF_SIZE : len; + copy_from_user(uart8250_buf, buf, to_write); + for (size_t i = 0; i < to_write; i += 1) { + uart8250_putc(uart8250_buf[i]); + } + return to_write; +} + +size_t uart8250_read(void* buf, size_t len) { + size_t to_read = len >= UART8250_BUF_SIZE ? UART8250_BUF_SIZE : len; + + size_t i = 0; + int c = 0; + for (; i < to_read && c != -1; i += 1) { + int c = uart8250_getc(); + if (c != -1) { + uart8250_buf[i] = (char)c; + } + } + copy_to_user(buf, uart8250_buf, i); + return i; +} diff --git a/runtime/include/call/sbi.h b/runtime/include/call/sbi.h index 03d40ec56..d5f714e69 100644 --- a/runtime/include/call/sbi.h +++ b/runtime/include/call/sbi.h @@ -28,5 +28,9 @@ uintptr_t sbi_attest_enclave(void* report, void* buf, uintptr_t len); uintptr_t sbi_get_sealing_key(uintptr_t key_struct, uintptr_t key_ident, uintptr_t len); +uintptr_t +sbi_claim_mmio(uintptr_t dev_string); +uintptr_t +sbi_release_mmio(uintptr_t dev_string); #endif diff --git a/runtime/include/drivers/drivers.h b/runtime/include/drivers/drivers.h new file mode 100644 index 000000000..2cdb56f14 --- /dev/null +++ b/runtime/include/drivers/drivers.h @@ -0,0 +1,40 @@ +#ifndef _DRIVERS_H_ +#define _DRIVERS_H_ + +#include +#include +#include + +#define DRIVER_NAME_MAX_LEN 32 + +typedef struct _driver { + char name[DRIVER_NAME_MAX_LEN]; + int (*init)(void); + int (*fini)(void); + size_t (*read)(void*, size_t); + size_t (*write)(void*, size_t); +} driver; + +/** + * @brief + * Use the "driver_instance" macro to simultaneously define a new + * driver struct and also add it to the eyrie-rt binary. + */ + +#define driver_instance __attribute__((section(".drivers"))) driver + +int init_driver_subsystem(); + +int init_driver(char *name); + +int fini_driver(char *name); + +uintptr_t drivers_openat_override(int dirfd, char* path, int flags, mode_t mode); + +uintptr_t drivers_close_override(int fd); + +uintptr_t drivers_read_override(int fd, void* buf, size_t len); + +uintptr_t drivers_write_override(int fd, void* buf, size_t len); + +#endif // _DRIVERS_H_ diff --git a/runtime/include/mm/mm.h b/runtime/include/mm/mm.h index c326640d4..011b53ca4 100644 --- a/runtime/include/mm/mm.h +++ b/runtime/include/mm/mm.h @@ -1,5 +1,7 @@ #ifndef _MM_H_ #define _MM_H_ + +#include #include #include @@ -14,10 +16,14 @@ void free_page(uintptr_t vpn); size_t alloc_pages(uintptr_t vpn, size_t count, int flags); void free_pages(uintptr_t vpn, size_t count); size_t test_va_range(uintptr_t vpn, size_t count); +uintptr_t find_va_range(size_t count); uintptr_t get_program_break(); void set_program_break(uintptr_t new_break); +uintptr_t map_with_dynamic_page_table(uintptr_t base, uintptr_t size, uintptr_t va, bool user); +uintptr_t map_anywhere_with_dynamic_page_table(uintptr_t base, uintptr_t size); void map_with_reserved_page_table(uintptr_t base, uintptr_t size, uintptr_t ptr, pte* l2_pt, pte* l3_pt); +void unmap_with_any_page_table(uintptr_t base, uintptr_t size); #endif /* _MM_H_ */ diff --git a/runtime/loader-binary/CMakeLists.txt b/runtime/loader-binary/CMakeLists.txt index 03c86ebd6..d5a86e31e 100644 --- a/runtime/loader-binary/CMakeLists.txt +++ b/runtime/loader-binary/CMakeLists.txt @@ -3,7 +3,7 @@ set(LOADER_SOURCES loader.S loader-binary.c) set(LOADER_LINK_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/loader.lds) add_executable(loader ${LOADER_SOURCES}) -target_link_libraries(loader rt_call ld_mm rt_util rt_loader gcc) +target_link_libraries(loader rt_call ld_mm rt_util rt_tmplib rt_loader gcc) target_link_options(loader PRIVATE -static -nostdlib -T ${LOADER_LINK_SCRIPT}) add_custom_target(loader.bin ALL diff --git a/runtime/mm/mm.c b/runtime/mm/mm.c index 280c9c1c0..318273372 100644 --- a/runtime/mm/mm.c +++ b/runtime/mm/mm.c @@ -3,6 +3,7 @@ #include "mm/vm.h" #include "mm/freemem.h" #include "mm/paging.h" +#include "util/rt_util.h" /* Page table utilities */ static pte* @@ -126,15 +127,14 @@ realloc_page(uintptr_t vpn, int flags) return 0; } -void -free_page(uintptr_t vpn) +uintptr_t +unmap_page(uintptr_t vpn) { - pte* pte = __walk(root_page_table, vpn << RISCV_PAGE_BITS); // No such PTE, or invalid if(!pte || !(*pte & PTE_V)) - return; + return 0; assert(*pte & PTE_U); @@ -142,15 +142,20 @@ free_page(uintptr_t vpn) // Mark invalid // TODO maybe do more here *pte = 0; + return ppn; +} +void +free_page(uintptr_t vpn){ + uintptr_t ppn = unmap_page(vpn); + + if(ppn) { #ifdef USE_PAGING - paging_dec_user_page(); + paging_dec_user_page(); #endif - // Return phys page - spa_put(__va(ppn << RISCV_PAGE_BITS)); - - return; - + // Return phys page + spa_put(__va(ppn << RISCV_PAGE_BITS)); + } } /* allocate n new pages from a given vpn @@ -196,6 +201,30 @@ test_va_range(uintptr_t vpn, size_t count){ return i; } +static uintptr_t curr_avail_vpn = 0; + +uintptr_t find_va_range(size_t count) { + if(!curr_avail_vpn) + curr_avail_vpn = vpn(EYRIE_ANON_REGION_START); + + uintptr_t vpn = curr_avail_vpn; + uintptr_t valid_pages; + + while((vpn + count) <= EYRIE_ANON_REGION_END){ + valid_pages = test_va_range(vpn, count); + + if(count == valid_pages){ + // Set a successful value if we allocate + curr_avail_vpn = vpn + count; + return vpn; + } + else + vpn += valid_pages + 1; + } + + return 0; +} + /* get a mapped physical address for a VA */ uintptr_t translate(uintptr_t va) @@ -216,6 +245,54 @@ pte_of_va(uintptr_t va) return pte; } +uintptr_t map_with_dynamic_page_table(uintptr_t base, uintptr_t size, uintptr_t va, bool user) { + // Base is PA, ptr is VA + unsigned int i; + pte *pte; + + for(i = 0; i < size; i += RISCV_PAGE_SIZE) { + // Below function will always return a pte, but it may be a preexisting one + // which would indicate that this virtual address range is already mapped. + // This is a situation we would not normally expect to see, since find_va_range + // above is supposed to return unallocated virtual address space. Dealing + // with this is complicated, so for now we just assert on this not being the + // case. However, correctly handling this is definitely a TODO + + pte = __walk_create(root_page_table, va + i); + assert(!(*pte & PTE_V)); + + *pte = pte_create(ppn(base + i), PTE_W | PTE_R | PTE_X | PTE_D | PTE_A | + (user ? PTE_U : 0)); + } + + tlb_flush(); + return va; +} + +uintptr_t map_anywhere_with_dynamic_page_table(uintptr_t base, uintptr_t size) +{ + uintptr_t virt_pagenum = find_va_range(vpn(PAGE_UP(size))); + if(virt_pagenum) { + return map_with_dynamic_page_table(base, size, + (virt_pagenum << RISCV_PAGE_BITS), false); + } else { + return 0; + } +} + +void unmap_with_any_page_table(uintptr_t base, uintptr_t size) { + int i; + uintptr_t ppn; + + for(i = 0; i < size; i += RISCV_PAGE_SIZE) { + ppn = unmap_page(vpn(base + i)); + + // If no ppn was returned, this was not a valid page mapping + assert(ppn); + } + + tlb_flush(); +} void __map_with_reserved_page_table_32(uintptr_t dram_base, @@ -315,5 +392,7 @@ map_with_reserved_page_table(uintptr_t dram_base, else __map_with_reserved_page_table_32(dram_base, dram_size, ptr, l2_pt); #endif + + tlb_flush(); } diff --git a/runtime/runtime.ld.S b/runtime/runtime.ld.S index d0e6245cc..d62d36243 100644 --- a/runtime/runtime.ld.S +++ b/runtime/runtime.ld.S @@ -25,5 +25,13 @@ SECTIONS PROVIDE(kernel_stack_end = .); } +#ifdef USE_DRIVERS + .drivers : { + PROVIDE(drivers_start = .); + *(.drivers) + PROVIDE(drivers_end = .); + } +#endif + _end = .; } diff --git a/runtime/sys/CMakeLists.txt b/runtime/sys/CMakeLists.txt index 54d445d83..0cb7fd104 100644 --- a/runtime/sys/CMakeLists.txt +++ b/runtime/sys/CMakeLists.txt @@ -6,7 +6,7 @@ add_executable(eyrie-build EXCLUDE_FROM_ALL ${SYS_SOURCES}) # required by one library are defined by the time that it is added to this list target_link_libraries(eyrie-build - rt_call rt_mm rt_crypto rt_tmplib rt_util rt_loader + rt_call rt_mm rt_crypto rt_drivers rt_tmplib rt_util rt_loader gcc ${KEYSTONE_SDK_DIR}/lib/libkeystone-edge.a) target_link_options(eyrie-build PRIVATE -static -nostdlib -T $) add_dependencies(eyrie-build rt_linkscript) diff --git a/runtime/sys/boot.c b/runtime/sys/boot.c index 1310e3017..e0c0da04b 100644 --- a/runtime/sys/boot.c +++ b/runtime/sys/boot.c @@ -13,6 +13,10 @@ #include "loader/elf.h" #include "loader/loader.h" +#ifdef USE_DRIVERS +#include "drivers/drivers.h" +#endif + /* defined in vm.h */ extern uintptr_t shared_buffer; extern uintptr_t shared_buffer_size; @@ -134,6 +138,11 @@ eyrie_boot(uintptr_t dummy, // $a0 contains the return value from the SBI /* set timer */ init_timer(); +#ifdef USE_DRIVERS + /* initialize any drivers included in the .drivers section */ + init_driver_subsystem(); +#endif + /* Enable the FPU */ csr_write(sstatus, csr_read(sstatus) | 0x6000); diff --git a/sdk/include/app/syscall.h b/sdk/include/app/syscall.h index 29db83b67..c4d22d875 100644 --- a/sdk/include/app/syscall.h +++ b/sdk/include/app/syscall.h @@ -53,4 +53,7 @@ get_sealing_key( struct sealing_key* sealing_key_struct, size_t sealing_key_struct_size, void* key_ident, size_t key_ident_size); +int claim_mmio(const char *devname, size_t namelen); +int release_mmio(const char *devname, size_t namelen); + #endif /* syscall.h */ diff --git a/sdk/include/shared/eyrie_call.h b/sdk/include/shared/eyrie_call.h index c50520286..34807ef49 100644 --- a/sdk/include/shared/eyrie_call.h +++ b/sdk/include/shared/eyrie_call.h @@ -6,6 +6,8 @@ #define RUNTIME_SYSCALL_SHAREDCOPY 1002 #define RUNTIME_SYSCALL_ATTEST_ENCLAVE 1003 #define RUNTIME_SYSCALL_GET_SEALING_KEY 1004 +#define RUNTIME_SYSCALL_CLAIM_MMIO 1005 +#define RUNTIME_SYSCALL_RELEASE_MMIO 1006 #define RUNTIME_SYSCALL_EXIT 1101 #endif // __EYRIE_CALL_H__ diff --git a/sdk/include/shared/sm_call.h b/sdk/include/shared/sm_call.h index b9d8f959a..3129c2e2d 100644 --- a/sdk/include/shared/sm_call.h +++ b/sdk/include/shared/sm_call.h @@ -23,6 +23,8 @@ #define SBI_SM_GET_SEALING_KEY 3003 #define SBI_SM_STOP_ENCLAVE 3004 #define SBI_SM_EXIT_ENCLAVE 3006 +#define SBI_SM_CLAIM_MMIO 3007 +#define SBI_SM_RELEASE_MMIO 3008 #define FID_RANGE_ENCLAVE 3999 /* 4000-4999 are experimental */ diff --git a/sdk/src/app/syscall.c b/sdk/src/app/syscall.c index 385b42387..33103cef6 100644 --- a/sdk/src/app/syscall.c +++ b/sdk/src/app/syscall.c @@ -33,3 +33,11 @@ get_sealing_key( sealing_key_struct, sealing_key_struct_size, key_ident, key_ident_size); } + +int claim_mmio(const char *devname, size_t namelen) { + return SYSCALL_2(RUNTIME_SYSCALL_CLAIM_MMIO, devname, namelen); +} + +int release_mmio(const char *devname, size_t namelen) { + return SYSCALL_2(RUNTIME_SYSCALL_RELEASE_MMIO, devname, namelen); +} diff --git a/sm/plat/fpga/ariane/platform.c b/sm/plat/fpga/ariane/platform.c index eda5b2f2c..b43ff25e8 100644 --- a/sm/plat/fpga/ariane/platform.c +++ b/sm/plat/fpga/ariane/platform.c @@ -73,12 +73,11 @@ static int ariane_early_init(bool cold_boot) */ static int ariane_final_init(bool cold_boot) { - void *fdt; - sm_init(cold_boot); + void *fdt = fdt_get_address(); + sm_init(cold_boot, fdt); if (!cold_boot) return 0; - fdt = fdt_get_address(); fdt_fixups(fdt); return 0; diff --git a/sm/plat/generic/generic.c b/sm/plat/generic/generic.c index 8385855cc..1fd765109 100644 --- a/sm/plat/generic/generic.c +++ b/sm/plat/generic/generic.c @@ -6,7 +6,7 @@ #include "sm.h" static int generic_final_init(bool cold_boot, const struct fdt_match *match) { - sm_init(cold_boot); + sm_init(cold_boot, sbi_scratch_thishart_arg1_ptr()); return 0; } diff --git a/sm/plat/hifive/unmatched/unmatched.c b/sm/plat/hifive/unmatched/unmatched.c index c5372228a..e89b38752 100644 --- a/sm/plat/hifive/unmatched/unmatched.c +++ b/sm/plat/hifive/unmatched/unmatched.c @@ -2,7 +2,7 @@ #include "sm.h" static int unmatched_final_init(bool cold_boot, const struct fdt_match *match) { - sm_init(cold_boot); + sm_init(cold_boot, fdt_get_address()); return sifive_fu740_final_init(cold_boot, match); } diff --git a/sm/src/device.c b/sm/src/device.c new file mode 100644 index 000000000..515e21d43 --- /dev/null +++ b/sm/src/device.c @@ -0,0 +1,354 @@ +#include "device.h" +#include "sbi/sbi_console.h" +#include "sbi/riscv_asm.h" + +#include +#include + +#ifndef TARGET_PLATFORM_HEADER +#error "SM requires a defined platform to build" +#endif + +// Special target platform header, set by configure script +#include TARGET_PLATFORM_HEADER + +#define IS_SECURE_DEVICE \ + (!strcmp(status, "disabled") && !strcmp(secure_status, "okay")) + +#define IS_NONSECURE_DEVICE \ + (!strcmp(status, "okay") && !strcmp(secure_status, "disabled")) + +#define IS_DISABLED_DEVICE \ + (!strcmp(status, "disabled") && !strcmp(secure_status, "disabled")) + +// By default, search the device tree at /soc (can be overriden) +#ifndef DEV_SEARCH_BASE +#define DEV_SEARCH_BASE "/soc" +#endif + +// Ignore some compatibles if requested by the platform +#ifdef DEV_IGNORED +#include +static const char *ignored_compatibles[] = DEV_IGNORED; +#endif + +struct keystone_device +{ + char devname[DEV_NAMELEN]; + region_id region_id; + bool claimed; +}; + +/* device handling */ +static int num_secure_devs = 0; +static int num_nonsecure_devs = 0; +static int num_disabled_devs = 0; + +#if NUM_SECURE_DEVS +static struct keystone_device secure_devs[NUM_SECURE_DEVS]; +#endif // NUM_SECURE_DEVS + +#if NUM_NONSECURE_DEVS +static struct keystone_device nonsecure_devs[NUM_NONSECURE_DEVS]; +#endif // NUM_NONSECURE_DEVS + +#if NUM_DISABLED_DEVS +static struct keystone_device disabled_devs[NUM_DISABLED_DEVS]; +#endif // NUM_NONSECURE_DEVS + +int fdt_init_pmp_devices(void *fdt) { + int i, ret, status_len, secure_status_len, name_len; + const char *status, *secure_status, *name; + const uint32_t *reg; + +#ifdef DEV_IGNORED + int compatible_len; + const char *compatible; +#endif + + // Device tree variables + int bus_offset, dev_offset, addr_cells, size_cells; + + // MMIO variables + region_id region; + uintptr_t mmio_addr; + uint64_t mmio_size; + + // Clear the state +#if NUM_SECURE_DEVS + memset(secure_devs, 0, sizeof(secure_devs)); +#endif // NUM_SECURE_DEVS + +#if NUM_NONSECURE_DEVS + memset(nonsecure_devs, 0, sizeof(nonsecure_devs)); +#endif // NUM_NONSECURE_DEVS + +#if NUM_DISABLED_DEVS + memset(disabled_devs, 0, sizeof(disabled_devs)); +#endif // NUM_DISABLED_DEVS + + bus_offset = fdt_path_offset(fdt, DEV_SEARCH_BASE); + + // These return defaults if nothing is specified + addr_cells = fdt_address_cells(fdt, bus_offset); + size_cells = fdt_size_cells(fdt, bus_offset); + + fdt_for_each_subnode(dev_offset, fdt, bus_offset) { +#ifdef DEV_IGNORED + // Check if we should ignore this device + compatible = fdt_getprop(fdt, dev_offset, "compatible", &compatible_len); + if(compatible) { + // A device without a compatible string would not be accesible by Linux, since these strings + // determine what driver to load. To that extent, it seems likely that such devices would + // potentially be mapped by an enclave. Therefore, if there is no compatible string, we + // choose to continue parsing in case it is a device we need to handle + + for(i = 0; i < array_size(ignored_compatibles); i++) { + if(!strcmp(compatible, ignored_compatibles[i])) { + break; + } + } + + if(i != array_size(ignored_compatibles)) + continue; + } +#endif + + // We follow the spec for secure nodes defined in the Linux kernel, + // under Documentation/devicetree/bindings/arm/secure.txt. + status = fdt_getprop(fdt, dev_offset, "status", &status_len); + if(!status) + status = "okay"; + + secure_status = fdt_getprop(fdt, dev_offset, "secure-status", &secure_status_len); + if(!secure_status) + secure_status = status; + + // We only care about devices which are explicitly mapped into one world + // (secure or nonsecure) or no worlds at all (fully disabled). The vast + // majority of devices do not have status specified, which means that they + // are enabled in both the secure and nonsecure worlds and we do not + // specifically need to manage them through PMP. + + if(IS_SECURE_DEVICE || IS_NONSECURE_DEVICE || IS_DISABLED_DEVICE) { + // This is a node which we need to register + name = fdt_get_name(fdt, dev_offset, &name_len); + if(!name || name_len >= DEV_NAMELEN) { + goto _fail; + } + + // Get the associated MMIO addresses + reg = fdt_getprop(fdt, dev_offset, "reg", &ret); + + // We only support one MMIO region per device for now, with the standard + // address-cells and size-cells specified at the root of the fdt. Otherwise, + // things get a bit more complicated than OpenSBI's FDT library is designed for. + if(!reg || ret != 4 * (addr_cells + size_cells)) { + sbi_printf("[SM] device %s has more than one MMIO region, which is currently unsupported\n", name); + continue; + } + + mmio_addr = 0; + for(i = 0; i < addr_cells; i++) { + mmio_addr |= (fdt32_to_cpu(reg[i]) + << (32 * (addr_cells - i - 1))); + } + + mmio_size = 0; + for(i = 0; i < size_cells; i++) { + mmio_size |= (fdt32_to_cpu(reg[addr_cells + i]) + << (32 * (size_cells - i - 1))); + } + + ret = pmp_region_init_atomic(mmio_addr, ROUNDUP(mmio_size, PAGE_SIZE), + PMP_PRI_ANY, ®ion, 0); + if(ret) { + goto _fail; + } + + if(IS_SECURE_DEVICE) { + if(num_secure_devs >= NUM_SECURE_DEVS) { + sbi_printf("[SM] too many secure devices specified\n"); + goto _fail; + } + +#if NUM_SECURE_DEVS + strcpy(secure_devs[num_secure_devs].devname, name); + secure_devs[num_secure_devs].region_id = region; + num_secure_devs++; +#endif // NUM_SECURE_DEVS + } else if(IS_NONSECURE_DEVICE) { + if(num_nonsecure_devs >= NUM_NONSECURE_DEVS) { + sbi_printf("[SM] too many nonsecure devices specified\n"); + goto _fail; + } + +#if NUM_NONSECURE_DEVS + strcpy(nonsecure_devs[num_nonsecure_devs].devname, name); + nonsecure_devs[num_nonsecure_devs].region_id = region; + num_nonsecure_devs++; +#endif // NUM_NONSECURE_DEVS + } else if(IS_DISABLED_DEVICE) { + if(num_disabled_devs >= NUM_DISABLED_DEVS) { + sbi_printf("[SM] too many disabled devices specified\n"); + goto _fail; + } + +#if NUM_DISABLED_DEVS + strcpy(disabled_devs[num_disabled_devs].devname, name); + disabled_devs[num_disabled_devs].region_id = region; + num_disabled_devs++; +#endif // NUM_DISABLED_DEVS + } + } + } + + return 0; + +_fail: + num_secure_devs = 0; + return -1; +} + + +region_id sm_claim_secure_device(const char *devname) +{ + __attribute__((unused)) int i; + if(!devname) { + return -1; + } + +#if NUM_SECURE_DEVS + for(i = 0; i < MIN(num_secure_devs, NUM_SECURE_DEVS); i++) { + if(strcmp(secure_devs[i].devname, devname) == 0) { + if(!secure_devs[i].claimed) { + secure_devs[i].claimed = true; + return secure_devs[i].region_id; + } + } + } +#endif // NUM_SECURE_DEVS + + // no match + return -1; +} + +region_id sm_release_secure_device(const char *devname) +{ + __attribute__((unused)) int i; + if(!devname) { + return -1; + } + +#if NUM_SECURE_DEVS + for(i = 0; i < MIN(num_secure_devs, NUM_SECURE_DEVS); i++) { + if(strcmp(secure_devs[i].devname, devname) == 0) { + if(secure_devs[i].claimed) { + secure_devs[i].claimed = false; + return 0; + } else { + sbi_printf("[SM] attempting to release unclaimed secure device\n"); + return -1; + } + } + } +#endif // NUM_SECURE_DEVS + + // no match + return -1; +} + +int device_switch_to_enclave(void) { + // Here, we need to only disable all nonsecure devices. Enclaves will then + // specifically enable the secure devices which they have claimed. + __attribute__((unused)) int i, ret; + +#if NUM_NONSECURE_DEVS + for(i = 0; i < MIN(num_nonsecure_devs, NUM_NONSECURE_DEVS); i++) { + ret = pmp_set_keystone(nonsecure_devs[i].region_id, PMP_NO_PERM); + if(ret != SBI_ERR_SM_PMP_SUCCESS) { + return -1; + } + } +#endif // NUM_NONSECURE_DEVS + +#if NUM_DISABLED_DEVS + // Ensure disable devices are still disabled + for(i = 0; i < MIN(num_disabled_devs, NUM_DISABLED_DEVS); i++) { + ret = pmp_set_keystone(disabled_devs[i].region_id, PMP_NO_PERM); + if(ret != SBI_ERR_SM_PMP_SUCCESS) { + return -1; + } + } +#endif // NUM_DISABLED_DEVS + + return 0; +} + +int device_switch_to_host(void) { + // Here, we need to disable all secure devices and enable all nonsecure + // devices. Some of these secure devices will be re-disabled by functions + // such as context_switch_to_host, but this is okay. + __attribute__((unused)) int i, ret; + +#if NUM_SECURE_DEVS + for(i = 0; i < MIN(num_secure_devs, NUM_SECURE_DEVS); i++) { + ret = pmp_set_keystone(secure_devs[i].region_id, PMP_NO_PERM); + if(ret != SBI_ERR_SM_PMP_SUCCESS) { + return -1; + } + } +#endif // NUM_SECURE_DEVS + +#if NUM_NONSECURE_DEVS + for(i = 0; i < MIN(num_nonsecure_devs, NUM_NONSECURE_DEVS); i++) { + ret = pmp_set_keystone(nonsecure_devs[i].region_id, PMP_ALL_PERM); + if(ret != SBI_ERR_SM_PMP_SUCCESS) { + return -1; + } + } +#endif // NUM_NONSECURE_DEVS + + // Ensure disable devices are still disabled +#if NUM_DISABLED_DEVS + for(i = 0; i < MIN(num_disabled_devs, NUM_DISABLED_DEVS); i++) { + ret = pmp_set_keystone(disabled_devs[i].region_id, PMP_NO_PERM); + if(ret != SBI_ERR_SM_PMP_SUCCESS) { + return -1; + } + } +#endif // NUM_DISABLED_DEVS + + return 0; +} + +const char *device_name_from_region(region_id rid) { + __attribute__((unused)) int i; + +#if NUM_SECURE_DEVS + for(i = 0; i < MIN(num_secure_devs, NUM_SECURE_DEVS); i++) { + if(secure_devs[i].region_id == rid) { + return secure_devs[i].devname; + } + } +#endif // NUM_SECURE_DEVS + + return NULL; +} + +region_id region_from_device_name(const char *devname) { + __attribute__((unused)) int i; + if(!devname) { + return -1; + } + +#if NUM_SECURE_DEVS + for(i = 0; i < MIN(num_secure_devs, NUM_SECURE_DEVS); i++) { + if(strcmp(secure_devs[i].devname, devname) == 0) { + return secure_devs[i].region_id; + } + } +#endif // NUM_SECURE_DEVS + + return -1; +} diff --git a/sm/src/device.h b/sm/src/device.h new file mode 100644 index 000000000..a08bb12c8 --- /dev/null +++ b/sm/src/device.h @@ -0,0 +1,22 @@ +#ifndef _DEVICE_H_ +#define _DEVICE_H_ + +#include "pmp.h" + +/* exported functions */ + +// initialization +int fdt_init_pmp_devices(void *fdt); + +// control +region_id sm_claim_secure_device(const char *devname); +region_id sm_release_secure_device(const char *devname); + +int device_switch_to_enclave(void); +int device_switch_to_host(void); + +// internal utility. these are only implemented for secure devices +const char *device_name_from_region(region_id rid); +region_id region_from_device_name(const char *devname); + +#endif //_DEVICE_H_ diff --git a/sm/src/enclave.c b/sm/src/enclave.c index 35e423889..309beaef7 100644 --- a/sm/src/enclave.c +++ b/sm/src/enclave.c @@ -2,6 +2,7 @@ // Copyright (c) 2018, The Regents of the University of California (Regents). // All Rights Reserved. See LICENSE for license details. //------------------------------------------------------------------------------ +#include "device.h" #include "enclave.h" #include "mprv.h" #include "pmp.h" @@ -84,6 +85,9 @@ static inline void context_switch_to_enclave(struct sbi_trap_regs* regs, } } + // ensure nonsecure-only devices are unmapped + device_switch_to_enclave(); + // Setup any platform specific defenses platform_switch_to_enclave(&(enclaves[eid])); cpu_enter_enclave_context(eid); @@ -93,6 +97,9 @@ static inline void context_switch_to_host(struct sbi_trap_regs *regs, enclave_id eid, int return_on_resume){ + // ensure nonsecure-only devices are remapped + device_switch_to_host(); + // set PMP int memid; for(memid=0; memid < ENCLAVE_REGIONS_MAX; memid++) { @@ -474,17 +481,25 @@ unsigned long destroy_enclave(enclave_id eid) region_id rid; for(i = 0; i < ENCLAVE_REGIONS_MAX; i++){ if(enclaves[eid].regions[i].type == REGION_INVALID || - enclaves[eid].regions[i].type == REGION_UTM) + enclaves[eid].regions[i].type == REGION_UTM) { continue; - //1.a Clear all pages - rid = enclaves[eid].regions[i].pmp_rid; - base = (void*) pmp_region_get_addr(rid); - size = (size_t) pmp_region_get_size(rid); - sbi_memset((void*) base, 0, size); + } - //1.b free pmp region - pmp_unset_global(rid); - pmp_region_free_atomic(rid); + rid = enclaves[eid].regions[i].pmp_rid; + if(enclaves[eid].regions[i].type == REGION_EPM) { + //1.a Clear all pages + base = (void*) pmp_region_get_addr(rid); + size = (size_t) pmp_region_get_size(rid); + sbi_memset((void*) base, 0, size); + + //1.b free pmp region + pmp_unset_global(rid); + pmp_region_free_atomic(rid); + } else if (enclaves[eid].regions[i].type == REGION_MMIO) { + // todo: reset the hardware device so that state is not leaked + // for now, just release the device + sm_release_secure_device(device_name_from_region(enclaves[eid].regions[i].pmp_rid)); + } } // 2. free pmp region for UTM @@ -680,3 +695,44 @@ unsigned long get_sealing_key(uintptr_t sealing_key, uintptr_t key_ident, return SBI_ERR_SM_ENCLAVE_SUCCESS; } + +unsigned long claim_mmio(uintptr_t dev_string, enclave_id eid) { + int i; + region_id rid; + + for(i = 0; i < ENCLAVE_REGIONS_MAX; i++) { + if(enclaves[eid].regions[i].type == REGION_INVALID) { + // Find the region now that we know we have a slot for it + rid = sm_claim_secure_device((const char *) dev_string); + if(rid < 0) { + return rid; + } + + // Register this region + enclaves[eid].regions[i].pmp_rid = rid; + enclaves[eid].regions[i].type = REGION_MMIO; + return 0; + } + } + + // No free regions found + return -1; +} + +unsigned long release_mmio(uintptr_t dev_string, enclave_id eid) { + int i; + region_id rid = region_from_device_name((const char *) dev_string); + + for(i = 0; i < ENCLAVE_REGIONS_MAX; i++) { + if(enclaves[eid].regions[i].type == REGION_MMIO && enclaves[eid].regions[i].pmp_rid == rid) { + // This is the correct region to deregister + sm_release_secure_device((const char *) dev_string); + enclaves[eid].regions[i].pmp_rid = -1; + enclaves[eid].regions[i].type = REGION_INVALID; + return 0; + } + } + + // Could not find the region to release + return -1; +} diff --git a/sm/src/enclave.h b/sm/src/enclave.h index 0399a4d3d..4b43ea37b 100644 --- a/sm/src/enclave.h +++ b/sm/src/enclave.h @@ -36,6 +36,7 @@ typedef unsigned int enclave_id; /* Metadata around memory regions associate with this enclave * EPM is the 'home' for the enclave, contains runtime code/etc * UTM is the untrusted shared pages + * MMIO is secure device space managed by the SM * OTHER is managed by some other component (e.g. platform_) * INVALID is an unused index */ @@ -43,6 +44,7 @@ enum enclave_region_type{ REGION_INVALID, REGION_EPM, REGION_UTM, + REGION_MMIO, REGION_OTHER, }; @@ -125,6 +127,8 @@ int get_enclave_region_index(enclave_id eid, enum enclave_region_type type); uintptr_t get_enclave_region_base(enclave_id eid, int memid); uintptr_t get_enclave_region_size(enclave_id eid, int memid); unsigned long get_sealing_key(uintptr_t seal_key, uintptr_t key_ident, size_t key_ident_size, enclave_id eid); +unsigned long claim_mmio(uintptr_t dev_string, enclave_id eid); +unsigned long release_mmio(uintptr_t dev_string, enclave_id eid); // interrupt handlers void sbi_trap_handler_keystone_enclave(struct sbi_trap_regs *regs); #endif diff --git a/sm/src/objects.mk b/sm/src/objects.mk index 6fa93c52c..1dca4d5f2 100644 --- a/sm/src/objects.mk +++ b/sm/src/objects.mk @@ -30,7 +30,7 @@ keystone-sm-headers += plugins/multimem.h plugins/plugins.h # Core files keystone-sm-sources += attest.c cpu.c enclave.c pmp.c sm.c sm-sbi.c sm-sbi-opensbi.c \ - thread.c mprv.c sbi_trap_hack.c trap.c ipi.c + thread.c mprv.c sbi_trap_hack.c trap.c ipi.c device.c # Crypto ifneq ($(KEYSTONE_SM_NO_CRYPTO),y) diff --git a/sm/src/platform/fpga/ariane/platform.h b/sm/src/platform/fpga/ariane/platform.h index 09fa7841f..dbbcdfb1c 100644 --- a/sm/src/platform/fpga/ariane/platform.h +++ b/sm/src/platform/fpga/ariane/platform.h @@ -22,6 +22,11 @@ struct platform_enclave_data{ // CPU configuration #define MAX_HARTS 5 +// Device configuration +#define DEV_NAMELEN 64 +#define NUM_SECURE_DEVS 8 +#define NUM_NONSECURE_DEVS 8 +#define NUM_DISABLED_DEVS 8 // Initialization functions void sm_copy_key(void); diff --git a/sm/src/platform/generic/platform.h b/sm/src/platform/generic/platform.h index 7270378ce..cfe6bac79 100644 --- a/sm/src/platform/generic/platform.h +++ b/sm/src/platform/generic/platform.h @@ -22,6 +22,12 @@ struct platform_enclave_data{ // CPU configuration #define MAX_HARTS 16 +// Device configuration +#define DEV_NAMELEN 64 +#define NUM_SECURE_DEVS 8 +#define NUM_NONSECURE_DEVS 8 +#define NUM_DISABLED_DEVS 8 + // Initialization functions void sm_copy_key(void); diff --git a/sm/src/platform/mpfs/platform.h b/sm/src/platform/mpfs/platform.h index 5e9ddaf2e..38189c548 100644 --- a/sm/src/platform/mpfs/platform.h +++ b/sm/src/platform/mpfs/platform.h @@ -23,6 +23,16 @@ struct platform_enclave_data{ // CPU configuration #define MAX_HARTS 5 +// Device configuration +#define DEV_NAMELEN 64 +#define NUM_SECURE_DEVS 3 +#define NUM_NONSECURE_DEVS 0 +#define NUM_DISABLED_DEVS 0 + +// Search for FPGA devices +#define DEV_SEARCH_BASE "/fabric-bus@40000000" +#define DEV_IGNORED { "microchip,mpfs-ccc", "microchip,mpfs-qspi" } + // Initialization functions void sm_copy_key(void); diff --git a/sm/src/pmp.h b/sm/src/pmp.h index b77caf737..547befa37 100644 --- a/sm/src/pmp.h +++ b/sm/src/pmp.h @@ -5,6 +5,9 @@ #ifndef _PMP_H_ #define _PMP_H_ +typedef int pmpreg_id; +typedef int region_id; + #include "sm.h" #include @@ -82,9 +85,6 @@ struct pmp_region int reg_idx; }; -typedef int pmpreg_id; -typedef int region_id; - /* external functions */ void pmp_init(void); int pmp_region_init_atomic(uintptr_t start, uint64_t size, enum pmp_priority pri, region_id* rid, int allow_overlap); diff --git a/sm/src/sm-sbi-opensbi.c b/sm/src/sm-sbi-opensbi.c index e579fda24..ff6bd8246 100644 --- a/sm/src/sm-sbi-opensbi.c +++ b/sm/src/sm-sbi-opensbi.c @@ -58,6 +58,12 @@ static int sbi_ecall_keystone_enclave_handler(unsigned long extid, unsigned long case SBI_SM_GET_SEALING_KEY: retval = sbi_sm_get_sealing_key(regs->a0, regs->a1, regs->a2); break; + case SBI_SM_CLAIM_MMIO: + retval = sbi_sm_claim_mmio(regs->a0); + break; + case SBI_SM_RELEASE_MMIO: + retval = sbi_sm_release_mmio(regs->a0); + break; case SBI_SM_STOP_ENCLAVE: retval = sbi_sm_stop_enclave((struct sbi_trap_regs*) regs, regs->a0); __builtin_unreachable(); diff --git a/sm/src/sm-sbi.c b/sm/src/sm-sbi.c index 461643359..2669175d6 100644 --- a/sm/src/sm-sbi.c +++ b/sm/src/sm-sbi.c @@ -86,6 +86,20 @@ unsigned long sbi_sm_get_sealing_key(uintptr_t sealing_key, uintptr_t key_ident, return ret; } +unsigned long sbi_sm_claim_mmio(uintptr_t dev_string) +{ + unsigned long ret; + ret = claim_mmio(dev_string, cpu_get_enclave_id()); + return ret; +} + +unsigned long sbi_sm_release_mmio(uintptr_t dev_string) +{ + unsigned long ret; + ret = release_mmio(dev_string, cpu_get_enclave_id()); + return ret; +} + unsigned long sbi_sm_random(void) { return (unsigned long) platform_random(); diff --git a/sm/src/sm-sbi.h b/sm/src/sm-sbi.h index 13aa55112..04ef85066 100644 --- a/sm/src/sm-sbi.h +++ b/sm/src/sm-sbi.h @@ -32,6 +32,12 @@ sbi_sm_attest_enclave(uintptr_t report, uintptr_t data, uintptr_t size); unsigned long sbi_sm_get_sealing_key(uintptr_t seal_key, uintptr_t key_ident, size_t key_ident_size); +unsigned long +sbi_sm_claim_mmio(uintptr_t dev_string); + +unsigned long +sbi_sm_release_mmio(uintptr_t dev_string); + unsigned long sbi_sm_random(void); diff --git a/sm/src/sm.c b/sm/src/sm.c index 351d49848..6b3b1eef5 100644 --- a/sm/src/sm.c +++ b/sm/src/sm.c @@ -6,6 +6,7 @@ #include "sm.h" #include "pmp.h" #include +#include "device.h" #include "enclave.h" #include "platform-hook.h" #include "sm-sbi-opensbi.h" @@ -15,9 +16,11 @@ #include #include + static int sm_init_done = 0; static int sm_region_id = 0, os_region_id = 0; + #ifndef TARGET_PLATFORM_HEADER #error "SM requires a defined platform to build" #endif @@ -115,8 +118,9 @@ void sm_print_cert() } */ -void sm_init(bool cold_boot) +void sm_init(bool cold_boot, void *fdt) { + int ret; // initialize SMM if (cold_boot) { /* only the cold-booting hart will execute these */ @@ -136,6 +140,12 @@ void sm_init(bool cold_boot) sbi_hart_hang(); } + ret = fdt_init_pmp_devices(fdt); + if(ret < 0) { + sbi_printf("[SM] intolerable error - failed to initialize secured devices"); + sbi_hart_hang(); + } + if (platform_init_global_once() != SBI_ERR_SM_ENCLAVE_SUCCESS) { sbi_printf("[SM] platform global init fatal error"); sbi_hart_hang(); @@ -160,6 +170,7 @@ void sm_init(bool cold_boot) pmp_init(); pmp_set_keystone(sm_region_id, PMP_NO_PERM); pmp_set_keystone(os_region_id, PMP_ALL_PERM); + device_switch_to_host(); /* Fire platform specific global init */ if (platform_init_global() != SBI_ERR_SM_ENCLAVE_SUCCESS) { diff --git a/sm/src/sm.h b/sm/src/sm.h index 685b6808a..5c1ea25cd 100644 --- a/sm/src/sm.h +++ b/sm/src/sm.h @@ -13,7 +13,7 @@ #include "sm_call.h" #include "sm_err.h" -void sm_init(bool cold_boot); +void sm_init(bool cold_boot, void *fdt); /* platform specific functions */ #define ATTESTATION_KEY_LENGTH 64