diff options
author | marcel <marcel@FreeBSD.org> | 2008-02-16 22:13:11 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2008-02-16 22:13:11 +0000 |
commit | 192282ff7a28f13eb4a1f722ced0248e4423de14 (patch) | |
tree | de0f495aaac581ea556530edfdbc69009d726479 /sys/boot | |
parent | f051ca1feb52908fddd292d0f94338e5c33ddda3 (diff) | |
download | FreeBSD-src-192282ff7a28f13eb4a1f722ced0248e4423de14.zip FreeBSD-src-192282ff7a28f13eb4a1f722ced0248e4423de14.tar.gz |
MFp4 (e500):
Add support for U-Boot. This uses the U-Boot API as developed by
Rafal and which is (will be) part of U-Boot 1.3.2 and later.
Credits to: raj@
Diffstat (limited to 'sys/boot')
-rw-r--r-- | sys/boot/uboot/Makefile | 5 | ||||
-rw-r--r-- | sys/boot/uboot/common/Makefile.inc | 3 | ||||
-rw-r--r-- | sys/boot/uboot/common/main.c | 226 | ||||
-rw-r--r-- | sys/boot/uboot/lib/Makefile | 28 | ||||
-rw-r--r-- | sys/boot/uboot/lib/api_public.h | 104 | ||||
-rw-r--r-- | sys/boot/uboot/lib/console.c | 83 | ||||
-rw-r--r-- | sys/boot/uboot/lib/copy.c | 57 | ||||
-rw-r--r-- | sys/boot/uboot/lib/devicename.c | 237 | ||||
-rw-r--r-- | sys/boot/uboot/lib/disk.c | 103 | ||||
-rw-r--r-- | sys/boot/uboot/lib/elf_freebsd.c | 90 | ||||
-rw-r--r-- | sys/boot/uboot/lib/glue.c | 530 | ||||
-rw-r--r-- | sys/boot/uboot/lib/libuboot.h | 74 | ||||
-rw-r--r-- | sys/boot/uboot/lib/module.c | 46 | ||||
-rw-r--r-- | sys/boot/uboot/lib/net.c | 252 | ||||
-rw-r--r-- | sys/boot/uboot/lib/reboot.c | 34 | ||||
-rw-r--r-- | sys/boot/uboot/lib/time.c | 61 |
16 files changed, 1933 insertions, 0 deletions
diff --git a/sys/boot/uboot/Makefile b/sys/boot/uboot/Makefile new file mode 100644 index 0000000..d60f27e --- /dev/null +++ b/sys/boot/uboot/Makefile @@ -0,0 +1,5 @@ +# $FreeBSD$ + +SUBDIR= lib + +.include <bsd.subdir.mk> diff --git a/sys/boot/uboot/common/Makefile.inc b/sys/boot/uboot/common/Makefile.inc new file mode 100644 index 0000000..5d20372 --- /dev/null +++ b/sys/boot/uboot/common/Makefile.inc @@ -0,0 +1,3 @@ +# $FreeBSD$ + +SRCS+= main.c diff --git a/sys/boot/uboot/common/main.c b/sys/boot/uboot/common/main.c new file mode 100644 index 0000000..2c793e7 --- /dev/null +++ b/sys/boot/uboot/common/main.c @@ -0,0 +1,226 @@ +/*- + * Copyright (c) 2000 Benno Rice <benno@jeamland.net> + * Copyright (c) 2000 Stephane Potvin <sepotvin@videotron.ca> + * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com> + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include "bootstrap.h" + +#include "libuboot.h" +#include "api_public.h" + +struct uboot_devdesc currdev; +struct arch_switch archsw; /* MI/MD interface boundary */ +int devs_no; + +extern char end[]; +extern char bootprog_name[]; +extern char bootprog_rev[]; +extern char bootprog_date[]; +extern char bootprog_maker[]; + +static char bootargs[128]; + +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[]; + +extern void * syscall_ptr; + +struct sys_info * ub_get_sys_info(void); + + +void dump_si(struct sys_info *si) +{ +#ifdef DEBUG + printf("sys info:\n"); + printf(" clkbus\t= 0x%08x\n", si->clk_bus); + printf(" clkcpu\t= 0x%08x\n", si->clk_cpu); + printf(" bar\t\t= 0x%08x\n", si->bar); +#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", (u_int32_t)_etext); + printf(" _edata = 0x%08x\n", (u_int32_t)_edata); + printf(" __sbss_start = 0x%08x\n", (u_int32_t)__sbss_start); + printf(" __sbss_end = 0x%08x\n", (u_int32_t)__sbss_end); + printf(" __sbss_start = 0x%08x\n", (u_int32_t)__bss_start); + printf(" _end = 0x%08x\n", (u_int32_t)_end); + printf(" syscall entry = 0x%08x\n", (u_int32_t)syscall_ptr); +#endif +} + +static uint64_t +memsize(int flags) +{ + int i; + struct sys_info * si; + + if ((si = ub_get_sys_info()) == NULL) + return 0; + + for (i = 0; i < si->mr_no; i++) + if (si->mr[i].flags == flags && si->mr[i].size) + return (si->mr[i].size); + + return 0; +} + +int +main(void) +{ + int i; + char *ch; + int bargc; + char **bargv; + + struct api_signature *sig = NULL; + + if (!api_search_sig(&sig)) + return -1; + + syscall_ptr = sig->syscall; + if (syscall_ptr == NULL) + return -2; + + if (sig->version > API_SIG_VERSION) + return -3; + + /* 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", 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 devices found"); + printf("Number of U-Boot devices found %d\n", devs_no); + + /* XXX all our dv_init()s currently don't do anything... */ + /* + * March through the device switch probing for things. + */ + for (i = 0; devsw[i] != NULL; i++) + if (devsw[i]->dv_init != NULL) + (devsw[i]->dv_init)(); + + printf("\n"); + printf("%s, Revision %s\n", bootprog_name, bootprog_rev); + printf("(%s, %s)\n", bootprog_maker, bootprog_date); + printf("Memory: %lldMB\n", memsize(MR_ATTR_DRAM) / 1024 / 1024); + printf("FLASH: %lldMB\n", memsize(MR_ATTR_FLASH) / 1024 / 1024); +// printf("SRAM: %lldMB\n", memsize(MR_ATTR_SRAM) / 1024 / 1024); + + /* XXX only support netbooting for now */ + for (i = 0; devsw[i] != NULL; i++) + if (strncmp(devsw[i]->dv_name, "net", strlen(devsw[i]->dv_name)) == 0) + break; + + if (devsw[i] == NULL) + panic("no network devices?!"); + + currdev.d_dev = devsw[i]; + currdev.d_type = currdev.d_dev->dv_type; + currdev.d_unit = 0; + + 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 %ld\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); +} diff --git a/sys/boot/uboot/lib/Makefile b/sys/boot/uboot/lib/Makefile new file mode 100644 index 0000000..0a0c484 --- /dev/null +++ b/sys/boot/uboot/lib/Makefile @@ -0,0 +1,28 @@ +# $FreeBSD$ + +LIB= uboot +INTERNALLIB= + +SRCS= devicename.c elf_freebsd.c console.c copy.c disk.c \ + module.c net.c reboot.c time.c glue.c + +CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/ + +# Pick up the bootstrap header for some interface items +CFLAGS+= -I${.CURDIR}/../../common -I${.CURDIR}/../../.. -I. + +CFLAGS+= -ffreestanding + +.ifdef(BOOT_DISK_DEBUG) +# Make the disk code more talkative +CFLAGS+= -DDISK_DEBUG +.endif + +machine: + ln -sf ${.CURDIR}/../../../${MACHINE_ARCH}/include machine + +CLEANFILES+= machine + +.include <bsd.lib.mk> + +beforedepend ${OBJS}: machine diff --git a/sys/boot/uboot/lib/api_public.h b/sys/boot/uboot/lib/api_public.h new file mode 100644 index 0000000..5075763 --- /dev/null +++ b/sys/boot/uboot/lib/api_public.h @@ -0,0 +1,104 @@ +/* $FreeBSD$ */ + +#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 */ + +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 u_int64_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 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_ */ diff --git a/sys/boot/uboot/lib/console.c b/sys/boot/uboot/lib/console.c new file mode 100644 index 0000000..f6e626d --- /dev/null +++ b/sys/boot/uboot/lib/console.c @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com> + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include "bootstrap.h" + +int console; + +static void uboot_cons_probe(struct console *cp); +static int uboot_cons_init(int); +static void uboot_cons_putchar(int); +static int uboot_cons_getchar(void); +static int uboot_cons_poll(void); + +struct console uboot_console = { + "uboot", + "U-Boot console", + 0, + uboot_cons_probe, + uboot_cons_init, + uboot_cons_putchar, + uboot_cons_getchar, + uboot_cons_poll, +}; + +static void +uboot_cons_probe(struct console *cp) +{ + cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT); +} + +static int +uboot_cons_init(int arg) +{ + return 0; +} + +static void +uboot_cons_putchar(int c) +{ + if (c == '\n') + ub_putc('\r'); + + ub_putc(c); +} + +static int +uboot_cons_getchar() +{ + return (ub_getc()); +} + +static int +uboot_cons_poll() +{ + return (ub_tstc()); +} diff --git a/sys/boot/uboot/lib/copy.c b/sys/boot/uboot/lib/copy.c new file mode 100644 index 0000000..88b4f81 --- /dev/null +++ b/sys/boot/uboot/lib/copy.c @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com> + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> + +/* + * MD primitives supporting placement of module data + * + * XXX should check load address/size against memory top. + */ + +ssize_t +uboot_copyin(const void *src, vm_offset_t dest, const size_t len) +{ + bcopy(src, (void *)dest, len); + return (len); +} + +ssize_t +uboot_copyout(const vm_offset_t src, void *dest, const size_t len) +{ + bcopy((void *)src, dest, len); + return (len); +} + +ssize_t +uboot_readin(const int fd, vm_offset_t dest, const size_t len) +{ + return (read(fd, (void *) dest, len)); +} diff --git a/sys/boot/uboot/lib/devicename.c b/sys/boot/uboot/lib/devicename.c new file mode 100644 index 0000000..2bf2bea --- /dev/null +++ b/sys/boot/uboot/lib/devicename.c @@ -0,0 +1,237 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include <string.h> +#include <sys/disklabel.h> + +#include "bootstrap.h" +#include "libuboot.h" + +static int uboot_parsedev(struct uboot_devdesc **dev, const char *devspec, const char **path); + +/* + * Point (dev) at an allocated device specifier for the device matching the + * path in (devspec). If it contains an explicit device specification, + * use that. If not, use the default device. + */ +int +uboot_getdev(void **vdev, const char *devspec, const char **path) +{ + struct uboot_devdesc **dev = (struct uboot_devdesc **)vdev; + int rv; + + /* + * If it looks like this is just a path and no + * device, go with the current device. + */ + if ((devspec == NULL) || + (devspec[0] == '/') || + (strchr(devspec, ':') == NULL)) { + + if (((rv = uboot_parsedev(dev, getenv("currdev"), NULL)) == 0) && + (path != NULL)) + *path = devspec; + return(rv); + } + + /* + * Try to parse the device name off the beginning of the devspec + */ + return(uboot_parsedev(dev, devspec, path)); +} + +/* + * Point (dev) at an allocated device specifier matching the string version + * at the beginning of (devspec). Return a pointer to the remaining + * text in (path). + * + * In all cases, the beginning of (devspec) is compared to the names + * of known devices in the device switch, and then any following text + * is parsed according to the rules applied to the device type. + * + * For disk-type devices, the syntax is: + * + * disk<unit>[s<slice>][<partition>]: + * + */ +static int +uboot_parsedev(struct uboot_devdesc **dev, const char *devspec, const char **path) +{ + struct uboot_devdesc *idev; + struct devsw *dv; + int i, unit, slice, partition, err; + char *cp; + const char *np; + + /* minimum length check */ + if (strlen(devspec) < 2) + return(EINVAL); + + /* look for a device that matches */ + for (i = 0, dv = NULL; devsw[i] != NULL; i++) { + if (!strncmp(devspec, devsw[i]->dv_name, strlen(devsw[i]->dv_name))) { + dv = devsw[i]; + break; + } + } + if (dv == NULL) + return(ENOENT); + idev = malloc(sizeof(struct uboot_devdesc)); + err = 0; + np = (devspec + strlen(dv->dv_name)); + + switch(dv->dv_type) { + case DEVT_NONE: /* XXX what to do here? Do we care? */ + break; + + case DEVT_DISK: + unit = -1; + slice = -1; + partition = -1; + if (*np && (*np != ':')) { + unit = strtol(np, &cp, 10); /* next comes the unit number */ + if (cp == np) { + err = EUNIT; + goto fail; + } + if (*cp == 's') { /* got a slice number */ + np = cp + 1; + slice = strtol(np, &cp, 10); + if (cp == np) { + err = ESLICE; + goto fail; + } + } + if (*cp && (*cp != ':')) { + partition = *cp - 'a'; /* get a partition number */ + if ((partition < 0) || (partition >= MAXPARTITIONS)) { + err = EPART; + goto fail; + } + cp++; + } + } + if (*cp && (*cp != ':')) { + err = EINVAL; + goto fail; + } + + idev->d_unit = unit; + idev->d_kind.disk.slice = slice; + idev->d_kind.disk.partition = partition; + if (path != NULL) + *path = (*cp == 0) ? cp : cp + 1; + break; + + case DEVT_NET: + unit = 0; + + if (*np && (*np != ':')) { + unit = strtol(np, &cp, 0); /* get unit number if present */ + if (cp == np) { + err = EUNIT; + goto fail; + } + } + if (*cp && (*cp != ':')) { + err = EINVAL; + goto fail; + } + + if (dv->dv_type == DEVT_NET) + idev->d_unit = unit; + + if (path != NULL) + *path = (*cp == 0) ? cp : cp + 1; + break; + + default: + err = EINVAL; + goto fail; + } + idev->d_dev = dv; + idev->d_type = dv->dv_type; + if (dev == NULL) { + free(idev); + } else { + *dev = idev; + } + return(0); + + fail: + free(idev); + return(err); +} + + +char * +uboot_fmtdev(void *vdev) +{ + struct uboot_devdesc *dev = (struct uboot_devdesc *)vdev; + static char buf[128]; /* XXX device length constant? */ + char *cp; + + switch(dev->d_type) { + case DEVT_NONE: + strcpy(buf, "(no device)"); + break; + + case DEVT_DISK: + cp = buf; + cp += sprintf(cp, "%s%d", dev->d_dev->dv_name, dev->d_unit); + if (dev->d_kind.disk.slice > 0) + cp += sprintf(cp, "s%d", dev->d_kind.disk.slice); + if (dev->d_kind.disk.partition >= 0) + cp += sprintf(cp, "%c", dev->d_kind.disk.partition + 'a'); + strcat(cp, ":"); + break; + + case DEVT_NET: + sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); + break; + } + return(buf); +} + +/* + * Set currdev to suit the value being supplied in (value) + */ +int +uboot_setcurrdev(struct env_var *ev, int flags, const void *value) +{ + struct uboot_devdesc *ncurr; + int rv; + + if ((rv = uboot_parsedev(&ncurr, value, NULL)) != 0) + return(rv); + free(ncurr); + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + return(0); +} diff --git a/sys/boot/uboot/lib/disk.c b/sys/boot/uboot/lib/disk.c new file mode 100644 index 0000000..2adc6ba --- /dev/null +++ b/sys/boot/uboot/lib/disk.c @@ -0,0 +1,103 @@ +/*- + * Copyright (C) 2000 Benno Rice. + * 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 Benno Rice ``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 TOOLS GMBH 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Disk I/O routines using U-Boot - TODO + */ + +#include <sys/param.h> +#include <sys/queue.h> + +#include <netinet/in.h> +#include <machine/stdarg.h> +#include <stand.h> + +#include "bootstrap.h" + +static int d_init(void); +static int d_strategy(void *devdata, int flag, daddr_t dblk, + size_t size, char *buf, size_t *rsize); +static int d_open(struct open_file *f, ...); +static int d_close(struct open_file *f); +static int d_ioctl(struct open_file *f, u_long cmd, void *data); +static void d_print(int verbose); + +struct devsw uboot_disk = { + "block", + DEVT_DISK, + d_init, + d_strategy, + d_open, + d_close, + d_ioctl, + d_print +}; + +struct opened_dev { + u_int count; + SLIST_ENTRY(opened_dev) link; +}; + +SLIST_HEAD(, opened_dev) opened_devs = SLIST_HEAD_INITIALIZER(opened_dev); + +static int +d_init(void) +{ + return 0; +} + +static int +d_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, + size_t *rsize) +{ + return (EINVAL); +} + +static int +d_open(struct open_file *f, ...) +{ + return (EINVAL); +} + +static int +d_close(struct open_file *f) +{ + return (EINVAL); +} + +static int +d_ioctl(struct open_file *f, u_long cmd, void *data) +{ + return (EINVAL); +} + +static void +d_print(int verbose) +{ + +} diff --git a/sys/boot/uboot/lib/elf_freebsd.c b/sys/boot/uboot/lib/elf_freebsd.c new file mode 100644 index 0000000..735dd31 --- /dev/null +++ b/sys/boot/uboot/lib/elf_freebsd.c @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 2001 Benno Rice <benno@FreeBSD.org> + * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com> + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/linker.h> + +#include <machine/metadata.h> +#include <machine/elf.h> + +#include <stand.h> + +#include "bootstrap.h" + +int +__elfN(uboot_load)(char *filename, u_int64_t dest, + struct preloaded_file **result) +{ + int r; + + r = __elfN(loadfile)(filename, dest, result); + if (r != 0) + return (r); + +#if defined(__powerpc__) + /* + * No need to sync the icache for modules: this will + * be done by the kernel after relocation. + */ + if (!strcmp((*result)->f_type, "elf kernel")) + __syncicache((void *) (*result)->f_addr, (*result)->f_size); +#endif + return (0); +} + +int +__elfN(uboot_exec)(struct preloaded_file *fp) +{ + struct file_metadata *fmp; + vm_offset_t mdp; + Elf_Ehdr *e; + int error; + + if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) { + return (EFTYPE); + } + e = (Elf_Ehdr *)&fmp->md_data; + + if ((error = md_load(fp->f_args, &mdp)) != 0) + return (error); + + printf("Kernel entry at 0x%lx ...\n", e->e_entry); + + dev_cleanup(); + + (*(void (*)())e->e_entry)((void *)mdp); + panic("exec returned"); +} + +struct file_format uboot_elf = +{ + __elfN(uboot_load), + __elfN(uboot_exec) +}; diff --git a/sys/boot/uboot/lib/glue.c b/sys/boot/uboot/lib/glue.c new file mode 100644 index 0000000..03c713b --- /dev/null +++ b/sys/boot/uboot/lib/glue.c @@ -0,0 +1,530 @@ +/*- + * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com> + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include "api_public.h" + +#undef DEBUG +#define DEBUG + +#ifdef DEBUG +#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0) +#else +#define debugf(fmt, args...) +#endif + +/* console */ +int ub_getc(void); +int ub_tstc(void); +void ub_putc(char c); +void ub_puts(const char *s); + +/* system */ +void ub_reset(void); +struct sys_info * ub_get_sys_info(void); + +/* time */ +void ub_udelay(unsigned long); +unsigned long ub_get_timer(unsigned long); + +/* env vars */ +char * ub_env_get(const char *name); +void ub_env_set(const char *name, char *value); +const char * ub_env_enum(const char *last); + +/* devices */ +int ub_dev_enum(void); +int ub_dev_open(int handle); +int ub_dev_close(int handle); +int ub_dev_read(int handle, void *buf, + lbasize_t len, lbastart_t start); +int ub_dev_send(int handle, void *buf, int len); +int ub_dev_recv(int handle, void *buf, int len); + +int api_search_sig(struct api_signature **sig); + +extern int syscall(int, int *, ...); + + +/* crc32 stuff stolen from lib/libdisk/write_ia64_disk.c */ +static uint32_t crc32_tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +static uint32_t +crc32(const void *buf, size_t size) +{ + const uint8_t *p; + uint32_t crc; + + p = buf; + crc = ~0U; + + while (size--) + crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + + return (crc ^ ~0U); +} + + +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; +} + +#define API_SEARCH_START (255*1024*1024) /* start at 1MB below the RAM top */ +//#define API_SEARCH_START 0 +#define API_SEARCH_END (256 * 1024 * 1024 - 1) /* ...and search to the end */ + +/* + * 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; + + if (sig == NULL) + return 0; + + sp = (unsigned char *)API_SEARCH_START; + + while ((sp + (int)API_SIG_MAGLEN) < (unsigned char *)API_SEARCH_END) { + 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; +} + + +/* + * NOTICE: ub_ library calls are part of the application, not U-Boot code! + * They are front-end wrappers that are used by the consumer application: they + * prepare arguments for particular syscall and jump to the low level + * syscall() + * + */ + +/**************************************** + * + * 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); +} + + +#define MR_MAX 5 +static struct mem_region mr[MR_MAX]; +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 = MR_MAX; + 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, ..., MAX_DEVS-1 + * + ***************************************************************************/ + +#define MAX_DEVS 6 + +static struct device_info devices[MAX_DEVS]; + +struct device_info * ub_dev_get(int i) +{ + return ((i < 0 || i >= MAX_DEVS) ? 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) * MAX_DEVS); + di = &devices[0]; + + if (!syscall(API_DEV_ENUM, NULL, di)) + return 0; + + while (di->cookie != NULL) { + + if (++n >= MAX_DEVS) + 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 >= MAX_DEVS) + 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 >= MAX_DEVS) + 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 >= MAX_DEVS) + 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) +{ + 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 -1; + + if (err) + return err; + + if (act_len != len) + return API_EIO; + + return 0; +} + +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) +{ + 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 -1; + + if (err) + return -1; + + return act_len; +} + +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 -1; + + return err; +} + +/**************************************** + * + * 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; + + env = NULL; + + /* + * 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 + */ + if (!syscall(API_ENV_ENUM, NULL, (uint32_t)last, (uint32_t)&env)) + return NULL; + + if (!env) + /* no more env. variables to enumerate */ + return NULL; +#if 0 + if (last && strncmp(env, last, strlen(last)) == 0); + /* error, trying to enumerate non existing env. variable */ + return NULL; +#endif + + /* 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; +} diff --git a/sys/boot/uboot/lib/libuboot.h b/sys/boot/uboot/lib/libuboot.h new file mode 100644 index 0000000..d8762b0 --- /dev/null +++ b/sys/boot/uboot/lib/libuboot.h @@ -0,0 +1,74 @@ +/*- + * Copyright (C) 2000 Benno Rice. + * Copyright (C) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com> + * 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$ + */ + +/* + * Fully-qualified device descriptor. + * Note, this must match the 'struct devdesc' declaration + * in bootstrap.h. + */ +struct uboot_devdesc +{ + struct devsw *d_dev; + int d_type; + int d_unit; + union + { + struct + { + void *data; + int slice; + int partition; + } disk; + } d_kind; +}; + +/* + * Default network packet alignment in memory + */ +#define PKTALIGN 32 + +extern int uboot_getdev(void **vdev, const char *devspec, const char **path); +extern char *uboot_fmtdev(void *vdev); +extern int uboot_setcurrdev(struct env_var *ev, int flags, const void *value); + +extern struct netif_driver uboot_net; +extern struct devsw uboot_disk; + +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; + +extern void reboot(void); diff --git a/sys/boot/uboot/lib/module.c b/sys/boot/uboot/lib/module.c new file mode 100644 index 0000000..3928857 --- /dev/null +++ b/sys/boot/uboot/lib/module.c @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * U-Boot-specific module functionality. + * + * XXX not much for now... + * + */ + +#include <stand.h> +#include <string.h> + +#include "bootstrap.h" + +int +uboot_autoload(void) +{ + return(0); +} diff --git a/sys/boot/uboot/lib/net.c b/sys/boot/uboot/lib/net.c new file mode 100644 index 0000000..88021c8 --- /dev/null +++ b/sys/boot/uboot/lib/net.c @@ -0,0 +1,252 @@ +/*- + * Copyright (c) 2000-2001 Benno Rice + * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com> + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/if_ether.h> +#include <netinet/ip.h> + +#include <stand.h> +#include <net.h> +#include <netif.h> + +#include "api_public.h" +#include "libuboot.h" + +#define NETIF_DEBUG +#define NETIF_VERBOSE_DEBUG +#undef NETIF_DEBUG +#undef NETIF_VERBOSE_DEBUG + + +static int net_probe(struct netif *, void *); +static int net_match(struct netif *, void *); +static void net_init(struct iodesc *, void *); +static int net_get(struct iodesc *, void *, size_t, time_t); +static int net_put(struct iodesc *, void *, size_t); +static void net_end(struct netif *); + +struct device_info * ub_dev_get(int i); + +extern int devs_no; +extern struct netif_stats net_stats[]; + +struct netif_dif net_ifs[] = { + /* dif_unit dif_nsel dif_stats dif_private */ + { 0, 1, &net_stats[0], 0, }, +}; + +struct netif_stats net_stats[NENTS(net_ifs)]; + +struct netif_driver uboot_net = { + "uboot_eth", /* netif_bname */ + net_match, /* netif_match */ + net_probe, /* netif_probe */ + net_init, /* netif_init */ + net_get, /* netif_get */ + net_put, /* netif_put */ + net_end, /* netif_end */ + net_ifs, /* netif_ifs */ + NENTS(net_ifs) /* netif_nifs */ +}; + +struct uboot_softc { + u_int32_t sc_pad; + u_int8_t sc_rxbuf[ETHER_MAX_LEN]; + u_int8_t sc_txbuf[ETHER_MAX_LEN + PKTALIGN]; + u_int8_t *sc_txbufp; + int sc_handle; /* device handle for ub_dev_xxx */ +}; + +static struct uboot_softc uboot_softc; + +static int +net_match(struct netif *nif, void *machdep_hint) +{ + char **a = (char **)machdep_hint; + + if (memcmp("net", *a, 3) == 0) + return 1; + + printf("net_match: could not match network device\n"); + return 0; +} + +static int +net_probe(struct netif *nif, void *machdep_hint) +{ + int i; + struct device_info *di; + + for (i = 0; i < devs_no; i++) + if (di = ub_dev_get(i)) + if (di->type == DEV_TYP_NET) + break; + if (i == devs_no) { + printf("net_probe: no network devices found, maybe not\ + enumerated yet..?\n"); + return -1; + } + +#if defined(NETIF_DEBUG) + printf("net_probe: network device found: %d\n", i); +#endif + uboot_softc.sc_handle = i; + + return 0; +} + +static int +net_put(struct iodesc *desc, void *pkt, size_t len) +{ + struct netif *nif = desc->io_netif; + struct uboot_softc *sc = nif->nif_devdata; + + struct ether_header *eh; + size_t sendlen; + ssize_t rv; + +#if defined(NETIF_DEBUG) + printf("net_put: desc 0x%x, pkt 0x%x, len %d\n", desc, pkt, len); + eh = pkt; + printf("dst: %s ", ether_sprintf(eh->ether_dhost)); + printf("src: %s ", ether_sprintf(eh->ether_shost)); + printf("type: 0x%x\n", eh->ether_type & 0xffff); +#endif + + if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) { + sendlen = ETHER_MIN_LEN - ETHER_CRC_LEN; + bzero(sc->sc_txbufp, sendlen); + } else + sendlen = len; + + memcpy(sc->sc_txbufp, pkt, len); + + rv = ub_dev_send(sc->sc_handle, sc->sc_txbufp, sendlen); + +#if defined(NETIF_DEBUG) + printf("net_put: ub_send returned %d\n", rv); +#endif + if (rv == 0) + rv = len; + else + rv = -1; + + return rv; +} + +static int +net_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout) +{ + struct netif *nif = desc->io_netif; + struct uboot_softc *sc = nif->nif_devdata; + + time_t t; + int length; + +#if defined(NETIF_DEBUG) + printf("net_get: pkt %x, len %d, timeout %d\n", pkt, len, + timeout); +#endif + + t = getsecs(); + do { + length = ub_dev_recv(sc->sc_handle, sc->sc_rxbuf, len); + } while ((length == -1 || length == 0) && + (getsecs() - t < timeout)); + +#if defined(NETIF_DEBUG) + printf("net_get: received len %d (%x)\n", length, length); +#endif + + if (length > 0) { + memcpy(pkt, sc->sc_rxbuf, MIN(len, length)); + if (length != len) { +#if defined(NETIF_DEBUG) + printf("net_get: len %x, length %x\n", len, length); +#endif + } + return length; + } + + return -1; +} + + +static void +net_init(struct iodesc *desc, void *machdep_hint) +{ + int i, err; + struct netif *nif = desc->io_netif; + struct uboot_softc *sc; + struct device_info *di; + + sc = nif->nif_devdata = &uboot_softc; + + if (err = ub_dev_open(sc->sc_handle)) + panic("%s%d: initialisation failed with error %d\n", + nif->nif_driver->netif_bname, nif->nif_unit, err); + + /* Get MAC address */ + di = ub_dev_get(sc->sc_handle); + memcpy(desc->myea, di->di_net.hwaddr, 6); + if (memcmp (desc->myea, "\0\0\0\0\0\0", 6) == 0) { + panic("%s%d: empty ethernet address!", + nif->nif_driver->netif_bname, nif->nif_unit); + } + +#if defined(NETIF_DEBUG) + printf("network: %s%d attached to %s\n", nif->nif_driver->netif_bname, + nif->nif_unit, ether_sprintf(desc->myea)); +#endif + + /* Set correct alignment for TX packets */ + sc->sc_txbufp = sc->sc_txbuf; + if ((unsigned long)sc->sc_txbufp % PKTALIGN) + sc->sc_txbufp += PKTALIGN - + (unsigned long)sc->sc_txbufp % PKTALIGN; +} + + +static void +net_end(struct netif *nif) +{ + int err; + struct uboot_softc *sc = nif->nif_devdata; + + if (err = ub_dev_close(sc->sc_handle)) + panic("%s%d: net_end failed with error %d\n", + nif->nif_driver->netif_bname, nif->nif_unit, err); +} diff --git a/sys/boot/uboot/lib/reboot.c b/sys/boot/uboot/lib/reboot.c new file mode 100644 index 0000000..e709d50 --- /dev/null +++ b/sys/boot/uboot/lib/reboot.c @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com> + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +void +exit(int code) +{ + ub_reset(); +} diff --git a/sys/boot/uboot/lib/time.c b/sys/boot/uboot/lib/time.c new file mode 100644 index 0000000..2ec700c --- /dev/null +++ b/sys/boot/uboot/lib/time.c @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2000 Benno Rice + * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com> + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> + +/* + * Return the time in seconds since the beginning of the day. + */ +time_t +time(time_t *tloc) +{ + int secs; + + secs = ub_get_timer(0) / 1000; + if (tloc) + *tloc = secs; + + return secs; +} + +int +getsecs() +{ + return (time(NULL)); +} + +/* + * Use U-Boot udelay() function to wait for a given microseconds period + */ +void +delay(int usecs) +{ + ub_udelay(usecs); +} |