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
34typedef void (*kentry)(register_t, register_t, register_t, register_t);
35#define PRIMARY 1
36
37int	octboot_kexec(struct octboot_kexec_args *, struct proc *);
38int	octboot_read(struct octboot_kexec_args *, void *, size_t, off_t);
39
40uint64_t	octeon_boot_entry;
41uint32_t	octeon_boot_ready;
42
43void
44octbootattach(int num)
45{
46}
47
48int
49octbootopen(dev_t dev, int flags, int mode, struct proc *p)
50{
51	return (0);
52}
53
54int
55octbootclose(dev_t dev, int flags, int mode, struct proc *p)
56{
57	return (0);
58}
59
60int
61octbootioctl(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
89int
90octboot_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
341fail:
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
358int
359octboot_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