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