1 /* $OpenBSD: exec.c,v 1.16 2020/05/17 14:32:12 kettenis Exp $ */ 2 3 /* 4 * Copyright (c) 2006, 2016 Mark Kettenis 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/reboot.h> 21 #include <dev/cons.h> 22 23 #include <lib/libkern/libkern.h> 24 #include <lib/libsa/loadfile.h> 25 #include <sys/exec_elf.h> 26 27 #include <efi.h> 28 #include <stand/boot/cmd.h> 29 30 #include <arm/armreg.h> 31 32 #include "efiboot.h" 33 #include "libsa.h" 34 35 typedef void (*startfuncp)(void *, void *, void *) __attribute__ ((noreturn)); 36 37 #define CLIDR_LOC(x) ((x >> 24) & 0x7) 38 #define CLIDR_CTYPE(x, n) ((x >> (n * 3)) & 0x7) 39 #define CLIDR_CTYPE_NOCACHE 0x0 40 #define CLIDR_CTYPE_ICACHE 0x1 41 #define CLIDR_CTYPE_DCACHE 0x2 42 #define CLIDR_CTYPE_SEP_CACHE 0x3 43 #define CLIDR_CTYPE_UNI_CACHE 0x4 44 #define CCSIDR_NUMSETS(x) ((x >> 13) & 0x7fff) 45 #define CCSIDR_ASSOCIATIVITY(x) ((x >> 3) & 0x3ff) 46 #define CCSIDR_LINESZ(x) (x & 0x7) 47 48 void 49 dcache_wbinv_all(void) 50 { 51 uint32_t clidr; 52 uint32_t ccsidr; 53 uint32_t val; 54 int nways, nsets; 55 int wshift, sshift; 56 int way, set; 57 int level; 58 59 __asm volatile("mrc p15, 1, %0, c0, c0, 1" : "=r"(clidr)); 60 for (level = 0; level < CLIDR_LOC(clidr); level++) { 61 if (CLIDR_CTYPE(clidr, level) == CLIDR_CTYPE_NOCACHE) 62 break; 63 if (CLIDR_CTYPE(clidr, level) == CLIDR_CTYPE_ICACHE) 64 continue; 65 66 __asm volatile("mcr p15, 2, %0, c0, c0, 0" :: "r"(level << 1)); 67 __asm volatile("isb"); 68 __asm volatile("mrc p15, 1, %0, c0, c0, 0" : "=r"(ccsidr)); 69 70 nways = CCSIDR_ASSOCIATIVITY(ccsidr) + 1; 71 nsets = CCSIDR_NUMSETS(ccsidr) + 1; 72 73 sshift = CCSIDR_LINESZ(ccsidr) + 4; 74 wshift = __builtin_clz(CCSIDR_ASSOCIATIVITY(ccsidr)); 75 76 for (way = 0; way < nways; way++) { 77 for (set = 0; set < nsets; set++) { 78 val = (way << wshift) | (set << sshift) | 79 (level << 1); 80 __asm volatile("mcr p15, 0, %0, c7, c14, 2" 81 :: "r"(val)); 82 } 83 } 84 } 85 86 __asm volatile("dsb"); 87 } 88 89 void 90 icache_inv_all(void) 91 { 92 __asm volatile("mcr p15, 0, r0, c7, c5, 0"); /* ICIALLU */ 93 __asm volatile("dsb"); 94 __asm volatile("isb"); 95 } 96 97 void 98 dcache_disable(void) 99 { 100 uint32_t sctlr; 101 102 __asm volatile("mrc p15, 0, %0, c1, c0, 0" : "=r"(sctlr)); 103 sctlr &= ~CPU_CONTROL_DC_ENABLE; 104 __asm volatile("mcr p15, 0, %0, c1, c0, 0" :: "r"(sctlr)); 105 __asm volatile("dsb"); 106 __asm volatile("isb"); 107 } 108 109 void 110 icache_disable(void) 111 { 112 uint32_t sctlr; 113 114 __asm volatile("mrc p15, 0, %0, c1, c0, 0" : "=r"(sctlr)); 115 sctlr &= ~CPU_CONTROL_IC_ENABLE; 116 __asm volatile("mcr p15, 0, %0, c1, c0, 0" :: "r"(sctlr)); 117 __asm volatile("dsb"); 118 __asm volatile("isb"); 119 } 120 121 void 122 mmu_disable(void) 123 { 124 uint32_t sctlr; 125 126 __asm volatile("mrc p15, 0, %0, c1, c0, 0" : "=r"(sctlr)); 127 sctlr &= ~CPU_CONTROL_MMU_ENABLE; 128 __asm volatile("mcr p15, 0, %0, c1, c0, 0" :: "r"(sctlr)); 129 130 __asm volatile("mcr p15, 0, r0, c8, c7, 0"); /* TLBIALL */ 131 __asm volatile("mcr p15, 0, r0, c7, c5, 6"); /* BPIALL */ 132 __asm volatile("dsb"); 133 __asm volatile("isb"); 134 } 135 136 void 137 run_loadfile(uint64_t *marks, int howto) 138 { 139 Elf_Ehdr *elf = (Elf_Ehdr *)marks[MARK_SYM]; 140 Elf_Shdr *shp = (Elf_Shdr *)(marks[MARK_SYM] + elf->e_shoff); 141 u_long esym = marks[MARK_END] & 0x0fffffff; 142 u_long offset = 0; 143 char args[256]; 144 char *cp; 145 void *fdt; 146 int i; 147 148 /* 149 * Tell locore.S where the symbol table ends by setting 150 * 'esym', which should be the first word in the .data 151 * section. 152 */ 153 for (i = 0; i < elf->e_shnum; i++) { 154 /* XXX Assume .data is the first writable segment. */ 155 if (shp[i].sh_flags & SHF_WRITE) { 156 /* XXX We have to store the virtual address. */ 157 esym |= shp[i].sh_addr & 0xf0000000; 158 *(u_long *)(LOADADDR(shp[i].sh_addr)) = esym; 159 break; 160 } 161 } 162 163 snprintf(args, sizeof(args) - 8, "%s:%s", cmd.bootdev, cmd.image); 164 cp = args + strlen(args); 165 166 *cp++ = ' '; 167 *cp = '-'; 168 if (howto & RB_ASKNAME) 169 *++cp = 'a'; 170 if (howto & RB_CONFIG) 171 *++cp = 'c'; 172 if (howto & RB_SINGLE) 173 *++cp = 's'; 174 if (howto & RB_KDB) 175 *++cp = 'd'; 176 if (*cp == '-') 177 *--cp = 0; 178 else 179 *++cp = 0; 180 181 fdt = efi_makebootargs(args, howto); 182 183 efi_cleanup(); 184 185 dcache_disable(); 186 dcache_wbinv_all(); 187 icache_disable(); 188 icache_inv_all(); 189 mmu_disable(); 190 191 (*(startfuncp)(marks[MARK_ENTRY]))((void *)esym, NULL, fdt); 192 193 /* NOTREACHED */ 194 } 195