1 /* $OpenBSD: exec.c,v 1.18 2024/03/10 15:37:54 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
dcache_wbinv_all(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
icache_inv_all(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
dcache_disable(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
icache_disable(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
mmu_disable(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
run_loadfile(uint64_t * marks,int howto)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_wbinv_all();
186 dcache_disable();
187 icache_inv_all();
188 icache_disable();
189 mmu_disable();
190
191 (*(startfuncp)(marks[MARK_ENTRY]))((void *)esym, NULL, fdt);
192
193 /* NOTREACHED */
194 }
195