1 /* $OpenBSD: octboot.c,v 1.5 2022/01/10 16:21:19 visa Exp $ */
2
3 /*
4 * Copyright (c) 2019-2020 Visa Hankala
5 *
6 * Permission to use, copy, modify, and/or 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/systm.h>
21 #include <sys/exec_elf.h>
22 #include <sys/malloc.h>
23 #include <sys/proc.h>
24 #include <sys/mount.h>
25
26 #include <uvm/uvm_extern.h>
27
28 #include <mips64/memconf.h>
29
30 #include <machine/autoconf.h>
31 #include <machine/octboot.h>
32 #include <machine/octeonvar.h>
33
34 typedef void (*kentry)(register_t, register_t, register_t, register_t);
35 #define PRIMARY 1
36
37 int octboot_kexec(struct octboot_kexec_args *, struct proc *);
38 int octboot_read(struct octboot_kexec_args *, void *, size_t, off_t);
39
40 uint64_t octeon_boot_entry;
41 uint32_t octeon_boot_ready;
42
43 void
octbootattach(int num)44 octbootattach(int num)
45 {
46 }
47
48 int
octbootopen(dev_t dev,int flags,int mode,struct proc * p)49 octbootopen(dev_t dev, int flags, int mode, struct proc *p)
50 {
51 return (0);
52 }
53
54 int
octbootclose(dev_t dev,int flags,int mode,struct proc * p)55 octbootclose(dev_t dev, int flags, int mode, struct proc *p)
56 {
57 return (0);
58 }
59
60 int
octbootioctl(dev_t dev,u_long cmd,caddr_t data,int flags,struct proc * p)61 octbootioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
62 {
63 int error = 0;
64
65 switch (cmd) {
66 case OBIOC_GETROOTDEV:
67 if (strlen(uboot_rootdev) == 0) {
68 error = ENOENT;
69 break;
70 }
71 strlcpy((char *)data, uboot_rootdev, PATH_MAX);
72 break;
73
74 case OBIOC_KEXEC:
75 error = suser(p);
76 if (error != 0)
77 break;
78 error = octboot_kexec((struct octboot_kexec_args *)data, p);
79 break;
80
81 default:
82 error = ENOTTY;
83 break;
84 }
85
86 return error;
87 }
88
89 int
octboot_kexec(struct octboot_kexec_args * kargs,struct proc * p)90 octboot_kexec(struct octboot_kexec_args *kargs, struct proc *p)
91 {
92 extern char start[], end[];
93 Elf_Ehdr eh;
94 Elf_Phdr *ph = NULL;
95 Elf_Shdr *sh = NULL;
96 paddr_t ekern = 0, elfp, maxp = 0, off, pa, shp;
97 size_t phsize = 0, shsize = 0, shstrsize = 0;
98 size_t len, size;
99 char *argbuf = NULL, *argptr;
100 char *shstr = NULL;
101 int argc = 0, error, havesyms = 0, i, nalloc = 0;
102
103 memset(&eh, 0, sizeof(eh));
104
105 /*
106 * Load kernel arguments into a temporary buffer.
107 * This also translates the userspace argv pointers to kernel pointers.
108 */
109 argbuf = malloc(PAGE_SIZE, M_TEMP, M_NOWAIT);
110 if (argbuf == NULL) {
111 error = ENOMEM;
112 goto fail;
113 }
114 argptr = argbuf;
115 for (i = 0; i < OCTBOOT_MAX_ARGS && kargs->argv[i] != NULL; i++) {
116 len = argbuf + PAGE_SIZE - argptr;
117 error = copyinstr(kargs->argv[i], argptr, len, &len);
118 if (error != 0)
119 goto fail;
120 kargs->argv[i] = argptr;
121 argptr += len;
122 argc++;
123 }
124
125 /*
126 * Read the headers and validate them.
127 */
128 error = octboot_read(kargs, &eh, sizeof(eh), 0);
129 if (error != 0)
130 goto fail;
131
132 /* Load program headers. */
133 ph = mallocarray(eh.e_phnum, sizeof(Elf_Phdr), M_TEMP, M_NOWAIT);
134 if (ph == NULL) {
135 error = ENOMEM;
136 goto fail;
137 }
138 phsize = eh.e_phnum * sizeof(Elf_Phdr);
139 error = octboot_read(kargs, ph, phsize, eh.e_phoff);
140 if (error != 0)
141 goto fail;
142
143 /* Load section headers. */
144 sh = mallocarray(eh.e_shnum, sizeof(Elf_Shdr), M_TEMP, M_NOWAIT);
145 if (sh == NULL) {
146 error = ENOMEM;
147 goto fail;
148 }
149 shsize = eh.e_shnum * sizeof(Elf_Shdr);
150 error = octboot_read(kargs, sh, shsize, eh.e_shoff);
151 if (error != 0)
152 goto fail;
153
154 /* Sanity-check addresses. */
155 for (i = 0; i < eh.e_phnum; i++) {
156 if (ph[i].p_type != PT_LOAD &&
157 ph[i].p_type != PT_OPENBSD_RANDOMIZE)
158 continue;
159 if (ph[i].p_paddr < CKSEG0_BASE ||
160 ph[i].p_paddr + ph[i].p_memsz >= CKSEG0_BASE + CKSEG_SIZE) {
161 error = ENOEXEC;
162 goto fail;
163 }
164 }
165
166 /*
167 * Allocate physical memory and load the segments.
168 */
169
170 for (i = 0; i < eh.e_phnum; i++) {
171 if (ph[i].p_type != PT_LOAD)
172 continue;
173 pa = CKSEG0_TO_PHYS(ph[i].p_paddr);
174 size = roundup(ph[i].p_memsz, BOOTMEM_BLOCK_ALIGN);
175 if (bootmem_alloc_region(pa, size) != 0) {
176 printf("kexec: failed to allocate segment "
177 "0x%lx @ 0x%lx\n", size, pa);
178 error = ENOMEM;
179 goto fail;
180 }
181 if (maxp < pa + size)
182 maxp = pa + size;
183 nalloc++;
184 }
185
186 for (i = 0; i < eh.e_phnum; i++) {
187 if (ph[i].p_type == PT_OPENBSD_RANDOMIZE) {
188 /* Assume that the segment is inside a LOAD segment. */
189 arc4random_buf((caddr_t)ph[i].p_paddr, ph[i].p_filesz);
190 continue;
191 }
192
193 if (ph[i].p_type != PT_LOAD)
194 continue;
195
196 error = octboot_read(kargs, (caddr_t)ph[i].p_paddr,
197 ph[i].p_filesz, ph[i].p_offset);
198 if (error != 0)
199 goto fail;
200
201 /* Clear any BSS. */
202 if (ph[i].p_memsz > ph[i].p_filesz) {
203 memset((caddr_t)ph[i].p_paddr + ph[i].p_filesz,
204 0, ph[i].p_memsz - ph[i].p_filesz);
205 }
206 }
207 ekern = maxp;
208
209 for (i = 0; i < eh.e_shnum; i++) {
210 if (sh[i].sh_type == SHT_SYMTAB) {
211 havesyms = 1;
212 break;
213 }
214 }
215
216 if (havesyms) {
217 /* Reserve space for ssym and esym pointers. */
218 maxp += sizeof(int32_t) * 2;
219
220 elfp = roundup(maxp, sizeof(Elf_Addr));
221 maxp = elfp + sizeof(Elf_Ehdr);
222 shp = maxp;
223 maxp = shp + roundup(shsize, sizeof(Elf_Addr));
224 maxp = roundup(maxp, BOOTMEM_BLOCK_ALIGN);
225 if (bootmem_alloc_region(ekern, maxp - ekern) != 0) {
226 printf("kexec: failed to allocate %zu bytes for ELF "
227 "and section headers\n", maxp - ekern);
228 error = ENOMEM;
229 goto fail;
230 }
231
232 shstrsize = sh[eh.e_shstrndx].sh_size;
233 shstr = malloc(shstrsize, M_TEMP, M_NOWAIT);
234 if (shstr == NULL) {
235 error = ENOMEM;
236 goto fail;
237 }
238 error = octboot_read(kargs, shstr, shstrsize,
239 sh[eh.e_shstrndx].sh_offset);
240 if (error != 0)
241 goto fail;
242
243 off = maxp - elfp;
244 for (i = 0; i < eh.e_shnum; i++) {
245 if (sh[i].sh_type == SHT_STRTAB ||
246 sh[i].sh_type == SHT_SYMTAB ||
247 strcmp(shstr + sh[i].sh_name, ELF_CTF) == 0 ||
248 strcmp(shstr + sh[i].sh_name, ".debug_line") == 0) {
249 size_t bsize = roundup(sh[i].sh_size,
250 BOOTMEM_BLOCK_ALIGN);
251
252 if (bootmem_alloc_region(maxp, bsize) != 0) {
253 error = ENOMEM;
254 goto fail;
255 }
256 error = octboot_read(kargs,
257 (caddr_t)PHYS_TO_CKSEG0(maxp),
258 sh[i].sh_size, sh[i].sh_offset);
259 maxp += bsize;
260 if (error != 0)
261 goto fail;
262 sh[i].sh_offset = off;
263 sh[i].sh_flags |= SHF_ALLOC;
264 off += bsize;
265 }
266 }
267
268 eh.e_phoff = 0;
269 eh.e_shoff = sizeof(eh);
270 eh.e_phentsize = 0;
271 eh.e_phnum = 0;
272 memcpy((caddr_t)PHYS_TO_CKSEG0(elfp), &eh, sizeof(eh));
273 memcpy((caddr_t)PHYS_TO_CKSEG0(shp), sh, shsize);
274
275 *(int32_t *)PHYS_TO_CKSEG0(ekern) = PHYS_TO_CKSEG0(elfp);
276 *((int32_t *)PHYS_TO_CKSEG0(ekern) + 1) = PHYS_TO_CKSEG0(maxp);
277 }
278
279 /*
280 * Put kernel arguments in place.
281 */
282 octeon_boot_desc->argc = 0;
283 for (i = 0; i < OCTEON_ARGV_MAX; i++)
284 octeon_boot_desc->argv[i] = 0;
285 if (argptr > argbuf) {
286 size = roundup(argptr - argbuf, BOOTMEM_BLOCK_ALIGN);
287 if (bootmem_alloc_region(maxp, size) != 0) {
288 error = ENOMEM;
289 goto fail;
290 }
291 memcpy((caddr_t)PHYS_TO_CKSEG0(maxp), argbuf, argptr - argbuf);
292 for (i = 0; i < argc; i++) {
293 KASSERT(kargs->argv[i] >= argbuf);
294 KASSERT(kargs->argv[i] < argbuf + PAGE_SIZE);
295 octeon_boot_desc->argv[i] = kargs->argv[i] - argbuf +
296 maxp;
297 }
298 octeon_boot_desc->argc = argc;
299 maxp += size;
300 }
301
302 vfs_shutdown(p);
303
304 printf("launching kernel\n");
305
306 config_suspend_all(DVACT_POWERDOWN);
307
308 intr_disable();
309
310 /* Put UVM memory back to the free list. */
311 for (i = 0; mem_layout[i].mem_last_page != 0; i++) {
312 uint64_t fp = mem_layout[i].mem_first_page;
313 uint64_t lp = mem_layout[i].mem_last_page;
314
315 bootmem_free(ptoa(fp), ptoa(lp) - ptoa(fp));
316 }
317
318 /*
319 * Release the memory of the bootloader kernel.
320 * This may overwrite a tiny region at the start of the running image.
321 */
322 bootmem_free(CKSEG0_TO_PHYS((vaddr_t)start), end - start);
323
324 /* Let secondary cores proceed to the new kernel. */
325 octeon_boot_entry = eh.e_entry;
326 octeon_syncw(); /* Order writes. */
327 octeon_boot_ready = 1; /* Open the gate. */
328 octeon_syncw(); /* Flush writes. */
329 delay(1000); /* Give secondary cores a lead. */
330
331 __asm__ volatile (
332 " cache 1, 0($0)\n" /* Flush and invalidate dcache. */
333 " cache 0, 0($0)\n" /* Invalidate icache. */
334 ::: "memory");
335
336 (*(kentry)eh.e_entry)(0, 0, PRIMARY, (register_t)octeon_boot_desc);
337
338 for (;;)
339 continue;
340
341 fail:
342 if (ekern != 0)
343 bootmem_free(ekern, maxp - ekern);
344 for (i = 0; i < eh.e_phnum && nalloc > 0; i++) {
345 if (ph[i].p_type == PT_LOAD) {
346 pa = CKSEG0_TO_PHYS(ph[i].p_paddr);
347 bootmem_free(pa, ph[i].p_memsz);
348 nalloc--;
349 }
350 }
351 free(shstr, M_TEMP, shstrsize);
352 free(sh, M_TEMP, shsize);
353 free(ph, M_TEMP, phsize);
354 free(argbuf, M_TEMP, PAGE_SIZE);
355 return error;
356 }
357
358 int
octboot_read(struct octboot_kexec_args * kargs,void * buf,size_t size,off_t off)359 octboot_read(struct octboot_kexec_args *kargs, void *buf, size_t size,
360 off_t off)
361 {
362 if (off + size < off || off + size > kargs->klen)
363 return ENOEXEC;
364 return copyin(kargs->kimg + off, buf, size);
365 }
366