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$"); 31283505Sian#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 40265071Sian#ifndef nitems 41265071Sian#define nitems(x) (sizeof((x)) / sizeof((x)[0])) 42265071Sian#endif 43265071Sian 44182732Srajstruct uboot_devdesc currdev; 45182732Srajstruct arch_switch archsw; /* MI/MD interface boundary */ 46182732Srajint devs_no; 47176348Smarcel 48283505Sianuintptr_t uboot_heap_start; 49283505Sianuintptr_t uboot_heap_end; 50283505Sian 51265071Sianstruct device_type { 52265071Sian const char *name; 53265071Sian int type; 54265071Sian} device_types[] = { 55265071Sian { "disk", DEV_TYP_STOR }, 56265071Sian { "ide", DEV_TYP_STOR | DT_STOR_IDE }, 57265071Sian { "mmc", DEV_TYP_STOR | DT_STOR_MMC }, 58265071Sian { "sata", DEV_TYP_STOR | DT_STOR_SATA }, 59265071Sian { "scsi", DEV_TYP_STOR | DT_STOR_SCSI }, 60265071Sian { "usb", DEV_TYP_STOR | DT_STOR_USB }, 61265071Sian { "net", DEV_TYP_NET } 62265071Sian}; 63265071Sian 64176348Smarcelextern char end[]; 65176348Smarcelextern char bootprog_name[]; 66176348Smarcelextern char bootprog_rev[]; 67176348Smarcelextern char bootprog_date[]; 68176348Smarcelextern char bootprog_maker[]; 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) 135265071Sian printf("%s: %lldMB\n", ub_mem_type(t[i]), 136182732Sraj size / 1024 / 1024); 137182732Sraj } 138182732Sraj} 139182732Sraj 140265071Sianstatic const char * 141265071Sianget_device_type(const char *devstr, int *devtype) 142265071Sian{ 143265071Sian int i; 144265071Sian int namelen; 145265071Sian struct device_type *dt; 146265071Sian 147265071Sian if (devstr) { 148265071Sian for (i = 0; i < nitems(device_types); i++) { 149265071Sian dt = &device_types[i]; 150265071Sian namelen = strlen(dt->name); 151265071Sian if (strncmp(dt->name, devstr, namelen) == 0) { 152265071Sian *devtype = dt->type; 153265071Sian return (devstr + namelen); 154265071Sian } 155265071Sian } 156265071Sian printf("Unknown device type '%s'\n", devstr); 157265071Sian } 158265071Sian 159265071Sian *devtype = -1; 160265071Sian return (NULL); 161265071Sian} 162265071Sian 163265071Sianstatic const char * 164265071Siandevice_typename(int type) 165265071Sian{ 166265071Sian int i; 167265071Sian 168265071Sian for (i = 0; i < nitems(device_types); i++) 169265071Sian if (device_types[i].type == type) 170265071Sian return (device_types[i].name); 171265071Sian 172265071Sian return ("<unknown>"); 173265071Sian} 174265071Sian 175265071Sian/* 176265071Sian * Parse a device string into type, unit, slice and partition numbers. A 177265071Sian * returned value of -1 for type indicates a search should be done for the 178265071Sian * first loadable device, otherwise a returned value of -1 for unit 179265071Sian * indicates a search should be done for the first loadable device of the 180265071Sian * given type. 181265071Sian * 182265071Sian * The returned values for slice and partition are interpreted by 183265071Sian * disk_open(). 184265071Sian * 185265071Sian * Valid device strings: For device types: 186265071Sian * 187265071Sian * <type_name> DEV_TYP_STOR, DEV_TYP_NET 188265071Sian * <type_name><unit> DEV_TYP_STOR, DEV_TYP_NET 189265071Sian * <type_name><unit>: DEV_TYP_STOR, DEV_TYP_NET 190265071Sian * <type_name><unit>:<slice> DEV_TYP_STOR 191265071Sian * <type_name><unit>:<slice>. DEV_TYP_STOR 192265071Sian * <type_name><unit>:<slice>.<partition> DEV_TYP_STOR 193265071Sian * 194265071Sian * For valid type names, see the device_types array, above. 195265071Sian * 196265071Sian * Slice numbers are 1-based. 0 is a wildcard. 197265071Sian */ 198265071Sianstatic void 199265071Sianget_load_device(int *type, int *unit, int *slice, int *partition) 200265071Sian{ 201265071Sian char *devstr; 202265071Sian const char *p; 203265071Sian char *endp; 204265071Sian 205265071Sian *type = -1; 206265071Sian *unit = -1; 207265071Sian *slice = 0; 208265071Sian *partition = -1; 209265071Sian 210265071Sian devstr = ub_env_get("loaderdev"); 211265071Sian if (devstr == NULL) { 212265071Sian printf("U-Boot env: loaderdev not set, will probe all devices.\n"); 213265071Sian return; 214265071Sian } 215265071Sian printf("U-Boot env: loaderdev='%s'\n", devstr); 216265071Sian 217265071Sian p = get_device_type(devstr, type); 218265071Sian 219276289Sian /* Ignore optional spaces after the device name. */ 220276289Sian while (*p == ' ') 221276289Sian p++; 222276289Sian 223276289Sian /* Unknown device name, or a known name without unit number. */ 224265071Sian if ((*type == -1) || (*p == '\0')) { 225265071Sian return; 226265071Sian } 227265071Sian 228265071Sian /* Malformed unit number. */ 229265071Sian if (!isdigit(*p)) { 230265071Sian *type = -1; 231265071Sian return; 232265071Sian } 233265071Sian 234265071Sian /* Guaranteed to extract a number from the string, as *p is a digit. */ 235265071Sian *unit = strtol(p, &endp, 10); 236265071Sian p = endp; 237265071Sian 238265071Sian /* Known device name with unit number and nothing else. */ 239265071Sian if (*p == '\0') { 240265071Sian return; 241265071Sian } 242265071Sian 243265071Sian /* Device string is malformed beyond unit number. */ 244265071Sian if (*p != ':') { 245265071Sian *type = -1; 246265071Sian *unit = -1; 247265071Sian return; 248265071Sian } 249265071Sian 250265071Sian p++; 251265071Sian 252265071Sian /* No slice and partition specification. */ 253265071Sian if ('\0' == *p ) 254265071Sian return; 255265071Sian 256265071Sian /* Only DEV_TYP_STOR devices can have a slice specification. */ 257265071Sian if (!(*type & DEV_TYP_STOR)) { 258265071Sian *type = -1; 259265071Sian *unit = -1; 260265071Sian return; 261265071Sian } 262265071Sian 263265071Sian *slice = strtoul(p, &endp, 10); 264265071Sian 265265071Sian /* Malformed slice number. */ 266265071Sian if (p == endp) { 267265071Sian *type = -1; 268265071Sian *unit = -1; 269265071Sian *slice = 0; 270265071Sian return; 271265071Sian } 272265071Sian 273265071Sian p = endp; 274265071Sian 275265071Sian /* No partition specification. */ 276265071Sian if (*p == '\0') 277265071Sian return; 278265071Sian 279265071Sian /* Device string is malformed beyond slice number. */ 280265071Sian if (*p != '.') { 281265071Sian *type = -1; 282265071Sian *unit = -1; 283265071Sian *slice = 0; 284265071Sian return; 285265071Sian } 286265071Sian 287265071Sian p++; 288265071Sian 289265071Sian /* No partition specification. */ 290265071Sian if (*p == '\0') 291265071Sian return; 292265071Sian 293265071Sian *partition = strtol(p, &endp, 10); 294265071Sian p = endp; 295265071Sian 296265071Sian /* Full, valid device string. */ 297265071Sian if (*endp == '\0') 298265071Sian return; 299265071Sian 300265071Sian /* Junk beyond partition number. */ 301265071Sian *type = -1; 302265071Sian *unit = -1; 303265071Sian *slice = 0; 304265071Sian *partition = -1; 305265071Sian} 306265071Sian 307265071Sianstatic void 308265071Sianprint_disk_probe_info() 309265071Sian{ 310265071Sian char slice[32]; 311265071Sian char partition[32]; 312265071Sian 313265071Sian if (currdev.d_disk.slice > 0) 314265071Sian sprintf(slice, "%d", currdev.d_disk.slice); 315265071Sian else 316265071Sian strcpy(slice, "<auto>"); 317265071Sian 318294341Sian if (currdev.d_disk.partition >= 0) 319265071Sian sprintf(partition, "%d", currdev.d_disk.partition); 320265071Sian else 321265071Sian strcpy(partition, "<auto>"); 322265071Sian 323265071Sian printf(" Checking unit=%d slice=%s partition=%s...", 324265071Sian currdev.d_unit, slice, partition); 325265071Sian 326265071Sian} 327265071Sian 328265071Sianstatic int 329265071Sianprobe_disks(int devidx, int load_type, int load_unit, int load_slice, 330265071Sian int load_partition) 331265071Sian{ 332265071Sian int open_result, unit; 333265071Sian struct open_file f; 334265071Sian 335265071Sian currdev.d_disk.slice = load_slice; 336265071Sian currdev.d_disk.partition = load_partition; 337265071Sian 338265071Sian f.f_devdata = &currdev; 339265071Sian open_result = -1; 340265071Sian 341265071Sian if (load_type == -1) { 342265071Sian printf(" Probing all disk devices...\n"); 343265071Sian /* Try each disk in succession until one works. */ 344265071Sian for (currdev.d_unit = 0; currdev.d_unit < UB_MAX_DEV; 345265071Sian currdev.d_unit++) { 346265071Sian print_disk_probe_info(); 347265071Sian open_result = devsw[devidx]->dv_open(&f, &currdev); 348265071Sian if (open_result == 0) { 349265071Sian printf(" good.\n"); 350265071Sian return (0); 351265071Sian } 352265071Sian printf("\n"); 353265071Sian } 354265071Sian return (-1); 355265071Sian } 356265071Sian 357265071Sian if (load_unit == -1) { 358265071Sian printf(" Probing all %s devices...\n", device_typename(load_type)); 359265071Sian /* Try each disk of given type in succession until one works. */ 360265071Sian for (unit = 0; unit < UB_MAX_DEV; unit++) { 361265071Sian currdev.d_unit = uboot_diskgetunit(load_type, unit); 362265071Sian if (currdev.d_unit == -1) 363265071Sian break; 364265071Sian print_disk_probe_info(); 365265071Sian open_result = devsw[devidx]->dv_open(&f, &currdev); 366265071Sian if (open_result == 0) { 367265071Sian printf(" good.\n"); 368265071Sian return (0); 369265071Sian } 370265071Sian printf("\n"); 371265071Sian } 372265071Sian return (-1); 373265071Sian } 374265071Sian 375265071Sian if ((currdev.d_unit = uboot_diskgetunit(load_type, load_unit)) != -1) { 376265071Sian print_disk_probe_info(); 377265071Sian open_result = devsw[devidx]->dv_open(&f,&currdev); 378265071Sian if (open_result == 0) { 379265071Sian printf(" good.\n"); 380265071Sian return (0); 381265071Sian } 382265071Sian printf("\n"); 383265071Sian } 384265071Sian 385294341Sian printf(" Requested disk type/unit/slice/partition not found\n"); 386265071Sian return (-1); 387265071Sian} 388265071Sian 389176348Smarcelint 390176348Smarcelmain(void) 391176348Smarcel{ 392176348Smarcel struct api_signature *sig = NULL; 393265071Sian int load_type, load_unit, load_slice, load_partition; 394265071Sian int i; 395294341Sian const char *ldev; 396176348Smarcel 397265070Sian /* 398265070Sian * If we can't find the magic signature and related info, exit with a 399265070Sian * unique error code that U-Boot reports as "## Application terminated, 400265070Sian * rc = 0xnnbadab1". Hopefully 'badab1' looks enough like "bad api" to 401265070Sian * provide a clue. It's better than 0xffffffff anyway. 402265070Sian */ 403176348Smarcel if (!api_search_sig(&sig)) 404265070Sian return (0x01badab1); 405176348Smarcel 406176348Smarcel syscall_ptr = sig->syscall; 407176348Smarcel if (syscall_ptr == NULL) 408265070Sian return (0x02badab1); 409176348Smarcel 410176348Smarcel if (sig->version > API_SIG_VERSION) 411265070Sian return (0x03badab1); 412176348Smarcel 413176348Smarcel /* Clear BSS sections */ 414176348Smarcel bzero(__sbss_start, __sbss_end - __sbss_start); 415176348Smarcel bzero(__bss_start, _end - __bss_start); 416176348Smarcel 417176348Smarcel /* 418265071Sian * Initialise the heap as early as possible. Once this is done, 419265071Sian * alloc() is usable. The stack is buried inside us, so this is safe. 420265071Sian */ 421283505Sian uboot_heap_start = round_page((uintptr_t)end); 422283505Sian uboot_heap_end = uboot_heap_start + 512 * 1024; 423283505Sian setheap((void *)uboot_heap_start, (void *)uboot_heap_end); 424265071Sian 425265071Sian /* 426265071Sian * Set up console. 427265071Sian */ 428176348Smarcel cons_probe(); 429265071Sian printf("Compatible U-Boot API signature found @%x\n", (uint32_t)sig); 430176348Smarcel 431265071Sian printf("\n"); 432265071Sian printf("%s, Revision %s\n", bootprog_name, bootprog_rev); 433265071Sian printf("(%s, %s)\n", bootprog_maker, bootprog_date); 434265071Sian printf("\n"); 435176348Smarcel 436176348Smarcel dump_sig(sig); 437176348Smarcel dump_addr_info(); 438176348Smarcel 439265071Sian meminfo(); 440176348Smarcel 441176348Smarcel /* 442176348Smarcel * Enumerate U-Boot devices 443176348Smarcel */ 444176348Smarcel if ((devs_no = ub_dev_enum()) == 0) 445182732Sraj panic("no U-Boot devices found"); 446182732Sraj printf("Number of U-Boot devices: %d\n", devs_no); 447176348Smarcel 448265071Sian get_load_device(&load_type, &load_unit, &load_slice, &load_partition); 449176348Smarcel 450208534Sraj /* 451265071Sian * March through the device switch probing for things. 452208534Sraj */ 453204316Sraj for (i = 0; devsw[i] != NULL; i++) { 454204316Sraj 455208534Sraj if (devsw[i]->dv_init == NULL) 456208534Sraj continue; 457208534Sraj if ((devsw[i]->dv_init)() != 0) 458208534Sraj continue; 459208534Sraj 460265071Sian printf("Found U-Boot device: %s\n", devsw[i]->dv_name); 461208534Sraj 462265071Sian currdev.d_dev = devsw[i]; 463265071Sian currdev.d_type = currdev.d_dev->dv_type; 464265071Sian currdev.d_unit = 0; 465265071Sian 466265071Sian if ((load_type == -1 || (load_type & DEV_TYP_STOR)) && 467265071Sian strcmp(devsw[i]->dv_name, "disk") == 0) { 468265071Sian if (probe_disks(i, load_type, load_unit, load_slice, 469265071Sian load_partition) == 0) 470265071Sian break; 471204316Sraj } 472265071Sian 473265071Sian if ((load_type == -1 || (load_type & DEV_TYP_NET)) && 474265071Sian strcmp(devsw[i]->dv_name, "net") == 0) 475265071Sian break; 476204316Sraj } 477176348Smarcel 478265071Sian /* 479265071Sian * If we couldn't find a boot device, return an error to u-boot. 480265071Sian * U-boot may be running a boot script that can try something different 481265071Sian * so returning an error is better than forcing a reboot. 482265071Sian */ 483265071Sian if (devsw[i] == NULL) { 484265071Sian printf("No boot device found!\n"); 485265071Sian return (0xbadef1ce); 486265071Sian } 487176348Smarcel 488294341Sian ldev = uboot_fmtdev(&currdev); 489294341Sian env_setenv("currdev", EV_VOLATILE, ldev, uboot_setcurrdev, env_nounset); 490294341Sian env_setenv("loaddev", EV_VOLATILE, ldev, env_noset, env_nounset); 491294341Sian printf("Booting from %s\n", ldev); 492176348Smarcel 493176348Smarcel setenv("LINES", "24", 1); /* optional */ 494176348Smarcel setenv("prompt", "loader>", 1); 495176348Smarcel 496283505Sian archsw.arch_loadaddr = uboot_loadaddr; 497176348Smarcel archsw.arch_getdev = uboot_getdev; 498176348Smarcel archsw.arch_copyin = uboot_copyin; 499176348Smarcel archsw.arch_copyout = uboot_copyout; 500176348Smarcel archsw.arch_readin = uboot_readin; 501176348Smarcel archsw.arch_autoload = uboot_autoload; 502176348Smarcel 503176348Smarcel interact(); /* doesn't return */ 504176348Smarcel 505182732Sraj return (0); 506176348Smarcel} 507176348Smarcel 508176348Smarcel 509176348SmarcelCOMMAND_SET(heap, "heap", "show heap usage", command_heap); 510176348Smarcelstatic int 511176348Smarcelcommand_heap(int argc, char *argv[]) 512176348Smarcel{ 513182723Sraj 514182723Sraj printf("heap base at %p, top at %p, used %d\n", end, sbrk(0), 515177152Sobrien sbrk(0) - end); 516176348Smarcel 517182732Sraj return (CMD_OK); 518176348Smarcel} 519176348Smarcel 520176348SmarcelCOMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 521176348Smarcelstatic int 522176348Smarcelcommand_reboot(int argc, char *argv[]) 523176348Smarcel{ 524186231Sraj 525176348Smarcel printf("Resetting...\n"); 526176348Smarcel ub_reset(); 527176348Smarcel 528176348Smarcel printf("Reset failed!\n"); 529176348Smarcel while(1); 530176348Smarcel} 531182732Sraj 532182732SrajCOMMAND_SET(devinfo, "devinfo", "show U-Boot devices", command_devinfo); 533182732Srajstatic int 534182732Srajcommand_devinfo(int argc, char *argv[]) 535182732Sraj{ 536182732Sraj int i; 537182732Sraj 538182732Sraj if ((devs_no = ub_dev_enum()) == 0) { 539182732Sraj command_errmsg = "no U-Boot devices found!?"; 540182732Sraj return (CMD_ERROR); 541182732Sraj } 542182732Sraj 543182732Sraj printf("U-Boot devices:\n"); 544182732Sraj for (i = 0; i < devs_no; i++) { 545182732Sraj ub_dump_di(i); 546182732Sraj printf("\n"); 547182732Sraj } 548182732Sraj return (CMD_OK); 549182732Sraj} 550182732Sraj 551182732SrajCOMMAND_SET(sysinfo, "sysinfo", "show U-Boot system info", command_sysinfo); 552182732Srajstatic int 553182732Srajcommand_sysinfo(int argc, char *argv[]) 554182732Sraj{ 555182732Sraj struct sys_info *si; 556182732Sraj 557182732Sraj if ((si = ub_get_sys_info()) == NULL) { 558182732Sraj command_errmsg = "could not retrieve U-Boot sys info!?"; 559182732Sraj return (CMD_ERROR); 560182732Sraj } 561182732Sraj 562182732Sraj printf("U-Boot system info:\n"); 563182732Sraj ub_dump_si(si); 564182732Sraj return (CMD_OK); 565182732Sraj} 566208538Sraj 567273665Sianenum ubenv_action { 568273665Sian UBENV_UNKNOWN, 569273665Sian UBENV_SHOW, 570273665Sian UBENV_IMPORT 571273665Sian}; 572273665Sian 573273665Sianstatic void 574273665Sianhandle_uboot_env_var(enum ubenv_action action, const char * var) 575273665Sian{ 576294341Sian char ldvar[128]; 577294341Sian const char *val; 578294341Sian char *wrk; 579294341Sian int len; 580273665Sian 581273665Sian /* 582294341Sian * On an import with the variable name formatted as ldname=ubname, 583294341Sian * import the uboot variable ubname into the loader variable ldname, 584294341Sian * otherwise the historical behavior is to import to uboot.ubname. 585294341Sian */ 586294341Sian if (action == UBENV_IMPORT) { 587294341Sian len = strcspn(var, "="); 588294346Sian if (len == 0) { 589294346Sian printf("name cannot start with '=': '%s'\n", var); 590294346Sian return; 591294346Sian } 592294341Sian if (var[len] == 0) { 593294341Sian strcpy(ldvar, "uboot."); 594294341Sian strncat(ldvar, var, sizeof(ldvar) - 7); 595294341Sian } else { 596294341Sian len = MIN(len, sizeof(ldvar) - 1); 597294341Sian strncpy(ldvar, var, len); 598294341Sian ldvar[len] = 0; 599294341Sian var = &var[len + 1]; 600294341Sian } 601294341Sian } 602294341Sian 603294341Sian /* 604273665Sian * If the user prepended "uboot." (which is how they usually see these 605273665Sian * names) strip it off as a convenience. 606273665Sian */ 607273665Sian if (strncmp(var, "uboot.", 6) == 0) { 608294341Sian var = &var[6]; 609273665Sian } 610294341Sian 611294346Sian /* If there is no variable name left, punt. */ 612294346Sian if (var[0] == 0) { 613294346Sian printf("empty variable name\n"); 614294341Sian return; 615294346Sian } 616294341Sian 617273665Sian val = ub_env_get(var); 618273665Sian if (action == UBENV_SHOW) { 619273665Sian if (val == NULL) 620273665Sian printf("uboot.%s is not set\n", var); 621273665Sian else 622273665Sian printf("uboot.%s=%s\n", var, val); 623273665Sian } else if (action == UBENV_IMPORT) { 624273665Sian if (val != NULL) { 625294341Sian setenv(ldvar, val, 1); 626273665Sian } 627273665Sian } 628273665Sian} 629273665Sian 630273665Sianstatic int 631273665Siancommand_ubenv(int argc, char *argv[]) 632273665Sian{ 633273665Sian enum ubenv_action action; 634273665Sian const char *var; 635273665Sian int i; 636273665Sian 637273665Sian action = UBENV_UNKNOWN; 638273665Sian if (argc > 1) { 639273665Sian if (strcasecmp(argv[1], "import") == 0) 640273665Sian action = UBENV_IMPORT; 641273665Sian else if (strcasecmp(argv[1], "show") == 0) 642273665Sian action = UBENV_SHOW; 643273665Sian } 644273665Sian if (action == UBENV_UNKNOWN) { 645273665Sian command_errmsg = "usage: 'ubenv <import|show> [var ...]"; 646273665Sian return (CMD_ERROR); 647273665Sian } 648273665Sian 649273665Sian if (argc > 2) { 650273665Sian for (i = 2; i < argc; i++) 651273665Sian handle_uboot_env_var(action, argv[i]); 652273665Sian } else { 653273665Sian var = NULL; 654273665Sian for (;;) { 655273665Sian if ((var = ub_env_enum(var)) == NULL) 656273665Sian break; 657273665Sian handle_uboot_env_var(action, var); 658273665Sian } 659273665Sian } 660273665Sian 661273665Sian return (CMD_OK); 662273665Sian} 663273665SianCOMMAND_SET(ubenv, "ubenv", "show or import U-Boot env vars", command_ubenv); 664273665Sian 665208538Sraj#ifdef LOADER_FDT_SUPPORT 666208538Sraj/* 667208538Sraj * Since proper fdt command handling function is defined in fdt_loader_cmd.c, 668208538Sraj * and declaring it as extern is in contradiction with COMMAND_SET() macro 669208538Sraj * (which uses static pointer), we're defining wrapper function, which 670208538Sraj * calls the proper fdt handling routine. 671208538Sraj */ 672208538Srajstatic int 673208538Srajcommand_fdt(int argc, char *argv[]) 674208538Sraj{ 675208538Sraj 676208538Sraj return (command_fdt_internal(argc, argv)); 677208538Sraj} 678208538Sraj 679208538SrajCOMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); 680208538Sraj#endif 681