2 * Copyright (c) 2000 Benno Rice <benno@jeamland.net>
3 * Copyright (c) 2000 Stephane Potvin <sepotvin@videotron.ca>
4 * Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 #include <sys/param.h>
34 #include "api_public.h"
35 #include "bootstrap.h"
40 #define nitems(x) (sizeof((x)) / sizeof((x)[0]))
43 struct uboot_devdesc currdev
;
44 struct arch_switch archsw
; /* MI/MD interface boundary */
47 uintptr_t uboot_heap_start
;
48 uintptr_t uboot_heap_end
;
54 { "disk", DEV_TYP_STOR
},
55 { "ide", DEV_TYP_STOR
| DT_STOR_IDE
},
56 { "mmc", DEV_TYP_STOR
| DT_STOR_MMC
},
57 { "sata", DEV_TYP_STOR
| DT_STOR_SATA
},
58 { "scsi", DEV_TYP_STOR
| DT_STOR_SCSI
},
59 { "usb", DEV_TYP_STOR
| DT_STOR_USB
},
60 { "net", DEV_TYP_NET
}
64 extern char bootprog_info
[];
66 extern unsigned char _etext
[];
67 extern unsigned char _edata
[];
68 extern unsigned char __bss_start
[];
69 extern unsigned char __sbss_start
[];
70 extern unsigned char __sbss_end
[];
71 extern unsigned char _end
[];
73 #ifdef LOADER_FDT_SUPPORT
74 extern int command_fdt_internal(int argc
, char *argv
[]);
78 dump_sig(struct api_signature
*sig
)
81 printf("signature:\n");
82 printf(" version\t= %d\n", sig
->version
);
83 printf(" checksum\t= 0x%08x\n", sig
->checksum
);
84 printf(" sc entry\t= 0x%08x\n", sig
->syscall
);
92 printf("\naddresses info:\n");
93 printf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext
);
94 printf(" _edata = 0x%08x\n", (uint32_t)_edata
);
95 printf(" __sbss_start = 0x%08x\n", (uint32_t)__sbss_start
);
96 printf(" __sbss_end = 0x%08x\n", (uint32_t)__sbss_end
);
97 printf(" __sbss_start = 0x%08x\n", (uint32_t)__bss_start
);
98 printf(" _end = 0x%08x\n", (uint32_t)_end
);
99 printf(" syscall entry = 0x%08x\n", (uint32_t)syscall_ptr
);
104 memsize(struct sys_info
*si
, int flags
)
110 for (i
= 0; i
< si
->mr_no
; i
++)
111 if (si
->mr
[i
].flags
== flags
&& si
->mr
[i
].size
)
112 size
+= (si
->mr
[i
].size
);
122 int t
[3] = { MR_ATTR_DRAM
, MR_ATTR_FLASH
, MR_ATTR_SRAM
};
125 if ((si
= ub_get_sys_info()) == NULL
)
126 panic("could not retrieve system info");
128 for (i
= 0; i
< 3; i
++) {
129 size
= memsize(si
, t
[i
]);
131 printf("%s: %juMB\n", ub_mem_type(t
[i
]),
132 (uintmax_t)(size
/ 1024 / 1024));
137 get_device_type(const char *devstr
, int *devtype
)
141 struct device_type
*dt
;
144 for (i
= 0; i
< nitems(device_types
); i
++) {
145 dt
= &device_types
[i
];
146 namelen
= strlen(dt
->name
);
147 if (strncmp(dt
->name
, devstr
, namelen
) == 0) {
149 return (devstr
+ namelen
);
152 printf("Unknown device type '%s'\n", devstr
);
160 device_typename(int type
)
164 for (i
= 0; i
< nitems(device_types
); i
++)
165 if (device_types
[i
].type
== type
)
166 return (device_types
[i
].name
);
168 return ("<unknown>");
172 * Parse a device string into type, unit, slice and partition numbers. A
173 * returned value of -1 for type indicates a search should be done for the
174 * first loadable device, otherwise a returned value of -1 for unit
175 * indicates a search should be done for the first loadable device of the
178 * The returned values for slice and partition are interpreted by
181 * Valid device strings: For device types:
183 * <type_name> DEV_TYP_STOR, DEV_TYP_NET
184 * <type_name><unit> DEV_TYP_STOR, DEV_TYP_NET
185 * <type_name><unit>: DEV_TYP_STOR, DEV_TYP_NET
186 * <type_name><unit>:<slice> DEV_TYP_STOR
187 * <type_name><unit>:<slice>. DEV_TYP_STOR
188 * <type_name><unit>:<slice>.<partition> DEV_TYP_STOR
190 * For valid type names, see the device_types array, above.
192 * Slice numbers are 1-based. 0 is a wildcard.
195 get_load_device(int *type
, int *unit
, int *slice
, int *partition
)
206 devstr
= ub_env_get("loaderdev");
207 if (devstr
== NULL
) {
208 printf("U-Boot env: loaderdev not set, will probe all devices.\n");
211 printf("U-Boot env: loaderdev='%s'\n", devstr
);
213 p
= get_device_type(devstr
, type
);
215 /* Ignore optional spaces after the device name. */
219 /* Unknown device name, or a known name without unit number. */
220 if ((*type
== -1) || (*p
== '\0')) {
224 /* Malformed unit number. */
230 /* Guaranteed to extract a number from the string, as *p is a digit. */
231 *unit
= strtol(p
, &endp
, 10);
234 /* Known device name with unit number and nothing else. */
239 /* Device string is malformed beyond unit number. */
248 /* No slice and partition specification. */
252 /* Only DEV_TYP_STOR devices can have a slice specification. */
253 if (!(*type
& DEV_TYP_STOR
)) {
259 *slice
= strtoul(p
, &endp
, 10);
261 /* Malformed slice number. */
271 /* No partition specification. */
275 /* Device string is malformed beyond slice number. */
285 /* No partition specification. */
289 *partition
= strtol(p
, &endp
, 10);
292 /* Full, valid device string. */
296 /* Junk beyond partition number. */
304 print_disk_probe_info()
309 if (currdev
.d_disk
.slice
> 0)
310 sprintf(slice
, "%d", currdev
.d_disk
.slice
);
312 strcpy(slice
, "<auto>");
314 if (currdev
.d_disk
.partition
>= 0)
315 sprintf(partition
, "%d", currdev
.d_disk
.partition
);
317 strcpy(partition
, "<auto>");
319 printf(" Checking unit=%d slice=%s partition=%s...",
320 currdev
.dd
.d_unit
, slice
, partition
);
325 probe_disks(int devidx
, int load_type
, int load_unit
, int load_slice
,
328 int open_result
, unit
;
331 currdev
.d_disk
.slice
= load_slice
;
332 currdev
.d_disk
.partition
= load_partition
;
334 f
.f_devdata
= &currdev
;
337 if (load_type
== -1) {
338 printf(" Probing all disk devices...\n");
339 /* Try each disk in succession until one works. */
340 for (currdev
.dd
.d_unit
= 0; currdev
.dd
.d_unit
< UB_MAX_DEV
;
341 currdev
.dd
.d_unit
++) {
342 print_disk_probe_info();
343 open_result
= devsw
[devidx
]->dv_open(&f
, &currdev
);
344 if (open_result
== 0) {
353 if (load_unit
== -1) {
354 printf(" Probing all %s devices...\n", device_typename(load_type
));
355 /* Try each disk of given type in succession until one works. */
356 for (unit
= 0; unit
< UB_MAX_DEV
; unit
++) {
357 currdev
.dd
.d_unit
= uboot_diskgetunit(load_type
, unit
);
358 if (currdev
.dd
.d_unit
== -1)
360 print_disk_probe_info();
361 open_result
= devsw
[devidx
]->dv_open(&f
, &currdev
);
362 if (open_result
== 0) {
371 if ((currdev
.dd
.d_unit
= uboot_diskgetunit(load_type
, load_unit
)) != -1) {
372 print_disk_probe_info();
373 open_result
= devsw
[devidx
]->dv_open(&f
,&currdev
);
374 if (open_result
== 0) {
381 printf(" Requested disk type/unit/slice/partition not found\n");
388 struct api_signature
*sig
= NULL
;
389 int load_type
, load_unit
, load_slice
, load_partition
;
394 * If we can't find the magic signature and related info, exit with a
395 * unique error code that U-Boot reports as "## Application terminated,
396 * rc = 0xnnbadab1". Hopefully 'badab1' looks enough like "bad api" to
397 * provide a clue. It's better than 0xffffffff anyway.
399 if (!api_search_sig(&sig
))
402 syscall_ptr
= sig
->syscall
;
403 if (syscall_ptr
== NULL
)
406 if (sig
->version
> API_SIG_VERSION
)
409 /* Clear BSS sections */
410 bzero(__sbss_start
, __sbss_end
- __sbss_start
);
411 bzero(__bss_start
, _end
- __bss_start
);
414 * Initialise the heap as early as possible. Once this is done,
415 * alloc() is usable. The stack is buried inside us, so this is safe.
417 uboot_heap_start
= round_page((uintptr_t)end
);
418 uboot_heap_end
= uboot_heap_start
+ 512 * 1024;
419 setheap((void *)uboot_heap_start
, (void *)uboot_heap_end
);
425 printf("Compatible U-Boot API signature found @%p\n", sig
);
427 printf("\n%s", bootprog_info
);
436 * Enumerate U-Boot devices
438 if ((devs_no
= ub_dev_enum()) == 0)
439 panic("no U-Boot devices found");
440 printf("Number of U-Boot devices: %d\n", devs_no
);
442 get_load_device(&load_type
, &load_unit
, &load_slice
, &load_partition
);
445 * March through the device switch probing for things.
447 for (i
= 0; devsw
[i
] != NULL
; i
++) {
449 if (devsw
[i
]->dv_init
== NULL
)
451 if ((devsw
[i
]->dv_init
)() != 0)
454 printf("Found U-Boot device: %s\n", devsw
[i
]->dv_name
);
456 currdev
.dd
.d_dev
= devsw
[i
];
457 currdev
.dd
.d_unit
= 0;
459 if ((load_type
== -1 || (load_type
& DEV_TYP_STOR
)) &&
460 strcmp(devsw
[i
]->dv_name
, "disk") == 0) {
461 if (probe_disks(i
, load_type
, load_unit
, load_slice
,
462 load_partition
) == 0)
466 if ((load_type
== -1 || (load_type
& DEV_TYP_NET
)) &&
467 strcmp(devsw
[i
]->dv_name
, "net") == 0)
472 * If we couldn't find a boot device, return an error to u-boot.
473 * U-boot may be running a boot script that can try something different
474 * so returning an error is better than forcing a reboot.
476 if (devsw
[i
] == NULL
) {
477 printf("No boot device found!\n");
481 ldev
= uboot_fmtdev(&currdev
);
482 env_setenv("currdev", EV_VOLATILE
, ldev
, uboot_setcurrdev
, env_nounset
);
483 env_setenv("loaddev", EV_VOLATILE
, ldev
, env_noset
, env_nounset
);
484 printf("Booting from %s\n", ldev
);
486 setenv("LINES", "24", 1); /* optional */
487 setenv("prompt", "loader>", 1);
489 archsw
.arch_loadaddr
= uboot_loadaddr
;
490 archsw
.arch_getdev
= uboot_getdev
;
491 archsw
.arch_copyin
= uboot_copyin
;
492 archsw
.arch_copyout
= uboot_copyout
;
493 archsw
.arch_readin
= uboot_readin
;
494 archsw
.arch_autoload
= uboot_autoload
;
496 interact(NULL
); /* doesn't return */
502 COMMAND_SET(heap
, "heap", "show heap usage", command_heap
);
504 command_heap(int argc
, char *argv
[])
507 printf("heap base at %p, top at %p, used %td\n", end
, sbrk(0),
513 COMMAND_SET(reboot
, "reboot", "reboot the system", command_reboot
);
515 command_reboot(int argc
, char *argv
[])
518 printf("Resetting...\n");
521 printf("Reset failed!\n");
525 COMMAND_SET(devinfo
, "devinfo", "show U-Boot devices", command_devinfo
);
527 command_devinfo(int argc
, char *argv
[])
531 if ((devs_no
= ub_dev_enum()) == 0) {
532 command_errmsg
= "no U-Boot devices found!?";
536 printf("U-Boot devices:\n");
537 for (i
= 0; i
< devs_no
; i
++) {
544 COMMAND_SET(sysinfo
, "sysinfo", "show U-Boot system info", command_sysinfo
);
546 command_sysinfo(int argc
, char *argv
[])
550 if ((si
= ub_get_sys_info()) == NULL
) {
551 command_errmsg
= "could not retrieve U-Boot sys info!?";
555 printf("U-Boot system info:\n");
567 handle_uboot_env_var(enum ubenv_action action
, const char * var
)
575 * On an import with the variable name formatted as ldname=ubname,
576 * import the uboot variable ubname into the loader variable ldname,
577 * otherwise the historical behavior is to import to uboot.ubname.
579 if (action
== UBENV_IMPORT
) {
580 len
= strcspn(var
, "=");
582 printf("name cannot start with '=': '%s'\n", var
);
586 strcpy(ldvar
, "uboot.");
587 strncat(ldvar
, var
, sizeof(ldvar
) - 7);
589 len
= MIN(len
, sizeof(ldvar
) - 1);
590 strncpy(ldvar
, var
, len
);
597 * If the user prepended "uboot." (which is how they usually see these
598 * names) strip it off as a convenience.
600 if (strncmp(var
, "uboot.", 6) == 0) {
604 /* If there is no variable name left, punt. */
606 printf("empty variable name\n");
610 val
= ub_env_get(var
);
611 if (action
== UBENV_SHOW
) {
613 printf("uboot.%s is not set\n", var
);
615 printf("uboot.%s=%s\n", var
, val
);
616 } else if (action
== UBENV_IMPORT
) {
618 setenv(ldvar
, val
, 1);
624 command_ubenv(int argc
, char *argv
[])
626 enum ubenv_action action
;
630 action
= UBENV_UNKNOWN
;
632 if (strcasecmp(argv
[1], "import") == 0)
633 action
= UBENV_IMPORT
;
634 else if (strcasecmp(argv
[1], "show") == 0)
637 if (action
== UBENV_UNKNOWN
) {
638 command_errmsg
= "usage: 'ubenv <import|show> [var ...]";
643 for (i
= 2; i
< argc
; i
++)
644 handle_uboot_env_var(action
, argv
[i
]);
648 if ((var
= ub_env_enum(var
)) == NULL
)
650 handle_uboot_env_var(action
, var
);
656 COMMAND_SET(ubenv
, "ubenv", "show or import U-Boot env vars", command_ubenv
);
658 #ifdef LOADER_FDT_SUPPORT
660 * Since proper fdt command handling function is defined in fdt_loader_cmd.c,
661 * and declaring it as extern is in contradiction with COMMAND_SET() macro
662 * (which uses static pointer), we're defining wrapper function, which
663 * calls the proper fdt handling routine.
666 command_fdt(int argc
, char *argv
[])
669 return (command_fdt_internal(argc
, argv
));
672 COMMAND_SET(fdt
, "fdt", "flattened device tree handling", command_fdt
);