main.c revision 329183
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 329183 2018-02-12 20:51:28Z 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 295 interact(); /* doesn't return */ 296 297 return (0); 298} 299 300void 301exit(int code) 302{ 303 while (1); /* XXX: host_exit */ 304 __unreachable(); 305} 306 307void 308delay(int usecs) 309{ 310 struct host_timeval tvi, tv; 311 uint64_t ti, t; 312 host_gettimeofday(&tvi, NULL); 313 ti = tvi.tv_sec*1000000 + tvi.tv_usec; 314 do { 315 host_gettimeofday(&tv, NULL); 316 t = tv.tv_sec*1000000 + tv.tv_usec; 317 } while (t < ti + usecs); 318} 319 320time_t 321getsecs(void) 322{ 323 struct host_timeval tv; 324 host_gettimeofday(&tv, NULL); 325 return (tv.tv_sec); 326} 327 328time_t 329time(time_t *tloc) 330{ 331 time_t rv; 332 333 rv = getsecs(); 334 if (tloc != NULL) 335 *tloc = rv; 336 337 return (rv); 338} 339 340struct kexec_segment { 341 void *buf; 342 int bufsz; 343 void *mem; 344 int memsz; 345}; 346 347struct kexec_segment loaded_segments[128]; 348int nkexec_segments = 0; 349 350static ssize_t 351get_phys_buffer(vm_offset_t dest, const size_t len, void **buf) 352{ 353 int i = 0; 354 const size_t segsize = 4*1024*1024; 355 356 for (i = 0; i < nkexec_segments; i++) { 357 if (dest >= (vm_offset_t)loaded_segments[i].mem && 358 dest < (vm_offset_t)loaded_segments[i].mem + 359 loaded_segments[i].memsz) 360 goto out; 361 } 362 363 loaded_segments[nkexec_segments].buf = host_getmem(segsize); 364 loaded_segments[nkexec_segments].bufsz = segsize; 365 loaded_segments[nkexec_segments].mem = (void *)rounddown2(dest,segsize); 366 loaded_segments[nkexec_segments].memsz = segsize; 367 368 i = nkexec_segments; 369 nkexec_segments++; 370 371out: 372 *buf = loaded_segments[i].buf + (dest - 373 (vm_offset_t)loaded_segments[i].mem); 374 return (min(len,loaded_segments[i].bufsz - (dest - 375 (vm_offset_t)loaded_segments[i].mem))); 376} 377 378ssize_t 379kboot_copyin(const void *src, vm_offset_t dest, const size_t len) 380{ 381 ssize_t segsize, remainder; 382 void *destbuf; 383 384 remainder = len; 385 do { 386 segsize = get_phys_buffer(dest, remainder, &destbuf); 387 bcopy(src, destbuf, segsize); 388 remainder -= segsize; 389 src += segsize; 390 dest += segsize; 391 } while (remainder > 0); 392 393 return (len); 394} 395 396ssize_t 397kboot_copyout(vm_offset_t src, void *dest, const size_t len) 398{ 399 ssize_t segsize, remainder; 400 void *srcbuf; 401 402 remainder = len; 403 do { 404 segsize = get_phys_buffer(src, remainder, &srcbuf); 405 bcopy(srcbuf, dest, segsize); 406 remainder -= segsize; 407 src += segsize; 408 dest += segsize; 409 } while (remainder > 0); 410 411 return (len); 412} 413 414ssize_t 415kboot_readin(const int fd, vm_offset_t dest, const size_t len) 416{ 417 void *buf; 418 size_t resid, chunk, get; 419 ssize_t got; 420 vm_offset_t p; 421 422 p = dest; 423 424 chunk = min(PAGE_SIZE, len); 425 buf = malloc(chunk); 426 if (buf == NULL) { 427 printf("kboot_readin: buf malloc failed\n"); 428 return (0); 429 } 430 431 for (resid = len; resid > 0; resid -= got, p += got) { 432 get = min(chunk, resid); 433 got = read(fd, buf, get); 434 if (got <= 0) { 435 if (got < 0) 436 printf("kboot_readin: read failed\n"); 437 break; 438 } 439 440 kboot_copyin(buf, p, got); 441 } 442 443 free (buf); 444 return (len - resid); 445} 446 447int 448kboot_autoload(void) 449{ 450 451 return (0); 452} 453 454uint64_t 455kboot_loadaddr(u_int type, void *data, uint64_t addr) 456{ 457 458 if (type == LOAD_ELF) 459 addr = roundup(addr, PAGE_SIZE); 460 else 461 addr += kboot_get_phys_load_segment(); 462 463 return (addr); 464} 465 466static void 467kboot_kseg_get(int *nseg, void **ptr) 468{ 469#if 0 470 int a; 471 472 for (a = 0; a < nkexec_segments; a++) { 473 printf("kseg_get: %jx %jx %jx %jx\n", 474 (uintmax_t)loaded_segments[a].buf, 475 (uintmax_t)loaded_segments[a].bufsz, 476 (uintmax_t)loaded_segments[a].mem, 477 (uintmax_t)loaded_segments[a].memsz); 478 } 479#endif 480 481 *nseg = nkexec_segments; 482 *ptr = &loaded_segments[0]; 483} 484 485void 486_start(int argc, const char **argv, char **env) 487{ 488 register volatile void **sp asm("r1"); 489 main((int)sp[0], (const char **)&sp[1]); 490} 491 492/* 493 * Since proper fdt command handling function is defined in fdt_loader_cmd.c, 494 * and declaring it as extern is in contradiction with COMMAND_SET() macro 495 * (which uses static pointer), we're defining wrapper function, which 496 * calls the proper fdt handling routine. 497 */ 498static int 499command_fdt(int argc, char *argv[]) 500{ 501 502 return (command_fdt_internal(argc, argv)); 503} 504 505COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); 506 507