1// See LICENSE for license details. 2 3#include "bbl.h" 4#include "mtrap.h" 5#include "atomic.h" 6#include "vm.h" 7#include "bits.h" 8#include "config.h" 9#include "fdt.h" 10#include <string.h> 11 12extern char _payload_start, _payload_end; /* internal payload */ 13static const void* entry_point; 14long disabled_hart_mask; 15 16static uintptr_t dtb_output() 17{ 18 /* 19 * Place DTB after the payload, either the internal payload or a 20 * preloaded external payload specified in device-tree, if present. 21 * 22 * Note: linux kernel calls __va(dtb) to get the device-tree virtual 23 * address. The kernel's virtual mapping begins at its load address, 24 * thus mandating device-tree is in physical memory after the kernel. 25 */ 26 uintptr_t end = kernel_end ? (uintptr_t)kernel_end : (uintptr_t)&_payload_end; 27 return (end + MEGAPAGE_SIZE - 1) / MEGAPAGE_SIZE * MEGAPAGE_SIZE; 28} 29 30static void filter_dtb(uintptr_t source) 31{ 32 uintptr_t dest = dtb_output(); 33 uint32_t size = fdt_size(source); 34 memcpy((void*)dest, (void*)source, size); 35 36 // Remove information from the chained FDT 37 filter_harts(dest, &disabled_hart_mask); 38 filter_plic(dest); 39 filter_compat(dest, "riscv,clint0"); 40 filter_compat(dest, "riscv,debug-013"); 41} 42 43static void protect_memory(void) 44{ 45 // Check to see if up to four PMP registers are implemented. 46 // Ignore the illegal-instruction trap if PMPs aren't supported. 47 uintptr_t a0 = 0, a1 = 0, a2 = 0, a3 = 0, tmp, cfg; 48 asm volatile ("la %[tmp], 1f\n\t" 49 "csrrw %[tmp], mtvec, %[tmp]\n\t" 50 "csrw pmpaddr0, %[m1]\n\t" 51 "csrr %[a0], pmpaddr0\n\t" 52 "csrw pmpaddr1, %[m1]\n\t" 53 "csrr %[a1], pmpaddr1\n\t" 54 "csrw pmpaddr2, %[m1]\n\t" 55 "csrr %[a2], pmpaddr2\n\t" 56 "csrw pmpaddr3, %[m1]\n\t" 57 "csrr %[a3], pmpaddr3\n\t" 58 ".align 2\n\t" 59 "1: csrw mtvec, %[tmp]" 60 : [tmp] "=&r" (tmp), 61 [a0] "+r" (a0), [a1] "+r" (a1), [a2] "+r" (a2), [a3] "+r" (a3) 62 : [m1] "r" (-1UL)); 63 64 // We need at least four PMP registers to protect M-mode from S-mode. 65 if (!(a0 & a1 & a2 & a3)) 66 return setup_pmp(); 67 68 // Prevent S-mode access to our part of memory. 69 extern char _ftext, _end; 70 a0 = (uintptr_t)&_ftext >> PMP_SHIFT; 71 a1 = (uintptr_t)&_end >> PMP_SHIFT; 72 cfg = PMP_TOR << 8; 73 // Give S-mode free rein of everything else. 74 a2 = -1; 75 cfg |= (PMP_NAPOT | PMP_R | PMP_W | PMP_X) << 16; 76 // No use for PMP 3 just yet. 77 a3 = 0; 78 79 // Plug it all in. 80 asm volatile ("csrw pmpaddr0, %[a0]\n\t" 81 "csrw pmpaddr1, %[a1]\n\t" 82 "csrw pmpaddr2, %[a2]\n\t" 83 "csrw pmpaddr3, %[a3]\n\t" 84 "csrw pmpcfg0, %[cfg]" 85 :: [a0] "r" (a0), [a1] "r" (a1), [a2] "r" (a2), [a3] "r" (a3), 86 [cfg] "r" (cfg)); 87} 88 89void boot_other_hart(uintptr_t unused __attribute__((unused))) 90{ 91 const void* entry; 92 do { 93 entry = entry_point; 94 mb(); 95 } while (!entry); 96 97 long hartid = read_csr(mhartid); 98 if ((1 << hartid) & disabled_hart_mask) { 99 while (1) { 100 __asm__ volatile("wfi"); 101#ifdef __riscv_div 102 __asm__ volatile("div x0, x0, x0"); 103#endif 104 } 105 } 106 107#ifdef BBL_BOOT_MACHINE 108 enter_machine_mode(entry, hartid, dtb_output()); 109#else /* Run bbl in supervisor mode */ 110 protect_memory(); 111 enter_supervisor_mode(entry, hartid, dtb_output()); 112#endif 113} 114 115void boot_loader(uintptr_t dtb) 116{ 117 filter_dtb(dtb); 118#ifdef PK_ENABLE_LOGO 119 print_logo(); 120#endif 121#ifdef PK_PRINT_DEVICE_TREE 122 fdt_print(dtb_output()); 123#endif 124 mb(); 125 /* Use optional FDT preloaded external payload if present */ 126 entry_point = kernel_start ? kernel_start : &_payload_start; 127 boot_other_hart(0); 128} 129