summaryrefslogtreecommitdiffstats
path: root/sys/boot/arm/ixp425
diff options
context:
space:
mode:
authorjhay <jhay@FreeBSD.org>2008-10-06 19:38:10 +0000
committerjhay <jhay@FreeBSD.org>2008-10-06 19:38:10 +0000
commite9b8d6399adb4adf785eeca7ca1b8a95d4ed5ed8 (patch)
treeb878c5d5f889c266775eba5483918604ecf3c047 /sys/boot/arm/ixp425
parent730ae9451a0c6c01b7f4f5c4b3fb52c760645523 (diff)
downloadFreeBSD-src-e9b8d6399adb4adf785eeca7ca1b8a95d4ed5ed8.zip
FreeBSD-src-e9b8d6399adb4adf785eeca7ca1b8a95d4ed5ed8.tar.gz
Add a boot loader for ixp425 based boards like the Gateworks Avila
and ADI Pronghorn Metro with Redboot on them.
Diffstat (limited to 'sys/boot/arm/ixp425')
-rw-r--r--sys/boot/arm/ixp425/Makefile.inc42
-rw-r--r--sys/boot/arm/ixp425/boot2/Makefile75
-rw-r--r--sys/boot/arm/ixp425/boot2/arm_init.S50
-rw-r--r--sys/boot/arm/ixp425/boot2/boot2.c483
-rw-r--r--sys/boot/arm/ixp425/boot2/cf_ata.h62
-rw-r--r--sys/boot/arm/ixp425/boot2/ixp425_board.c697
-rw-r--r--sys/boot/arm/ixp425/boot2/lib.h64
7 files changed, 1473 insertions, 0 deletions
diff --git a/sys/boot/arm/ixp425/Makefile.inc b/sys/boot/arm/ixp425/Makefile.inc
new file mode 100644
index 0000000..37af9c7
--- /dev/null
+++ b/sys/boot/arm/ixp425/Makefile.inc
@@ -0,0 +1,42 @@
+# $FreeBSD$
+
+.if !target(__ixp425_boot_Makefile.inc__)
+.PATH: ${.CURDIR}/../../../../libkern ${.CURDIR}/../../../../libkern/arm
+
+__ixp425_boot_Makefile.inc__:
+
+# Both Avila and Pronghorn Metro are supported by ixp425
+BOOT_FLAVOR=ixp425
+
+CFLAGS+=-Os -ffreestanding \
+ -I${.CURDIR}/../../../.. \
+ -I${.CURDIR}/../../../../arm \
+ -DCPU_XSCALE_IXP425 \
+ -Wall -Waggregate-return \
+ -Werror \
+ -Wnested-externs \
+ -Wpointer-arith -Wshadow -Wwrite-strings \
+ -Wmissing-prototypes \
+ -Wmissing-declarations
+
+# -Wstrict-prototypes
+
+CFLAGS+=-DBOOT_${BOOT_FLAVOR:U}
+
+LD ?= ld
+OBJCOPY ?= objcopy
+
+.if defined(P)
+${P}: ${OBJS}
+ ${LD} ${LDFLAGS} -o ${.TARGET} ${OBJS}
+
+CLEANFILES+= ${P}
+.endif
+
+.if defined(WITH_TAG_LIST)
+MK_TAG_LIST:=yes
+.else
+MK_TAG_LIST:=no
+.endif
+
+.endif
diff --git a/sys/boot/arm/ixp425/boot2/Makefile b/sys/boot/arm/ixp425/boot2/Makefile
new file mode 100644
index 0000000..94479434
--- /dev/null
+++ b/sys/boot/arm/ixp425/boot2/Makefile
@@ -0,0 +1,75 @@
+# $FreeBSD$
+
+# We get a lot of the std lib functions from here.
+.PATH: ${.CURDIR}/../../at91/libat91
+
+# Enable to get debug msgs
+#DEBUG=yes
+
+# Hack to search through the kernel for ufs:ad0s1a and replace it with
+# the correct one for the active slice/partition.
+FIXUP_BOOT_DRV=yes
+
+P=boot2
+FILES=${P}
+SRCS=arm_init.S boot2.c ${BOOT_FLAVOR:L}_board.c
+SRCS+=memchr.c memcmp.c memcpy.c memmem.c memset.c printf.c strcmp.c strcpy.c
+SRCS+=strlen.c ashldi3.c divsi3.S muldi3.c
+NO_MAN=
+
+KERNPHYSADDR=0x180000
+KERNVIRTADDR=${KERNPHYSADDR}
+BOOT_STACK=0x200000-4
+M=${MACHINE_ARCH}
+LDFLAGS=-e ${KERNPHYSADDR} -EB -T ldscript.${M}
+OBJS+= ${SRCS:N*.h:R:S/$/.o/g}
+S=${.CURDIR}/../../../..
+
+CFLAGS+= \
+ -DBOOT_STACK=${BOOT_STACK} \
+ -I${.CURDIR}/../../../common \
+ -I${.CURDIR}
+
+.if defined(FIXUP_BOOT_DRV)
+CFLAGS+=-DFIXUP_BOOT_DRV
+.endif
+.if defined(DEBUG)
+CFLAGS+=-DDEBUG
+.endif
+
+ldscript.$M: $S/conf/ldscript.$M
+ cat $S/conf/ldscript.$M|sed s/KERNPHYSADDR/${KERNPHYSADDR}/g| \
+ sed s/KERNVIRTADDR/${KERNVIRTADDR}/g | \
+ sed s/" + SIZEOF_HEADERS"// > ldscript.$M
+
+${P}: ldscript.$M
+
+CLEANFILES+=ldscript.$M
+
+memchr.c: $S/../lib/libc/string/memchr.c
+ sed -e 's/string\.h/lib.h/' < $S/../lib/libc/string/memchr.c > \
+ ${.TARGET}
+
+memmem.c: $S/../lib/libc/string/memmem.c
+ sed -e 's/string\.h/lib.h/' < $S/../lib/libc/string/memmem.c > \
+ ${.TARGET}
+
+CLEANFILES+=memchr.c memmem.c
+
+ashldi3.o: $S/libkern/ashldi3.c
+ cc -c ${CFLAGS} -D_KERNEL -o ${.TARGET} ${.IMPSRC}
+
+divsi3.o: $S/libkern/${M}/divsi3.S
+ cc -c ${CFLAGS} -D_KERNEL -o ${.TARGET} ${.IMPSRC}
+
+muldi3.o: $S/libkern/${M}/muldi3.c
+ cc -c ${CFLAGS} -D_KERNEL -o ${.TARGET} ${.IMPSRC}
+
+inflate.c: $S/kern/inflate.c
+ sed -e 's/extern void putstr (char/extern void putstr (const char/' < \
+ $S/kern/inflate.c > ${.TARGET}
+
+CLEANFILES+=inflate.c
+
+.include <bsd.prog.mk>
+
diff --git a/sys/boot/arm/ixp425/boot2/arm_init.S b/sys/boot/arm/ixp425/boot2/arm_init.S
new file mode 100644
index 0000000..088f23d
--- /dev/null
+++ b/sys/boot/arm/ixp425/boot2/arm_init.S
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2008 John Hay. 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 ``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 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$
+ */
+
+start:
+
+/* Initialise bss and sp */
+ nop
+ adr r1, .Lstart
+ ldmia r1, {r1, r2, sp} /* Set initial stack and */
+ sub r2, r2, r1 /* get zero init data */
+ mov r3, #0
+.L1:
+ str r3, [r1], #0x0004 /* get zero init data */
+ subs r2, r2, #4
+ bgt .L1
+
+ .extern main
+ bl main
+/* main should not return. If it does, spin forever */
+infiniteLoop:
+ b infiniteLoop
+
+.Lstart:
+ .word _edata
+ .word _end
+ .word BOOT_STACK
+/* End */
diff --git a/sys/boot/arm/ixp425/boot2/boot2.c b/sys/boot/arm/ixp425/boot2/boot2.c
new file mode 100644
index 0000000..d46c4ae
--- /dev/null
+++ b/sys/boot/arm/ixp425/boot2/boot2.c
@@ -0,0 +1,483 @@
+/*-
+ * Copyright (c) 2008 John Hay
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/disklabel.h>
+#include <sys/diskmbr.h>
+#include <sys/dirent.h>
+#include <sys/reboot.h>
+
+#include <machine/elf.h>
+
+#include <stdarg.h>
+
+#include "lib.h"
+
+#define RBX_ASKNAME 0x0 /* -a */
+#define RBX_SINGLE 0x1 /* -s */
+/* 0x2 is reserved for log2(RB_NOSYNC). */
+/* 0x3 is reserved for log2(RB_HALT). */
+/* 0x4 is reserved for log2(RB_INITNAME). */
+#define RBX_DFLTROOT 0x5 /* -r */
+/* #define RBX_KDB 0x6 -d */
+/* 0x7 is reserved for log2(RB_RDONLY). */
+/* 0x8 is reserved for log2(RB_DUMP). */
+/* 0x9 is reserved for log2(RB_MINIROOT). */
+#define RBX_CONFIG 0xa /* -c */
+#define RBX_VERBOSE 0xb /* -v */
+/* #define RBX_SERIAL 0xc -h */
+/* #define RBX_CDROM 0xd -C */
+/* 0xe is reserved for log2(RB_POWEROFF). */
+#define RBX_GDB 0xf /* -g */
+/* #define RBX_MUTE 0x10 -m */
+/* 0x11 is reserved for log2(RB_SELFTEST). */
+/* 0x12 is reserved for boot programs. */
+/* 0x13 is reserved for boot programs. */
+/* #define RBX_PAUSE 0x14 -p */
+/* #define RBX_QUIET 0x15 -q */
+#define RBX_NOINTR 0x1c /* -n */
+/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */
+/* #define RBX_DUAL 0x1d -D */
+/* 0x1f is reserved for log2(RB_BOOTINFO). */
+
+/* pass: -a, -s, -r, -v, -g */
+#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \
+ OPT_SET(RBX_DFLTROOT) | \
+ OPT_SET(RBX_VERBOSE) | \
+ OPT_SET(RBX_GDB))
+
+#define PATH_CONFIG "/boot.config"
+#define PATH_KERNEL "/boot/kernel/kernel"
+
+extern uint32_t _end;
+
+#define NOPT 6
+
+#define OPT_SET(opt) (1 << (opt))
+#define OPT_CHECK(opt) ((opts) & OPT_SET(opt))
+
+static const char optstr[NOPT] = "agnrsv";
+static const unsigned char flags[NOPT] = {
+ RBX_ASKNAME,
+ RBX_GDB,
+ RBX_NOINTR,
+ RBX_DFLTROOT,
+ RBX_SINGLE,
+ RBX_VERBOSE
+};
+
+static unsigned dsk_start;
+static char cmd[512];
+static char kname[1024];
+static uint32_t opts;
+static int dsk_meta;
+static int bootslice;
+static int bootpart;
+static int disk_layout;
+#define DL_UNKNOWN 0
+#define DL_RAW 1 /* Dangerously dedicated */
+#define DL_SLICE 2 /* Use only slices (DOS partitions) */
+#define DL_SLICEPART 3 /* Use slices and partitions */
+
+static void load(void);
+static int parse(void);
+static int xfsread(ino_t, void *, size_t);
+static int dskread(void *, unsigned, unsigned);
+static int drvread(void *, unsigned, unsigned);
+#ifdef FIXUP_BOOT_DRV
+static void fixup_boot_drv(caddr_t, int, int, int);
+#endif
+
+#include "ufsread.c"
+
+#ifdef DEBUG
+#define DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+static inline int
+xfsread(ino_t inode, void *buf, size_t nbyte)
+{
+ if ((size_t)fsread(inode, buf, nbyte) != nbyte)
+ return -1;
+ return 0;
+}
+
+static inline void
+getstr(int c)
+{
+ char *s;
+
+ s = cmd;
+ if (c == 0)
+ c = getc(10000);
+ for (;;) {
+ switch (c) {
+ case 0:
+ break;
+ case '\177':
+ case '\b':
+ if (s > cmd) {
+ s--;
+ printf("\b \b");
+ }
+ break;
+ case '\n':
+ case '\r':
+ *s = 0;
+ return;
+ default:
+ if (s - cmd < sizeof(cmd) - 1)
+ *s++ = c;
+ xputchar(c);
+ }
+ c = getc(10000);
+ }
+}
+
+int
+main(void)
+{
+ const char *bt;
+ int autoboot, c = 0;
+ ino_t ino;
+
+ dmadat = (void *)(0x1c0000);
+ p_memset((char *)dmadat, 0, 32 * 1024);
+ bt = board_init();
+
+ printf("FreeBSD ARM (%s) boot2 v%d.%d\n", bt, 0, 3);
+
+ autoboot = 1;
+
+ /* Process configuration file */
+ if ((ino = lookup(PATH_CONFIG)))
+ fsread(ino, cmd, sizeof(cmd));
+
+ if (*cmd) {
+ if (parse())
+ autoboot = 0;
+ printf("%s: %s\n", PATH_CONFIG, cmd);
+ /* Do not process this command twice */
+ *cmd = 0;
+ }
+
+ if (*kname == '\0')
+ strcpy(kname, PATH_KERNEL);
+
+ /* Present the user with the boot2 prompt. */
+ for (;;) {
+ printf("\nDefault: %s\nboot: ", kname);
+ if (!autoboot ||
+ (OPT_CHECK(RBX_NOINTR) == 0 && (c = getc(2)) != 0))
+ getstr(c);
+ xputchar('\n');
+ autoboot = 0;
+ c = 0;
+ DPRINTF("cmd is '%s'\n", cmd);
+ if (parse())
+ xputchar('\a');
+ else
+ load();
+ }
+}
+
+static void
+load(void)
+{
+ Elf32_Ehdr eh;
+ static Elf32_Phdr ep[2];
+ caddr_t p;
+ ino_t ino;
+ uint32_t addr;
+ int i, j;
+#ifdef FIXUP_BOOT_DRV
+ caddr_t staddr;
+ int klen;
+
+ staddr = (caddr_t)0xffffffff;
+ klen = 0;
+#endif
+ if (!(ino = lookup(kname))) {
+ if (!ls)
+ printf("No %s\n", kname);
+ return;
+ }
+ DPRINTF("Found %s\n", kname);
+ if (xfsread(ino, &eh, sizeof(eh)))
+ return;
+ if (!IS_ELF(eh)) {
+ printf("Invalid %s\n", "format");
+ return;
+ }
+ fs_off = eh.e_phoff;
+ for (j = i = 0; i < eh.e_phnum && j < 2; i++) {
+ if (xfsread(ino, ep + j, sizeof(ep[0])))
+ return;
+ if (ep[j].p_type == PT_LOAD)
+ j++;
+ }
+ for (i = 0; i < 2; i++) {
+ p = (caddr_t)(ep[i].p_paddr & 0x0fffffff);
+ fs_off = ep[i].p_offset;
+#ifdef FIXUP_BOOT_DRV
+ if (staddr == (caddr_t)0xffffffff)
+ staddr = p;
+ klen += ep[i].p_filesz;
+#endif
+ if (xfsread(ino, p, ep[i].p_filesz))
+ return;
+ }
+ addr = eh.e_entry & 0x0fffffff;
+ DPRINTF("Entry point %x for %s\n", addr, kname);
+ clr_board();
+#ifdef FIXUP_BOOT_DRV
+ fixup_boot_drv(staddr, klen, bootslice, bootpart);
+#endif
+ ((void(*)(int))addr)(RB_BOOTINFO /* XXX | (opts & RBX_MASK) */);
+}
+
+static int
+parse()
+{
+ char *arg = cmd;
+ char *ep, *p;
+ int c, i;
+
+ while ((c = *arg++)) {
+ if (c == ' ' || c == '\t' || c == '\n')
+ continue;
+ for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
+ ep = p;
+ if (*p)
+ *p++ = 0;
+ if (c == '-') {
+ while ((c = *arg++)) {
+ for (i = 0; c != optstr[i]; i++)
+ if (i == NOPT - 1)
+ return -1;
+ opts ^= OPT_SET(flags[i]);
+ }
+ } else {
+ arg--;
+ /* look for ad0s1a:... | ad0s1:... */
+ if (strlen(arg) > 6 && arg[0] == 'a' &&
+ arg[1] == 'd' && arg[3] == 's' &&
+ (arg[5] == ':' || arg[6] == ':')) {
+ /* XXX Should also handle disk. */
+ bootslice = arg[4] - '0';
+ if (bootslice < 1 || bootslice > 4)
+ return (-1);
+ bootpart = 0;
+ if (arg[5] != ':')
+ bootpart = arg[5] - 'a';
+ if (bootpart < 0 || bootpart > 7)
+ return (-1);
+ dsk_meta = 0;
+ if (arg[5] == ':')
+ arg += 6;
+ else
+ arg += 7;
+ /* look for ad0a:... */
+ } else if (strlen(arg) > 4 && arg[0] == 'a' &&
+ arg[1] == 'd' && arg[2] == '0' && arg[4] == ':') {
+ bootslice = 0;
+ bootpart = arg[3] - 'a';
+ if (bootpart < 0 || bootpart > 7)
+ return (-1);
+ dsk_meta = 0;
+ arg += 5;
+ }
+ if ((i = ep - arg)) {
+ if ((size_t)i >= sizeof(kname))
+ return -1;
+ memcpy(kname, arg, i + 1);
+ }
+ }
+ arg = p;
+ }
+ return 0;
+}
+
+/*
+ * dskread() will try to handle the disk layouts that are typically
+ * encountered.
+ * - raw or "Dangerously Dedicated" mode. No real slice table, just the
+ * default one that is included with bsdlabel -B. Typically this is
+ * used with ROOTDEVNAME=\"ufs:ad0a\".
+ * - slice only. Only a slice table is installed with no bsd label or
+ * bsd partition table. This is typically used with
+ * ROOTDEVNAME=\"ufs:ad0s1\".
+ * - slice + bsd label + partition table. This is typically done with
+ * with fdisk + bsdlabel and is used with ROOTDEVNAME=\"ufs:ad0s1a\".
+ */
+static int
+dskread(void *buf, unsigned lba, unsigned nblk)
+{
+ struct dos_partition *dp;
+ struct disklabel *d;
+ char *sec;
+ int i;
+
+ if (!dsk_meta) {
+ sec = dmadat->secbuf;
+ dsk_start = 0;
+ if (drvread(sec, DOSBBSECTOR, 1))
+ return -1;
+ dp = (void *)(sec + DOSPARTOFF);
+ if (bootslice != 0) {
+ i = bootslice - 1;
+ if (dp[i].dp_typ != DOSPTYP_386BSD)
+ return -1;
+ } else {
+ for (i = 0; i < NDOSPART; i++) {
+ if ((dp[i].dp_typ == DOSPTYP_386BSD) &&
+ (dp[i].dp_flag == 0x80))
+ break;
+ }
+ }
+ if (i != NDOSPART) {
+ bootslice = i + 1;
+ DPRINTF("Found an active fbsd slice. (%d)\n", i + 1);
+ /*
+ * Although dp_start is aligned within the disk
+ * partition structure, DOSPARTOFF is 446, which
+ * is only word (2) aligned, not longword (4)
+ * aligned. Cope by using memcpy to fetch the
+ * start of this partition.
+ */
+ memcpy(&dsk_start, &dp[i].dp_start, 4);
+ dsk_start = swap32(dsk_start);
+ DPRINTF("dsk_start %x\n", dsk_start);
+ if ((bootslice == 4) && (dsk_start == 0)) {
+ disk_layout = DL_RAW;
+ bootslice = 0;
+ }
+ }
+ if (drvread(sec, dsk_start + LABELSECTOR, 1))
+ return -1;
+ d = (void *)(sec + LABELOFFSET);
+ if ((d->d_magic == DISKMAGIC && d->d_magic2 == DISKMAGIC) ||
+ (swap32(d->d_magic) == DISKMAGIC &&
+ swap32(d->d_magic2) == DISKMAGIC)) {
+ DPRINTF("p_size = %x\n",
+ !d->d_partitions[bootpart].p_size);
+ if (!d->d_partitions[bootpart].p_size) {
+ printf("Invalid partition\n");
+ return -1;
+ }
+ DPRINTF("p_offset %x, RAW %x\n",
+ swap32(d->d_partitions[bootpart].p_offset),
+ swap32(d->d_partitions[RAW_PART].p_offset));
+ dsk_start += swap32(d->d_partitions[bootpart].p_offset);
+ dsk_start -= swap32(d->d_partitions[RAW_PART].p_offset);
+ if ((disk_layout == DL_UNKNOWN) && (bootslice == 0))
+ disk_layout = DL_RAW;
+ else if (disk_layout == DL_UNKNOWN)
+ disk_layout = DL_SLICEPART;
+ } else {
+ disk_layout = DL_SLICE;
+ DPRINTF("Invalid %s\n", "label");
+ }
+ DPRINTF("bootslice %d, bootpart %d, dsk_start %u\n", bootslice,
+ bootpart, dsk_start);
+ dsk_meta++;
+ }
+ return drvread(buf, dsk_start + lba, nblk);
+}
+
+static int
+drvread(void *buf, unsigned lba, unsigned nblk)
+{
+ static unsigned c = 0x2d5c7c2f;
+
+ printf("%c\b", c = c << 8 | c >> 24);
+ return (avila_read((char *)buf, lba, nblk));
+}
+
+#ifdef FIXUP_BOOT_DRV
+/*
+ * fixup_boot_drv() will try to find the ROOTDEVNAME spec in the kernel
+ * and change it to what was specified on the comandline or /boot.conf
+ * file or to what was encountered on the disk. It will try to handle 3
+ * different disk layouts, raw (dangerously dedicated), slice only and
+ * slice + partition. It will look for the following strings in the
+ * kernel, but if it is one of the first three, the string in the kernel
+ * must use the correct form to match the actual disk layout:
+ * - ufs:ad0a
+ * - ufs:ad0s1
+ * - ufs:ad0s1a
+ * - ufs:ROOTDEVNAME
+ * In the case of the first three strings, only the "a" at the end and
+ * the "1" after the "s" will be modified, if they exist. The string
+ * length will not be changed. In the case of the last string, the
+ * whole string will be built up and nul, '\0' terminated.
+ */
+static void
+fixup_boot_drv(caddr_t addr, int klen, int bs, int bp)
+{
+ const u_int8_t op[] = "ufs:ROOTDEVNAME";
+ const u_int8_t op2[] = "ufs:ad0";
+ u_int8_t *p, *ps;
+
+ DPRINTF("fixup_boot_drv: 0x%x, %d, slice %d, partition %d\n",
+ (int)addr, klen, bs, bp);
+ if (bs > 4)
+ return;
+ if (bp > 7)
+ return;
+ ps = memmem(addr, klen, op, sizeof(op));
+ if (ps != NULL) {
+ p = ps + 4; /* past ufs: */
+ DPRINTF("Found it at 0x%x\n", (int)ps);
+ p[0] = 'a'; p[1] = 'd'; p[2] = '0'; /* ad0 */
+ p += 3;
+ if (bs > 0) {
+ /* append slice */
+ *p++ = 's';
+ *p++ = bs + '0';
+ }
+ if (disk_layout != DL_SLICE) {
+ /* append partition */
+ *p++ = bp + 'a';
+ }
+ *p = '\0';
+ } else {
+ ps = memmem(addr, klen, op2, sizeof(op2) - 1);
+ if (ps != NULL) {
+ p = ps + sizeof(op2) - 1;
+ DPRINTF("Found it at 0x%x\n", (int)ps);
+ if (*p == 's') {
+ /* fix slice */
+ p++;
+ *p++ = bs + '0';
+ }
+ if (*p == 'a')
+ *p = bp + 'a';
+ }
+ }
+ if (ps == NULL) {
+ printf("Could not locate \"%s\" to fix kernel boot device, "
+ "check ROOTDEVNAME is set\n", op);
+ return;
+ }
+ DPRINTF("Changed boot device to %s\n", ps);
+}
+#endif
diff --git a/sys/boot/arm/ixp425/boot2/cf_ata.h b/sys/boot/arm/ixp425/boot2/cf_ata.h
new file mode 100644
index 0000000..3c9e9e5
--- /dev/null
+++ b/sys/boot/arm/ixp425/boot2/cf_ata.h
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2008 John Hay. 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 ``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 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$
+ */
+
+#ifndef ARM_BOOT_CF_ATA_H
+#define ARM_BOOT_CF_ATA_H
+
+#define CF_DATA 0x00
+#define CF_ERROR 0x01
+#define CF_FEATURE 0x01
+#define CF_SECT_CNT 0x02
+#define CF_SECT_NUM 0x03
+#define CF_CYL_L 0x04
+#define CF_CYL_H 0x05
+#define CF_DRV_HEAD 0x06
+#define CF_D_MASTER 0x00
+#define CF_D_LBA 0x40
+#define CF_D_IBM 0xa0
+#define CF_STATUS 0x07
+#define CF_S_ERROR 0x01
+#define CF_S_INDEX 0x02
+#define CF_S_CORR 0x04
+#define CF_S_DRQ 0x08
+#define CF_S_DSC 0x10
+#define CF_S_DWF 0x20
+#define CF_S_READY 0x40
+#define CF_S_BUSY 0x80
+#define CF_COMMAND 0x07
+
+/* This is according to the appnote, but Sam use 0x1e in avila_ata.c */
+#define CF_ALT_STATUS 0x16
+#define CF_ALT_DEV_CTR 0x16
+#define CF_ALT_DEV_CTR2 0x1e
+#define CF_A_IDS 0x02
+#define CF_A_RESET 0x04
+#define CF_A_4BIT 0x08
+
+#define AVILA_IDE_GPIN 12
+
+#endif /* !ARM_BOOT_CF_ATA_H */
diff --git a/sys/boot/arm/ixp425/boot2/ixp425_board.c b/sys/boot/arm/ixp425/boot2/ixp425_board.c
new file mode 100644
index 0000000..985c0a5
--- /dev/null
+++ b/sys/boot/arm/ixp425/boot2/ixp425_board.c
@@ -0,0 +1,697 @@
+/*-
+ * Copyright (c) 2008 John Hay. 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 ``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 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/ata.h>
+
+#include <stdarg.h>
+
+#include "lib.h"
+#include "cf_ata.h"
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <dev/ic/ns16550.h>
+
+static u_int8_t *ubase;
+
+#define BOARD_AVILA 0
+#define BOARD_PRONGHORN 1
+static int board;
+
+static u_int8_t uart_getreg(u_int8_t *, int);
+static void uart_setreg(u_int8_t *, int, u_int8_t);
+
+static void cf_init(void);
+static void cf_clr(void);
+
+#ifdef DEBUG
+#define DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+const char *
+board_init(void)
+{
+ volatile u_int32_t *cs;
+ const char *bt = NULL;
+
+ /*
+ * Redboot only configure the chip selects that are needed, so
+ * use that to figure out if it is an Avila or ADI board. The
+ * Avila boards use CS2 and ADI does not.
+ */
+ cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS2_OFFSET);
+ if (*cs != 0) {
+ board = BOARD_AVILA;
+ bt = "Avila";
+ } else {
+ board = BOARD_PRONGHORN;
+ bt = "Pronghorn Metro";
+ }
+
+ /* Config the serial port. RedBoot should do the rest. */
+ if (board == BOARD_AVILA)
+ ubase = (u_int8_t *)(IXP425_UART0_HWBASE);
+ else
+ ubase = (u_int8_t *)(IXP425_UART1_HWBASE);
+
+ cf_init();
+
+ return bt;
+}
+
+/*
+ * This should be called just before starting the kernel. This is so
+ * that one can undo incompatable hardware settings.
+ */
+void
+clr_board(void)
+{
+ cf_clr();
+}
+
+/*
+ * General support functions.
+ */
+
+/*
+ * DELAY should delay for the number of microseconds.
+ * The idea is that the inner loop should take 1us, so val is the
+ * number of usecs to delay.
+ */
+void
+DELAY(int val)
+{
+ volatile int sub;
+ volatile int subsub;
+
+ sub = val;
+ while(sub) {
+ subsub = 3;
+ while(subsub)
+ subsub--;
+ sub--;
+ }
+}
+
+u_int32_t
+swap32(u_int32_t a)
+{
+ return (((a & 0xff) << 24) | ((a & 0xff00) << 8) |
+ ((a & 0xff0000) >> 8) | ((a & 0xff000000) >> 24));
+}
+
+u_int16_t
+swap16(u_int16_t val)
+{
+ return (val << 8) | (val >> 8);
+}
+
+/*
+ * uart related funcs
+ */
+static u_int8_t
+uart_getreg(u_int8_t *bas, int off)
+{
+ return *((volatile u_int32_t *)(bas + (off << 2))) & 0xff;
+}
+
+static void
+uart_setreg(u_int8_t *bas, int off, u_int8_t val)
+{
+ *((volatile u_int32_t *)(bas + (off << 2))) = (u_int32_t)val;
+}
+
+int
+getc(int seconds)
+{
+ int c, delay, limit;
+
+ c = 0;
+ delay = 10000;
+ limit = seconds * 1000000/10000;
+ while ((uart_getreg(ubase, REG_LSR) & LSR_RXRDY) == 0 && --limit)
+ DELAY(delay);
+
+ if ((uart_getreg(ubase, REG_LSR) & LSR_RXRDY) == LSR_RXRDY)
+ c = uart_getreg(ubase, REG_DATA);
+
+ return c;
+}
+
+void
+putchar(int ch)
+{
+ int delay, limit;
+
+ delay = 500;
+ limit = 20;
+ while ((uart_getreg(ubase, REG_LSR) & LSR_THRE) == 0 && --limit)
+ DELAY(delay);
+ uart_setreg(ubase, REG_DATA, ch);
+
+ limit = 40;
+ while ((uart_getreg(ubase, REG_LSR) & LSR_TEMT) == 0 && --limit)
+ DELAY(delay);
+}
+
+void
+xputchar(int ch)
+{
+ if (ch == '\n')
+ putchar('\r');
+ putchar(ch);
+}
+
+void
+putstr(const char *str)
+{
+ while(*str)
+ xputchar(*str++);
+}
+
+void
+puthex8(u_int8_t ch)
+{
+ const char *hex = "0123456789abcdef";
+
+ putchar(hex[ch >> 4]);
+ putchar(hex[ch & 0xf]);
+}
+
+void
+puthexlist(const u_int8_t *str, int length)
+{
+ while(length) {
+ puthex8(*str);
+ putchar(' ');
+ str++;
+ length--;
+ }
+}
+
+/*
+ *
+ * CF/IDE functions.
+ *
+ */
+
+struct {
+ u_int64_t dsize;
+ u_int64_t total_secs;
+ u_int8_t heads;
+ u_int8_t sectors;
+ u_int32_t cylinders;
+
+ u_int8_t *cs1;
+ u_int8_t *cs2;
+
+ u_int32_t use_lba;
+ u_int32_t use_stream8;
+ u_int32_t debug;
+
+ u_int8_t status;
+ u_int8_t error;
+} dskinf;
+
+static void cfenable16(void);
+static void cfdisable16(void);
+static u_int8_t cfread8(u_int32_t off);
+static u_int16_t cfread16(u_int32_t off);
+static void cfreadstream8(void *buf, int length);
+static void cfreadstream16(void *buf, int length);
+static void cfwrite8(u_int32_t off, u_int8_t val);
+static u_int8_t cfaltread8(u_int32_t off);
+static void cfaltwrite8(u_int32_t off, u_int8_t val);
+static int cfwait(u_int8_t mask);
+static int cfaltwait(u_int8_t mask);
+static int cfcmd(u_int32_t cmd, u_int32_t cylinder, u_int32_t head,
+ u_int32_t sector, u_int32_t count, u_int32_t feature);
+static void cfreset(void);
+#ifdef DEBUG
+static int cfgetparams(void);
+#endif
+static void cfprintregs(void);
+
+static void
+cf_init(void)
+{
+ u_int8_t status;
+#ifdef DEBUG
+ int rval;
+#endif
+ volatile u_int32_t *cs;
+
+ /* Setup the CF select timeing. Maybe already done by RedBoot? */
+ if (board == BOARD_AVILA) {
+ cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS1_OFFSET);
+ *cs |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
+ DPRINTF("t1 %x, ", *cs);
+
+ cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS2_OFFSET);
+ *cs |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
+ DPRINTF("t2 %x\n", *cs);
+
+ dskinf.cs1 = (u_int8_t *)IXP425_EXP_BUS_CS1_HWBASE;
+ dskinf.cs2 = (u_int8_t *)IXP425_EXP_BUS_CS2_HWBASE;
+ } else {
+ cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS3_OFFSET);
+ *cs |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
+ DPRINTF("t1 %x, ", *cs);
+
+ cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS4_OFFSET);
+ *cs |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
+ DPRINTF("t2 %x\n", *cs);
+
+ dskinf.cs1 = (u_int8_t *)IXP425_EXP_BUS_CS3_HWBASE;
+ dskinf.cs2 = (u_int8_t *)IXP425_EXP_BUS_CS4_HWBASE;
+ }
+ DPRINTF("cs1 %x, cs2 %x\n", dskinf.cs1, dskinf.cs2);
+
+ dskinf.use_stream8 = 0;
+ dskinf.use_lba = 0;
+ dskinf.debug = 1;
+
+ /* Detect if there is a disk. */
+ cfwrite8(CF_DRV_HEAD, CF_D_IBM);
+ DELAY(1000);
+ status = cfread8(CF_STATUS);
+ if (status != 0x50)
+ printf("cf-ata0 %x\n", (u_int32_t)status);
+ if (status == 0xff) {
+ printf("cf_ata0: No disk!\n");
+ return;
+ }
+
+ cfreset();
+
+ if (dskinf.use_stream8) {
+ DPRINTF("setting %d bit mode.\n", 8);
+ cfwrite8(CF_FEATURE, 0x01); /* Enable 8 bit transfers */
+ cfwrite8(CF_COMMAND, ATA_SETFEATURES);
+ cfaltwait(CF_S_READY);
+ }
+
+#ifdef DEBUG
+ rval = cfgetparams();
+ if (rval)
+ return;
+#endif
+ dskinf.use_lba = 1;
+ dskinf.debug = 0;
+}
+
+static void
+cf_clr(void)
+{
+ cfwrite8(CF_DRV_HEAD, CF_D_IBM);
+ cfaltwait(CF_S_READY);
+ cfwrite8(CF_FEATURE, 0x81); /* Enable 8 bit transfers */
+ cfwrite8(CF_COMMAND, ATA_SETFEATURES);
+ cfaltwait(CF_S_READY);
+}
+
+static void
+cfenable16(void)
+{
+ u_int32_t val;
+ volatile u_int32_t *cs;
+
+ if (board == BOARD_AVILA)
+ cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS1_OFFSET);
+ else
+ cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS3_OFFSET);
+ val = *cs;
+ *cs = val & (~1);
+ DPRINTF("cfenable16: cs1 timing reg %x\n", *cs);
+}
+
+static void
+cfdisable16(void)
+{
+ u_int32_t val;
+ volatile u_int32_t *cs;
+
+ if (board == BOARD_AVILA)
+ cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS1_OFFSET);
+ else
+ cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS3_OFFSET);
+ val = *cs;
+ *cs = val | 1;
+}
+
+static u_int8_t
+cfread8(u_int32_t off)
+{
+ volatile u_int8_t *vp;
+
+ vp = (volatile u_int8_t *)(dskinf.cs1 + off);
+ return *vp;
+}
+
+static void
+cfreadstream8(void *buf, int length)
+{
+ u_int8_t *lbuf;
+ u_int8_t tmp;
+
+ lbuf = buf;
+ while (length) {
+ tmp = cfread8(CF_DATA);
+ *lbuf = tmp;
+#ifdef DEBUG
+ if (dskinf.debug && (length > (512 - 32))) {
+ if ((length % 16) == 0)
+ xputchar('\n');
+ puthex8(tmp);
+ putchar(' ');
+ }
+#endif
+ lbuf++;
+ length--;
+ }
+#ifdef DEBUG
+ if (dskinf.debug)
+ xputchar('\n');
+#endif
+}
+
+static u_int16_t
+cfread16(u_int32_t off)
+{
+ volatile u_int16_t *vp;
+
+ vp = (volatile u_int16_t *)(dskinf.cs1 + off);
+ return swap16(*vp);
+}
+
+static void
+cfreadstream16(void *buf, int length)
+{
+ u_int16_t *lbuf;
+
+ length = length / 2;
+ cfenable16();
+ lbuf = buf;
+ while (length--) {
+ *lbuf = cfread16(CF_DATA);
+ lbuf++;
+ }
+ cfdisable16();
+}
+
+static void
+cfwrite8(u_int32_t off, u_int8_t val)
+{
+ volatile u_int8_t *vp;
+
+ vp = (volatile u_int8_t *)(dskinf.cs1 + off);
+ *vp = val;
+}
+
+#if 0
+static void
+cfwrite16(u_int32_t off, u_int16_t val)
+{
+ volatile u_int16_t *vp;
+
+ vp = (volatile u_int16_t *)(dskinf.cs1 + off);
+ *vp = val;
+}
+#endif
+
+static u_int8_t
+cfaltread8(u_int32_t off)
+{
+ volatile u_int8_t *vp;
+
+ off &= 0x0f;
+ vp = (volatile u_int8_t *)(dskinf.cs2 + off);
+ return *vp;
+}
+
+static void
+cfaltwrite8(u_int32_t off, u_int8_t val)
+{
+ volatile u_int8_t *vp;
+
+ /*
+ * This is documented in the Intel appnote 302456.
+ */
+ off &= 0x0f;
+ vp = (volatile u_int8_t *)(dskinf.cs2 + off);
+ *vp = val;
+}
+
+static int
+cfwait(u_int8_t mask)
+{
+ u_int8_t status;
+ u_int32_t tout;
+
+ tout = 0;
+ while (tout <= 5000000) {
+ status = cfread8(CF_STATUS);
+ if (status == 0xff) {
+ printf("cfwait: master: no status, reselecting\n");
+ cfwrite8(CF_DRV_HEAD, CF_D_IBM);
+ DELAY(1);
+ status = cfread8(CF_STATUS);
+ }
+ if (status == 0xff)
+ return -1;
+ dskinf.status = status;
+ if (!(status & CF_S_BUSY)) {
+ if (status & CF_S_ERROR)
+ dskinf.error = cfread8(CF_ERROR);
+ if ((status & mask) == mask) {
+ DPRINTF("cfwait: tout %u\n", tout);
+ return (status & CF_S_ERROR);
+ }
+ }
+ if (tout > 1000) {
+ tout += 1000;
+ DELAY(1000);
+ } else {
+ tout += 10;
+ DELAY(10);
+ }
+ }
+ return -1;
+}
+
+static int
+cfaltwait(u_int8_t mask)
+{
+ u_int8_t status;
+ u_int32_t tout;
+
+ tout = 0;
+ while (tout <= 5000000) {
+ status = cfaltread8(CF_ALT_STATUS);
+ if (status == 0xff) {
+ printf("cfaltwait: master: no status, reselectin\n");
+ cfwrite8(CF_DRV_HEAD, CF_D_IBM);
+ DELAY(1);
+ status = cfread8(CF_STATUS);
+ }
+ if (status == 0xff)
+ return -1;
+ dskinf.status = status;
+ if (!(status & CF_S_BUSY)) {
+ if (status & CF_S_ERROR)
+ dskinf.error = cfread8(CF_ERROR);
+ if ((status & mask) == mask) {
+ DPRINTF("cfaltwait: tout %u\n", tout);
+ return (status & CF_S_ERROR);
+ }
+ }
+ if (tout > 1000) {
+ tout += 1000;
+ DELAY(1000);
+ } else {
+ tout += 10;
+ DELAY(10);
+ }
+ }
+ return -1;
+}
+
+static int
+cfcmd(u_int32_t cmd, u_int32_t cylinder, u_int32_t head, u_int32_t sector,
+ u_int32_t count, u_int32_t feature)
+{
+ if (cfwait(0) < 0) {
+ printf("cfcmd: timeout\n");
+ return -1;
+ }
+ cfwrite8(CF_FEATURE, feature);
+ cfwrite8(CF_CYL_L, cylinder);
+ cfwrite8(CF_CYL_H, cylinder >> 8);
+ if (dskinf.use_lba)
+ cfwrite8(CF_DRV_HEAD, CF_D_IBM | CF_D_LBA | head);
+ else
+ cfwrite8(CF_DRV_HEAD, CF_D_IBM | head);
+ cfwrite8(CF_SECT_NUM, sector);
+ cfwrite8(CF_SECT_CNT, count);
+ cfwrite8(CF_COMMAND, cmd);
+ return 0;
+}
+
+static void
+cfreset(void)
+{
+ u_int8_t status;
+ u_int32_t tout;
+
+ cfwrite8(CF_DRV_HEAD, CF_D_IBM);
+ DELAY(1);
+#ifdef DEBUG
+ cfprintregs();
+#endif
+ cfread8(CF_STATUS);
+ cfaltwrite8(CF_ALT_DEV_CTR, CF_A_IDS | CF_A_RESET);
+ DELAY(10000);
+ cfaltwrite8(CF_ALT_DEV_CTR, CF_A_IDS);
+ DELAY(10000);
+ cfread8(CF_ERROR);
+ DELAY(3000);
+
+ for (tout = 0; tout < 310000; tout++) {
+ cfwrite8(CF_DRV_HEAD, CF_D_IBM);
+ DELAY(1);
+ status = cfread8(CF_STATUS);
+ if (!(status & CF_S_BUSY))
+ break;
+ DELAY(100);
+ }
+ DELAY(1);
+ if (status & CF_S_BUSY) {
+ cfprintregs();
+ printf("cfreset: Status stayed busy after reset.\n");
+ }
+ DPRINTF("cfreset: finished, tout %u\n", tout);
+}
+
+#ifdef DEBUG
+static int
+cfgetparams(void)
+{
+ u_int8_t *buf;
+
+ buf = (u_int8_t *)(0x170000);
+ p_memset((char *)buf, 0, 1024);
+ /* Select the drive. */
+ cfwrite8(CF_DRV_HEAD, CF_D_IBM);
+ DELAY(1);
+ cfcmd(ATA_ATA_IDENTIFY, 0, 0, 0, 0, 0);
+ if (cfaltwait(CF_S_READY | CF_S_DSC | CF_S_DRQ)) {
+ printf("cfgetparams: ATA_IDENTIFY failed.\n");
+ return -1;
+ }
+ if (dskinf.use_stream8)
+ cfreadstream8(buf, 512);
+ else
+ cfreadstream16(buf, 512);
+ if (dskinf.debug)
+ cfprintregs();
+#if 0
+ memcpy(&dskinf.ata_params, buf, sizeof(struct ata_params));
+ dskinf.cylinders = dskinf.ata_params.cylinders;
+ dskinf.heads = dskinf.ata_params.heads;
+ dskinf.sectors = dskinf.ata_params.sectors;
+ printf("dsk0: sec %x, hd %x, cyl %x, stat %x, err %x\n",
+ (u_int32_t)dskinf.ata_params.sectors,
+ (u_int32_t)dskinf.ata_params.heads,
+ (u_int32_t)dskinf.ata_params.cylinders,
+ (u_int32_t)dskinf.status,
+ (u_int32_t)dskinf.error);
+#endif
+ dskinf.status = cfread8(CF_STATUS);
+ if (dskinf.debug)
+ printf("cfgetparams: ata_params * %x, stat %x\n",
+ (u_int32_t)buf, (u_int32_t)dskinf.status);
+ return 0;
+}
+#endif /* DEBUG */
+
+static void
+cfprintregs(void)
+{
+ u_int8_t rv;
+
+ putstr("cfprintregs: regs error ");
+ rv = cfread8(CF_ERROR);
+ puthex8(rv);
+ putstr(", count ");
+ rv = cfread8(CF_SECT_CNT);
+ puthex8(rv);
+ putstr(", sect ");
+ rv = cfread8(CF_SECT_NUM);
+ puthex8(rv);
+ putstr(", cyl low ");
+ rv = cfread8(CF_CYL_L);
+ puthex8(rv);
+ putstr(", cyl high ");
+ rv = cfread8(CF_CYL_H);
+ puthex8(rv);
+ putstr(", drv head ");
+ rv = cfread8(CF_DRV_HEAD);
+ puthex8(rv);
+ putstr(", status ");
+ rv = cfread8(CF_STATUS);
+ puthex8(rv);
+ putstr("\n");
+}
+
+int
+avila_read(char *dest, unsigned source, unsigned length)
+{
+ if (dskinf.use_lba == 0 && source == 0)
+ source++;
+ if (dskinf.debug)
+ printf("avila_read: 0x%x, sect %d num secs %d\n",
+ (u_int32_t)dest, source, length);
+ while (length) {
+ cfwait(CF_S_READY);
+ /* cmd, cyl, head, sect, count, feature */
+ cfcmd(ATA_READ, (source >> 8) & 0xffff, source >> 24,
+ source & 0xff, 1, 0);
+
+ cfwait(CF_S_READY | CF_S_DRQ | CF_S_DSC);
+ if (dskinf.use_stream8)
+ cfreadstream8(dest, 512);
+ else
+ cfreadstream16(dest, 512);
+ length--;
+ source++;
+ dest += 512;
+ }
+ return 0;
+}
+
diff --git a/sys/boot/arm/ixp425/boot2/lib.h b/sys/boot/arm/ixp425/boot2/lib.h
new file mode 100644
index 0000000..7b39028
--- /dev/null
+++ b/sys/boot/arm/ixp425/boot2/lib.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2008 John Hay. 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 ``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 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$
+ */
+
+#ifndef ARM_BOOT_LIB_H
+#define ARM_BOOT_LIB_H
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+
+void DELAY(int);
+
+int getc(int);
+void putchar(int);
+void xputchar(int);
+void putstr(const char *);
+void puthex8(u_int8_t);
+void puthexlist(const u_int8_t *, int);
+void printf(const char *fmt,...);
+
+void bzero(void *, size_t);
+char *strcpy(char *to, const char *from);
+int strcmp(const char *to, const char *from);
+int p_strlen(const char *);
+int p_memcmp(const char *, const char *, unsigned);
+void *memchr(const void *, int, size_t);
+void memcpy(void *to, const void *from, unsigned size);
+void *memmem(const void *, size_t, const void *, size_t);
+void p_memset(char *buffer, char value, int size);
+
+#define strlen p_strlen
+#define memcmp p_memcmp
+#define memset p_memset
+
+u_int16_t swap16(u_int16_t);
+u_int32_t swap32(u_int32_t);
+
+const char *board_init(void);
+void clr_board(void);
+int avila_read(char*, unsigned, unsigned);
+
+#endif /* !ARM_BOOT_LIB_H */
OpenPOWER on IntegriCloud