/* $NetBSD: Locore.c,v 1.35 2021/02/28 20:27:40 thorpej 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 #include "openfirm.h" static int (*openfirmware)(void *); static void startup(void *, int, int (*)(void *), char *, int) __attribute__((__used__)); static void setup(void); #ifdef HEAP_VARIABLE #ifndef HEAP_SIZE #define HEAP_SIZE 0x20000 #endif char *heapspace; #endif static int stack[8192/4 + 4] __attribute__((__used__)); #ifdef XCOFF_GLUE __asm( " .text \n" " .globl _entry \n" "_entry: \n" " .long _start,0,0 \n" ); #endif /* XCOFF_GLUE */ __asm( " .text \n" " .globl _start \n" "_start: \n" " sync \n" " isync \n" " lis %r1,stack@ha \n" " addi %r1,%r1,stack@l \n" " addi %r1,%r1,8192 \n" " \n" " mfmsr %r8 \n" " li %r0,0 \n" " mtmsr %r0 \n" " isync \n" " \n" " \n" /* test for 601 */ " mfspr %r0,287 \n" /* mfpvbr %r0 PVR = 287 */ " srwi %r0,%r0,0x10 \n" " cmplwi %r0,0x02 \n" /* 601 CPU = 0x0001 */ " blt 2f \n" /* skip over non-601 BAT setup */ " cmplwi %r0,0x39 \n" /* PPC970 */ " blt 0f \n" " cmplwi %r0,0x45 \n" /* PPC970GX */ " ble 1f \n" /* non PPC 601 BATs */ "0: li %r0,0 \n" " mtibatu 0,%r0 \n" " mtibatu 1,%r0 \n" " mtibatu 2,%r0 \n" " mtibatu 3,%r0 \n" " mtdbatu 0,%r0 \n" " mtdbatu 1,%r0 \n" " mtdbatu 2,%r0 \n" " mtdbatu 3,%r0 \n" " \n" " li %r9,0x12 \n" /* BATL(0, BAT_M, BAT_PP_RW) */ " mtibatl 0,%r9 \n" " mtdbatl 0,%r9 \n" " li %r9,0x1ffe \n" /* BATU(0, BAT_BL_256M, BAT_Vs) */ " mtibatu 0,%r9 \n" " mtdbatu 0,%r9 \n" " b 3f \n" /* 970 initialization stuff */ "1: \n" /* make sure we're in bridge mode */ " clrldi %r8,%r8,3 \n" " mtmsrd %r8 \n" " isync \n" /* clear HID5 DCBZ bits (56/57), need to do this early */ " mfspr %r9,0x3f6 \n" " rldimi %r9,0,6,56 \n" " sync \n" " mtspr 0x3f6,%r9 \n" " isync \n" " sync \n" /* Setup HID1 features, prefetch + i-cacheability controlled by PTE */ " mfspr %r9,0x3f1 \n" " li %r11,0x1200 \n" " sldi %r11,%r11,44 \n" " or %r9,%r9,%r11 \n" " mtspr 0x3f1,%r9 \n" " isync \n" " sync \n" " b 3f \n" /* PPC 601 BATs */ "2: li %r0,0 \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" "3: isync \n" " \n" " mtmsr %r8 \n" " isync \n" " \n" /* * Make sure that .bss is zeroed */ " \n" " li %r0,0 \n" " lis %r8,_edata@ha \n" " addi %r8,%r8,_edata@l\n" " lis %r9,_end@ha \n" " addi %r9,%r9,_end@l \n" " \n" "5: cmpw 0,%r8,%r9 \n" " bge 6f \n" /* * clear by bytes to avoid ppc601 alignment exceptions */ " stb %r0,0(%r8) \n" " stb %r0,1(%r8) \n" " stb %r0,2(%r8) \n" " stb %r0,3(%r8) \n" " addi %r8,%r8,4 \n" " b 5b \n" " \n" "6: b startup \n" ); #if 0 static int openfirmware(void *arg) { __asm volatile ("sync; isync"); openfirmware_entry(arg); __asm volatile ("sync; isync"); } #endif int ofw_real_mode; int ofw_address_cells; int ofw_size_cells; int ofw_root; /* / */ int ofw_options; /* /options */ int ofw_openprom; /* /openprom */ int ofw_chosen; /* /chosen (package) */ int ofw_stdin; /* /chosen/stdin */ int ofw_stdout; /* /chosen/stdout */ int ofw_memory_ihandle; /* /chosen/memory */ int ofw_mmu_ihandle; /* /chosen/mmu */ bool ofw_option_truefalse(const char *prop, int proplen) { /* These are all supposed to be strings. */ switch (prop[0]) { case 'y': case 'Y': case 't': case 'T': case '1': return true; } return false; } static void startup(void *vpd, int res, int (*openfirm)(void *), char *arg, int argl) { openfirmware = openfirm; setup(); main(); OF_exit(); } #if 0 void OF_enter(void) { static struct { const char *name; int nargs; int nreturns; } args = { "enter", 0, 0 }; openfirmware(&args); } #endif /* OF_enter */ __dead void OF_exit(void) { static struct { const char *name; int nargs; int nreturns; } args = { "exit", 0, 0 }; openfirmware(&args); for (;;); /* just in case */ } int OF_finddevice(const char *name) { static struct { const char *name; int nargs; int nreturns; const char *device; int phandle; } args = { "finddevice", 1, 1, }; args.device = name; if (openfirmware(&args) == -1) return -1; return args.phandle; } int OF_instance_to_package(int ihandle) { static struct { const char *name; int nargs; int nreturns; int ihandle; int phandle; } args = { "instance-to-package", 1, 1, }; args.ihandle = ihandle; if (openfirmware(&args) == -1) return -1; return args.phandle; } int OF_getprop(int handle, const char *prop, void *buf, int buflen) { static struct { const char *name; int nargs; int nreturns; int phandle; const char *prop; void *buf; int buflen; int size; } args = { "getprop", 4, 1, }; args.phandle = handle; args.prop = prop; args.buf = buf; args.buflen = buflen; if (openfirmware(&args) == -1) return -1; return args.size; } #ifdef __notyet__ /* Has a bug on FirePower */ int OF_setprop(int handle, const char *prop, void *buf, int len) { static struct { const char *name; int nargs; int nreturns; int phandle; const char *prop; void *buf; int len; int size; } args = { "setprop", 4, 1, }; args.phandle = handle; args.prop = prop; args.buf = buf; args.len = len; if (openfirmware(&args) == -1) return -1; return args.size; } #endif int OF_open(const char *dname) { static struct { const char *name; int nargs; int nreturns; const char *dname; int handle; } args = { "open", 1, 1, }; #ifdef OFW_DEBUG printf("OF_open(%s) -> ", dname); #endif args.dname = dname; if (openfirmware(&args) == -1 || args.handle == 0) { #ifdef OFW_DEBUG printf("lose\n"); #endif return -1; } #ifdef OFW_DEBUG printf("%d\n", args.handle); #endif return args.handle; } void OF_close(int handle) { static struct { const char *name; int nargs; int nreturns; int handle; } args = { "close", 1, 0, }; #ifdef OFW_DEBUG printf("OF_close(%d)\n", handle); #endif args.handle = handle; openfirmware(&args); } int OF_write(int handle, void *addr, int len) { static struct { const char *name; int nargs; int nreturns; int ihandle; void *addr; int len; int actual; } args = { "write", 3, 1, }; #ifdef OFW_DEBUG if (len != 1) printf("OF_write(%d, %p, %x) -> ", handle, addr, len); #endif args.ihandle = handle; args.addr = addr; args.len = len; if (openfirmware(&args) == -1) { #ifdef OFW_DEBUG printf("lose\n"); #endif return -1; } #ifdef OFW_DEBUG if (len != 1) printf("%x\n", args.actual); #endif return args.actual; } int OF_read(int handle, void *addr, int len) { static struct { const char *name; int nargs; int nreturns; int ihandle; void *addr; int len; int actual; } args = { "read", 3, 1, }; #ifdef OFW_DEBUG if (len != 1) printf("OF_read(%d, %p, %x) -> ", handle, addr, len); #endif args.ihandle = handle; args.addr = addr; args.len = len; if (openfirmware(&args) == -1) { #ifdef OFW_DEBUG printf("lose\n"); #endif return -1; } #ifdef OFW_DEBUG if (len != 1) printf("%x\n", args.actual); #endif return args.actual; } int OF_seek(int handle, u_quad_t pos) { static struct { const char *name; int nargs; int nreturns; int handle; int poshi; int poslo; int status; } args = { "seek", 3, 1, }; #ifdef OFW_DEBUG printf("OF_seek(%d, %x, %x) -> ", handle, (int)(pos >> 32), (int)pos); #endif args.handle = handle; args.poshi = (int)(pos >> 32); args.poslo = (int)pos; if (openfirmware(&args) == -1) { #ifdef OFW_DEBUG printf("lose\n"); #endif return -1; } #ifdef OFW_DEBUG printf("%d\n", args.status); #endif return args.status; } void * OF_claim(void *virt, u_int size, u_int align) { static struct { const char *name; int nargs; int nreturns; void *virt; u_int size; u_int align; void *baseaddr; } args = { "claim", 3, 1, }; #ifdef OFW_DEBUG printf("OF_claim(%p, %x, %x) -> ", virt, size, align); #endif args.virt = virt; args.size = size; args.align = align; if (openfirmware(&args) == -1) { #ifdef OFW_DEBUG printf("lose\n"); #endif return (void *)-1; } #ifdef OFW_DEBUG printf("%p\n", args.baseaddr); #endif return args.baseaddr; } void OF_release(void *virt, u_int size) { static struct { const char *name; int nargs; int nreturns; void *virt; u_int size; } args = { "release", 2, 0, }; #ifdef OFW_DEBUG printf("OF_release(%p, %x)\n", virt, size); #endif args.virt = virt; args.size = size; openfirmware(&args); } int OF_milliseconds(void) { static struct { const char *name; int nargs; int nreturns; int ms; } args = { "milliseconds", 0, 1, }; openfirmware(&args); return args.ms; } #ifdef __notyet__ void OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len) { static struct { const char *name; int nargs; int nreturns; void *virt; u_int size; void (*entry)(); void *arg; u_int len; } args = { "chain", 5, 0, }; args.virt = virt; args.size = size; args.entry = entry; args.arg = arg; args.len = len; openfirmware(&args); } #else void OF_chain(void *virt, u_int size, boot_entry_t entry, void *arg, u_int len) { /* * This is a REALLY dirty hack till the firmware gets this going */ #if 0 OF_release(virt, size); #endif entry(0, 0, openfirmware, arg, len); } #endif int OF_call_method(const char *method, int ihandle, int nargs, int nreturns, int *cells) { static struct { const char *name; int nargs; int nreturns; const char *method; int ihandle; int args_n_results[12]; } args = { "call-method", 2, 1, }; int *ip, n; if (nargs > 6) return -1; args.nargs = nargs + 2; args.nreturns = nreturns + 1; args.method = method; args.ihandle = ihandle; for (ip = args.args_n_results + (n = nargs); --n >= 0;) *--ip = *cells++; if (openfirmware(&args) == -1) { return -1; } if (args.args_n_results[nargs]) { return args.args_n_results[nargs]; } for (ip = args.args_n_results + nargs + (n = args.nreturns); --n > 0;) *cells++ = *--ip; return 0; } static void setup(void) { char prop[32]; int proplen; const char *reason = NULL; if ((ofw_chosen = OF_finddevice("/chosen")) == -1) OF_exit(); if (OF_getprop(ofw_chosen, "stdin", &ofw_stdin, sizeof(ofw_stdin)) != sizeof(ofw_stdin) || OF_getprop(ofw_chosen, "stdout", &ofw_stdout, sizeof(ofw_stdout)) != sizeof(ofw_stdout)) OF_exit(); if (ofw_stdout == 0) { /* screen should be console, but it is not open */ ofw_stdout = OF_open("screen"); } #ifdef HEAP_VARIABLE uint32_t pvr, vers, hsize = HEAP_SIZE; __asm volatile ("mfpvr %0" : "=r"(pvr)); vers = pvr >> 16; if (vers >= IBM970 && vers <= IBM970GX) hsize = 0x800000; heapspace = OF_claim(0, hsize, NBPG); if (heapspace == (char *)-1) { panic("Failed to allocate heap"); } setheap(heapspace, heapspace + HEAP_SIZE); #endif /* HEAP_VARIABLE */ ofw_root = OF_finddevice("/"); ofw_options = OF_finddevice("/options"); ofw_openprom = OF_finddevice("/openprom"); ofw_chosen = OF_finddevice("/chosen"); if (ofw_root == -1) { reason = "No root node"; goto bad_environment; } if (ofw_chosen == -1) { reason = "No chosen node"; goto bad_environment; } if (ofw_options != -1) { proplen = OF_getprop(ofw_options, "real-mode?", prop, sizeof(prop)); if (proplen > 0) { ofw_real_mode = ofw_option_truefalse(prop, proplen); } } /* * Get #address-cells and #size-cells. */ ofw_address_cells = 1; ofw_size_cells = 1; OF_getprop(ofw_root, "#address-cells", &ofw_address_cells, sizeof(ofw_address_cells)); OF_getprop(ofw_root, "#size-cells", &ofw_size_cells, sizeof(ofw_size_cells)); /* See loadfile_machdep.c */ if (ofw_size_cells != 1) { printf("#size-cells = %d not yet supported\n", ofw_size_cells); reason = "unsupported #size-cells"; goto bad_environment; } /* * Get the ihandle on /chosen/memory and /chosen/mmu. */ ofw_memory_ihandle = -1; ofw_mmu_ihandle = -1; OF_getprop(ofw_chosen, "memory", &ofw_memory_ihandle, sizeof(ofw_memory_ihandle)); OF_getprop(ofw_chosen, "mmu", &ofw_mmu_ihandle, sizeof(ofw_mmu_ihandle)); if (ofw_memory_ihandle == -1) { reason = "no /chosen/memory"; goto bad_environment; } if (ofw_mmu_ihandle == -1) { reason = "no /chosen/mmu"; goto bad_environment; } return; bad_environment: if (reason == NULL) { reason = "unknown reason"; } printf("Invalid Openfirmware environment: %s\n", reason); OF_exit(); } void putchar(int c) { char ch = c; if (c == '\n') putchar('\r'); OF_write(ofw_stdout, &ch, 1); } int getchar(void) { unsigned char ch = '\0'; int l; while ((l = OF_read(ofw_stdin, &ch, 1)) != 1) if (l != -2 && l != 0) return -1; return ch; }