main.c revision 283505
1296781Sdes/*-
257429Smarkm * Copyright (c) 2000 Benno Rice <benno@jeamland.net>
357429Smarkm * Copyright (c) 2000 Stephane Potvin <sepotvin@videotron.ca>
457429Smarkm * Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com>
557429Smarkm * All rights reserved.
660576Skris *
765674Skris * Redistribution and use in source and binary forms, with or without
865674Skris * modification, are permitted provided that the following conditions
965674Skris * are met:
1065674Skris * 1. Redistributions of source code must retain the above copyright
1165674Skris *    notice, this list of conditions and the following disclaimer.
1260576Skris * 2. Redistributions in binary form must reproduce the above copyright
1365674Skris *    notice, this list of conditions and the following disclaimer in the
1465674Skris *    documentation and/or other materials provided with the distribution.
1592559Sdes *
1665674Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1765674Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1865674Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1965674Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2065674Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2165674Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2265674Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2365674Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2465674Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2565674Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2665674Skris * SUCH DAMAGE.
2765674Skris */
2865674Skris
2965674Skris#include <sys/cdefs.h>
3065674Skris__FBSDID("$FreeBSD: stable/10/sys/boot/uboot/common/main.c 283505 2015-05-25 01:06:55Z ian $");
3165674Skris#include <sys/param.h>
3265674Skris
3365674Skris#include <stand.h>
3465674Skris
3565674Skris#include "api_public.h"
3657429Smarkm#include "bootstrap.h"
3757429Smarkm#include "glue.h"
3857429Smarkm#include "libuboot.h"
3957429Smarkm
40162856Sdes#ifndef nitems
41162856Sdes#define	nitems(x)	(sizeof((x)) / sizeof((x)[0]))
42162856Sdes#endif
43162856Sdes
44262566Sdesstruct uboot_devdesc currdev;
45162856Sdesstruct arch_switch archsw;		/* MI/MD interface boundary */
46295367Sdesint devs_no;
47262566Sdes
48295367Sdesuintptr_t uboot_heap_start;
49295367Sdesuintptr_t uboot_heap_end;
50264377Sdes
5157429Smarkmstruct device_type {
52149753Sdes	const char *name;
5398941Sdes	int type;
54295367Sdes} device_types[] = {
55124211Sdes	{ "disk", DEV_TYP_STOR },
56124211Sdes	{ "ide",  DEV_TYP_STOR | DT_STOR_IDE },
57295367Sdes	{ "mmc",  DEV_TYP_STOR | DT_STOR_MMC },
58295367Sdes	{ "sata", DEV_TYP_STOR | DT_STOR_SATA },
5957429Smarkm	{ "scsi", DEV_TYP_STOR | DT_STOR_SCSI },
60295367Sdes	{ "usb",  DEV_TYP_STOR | DT_STOR_USB },
6192559Sdes	{ "net",  DEV_TYP_NET }
6292559Sdes};
6392559Sdes
6492559Sdesextern char end[];
65248619Sdesextern char bootprog_name[];
66248619Sdesextern char bootprog_rev[];
67149753Sdesextern char bootprog_date[];
68262566Sdesextern char bootprog_maker[];
69262566Sdes
70262566Sdesextern unsigned char _etext[];
71295367Sdesextern unsigned char _edata[];
72295367Sdesextern unsigned char __bss_start[];
73295367Sdesextern unsigned char __sbss_start[];
7498684Sdesextern unsigned char __sbss_end[];
75295367Sdesextern unsigned char _end[];
76295367Sdes
77295367Sdes#ifdef LOADER_FDT_SUPPORT
78255767Sdesextern int command_fdt_internal(int argc, char *argv[]);
79255767Sdes#endif
80295367Sdes
81295367Sdesstatic void
82248619Sdesdump_sig(struct api_signature *sig)
83248619Sdes{
84323124Sdes#ifdef DEBUG
85248619Sdes	printf("signature:\n");
86323124Sdes	printf("  version\t= %d\n", sig->version);
87295367Sdes	printf("  checksum\t= 0x%08x\n", sig->checksum);
88295367Sdes	printf("  sc entry\t= 0x%08x\n", sig->syscall);
89295367Sdes#endif
90248619Sdes}
91323124Sdes
92248619Sdesstatic void
93248619Sdesdump_addr_info(void)
94323124Sdes{
95323124Sdes#ifdef DEBUG
96248619Sdes	printf("\naddresses info:\n");
97248619Sdes	printf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext);
98323124Sdes	printf(" _edata         = 0x%08x\n", (uint32_t)_edata);
99323124Sdes	printf(" __sbss_start   = 0x%08x\n", (uint32_t)__sbss_start);
100248619Sdes	printf(" __sbss_end     = 0x%08x\n", (uint32_t)__sbss_end);
101248619Sdes	printf(" __sbss_start   = 0x%08x\n", (uint32_t)__bss_start);
102248619Sdes	printf(" _end           = 0x%08x\n", (uint32_t)_end);
103323124Sdes	printf(" syscall entry  = 0x%08x\n", (uint32_t)syscall_ptr);
104248619Sdes#endif
105248619Sdes}
106248619Sdes
10798684Sdesstatic uint64_t
108248619Sdesmemsize(struct sys_info *si, int flags)
109248619Sdes{
110248619Sdes	uint64_t size;
111248619Sdes	int i;
112295367Sdes
113248619Sdes	size = 0;
114248619Sdes	for (i = 0; i < si->mr_no; i++)
115248619Sdes		if (si->mr[i].flags == flags && si->mr[i].size)
116248619Sdes			size += (si->mr[i].size);
117295367Sdes
118295367Sdes	return (size);
119295367Sdes}
120295367Sdes
121295367Sdesstatic void
122295367Sdesmeminfo(void)
123295367Sdes{
124262566Sdes	uint64_t size;
125262566Sdes	struct sys_info *si;
126295367Sdes	int t[3] = { MR_ATTR_DRAM, MR_ATTR_FLASH, MR_ATTR_SRAM };
127248619Sdes	int i;
12892559Sdes
12969591Sgreen	if ((si = ub_get_sys_info()) == NULL)
13092559Sdes		panic("could not retrieve system info");
13157429Smarkm
132295367Sdes	for (i = 0; i < 3; i++) {
133255767Sdes		size = memsize(si, t[i]);
134262566Sdes		if (size > 0)
135255767Sdes			printf("%s: %lldMB\n", ub_mem_type(t[i]),
136295367Sdes			    size / 1024 / 1024);
137255767Sdes	}
138295367Sdes}
139255767Sdes
140255767Sdesstatic const char *
141255767Sdesget_device_type(const char *devstr, int *devtype)
142255767Sdes{
143262566Sdes	int i;
144262566Sdes	int namelen;
145255767Sdes	struct device_type *dt;
146262566Sdes
147255767Sdes	if (devstr) {
148295367Sdes		for (i = 0; i < nitems(device_types); i++) {
149295367Sdes			dt = &device_types[i];
150295367Sdes			namelen = strlen(dt->name);
151295367Sdes			if (strncmp(dt->name, devstr, namelen) == 0) {
152295367Sdes				*devtype = dt->type;
153255767Sdes				return (devstr + namelen);
154255767Sdes			}
155255767Sdes		}
156255767Sdes		printf("Unknown device type '%s'\n", devstr);
157255767Sdes	}
158255767Sdes
15998684Sdes	*devtype = -1;
160295367Sdes	return (NULL);
16157429Smarkm}
16292559Sdes
16357429Smarkmstatic const char *
16499063Sdesdevice_typename(int type)
16598684Sdes{
166295367Sdes	int i;
16769591Sgreen
16892559Sdes	for (i = 0; i < nitems(device_types); i++)
16969591Sgreen		if (device_types[i].type == type)
17099063Sdes			return (device_types[i].name);
17198684Sdes
172295367Sdes	return ("<unknown>");
173262566Sdes}
174262566Sdes
175262566Sdes/*
176262566Sdes * Parse a device string into type, unit, slice and partition numbers. A
177262566Sdes * returned value of -1 for type indicates a search should be done for the
178262566Sdes * first loadable device, otherwise a returned value of -1 for unit
179262566Sdes * indicates a search should be done for the first loadable device of the
180295367Sdes * given type.
181248619Sdes *
182248619Sdes * The returned values for slice and partition are interpreted by
183248619Sdes * disk_open().
184248619Sdes *
185248619Sdes * Valid device strings:                     For device types:
186295367Sdes *
187248619Sdes * <type_name>                               DEV_TYP_STOR, DEV_TYP_NET
188262566Sdes * <type_name><unit>                         DEV_TYP_STOR, DEV_TYP_NET
189262566Sdes * <type_name><unit>:                        DEV_TYP_STOR, DEV_TYP_NET
190262566Sdes * <type_name><unit>:<slice>                 DEV_TYP_STOR
191262566Sdes * <type_name><unit>:<slice>.                DEV_TYP_STOR
192262566Sdes * <type_name><unit>:<slice>.<partition>     DEV_TYP_STOR
193262566Sdes *
194248619Sdes * For valid type names, see the device_types array, above.
195248619Sdes *
196248619Sdes * Slice numbers are 1-based.  0 is a wildcard.
197295367Sdes */
19898684Sdesstatic void
19998684Sdesget_load_device(int *type, int *unit, int *slice, int *partition)
20098684Sdes{
20169591Sgreen	char *devstr;
20276262Sgreen	const char *p;
203295367Sdes	char *endp;
204192595Sdes
205262566Sdes	*type = -1;
206192595Sdes	*unit = -1;
207192595Sdes	*slice = 0;
208192595Sdes	*partition = -1;
20969591Sgreen
21057429Smarkm	devstr = ub_env_get("loaderdev");
21176262Sgreen	if (devstr == NULL) {
21292559Sdes		printf("U-Boot env: loaderdev not set, will probe all devices.\n");
21357429Smarkm		return;
21469591Sgreen	}
21569591Sgreen	printf("U-Boot env: loaderdev='%s'\n", devstr);
21669591Sgreen
21757429Smarkm	p = get_device_type(devstr, type);
21857429Smarkm
21969591Sgreen	/* Ignore optional spaces after the device name. */
220295367Sdes	while (*p == ' ')
22169591Sgreen		p++;
22260576Skris
223295367Sdes	/* Unknown device name, or a known name without unit number.  */
22469591Sgreen	if ((*type == -1) || (*p == '\0')) {
225147005Sdes		return;
22669591Sgreen	}
22769591Sgreen
22860576Skris	/* Malformed unit number. */
22957429Smarkm	if (!isdigit(*p)) {
230295367Sdes		*type = -1;
23169591Sgreen		return;
23257429Smarkm	}
233295367Sdes
23469591Sgreen	/* Guaranteed to extract a number from the string, as *p is a digit. */
23569591Sgreen	*unit = strtol(p, &endp, 10);
23669591Sgreen	p = endp;
23769591Sgreen
23857429Smarkm	/* Known device name with unit number and nothing else. */
23957429Smarkm	if (*p == '\0') {
24060576Skris		return;
24160576Skris	}
24260576Skris
24360576Skris	/* Device string is malformed beyond unit number. */
244295367Sdes	if (*p != ':') {
245137019Sdes		*type = -1;
24660576Skris		*unit = -1;
24760576Skris		return;
24861212Skris	}
24960576Skris
250295367Sdes	p++;
251295367Sdes
25269591Sgreen	/* No slice and partition specification. */
25392559Sdes	if ('\0' == *p )
25469591Sgreen		return;
255294693Sdes
256255767Sdes	/* Only DEV_TYP_STOR devices can have a slice specification. */
25760576Skris	if (!(*type & DEV_TYP_STOR)) {
25860576Skris		*type = -1;
25960576Skris		*unit = -1;
260255767Sdes		return;
26160576Skris	}
26260576Skris
26360576Skris	*slice = strtoul(p, &endp, 10);
26457429Smarkm
26557429Smarkm	/* Malformed slice number. */
26657429Smarkm	if (p == endp) {
26757429Smarkm		*type = -1;
26857429Smarkm		*unit = -1;
26957429Smarkm		*slice = 0;
27057429Smarkm		return;
27157429Smarkm	}
272295367Sdes
27361212Skris	p = endp;
27461212Skris
275147005Sdes	/* No partition specification. */
276147005Sdes	if (*p == '\0')
277147005Sdes		return;
278147005Sdes
27957429Smarkm	/* Device string is malformed beyond slice number. */
28057429Smarkm	if (*p != '.') {
28169591Sgreen		*type = -1;
28269591Sgreen		*unit = -1;
28357429Smarkm		*slice = 0;
284295367Sdes		return;
28569591Sgreen	}
28657429Smarkm
28757429Smarkm	p++;
288295367Sdes
289295367Sdes	/* No partition specification. */
290295367Sdes	if (*p == '\0')
291295367Sdes		return;
292295367Sdes
293295367Sdes	*partition = strtol(p, &endp, 10);
294295367Sdes	p = endp;
295295367Sdes
296295367Sdes	/*  Full, valid device string. */
297295367Sdes	if (*endp == '\0')
298295367Sdes		return;
299295367Sdes
300295367Sdes	/* Junk beyond partition number. */
30192559Sdes	*type = -1;
302137019Sdes	*unit = -1;
30357429Smarkm	*slice = 0;
304295367Sdes	*partition = -1;
305295367Sdes}
30692559Sdes
307149753Sdesstatic void
308149753Sdesprint_disk_probe_info()
30992559Sdes{
31092559Sdes	char slice[32];
31192559Sdes	char partition[32];
31292559Sdes
31392559Sdes	if (currdev.d_disk.slice > 0)
314295367Sdes		sprintf(slice, "%d", currdev.d_disk.slice);
31592559Sdes	else
316248619Sdes		strcpy(slice, "<auto>");
31792559Sdes
318295367Sdes	if (currdev.d_disk.partition > 0)
319295367Sdes		sprintf(partition, "%d", currdev.d_disk.partition);
320295367Sdes	else
321295367Sdes		strcpy(partition, "<auto>");
32269591Sgreen
323262566Sdes	printf("  Checking unit=%d slice=%s partition=%s...",
324295367Sdes	    currdev.d_unit, slice, partition);
325262566Sdes
326295367Sdes}
327295367Sdes
328295367Sdesstatic int
329295367Sdesprobe_disks(int devidx, int load_type, int load_unit, int load_slice,
330295367Sdes    int load_partition)
331295367Sdes{
332295367Sdes	int open_result, unit;
333295367Sdes	struct open_file f;
334295367Sdes
335295367Sdes	currdev.d_disk.slice = load_slice;
33692559Sdes	currdev.d_disk.partition = load_partition;
33792559Sdes
338295367Sdes	f.f_devdata = &currdev;
339295367Sdes	open_result = -1;
340295367Sdes
341295367Sdes	if (load_type == -1) {
34298941Sdes		printf("  Probing all disk devices...\n");
343248619Sdes		/* Try each disk in succession until one works.  */
344248619Sdes		for (currdev.d_unit = 0; currdev.d_unit < UB_MAX_DEV;
345295367Sdes		     currdev.d_unit++) {
346295367Sdes			print_disk_probe_info();
347295367Sdes			open_result = devsw[devidx]->dv_open(&f, &currdev);
348295367Sdes			if (open_result == 0) {
34992559Sdes				printf(" good.\n");
350149753Sdes				return (0);
351295367Sdes			}
352295367Sdes			printf("\n");
353295367Sdes		}
354295367Sdes		return (-1);
35592559Sdes	}
356295367Sdes
357295367Sdes	if (load_unit == -1) {
358295367Sdes		printf("  Probing all %s devices...\n", device_typename(load_type));
359295367Sdes		/* Try each disk of given type in succession until one works. */
360149753Sdes		for (unit = 0; unit < UB_MAX_DEV; unit++) {
361149753Sdes			currdev.d_unit = uboot_diskgetunit(load_type, unit);
362295367Sdes			if (currdev.d_unit == -1)
363295367Sdes				break;
364296781Sdes			print_disk_probe_info();
365295367Sdes			open_result = devsw[devidx]->dv_open(&f, &currdev);
366295367Sdes			if (open_result == 0) {
367295367Sdes				printf(" good.\n");
368295367Sdes				return (0);
369264377Sdes			}
370255767Sdes			printf("\n");
371255767Sdes		}
372295367Sdes		return (-1);
373295367Sdes	}
374295367Sdes
375295367Sdes	if ((currdev.d_unit = uboot_diskgetunit(load_type, load_unit)) != -1) {
376295367Sdes		print_disk_probe_info();
377295367Sdes		open_result = devsw[devidx]->dv_open(&f,&currdev);
378149753Sdes		if (open_result == 0) {
379295367Sdes			printf(" good.\n");
380295367Sdes			return (0);
38157429Smarkm		}
38257429Smarkm		printf("\n");
383248619Sdes	}
384248619Sdes
385248619Sdes	printf("  Requested disk type/unit not found\n");
386248619Sdes	return (-1);
387248619Sdes}
388248619Sdes
389248619Sdesint
390248619Sdesmain(void)
391248619Sdes{
392248619Sdes	struct api_signature *sig = NULL;
393262566Sdes	int load_type, load_unit, load_slice, load_partition;
394295367Sdes	int i;
395295367Sdes	const char * loaderdev;
39660576Skris
397295367Sdes	/*
398295367Sdes	 * If we can't find the magic signature and related info, exit with a
399295367Sdes	 * unique error code that U-Boot reports as "## Application terminated,
400295367Sdes	 * rc = 0xnnbadab1". Hopefully 'badab1' looks enough like "bad api" to
401295367Sdes	 * provide a clue. It's better than 0xffffffff anyway.
402295367Sdes	 */
403295367Sdes	if (!api_search_sig(&sig))
404295367Sdes		return (0x01badab1);
405295367Sdes
406295367Sdes	syscall_ptr = sig->syscall;
407295367Sdes	if (syscall_ptr == NULL)
408295367Sdes		return (0x02badab1);
409295367Sdes
410295367Sdes	if (sig->version > API_SIG_VERSION)
411295367Sdes		return (0x03badab1);
412295367Sdes
413295367Sdes        /* Clear BSS sections */
414295367Sdes	bzero(__sbss_start, __sbss_end - __sbss_start);
415248619Sdes	bzero(__bss_start, _end - __bss_start);
416248619Sdes
417248619Sdes	/*
418248619Sdes	 * Initialise the heap as early as possible.  Once this is done,
419295367Sdes	 * alloc() is usable. The stack is buried inside us, so this is safe.
420248619Sdes	 */
421248619Sdes	uboot_heap_start = round_page((uintptr_t)end);
422248619Sdes	uboot_heap_end   = uboot_heap_start + 512 * 1024;
423295367Sdes	setheap((void *)uboot_heap_start, (void *)uboot_heap_end);
424248619Sdes
425248619Sdes	/*
426248619Sdes	 * Set up console.
427248619Sdes	 */
428295367Sdes	cons_probe();
429248619Sdes	printf("Compatible U-Boot API signature found @%x\n", (uint32_t)sig);
430248619Sdes
431248619Sdes	printf("\n");
432248619Sdes	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
433295367Sdes	printf("(%s, %s)\n", bootprog_maker, bootprog_date);
434248619Sdes	printf("\n");
435248619Sdes
43669591Sgreen	dump_sig(sig);
437295367Sdes	dump_addr_info();
438248619Sdes
439248619Sdes	meminfo();
440295367Sdes
441248619Sdes	/*
442248619Sdes	 * Enumerate U-Boot devices
443295367Sdes	 */
444295367Sdes	if ((devs_no = ub_dev_enum()) == 0)
445295367Sdes		panic("no U-Boot devices found");
446248619Sdes	printf("Number of U-Boot devices: %d\n", devs_no);
447248619Sdes
448248619Sdes	get_load_device(&load_type, &load_unit, &load_slice, &load_partition);
449295367Sdes
450248619Sdes	/*
451262566Sdes	 * March through the device switch probing for things.
452295367Sdes	 */
45360576Skris	for (i = 0; devsw[i] != NULL; i++) {
45460576Skris
455262566Sdes		if (devsw[i]->dv_init == NULL)
456262566Sdes			continue;
457295367Sdes		if ((devsw[i]->dv_init)() != 0)
458262566Sdes			continue;
459262566Sdes
460262566Sdes		printf("Found U-Boot device: %s\n", devsw[i]->dv_name);
461262566Sdes
462262566Sdes		currdev.d_dev = devsw[i];
463262566Sdes		currdev.d_type = currdev.d_dev->dv_type;
464295367Sdes		currdev.d_unit = 0;
465262566Sdes
466262566Sdes		if ((load_type == -1 || (load_type & DEV_TYP_STOR)) &&
467262566Sdes		    strcmp(devsw[i]->dv_name, "disk") == 0) {
468262566Sdes			if (probe_disks(i, load_type, load_unit, load_slice,
469295367Sdes			    load_partition) == 0)
470295367Sdes				break;
47157429Smarkm		}
472295367Sdes
473295367Sdes		if ((load_type == -1 || (load_type & DEV_TYP_NET)) &&
474262566Sdes		    strcmp(devsw[i]->dv_name, "net") == 0)
475264377Sdes			break;
476295367Sdes	}
477295367Sdes
478295367Sdes	/*
479262566Sdes	 * If we couldn't find a boot device, return an error to u-boot.
480295367Sdes	 * U-boot may be running a boot script that can try something different
481295367Sdes	 * so returning an error is better than forcing a reboot.
482295367Sdes	 */
48357429Smarkm	if (devsw[i] == NULL) {
48457429Smarkm		printf("No boot device found!\n");
48569591Sgreen		return (0xbadef1ce);
48669591Sgreen	}
48769591Sgreen
48869591Sgreen	env_setenv("currdev", EV_VOLATILE, uboot_fmtdev(&currdev),
489295367Sdes	    uboot_setcurrdev, env_nounset);
490295367Sdes	env_setenv("loaddev", EV_VOLATILE, uboot_fmtdev(&currdev),
491137019Sdes	    env_noset, env_nounset);
49257429Smarkm
49376262Sgreen	setenv("LINES", "24", 1);		/* optional */
494295367Sdes	setenv("prompt", "loader>", 1);
49557429Smarkm
496295367Sdes	archsw.arch_loadaddr = uboot_loadaddr;
497295367Sdes	archsw.arch_getdev = uboot_getdev;
498295367Sdes	archsw.arch_copyin = uboot_copyin;
499295367Sdes	archsw.arch_copyout = uboot_copyout;
50057429Smarkm	archsw.arch_readin = uboot_readin;
501295367Sdes	archsw.arch_autoload = uboot_autoload;
502295367Sdes
503264377Sdes	interact();				/* doesn't return */
504295367Sdes
50557429Smarkm	return (0);
50692559Sdes}
50792559Sdes
508295367Sdes
50998684SdesCOMMAND_SET(heap, "heap", "show heap usage", command_heap);
51098684Sdesstatic int
51198684Sdescommand_heap(int argc, char *argv[])
51298684Sdes{
513295367Sdes
51498684Sdes	printf("heap base at %p, top at %p, used %d\n", end, sbrk(0),
515295367Sdes	    sbrk(0) - end);
516295367Sdes
51798684Sdes	return (CMD_OK);
51898684Sdes}
51998684Sdes
520262566SdesCOMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
521262566Sdesstatic int
522295367Sdescommand_reboot(int argc, char *argv[])
523295367Sdes{
524295367Sdes
52598684Sdes	printf("Resetting...\n");
52698684Sdes	ub_reset();
527295367Sdes
52898684Sdes	printf("Reset failed!\n");
52998684Sdes	while(1);
53098684Sdes}
531295367Sdes
532295367SdesCOMMAND_SET(devinfo, "devinfo", "show U-Boot devices", command_devinfo);
53398684Sdesstatic int
534295367Sdescommand_devinfo(int argc, char *argv[])
535295367Sdes{
536295367Sdes	int i;
537295367Sdes
53898684Sdes	if ((devs_no = ub_dev_enum()) == 0) {
539262566Sdes		command_errmsg = "no U-Boot devices found!?";
540262566Sdes		return (CMD_ERROR);
541295367Sdes	}
542295367Sdes
543262566Sdes	printf("U-Boot devices:\n");
544295367Sdes	for (i = 0; i < devs_no; i++) {
545295367Sdes		ub_dump_di(i);
546295367Sdes		printf("\n");
547295367Sdes	}
548295367Sdes	return (CMD_OK);
549295367Sdes}
550295367Sdes
551295367SdesCOMMAND_SET(sysinfo, "sysinfo", "show U-Boot system info", command_sysinfo);
552262566Sdesstatic int
55398684Sdescommand_sysinfo(int argc, char *argv[])
554295367Sdes{
55598684Sdes	struct sys_info *si;
55698684Sdes
55798684Sdes	if ((si = ub_get_sys_info()) == NULL) {
55898684Sdes		command_errmsg = "could not retrieve U-Boot sys info!?";
559295367Sdes		return (CMD_ERROR);
560295367Sdes	}
561295367Sdes
562295367Sdes	printf("U-Boot system info:\n");
563149753Sdes	ub_dump_si(si);
564295367Sdes	return (CMD_OK);
565248619Sdes}
566124211Sdes
567124211Sdesenum ubenv_action {
568124211Sdes	UBENV_UNKNOWN,
569248619Sdes	UBENV_SHOW,
570295367Sdes	UBENV_IMPORT
571295367Sdes};
572295367Sdes
573295367Sdesstatic void
574295367Sdeshandle_uboot_env_var(enum ubenv_action action, const char * var)
575295367Sdes{
57698684Sdes	const char * val;
577295367Sdes	char ubv[128];
578295367Sdes
579124211Sdes	/*
580295367Sdes	 * If the user prepended "uboot." (which is how they usually see these
581295367Sdes	 * names) strip it off as a convenience.
58298684Sdes	 */
583295367Sdes	if (strncmp(var, "uboot.", 6) == 0) {
58498684Sdes		snprintf(ubv, sizeof(ubv), "%s", &var[6]);
585295367Sdes		var = ubv;
58698684Sdes	}
58798684Sdes	val = ub_env_get(var);
588295367Sdes	if (action == UBENV_SHOW) {
589295367Sdes		if (val == NULL)
59098684Sdes			printf("uboot.%s is not set\n", var);
591295367Sdes		else
592295367Sdes			printf("uboot.%s=%s\n", var, val);
593295367Sdes	} else if (action == UBENV_IMPORT) {
594295367Sdes		if (val != NULL) {
59598684Sdes			snprintf(ubv, sizeof(ubv), "uboot.%s", var);
596262566Sdes			setenv(ubv, val, 1);
597295367Sdes		}
598295367Sdes	}
599295367Sdes}
600262566Sdes
60198684Sdesstatic int
602295367Sdescommand_ubenv(int argc, char *argv[])
60398684Sdes{
60498684Sdes	enum ubenv_action action;
60598684Sdes	const char *var;
60698684Sdes	int i;
607295367Sdes
608295367Sdes	action = UBENV_UNKNOWN;
609295367Sdes	if (argc > 1) {
610295367Sdes		if (strcasecmp(argv[1], "import") == 0)
611295367Sdes			action = UBENV_IMPORT;
612295367Sdes		else if (strcasecmp(argv[1], "show") == 0)
613295367Sdes			action = UBENV_SHOW;
614295367Sdes	}
615295367Sdes	if (action == UBENV_UNKNOWN) {
616295367Sdes		command_errmsg = "usage: 'ubenv <import|show> [var ...]";
61798684Sdes		return (CMD_ERROR);
618295367Sdes	}
619295367Sdes
620295367Sdes	if (argc > 2) {
621248619Sdes		for (i = 2; i < argc; i++)
62298684Sdes			handle_uboot_env_var(action, argv[i]);
623295367Sdes	} else {
62498684Sdes		var = NULL;
625295367Sdes		for (;;) {
62698684Sdes			if ((var = ub_env_enum(var)) == NULL)
62798684Sdes				break;
628295367Sdes			handle_uboot_env_var(action, var);
629295367Sdes		}
630295367Sdes	}
631295367Sdes
632295367Sdes	return (CMD_OK);
63398684Sdes}
634295367SdesCOMMAND_SET(ubenv, "ubenv", "show or import U-Boot env vars", command_ubenv);
63598684Sdes
636323124Sdes#ifdef LOADER_FDT_SUPPORT
637295367Sdes/*
63898684Sdes * Since proper fdt command handling function is defined in fdt_loader_cmd.c,
63998684Sdes * and declaring it as extern is in contradiction with COMMAND_SET() macro
640248619Sdes * (which uses static pointer), we're defining wrapper function, which
64198684Sdes * calls the proper fdt handling routine.
64298684Sdes */
64398684Sdesstatic int
64498684Sdescommand_fdt(int argc, char *argv[])
64598684Sdes{
64698684Sdes
647295367Sdes	return (command_fdt_internal(argc, argv));
648295367Sdes}
649295367Sdes
65098684SdesCOMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
65198684Sdes#endif
65298684Sdes