1176348Smarcel/*- 2176348Smarcel * Copyright (c) 2000 Benno Rice <benno@jeamland.net> 3176348Smarcel * Copyright (c) 2000 Stephane Potvin <sepotvin@videotron.ca> 4182732Sraj * Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com> 5176348Smarcel * All rights reserved. 6176348Smarcel * 7176348Smarcel * Redistribution and use in source and binary forms, with or without 8176348Smarcel * modification, are permitted provided that the following conditions 9176348Smarcel * are met: 10176348Smarcel * 1. Redistributions of source code must retain the above copyright 11176348Smarcel * notice, this list of conditions and the following disclaimer. 12176348Smarcel * 2. Redistributions in binary form must reproduce the above copyright 13176348Smarcel * notice, this list of conditions and the following disclaimer in the 14176348Smarcel * documentation and/or other materials provided with the distribution. 15176348Smarcel * 16176348Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17176348Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18176348Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19176348Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20176348Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21176348Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22176348Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23176348Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24176348Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25176348Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26176348Smarcel * SUCH DAMAGE. 27176348Smarcel */ 28176348Smarcel 29176348Smarcel#include <sys/cdefs.h> 30176348Smarcel__FBSDID("$FreeBSD: stable/11/stand/uboot/common/main.c 346483 2019-04-21 04:35:49Z kevans $"); 31283035Sian#include <sys/param.h> 32176348Smarcel 33176348Smarcel#include <stand.h> 34176482Smarcel 35176482Smarcel#include "api_public.h" 36176348Smarcel#include "bootstrap.h" 37176482Smarcel#include "glue.h" 38176348Smarcel#include "libuboot.h" 39176348Smarcel 40263052Sian#ifndef nitems 41263052Sian#define nitems(x) (sizeof((x)) / sizeof((x)[0])) 42263052Sian#endif 43263052Sian 44331307Skevans#ifndef HEAP_SIZE 45337815Skevans#define HEAP_SIZE (2 * 1024 * 1024) 46331307Skevans#endif 47331307Skevans 48182732Srajstruct uboot_devdesc currdev; 49182732Srajstruct arch_switch archsw; /* MI/MD interface boundary */ 50182732Srajint devs_no; 51176348Smarcel 52283035Sianuintptr_t uboot_heap_start; 53283035Sianuintptr_t uboot_heap_end; 54283035Sian 55263052Sianstruct device_type { 56263052Sian const char *name; 57263052Sian int type; 58263052Sian} device_types[] = { 59263052Sian { "disk", DEV_TYP_STOR }, 60263052Sian { "ide", DEV_TYP_STOR | DT_STOR_IDE }, 61263052Sian { "mmc", DEV_TYP_STOR | DT_STOR_MMC }, 62263052Sian { "sata", DEV_TYP_STOR | DT_STOR_SATA }, 63263052Sian { "scsi", DEV_TYP_STOR | DT_STOR_SCSI }, 64263052Sian { "usb", DEV_TYP_STOR | DT_STOR_USB }, 65263052Sian { "net", DEV_TYP_NET } 66263052Sian}; 67263052Sian 68176348Smarcelextern char end[]; 69176348Smarcel 70176348Smarcelextern unsigned char _etext[]; 71176348Smarcelextern unsigned char _edata[]; 72176348Smarcelextern unsigned char __bss_start[]; 73176348Smarcelextern unsigned char __sbss_start[]; 74176348Smarcelextern unsigned char __sbss_end[]; 75176348Smarcelextern unsigned char _end[]; 76176348Smarcel 77208538Sraj#ifdef LOADER_FDT_SUPPORT 78208538Srajextern int command_fdt_internal(int argc, char *argv[]); 79208538Sraj#endif 80208538Sraj 81182732Srajstatic void 82182732Srajdump_sig(struct api_signature *sig) 83176348Smarcel{ 84176348Smarcel#ifdef DEBUG 85176348Smarcel printf("signature:\n"); 86176348Smarcel printf(" version\t= %d\n", sig->version); 87176348Smarcel printf(" checksum\t= 0x%08x\n", sig->checksum); 88176348Smarcel printf(" sc entry\t= 0x%08x\n", sig->syscall); 89176348Smarcel#endif 90176348Smarcel} 91182732Sraj 92176348Smarcelstatic void 93176348Smarceldump_addr_info(void) 94176348Smarcel{ 95176348Smarcel#ifdef DEBUG 96176348Smarcel printf("\naddresses info:\n"); 97182732Sraj printf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext); 98182732Sraj printf(" _edata = 0x%08x\n", (uint32_t)_edata); 99182732Sraj printf(" __sbss_start = 0x%08x\n", (uint32_t)__sbss_start); 100182732Sraj printf(" __sbss_end = 0x%08x\n", (uint32_t)__sbss_end); 101182732Sraj printf(" __sbss_start = 0x%08x\n", (uint32_t)__bss_start); 102182732Sraj printf(" _end = 0x%08x\n", (uint32_t)_end); 103182732Sraj printf(" syscall entry = 0x%08x\n", (uint32_t)syscall_ptr); 104176348Smarcel#endif 105176348Smarcel} 106176348Smarcel 107176348Smarcelstatic uint64_t 108182732Srajmemsize(struct sys_info *si, int flags) 109176348Smarcel{ 110182732Sraj uint64_t size; 111182732Sraj int i; 112176348Smarcel 113176482Smarcel size = 0; 114176348Smarcel for (i = 0; i < si->mr_no; i++) 115176348Smarcel if (si->mr[i].flags == flags && si->mr[i].size) 116176482Smarcel size += (si->mr[i].size); 117176348Smarcel 118176482Smarcel return (size); 119176348Smarcel} 120176348Smarcel 121182732Srajstatic void 122182732Srajmeminfo(void) 123182732Sraj{ 124182732Sraj uint64_t size; 125182732Sraj struct sys_info *si; 126182732Sraj int t[3] = { MR_ATTR_DRAM, MR_ATTR_FLASH, MR_ATTR_SRAM }; 127182732Sraj int i; 128182732Sraj 129182732Sraj if ((si = ub_get_sys_info()) == NULL) 130182732Sraj panic("could not retrieve system info"); 131182732Sraj 132182732Sraj for (i = 0; i < 3; i++) { 133182732Sraj size = memsize(si, t[i]); 134182732Sraj if (size > 0) 135296182Ssgalabov printf("%s: %juMB\n", ub_mem_type(t[i]), 136296182Ssgalabov (uintmax_t)(size / 1024 / 1024)); 137182732Sraj } 138182732Sraj} 139182732Sraj 140263052Sianstatic const char * 141263052Sianget_device_type(const char *devstr, int *devtype) 142263052Sian{ 143263052Sian int i; 144263052Sian int namelen; 145263052Sian struct device_type *dt; 146263052Sian 147263052Sian if (devstr) { 148263052Sian for (i = 0; i < nitems(device_types); i++) { 149263052Sian dt = &device_types[i]; 150263052Sian namelen = strlen(dt->name); 151263052Sian if (strncmp(dt->name, devstr, namelen) == 0) { 152263052Sian *devtype = dt->type; 153263052Sian return (devstr + namelen); 154263052Sian } 155263052Sian } 156263052Sian printf("Unknown device type '%s'\n", devstr); 157263052Sian } 158263052Sian 159346483Skevans *devtype = DEV_TYP_NONE; 160263052Sian return (NULL); 161263052Sian} 162263052Sian 163263052Sianstatic const char * 164263052Siandevice_typename(int type) 165263052Sian{ 166263052Sian int i; 167263052Sian 168263052Sian for (i = 0; i < nitems(device_types); i++) 169263052Sian if (device_types[i].type == type) 170263052Sian return (device_types[i].name); 171263052Sian 172263052Sian return ("<unknown>"); 173263052Sian} 174263052Sian 175263052Sian/* 176263052Sian * Parse a device string into type, unit, slice and partition numbers. A 177263052Sian * returned value of -1 for type indicates a search should be done for the 178263052Sian * first loadable device, otherwise a returned value of -1 for unit 179263052Sian * indicates a search should be done for the first loadable device of the 180263052Sian * given type. 181263052Sian * 182263052Sian * The returned values for slice and partition are interpreted by 183263052Sian * disk_open(). 184263052Sian * 185346483Skevans * The device string can be a standard loader(8) disk specifier: 186346483Skevans * 187346483Skevans * disk<unit>s<slice> disk0s1 188346483Skevans * disk<unit>s<slice><partition> disk1s2a 189346483Skevans * disk<unit>p<partition> disk0p4 190346483Skevans * 191346483Skevans * or one of the following formats: 192346483Skevans * 193263052Sian * Valid device strings: For device types: 194263052Sian * 195263052Sian * <type_name> DEV_TYP_STOR, DEV_TYP_NET 196263052Sian * <type_name><unit> DEV_TYP_STOR, DEV_TYP_NET 197263052Sian * <type_name><unit>: DEV_TYP_STOR, DEV_TYP_NET 198263052Sian * <type_name><unit>:<slice> DEV_TYP_STOR 199263052Sian * <type_name><unit>:<slice>. DEV_TYP_STOR 200263052Sian * <type_name><unit>:<slice>.<partition> DEV_TYP_STOR 201263052Sian * 202263052Sian * For valid type names, see the device_types array, above. 203263052Sian * 204263052Sian * Slice numbers are 1-based. 0 is a wildcard. 205263052Sian */ 206263052Sianstatic void 207263052Sianget_load_device(int *type, int *unit, int *slice, int *partition) 208263052Sian{ 209346483Skevans struct disk_devdesc dev; 210263052Sian char *devstr; 211263052Sian const char *p; 212263052Sian char *endp; 213263052Sian 214346483Skevans *type = DEV_TYP_NONE; 215263267Sian *unit = -1; 216263267Sian *slice = 0; 217263267Sian *partition = -1; 218263267Sian 219263052Sian devstr = ub_env_get("loaderdev"); 220263267Sian if (devstr == NULL) { 221263267Sian printf("U-Boot env: loaderdev not set, will probe all devices.\n"); 222263267Sian return; 223263267Sian } 224263267Sian printf("U-Boot env: loaderdev='%s'\n", devstr); 225263052Sian 226263052Sian p = get_device_type(devstr, type); 227263052Sian 228346483Skevans /* 229346483Skevans * If type is DEV_TYP_STOR we have a disk-like device. If the remainder 230346483Skevans * of the string contains spaces, dots, or a colon in any location other 231346483Skevans * than the last char, it's legacy format. Otherwise it might be 232346483Skevans * standard loader(8) format (e.g., disk0s2a or mmc1p12), so try to 233346483Skevans * parse the remainder of the string as such, and if it works, return 234346483Skevans * those results. Otherwise we'll fall through to the code that parses 235346483Skevans * the legacy format. 236346483Skevans */ 237346483Skevans if (*type & DEV_TYP_STOR) { 238346483Skevans size_t len = strlen(p); 239346483Skevans if (strcspn(p, " .") == len && strcspn(p, ":") >= len - 1 && 240346483Skevans disk_parsedev(&dev, p, NULL) == 0) { 241346483Skevans *unit = dev.dd.d_unit; 242346483Skevans *slice = dev.d_slice; 243346483Skevans *partition = dev.d_partition; 244346483Skevans return; 245346483Skevans } 246346483Skevans } 247346483Skevans 248276026Sian /* Ignore optional spaces after the device name. */ 249276026Sian while (*p == ' ') 250276026Sian p++; 251276026Sian 252276026Sian /* Unknown device name, or a known name without unit number. */ 253346483Skevans if ((*type == DEV_TYP_NONE) || (*p == '\0')) { 254263052Sian return; 255263052Sian } 256263052Sian 257263052Sian /* Malformed unit number. */ 258263052Sian if (!isdigit(*p)) { 259346483Skevans *type = DEV_TYP_NONE; 260263052Sian return; 261263052Sian } 262263052Sian 263263052Sian /* Guaranteed to extract a number from the string, as *p is a digit. */ 264263052Sian *unit = strtol(p, &endp, 10); 265263052Sian p = endp; 266263052Sian 267263052Sian /* Known device name with unit number and nothing else. */ 268263052Sian if (*p == '\0') { 269263052Sian return; 270263052Sian } 271263052Sian 272263052Sian /* Device string is malformed beyond unit number. */ 273263052Sian if (*p != ':') { 274346483Skevans *type = DEV_TYP_NONE; 275263052Sian *unit = -1; 276263052Sian return; 277263052Sian } 278263052Sian 279263052Sian p++; 280263052Sian 281263052Sian /* No slice and partition specification. */ 282263052Sian if ('\0' == *p ) 283263052Sian return; 284263052Sian 285263052Sian /* Only DEV_TYP_STOR devices can have a slice specification. */ 286263052Sian if (!(*type & DEV_TYP_STOR)) { 287346483Skevans *type = DEV_TYP_NONE; 288263052Sian *unit = -1; 289263052Sian return; 290263052Sian } 291263052Sian 292263052Sian *slice = strtoul(p, &endp, 10); 293263052Sian 294263052Sian /* Malformed slice number. */ 295263052Sian if (p == endp) { 296346483Skevans *type = DEV_TYP_NONE; 297263052Sian *unit = -1; 298263052Sian *slice = 0; 299263052Sian return; 300263052Sian } 301263052Sian 302263052Sian p = endp; 303263052Sian 304263052Sian /* No partition specification. */ 305263052Sian if (*p == '\0') 306263052Sian return; 307263052Sian 308263052Sian /* Device string is malformed beyond slice number. */ 309263052Sian if (*p != '.') { 310346483Skevans *type = DEV_TYP_NONE; 311263052Sian *unit = -1; 312263052Sian *slice = 0; 313263052Sian return; 314263052Sian } 315263052Sian 316263052Sian p++; 317263052Sian 318263052Sian /* No partition specification. */ 319263052Sian if (*p == '\0') 320263052Sian return; 321263052Sian 322263052Sian *partition = strtol(p, &endp, 10); 323263052Sian p = endp; 324263052Sian 325263052Sian /* Full, valid device string. */ 326263052Sian if (*endp == '\0') 327263052Sian return; 328263052Sian 329263052Sian /* Junk beyond partition number. */ 330346483Skevans *type = DEV_TYP_NONE; 331263052Sian *unit = -1; 332263052Sian *slice = 0; 333263052Sian *partition = -1; 334263052Sian} 335263052Sian 336263267Sianstatic void 337263267Sianprint_disk_probe_info() 338263267Sian{ 339263267Sian char slice[32]; 340263267Sian char partition[32]; 341263267Sian 342346483Skevans if (currdev.d_disk.d_slice > 0) 343346483Skevans sprintf(slice, "%d", currdev.d_disk.d_slice); 344263267Sian else 345263267Sian strcpy(slice, "<auto>"); 346263267Sian 347346483Skevans if (currdev.d_disk.d_partition >= 0) 348346483Skevans sprintf(partition, "%d", currdev.d_disk.d_partition); 349263267Sian else 350263267Sian strcpy(partition, "<auto>"); 351263267Sian 352263267Sian printf(" Checking unit=%d slice=%s partition=%s...", 353332154Skevans currdev.dd.d_unit, slice, partition); 354263267Sian 355263267Sian} 356263267Sian 357263052Sianstatic int 358263124Sianprobe_disks(int devidx, int load_type, int load_unit, int load_slice, 359263124Sian int load_partition) 360263052Sian{ 361263124Sian int open_result, unit; 362263052Sian struct open_file f; 363263052Sian 364346483Skevans currdev.d_disk.d_slice = load_slice; 365346483Skevans currdev.d_disk.d_partition = load_partition; 366263052Sian 367263052Sian f.f_devdata = &currdev; 368263052Sian open_result = -1; 369263052Sian 370263052Sian if (load_type == -1) { 371263267Sian printf(" Probing all disk devices...\n"); 372263052Sian /* Try each disk in succession until one works. */ 373332154Skevans for (currdev.dd.d_unit = 0; currdev.dd.d_unit < UB_MAX_DEV; 374332154Skevans currdev.dd.d_unit++) { 375263267Sian print_disk_probe_info(); 376263124Sian open_result = devsw[devidx]->dv_open(&f, &currdev); 377263052Sian if (open_result == 0) { 378263052Sian printf(" good.\n"); 379263052Sian return (0); 380263052Sian } 381263052Sian printf("\n"); 382263052Sian } 383263052Sian return (-1); 384263052Sian } 385263052Sian 386263052Sian if (load_unit == -1) { 387263267Sian printf(" Probing all %s devices...\n", device_typename(load_type)); 388263052Sian /* Try each disk of given type in succession until one works. */ 389263052Sian for (unit = 0; unit < UB_MAX_DEV; unit++) { 390332154Skevans currdev.dd.d_unit = uboot_diskgetunit(load_type, unit); 391332154Skevans if (currdev.dd.d_unit == -1) 392263052Sian break; 393263267Sian print_disk_probe_info(); 394263124Sian open_result = devsw[devidx]->dv_open(&f, &currdev); 395263052Sian if (open_result == 0) { 396263052Sian printf(" good.\n"); 397263052Sian return (0); 398263052Sian } 399263052Sian printf("\n"); 400263052Sian } 401263052Sian return (-1); 402263052Sian } 403263052Sian 404332154Skevans if ((currdev.dd.d_unit = uboot_diskgetunit(load_type, load_unit)) != -1) { 405263267Sian print_disk_probe_info(); 406263124Sian open_result = devsw[devidx]->dv_open(&f,&currdev); 407263052Sian if (open_result == 0) { 408263267Sian printf(" good.\n"); 409263052Sian return (0); 410263052Sian } 411263052Sian printf("\n"); 412263052Sian } 413263052Sian 414291164Sian printf(" Requested disk type/unit/slice/partition not found\n"); 415263052Sian return (-1); 416263052Sian} 417263052Sian 418176348Smarcelint 419296564Ssgalabovmain(int argc, char **argv) 420176348Smarcel{ 421176348Smarcel struct api_signature *sig = NULL; 422263052Sian int load_type, load_unit, load_slice, load_partition; 423263052Sian int i; 424291164Sian const char *ldev; 425176348Smarcel 426262666Sian /* 427296564Ssgalabov * We first check if a command line argument was passed to us containing 428296564Ssgalabov * API's signature address. If it wasn't then we try to search for the 429296564Ssgalabov * API signature via the usual hinted address. 430262666Sian * If we can't find the magic signature and related info, exit with a 431262666Sian * unique error code that U-Boot reports as "## Application terminated, 432262666Sian * rc = 0xnnbadab1". Hopefully 'badab1' looks enough like "bad api" to 433262666Sian * provide a clue. It's better than 0xffffffff anyway. 434262666Sian */ 435296564Ssgalabov if (!api_parse_cmdline_sig(argc, argv, &sig) && !api_search_sig(&sig)) 436262666Sian return (0x01badab1); 437176348Smarcel 438176348Smarcel syscall_ptr = sig->syscall; 439176348Smarcel if (syscall_ptr == NULL) 440262666Sian return (0x02badab1); 441176348Smarcel 442176348Smarcel if (sig->version > API_SIG_VERSION) 443262666Sian return (0x03badab1); 444176348Smarcel 445176348Smarcel /* Clear BSS sections */ 446176348Smarcel bzero(__sbss_start, __sbss_end - __sbss_start); 447176348Smarcel bzero(__bss_start, _end - __bss_start); 448176348Smarcel 449176348Smarcel /* 450263267Sian * Initialise the heap as early as possible. Once this is done, 451323409Sian * alloc() is usable. We are using the stack u-boot set up near the top 452323409Sian * of physical ram; hopefully there is sufficient space between the end 453323409Sian * of our bss and the bottom of the u-boot stack to avoid overlap. 454263267Sian */ 455283035Sian uboot_heap_start = round_page((uintptr_t)end); 456331307Skevans uboot_heap_end = uboot_heap_start + HEAP_SIZE; 457283035Sian setheap((void *)uboot_heap_start, (void *)uboot_heap_end); 458263267Sian 459263267Sian /* 460263267Sian * Set up console. 461263267Sian */ 462176348Smarcel cons_probe(); 463296182Ssgalabov printf("Compatible U-Boot API signature found @%p\n", sig); 464176348Smarcel 465312318Semaste printf("\n%s", bootprog_info); 466263267Sian printf("\n"); 467176348Smarcel 468176348Smarcel dump_sig(sig); 469176348Smarcel dump_addr_info(); 470176348Smarcel 471263267Sian meminfo(); 472176348Smarcel 473176348Smarcel /* 474176348Smarcel * Enumerate U-Boot devices 475176348Smarcel */ 476344375Skevans if ((devs_no = ub_dev_enum()) == 0) { 477344375Skevans printf("no U-Boot devices found"); 478344375Skevans goto do_interact; 479344375Skevans } 480182732Sraj printf("Number of U-Boot devices: %d\n", devs_no); 481176348Smarcel 482263052Sian get_load_device(&load_type, &load_unit, &load_slice, &load_partition); 483263052Sian 484208534Sraj /* 485263052Sian * March through the device switch probing for things. 486208534Sraj */ 487204316Sraj for (i = 0; devsw[i] != NULL; i++) { 488204316Sraj 489208534Sraj if (devsw[i]->dv_init == NULL) 490208534Sraj continue; 491208534Sraj if ((devsw[i]->dv_init)() != 0) 492208534Sraj continue; 493208534Sraj 494263052Sian printf("Found U-Boot device: %s\n", devsw[i]->dv_name); 495208534Sraj 496332154Skevans currdev.dd.d_dev = devsw[i]; 497332154Skevans currdev.dd.d_unit = 0; 498263052Sian 499346483Skevans if ((load_type == DEV_TYP_NONE || (load_type & DEV_TYP_STOR)) && 500263052Sian strcmp(devsw[i]->dv_name, "disk") == 0) { 501263124Sian if (probe_disks(i, load_type, load_unit, load_slice, 502263052Sian load_partition) == 0) 503263052Sian break; 504204316Sraj } 505263052Sian 506346483Skevans if ((load_type == DEV_TYP_NONE || (load_type & DEV_TYP_NET)) && 507263265Sian strcmp(devsw[i]->dv_name, "net") == 0) 508263052Sian break; 509204316Sraj } 510176348Smarcel 511263052Sian /* 512263052Sian * If we couldn't find a boot device, return an error to u-boot. 513263052Sian * U-boot may be running a boot script that can try something different 514263052Sian * so returning an error is better than forcing a reboot. 515263052Sian */ 516263052Sian if (devsw[i] == NULL) { 517263052Sian printf("No boot device found!\n"); 518263052Sian return (0xbadef1ce); 519263052Sian } 520176348Smarcel 521291164Sian ldev = uboot_fmtdev(&currdev); 522291164Sian env_setenv("currdev", EV_VOLATILE, ldev, uboot_setcurrdev, env_nounset); 523291164Sian env_setenv("loaddev", EV_VOLATILE, ldev, env_noset, env_nounset); 524291876Sngie printf("Booting from %s\n", ldev); 525176348Smarcel 526344375Skevansdo_interact: 527176348Smarcel setenv("LINES", "24", 1); /* optional */ 528176348Smarcel setenv("prompt", "loader>", 1); 529176348Smarcel 530283035Sian archsw.arch_loadaddr = uboot_loadaddr; 531176348Smarcel archsw.arch_getdev = uboot_getdev; 532176348Smarcel archsw.arch_copyin = uboot_copyin; 533176348Smarcel archsw.arch_copyout = uboot_copyout; 534176348Smarcel archsw.arch_readin = uboot_readin; 535176348Smarcel archsw.arch_autoload = uboot_autoload; 536176348Smarcel 537329175Skevans interact(); /* doesn't return */ 538176348Smarcel 539182732Sraj return (0); 540176348Smarcel} 541176348Smarcel 542176348Smarcel 543176348SmarcelCOMMAND_SET(heap, "heap", "show heap usage", command_heap); 544176348Smarcelstatic int 545176348Smarcelcommand_heap(int argc, char *argv[]) 546176348Smarcel{ 547182723Sraj 548296182Ssgalabov printf("heap base at %p, top at %p, used %td\n", end, sbrk(0), 549177152Sobrien sbrk(0) - end); 550176348Smarcel 551182732Sraj return (CMD_OK); 552176348Smarcel} 553176348Smarcel 554176348SmarcelCOMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 555176348Smarcelstatic int 556176348Smarcelcommand_reboot(int argc, char *argv[]) 557176348Smarcel{ 558186231Sraj 559176348Smarcel printf("Resetting...\n"); 560176348Smarcel ub_reset(); 561176348Smarcel 562176348Smarcel printf("Reset failed!\n"); 563329175Skevans while (1); 564329175Skevans __unreachable(); 565176348Smarcel} 566182732Sraj 567182732SrajCOMMAND_SET(devinfo, "devinfo", "show U-Boot devices", command_devinfo); 568182732Srajstatic int 569182732Srajcommand_devinfo(int argc, char *argv[]) 570182732Sraj{ 571182732Sraj int i; 572182732Sraj 573182732Sraj if ((devs_no = ub_dev_enum()) == 0) { 574182732Sraj command_errmsg = "no U-Boot devices found!?"; 575182732Sraj return (CMD_ERROR); 576182732Sraj } 577182732Sraj 578182732Sraj printf("U-Boot devices:\n"); 579182732Sraj for (i = 0; i < devs_no; i++) { 580182732Sraj ub_dump_di(i); 581182732Sraj printf("\n"); 582182732Sraj } 583182732Sraj return (CMD_OK); 584182732Sraj} 585182732Sraj 586182732SrajCOMMAND_SET(sysinfo, "sysinfo", "show U-Boot system info", command_sysinfo); 587182732Srajstatic int 588182732Srajcommand_sysinfo(int argc, char *argv[]) 589182732Sraj{ 590182732Sraj struct sys_info *si; 591182732Sraj 592182732Sraj if ((si = ub_get_sys_info()) == NULL) { 593182732Sraj command_errmsg = "could not retrieve U-Boot sys info!?"; 594182732Sraj return (CMD_ERROR); 595182732Sraj } 596182732Sraj 597182732Sraj printf("U-Boot system info:\n"); 598182732Sraj ub_dump_si(si); 599182732Sraj return (CMD_OK); 600182732Sraj} 601208538Sraj 602271285Sianenum ubenv_action { 603271285Sian UBENV_UNKNOWN, 604271285Sian UBENV_SHOW, 605271285Sian UBENV_IMPORT 606271285Sian}; 607271285Sian 608271285Sianstatic void 609271285Sianhandle_uboot_env_var(enum ubenv_action action, const char * var) 610271285Sian{ 611292227Sian char ldvar[128]; 612292227Sian const char *val; 613292227Sian char *wrk; 614292227Sian int len; 615271285Sian 616271285Sian /* 617292227Sian * On an import with the variable name formatted as ldname=ubname, 618292227Sian * import the uboot variable ubname into the loader variable ldname, 619292227Sian * otherwise the historical behavior is to import to uboot.ubname. 620292227Sian */ 621292227Sian if (action == UBENV_IMPORT) { 622292227Sian len = strcspn(var, "="); 623292888Sian if (len == 0) { 624292888Sian printf("name cannot start with '=': '%s'\n", var); 625292888Sian return; 626292888Sian } 627292227Sian if (var[len] == 0) { 628292227Sian strcpy(ldvar, "uboot."); 629292227Sian strncat(ldvar, var, sizeof(ldvar) - 7); 630292227Sian } else { 631292227Sian len = MIN(len, sizeof(ldvar) - 1); 632292227Sian strncpy(ldvar, var, len); 633292227Sian ldvar[len] = 0; 634292227Sian var = &var[len + 1]; 635292227Sian } 636292227Sian } 637292227Sian 638292227Sian /* 639271285Sian * If the user prepended "uboot." (which is how they usually see these 640271285Sian * names) strip it off as a convenience. 641271285Sian */ 642271285Sian if (strncmp(var, "uboot.", 6) == 0) { 643292227Sian var = &var[6]; 644271285Sian } 645292227Sian 646292888Sian /* If there is no variable name left, punt. */ 647292888Sian if (var[0] == 0) { 648292888Sian printf("empty variable name\n"); 649292227Sian return; 650292888Sian } 651292227Sian 652271285Sian val = ub_env_get(var); 653271285Sian if (action == UBENV_SHOW) { 654271285Sian if (val == NULL) 655271285Sian printf("uboot.%s is not set\n", var); 656271285Sian else 657271285Sian printf("uboot.%s=%s\n", var, val); 658271285Sian } else if (action == UBENV_IMPORT) { 659271285Sian if (val != NULL) { 660292227Sian setenv(ldvar, val, 1); 661271285Sian } 662271285Sian } 663271285Sian} 664271285Sian 665271285Sianstatic int 666271285Siancommand_ubenv(int argc, char *argv[]) 667271285Sian{ 668271285Sian enum ubenv_action action; 669271285Sian const char *var; 670271285Sian int i; 671271285Sian 672271285Sian action = UBENV_UNKNOWN; 673271285Sian if (argc > 1) { 674271285Sian if (strcasecmp(argv[1], "import") == 0) 675271285Sian action = UBENV_IMPORT; 676271285Sian else if (strcasecmp(argv[1], "show") == 0) 677271285Sian action = UBENV_SHOW; 678271285Sian } 679271285Sian if (action == UBENV_UNKNOWN) { 680271285Sian command_errmsg = "usage: 'ubenv <import|show> [var ...]"; 681271285Sian return (CMD_ERROR); 682271285Sian } 683271285Sian 684271285Sian if (argc > 2) { 685271285Sian for (i = 2; i < argc; i++) 686271285Sian handle_uboot_env_var(action, argv[i]); 687271285Sian } else { 688271285Sian var = NULL; 689271285Sian for (;;) { 690271285Sian if ((var = ub_env_enum(var)) == NULL) 691271285Sian break; 692271285Sian handle_uboot_env_var(action, var); 693271285Sian } 694271285Sian } 695271285Sian 696271285Sian return (CMD_OK); 697271285Sian} 698271285SianCOMMAND_SET(ubenv, "ubenv", "show or import U-Boot env vars", command_ubenv); 699271285Sian 700208538Sraj#ifdef LOADER_FDT_SUPPORT 701208538Sraj/* 702208538Sraj * Since proper fdt command handling function is defined in fdt_loader_cmd.c, 703208538Sraj * and declaring it as extern is in contradiction with COMMAND_SET() macro 704208538Sraj * (which uses static pointer), we're defining wrapper function, which 705208538Sraj * calls the proper fdt handling routine. 706208538Sraj */ 707208538Srajstatic int 708208538Srajcommand_fdt(int argc, char *argv[]) 709208538Sraj{ 710208538Sraj 711208538Sraj return (command_fdt_internal(argc, argv)); 712208538Sraj} 713208538Sraj 714208538SrajCOMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); 715208538Sraj#endif 716