diff -r 5b74fbd1073b -r b99183572b9d sys/arch/evbarm/fdt/fdt_machdep.c --- a/sys/arch/evbarm/fdt/fdt_machdep.c Mon May 11 02:10:19 2020 +0000 +++ b/sys/arch/evbarm/fdt/fdt_machdep.c Thu May 14 18:40:44 2020 +0000 @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -119,7 +120,8 @@ u_long uboot_args[4] __attribute__((__se const uint8_t *fdt_addr_r __attribute__((__section__(".data"))); static uint64_t initrd_start, initrd_end; -static uint64_t rndseed_start, rndseed_end; +static uint64_t rndseed_start, rndseed_end; /* our on-disk seed */ +static uint64_t efirng_start, efirng_end; /* firmware's EFI RNG output */ #include #include @@ -313,6 +315,10 @@ fdt_build_bootconfig(uint64_t mem_start, if (rndseed_size > 0) fdt_memory_remove_range(rndseed_start, rndseed_size); + const uint64_t efirng_size = efirng_end - efirng_start; + if (efirng_size > 0) + fdt_memory_remove_range(efirng_start, efirng_size); + const int framebuffer = OF_finddevice("/chosen/framebuffer"); if (framebuffer >= 0) { for (index = 0; @@ -328,20 +334,20 @@ fdt_build_bootconfig(uint64_t mem_start, } static void -fdt_probe_initrd(uint64_t *pstart, uint64_t *pend) +fdt_probe_range(const char *startname, const char *endname, + uint64_t *pstart, uint64_t *pend) { + int chosen, len; + const void *start_data, *end_data; + *pstart = *pend = 0; -#ifdef MEMORY_DISK_DYNAMIC - const int chosen = OF_finddevice("/chosen"); + chosen = OF_finddevice("/chosen"); if (chosen < 0) return; - int len; - const void *start_data = fdtbus_get_prop(chosen, - "linux,initrd-start", &len); - const void *end_data = fdtbus_get_prop(chosen, - "linux,initrd-end", NULL); + start_data = fdtbus_get_prop(chosen, startname, &len); + end_data = fdtbus_get_prop(chosen, endname, NULL); if (start_data == NULL || end_data == NULL) return; @@ -355,9 +361,46 @@ fdt_probe_initrd(uint64_t *pstart, uint6 *pend = be64dec(end_data); break; default: - printf("Unsupported len %d for /chosen/initrd-start\n", len); + printf("Unsupported len %d for /chosen/%s\n", len, startname); return; } +} + +static void * +fdt_map_range(uint64_t start, uint64_t end, uint64_t *psize, + const char *purpose) +{ + const paddr_t startpa = trunc_page(start); + const paddr_t endpa = round_page(end); + paddr_t pa; + vaddr_t va; + void *ptr; + + *psize = end - start; + if (*psize == 0) + return NULL; + + va = uvm_km_alloc(kernel_map, *psize, 0, UVM_KMF_VAONLY|UVM_KMF_NOWAIT); + if (va == 0) { + printf("Failed to allocate VA for %s\n", purpose); + return NULL; + } + ptr = (void *)(va + (start & (PAGE_SIZE-1))); + + for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) + pmap_kenter_pa(va, pa, VM_PROT_READ|VM_PROT_WRITE, 0); + pmap_update(pmap_kernel()); + + return ptr; +} + +static void +fdt_probe_initrd(uint64_t *pstart, uint64_t *pend) +{ + *pstart = *pend = 0; + +#ifdef MEMORY_DISK_DYNAMIC + fdt_probe_range("linux,initrd-start", "linux,initrd-end", pstart, pend); #endif } @@ -365,29 +408,13 @@ static void fdt_setup_initrd(void) { #ifdef MEMORY_DISK_DYNAMIC - const uint64_t initrd_size = initrd_end - initrd_start; - paddr_t startpa = trunc_page(initrd_start); - paddr_t endpa = round_page(initrd_end); - paddr_t pa; - vaddr_t va; void *md_start; - - if (initrd_size == 0) - return; + uint64_t initrd_size; - va = uvm_km_alloc(kernel_map, initrd_size, 0, - UVM_KMF_VAONLY | UVM_KMF_NOWAIT); - if (va == 0) { - printf("Failed to allocate VA for initrd\n"); + md_start = fdt_map_range(initrd_start, initrd_end, &initrd_size, + "initrd"); + if (md_start == NULL) return; - } - - md_start = (void *)va; - - for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) - pmap_kenter_pa(va, pa, VM_PROT_READ|VM_PROT_WRITE, 0); - pmap_update(pmap_kernel()); - md_root_setconf(md_start, initrd_size); #endif } @@ -395,60 +422,49 @@ fdt_setup_initrd(void) static void fdt_probe_rndseed(uint64_t *pstart, uint64_t *pend) { - int chosen, len; - const void *start_data, *end_data; - *pstart = *pend = 0; - chosen = OF_finddevice("/chosen"); - if (chosen < 0) - return; - - start_data = fdtbus_get_prop(chosen, "netbsd,rndseed-start", &len); - end_data = fdtbus_get_prop(chosen, "netbsd,rndseed-end", NULL); - if (start_data == NULL || end_data == NULL) - return; - - switch (len) { - case 4: - *pstart = be32dec(start_data); - *pend = be32dec(end_data); - break; - case 8: - *pstart = be64dec(start_data); - *pend = be64dec(end_data); - break; - default: - printf("Unsupported len %d for /chosen/rndseed-start\n", len); - return; - } + fdt_probe_range("netbsd,rndseed-start", "netbsd,rndseed-end", + pstart, pend); } static void fdt_setup_rndseed(void) { - const uint64_t rndseed_size = rndseed_end - rndseed_start; - const paddr_t startpa = trunc_page(rndseed_start); - const paddr_t endpa = round_page(rndseed_end); - paddr_t pa; - vaddr_t va; + uint64_t rndseed_size; void *rndseed; - if (rndseed_size == 0) + rndseed = fdt_map_range(rndseed_start, rndseed_end, &rndseed_size, + "rndseed"); + if (rndseed == NULL) + return; + rnd_seed(rndseed, rndseed_size); +} + +static void +fdt_probe_efirng(uint64_t *pstart, uint64_t *pend) +{ + + fdt_probe_range("netbsd,efirng-start", "netbsd,efirng-end", + pstart, pend); +} + +static struct krndsource efirng_source; + +static void +fdt_setup_efirng(void) +{ + uint64_t efirng_size; + void *efirng; + + efirng = fdt_map_range(efirng_start, efirng_end, &efirng_size, + "efirng"); + if (efirng == NULL) return; - va = uvm_km_alloc(kernel_map, endpa - startpa, 0, - UVM_KMF_VAONLY | UVM_KMF_NOWAIT); - if (va == 0) { - printf("Failed to allocate VA for rndseed\n"); - return; - } - rndseed = (void *)va; - - for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) - pmap_kenter_pa(va, pa, VM_PROT_READ|VM_PROT_WRITE, 0); - pmap_update(pmap_kernel()); - - rnd_seed(rndseed, rndseed_size); + rnd_attach_source(&efirng_source, "efirng", RND_TYPE_RNG, + RND_FLAG_DEFAULT); + rnd_add_data(&efirng_source, efirng, efirng_size, 0); + explicit_memset(efirng, 0, efirng_size); } #ifdef EFI_RUNTIME @@ -579,8 +595,9 @@ initarm(void *arg) /* Parse ramdisk info */ fdt_probe_initrd(&initrd_start, &initrd_end); - /* Parse rndseed */ + /* Parse our on-disk rndseed and the firmware's RNG from EFI */ fdt_probe_rndseed(&rndseed_start, &rndseed_end); + fdt_probe_efirng(&efirng_start, &efirng_end); /* * Populate bootconfig structure for the benefit of @@ -699,6 +716,7 @@ cpu_startup_hook(void) fdtbus_intr_init(); fdt_setup_rndseed(); + fdt_setup_efirng(); } void diff -r 5b74fbd1073b -r b99183572b9d sys/stand/efiboot/efiboot.c --- a/sys/stand/efiboot/efiboot.c Mon May 11 02:10:19 2020 +0000 +++ b/sys/stand/efiboot/efiboot.c Thu May 14 18:40:44 2020 +0000 @@ -31,6 +31,7 @@ #include "efiblock.h" #include "efifdt.h" #include "efiacpi.h" +#include "efirng.h" #include @@ -99,6 +100,7 @@ efi_main(EFI_HANDLE imageHandle, EFI_SYS efi_net_probe(); efi_file_system_probe(); efi_block_probe(); + efi_rng_probe(); boot(); diff -r 5b74fbd1073b -r b99183572b9d sys/stand/efiboot/efifdt.c --- a/sys/stand/efiboot/efifdt.c Mon May 11 02:10:19 2020 +0000 +++ b/sys/stand/efiboot/efifdt.c Thu May 14 18:40:44 2020 +0000 @@ -185,6 +185,22 @@ efi_fdt_show(void) printf("]\n"); } +static int +efi_fdt_chosen(void) +{ + int chosen; + + chosen = fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH); + if (chosen < 0) + chosen = fdt_add_subnode(fdt_data, + fdt_path_offset(fdt_data, "/"), + FDT_CHOSEN_NODE_NAME); + if (chosen < 0) + panic("FDT: Failed to create " FDT_CHOSEN_NODE_PATH " node"); + + return chosen; +} + void efi_fdt_memory_map(void) { @@ -200,11 +216,7 @@ efi_fdt_memory_map(void) if (memory < 0) panic("FDT: Failed to create " FDT_MEMORY_NODE_PATH " node"); - chosen = fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH); - if (chosen < 0) - chosen = fdt_add_subnode(fdt_data, fdt_path_offset(fdt_data, "/"), FDT_CHOSEN_NODE_NAME); - if (chosen < 0) - panic("FDT: Failed to create " FDT_CHOSEN_NODE_PATH " node"); + chosen = efi_fdt_chosen(); fdt_delprop(fdt_data, memory, "reg"); @@ -335,11 +347,7 @@ efi_fdt_bootargs(const char *bootargs) uint8_t macaddr[6]; int chosen; - chosen = fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH); - if (chosen < 0) - chosen = fdt_add_subnode(fdt_data, fdt_path_offset(fdt_data, "/"), FDT_CHOSEN_NODE_NAME); - if (chosen < 0) - panic("FDT: Failed to create " FDT_CHOSEN_NODE_PATH " node"); + chosen = efi_fdt_chosen(); if (*bootargs) fdt_setprop_string(fdt_data, chosen, "bootargs", bootargs); @@ -381,16 +389,12 @@ efi_fdt_initrd(u_long initrd_addr, u_lon if (initrd_size == 0) return; - chosen = fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH); - if (chosen < 0) - chosen = fdt_add_subnode(fdt_data, fdt_path_offset(fdt_data, "/"), FDT_CHOSEN_NODE_NAME); - if (chosen < 0) - panic("FDT: Failed to create " FDT_CHOSEN_NODE_PATH " node"); - + chosen = efi_fdt_chosen(); fdt_setprop_u64(fdt_data, chosen, "linux,initrd-start", initrd_addr); fdt_setprop_u64(fdt_data, chosen, "linux,initrd-end", initrd_addr + initrd_size); } +/* pass in the NetBSD on-disk random seed */ void efi_fdt_rndseed(u_long rndseed_addr, u_long rndseed_size) { @@ -399,16 +403,25 @@ efi_fdt_rndseed(u_long rndseed_addr, u_l if (rndseed_size == 0) return; - chosen = fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH); - if (chosen < 0) - chosen = fdt_add_subnode(fdt_data, - fdt_path_offset(fdt_data, "/"), - FDT_CHOSEN_NODE_NAME); - if (chosen < 0) - panic("FDT: Failed to create " FDT_CHOSEN_NODE_PATH " node"); - + chosen = efi_fdt_chosen(); fdt_setprop_u64(fdt_data, chosen, "netbsd,rndseed-start", rndseed_addr); fdt_setprop_u64(fdt_data, chosen, "netbsd,rndseed-end", rndseed_addr + rndseed_size); } + +/* pass in output from the EFI firmware's RNG from some unknown source */ +void +efi_fdt_efirng(u_long efirng_addr, u_long efirng_size) +{ + int chosen; + + if (efirng_size == 0) + return; + + chosen = efi_fdt_chosen(); + fdt_setprop_u64(fdt_data, chosen, "netbsd,efirng-start", + efirng_addr); + fdt_setprop_u64(fdt_data, chosen, "netbsd,efirng-end", + efirng_addr + efirng_size); +} diff -r 5b74fbd1073b -r b99183572b9d sys/stand/efiboot/efifdt.h --- a/sys/stand/efiboot/efifdt.h Mon May 11 02:10:19 2020 +0000 +++ b/sys/stand/efiboot/efifdt.h Thu May 14 18:40:44 2020 +0000 @@ -38,5 +38,6 @@ void efi_fdt_show(void); void efi_fdt_bootargs(const char *); void efi_fdt_initrd(u_long, u_long); void efi_fdt_rndseed(u_long, u_long); +void efi_fdt_efirng(u_long, u_long); void efi_fdt_init(u_long, u_long); void efi_fdt_fini(void); diff -r 5b74fbd1073b -r b99183572b9d sys/stand/efiboot/exec.c --- a/sys/stand/efiboot/exec.c Mon May 11 02:10:19 2020 +0000 +++ b/sys/stand/efiboot/exec.c Thu May 14 18:40:44 2020 +0000 @@ -31,6 +31,7 @@ #include "efienv.h" #include "efifdt.h" #include "efiacpi.h" +#include "efirng.h" #include @@ -41,8 +42,8 @@ u_long load_offset = 0; #define FDT_SPACE (4 * 1024 * 1024) #define FDT_ALIGN ((2 * 1024 * 1024) - 1) -static EFI_PHYSICAL_ADDRESS initrd_addr, dtb_addr, rndseed_addr; -static u_long initrd_size = 0, dtb_size = 0, rndseed_size = 0; +static EFI_PHYSICAL_ADDRESS initrd_addr, dtb_addr, rndseed_addr, efirng_addr; +static u_long initrd_size = 0, dtb_size = 0, rndseed_size = 0, efirng_size = 0; static int load_file(const char *path, u_long extra, bool quiet_errors, @@ -273,6 +274,48 @@ load_fdt_overlays(void) prop_object_iterator_release(iter); } +static void +generate_efirng(void) +{ + EFI_PHYSICAL_ADDRESS addr; + u_long size = EFI_PAGE_SIZE; + EFI_STATUS status; + + /* Check whether the RNG is available before bothering. */ + if (!efi_rng_available()) + return; + + /* + * Allocate a page. This is the smallest unit we can pass into + * the kernel conveniently. + */ +#ifdef EFIBOOT_ALLOCATE_MAX_ADDRESS + addr = EFIBOOT_ALLOCATE_MAX_ADDRESS; + status = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, + EfiLoaderData, EFI_SIZE_TO_PAGES(size), &addr); +#else + addr = 0; + status = uefi_call_wrapper(BS->AllocatePages, 4, AllocateAnyPages, + EfiLoaderData, EFI_SIZE_TO_PAGES(size), &addr); +#endif + if (EFI_ERROR(status)) { + Print(L"Failed to allocate page for EFI RNG output: %r\n", + status); + return; + } + + /* Fill the page with whatever the EFI RNG will do. */ + if (efi_rng((void *)(uintptr_t)addr, size)) { + uefi_call_wrapper(BS->FreePages, 2, addr, size); + return; + } + + /* Success! */ + printf("efirng addr=%lx size=%lu\n", addr, size); + efirng_addr = addr; + efirng_size = size; +} + int exec_netbsd(const char *fname, const char *args) { @@ -283,6 +326,7 @@ exec_netbsd(const char *fname, const cha load_file(get_initrd_path(), 0, false, &initrd_addr, &initrd_size); load_file(get_dtb_path(), 0, false, &dtb_addr, &dtb_size); + generate_efirng(); memset(marks, 0, sizeof(marks)); ohowto = howto; @@ -346,6 +390,7 @@ exec_netbsd(const char *fname, const cha load_fdt_overlays(); efi_fdt_initrd(initrd_addr, initrd_size); efi_fdt_rndseed(rndseed_addr, rndseed_size); + efi_fdt_efirng(efirng_addr, efirng_size); efi_fdt_bootargs(args); #ifdef EFIBOOT_ACPI if (efi_acpi_available()) diff -r 5b74fbd1073b -r b99183572b9d sys/stand/efiboot/version --- a/sys/stand/efiboot/version Mon May 11 02:10:19 2020 +0000 +++ b/sys/stand/efiboot/version Thu May 14 18:40:44 2020 +0000 @@ -18,3 +18,4 @@ 1.10: Add support for EFI GOP framebuffe 1.11: Add full UEFI memory map to /chosen node. 1.12: Derive ACPI model string from SMBIOS. 1.13: Add rndseed support. +1.14: Add EFI RNG support.