Index: head/sys/boot/uboot/common/main.c =================================================================== --- head/sys/boot/uboot/common/main.c (revision 263051) +++ head/sys/boot/uboot/common/main.c (revision 263052) @@ -1,358 +1,556 @@ /*- * Copyright (c) 2000 Benno Rice * Copyright (c) 2000 Stephane Potvin * Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include "api_public.h" #include "bootstrap.h" #include "glue.h" #include "libuboot.h" +#ifndef nitems +#define nitems(x) (sizeof((x)) / sizeof((x)[0])) +#endif + struct uboot_devdesc currdev; struct arch_switch archsw; /* MI/MD interface boundary */ int devs_no; +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 bootprog_name[]; extern char bootprog_rev[]; extern char bootprog_date[]; extern char bootprog_maker[]; extern unsigned char _etext[]; extern unsigned char _edata[]; extern unsigned char __bss_start[]; extern unsigned char __sbss_start[]; extern unsigned char __sbss_end[]; extern unsigned char _end[]; #ifdef LOADER_FDT_SUPPORT extern int command_fdt_internal(int argc, char *argv[]); #endif static void dump_sig(struct api_signature *sig) { #ifdef DEBUG 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); #endif } static void dump_addr_info(void) { #ifdef DEBUG 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(" __sbss_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); #endif } static uint64_t memsize(struct sys_info *si, int flags) { uint64_t size; int i; size = 0; for (i = 0; i < si->mr_no; i++) if (si->mr[i].flags == flags && si->mr[i].size) size += (si->mr[i].size); return (size); } static void meminfo(void) { uint64_t size; struct sys_info *si; int t[3] = { MR_ATTR_DRAM, MR_ATTR_FLASH, MR_ATTR_SRAM }; int i; if ((si = ub_get_sys_info()) == NULL) panic("could not retrieve system info"); for (i = 0; i < 3; i++) { size = memsize(si, t[i]); if (size > 0) printf("%s:\t %lldMB\n", ub_mem_type(t[i]), size / 1024 / 1024); } } +static const char * +get_device_type(const char *devstr, int *devtype) +{ + int i; + int namelen; + struct device_type *dt; + + if (devstr) { + for (i = 0; i < nitems(device_types); i++) { + dt = &device_types[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); +} + +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 (""); +} + +/* + * Parse a device string into type, unit, slice and partition numbers. A + * 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 + * disk_open(). + * + * Valid device strings: For device types: + * + * DEV_TYP_STOR, DEV_TYP_NET + * DEV_TYP_STOR, DEV_TYP_NET + * : DEV_TYP_STOR, DEV_TYP_NET + * : DEV_TYP_STOR + * :. DEV_TYP_STOR + * :. DEV_TYP_STOR + * + * For valid type names, see the device_types array, above. + * + * Slice numbers are 1-based. 0 is a wildcard. + */ +static void +get_load_device(int *type, int *unit, int *slice, int *partition) +{ + char *devstr; + const char *p; + char *endp; + + devstr = ub_env_get("loaderdev"); + if (devstr == NULL) + devstr = ""; + else + printf("U-Boot setting: loaderdev=%s\n", devstr); + + p = get_device_type(devstr, type); + + *unit = -1; + *slice = 0; + *partition = -1; + + /* + * Empty device string, or unknown device name, or a bare, known + * device name. + */ + if ((*type == -1) || (*p == '\0')) { + return; + } + + /* Malformed unit number. */ + if (!isdigit(*p)) { + *type = -1; + return; + } + + /* Guaranteed to extract a number from the string, as *p is a digit. */ + *unit = strtol(p, &endp, 10); + p = endp; + + /* Known device name with unit number and nothing else. */ + if (*p == '\0') { + return; + } + + /* Device string is malformed beyond unit number. */ + if (*p != ':') { + *type = -1; + *unit = -1; + return; + } + + p++; + + /* No slice and partition specification. */ + if ('\0' == *p ) + return; + + /* Only DEV_TYP_STOR devices can have a slice specification. */ + if (!(*type & DEV_TYP_STOR)) { + *type = -1; + *unit = -1; + return; + } + + *slice = strtoul(p, &endp, 10); + + /* Malformed slice number. */ + if (p == endp) { + *type = -1; + *unit = -1; + *slice = 0; + return; + } + + p = endp; + + /* No partition specification. */ + if (*p == '\0') + return; + + /* Device string is malformed beyond slice number. */ + if (*p != '.') { + *type = -1; + *unit = -1; + *slice = 0; + return; + } + + p++; + + /* No partition specification. */ + if (*p == '\0') + return; + + *partition = strtol(p, &endp, 10); + p = endp; + + /* Full, valid device string. */ + if (*endp == '\0') + return; + + /* Junk beyond partition number. */ + *type = -1; + *unit = -1; + *slice = 0; + *partition = -1; +} + +static int +probe_disks(int load_type, int load_unit, int load_slice, int load_partition) +{ + int i, open_result, unit; + struct open_file f; + + currdev.d_disk.slice = load_slice; + currdev.d_disk.partition = load_partition; + + f.f_devdata = &currdev; + open_result = -1; + + if (load_type == -1) { + printf("Probing all storage devices...\n"); + /* Try each disk in succession until one works. */ + for (currdev.d_unit = 0; currdev.d_unit < UB_MAX_DEV; + currdev.d_unit++) { + printf("Checking unit=%d slice=%d partition=%d...", + currdev.d_unit, currdev.d_disk.slice, + currdev.d_disk.partition); + open_result = devsw[i]->dv_open(&f, &currdev); + if (open_result == 0) { + printf(" good.\n"); + return (0); + } + printf("\n"); + } + return (-1); + } + + if (load_unit == -1) { + printf("Probing all %s devices...\n", device_typename(load_type)); + /* Try each disk of given type in succession until one works. */ + for (unit = 0; unit < UB_MAX_DEV; unit++) { + currdev.d_unit = uboot_diskgetunit(load_type, unit); + if (currdev.d_unit == -1) + break; + printf("Checking unit=%d slice=%d partition=%d...", + currdev.d_unit, currdev.d_disk.slice, + currdev.d_disk.partition); + open_result = devsw[i]->dv_open(&f, &currdev); + if (open_result == 0) { + printf(" good.\n"); + return (0); + } + printf("\n"); + } + return (-1); + } + + if ((currdev.d_unit = uboot_diskgetunit(load_type, load_unit)) != -1) { + printf("Checking unit=%d slice=%d partition=%d...", + currdev.d_unit, currdev.d_disk.slice, + currdev.d_disk.partition); + open_result = devsw[i]->dv_open(&f,&currdev); + if (open_result == 0) { + printf("good.\n"); + return (0); + } + printf("\n"); + } + + printf("Requested disk type/unit not found\n"); + return (-1); +} + int main(void) { struct api_signature *sig = NULL; - int diskdev, i, netdev, usedev; - struct open_file f; + int load_type, load_unit, load_slice, load_partition; + int i; const char * loaderdev; /* * If we can't find the magic signature and related info, exit with a * unique error code that U-Boot reports as "## Application terminated, * rc = 0xnnbadab1". Hopefully 'badab1' looks enough like "bad api" to * provide a clue. It's better than 0xffffffff anyway. */ if (!api_search_sig(&sig)) return (0x01badab1); syscall_ptr = sig->syscall; if (syscall_ptr == NULL) return (0x02badab1); if (sig->version > API_SIG_VERSION) return (0x03badab1); /* Clear BSS sections */ bzero(__sbss_start, __sbss_end - __sbss_start); bzero(__bss_start, _end - __bss_start); /* * Set up console. */ cons_probe(); printf("Compatible API signature found @%x\n", (uint32_t)sig); dump_sig(sig); dump_addr_info(); /* * Initialise the heap as early as possible. Once this is done, * alloc() is usable. The stack is buried inside us, so this is * safe. */ setheap((void *)end, (void *)(end + 512 * 1024)); /* * Enumerate U-Boot devices */ if ((devs_no = ub_dev_enum()) == 0) panic("no U-Boot devices found"); printf("Number of U-Boot devices: %d\n", devs_no); printf("\n"); printf("%s, Revision %s\n", bootprog_name, bootprog_rev); printf("(%s, %s)\n", bootprog_maker, bootprog_date); meminfo(); + get_load_device(&load_type, &load_unit, &load_slice, &load_partition); + /* - * March through the device switch probing for things -- sort of. - * - * The devsw array will have one or two items in it. If - * LOADER_DISK_SUPPORT is defined the first item will be a disk (which - * may not actually work if u-boot didn't supply one). If - * LOADER_NET_SUPPORT is defined the next item will be a network - * interface. Again it may not actually work at the u-boot level. - * - * The original logic was to always use a disk if it could be - * successfully opened, otherwise use the network interface. Now that - * logic is amended to first check whether the u-boot environment - * contains a loaderdev variable which tells us which device to use. If - * it does, we use it and skip the original (second) loop which "probes" - * for a device. We still loop over the devsw just in case it ever gets - * expanded to hold more than 2 devices (but then unit numbers, which - * don't currently exist, may come into play). If the device named by - * loaderdev isn't found, fall back using to the old "probe" loop. - * - * The original probe loop still effectively behaves as it always has: - * the first usable disk device is choosen, and a network device is used - * only if no disk device is found. The logic has been reworked so that - * it examines (and thus lists) every potential device along the way - * instead of breaking out of the loop when the first device is found. + * March through the device switch probing for things. */ - loaderdev = ub_env_get("loaderdev"); - usedev = -1; - if (loaderdev != NULL) { - for (i = 0; devsw[i] != NULL; i++) { - if (strcmp(loaderdev, devsw[i]->dv_name) == 0) { - if (devsw[i]->dv_init == NULL) - continue; - if ((devsw[i]->dv_init)() != 0) - continue; - usedev = i; - goto have_device; - } - } - printf("U-Boot env contains 'loaderdev=%s', " - "device not found.\n", loaderdev); - } - printf("Probing for bootable devices...\n"); - diskdev = -1; - netdev = -1; for (i = 0; devsw[i] != NULL; i++) { if (devsw[i]->dv_init == NULL) continue; if ((devsw[i]->dv_init)() != 0) continue; - printf("Bootable device: %s\n", devsw[i]->dv_name); + printf("Found U-Boot device: %s\n", devsw[i]->dv_name); - if (strncmp(devsw[i]->dv_name, "disk", - strlen(devsw[i]->dv_name)) == 0) { - f.f_devdata = &currdev; - currdev.d_dev = devsw[i]; - currdev.d_type = currdev.d_dev->dv_type; - currdev.d_unit = 0; - currdev.d_disk.slice = 0; - if (devsw[i]->dv_open(&f, &currdev) == 0) { - devsw[i]->dv_close(&f); - if (diskdev == -1) - diskdev = i; - } - } else if (strncmp(devsw[i]->dv_name, "net", - strlen(devsw[i]->dv_name)) == 0) { - if (netdev == -1) - netdev = i; + 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(load_type, load_unit, load_slice, + load_partition) == 0) + break; } + + if (load_type == -1 || ((load_type & DEV_TYP_NET) && + strcmp(devsw[i]->dv_name, "net") == 0)) + break; } - if (diskdev != -1) - usedev = diskdev; - else if (netdev != -1) - usedev = netdev; - else - panic("No bootable devices found!\n"); - -have_device: - - currdev.d_dev = devsw[usedev]; - currdev.d_type = devsw[usedev]->dv_type; - currdev.d_unit = 0; - if (currdev.d_type == DEV_TYP_STOR) - currdev.d_disk.slice = 0; - - printf("Current device: %s\n", currdev.d_dev->dv_name); + /* + * 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 + * so returning an error is better than forcing a reboot. + */ + if (devsw[i] == NULL) { + printf("No boot device found!\n"); + return (0xbadef1ce); + } env_setenv("currdev", EV_VOLATILE, uboot_fmtdev(&currdev), uboot_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, uboot_fmtdev(&currdev), env_noset, env_nounset); setenv("LINES", "24", 1); /* optional */ setenv("prompt", "loader>", 1); 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(); /* doesn't return */ return (0); } COMMAND_SET(heap, "heap", "show heap usage", command_heap); static int command_heap(int argc, char *argv[]) { printf("heap base at %p, top at %p, used %d\n", end, sbrk(0), sbrk(0) - end); return (CMD_OK); } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { printf("Resetting...\n"); ub_reset(); printf("Reset failed!\n"); while(1); } COMMAND_SET(devinfo, "devinfo", "show U-Boot devices", command_devinfo); static int command_devinfo(int argc, char *argv[]) { int i; if ((devs_no = ub_dev_enum()) == 0) { command_errmsg = "no U-Boot devices found!?"; return (CMD_ERROR); } printf("U-Boot devices:\n"); for (i = 0; i < devs_no; i++) { ub_dump_di(i); printf("\n"); } return (CMD_OK); } COMMAND_SET(sysinfo, "sysinfo", "show U-Boot system info", command_sysinfo); static int command_sysinfo(int argc, char *argv[]) { struct sys_info *si; if ((si = ub_get_sys_info()) == NULL) { command_errmsg = "could not retrieve U-Boot sys info!?"; return (CMD_ERROR); } printf("U-Boot system info:\n"); ub_dump_si(si); return (CMD_OK); } #ifdef LOADER_FDT_SUPPORT /* * 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 * (which uses static pointer), we're defining wrapper function, which * calls the proper fdt handling routine. */ static int command_fdt(int argc, char *argv[]) { return (command_fdt_internal(argc, argv)); } COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); #endif Index: head/sys/boot/uboot/lib/api_public.h =================================================================== --- head/sys/boot/uboot/lib/api_public.h (revision 263051) +++ head/sys/boot/uboot/lib/api_public.h (revision 263052) @@ -1,160 +1,160 @@ /* * (C) Copyright 2007-2008 Semihalf * * Written by: Rafal Jaworowski * * This file is dual licensed; you can use it under the terms of * either the GPL, or the BSD license, at your option. * * I. GPL: * * This file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Alternatively, * * II. BSD license: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ * * This file needs to be kept in sync with U-Boot reference: * http://www.denx.de/cgi-bin/gitweb.cgi?p=u-boot.git;a=blob;f=include/api_public.h */ #ifndef _API_PUBLIC_H_ #define _API_PUBLIC_H_ #define API_EINVAL 1 /* invalid argument(s) */ #define API_ENODEV 2 /* no device */ #define API_ENOMEM 3 /* no memory */ #define API_EBUSY 4 /* busy, occupied etc. */ #define API_EIO 5 /* I/O error */ #define API_ESYSC 6 /* syscall error */ typedef int (*scp_t)(int, int *, ...); #define API_SIG_VERSION 1 #define API_SIG_MAGIC "UBootAPI" #define API_SIG_MAGLEN 8 struct api_signature { char magic[API_SIG_MAGLEN]; /* magic string */ uint16_t version; /* API version */ uint32_t checksum; /* checksum of this sig struct */ scp_t syscall; /* entry point to the API */ }; enum { API_RSVD = 0, API_GETC, API_PUTC, API_TSTC, API_PUTS, API_RESET, API_GET_SYS_INFO, API_UDELAY, API_GET_TIMER, API_DEV_ENUM, API_DEV_OPEN, API_DEV_CLOSE, API_DEV_READ, API_DEV_WRITE, API_ENV_ENUM, API_ENV_GET, API_ENV_SET, API_MAXCALL }; #define MR_ATTR_FLASH 0x0001 #define MR_ATTR_DRAM 0x0002 #define MR_ATTR_SRAM 0x0003 struct mem_region { unsigned long start; unsigned long size; int flags; }; struct sys_info { unsigned long clk_bus; unsigned long clk_cpu; unsigned long bar; struct mem_region *mr; int mr_no; /* number of memory regions */ }; #undef CFG_64BIT_LBA #ifdef CFG_64BIT_LBA typedef uint64_t lbasize_t; #else typedef unsigned long lbasize_t; #endif typedef unsigned long lbastart_t; #define DEV_TYP_NONE 0x0000 #define DEV_TYP_NET 0x0001 #define DEV_TYP_STOR 0x0002 #define DT_STOR_IDE 0x0010 #define DT_STOR_SCSI 0x0020 #define DT_STOR_USB 0x0040 #define DT_STOR_MMC 0x0080 -#define DT_STOR_NAND 0x0100 +#define DT_STOR_SATA 0x0100 #define DEV_STA_CLOSED 0x0000 /* invalid, closed */ #define DEV_STA_OPEN 0x0001 /* open i.e. active */ struct device_info { int type; void *cookie; union { struct { lbasize_t block_count; /* no of blocks */ unsigned long block_size; /* size of one block */ } storage; struct { unsigned char hwaddr[6]; } net; } info; #define di_stor info.storage #define di_net info.net int state; }; #endif /* _API_PUBLIC_H_ */ Index: head/sys/boot/uboot/lib/disk.c =================================================================== --- head/sys/boot/uboot/lib/disk.c (revision 263051) +++ head/sys/boot/uboot/lib/disk.c (revision 263052) @@ -1,280 +1,303 @@ /*- * Copyright (c) 2008 Semihalf, Rafal Jaworowski * Copyright (c) 2009 Semihalf, Piotr Ziecik * Copyright (c) 2012 Andrey V. Elsukov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* * Block storage I/O routines for U-Boot */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include "api_public.h" #include "bootstrap.h" #include "disk.h" #include "glue.h" #include "libuboot.h" #define stor_printf(fmt, args...) do { \ printf("%s%d: ", dev->d_dev->dv_name, dev->d_unit); \ printf(fmt, ##args); \ } while (0) #ifdef DEBUG #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ printf(fmt,##args); } while (0) #else #define debugf(fmt, args...) #endif static struct { int opened; /* device is opened */ int handle; /* storage device handle */ int type; /* storage type */ off_t blocks; /* block count */ u_int bsize; /* block size */ } stor_info[UB_MAX_DEV]; #define SI(dev) (stor_info[(dev)->d_unit]) static int stor_info_no = 0; static int stor_opendev(struct disk_devdesc *); static int stor_readdev(struct disk_devdesc *, daddr_t, size_t, char *); /* devsw I/F */ static int stor_init(void); static int stor_strategy(void *, int, daddr_t, size_t, char *, size_t *); static int stor_open(struct open_file *, ...); static int stor_close(struct open_file *); static int stor_ioctl(struct open_file *f, u_long cmd, void *data); static void stor_print(int); static void stor_cleanup(void); struct devsw uboot_storage = { "disk", DEVT_DISK, stor_init, stor_strategy, stor_open, stor_close, stor_ioctl, stor_print, stor_cleanup }; static int stor_init(void) { struct device_info *di; int i; if (devs_no == 0) { printf("No U-Boot devices! Really enumerated?\n"); return (-1); } for (i = 0; i < devs_no; i++) { di = ub_dev_get(i); if ((di != NULL) && (di->type & DEV_TYP_STOR)) { if (stor_info_no >= UB_MAX_DEV) { printf("Too many storage devices: %d\n", stor_info_no); return (-1); } stor_info[stor_info_no].handle = i; stor_info[stor_info_no].opened = 0; stor_info[stor_info_no].type = di->type; stor_info[stor_info_no].blocks = di->di_stor.block_count; stor_info[stor_info_no].bsize = di->di_stor.block_size; stor_info_no++; } } if (!stor_info_no) { debugf("No storage devices\n"); return (-1); } debugf("storage devices found: %d\n", stor_info_no); return (0); } static void stor_cleanup(void) { int i; for (i = 0; i < stor_info_no; i++) if (stor_info[i].opened > 0) ub_dev_close(stor_info[i].handle); disk_cleanup(&uboot_storage); } static int stor_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, size_t *rsize) { struct disk_devdesc *dev = (struct disk_devdesc *)devdata; daddr_t bcount; int err; if (rw != F_READ) { stor_printf("write attempt, operation not supported!\n"); return (EROFS); } if (size % SI(dev).bsize) { stor_printf("size=%d not multiple of device block size=%d\n", size, SI(dev).bsize); return (EIO); } bcount = size / SI(dev).bsize; if (rsize) *rsize = 0; err = stor_readdev(dev, blk + dev->d_offset, bcount, buf); if (!err && rsize) *rsize = size; return (err); } static int stor_open(struct open_file *f, ...) { va_list ap; struct disk_devdesc *dev; va_start(ap, f); dev = va_arg(ap, struct disk_devdesc *); va_end(ap); return (stor_opendev(dev)); } static int stor_opendev(struct disk_devdesc *dev) { int err; if (dev->d_unit < 0 || dev->d_unit >= stor_info_no) return (EIO); if (SI(dev).opened == 0) { err = ub_dev_open(SI(dev).handle); if (err != 0) { stor_printf("device open failed with error=%d, " "handle=%d\n", err, SI(dev).handle); return (ENXIO); } SI(dev).opened++; } return (disk_open(dev, SI(dev).blocks * SI(dev).bsize, SI(dev).bsize, 0)); } static int stor_close(struct open_file *f) { struct disk_devdesc *dev; dev = (struct disk_devdesc *)(f->f_devdata); return (disk_close(dev)); } static int stor_readdev(struct disk_devdesc *dev, daddr_t blk, size_t size, char *buf) { lbasize_t real_size; int err; debugf("reading blk=%d size=%d @ 0x%08x\n", (int)blk, size, (uint32_t)buf); err = ub_dev_read(SI(dev).handle, buf, size, blk, &real_size); if (err != 0) { stor_printf("read failed, error=%d\n", err); return (EIO); } if (real_size != size) { stor_printf("real size != size\n"); err = EIO; } return (err); } static void stor_print(int verbose) { struct disk_devdesc dev; static char line[80]; int i; for (i = 0; i < stor_info_no; i++) { dev.d_dev = &uboot_storage; dev.d_unit = i; dev.d_slice = -1; dev.d_partition = -1; sprintf(line, "\tdisk%d (%s)\n", i, ub_stor_type(SI(&dev).type)); pager_output(line); if (stor_opendev(&dev) == 0) { sprintf(line, "\tdisk%d", i); disk_print(&dev, line, verbose); disk_close(&dev); } } } static int stor_ioctl(struct open_file *f, u_long cmd, void *data) { struct disk_devdesc *dev; dev = (struct disk_devdesc *)f->f_devdata; switch (cmd) { case DIOCGSECTORSIZE: *(u_int *)data = SI(dev).bsize; break; case DIOCGMEDIASIZE: *(off_t *)data = SI(dev).bsize * SI(dev).blocks; break; default: return (ENOTTY); } return (0); } + +/* + * Return the device unit number for the given type and type-relative unit + * number. + */ +int +uboot_diskgetunit(int type, int type_unit) +{ + int local_type_unit; + int i; + + local_type_unit = 0; + for (i = 0; i < stor_info_no; i++) { + if ((stor_info[i].type & type) == type) { + if (local_type_unit == type_unit) { + return (i); + } + local_type_unit++; + } + } + + return (-1); +} Index: head/sys/boot/uboot/lib/glue.c =================================================================== --- head/sys/boot/uboot/lib/glue.c (revision 263051) +++ head/sys/boot/uboot/lib/glue.c (revision 263052) @@ -1,528 +1,528 @@ /*- * Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include "api_public.h" #include "glue.h" #ifdef DEBUG #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0) #else #define debugf(fmt, args...) #endif /* Some random address used by U-Boot. */ extern long uboot_address; static int valid_sig(struct api_signature *sig) { uint32_t checksum; struct api_signature s; if (sig == NULL) return (0); /* * Clear the checksum field (in the local copy) so as to calculate the * CRC with the same initial contents as at the time when the sig was * produced */ s = *sig; s.checksum = 0; checksum = crc32((void *)&s, sizeof(struct api_signature)); if (checksum != sig->checksum) return (0); return (1); } /* * Searches for the U-Boot API signature * * returns 1/0 depending on found/not found result */ int api_search_sig(struct api_signature **sig) { unsigned char *sp, *spend; if (sig == NULL) return (0); if (uboot_address == 0) uboot_address = 255 * 1024 * 1024; sp = (void *)(uboot_address & ~0x000fffff); spend = sp + 0x00300000 - API_SIG_MAGLEN; while (sp < spend) { if (!bcmp(sp, API_SIG_MAGIC, API_SIG_MAGLEN)) { *sig = (struct api_signature *)sp; if (valid_sig(*sig)) return (1); } sp += API_SIG_MAGLEN; } *sig = NULL; return (0); } /**************************************** * * console * ****************************************/ int ub_getc(void) { int c; if (!syscall(API_GETC, NULL, (uint32_t)&c)) return (-1); return (c); } int ub_tstc(void) { int t; if (!syscall(API_TSTC, NULL, (uint32_t)&t)) return (-1); return (t); } void ub_putc(char c) { syscall(API_PUTC, NULL, (uint32_t)&c); } void ub_puts(const char *s) { syscall(API_PUTS, NULL, (uint32_t)s); } /**************************************** * * system * ****************************************/ void ub_reset(void) { syscall(API_RESET, NULL); } static struct mem_region mr[UB_MAX_MR]; static struct sys_info si; struct sys_info * ub_get_sys_info(void) { int err = 0; memset(&si, 0, sizeof(struct sys_info)); si.mr = mr; si.mr_no = UB_MAX_MR; memset(&mr, 0, sizeof(mr)); if (!syscall(API_GET_SYS_INFO, &err, (u_int32_t)&si)) return (NULL); return ((err) ? NULL : &si); } /**************************************** * * timing * ****************************************/ void ub_udelay(unsigned long usec) { syscall(API_UDELAY, NULL, &usec); } unsigned long ub_get_timer(unsigned long base) { unsigned long cur; if (!syscall(API_GET_TIMER, NULL, &cur, &base)) return (0); return (cur); } /**************************************************************************** * * devices * * Devices are identified by handles: numbers 0, 1, 2, ..., UB_MAX_DEV-1 * ***************************************************************************/ static struct device_info devices[UB_MAX_DEV]; struct device_info * ub_dev_get(int i) { return ((i < 0 || i >= UB_MAX_DEV) ? NULL : &devices[i]); } /* * Enumerates the devices: fills out device_info elements in the devices[] * array. * * returns: number of devices found */ int ub_dev_enum(void) { struct device_info *di; int n = 0; memset(&devices, 0, sizeof(struct device_info) * UB_MAX_DEV); di = &devices[0]; if (!syscall(API_DEV_ENUM, NULL, di)) return (0); while (di->cookie != NULL) { if (++n >= UB_MAX_DEV) break; /* take another device_info */ di++; /* pass on the previous cookie */ di->cookie = devices[n - 1].cookie; if (!syscall(API_DEV_ENUM, NULL, di)) return (0); } return (n); } /* * handle: 0-based id of the device * * returns: 0 when OK, err otherwise */ int ub_dev_open(int handle) { struct device_info *di; int err = 0; if (handle < 0 || handle >= UB_MAX_DEV) return (API_EINVAL); di = &devices[handle]; if (!syscall(API_DEV_OPEN, &err, di)) return (-1); return (err); } int ub_dev_close(int handle) { struct device_info *di; if (handle < 0 || handle >= UB_MAX_DEV) return (API_EINVAL); di = &devices[handle]; if (!syscall(API_DEV_CLOSE, NULL, di)) return (-1); return (0); } /* * Validates device for read/write, it has to: * * - have sane handle * - be opened * * returns: 0/1 accordingly */ static int dev_valid(int handle) { if (handle < 0 || handle >= UB_MAX_DEV) return (0); if (devices[handle].state != DEV_STA_OPEN) return (0); return (1); } static int dev_stor_valid(int handle) { if (!dev_valid(handle)) return (0); if (!(devices[handle].type & DEV_TYP_STOR)) return (0); return (1); } int ub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start, lbasize_t *rlen) { struct device_info *di; lbasize_t act_len; int err = 0; if (!dev_stor_valid(handle)) return (API_ENODEV); di = &devices[handle]; if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len)) return (API_ESYSC); if (!err && rlen) *rlen = act_len; return (err); } static int dev_net_valid(int handle) { if (!dev_valid(handle)) return (0); if (devices[handle].type != DEV_TYP_NET) return (0); return (1); } int ub_dev_recv(int handle, void *buf, int len, int *rlen) { struct device_info *di; int err = 0, act_len; if (!dev_net_valid(handle)) return (API_ENODEV); di = &devices[handle]; if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len)) return (API_ESYSC); if (!err) *rlen = act_len; return (err); } int ub_dev_send(int handle, void *buf, int len) { struct device_info *di; int err = 0; if (!dev_net_valid(handle)) return (API_ENODEV); di = &devices[handle]; if (!syscall(API_DEV_WRITE, &err, di, buf, &len)) return (API_ESYSC); return (err); } char * ub_stor_type(int type) { if (type & DT_STOR_IDE) return ("IDE"); if (type & DT_STOR_SCSI) return ("SCSI"); if (type & DT_STOR_USB) return ("USB"); if (type & DT_STOR_MMC) return ("MMC"); - if (type & DT_STOR_NAND) - return ("NAND"); + if (type & DT_STOR_SATA) + return ("SATA"); return ("Unknown"); } char * ub_mem_type(int flags) { switch (flags & 0x000F) { case MR_ATTR_FLASH: return ("FLASH"); case MR_ATTR_DRAM: return ("DRAM"); case MR_ATTR_SRAM: return ("SRAM"); default: return ("Unknown"); } } void ub_dump_di(int handle) { struct device_info *di = ub_dev_get(handle); int i; printf("device info (%d):\n", handle); printf(" cookie\t= 0x%08x\n", (uint32_t)di->cookie); printf(" type\t\t= 0x%08x\n", di->type); if (di->type == DEV_TYP_NET) { printf(" hwaddr\t= "); for (i = 0; i < 6; i++) printf("%02x ", di->di_net.hwaddr[i]); printf("\n"); } else if (di->type & DEV_TYP_STOR) { printf(" type\t\t= %s\n", ub_stor_type(di->type)); printf(" blk size\t\t= %ld\n", di->di_stor.block_size); printf(" blk count\t\t= %ld\n", di->di_stor.block_count); } } void ub_dump_si(struct sys_info *si) { int i; printf("sys info:\n"); printf(" clkbus\t= %ld MHz\n", si->clk_bus / 1000 / 1000); printf(" clkcpu\t= %ld MHz\n", si->clk_cpu / 1000 / 1000); printf(" bar\t\t= 0x%08lx\n", si->bar); printf("---\n"); for (i = 0; i < si->mr_no; i++) { if (si->mr[i].flags == 0) break; printf(" start\t= 0x%08lx\n", si->mr[i].start); printf(" size\t= 0x%08lx\n", si->mr[i].size); printf(" type\t= %s\n", ub_mem_type(si->mr[i].flags)); printf("---\n"); } } /**************************************** * * env vars * ****************************************/ char * ub_env_get(const char *name) { char *value; if (!syscall(API_ENV_GET, NULL, (uint32_t)name, (uint32_t)&value)) return (NULL); return (value); } void ub_env_set(const char *name, char *value) { syscall(API_ENV_SET, NULL, (uint32_t)name, (uint32_t)value); } static char env_name[256]; const char * ub_env_enum(const char *last) { const char *env, *str; int i; /* * It's OK to pass only the name piece as last (and not the whole * 'name=val' string), since the API_ENUM_ENV call uses envmatch() * internally, which handles such case */ env = NULL; if (!syscall(API_ENV_ENUM, NULL, (uint32_t)last, (uint32_t)&env)) return (NULL); if (env == NULL) /* no more env. variables to enumerate */ return (NULL); /* next enumerated env var */ memset(env_name, 0, 256); for (i = 0, str = env; *str != '=' && *str != '\0';) env_name[i++] = *str++; env_name[i] = '\0'; return (env_name); } Index: head/sys/boot/uboot/lib/libuboot.h =================================================================== --- head/sys/boot/uboot/lib/libuboot.h (revision 263051) +++ head/sys/boot/uboot/lib/libuboot.h (revision 263052) @@ -1,77 +1,79 @@ /*- * Copyright (C) 2000 Benno Rice. * Copyright (C) 2007 Semihalf, Rafal Jaworowski * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ struct uboot_devdesc { struct devsw *d_dev; int d_type; int d_unit; + void *d_opendata; union { struct { - void *data; int slice; int partition; off_t offset; } disk; } d_kind; }; #define d_disk d_kind.disk /* * Default network packet alignment in memory */ #define PKTALIGN 32 int uboot_getdev(void **vdev, const char *devspec, const char **path); char *uboot_fmtdev(void *vdev); int uboot_setcurrdev(struct env_var *ev, int flags, const void *value); extern int devs_no; extern struct netif_driver uboot_net; extern struct devsw uboot_storage; void *uboot_vm_translate(vm_offset_t); ssize_t uboot_copyin(const void *src, vm_offset_t dest, const size_t len); ssize_t uboot_copyout(const vm_offset_t src, void *dest, const size_t len); ssize_t uboot_readin(const int fd, vm_offset_t dest, const size_t len); extern int uboot_autoload(void); struct preloaded_file; struct file_format; extern struct file_format uboot_elf; void reboot(void); + +int uboot_diskgetunit(int type, int type_unit); #if defined(LOADER_FDT_SUPPORT) extern int fdt_setup_fdtp(); extern int fdt_copy(vm_offset_t); #endif