/* $NetBSD: bootxx.c,v 1.18 2009/03/14 21:04:12 dsl Exp $ */ /* * Copyright (C) 1995, 1996 Wolfgang Solfrank. * Copyright (C) 1995, 1996 TooLs GmbH. * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 #include #include int (*openfirmware)(void *); /* * 32 KB of stack with 32 bytes overpad * (see below) */ int32_t __attribute__((aligned(16))) stack[8192 + 8]; struct shared_bbinfo bbinfo = { { MACPPC_BBINFO_MAGIC }, 0, SHARED_BBINFO_MAXBLOCKS, { 0 } }; #ifndef DEFAULT_ENTRY_POINT #define DEFAULT_ENTRY_POINT 0xE00000 #endif void (*entry_point)(int, int, void *) = (void *)DEFAULT_ENTRY_POINT; __asm( " .text \n" " .align 2 \n" " .globl _start \n" "_start: \n" " lis %r8,(_start)@ha \n" " addi %r8,8,(_start)@l\n" " li %r9,0x40 \n" /* loop 64 times (for 2048 bytes of bootxx) */ " mtctr %r9 \n" "1: \n" " dcbf %r0,%r8 \n" " icbi %r0,%r8 \n" " addi %r8,%r8,0x20 \n" " bdnz 1b \n" " sync \n" " li %r0,0 \n" " mtdbatu 3,%r0 \n" " mtibatu 3,%r0 \n" " isync \n" " li %r8,0x1ffe \n" /* map the lowest 256MB */ " li %r9,0x22 \n" /* BAT_I */ " mtdbatl 3,%r9 \n" " mtdbatu 3,%r8 \n" " mtibatl 3,%r9 \n" " mtibatu 3,%r8 \n" " isync \n" /* * setup 32 KB of stack with 32 bytes overpad (see above) */ " lis %r1,(stack+32768)@ha\n" " addi %r1,%r1,(stack+32768)@l\n" " stw %r0,0(%r1) \n" /* terminate the frame link chain */ " b startup \n" ); static inline int OF_finddevice(char *name) { static struct { char *name; int nargs; int nreturns; char *device; int phandle; } args = { "finddevice", 1, 1, }; args.device = name; openfirmware(&args); return args.phandle; } static inline int OF_getprop(int handle, char *prop, void *buf, int buflen) { static struct { char *name; int nargs; int nreturns; int phandle; char *prop; void *buf; int buflen; int size; } args = { "getprop", 4, 1, }; args.phandle = handle; args.prop = prop; args.buf = buf; args.buflen = buflen; openfirmware(&args); return args.size; } static inline int OF_open(char *dname) { static struct { char *name; int nargs; int nreturns; char *dname; int handle; } args = { "open", 1, 1, }; args.dname = dname; openfirmware(&args); return args.handle; } static inline int OF_read(int handle, void *addr, int len) { static struct { char *name; int nargs; int nreturns; int ihandle; void *addr; int len; int actual; } args = { "read", 3, 1, }; args.ihandle = handle; args.addr = addr; args.len = len; openfirmware(&args); return args.actual; } static inline int OF_seek(int handle, u_quad_t pos) { static struct { char *name; int nargs; int nreturns; int handle; int poshi; int poslo; int status; } args = { "seek", 3, 1, }; args.handle = handle; args.poshi = (int)(pos >> 32); args.poslo = (int)pos; openfirmware(&args); return args.status; } static inline int OF_write(int handle, const void *addr, int len) { static struct { char *name; int nargs; int nreturns; int ihandle; const void *addr; int len; int actual; } args = { "write", 3, 1, }; args.ihandle = handle; args.addr = addr; args.len = len; openfirmware(&args); return args.actual; } int stdout; void putstrn(const char *s, size_t n) { OF_write(stdout, s, n); } #define putstr(x) putstrn((x),sizeof(x)-1) #define putc(x) do { char __x = (x) ; putstrn(&__x, 1); } while (0) void startup(int arg1, int arg2, void *openfirm) { int fd, blk, chosen, options, j; size_t i; char *addr; char bootpath[128]; openfirmware = openfirm; chosen = OF_finddevice("/chosen"); if (OF_getprop(chosen, "bootpath", bootpath, sizeof(bootpath)) == 1) { /* * buggy firmware doesn't set bootpath... */ options = OF_finddevice("/options"); OF_getprop(options, "boot-device", bootpath, sizeof(bootpath)); } if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) != sizeof(stdout)) stdout = -1; /* * "scsi/sd@0:0" --> "scsi/sd@0" */ for (i = 0; i < sizeof(bootpath); i++) { if (bootpath[i] == ':') bootpath[i] = 0; if (bootpath[i] == 0) break; } putstr("\r\nOF_open bootpath="); putstrn(bootpath, i); fd = OF_open(bootpath); addr = (char *)entry_point; putstr("\r\nread stage 2 blocks: "); for (j = 0; j < bbinfo.bbi_block_count; j++) { if ((blk = bbinfo.bbi_block_table[j]) == 0) break; putc('0' + j % 10); OF_seek(fd, (u_quad_t)blk * 512); OF_read(fd, addr, bbinfo.bbi_block_size); addr += bbinfo.bbi_block_size; } putstr(". done!\r\nstarting stage 2...\r\n"); /* * enable D/I cache */ __asm( "mtdbatu 3,%0\n\t" "mtdbatl 3,%1\n\t" "mtibatu 3,%0\n\t" "mtibatl 3,%1\n\t" "isync" :: "r"(BATU(0, BAT_BL_256M, BAT_Vs)), "r"(BATL(0, 0, BAT_PP_RW))); entry_point(0, 0, openfirm); for (;;); /* just in case */ }