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