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