Changeset View
Changeset View
Standalone View
Standalone View
sys/boot/uboot/common/main.c
/*- | /*- | ||||
* Copyright (c) 2000 Benno Rice <benno@jeamland.net> | * Copyright (c) 2000 Benno Rice <benno@jeamland.net> | ||||
* Copyright (c) 2000 Stephane Potvin <sepotvin@videotron.ca> | * Copyright (c) 2000 Stephane Potvin <sepotvin@videotron.ca> | ||||
* Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com> | * Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com> | ||||
* Copyright (c) 2016 Vladimir Belian <fate10@gmail.com> | |||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
* 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | ||||
Show All 19 Lines | |||||
#include <stand.h> | #include <stand.h> | ||||
#include "api_public.h" | #include "api_public.h" | ||||
#include "bootstrap.h" | #include "bootstrap.h" | ||||
#include "glue.h" | #include "glue.h" | ||||
#include "libuboot.h" | #include "libuboot.h" | ||||
#ifdef LOADER_ZFS_SUPPORT | |||||
#include <libzfs.h> | |||||
#endif | |||||
#ifndef nitems | #ifndef nitems | ||||
#define nitems(x) (sizeof((x)) / sizeof((x)[0])) | #define nitems(x) (sizeof((x)) / sizeof((x)[0])) | ||||
#endif | #endif | ||||
struct uboot_devdesc currdev; | #ifdef DEBUG | ||||
#define PRINT_DEBUG_INFO() do { \ | |||||
printf("signature:\n"); \ | |||||
printf(" version\t= %d\n", sig->version); \ | |||||
printf(" checksum\t= 0x%08x\n", sig->checksum); \ | |||||
printf(" sc entry\t= 0x%08x\n", sig->syscall); \ | |||||
printf("\naddresses info:\n"); \ | |||||
printf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext); \ | |||||
printf(" _edata = 0x%08x\n", (uint32_t)_edata); \ | |||||
printf(" __sbss_start = 0x%08x\n", (uint32_t)__sbss_start); \ | |||||
printf(" __sbss_end = 0x%08x\n", (uint32_t)__sbss_end); \ | |||||
printf(" __bss_start = 0x%08x\n", (uint32_t)__bss_start); \ | |||||
printf(" _end = 0x%08x\n", (uint32_t)_end); \ | |||||
printf(" syscall entry = 0x%08x\n", (uint32_t)syscall_ptr); \ | |||||
printf(" uboot_heap_start = 0x%08x\n", (uint32_t)uboot_heap_start); \ | |||||
printf(" uboot_heap_end = 0x%08x\n", (uint32_t)uboot_heap_end); } while (0) | |||||
#else | |||||
#define PRINT_DEBUG_INFO() | |||||
#endif | |||||
struct arch_switch archsw; /* MI/MD interface boundary */ | struct arch_switch archsw; /* MI/MD interface boundary */ | ||||
int devs_no; | |||||
uintptr_t uboot_heap_start; | uintptr_t uboot_heap_start; | ||||
uintptr_t uboot_heap_end; | uintptr_t uboot_heap_end; | ||||
struct device_type { | |||||
const char *name; | |||||
int type; | |||||
} device_types[] = { | |||||
{ "disk", DEV_TYP_STOR }, | |||||
{ "ide", DEV_TYP_STOR | DT_STOR_IDE }, | |||||
{ "mmc", DEV_TYP_STOR | DT_STOR_MMC }, | |||||
{ "sata", DEV_TYP_STOR | DT_STOR_SATA }, | |||||
{ "scsi", DEV_TYP_STOR | DT_STOR_SCSI }, | |||||
{ "usb", DEV_TYP_STOR | DT_STOR_USB }, | |||||
{ "net", DEV_TYP_NET } | |||||
}; | |||||
extern char end[]; | extern char end[]; | ||||
extern char bootprog_name[]; | extern char bootprog_name[]; | ||||
extern char bootprog_rev[]; | extern char bootprog_rev[]; | ||||
extern char bootprog_date[]; | extern char bootprog_date[]; | ||||
extern char bootprog_maker[]; | extern char bootprog_maker[]; | ||||
extern unsigned char _etext[]; | extern unsigned char _etext[]; | ||||
extern unsigned char _edata[]; | extern unsigned char _edata[]; | ||||
extern unsigned char __bss_start[]; | extern unsigned char __bss_start[]; | ||||
extern unsigned char __sbss_start[]; | extern unsigned char __sbss_start[]; | ||||
extern unsigned char __sbss_end[]; | extern unsigned char __sbss_end[]; | ||||
extern unsigned char _end[]; | extern unsigned char _end[]; | ||||
#ifdef LOADER_FDT_SUPPORT | #ifdef LOADER_FDT_SUPPORT | ||||
extern int command_fdt_internal(int argc, char *argv[]); | extern int command_fdt_internal(int argc, char *argv[]); | ||||
#endif | #endif | ||||
#ifdef LOADER_ZFS_SUPPORT | |||||
static uint64_t zfs_pools[UB_MAX_DEV]; | |||||
static void | static void | ||||
dump_sig(struct api_signature *sig) | uboot_zfs_probe(void) | ||||
{ | { | ||||
#ifdef DEBUG | char dname[SPECNAMELEN + 1]; | ||||
printf("signature:\n"); | uint64_t id; | ||||
printf(" version\t= %d\n", sig->version); | int p, n = 0, i = 0, maxp = 0; | ||||
printf(" checksum\t= 0x%08x\n", sig->checksum); | |||||
printf(" sc entry\t= 0x%08x\n", sig->syscall); | bzero(&zfs_pools, sizeof(zfs_pools)); | ||||
#endif | |||||
while (ub_dev_get(DEV_TYP_STOR, &i) != NULL) { | |||||
snprintf(dname, sizeof(dname), "disk%d:", n++); | |||||
id = 0; | |||||
if (zfs_probe_dev(dname, &id) == 0) { | |||||
if (id == 0) | |||||
continue; | |||||
/* skip pool guid duplicates if found */ | |||||
for (p = 0; (p < maxp) && (zfs_pools[p] != id); p++) ; | |||||
if (p < maxp) | |||||
continue; | |||||
zfs_pools[maxp++] = id; | |||||
} | } | ||||
} | |||||
} | |||||
static void | static const char * | ||||
dump_addr_info(void) | probe_zfs(const char *dstr) | ||||
{ | { | ||||
#ifdef DEBUG | struct zfs_devdesc dev; | ||||
printf("\naddresses info:\n"); | char *p = NULL, *buf; | ||||
printf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext); | int i, l; | ||||
printf(" _edata = 0x%08x\n", (uint32_t)_edata); | |||||
printf(" __sbss_start = 0x%08x\n", (uint32_t)__sbss_start); | if ((dstr != NULL) && (strncasecmp(dstr, "zfs", 3) != 0)) | ||||
printf(" __sbss_end = 0x%08x\n", (uint32_t)__sbss_end); | return (NULL); | ||||
printf(" __sbss_start = 0x%08x\n", (uint32_t)__bss_start); | |||||
printf(" _end = 0x%08x\n", (uint32_t)_end); | if ((dstr != NULL) && ((dstr = strchr(dstr, ' ')) != NULL)) | ||||
printf(" syscall entry = 0x%08x\n", (uint32_t)syscall_ptr); | dstr++; | ||||
#endif | |||||
for (i = 0; zfs_pools[i] != 0; i++) { | |||||
bzero(&dev, sizeof(dev)); | |||||
dev.d_dev = &zfs_dev; | |||||
dev.d_type = dev.d_dev->dv_type; | |||||
dev.pool_guid = zfs_pools[i]; | |||||
buf = zfs_fmtdev(&dev); | |||||
p = strchr(buf, ':') + 1; | |||||
l = strcspn(p, ":/"); | |||||
if ((buf != NULL) && ((dstr == NULL) || (*dstr == '\0') || | |||||
((l == strlen(dstr)) && (strncmp(dstr, p, l) == 0)))) | |||||
break; | |||||
buf = NULL; | |||||
} | } | ||||
if (buf != NULL) { | |||||
init_zfs_bootenv(buf); | |||||
return (zfs_fmtdev(&dev)); | |||||
} | |||||
printf("could not find %s zfs pool\n", | |||||
(((dstr == NULL) || (*dstr == '\0'))) ? "any" : dstr); | |||||
return (NULL); | |||||
} | |||||
#endif | |||||
static uint64_t | static uint64_t | ||||
memsize(struct sys_info *si, int flags) | memsize(struct sys_info *si, int flags) | ||||
{ | { | ||||
uint64_t size; | uint64_t size; | ||||
int i; | int i; | ||||
size = 0; | size = 0; | ||||
Show All 14 Lines | meminfo(void) | ||||
if ((si = ub_get_sys_info()) == NULL) | if ((si = ub_get_sys_info()) == NULL) | ||||
panic("could not retrieve system info"); | panic("could not retrieve system info"); | ||||
for (i = 0; i < 3; i++) { | for (i = 0; i < 3; i++) { | ||||
size = memsize(si, t[i]); | size = memsize(si, t[i]); | ||||
if (size > 0) | if (size > 0) | ||||
printf("%s: %juMB\n", ub_mem_type(t[i]), | printf("%s: %juMB\n", ub_mem_type(t[i]), | ||||
(uintmax_t)(size / 1024 / 1024)); | (uintmax_t)(size / 1024 / 1024)); | ||||
} | } | ||||
} | } | ||||
static const char * | static struct devsw * | ||||
get_device_type(const char *devstr, int *devtype) | search_devsw(int type) | ||||
{ | { | ||||
int i; | int i; | ||||
int namelen; | |||||
struct device_type *dt; | |||||
if (devstr) { | for (i = 0; devsw[i] != NULL; i++) | ||||
for (i = 0; i < nitems(device_types); i++) { | if (devsw[i]->dv_type == type) | ||||
dt = &device_types[i]; | return (devsw[i]); | ||||
namelen = strlen(dt->name); | |||||
if (strncmp(dt->name, devstr, namelen) == 0) { | |||||
*devtype = dt->type; | |||||
return (devstr + namelen); | |||||
} | |||||
} | |||||
printf("Unknown device type '%s'\n", devstr); | |||||
} | |||||
*devtype = -1; | |||||
return (NULL); | return (NULL); | ||||
} | } | ||||
static const char * | |||||
device_typename(int type) | |||||
{ | |||||
int i; | |||||
for (i = 0; i < nitems(device_types); i++) | |||||
if (device_types[i].type == type) | |||||
return (device_types[i].name); | |||||
return ("<unknown>"); | |||||
} | |||||
/* | /* | ||||
* Parse a device string into type, unit, slice and partition numbers. A | * Parse a device string into unit, slice and partition numbers. | ||||
* returned value of -1 for type indicates a search should be done for the | |||||
* first loadable device, otherwise a returned value of -1 for unit | |||||
* indicates a search should be done for the first loadable device of the | |||||
* given type. | |||||
* | * | ||||
* The returned values for slice and partition are interpreted by | * The returned values for slice and partition are interpreted by | ||||
* disk_open(). | * disk_open(). | ||||
* | * | ||||
* Valid device strings: For device types: | * Valid device strings: | ||||
* | * | ||||
* <type_name> DEV_TYP_STOR, DEV_TYP_NET | * <unit> | ||||
* <type_name><unit> DEV_TYP_STOR, DEV_TYP_NET | * <unit>: | ||||
* <type_name><unit>: DEV_TYP_STOR, DEV_TYP_NET | * <unit>:<slice> | ||||
* <type_name><unit>:<slice> DEV_TYP_STOR | * <unit>:<slice>. | ||||
* <type_name><unit>:<slice>. DEV_TYP_STOR | * <unit>:<slice>.<partition> | ||||
* <type_name><unit>:<slice>.<partition> DEV_TYP_STOR | |||||
* | * | ||||
* For valid type names, see the device_types array, above. | |||||
* | |||||
* Slice numbers are 1-based. 0 is a wildcard. | * Slice numbers are 1-based. 0 is a wildcard. | ||||
*/ | */ | ||||
static void | static int | ||||
get_load_device(int *type, int *unit, int *slice, int *partition) | decode_devstr(const char *dstr, int *unit, int *slice, int *partition) | ||||
{ | { | ||||
char *devstr; | |||||
const char *p; | const char *p; | ||||
char *endp; | char *endp; | ||||
*type = -1; | |||||
*unit = -1; | |||||
*slice = 0; | |||||
*partition = -1; | |||||
devstr = ub_env_get("loaderdev"); | |||||
if (devstr == NULL) { | |||||
printf("U-Boot env: loaderdev not set, will probe all devices.\n"); | |||||
return; | |||||
} | |||||
printf("U-Boot env: loaderdev='%s'\n", devstr); | |||||
p = get_device_type(devstr, type); | |||||
/* Ignore optional spaces after the device name. */ | /* Ignore optional spaces after the device name. */ | ||||
while (*p == ' ') | while (*dstr == ' ') | ||||
p++; | dstr++; | ||||
/* Unknown device name, or a known name without unit number. */ | /* No unit number present. */ | ||||
if ((*type == -1) || (*p == '\0')) { | if (*dstr == '\0') { | ||||
return; | return (-1); | ||||
} | } | ||||
/* Malformed unit number. */ | /* Malformed unit number. */ | ||||
if (!isdigit(*p)) { | if (!isdigit(*dstr)) | ||||
*type = -1; | return (0); | ||||
return; | |||||
} | |||||
/* Guaranteed to extract a number from the string, as *p is a digit. */ | /* Guaranteed to extract a number from the string, as *dstr is a digit. */ | ||||
*unit = strtol(p, &endp, 10); | *unit = strtol(dstr, &endp, 10); | ||||
p = endp; | dstr = endp; | ||||
/* Known device name with unit number and nothing else. */ | /* Unit number and nothing else. */ | ||||
if (*p == '\0') { | if (*dstr == '\0') | ||||
return; | return (1); | ||||
} | |||||
/* Device string is malformed beyond unit number. */ | /* Device string is malformed beyond unit number. */ | ||||
if (*p != ':') { | if (*dstr != ':') | ||||
*type = -1; | return (0); | ||||
*unit = -1; | dstr++; | ||||
return; | |||||
} | |||||
p++; | |||||
/* No slice and partition specification. */ | /* No slice and partition specification. */ | ||||
if ('\0' == *p ) | if (*dstr == '\0') | ||||
return; | return (1); | ||||
/* Only DEV_TYP_STOR devices can have a slice specification. */ | *slice = strtoul(dstr, &endp, 10); | ||||
if (!(*type & DEV_TYP_STOR)) { | |||||
*type = -1; | |||||
*unit = -1; | |||||
return; | |||||
} | |||||
*slice = strtoul(p, &endp, 10); | |||||
/* Malformed slice number. */ | /* Malformed slice number. */ | ||||
if (p == endp) { | if (dstr == endp) | ||||
*type = -1; | return (0); | ||||
*unit = -1; | dstr = endp; | ||||
*slice = 0; | |||||
return; | |||||
} | |||||
p = endp; | |||||
/* No partition specification. */ | /* No partition specification. */ | ||||
if (*p == '\0') | if (*dstr == '\0') | ||||
return; | return (1); | ||||
/* Device string is malformed beyond slice number. */ | /* Device string is malformed beyond slice number. */ | ||||
if (*p != '.') { | if (*dstr != '.') | ||||
*type = -1; | return (0); | ||||
*unit = -1; | dstr++; | ||||
*slice = 0; | |||||
return; | |||||
} | |||||
p++; | |||||
/* No partition specification. */ | /* No partition specification. */ | ||||
if (*p == '\0') | if (*dstr == '\0') | ||||
return; | return (1); | ||||
*partition = strtol(p, &endp, 10); | *partition = strtol(dstr, &endp, 10); | ||||
p = endp; | |||||
/* Full, valid device string. */ | /* Full, valid device string. */ | ||||
if (*endp == '\0') | if (*endp == '\0') | ||||
return; | return (1); | ||||
/* Junk beyond partition number. */ | /* Junk beyond partition number. */ | ||||
*type = -1; | return (0); | ||||
*unit = -1; | |||||
*slice = 0; | |||||
*partition = -1; | |||||
} | } | ||||
static void | static void | ||||
print_disk_probe_info() | print_disk_probe_info(struct uboot_devdesc dev) | ||||
{ | { | ||||
char slice[32]; | |||||
char partition[32]; | |||||
if (currdev.d_disk.slice > 0) | printf(" Checking unit=%d ", dev.d_unit); | ||||
sprintf(slice, "%d", currdev.d_disk.slice); | |||||
else | |||||
strcpy(slice, "<auto>"); | |||||
if (currdev.d_disk.partition >= 0) | if (dev.d_disk.slice > 0) | ||||
sprintf(partition, "%d", currdev.d_disk.partition); | printf("slice=%d ", dev.d_disk.slice); | ||||
else | else | ||||
strcpy(partition, "<auto>"); | printf("slice=<auto> "); | ||||
if (dev.d_disk.partition >= 0) | |||||
printf(" Checking unit=%d slice=%s partition=%s...", | printf("partition=%d...", dev.d_disk.partition); | ||||
currdev.d_unit, slice, partition); | else | ||||
printf("partition=<auto>..."); | |||||
} | } | ||||
static int | static const char * | ||||
probe_disks(int devidx, int load_type, int load_unit, int load_slice, | probe_disks(const char *dstr) | ||||
int load_partition) | |||||
{ | { | ||||
int open_result, unit; | struct device_info *di; | ||||
struct uboot_devdesc dev; | |||||
struct open_file f; | struct open_file f; | ||||
int stlist[] = { | |||||
DT_STOR_IDE, DT_STOR_SCSI, DT_STOR_USB, DT_STOR_MMC, | |||||
DT_STOR_SATA | |||||
}; | |||||
int type = DEV_TYP_STOR; | |||||
int nunits = 0, res = -1, valid = -1; | |||||
int i, v; | |||||
char *s; | |||||
currdev.d_disk.slice = load_slice; | bzero(&dev, sizeof(dev)); | ||||
currdev.d_disk.partition = load_partition; | |||||
f.f_devdata = &currdev; | if ((dev.d_dev = search_devsw(DEVT_DISK)) == NULL) | ||||
open_result = -1; | return (NULL); | ||||
if (load_type == -1) { | /* parse devstr if any */ | ||||
printf(" Probing all disk devices...\n"); | if (dstr != NULL) { | ||||
/* Try each disk in succession until one works. */ | for (i = 0; i < nitems(stlist); i++) { | ||||
for (currdev.d_unit = 0; currdev.d_unit < UB_MAX_DEV; | v = strlen(s = ub_stor_type(stlist[i])); | ||||
currdev.d_unit++) { | if (strncasecmp(dstr, s, v) == 0) { | ||||
print_disk_probe_info(); | type = stlist[i]; | ||||
open_result = devsw[devidx]->dv_open(&f, &currdev); | break; | ||||
if (open_result == 0) { | |||||
printf(" good.\n"); | |||||
return (0); | |||||
} | } | ||||
printf("\n"); | |||||
} | } | ||||
return (-1); | /* if device type is none above may be it's genereal disk type */ | ||||
if ((strncasecmp(dstr, "disk", 4) != 0) && (type == DEV_TYP_STOR)) | |||||
return (NULL); | |||||
if ((res = decode_devstr(&dstr[v], &dev.d_unit, | |||||
&dev.d_disk.slice, &dev.d_disk.partition)) == 0) | |||||
return (NULL); | |||||
} | } | ||||
/* calculate real unit address, offset and number of units */ | |||||
for (v = i = 0; (di = ub_dev_get(DEV_TYP_STOR, &i)) != NULL; v++) | |||||
if ((di->type & type) && (nunits++ == dev.d_unit)) | |||||
valid = dev.d_unit += v; | |||||
if (valid == -1) | |||||
return (NULL); | |||||
if (load_unit == -1) { | printf("Found U-Boot device: %s\n", dev.d_dev->dv_name); | ||||
printf(" Probing all %s devices...\n", device_typename(load_type)); | dev.d_type = dev.d_dev->dv_type; | ||||
/* Try each disk of given type in succession until one works. */ | dev.d_disk.partition = -1; | ||||
for (unit = 0; unit < UB_MAX_DEV; unit++) { | f.f_devdata = &dev; | ||||
currdev.d_unit = uboot_diskgetunit(load_type, unit); | |||||
if (currdev.d_unit == -1) | /* probe only one device unit if unit number is specified */ | ||||
break; | if (res > 0) | ||||
print_disk_probe_info(); | nunits = 1; | ||||
open_result = devsw[devidx]->dv_open(&f, &currdev); | while (nunits--) { | ||||
if (open_result == 0) { | print_disk_probe_info(dev); | ||||
if ((dev.d_dev)->dv_open(&f, &dev) == 0) { | |||||
printf(" good.\n"); | printf(" good.\n"); | ||||
return (0); | return (uboot_fmtdev(&dev)); | ||||
} | } | ||||
printf("\n"); | printf("\n"); | ||||
dev.d_unit++; | |||||
} | } | ||||
return (-1); | return (NULL); | ||||
} | } | ||||
if ((currdev.d_unit = uboot_diskgetunit(load_type, load_unit)) != -1) { | static const char * | ||||
print_disk_probe_info(); | probe_net(const char *dstr) | ||||
open_result = devsw[devidx]->dv_open(&f,&currdev); | { | ||||
if (open_result == 0) { | struct uboot_devdesc dev; | ||||
printf(" good.\n"); | int i; | ||||
return (0); | |||||
} | |||||
printf("\n"); | |||||
} | |||||
printf(" Requested disk type/unit/slice/partition not found\n"); | bzero(&dev, sizeof(dev)); | ||||
return (-1); | |||||
if ((dstr != NULL) && (strncasecmp(dstr, "net", 3) != 0)) | |||||
return (NULL); | |||||
if ((dev.d_dev = search_devsw(DEVT_NET)) == NULL) | |||||
return (NULL); | |||||
dev.d_type = dev.d_dev->dv_type; | |||||
return (uboot_fmtdev(&dev)); | |||||
} | } | ||||
int | int | ||||
main(int argc, char **argv) | main(int argc, char **argv) | ||||
{ | { | ||||
struct api_signature *sig = NULL; | struct api_signature *sig = NULL; | ||||
int load_type, load_unit, load_slice, load_partition; | int i, devs_no; | ||||
int i; | const char *devstr, *ldev; | ||||
const char *ldev; | |||||
/* | /* | ||||
* We first check if a command line argument was passed to us containing | * We first check if a command line argument was passed to us containing | ||||
* API's signature address. If it wasn't then we try to search for the | * API's signature address. If it wasn't then we try to search for the | ||||
* API signature via the usual hinted address. | * API signature via the usual hinted address. | ||||
* If we can't find the magic signature and related info, exit with a | * If we can't find the magic signature and related info, exit with a | ||||
* unique error code that U-Boot reports as "## Application terminated, | * unique error code that U-Boot reports as "## Application terminated, | ||||
* rc = 0xnnbadab1". Hopefully 'badab1' looks enough like "bad api" to | * rc = 0xnnbadab1". Hopefully 'badab1' looks enough like "bad api" to | ||||
Show All 13 Lines | main(int argc, char **argv) | ||||
bzero(__sbss_start, __sbss_end - __sbss_start); | bzero(__sbss_start, __sbss_end - __sbss_start); | ||||
bzero(__bss_start, _end - __bss_start); | bzero(__bss_start, _end - __bss_start); | ||||
/* | /* | ||||
* Initialise the heap as early as possible. Once this is done, | * Initialise the heap as early as possible. Once this is done, | ||||
* alloc() is usable. The stack is buried inside us, so this is safe. | * alloc() is usable. The stack is buried inside us, so this is safe. | ||||
*/ | */ | ||||
uboot_heap_start = round_page((uintptr_t)end); | uboot_heap_start = round_page((uintptr_t)end); | ||||
#ifndef LOADER_ZFS_SUPPORT | |||||
uboot_heap_end = uboot_heap_start + 512 * 1024; | uboot_heap_end = uboot_heap_start + 512 * 1024; | ||||
#else | |||||
uboot_heap_end = uboot_heap_start + 2 * 1024 * 1024; | |||||
#endif | |||||
setheap((void *)uboot_heap_start, (void *)uboot_heap_end); | setheap((void *)uboot_heap_start, (void *)uboot_heap_end); | ||||
/* | /* | ||||
* Set up console. | * Set up console. | ||||
*/ | */ | ||||
cons_probe(); | cons_probe(); | ||||
printf("Compatible U-Boot API signature found @%p\n", sig); | printf("Compatible U-Boot API signature found @%p\n", sig); | ||||
printf("\n"); | printf("\n"); | ||||
printf("%s, Revision %s\n", bootprog_name, bootprog_rev); | printf("%s, Revision %s\n", bootprog_name, bootprog_rev); | ||||
printf("(%s, %s)\n", bootprog_maker, bootprog_date); | printf("(%s, %s)\n", bootprog_maker, bootprog_date); | ||||
printf("\n"); | printf("\n"); | ||||
dump_sig(sig); | PRINT_DEBUG_INFO(); | ||||
dump_addr_info(); | |||||
meminfo(); | meminfo(); | ||||
archsw.arch_loadaddr = uboot_loadaddr; | |||||
archsw.arch_getdev = uboot_getdev; | |||||
archsw.arch_copyin = uboot_copyin; | |||||
archsw.arch_copyout = uboot_copyout; | |||||
archsw.arch_readin = uboot_readin; | |||||
archsw.arch_autoload = uboot_autoload; | |||||
#ifdef LOADER_ZFS_SUPPORT | |||||
/* Note this needs to be set before ZFS init. */ | |||||
archsw.arch_zfs_probe = uboot_zfs_probe; | |||||
#endif | |||||
/* | /* | ||||
* Enumerate U-Boot devices | * Enumerate U-Boot devices | ||||
*/ | */ | ||||
if ((devs_no = ub_dev_enum()) == 0) | if ((devs_no = ub_dev_enum()) == 0) | ||||
panic("no U-Boot devices found"); | panic("no U-Boot devices found"); | ||||
printf("Number of U-Boot devices: %d\n", devs_no); | printf("Number of U-Boot devices: %d\n", devs_no); | ||||
get_load_device(&load_type, &load_unit, &load_slice, &load_partition); | devstr = ub_env_get("loaderdev"); | ||||
if (devstr == NULL) | |||||
printf("U-Boot env: loaderdev not set, will probe all devices.\n"); | |||||
else | |||||
printf("U-Boot env: loaderdev='%s'\n", devstr); | |||||
/* | /* | ||||
* March through the device switch probing for things. | * March through the device switch probing for things. | ||||
*/ | */ | ||||
for (i = 0; devsw[i] != NULL; i++) { | for (i = 0; devsw[i] != NULL; i++) | ||||
if (devsw[i]->dv_init != NULL) | |||||
(devsw[i]->dv_init)(); | |||||
if (devsw[i]->dv_init == NULL) | do { | ||||
continue; | #ifdef LOADER_ZFS_SUPPORT | ||||
if ((devsw[i]->dv_init)() != 0) | if ((ldev = probe_zfs(devstr)) != NULL) | ||||
continue; | |||||
printf("Found U-Boot device: %s\n", devsw[i]->dv_name); | |||||
currdev.d_dev = devsw[i]; | |||||
currdev.d_type = currdev.d_dev->dv_type; | |||||
currdev.d_unit = 0; | |||||
if ((load_type == -1 || (load_type & DEV_TYP_STOR)) && | |||||
strcmp(devsw[i]->dv_name, "disk") == 0) { | |||||
if (probe_disks(i, load_type, load_unit, load_slice, | |||||
load_partition) == 0) | |||||
break; | break; | ||||
} | #endif | ||||
if ((ldev = probe_disks(devstr)) != NULL) | |||||
if ((load_type == -1 || (load_type & DEV_TYP_NET)) && | |||||
strcmp(devsw[i]->dv_name, "net") == 0) | |||||
break; | break; | ||||
} | |||||
if ((ldev = probe_net(devstr)) != NULL) | |||||
break; | |||||
/* | /* | ||||
* If we couldn't find a boot device, return an error to u-boot. | * If we couldn't find a boot device, return an error to u-boot. | ||||
* U-boot may be running a boot script that can try something different | * U-boot may be running a boot script that can try something | ||||
* so returning an error is better than forcing a reboot. | * different so returning an error is better than forcing a reboot. | ||||
*/ | */ | ||||
if (devsw[i] == NULL) { | |||||
printf("No boot device found!\n"); | printf("No boot device found!\n"); | ||||
return (0xbadef1ce); | return (0xbadef1ce); | ||||
} | } while (0); | ||||
ldev = uboot_fmtdev(&currdev); | printf("Booting from %s\n", ldev); | ||||
env_setenv("currdev", EV_VOLATILE, ldev, uboot_setcurrdev, env_nounset); | env_setenv("currdev", EV_VOLATILE, ldev, uboot_setcurrdev, env_nounset); | ||||
env_setenv("loaddev", EV_VOLATILE, ldev, env_noset, env_nounset); | env_setenv("loaddev", EV_VOLATILE, ldev, env_noset, env_nounset); | ||||
printf("Booting from %s\n", ldev); | |||||
setenv("LINES", "24", 1); /* optional */ | setenv("LINES", "24", 1); /* optional */ | ||||
setenv("prompt", "loader>", 1); | setenv("prompt", "loader>", 1); | ||||
archsw.arch_loadaddr = uboot_loadaddr; | |||||
archsw.arch_getdev = uboot_getdev; | |||||
archsw.arch_copyin = uboot_copyin; | |||||
archsw.arch_copyout = uboot_copyout; | |||||
archsw.arch_readin = uboot_readin; | |||||
archsw.arch_autoload = uboot_autoload; | |||||
interact(NULL); /* doesn't return */ | interact(NULL); /* doesn't return */ | ||||
return (0); | return (0); | ||||
} | } | ||||
COMMAND_SET(heap, "heap", "show heap usage", command_heap); | COMMAND_SET(heap, "heap", "show heap usage", command_heap); | ||||
static int | static int | ||||
command_heap(int argc, char *argv[]) | command_heap(int argc, char *argv[]) | ||||
{ | { | ||||
printf("heap base at %p, top at %p, used %td\n", end, sbrk(0), | printf("heap base at %p, top at %p, used %td\n", end, sbrk(0), | ||||
sbrk(0) - end); | sbrk(0) - end); | ||||
return (CMD_OK); | return (CMD_OK); | ||||
} | } | ||||
COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); | COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); | ||||
static int | static int | ||||
command_reboot(int argc, char *argv[]) | command_reboot(int argc, char *argv[]) | ||||
{ | { | ||||
printf("Resetting...\n"); | printf("Resetting...\n"); | ||||
ub_reset(); | ub_reset(); | ||||
printf("Reset failed!\n"); | printf("Reset failed!\n"); | ||||
while(1); | while(1); | ||||
} | } | ||||
COMMAND_SET(devinfo, "devinfo", "show U-Boot devices", command_devinfo); | COMMAND_SET(devinfo, "devinfo", "show U-Boot devices", command_devinfo); | ||||
static int | static int | ||||
command_devinfo(int argc, char *argv[]) | command_devinfo(int argc, char *argv[]) | ||||
{ | { | ||||
int i; | struct device_info *di; | ||||
int i = 0; | |||||
if ((devs_no = ub_dev_enum()) == 0) { | if (ub_dev_enum() == 0) { | ||||
command_errmsg = "no U-Boot devices found!?"; | command_errmsg = "no U-Boot devices found!?"; | ||||
return (CMD_ERROR); | return (CMD_ERROR); | ||||
} | } | ||||
printf("U-Boot devices:\n"); | printf("U-Boot devices:\n"); | ||||
for (i = 0; i < devs_no; i++) { | while ((di = ub_dev_get(DEV_TYP_NET | DEV_TYP_STOR, &i)) != NULL) { | ||||
ub_dump_di(i); | printf("device info (%d):\n", i - 1); | ||||
ub_dump_di(di); | |||||
printf("\n"); | printf("\n"); | ||||
} | } | ||||
return (CMD_OK); | return (CMD_OK); | ||||
} | } | ||||
COMMAND_SET(sysinfo, "sysinfo", "show U-Boot system info", command_sysinfo); | COMMAND_SET(sysinfo, "sysinfo", "show U-Boot system info", command_sysinfo); | ||||
static int | static int | ||||
command_sysinfo(int argc, char *argv[]) | command_sysinfo(int argc, char *argv[]) | ||||
{ | { | ||||
struct sys_info *si; | struct sys_info *si; | ||||
if ((si = ub_get_sys_info()) == NULL) { | if ((si = ub_get_sys_info()) == NULL) { | ||||
command_errmsg = "could not retrieve U-Boot sys info!?"; | command_errmsg = "could not retrieve U-Boot sys info!?"; | ||||
return (CMD_ERROR); | return (CMD_ERROR); | ||||
} | } | ||||
printf("U-Boot system info:\n"); | printf("U-Boot system info:\n"); | ||||
ub_dump_si(si); | ub_dump_si(si); | ||||
return (CMD_OK); | return (CMD_OK); | ||||
} | } | ||||
enum ubenv_action { | enum ubenv_action { | ||||
UBENV_UNKNOWN, | UBENV_UNKNOWN, | ||||
UBENV_SHOW, | UBENV_SHOW, | ||||
Show All 24 Lines | if (var[len] == 0) { | ||||
strncat(ldvar, var, sizeof(ldvar) - 7); | strncat(ldvar, var, sizeof(ldvar) - 7); | ||||
} else { | } else { | ||||
len = MIN(len, sizeof(ldvar) - 1); | len = MIN(len, sizeof(ldvar) - 1); | ||||
strncpy(ldvar, var, len); | strncpy(ldvar, var, len); | ||||
ldvar[len] = 0; | ldvar[len] = 0; | ||||
var = &var[len + 1]; | var = &var[len + 1]; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* If the user prepended "uboot." (which is how they usually see these | * If the user prepended "uboot." (which is how they usually see these | ||||
* names) strip it off as a convenience. | * names) strip it off as a convenience. | ||||
*/ | */ | ||||
if (strncmp(var, "uboot.", 6) == 0) { | if (strncmp(var, "uboot.", 6) == 0) { | ||||
var = &var[6]; | var = &var[6]; | ||||
} | } | ||||
/* If there is no variable name left, punt. */ | /* If there is no variable name left, punt. */ | ||||
if (var[0] == 0) { | if (var[0] == 0) { | ||||
printf("empty variable name\n"); | printf("empty variable name\n"); | ||||
return; | return; | ||||
} | } | ||||
val = ub_env_get(var); | val = ub_env_get(var); | ||||
if (action == UBENV_SHOW) { | if (action == UBENV_SHOW) { | ||||
if (val == NULL) | if (val == NULL) | ||||
printf("uboot.%s is not set\n", var); | printf("uboot.%s is not set\n", var); | ||||
else | else | ||||
printf("uboot.%s=%s\n", var, val); | printf("uboot.%s=%s\n", var, val); | ||||
} else if (action == UBENV_IMPORT) { | } else if (action == UBENV_IMPORT) { | ||||
if (val != NULL) { | if (val != NULL) { | ||||
Show All 15 Lines | if (strcasecmp(argv[1], "import") == 0) | ||||
action = UBENV_IMPORT; | action = UBENV_IMPORT; | ||||
else if (strcasecmp(argv[1], "show") == 0) | else if (strcasecmp(argv[1], "show") == 0) | ||||
action = UBENV_SHOW; | action = UBENV_SHOW; | ||||
} | } | ||||
if (action == UBENV_UNKNOWN) { | if (action == UBENV_UNKNOWN) { | ||||
command_errmsg = "usage: 'ubenv <import|show> [var ...]"; | command_errmsg = "usage: 'ubenv <import|show> [var ...]"; | ||||
return (CMD_ERROR); | return (CMD_ERROR); | ||||
} | } | ||||
if (argc > 2) { | if (argc > 2) { | ||||
for (i = 2; i < argc; i++) | for (i = 2; i < argc; i++) | ||||
handle_uboot_env_var(action, argv[i]); | handle_uboot_env_var(action, argv[i]); | ||||
} else { | } else { | ||||
var = NULL; | var = NULL; | ||||
for (;;) { | for (;;) { | ||||
if ((var = ub_env_enum(var)) == NULL) | if ((var = ub_env_enum(var)) == NULL) | ||||
break; | break; | ||||
handle_uboot_env_var(action, var); | handle_uboot_env_var(action, var); | ||||
} | } | ||||
} | } | ||||
return (CMD_OK); | return (CMD_OK); | ||||
} | } | ||||
COMMAND_SET(ubenv, "ubenv", "show or import U-Boot env vars", command_ubenv); | COMMAND_SET(ubenv, "ubenv", "show or import U-Boot env vars", command_ubenv); | ||||
#ifdef LOADER_FDT_SUPPORT | #ifdef LOADER_FDT_SUPPORT | ||||
/* | /* | ||||
* Since proper fdt command handling function is defined in fdt_loader_cmd.c, | * Since proper fdt command handling function is defined in fdt_loader_cmd.c, | ||||
* and declaring it as extern is in contradiction with COMMAND_SET() macro | * and declaring it as extern is in contradiction with COMMAND_SET() macro | ||||
* (which uses static pointer), we're defining wrapper function, which | * (which uses static pointer), we're defining wrapper function, which | ||||
* calls the proper fdt handling routine. | * calls the proper fdt handling routine. | ||||
*/ | */ | ||||
static int | static int | ||||
command_fdt(int argc, char *argv[]) | command_fdt(int argc, char *argv[]) | ||||
{ | { | ||||
return (command_fdt_internal(argc, argv)); | return (command_fdt_internal(argc, argv)); | ||||
} | } | ||||
COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); | COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); | ||||
#endif | |||||
#ifdef LOADER_ZFS_SUPPORT | |||||
COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", | |||||
command_lszfs); | |||||
static int | |||||
command_lszfs(int argc, char *argv[]) | |||||
{ | |||||
int err; | |||||
if (argc != 2) { | |||||
command_errmsg = "wrong number of arguments"; | |||||
return (CMD_ERROR); | |||||
} | |||||
err = zfs_list(argv[1]); | |||||
if (err != 0) { | |||||
command_errmsg = strerror(err); | |||||
return (CMD_ERROR); | |||||
} | |||||
return (CMD_OK); | |||||
} | |||||
COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments", | |||||
command_reloadbe); | |||||
static int | |||||
command_reloadbe(int argc, char *argv[]) | |||||
{ | |||||
int err; | |||||
char *root; | |||||
if (argc > 2) { | |||||
command_errmsg = "wrong number of arguments"; | |||||
return (CMD_ERROR); | |||||
} | |||||
if (argc == 2) { | |||||
err = zfs_bootenv(argv[1]); | |||||
} else { | |||||
root = getenv("zfs_be_root"); | |||||
if (root == NULL) { | |||||
return (CMD_OK); | |||||
} | |||||
err = zfs_bootenv(root); | |||||
} | |||||
if (err != 0) { | |||||
command_errmsg = strerror(err); | |||||
return (CMD_ERROR); | |||||
} | |||||
return (CMD_OK); | |||||
} | |||||
#endif | #endif |