xref: /openbsd/sys/arch/armv7/stand/efiboot/exec.c (revision 4bdff4be)
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