/* $NetBSD: bootxx.c,v 1.21 2020/01/23 17:23:03 uwe 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 #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" " \n" "1: dcbf 0,%r8 \n" " icbi 0,%r8 \n" " addi %r8,%r8,0x20 \n" " bdnz 1b \n" " sync \n" " li %r0,0 \n" " \n" /* test for 601 cpu */ " mfspr %r9,287 \n" /* mfpvbr %r9 PVR = 287 */ " srwi %r9,%r9,0x10 \n" " cmplwi %r9,0x02 \n" /* 601 cpu == 0x0001 */ " blt 2f \n" /* skip over non-601 BAT setup */ " \n" " mtdbatu 3,%r0 \n" /* non-601 BAT */ " 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" " b 3f \n" " \n" "2: mfmsr %r8 \n" /* 601 BAT */ " mtmsr %r0 \n" " isync \n" " \n" " mtibatu 0,%r0 \n" " mtibatu 1,%r0 \n" " mtibatu 2,%r0 \n" " mtibatu 3,%r0 \n" " \n" " li %r9,0x7f \n" " mtibatl 0,%r9 \n" " li %r9,0x1a \n" " mtibatu 0,%r9 \n" " \n" " lis %r9,0x80 \n" " addi %r9,%r9,0x7f \n" " mtibatl 1,%r9 \n" " lis %r9,0x80 \n" " addi %r9,%r9,0x1a \n" " mtibatu 1,%r9 \n" " \n" " lis %r9,0x100 \n" " addi %r9,%r9,0x7f \n" " mtibatl 2,%r9 \n" " lis %r9,0x100 \n" " addi %r9,%r9,0x1a \n" " mtibatu 2,%r9 \n" " \n" " lis %r9,0x180 \n" " addi %r9,%r9,0x7f \n" " mtibatl 3,%r9 \n" " lis %r9,0x180 \n" " addi %r9,%r9,0x1a \n" " mtibatu 3,%r9 \n" " \n" " isync \n" " \n" " mtmsr %r8 \n" " isync \n" " \n" /* * setup 32 KB of stack with 32 bytes overpad (see above) */ "3: lis %r1,(stack+32768)@ha\n" " addi %r1,%r1,(stack+32768)@l\n" /* * terminate the frame link chain, * clear by bytes to avoid ppc601 alignment exceptions */ " stb %r0,0(%r1) \n" " stb %r0,1(%r1) \n" " stb %r0,2(%r1) \n" " stb %r0,3(%r1) \n" " 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; static 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; uint32_t cpuvers; size_t i; char *addr; char bootpath[128]; __asm volatile ("mfpvr %0" : "=r"(cpuvers)); cpuvers >>= 16; 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"); if (cpuvers != MPC601) { /* * 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 */ }