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