main.c revision 332150
1/*- 2 * Copyright (C) 2010-2014 Nathan Whitehorn 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD: stable/11/stand/powerpc/kboot/main.c 332150 2018-04-06 20:24:50Z kevans $"); 28 29#include <stand.h> 30#include <sys/endian.h> 31#include <sys/param.h> 32#include <fdt_platform.h> 33 34#define _KERNEL 35#include <machine/cpufunc.h> 36#include "bootstrap.h" 37#include "host_syscall.h" 38 39 40struct arch_switch archsw; 41extern void *_end; 42 43extern char bootprog_info[]; 44 45int kboot_getdev(void **vdev, const char *devspec, const char **path); 46ssize_t kboot_copyin(const void *src, vm_offset_t dest, const size_t len); 47ssize_t kboot_copyout(vm_offset_t src, void *dest, const size_t len); 48ssize_t kboot_readin(const int fd, vm_offset_t dest, const size_t len); 49int kboot_autoload(void); 50uint64_t kboot_loadaddr(u_int type, void *data, uint64_t addr); 51int kboot_setcurrdev(struct env_var *ev, int flags, const void *value); 52static void kboot_kseg_get(int *nseg, void **ptr); 53 54extern int command_fdt_internal(int argc, char *argv[]); 55 56struct region_desc { 57 uint64_t start; 58 uint64_t end; 59}; 60 61static uint64_t 62kboot_get_phys_load_segment(void) 63{ 64 int fd; 65 uint64_t entry[2]; 66 static uint64_t load_segment = ~(0UL); 67 uint64_t val_64; 68 uint32_t val_32; 69 struct region_desc rsvd_reg[32]; 70 int rsvd_reg_cnt = 0; 71 int ret, a, b; 72 uint64_t start, end; 73 74 if (load_segment == ~(0UL)) { 75 76 /* Default load address is 0x00000000 */ 77 load_segment = 0UL; 78 79 /* Read reserved regions */ 80 fd = host_open("/proc/device-tree/reserved-ranges", O_RDONLY, 0); 81 if (fd >= 0) { 82 while (host_read(fd, &entry[0], sizeof(entry)) == sizeof(entry)) { 83 rsvd_reg[rsvd_reg_cnt].start = be64toh(entry[0]); 84 rsvd_reg[rsvd_reg_cnt].end = 85 be64toh(entry[1]) + rsvd_reg[rsvd_reg_cnt].start - 1; 86 rsvd_reg_cnt++; 87 } 88 host_close(fd); 89 } 90 /* Read where the kernel ends */ 91 fd = host_open("/proc/device-tree/chosen/linux,kernel-end", O_RDONLY, 0); 92 if (fd >= 0) { 93 ret = host_read(fd, &val_64, sizeof(val_64)); 94 95 if (ret == sizeof(uint64_t)) { 96 rsvd_reg[rsvd_reg_cnt].start = 0; 97 rsvd_reg[rsvd_reg_cnt].end = be64toh(val_64) - 1; 98 } else { 99 memcpy(&val_32, &val_64, sizeof(val_32)); 100 rsvd_reg[rsvd_reg_cnt].start = 0; 101 rsvd_reg[rsvd_reg_cnt].end = be32toh(val_32) - 1; 102 } 103 rsvd_reg_cnt++; 104 105 host_close(fd); 106 } 107 /* Read memory size (SOCKET0 only) */ 108 fd = host_open("/proc/device-tree/memory@0/reg", O_RDONLY, 0); 109 if (fd < 0) 110 fd = host_open("/proc/device-tree/memory/reg", O_RDONLY, 0); 111 if (fd >= 0) { 112 ret = host_read(fd, &entry, sizeof(entry)); 113 114 /* Memory range in start:length format */ 115 entry[0] = be64toh(entry[0]); 116 entry[1] = be64toh(entry[1]); 117 118 /* Reserve everything what is before start */ 119 if (entry[0] != 0) { 120 rsvd_reg[rsvd_reg_cnt].start = 0; 121 rsvd_reg[rsvd_reg_cnt].end = entry[0] - 1; 122 rsvd_reg_cnt++; 123 } 124 /* Reserve everything what is after end */ 125 if (entry[1] != 0xffffffffffffffffUL) { 126 rsvd_reg[rsvd_reg_cnt].start = entry[0] + entry[1]; 127 rsvd_reg[rsvd_reg_cnt].end = 0xffffffffffffffffUL; 128 rsvd_reg_cnt++; 129 } 130 131 host_close(fd); 132 } 133 134 /* Sort entries in ascending order (bubble) */ 135 for (a = rsvd_reg_cnt - 1; a > 0; a--) { 136 for (b = 0; b < a; b++) { 137 if (rsvd_reg[b].start > rsvd_reg[b + 1].start) { 138 struct region_desc tmp; 139 tmp = rsvd_reg[b]; 140 rsvd_reg[b] = rsvd_reg[b + 1]; 141 rsvd_reg[b + 1] = tmp; 142 } 143 } 144 } 145 146 /* Join overlapping/adjacent regions */ 147 for (a = 0; a < rsvd_reg_cnt - 1; ) { 148 149 if ((rsvd_reg[a + 1].start >= rsvd_reg[a].start) && 150 ((rsvd_reg[a + 1].start - 1) <= rsvd_reg[a].end)) { 151 /* We have overlapping/adjacent regions! */ 152 rsvd_reg[a].end = 153 MAX(rsvd_reg[a].end, rsvd_reg[a + a].end); 154 155 for (b = a + 1; b < rsvd_reg_cnt - 1; b++) 156 rsvd_reg[b] = rsvd_reg[b + 1]; 157 rsvd_reg_cnt--; 158 } else 159 a++; 160 } 161 162 /* Find the first free region */ 163 if (rsvd_reg_cnt > 0) { 164 start = 0; 165 end = rsvd_reg[0].start; 166 for (a = 0; a < rsvd_reg_cnt - 1; a++) { 167 if ((start >= rsvd_reg[a].start) && 168 (start <= rsvd_reg[a].end)) { 169 start = rsvd_reg[a].end + 1; 170 end = rsvd_reg[a + 1].start; 171 } else 172 break; 173 } 174 175 if (start != end) { 176 uint64_t align = 64UL*1024UL*1024UL; 177 178 /* Align both to 64MB boundary */ 179 start = (start + align - 1UL) & ~(align - 1UL); 180 end = ((end + 1UL) & ~(align - 1UL)) - 1UL; 181 182 if (start < end) 183 load_segment = start; 184 } 185 } 186 } 187 188 return (load_segment); 189} 190 191uint8_t 192kboot_get_kernel_machine_bits(void) 193{ 194 static uint8_t bits = 0; 195 struct old_utsname utsname; 196 int ret; 197 198 if (bits == 0) { 199 /* Default is 32-bit kernel */ 200 bits = 32; 201 202 /* Try to get system type */ 203 memset(&utsname, 0, sizeof(utsname)); 204 ret = host_uname(&utsname); 205 if (ret == 0) { 206 if (strcmp(utsname.machine, "ppc64") == 0) 207 bits = 64; 208 else if (strcmp(utsname.machine, "ppc64le") == 0) 209 bits = 64; 210 } 211 } 212 213 return (bits); 214} 215 216int 217kboot_getdev(void **vdev, const char *devspec, const char **path) 218{ 219 int i; 220 const char *devpath, *filepath; 221 struct devsw *dv; 222 struct devdesc *desc; 223 224 if (strchr(devspec, ':') != NULL) { 225 devpath = devspec; 226 filepath = strchr(devspec, ':') + 1; 227 } else { 228 devpath = getenv("currdev"); 229 filepath = devspec; 230 } 231 232 for (i = 0; (dv = devsw[i]) != NULL; i++) { 233 if (strncmp(dv->dv_name, devpath, strlen(dv->dv_name)) == 0) 234 goto found; 235 } 236 return (ENOENT); 237 238found: 239 if (path != NULL && filepath != NULL) 240 *path = filepath; 241 else if (path != NULL) 242 *path = strchr(devspec, ':') + 1; 243 244 if (vdev != NULL) { 245 desc = malloc(sizeof(*desc)); 246 desc->d_dev = dv; 247 desc->d_unit = 0; 248 desc->d_opendata = strdup(devpath); 249 *vdev = desc; 250 } 251 252 return (0); 253} 254 255int 256main(int argc, const char **argv) 257{ 258 void *heapbase; 259 const size_t heapsize = 15*1024*1024; 260 const char *bootdev; 261 262 /* 263 * Set the heap to one page after the end of the loader. 264 */ 265 heapbase = host_getmem(heapsize); 266 setheap(heapbase, heapbase + heapsize); 267 268 /* 269 * Set up console. 270 */ 271 cons_probe(); 272 273 /* Choose bootdev if provided */ 274 if (argc > 1) 275 bootdev = argv[1]; 276 else 277 bootdev = ""; 278 279 printf("Boot device: %s\n", bootdev); 280 281 archsw.arch_getdev = kboot_getdev; 282 archsw.arch_copyin = kboot_copyin; 283 archsw.arch_copyout = kboot_copyout; 284 archsw.arch_readin = kboot_readin; 285 archsw.arch_autoload = kboot_autoload; 286 archsw.arch_loadaddr = kboot_loadaddr; 287 archsw.arch_kexec_kseg_get = kboot_kseg_get; 288 289 printf("\n%s", bootprog_info); 290 291 setenv("currdev", bootdev, 1); 292 setenv("loaddev", bootdev, 1); 293 setenv("LINES", "24", 1); 294 setenv("usefdt", "1", 1); 295 296 interact(); /* doesn't return */ 297 298 return (0); 299} 300 301void 302exit(int code) 303{ 304 while (1); /* XXX: host_exit */ 305 __unreachable(); 306} 307 308void 309delay(int usecs) 310{ 311 struct host_timeval tvi, tv; 312 uint64_t ti, t; 313 host_gettimeofday(&tvi, NULL); 314 ti = tvi.tv_sec*1000000 + tvi.tv_usec; 315 do { 316 host_gettimeofday(&tv, NULL); 317 t = tv.tv_sec*1000000 + tv.tv_usec; 318 } while (t < ti + usecs); 319} 320 321time_t 322getsecs(void) 323{ 324 struct host_timeval tv; 325 host_gettimeofday(&tv, NULL); 326 return (tv.tv_sec); 327} 328 329time_t 330time(time_t *tloc) 331{ 332 time_t rv; 333 334 rv = getsecs(); 335 if (tloc != NULL) 336 *tloc = rv; 337 338 return (rv); 339} 340 341struct kexec_segment { 342 void *buf; 343 int bufsz; 344 void *mem; 345 int memsz; 346}; 347 348struct kexec_segment loaded_segments[128]; 349int nkexec_segments = 0; 350 351static ssize_t 352get_phys_buffer(vm_offset_t dest, const size_t len, void **buf) 353{ 354 int i = 0; 355 const size_t segsize = 4*1024*1024; 356 357 for (i = 0; i < nkexec_segments; i++) { 358 if (dest >= (vm_offset_t)loaded_segments[i].mem && 359 dest < (vm_offset_t)loaded_segments[i].mem + 360 loaded_segments[i].memsz) 361 goto out; 362 } 363 364 loaded_segments[nkexec_segments].buf = host_getmem(segsize); 365 loaded_segments[nkexec_segments].bufsz = segsize; 366 loaded_segments[nkexec_segments].mem = (void *)rounddown2(dest,segsize); 367 loaded_segments[nkexec_segments].memsz = segsize; 368 369 i = nkexec_segments; 370 nkexec_segments++; 371 372out: 373 *buf = loaded_segments[i].buf + (dest - 374 (vm_offset_t)loaded_segments[i].mem); 375 return (min(len,loaded_segments[i].bufsz - (dest - 376 (vm_offset_t)loaded_segments[i].mem))); 377} 378 379ssize_t 380kboot_copyin(const void *src, vm_offset_t dest, const size_t len) 381{ 382 ssize_t segsize, remainder; 383 void *destbuf; 384 385 remainder = len; 386 do { 387 segsize = get_phys_buffer(dest, remainder, &destbuf); 388 bcopy(src, destbuf, segsize); 389 remainder -= segsize; 390 src += segsize; 391 dest += segsize; 392 } while (remainder > 0); 393 394 return (len); 395} 396 397ssize_t 398kboot_copyout(vm_offset_t src, void *dest, const size_t len) 399{ 400 ssize_t segsize, remainder; 401 void *srcbuf; 402 403 remainder = len; 404 do { 405 segsize = get_phys_buffer(src, remainder, &srcbuf); 406 bcopy(srcbuf, dest, segsize); 407 remainder -= segsize; 408 src += segsize; 409 dest += segsize; 410 } while (remainder > 0); 411 412 return (len); 413} 414 415ssize_t 416kboot_readin(const int fd, vm_offset_t dest, const size_t len) 417{ 418 void *buf; 419 size_t resid, chunk, get; 420 ssize_t got; 421 vm_offset_t p; 422 423 p = dest; 424 425 chunk = min(PAGE_SIZE, len); 426 buf = malloc(chunk); 427 if (buf == NULL) { 428 printf("kboot_readin: buf malloc failed\n"); 429 return (0); 430 } 431 432 for (resid = len; resid > 0; resid -= got, p += got) { 433 get = min(chunk, resid); 434 got = read(fd, buf, get); 435 if (got <= 0) { 436 if (got < 0) 437 printf("kboot_readin: read failed\n"); 438 break; 439 } 440 441 kboot_copyin(buf, p, got); 442 } 443 444 free (buf); 445 return (len - resid); 446} 447 448int 449kboot_autoload(void) 450{ 451 452 return (0); 453} 454 455uint64_t 456kboot_loadaddr(u_int type, void *data, uint64_t addr) 457{ 458 459 if (type == LOAD_ELF) 460 addr = roundup(addr, PAGE_SIZE); 461 else 462 addr += kboot_get_phys_load_segment(); 463 464 return (addr); 465} 466 467static void 468kboot_kseg_get(int *nseg, void **ptr) 469{ 470#if 0 471 int a; 472 473 for (a = 0; a < nkexec_segments; a++) { 474 printf("kseg_get: %jx %jx %jx %jx\n", 475 (uintmax_t)loaded_segments[a].buf, 476 (uintmax_t)loaded_segments[a].bufsz, 477 (uintmax_t)loaded_segments[a].mem, 478 (uintmax_t)loaded_segments[a].memsz); 479 } 480#endif 481 482 *nseg = nkexec_segments; 483 *ptr = &loaded_segments[0]; 484} 485 486void 487_start(int argc, const char **argv, char **env) 488{ 489 register volatile void **sp asm("r1"); 490 main((int)sp[0], (const char **)&sp[1]); 491} 492 493/* 494 * Since proper fdt command handling function is defined in fdt_loader_cmd.c, 495 * and declaring it as extern is in contradiction with COMMAND_SET() macro 496 * (which uses static pointer), we're defining wrapper function, which 497 * calls the proper fdt handling routine. 498 */ 499static int 500command_fdt(int argc, char *argv[]) 501{ 502 503 return (command_fdt_internal(argc, argv)); 504} 505 506COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); 507 508