main.c revision 272461
1/*- 2 * Copyright (c) 2000 Benno Rice <benno@jeamland.net> 3 * Copyright (c) 2000 Stephane Potvin <sepotvin@videotron.ca> 4 * Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: releng/10.1/sys/boot/uboot/common/main.c 265071 2014-04-29 00:45:42Z ian $"); 31 32#include <stand.h> 33 34#include "api_public.h" 35#include "bootstrap.h" 36#include "glue.h" 37#include "libuboot.h" 38 39#ifndef nitems 40#define nitems(x) (sizeof((x)) / sizeof((x)[0])) 41#endif 42 43struct uboot_devdesc currdev; 44struct arch_switch archsw; /* MI/MD interface boundary */ 45int devs_no; 46 47struct device_type { 48 const char *name; 49 int type; 50} device_types[] = { 51 { "disk", DEV_TYP_STOR }, 52 { "ide", DEV_TYP_STOR | DT_STOR_IDE }, 53 { "mmc", DEV_TYP_STOR | DT_STOR_MMC }, 54 { "sata", DEV_TYP_STOR | DT_STOR_SATA }, 55 { "scsi", DEV_TYP_STOR | DT_STOR_SCSI }, 56 { "usb", DEV_TYP_STOR | DT_STOR_USB }, 57 { "net", DEV_TYP_NET } 58}; 59 60extern char end[]; 61extern char bootprog_name[]; 62extern char bootprog_rev[]; 63extern char bootprog_date[]; 64extern char bootprog_maker[]; 65 66extern unsigned char _etext[]; 67extern unsigned char _edata[]; 68extern unsigned char __bss_start[]; 69extern unsigned char __sbss_start[]; 70extern unsigned char __sbss_end[]; 71extern unsigned char _end[]; 72 73#ifdef LOADER_FDT_SUPPORT 74extern int command_fdt_internal(int argc, char *argv[]); 75#endif 76 77static void 78dump_sig(struct api_signature *sig) 79{ 80#ifdef DEBUG 81 printf("signature:\n"); 82 printf(" version\t= %d\n", sig->version); 83 printf(" checksum\t= 0x%08x\n", sig->checksum); 84 printf(" sc entry\t= 0x%08x\n", sig->syscall); 85#endif 86} 87 88static void 89dump_addr_info(void) 90{ 91#ifdef DEBUG 92 printf("\naddresses info:\n"); 93 printf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext); 94 printf(" _edata = 0x%08x\n", (uint32_t)_edata); 95 printf(" __sbss_start = 0x%08x\n", (uint32_t)__sbss_start); 96 printf(" __sbss_end = 0x%08x\n", (uint32_t)__sbss_end); 97 printf(" __sbss_start = 0x%08x\n", (uint32_t)__bss_start); 98 printf(" _end = 0x%08x\n", (uint32_t)_end); 99 printf(" syscall entry = 0x%08x\n", (uint32_t)syscall_ptr); 100#endif 101} 102 103static uint64_t 104memsize(struct sys_info *si, int flags) 105{ 106 uint64_t size; 107 int i; 108 109 size = 0; 110 for (i = 0; i < si->mr_no; i++) 111 if (si->mr[i].flags == flags && si->mr[i].size) 112 size += (si->mr[i].size); 113 114 return (size); 115} 116 117static void 118meminfo(void) 119{ 120 uint64_t size; 121 struct sys_info *si; 122 int t[3] = { MR_ATTR_DRAM, MR_ATTR_FLASH, MR_ATTR_SRAM }; 123 int i; 124 125 if ((si = ub_get_sys_info()) == NULL) 126 panic("could not retrieve system info"); 127 128 for (i = 0; i < 3; i++) { 129 size = memsize(si, t[i]); 130 if (size > 0) 131 printf("%s: %lldMB\n", ub_mem_type(t[i]), 132 size / 1024 / 1024); 133 } 134} 135 136static const char * 137get_device_type(const char *devstr, int *devtype) 138{ 139 int i; 140 int namelen; 141 struct device_type *dt; 142 143 if (devstr) { 144 for (i = 0; i < nitems(device_types); i++) { 145 dt = &device_types[i]; 146 namelen = strlen(dt->name); 147 if (strncmp(dt->name, devstr, namelen) == 0) { 148 *devtype = dt->type; 149 return (devstr + namelen); 150 } 151 } 152 printf("Unknown device type '%s'\n", devstr); 153 } 154 155 *devtype = -1; 156 return (NULL); 157} 158 159static const char * 160device_typename(int type) 161{ 162 int i; 163 164 for (i = 0; i < nitems(device_types); i++) 165 if (device_types[i].type == type) 166 return (device_types[i].name); 167 168 return ("<unknown>"); 169} 170 171/* 172 * Parse a device string into type, unit, slice and partition numbers. A 173 * returned value of -1 for type indicates a search should be done for the 174 * first loadable device, otherwise a returned value of -1 for unit 175 * indicates a search should be done for the first loadable device of the 176 * given type. 177 * 178 * The returned values for slice and partition are interpreted by 179 * disk_open(). 180 * 181 * Valid device strings: For device types: 182 * 183 * <type_name> DEV_TYP_STOR, DEV_TYP_NET 184 * <type_name><unit> DEV_TYP_STOR, DEV_TYP_NET 185 * <type_name><unit>: DEV_TYP_STOR, DEV_TYP_NET 186 * <type_name><unit>:<slice> DEV_TYP_STOR 187 * <type_name><unit>:<slice>. DEV_TYP_STOR 188 * <type_name><unit>:<slice>.<partition> DEV_TYP_STOR 189 * 190 * For valid type names, see the device_types array, above. 191 * 192 * Slice numbers are 1-based. 0 is a wildcard. 193 */ 194static void 195get_load_device(int *type, int *unit, int *slice, int *partition) 196{ 197 char *devstr; 198 const char *p; 199 char *endp; 200 201 *type = -1; 202 *unit = -1; 203 *slice = 0; 204 *partition = -1; 205 206 devstr = ub_env_get("loaderdev"); 207 if (devstr == NULL) { 208 printf("U-Boot env: loaderdev not set, will probe all devices.\n"); 209 return; 210 } 211 printf("U-Boot env: loaderdev='%s'\n", devstr); 212 213 p = get_device_type(devstr, type); 214 215 /* 216 * Empty device string, or unknown device name, or a bare, known 217 * device name. 218 */ 219 if ((*type == -1) || (*p == '\0')) { 220 return; 221 } 222 223 /* Malformed unit number. */ 224 if (!isdigit(*p)) { 225 *type = -1; 226 return; 227 } 228 229 /* Guaranteed to extract a number from the string, as *p is a digit. */ 230 *unit = strtol(p, &endp, 10); 231 p = endp; 232 233 /* Known device name with unit number and nothing else. */ 234 if (*p == '\0') { 235 return; 236 } 237 238 /* Device string is malformed beyond unit number. */ 239 if (*p != ':') { 240 *type = -1; 241 *unit = -1; 242 return; 243 } 244 245 p++; 246 247 /* No slice and partition specification. */ 248 if ('\0' == *p ) 249 return; 250 251 /* Only DEV_TYP_STOR devices can have a slice specification. */ 252 if (!(*type & DEV_TYP_STOR)) { 253 *type = -1; 254 *unit = -1; 255 return; 256 } 257 258 *slice = strtoul(p, &endp, 10); 259 260 /* Malformed slice number. */ 261 if (p == endp) { 262 *type = -1; 263 *unit = -1; 264 *slice = 0; 265 return; 266 } 267 268 p = endp; 269 270 /* No partition specification. */ 271 if (*p == '\0') 272 return; 273 274 /* Device string is malformed beyond slice number. */ 275 if (*p != '.') { 276 *type = -1; 277 *unit = -1; 278 *slice = 0; 279 return; 280 } 281 282 p++; 283 284 /* No partition specification. */ 285 if (*p == '\0') 286 return; 287 288 *partition = strtol(p, &endp, 10); 289 p = endp; 290 291 /* Full, valid device string. */ 292 if (*endp == '\0') 293 return; 294 295 /* Junk beyond partition number. */ 296 *type = -1; 297 *unit = -1; 298 *slice = 0; 299 *partition = -1; 300} 301 302static void 303print_disk_probe_info() 304{ 305 char slice[32]; 306 char partition[32]; 307 308 if (currdev.d_disk.slice > 0) 309 sprintf(slice, "%d", currdev.d_disk.slice); 310 else 311 strcpy(slice, "<auto>"); 312 313 if (currdev.d_disk.partition > 0) 314 sprintf(partition, "%d", currdev.d_disk.partition); 315 else 316 strcpy(partition, "<auto>"); 317 318 printf(" Checking unit=%d slice=%s partition=%s...", 319 currdev.d_unit, slice, partition); 320 321} 322 323static int 324probe_disks(int devidx, int load_type, int load_unit, int load_slice, 325 int load_partition) 326{ 327 int open_result, unit; 328 struct open_file f; 329 330 currdev.d_disk.slice = load_slice; 331 currdev.d_disk.partition = load_partition; 332 333 f.f_devdata = &currdev; 334 open_result = -1; 335 336 if (load_type == -1) { 337 printf(" Probing all disk devices...\n"); 338 /* Try each disk in succession until one works. */ 339 for (currdev.d_unit = 0; currdev.d_unit < UB_MAX_DEV; 340 currdev.d_unit++) { 341 print_disk_probe_info(); 342 open_result = devsw[devidx]->dv_open(&f, &currdev); 343 if (open_result == 0) { 344 printf(" good.\n"); 345 return (0); 346 } 347 printf("\n"); 348 } 349 return (-1); 350 } 351 352 if (load_unit == -1) { 353 printf(" Probing all %s devices...\n", device_typename(load_type)); 354 /* Try each disk of given type in succession until one works. */ 355 for (unit = 0; unit < UB_MAX_DEV; unit++) { 356 currdev.d_unit = uboot_diskgetunit(load_type, unit); 357 if (currdev.d_unit == -1) 358 break; 359 print_disk_probe_info(); 360 open_result = devsw[devidx]->dv_open(&f, &currdev); 361 if (open_result == 0) { 362 printf(" good.\n"); 363 return (0); 364 } 365 printf("\n"); 366 } 367 return (-1); 368 } 369 370 if ((currdev.d_unit = uboot_diskgetunit(load_type, load_unit)) != -1) { 371 print_disk_probe_info(); 372 open_result = devsw[devidx]->dv_open(&f,&currdev); 373 if (open_result == 0) { 374 printf(" good.\n"); 375 return (0); 376 } 377 printf("\n"); 378 } 379 380 printf(" Requested disk type/unit not found\n"); 381 return (-1); 382} 383 384int 385main(void) 386{ 387 struct api_signature *sig = NULL; 388 int load_type, load_unit, load_slice, load_partition; 389 int i; 390 const char * loaderdev; 391 392 /* 393 * If we can't find the magic signature and related info, exit with a 394 * unique error code that U-Boot reports as "## Application terminated, 395 * rc = 0xnnbadab1". Hopefully 'badab1' looks enough like "bad api" to 396 * provide a clue. It's better than 0xffffffff anyway. 397 */ 398 if (!api_search_sig(&sig)) 399 return (0x01badab1); 400 401 syscall_ptr = sig->syscall; 402 if (syscall_ptr == NULL) 403 return (0x02badab1); 404 405 if (sig->version > API_SIG_VERSION) 406 return (0x03badab1); 407 408 /* Clear BSS sections */ 409 bzero(__sbss_start, __sbss_end - __sbss_start); 410 bzero(__bss_start, _end - __bss_start); 411 412 /* 413 * Initialise the heap as early as possible. Once this is done, 414 * alloc() is usable. The stack is buried inside us, so this is safe. 415 */ 416 setheap((void *)end, (void *)(end + 512 * 1024)); 417 418 /* 419 * Set up console. 420 */ 421 cons_probe(); 422 printf("Compatible U-Boot API signature found @%x\n", (uint32_t)sig); 423 424 printf("\n"); 425 printf("%s, Revision %s\n", bootprog_name, bootprog_rev); 426 printf("(%s, %s)\n", bootprog_maker, bootprog_date); 427 printf("\n"); 428 429 dump_sig(sig); 430 dump_addr_info(); 431 432 meminfo(); 433 434 /* 435 * Enumerate U-Boot devices 436 */ 437 if ((devs_no = ub_dev_enum()) == 0) 438 panic("no U-Boot devices found"); 439 printf("Number of U-Boot devices: %d\n", devs_no); 440 441 get_load_device(&load_type, &load_unit, &load_slice, &load_partition); 442 443 /* 444 * March through the device switch probing for things. 445 */ 446 for (i = 0; devsw[i] != NULL; i++) { 447 448 if (devsw[i]->dv_init == NULL) 449 continue; 450 if ((devsw[i]->dv_init)() != 0) 451 continue; 452 453 printf("Found U-Boot device: %s\n", devsw[i]->dv_name); 454 455 currdev.d_dev = devsw[i]; 456 currdev.d_type = currdev.d_dev->dv_type; 457 currdev.d_unit = 0; 458 459 if ((load_type == -1 || (load_type & DEV_TYP_STOR)) && 460 strcmp(devsw[i]->dv_name, "disk") == 0) { 461 if (probe_disks(i, load_type, load_unit, load_slice, 462 load_partition) == 0) 463 break; 464 } 465 466 if ((load_type == -1 || (load_type & DEV_TYP_NET)) && 467 strcmp(devsw[i]->dv_name, "net") == 0) 468 break; 469 } 470 471 /* 472 * If we couldn't find a boot device, return an error to u-boot. 473 * U-boot may be running a boot script that can try something different 474 * so returning an error is better than forcing a reboot. 475 */ 476 if (devsw[i] == NULL) { 477 printf("No boot device found!\n"); 478 return (0xbadef1ce); 479 } 480 481 env_setenv("currdev", EV_VOLATILE, uboot_fmtdev(&currdev), 482 uboot_setcurrdev, env_nounset); 483 env_setenv("loaddev", EV_VOLATILE, uboot_fmtdev(&currdev), 484 env_noset, env_nounset); 485 486 setenv("LINES", "24", 1); /* optional */ 487 setenv("prompt", "loader>", 1); 488 489 archsw.arch_getdev = uboot_getdev; 490 archsw.arch_copyin = uboot_copyin; 491 archsw.arch_copyout = uboot_copyout; 492 archsw.arch_readin = uboot_readin; 493 archsw.arch_autoload = uboot_autoload; 494 495 interact(); /* doesn't return */ 496 497 return (0); 498} 499 500 501COMMAND_SET(heap, "heap", "show heap usage", command_heap); 502static int 503command_heap(int argc, char *argv[]) 504{ 505 506 printf("heap base at %p, top at %p, used %d\n", end, sbrk(0), 507 sbrk(0) - end); 508 509 return (CMD_OK); 510} 511 512COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 513static int 514command_reboot(int argc, char *argv[]) 515{ 516 517 printf("Resetting...\n"); 518 ub_reset(); 519 520 printf("Reset failed!\n"); 521 while(1); 522} 523 524COMMAND_SET(devinfo, "devinfo", "show U-Boot devices", command_devinfo); 525static int 526command_devinfo(int argc, char *argv[]) 527{ 528 int i; 529 530 if ((devs_no = ub_dev_enum()) == 0) { 531 command_errmsg = "no U-Boot devices found!?"; 532 return (CMD_ERROR); 533 } 534 535 printf("U-Boot devices:\n"); 536 for (i = 0; i < devs_no; i++) { 537 ub_dump_di(i); 538 printf("\n"); 539 } 540 return (CMD_OK); 541} 542 543COMMAND_SET(sysinfo, "sysinfo", "show U-Boot system info", command_sysinfo); 544static int 545command_sysinfo(int argc, char *argv[]) 546{ 547 struct sys_info *si; 548 549 if ((si = ub_get_sys_info()) == NULL) { 550 command_errmsg = "could not retrieve U-Boot sys info!?"; 551 return (CMD_ERROR); 552 } 553 554 printf("U-Boot system info:\n"); 555 ub_dump_si(si); 556 return (CMD_OK); 557} 558 559#ifdef LOADER_FDT_SUPPORT 560/* 561 * Since proper fdt command handling function is defined in fdt_loader_cmd.c, 562 * and declaring it as extern is in contradiction with COMMAND_SET() macro 563 * (which uses static pointer), we're defining wrapper function, which 564 * calls the proper fdt handling routine. 565 */ 566static int 567command_fdt(int argc, char *argv[]) 568{ 569 570 return (command_fdt_internal(argc, argv)); 571} 572 573COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); 574#endif 575