main.c revision 292227
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: head/sys/boot/uboot/common/main.c 292227 2015-12-14 22:00:46Z ian $"); 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 44182732Srajstruct uboot_devdesc currdev; 45182732Srajstruct arch_switch archsw; /* MI/MD interface boundary */ 46182732Srajint devs_no; 47176348Smarcel 48283035Sianuintptr_t uboot_heap_start; 49283035Sianuintptr_t uboot_heap_end; 50283035Sian 51263052Sianstruct device_type { 52263052Sian const char *name; 53263052Sian int type; 54263052Sian} device_types[] = { 55263052Sian { "disk", DEV_TYP_STOR }, 56263052Sian { "ide", DEV_TYP_STOR | DT_STOR_IDE }, 57263052Sian { "mmc", DEV_TYP_STOR | DT_STOR_MMC }, 58263052Sian { "sata", DEV_TYP_STOR | DT_STOR_SATA }, 59263052Sian { "scsi", DEV_TYP_STOR | DT_STOR_SCSI }, 60263052Sian { "usb", DEV_TYP_STOR | DT_STOR_USB }, 61263052Sian { "net", DEV_TYP_NET } 62263052Sian}; 63263052Sian 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) 135263267Sian printf("%s: %lldMB\n", ub_mem_type(t[i]), 136182732Sraj 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 159263052Sian *devtype = -1; 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 * 185263052Sian * Valid device strings: For device types: 186263052Sian * 187263052Sian * <type_name> DEV_TYP_STOR, DEV_TYP_NET 188263052Sian * <type_name><unit> DEV_TYP_STOR, DEV_TYP_NET 189263052Sian * <type_name><unit>: DEV_TYP_STOR, DEV_TYP_NET 190263052Sian * <type_name><unit>:<slice> DEV_TYP_STOR 191263052Sian * <type_name><unit>:<slice>. DEV_TYP_STOR 192263052Sian * <type_name><unit>:<slice>.<partition> DEV_TYP_STOR 193263052Sian * 194263052Sian * For valid type names, see the device_types array, above. 195263052Sian * 196263052Sian * Slice numbers are 1-based. 0 is a wildcard. 197263052Sian */ 198263052Sianstatic void 199263052Sianget_load_device(int *type, int *unit, int *slice, int *partition) 200263052Sian{ 201263052Sian char *devstr; 202263052Sian const char *p; 203263052Sian char *endp; 204263052Sian 205263267Sian *type = -1; 206263267Sian *unit = -1; 207263267Sian *slice = 0; 208263267Sian *partition = -1; 209263267Sian 210263052Sian devstr = ub_env_get("loaderdev"); 211263267Sian if (devstr == NULL) { 212263267Sian printf("U-Boot env: loaderdev not set, will probe all devices.\n"); 213263267Sian return; 214263267Sian } 215263267Sian printf("U-Boot env: loaderdev='%s'\n", devstr); 216263052Sian 217263052Sian p = get_device_type(devstr, type); 218263052Sian 219276026Sian /* Ignore optional spaces after the device name. */ 220276026Sian while (*p == ' ') 221276026Sian p++; 222276026Sian 223276026Sian /* Unknown device name, or a known name without unit number. */ 224263052Sian if ((*type == -1) || (*p == '\0')) { 225263052Sian return; 226263052Sian } 227263052Sian 228263052Sian /* Malformed unit number. */ 229263052Sian if (!isdigit(*p)) { 230263052Sian *type = -1; 231263052Sian return; 232263052Sian } 233263052Sian 234263052Sian /* Guaranteed to extract a number from the string, as *p is a digit. */ 235263052Sian *unit = strtol(p, &endp, 10); 236263052Sian p = endp; 237263052Sian 238263052Sian /* Known device name with unit number and nothing else. */ 239263052Sian if (*p == '\0') { 240263052Sian return; 241263052Sian } 242263052Sian 243263052Sian /* Device string is malformed beyond unit number. */ 244263052Sian if (*p != ':') { 245263052Sian *type = -1; 246263052Sian *unit = -1; 247263052Sian return; 248263052Sian } 249263052Sian 250263052Sian p++; 251263052Sian 252263052Sian /* No slice and partition specification. */ 253263052Sian if ('\0' == *p ) 254263052Sian return; 255263052Sian 256263052Sian /* Only DEV_TYP_STOR devices can have a slice specification. */ 257263052Sian if (!(*type & DEV_TYP_STOR)) { 258263052Sian *type = -1; 259263052Sian *unit = -1; 260263052Sian return; 261263052Sian } 262263052Sian 263263052Sian *slice = strtoul(p, &endp, 10); 264263052Sian 265263052Sian /* Malformed slice number. */ 266263052Sian if (p == endp) { 267263052Sian *type = -1; 268263052Sian *unit = -1; 269263052Sian *slice = 0; 270263052Sian return; 271263052Sian } 272263052Sian 273263052Sian p = endp; 274263052Sian 275263052Sian /* No partition specification. */ 276263052Sian if (*p == '\0') 277263052Sian return; 278263052Sian 279263052Sian /* Device string is malformed beyond slice number. */ 280263052Sian if (*p != '.') { 281263052Sian *type = -1; 282263052Sian *unit = -1; 283263052Sian *slice = 0; 284263052Sian return; 285263052Sian } 286263052Sian 287263052Sian p++; 288263052Sian 289263052Sian /* No partition specification. */ 290263052Sian if (*p == '\0') 291263052Sian return; 292263052Sian 293263052Sian *partition = strtol(p, &endp, 10); 294263052Sian p = endp; 295263052Sian 296263052Sian /* Full, valid device string. */ 297263052Sian if (*endp == '\0') 298263052Sian return; 299263052Sian 300263052Sian /* Junk beyond partition number. */ 301263052Sian *type = -1; 302263052Sian *unit = -1; 303263052Sian *slice = 0; 304263052Sian *partition = -1; 305263052Sian} 306263052Sian 307263267Sianstatic void 308263267Sianprint_disk_probe_info() 309263267Sian{ 310263267Sian char slice[32]; 311263267Sian char partition[32]; 312263267Sian 313263267Sian if (currdev.d_disk.slice > 0) 314263267Sian sprintf(slice, "%d", currdev.d_disk.slice); 315263267Sian else 316263267Sian strcpy(slice, "<auto>"); 317263267Sian 318291164Sian if (currdev.d_disk.partition >= 0) 319263267Sian sprintf(partition, "%d", currdev.d_disk.partition); 320263267Sian else 321263267Sian strcpy(partition, "<auto>"); 322263267Sian 323263267Sian printf(" Checking unit=%d slice=%s partition=%s...", 324263267Sian currdev.d_unit, slice, partition); 325263267Sian 326263267Sian} 327263267Sian 328263052Sianstatic int 329263124Sianprobe_disks(int devidx, int load_type, int load_unit, int load_slice, 330263124Sian int load_partition) 331263052Sian{ 332263124Sian int open_result, unit; 333263052Sian struct open_file f; 334263052Sian 335263052Sian currdev.d_disk.slice = load_slice; 336263052Sian currdev.d_disk.partition = load_partition; 337263052Sian 338263052Sian f.f_devdata = &currdev; 339263052Sian open_result = -1; 340263052Sian 341263052Sian if (load_type == -1) { 342263267Sian printf(" Probing all disk devices...\n"); 343263052Sian /* Try each disk in succession until one works. */ 344263052Sian for (currdev.d_unit = 0; currdev.d_unit < UB_MAX_DEV; 345263052Sian currdev.d_unit++) { 346263267Sian print_disk_probe_info(); 347263124Sian open_result = devsw[devidx]->dv_open(&f, &currdev); 348263052Sian if (open_result == 0) { 349263052Sian printf(" good.\n"); 350263052Sian return (0); 351263052Sian } 352263052Sian printf("\n"); 353263052Sian } 354263052Sian return (-1); 355263052Sian } 356263052Sian 357263052Sian if (load_unit == -1) { 358263267Sian printf(" Probing all %s devices...\n", device_typename(load_type)); 359263052Sian /* Try each disk of given type in succession until one works. */ 360263052Sian for (unit = 0; unit < UB_MAX_DEV; unit++) { 361263052Sian currdev.d_unit = uboot_diskgetunit(load_type, unit); 362263052Sian if (currdev.d_unit == -1) 363263052Sian break; 364263267Sian print_disk_probe_info(); 365263124Sian open_result = devsw[devidx]->dv_open(&f, &currdev); 366263052Sian if (open_result == 0) { 367263052Sian printf(" good.\n"); 368263052Sian return (0); 369263052Sian } 370263052Sian printf("\n"); 371263052Sian } 372263052Sian return (-1); 373263052Sian } 374263052Sian 375263052Sian if ((currdev.d_unit = uboot_diskgetunit(load_type, load_unit)) != -1) { 376263267Sian print_disk_probe_info(); 377263124Sian open_result = devsw[devidx]->dv_open(&f,&currdev); 378263052Sian if (open_result == 0) { 379263267Sian printf(" good.\n"); 380263052Sian return (0); 381263052Sian } 382263052Sian printf("\n"); 383263052Sian } 384263052Sian 385291164Sian printf(" Requested disk type/unit/slice/partition not found\n"); 386263052Sian return (-1); 387263052Sian} 388263052Sian 389176348Smarcelint 390176348Smarcelmain(void) 391176348Smarcel{ 392176348Smarcel struct api_signature *sig = NULL; 393263052Sian int load_type, load_unit, load_slice, load_partition; 394263052Sian int i; 395291164Sian const char *ldev; 396176348Smarcel 397262666Sian /* 398262666Sian * If we can't find the magic signature and related info, exit with a 399262666Sian * unique error code that U-Boot reports as "## Application terminated, 400262666Sian * rc = 0xnnbadab1". Hopefully 'badab1' looks enough like "bad api" to 401262666Sian * provide a clue. It's better than 0xffffffff anyway. 402262666Sian */ 403176348Smarcel if (!api_search_sig(&sig)) 404262666Sian return (0x01badab1); 405176348Smarcel 406176348Smarcel syscall_ptr = sig->syscall; 407176348Smarcel if (syscall_ptr == NULL) 408262666Sian return (0x02badab1); 409176348Smarcel 410176348Smarcel if (sig->version > API_SIG_VERSION) 411262666Sian return (0x03badab1); 412176348Smarcel 413176348Smarcel /* Clear BSS sections */ 414176348Smarcel bzero(__sbss_start, __sbss_end - __sbss_start); 415176348Smarcel bzero(__bss_start, _end - __bss_start); 416176348Smarcel 417176348Smarcel /* 418263267Sian * Initialise the heap as early as possible. Once this is done, 419263267Sian * alloc() is usable. The stack is buried inside us, so this is safe. 420263267Sian */ 421283035Sian uboot_heap_start = round_page((uintptr_t)end); 422283035Sian uboot_heap_end = uboot_heap_start + 512 * 1024; 423283035Sian setheap((void *)uboot_heap_start, (void *)uboot_heap_end); 424263267Sian 425263267Sian /* 426263267Sian * Set up console. 427263267Sian */ 428176348Smarcel cons_probe(); 429263267Sian printf("Compatible U-Boot API signature found @%x\n", (uint32_t)sig); 430176348Smarcel 431263267Sian printf("\n"); 432263267Sian printf("%s, Revision %s\n", bootprog_name, bootprog_rev); 433263267Sian printf("(%s, %s)\n", bootprog_maker, bootprog_date); 434263267Sian printf("\n"); 435176348Smarcel 436176348Smarcel dump_sig(sig); 437176348Smarcel dump_addr_info(); 438176348Smarcel 439263267Sian 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 448263052Sian get_load_device(&load_type, &load_unit, &load_slice, &load_partition); 449263052Sian 450208534Sraj /* 451263052Sian * 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 460263052Sian printf("Found U-Boot device: %s\n", devsw[i]->dv_name); 461208534Sraj 462263052Sian currdev.d_dev = devsw[i]; 463263052Sian currdev.d_type = currdev.d_dev->dv_type; 464263052Sian currdev.d_unit = 0; 465263052Sian 466263052Sian if ((load_type == -1 || (load_type & DEV_TYP_STOR)) && 467263052Sian strcmp(devsw[i]->dv_name, "disk") == 0) { 468263124Sian if (probe_disks(i, load_type, load_unit, load_slice, 469263052Sian load_partition) == 0) 470263052Sian break; 471204316Sraj } 472263052Sian 473263265Sian if ((load_type == -1 || (load_type & DEV_TYP_NET)) && 474263265Sian strcmp(devsw[i]->dv_name, "net") == 0) 475263052Sian break; 476204316Sraj } 477176348Smarcel 478263052Sian /* 479263052Sian * If we couldn't find a boot device, return an error to u-boot. 480263052Sian * U-boot may be running a boot script that can try something different 481263052Sian * so returning an error is better than forcing a reboot. 482263052Sian */ 483263052Sian if (devsw[i] == NULL) { 484263052Sian printf("No boot device found!\n"); 485263052Sian return (0xbadef1ce); 486263052Sian } 487176348Smarcel 488291164Sian ldev = uboot_fmtdev(&currdev); 489291164Sian env_setenv("currdev", EV_VOLATILE, ldev, uboot_setcurrdev, env_nounset); 490291164Sian env_setenv("loaddev", EV_VOLATILE, ldev, env_noset, env_nounset); 491291876Sngie printf("Booting from %s\n", ldev); 492176348Smarcel 493176348Smarcel setenv("LINES", "24", 1); /* optional */ 494176348Smarcel setenv("prompt", "loader>", 1); 495176348Smarcel 496283035Sian 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 503269153Smarcel interact(NULL); /* 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 567271285Sianenum ubenv_action { 568271285Sian UBENV_UNKNOWN, 569271285Sian UBENV_SHOW, 570271285Sian UBENV_IMPORT 571271285Sian}; 572271285Sian 573271285Sianstatic void 574271285Sianhandle_uboot_env_var(enum ubenv_action action, const char * var) 575271285Sian{ 576292227Sian char ldvar[128]; 577292227Sian const char *val; 578292227Sian char *wrk; 579292227Sian int len; 580271285Sian 581271285Sian /* 582292227Sian * On an import with the variable name formatted as ldname=ubname, 583292227Sian * import the uboot variable ubname into the loader variable ldname, 584292227Sian * otherwise the historical behavior is to import to uboot.ubname. 585292227Sian */ 586292227Sian if (action == UBENV_IMPORT) { 587292227Sian len = strcspn(var, "="); 588292227Sian if (var[len] == 0) { 589292227Sian strcpy(ldvar, "uboot."); 590292227Sian strncat(ldvar, var, sizeof(ldvar) - 7); 591292227Sian } else { 592292227Sian len = MIN(len, sizeof(ldvar) - 1); 593292227Sian strncpy(ldvar, var, len); 594292227Sian ldvar[len] = 0; 595292227Sian var = &var[len + 1]; 596292227Sian } 597292227Sian } 598292227Sian 599292227Sian /* 600271285Sian * If the user prepended "uboot." (which is how they usually see these 601271285Sian * names) strip it off as a convenience. 602271285Sian */ 603271285Sian if (strncmp(var, "uboot.", 6) == 0) { 604292227Sian var = &var[6]; 605271285Sian } 606292227Sian 607292227Sian /* If ldvar is malformed or there's no variable name left, punt. */ 608292227Sian if (ldvar[0] == 0 || var[0] == 0) 609292227Sian return; 610292227Sian 611271285Sian val = ub_env_get(var); 612271285Sian if (action == UBENV_SHOW) { 613271285Sian if (val == NULL) 614271285Sian printf("uboot.%s is not set\n", var); 615271285Sian else 616271285Sian printf("uboot.%s=%s\n", var, val); 617271285Sian } else if (action == UBENV_IMPORT) { 618271285Sian if (val != NULL) { 619292227Sian setenv(ldvar, val, 1); 620271285Sian } 621271285Sian } 622271285Sian} 623271285Sian 624271285Sianstatic int 625271285Siancommand_ubenv(int argc, char *argv[]) 626271285Sian{ 627271285Sian enum ubenv_action action; 628271285Sian const char *var; 629271285Sian int i; 630271285Sian 631271285Sian action = UBENV_UNKNOWN; 632271285Sian if (argc > 1) { 633271285Sian if (strcasecmp(argv[1], "import") == 0) 634271285Sian action = UBENV_IMPORT; 635271285Sian else if (strcasecmp(argv[1], "show") == 0) 636271285Sian action = UBENV_SHOW; 637271285Sian } 638271285Sian if (action == UBENV_UNKNOWN) { 639271285Sian command_errmsg = "usage: 'ubenv <import|show> [var ...]"; 640271285Sian return (CMD_ERROR); 641271285Sian } 642271285Sian 643271285Sian if (argc > 2) { 644271285Sian for (i = 2; i < argc; i++) 645271285Sian handle_uboot_env_var(action, argv[i]); 646271285Sian } else { 647271285Sian var = NULL; 648271285Sian for (;;) { 649271285Sian if ((var = ub_env_enum(var)) == NULL) 650271285Sian break; 651271285Sian handle_uboot_env_var(action, var); 652271285Sian } 653271285Sian } 654271285Sian 655271285Sian return (CMD_OK); 656271285Sian} 657271285SianCOMMAND_SET(ubenv, "ubenv", "show or import U-Boot env vars", command_ubenv); 658271285Sian 659208538Sraj#ifdef LOADER_FDT_SUPPORT 660208538Sraj/* 661208538Sraj * Since proper fdt command handling function is defined in fdt_loader_cmd.c, 662208538Sraj * and declaring it as extern is in contradiction with COMMAND_SET() macro 663208538Sraj * (which uses static pointer), we're defining wrapper function, which 664208538Sraj * calls the proper fdt handling routine. 665208538Sraj */ 666208538Srajstatic int 667208538Srajcommand_fdt(int argc, char *argv[]) 668208538Sraj{ 669208538Sraj 670208538Sraj return (command_fdt_internal(argc, argv)); 671208538Sraj} 672208538Sraj 673208538SrajCOMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); 674208538Sraj#endif 675