Date: Thu, 2 Jun 2011 14:12:37 +0000 (UTC) From: Nathan Whitehorn <nwhitehorn@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r222613 - in head/sys/powerpc: aim include ofw Message-ID: <201106021412.p52ECbaK020881@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: nwhitehorn Date: Thu Jun 2 14:12:37 2011 New Revision: 222613 URL: http://svn.freebsd.org/changeset/base/222613 Log: MFpseries: Renovate and improve the AIM Open Firmware support: - Add RTAS (Run-Time Abstraction Services) support, found on all IBM systems and some Apple ones - Improve support for 32-bit real mode Open Firmware systems - Pull some more OF bits over from the AIM directory - Fix memory detection on IBM LPARs and systems with more than one /memory node (by andreast@) Added: head/sys/powerpc/include/rtas.h (contents, props changed) head/sys/powerpc/ofw/ofwcall32.S (contents, props changed) head/sys/powerpc/ofw/ofwcall64.S (contents, props changed) head/sys/powerpc/ofw/ofwmagic.S - copied unchanged from r222507, head/sys/powerpc/aim/ofwmagic.S head/sys/powerpc/ofw/rtas.c (contents, props changed) Deleted: head/sys/powerpc/aim/ofwmagic.S Modified: head/sys/powerpc/aim/locore32.S head/sys/powerpc/aim/locore64.S head/sys/powerpc/ofw/ofw_machdep.c head/sys/powerpc/ofw/ofw_real.c Modified: head/sys/powerpc/aim/locore32.S ============================================================================== --- head/sys/powerpc/aim/locore32.S Thu Jun 2 14:09:30 2011 (r222612) +++ head/sys/powerpc/aim/locore32.S Thu Jun 2 14:12:37 2011 (r222613) @@ -87,9 +87,6 @@ GLOBAL(tmpstk) GLOBAL(esym) .long 0 /* end of symbol table */ -GLOBAL(ofmsr) - .long 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */ - #define INTRCNT_COUNT 256 /* max(HROWPIC_IRQMAX,OPENPIC_IRQMAX) */ GLOBAL(intrnames) .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 @@ -99,16 +96,6 @@ GLOBAL(intrcnt) .space INTRCNT_COUNT * 4 * 2 GLOBAL(eintrcnt) -/* - * File-scope for locore.S - */ -idle_u: - .long 0 /* fake uarea during idle after exit */ -openfirmware_entry: - .long 0 /* Open Firmware entry point */ -srsave: - .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - .text .globl btext btext: Modified: head/sys/powerpc/aim/locore64.S ============================================================================== --- head/sys/powerpc/aim/locore64.S Thu Jun 2 14:09:30 2011 (r222612) +++ head/sys/powerpc/aim/locore64.S Thu Jun 2 14:12:37 2011 (r222613) @@ -76,7 +76,6 @@ .set kernbase, KERNBASE #define TMPSTKSZ 8192 /* 8K temporary stack */ -#define OFWSTKSZ 4096 /* 4K Open Firmware stack */ /* * Globals @@ -85,14 +84,9 @@ .align 4 GLOBAL(tmpstk) .space TMPSTKSZ -GLOBAL(ofwstk) - .space OFWSTKSZ GLOBAL(esym) .llong 0 /* end of symbol table */ -GLOBAL(ofmsr) - .llong 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */ - #define INTRCNT_COUNT 256 /* max(HROWPIC_IRQMAX,OPENPIC_IRQMAX) */ GLOBAL(intrnames) .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 @@ -102,16 +96,6 @@ GLOBAL(intrcnt) .space INTRCNT_COUNT * 4 * 2 GLOBAL(eintrcnt) -/* - * File-scope for locore.S - */ -idle_u: - .llong 0 /* fake uarea during idle after exit */ -openfirmware_entry: - .llong 0 /* Open Firmware entry point */ -srsave: - .llong 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - .text .globl btext btext: @@ -208,122 +192,6 @@ tocbase: .llong .TOC.@tocbase /* - * Open Firmware Real-mode Entry Point. This is a huge pain. - */ - -ASENTRY(ofw_32bit_mode_entry) - mflr %r0 - std %r0,16(%r1) - stdu %r1,-208(%r1) - - /* - * We need to save the following, because OF's register save/ - * restore code assumes that the contents of registers are - * at most 32 bits wide: lr, cr, r2, r13-r31, the old MSR. These - * get placed in that order in the stack. - */ - - mfcr %r4 - std %r4,48(%r1) - std %r13,56(%r1) - std %r14,64(%r1) - std %r15,72(%r1) - std %r16,80(%r1) - std %r17,88(%r1) - std %r18,96(%r1) - std %r19,104(%r1) - std %r20,112(%r1) - std %r21,120(%r1) - std %r22,128(%r1) - std %r23,136(%r1) - std %r24,144(%r1) - std %r25,152(%r1) - std %r26,160(%r1) - std %r27,168(%r1) - std %r28,176(%r1) - std %r29,184(%r1) - std %r30,192(%r1) - std %r31,200(%r1) - - /* Record the old MSR */ - mfmsr %r6 - - /* read client interface handler */ - lis %r4,openfirmware_entry@ha - ld %r4,openfirmware_entry@l(%r4) - - /* - * Set the MSR to the OF value. This has the side effect of disabling - * exceptions, which is important for the next few steps. - */ - - lis %r5,ofmsr@ha - ld %r5,ofmsr@l(%r5) - mtmsrd %r5 - isync - - /* - * Set up OF stack. This needs to be accessible in real mode and - * use the 32-bit ABI stack frame format. The pointer to the current - * kernel stack is placed at the very top of the stack along with - * the old MSR so we can get them back later. - */ - mr %r5,%r1 - lis %r1,(ofwstk+OFWSTKSZ-32)@ha - addi %r1,%r1,(ofwstk+OFWSTKSZ-32)@l - std %r5,8(%r1) /* Save real stack pointer */ - std %r2,16(%r1) /* Save old TOC */ - std %r6,24(%r1) /* Save old MSR */ - li %r5,0 - stw %r5,4(%r1) - stw %r5,0(%r1) - - /* Finally, branch to OF */ - mtctr %r4 - bctrl - - /* Reload stack pointer and MSR from the OFW stack */ - ld %r6,24(%r1) - ld %r2,16(%r1) - ld %r1,8(%r1) - - /* Now set the real MSR */ - mtmsrd %r6 - isync - - /* Sign-extend the return value from OF */ - extsw %r3,%r3 - - /* Restore all the non-volatile registers */ - ld %r5,48(%r1) - mtcr %r5 - ld %r13,56(%r1) - ld %r14,64(%r1) - ld %r15,72(%r1) - ld %r16,80(%r1) - ld %r17,88(%r1) - ld %r18,96(%r1) - ld %r19,104(%r1) - ld %r20,112(%r1) - ld %r21,120(%r1) - ld %r22,128(%r1) - ld %r23,136(%r1) - ld %r24,144(%r1) - ld %r25,152(%r1) - ld %r26,160(%r1) - ld %r27,168(%r1) - ld %r28,176(%r1) - ld %r29,184(%r1) - ld %r30,192(%r1) - ld %r31,200(%r1) - - /* Restore the stack and link register */ - ld %r1,0(%r1) - ld %r0,16(%r1) - mtlr %r0 - blr - -/* * int setfault() * * Similar to setjmp to setup for handling faults on accesses to user memory. Added: head/sys/powerpc/include/rtas.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/powerpc/include/rtas.h Thu Jun 2 14:12:37 2011 (r222613) @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2011 Nathan Whitehorn + * 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$ + */ + +#ifndef _MACHINE_RTAS_H_ +#define _MACHINE_RTAS_H_ + +#include <sys/cdefs.h> +#include <sys/types.h> +#include <dev/ofw/openfirm.h> + +/* + * RTAS functions are defined by 32-bit integer tokens. These vary from + * system to system, and can be looked up from their standardized names + * using rtas_token_lookup(). If RTAS is not available, rtas_token_lookup() + * and rtas_call_method() return -1; this can be checked in advance using + * rtas_exists(). Otherwise, rtas_call_method() returns one of the RTAS + * status codes from the bottom of this file. + */ + +int rtas_exists(void); +int rtas_call_method(cell_t token, int nargs, int nreturns, ...); +cell_t rtas_token_lookup(const char *method); + +/* RTAS Status Codes: see CHRP or PAPR specification */ +#define RTAS_OK 0 +#define RTAS_HW_ERROR -1 +#define RTAS_BUSY -2 +#define RTAS_PARAM_ERROR -3 +#define RTAS_STATE_CHANGE -7 +#define RTAS_VENDOR_BEGIN 9000 +#define RTAS_EXTENDED_DELAY 9900 +#define RTAS_ISOLATION_ERROR -9000 +#define RTAS_VENDOR_ERROR_BEGIN -9004 + +#endif /* _MACHINE_RTAS_H_ */ + Modified: head/sys/powerpc/ofw/ofw_machdep.c ============================================================================== --- head/sys/powerpc/ofw/ofw_machdep.c Thu Jun 2 14:09:30 2011 (r222612) +++ head/sys/powerpc/ofw/ofw_machdep.c Thu Jun 2 14:12:37 2011 (r222613) @@ -60,17 +60,15 @@ __FBSDID("$FreeBSD$"); #include <machine/platform.h> #include <machine/ofw_machdep.h> -#define OFMEM_REGIONS 32 -static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3]; -static struct mem_region OFfree[OFMEM_REGIONS + 3]; -static int nOFmem; +static struct mem_region OFmem[PHYS_AVAIL_SZ], OFavail[PHYS_AVAIL_SZ]; +static struct mem_region OFfree[PHYS_AVAIL_SZ]; extern register_t ofmsr[5]; -static int (*ofwcall)(void *); +extern void *openfirmware_entry; static void *fdt; int ofw_real_mode; -int ofw_32bit_mode_entry(void *); +int ofwcall(void *); static void ofw_quiesce(void); static int openfirmware(void *args); @@ -134,11 +132,32 @@ memr_merge(struct mem_region *from, stru to->mr_size = end - to->mr_start; } +/* + * Quick sort callout for comparing memory regions. + */ +static int mr_cmp(const void *a, const void *b); + +static int +mr_cmp(const void *a, const void *b) +{ + const struct mem_region *regiona; + const struct mem_region *regionb; + + regiona = a; + regionb = b; + if (regiona->mr_start < regionb->mr_start) + return (-1); + else if (regiona->mr_start > regionb->mr_start) + return (1); + else + return (0); +} + static int parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) { cell_t address_cells, size_cells; - cell_t OFmem[4*(OFMEM_REGIONS + 1)]; + cell_t OFmem[4 * PHYS_AVAIL_SZ]; int sz, i, j; int apple_hack_mode; phandle_t phandle; @@ -175,7 +194,7 @@ parse_ofw_memory(phandle_t node, const c * Get memory. */ if ((node == -1) || (sz = OF_getprop(node, prop, - OFmem, sizeof(OFmem[0]) * 4 * OFMEM_REGIONS)) <= 0) + OFmem, sizeof(OFmem[0]) * 4 * PHYS_AVAIL_SZ)) <= 0) panic("Physical memory map not found"); i = 0; @@ -225,7 +244,7 @@ parse_ofw_memory(phandle_t node, const c #ifdef __powerpc64__ if (apple_hack_mode) { /* Add in regions above 4 GB to the available list */ - struct mem_region himem[OFMEM_REGIONS]; + struct mem_region himem[PHYS_AVAIL_SZ]; int hisz; hisz = parse_ofw_memory(node, "reg", himem); @@ -243,6 +262,81 @@ parse_ofw_memory(phandle_t node, const c return (sz); } +static int +parse_drconf_memory(int *msz, int *asz, struct mem_region *ofmem, + struct mem_region *ofavail) +{ + phandle_t phandle; + vm_offset_t base; + int i, idx, len, lasz, lmsz, res; + uint32_t lmb_size[2]; + unsigned long *dmem, flags; + + lmsz = *msz; + lasz = *asz; + + phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory"); + if (phandle == -1) + /* No drconf node, return. */ + return (0); + + res = OF_getprop(phandle, "ibm,lmb-size", lmb_size, sizeof(lmb_size)); + if (res == -1) + return (0); + + /* Parse the /ibm,dynamic-memory. + The first position gives the # of entries. The next two words + reflect the address of the memory block. The next four words are + the DRC index, reserved, list index and flags. + (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory) + + #el Addr DRC-idx res list-idx flags + ------------------------------------------------- + | 4 | 8 | 4 | 4 | 4 | 4 |.... + ------------------------------------------------- + */ + + len = OF_getproplen(phandle, "ibm,dynamic-memory"); + if (len > 0) { + + /* We have to use a variable length array on the stack + since we have very limited stack space. + */ + cell_t arr[len/sizeof(cell_t)]; + + res = OF_getprop(phandle, "ibm,dynamic-memory", &arr, + sizeof(arr)); + if (res == -1) + return (0); + + /* Number of elements */ + idx = arr[0]; + + /* First address. */ + dmem = (void*)&arr[1]; + + for (i = 0; i < idx; i++) { + base = *dmem; + dmem += 2; + flags = *dmem; + /* Use region only if available and not reserved. */ + if ((flags & 0x8) && !(flags & 0x80)) { + ofmem[lmsz].mr_start = base; + ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1]; + ofavail[lasz].mr_start = base; + ofavail[lasz].mr_size = (vm_size_t)lmb_size[1]; + lmsz++; + lasz++; + } + dmem++; + } + } + + *msz = lmsz; + *asz = lasz; + + return (1); +} /* * This is called during powerpc_init, before the system is really initialized. * It shall provide the total and the available regions of RAM. @@ -255,31 +349,62 @@ ofw_mem_regions(struct mem_region **memp struct mem_region **availp, int *availsz) { phandle_t phandle; + vm_offset_t maxphysaddr; int asz, msz, fsz; - int i, j; + int i, j, res; int still_merging; + char name[31]; asz = msz = 0; /* - * Get memory. + * Get memory from all the /memory nodes. */ - phandle = OF_finddevice("/memory"); - if (phandle == -1) - phandle = OF_finddevice("/memory@0"); + for (phandle = OF_child(OF_peer(0)); phandle != 0; + phandle = OF_peer(phandle)) { + if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) + continue; + if (strncmp(name, "memory", sizeof(name)) != 0) + continue; + + res = parse_ofw_memory(phandle, "reg", &OFmem[msz]); + msz += res/sizeof(struct mem_region); + if (OF_getproplen(phandle, "available") >= 0) + res = parse_ofw_memory(phandle, "available", + &OFavail[asz]); + else + res = parse_ofw_memory(phandle, "reg", &OFavail[asz]); + asz += res/sizeof(struct mem_region); + } - msz = parse_ofw_memory(phandle, "reg", OFmem); - nOFmem = msz / sizeof(struct mem_region); - asz = parse_ofw_memory(phandle, "available", OFavail); + /* Check for memory in ibm,dynamic-reconfiguration-memory */ + parse_drconf_memory(&msz, &asz, OFmem, OFavail); + + qsort(OFmem, msz, sizeof(*OFmem), mr_cmp); + qsort(OFavail, asz, sizeof(*OFavail), mr_cmp); *memp = OFmem; - *memsz = nOFmem; - + *memsz = msz; + + /* + * On some firmwares (SLOF), some memory may be marked available that + * doesn't actually exist. This manifests as an extension of the last + * available segment past the end of physical memory, so truncate that + * one. + */ + maxphysaddr = 0; + for (i = 0; i < msz; i++) + if (OFmem[i].mr_start + OFmem[i].mr_size > maxphysaddr) + maxphysaddr = OFmem[i].mr_start + OFmem[i].mr_size; + + if (OFavail[asz - 1].mr_start + OFavail[asz - 1].mr_size > maxphysaddr) + OFavail[asz - 1].mr_size = maxphysaddr - + OFavail[asz - 1].mr_start; + /* * OFavail may have overlapping regions - collapse these * and copy out remaining regions to OFfree */ - asz /= sizeof(struct mem_region); do { still_merging = FALSE; for (i = 0; i < asz; i++) { @@ -318,19 +443,6 @@ OF_initial_setup(void *fdt_ptr, void *ju else ofw_real_mode = 1; - ofwcall = NULL; - - #ifdef __powerpc64__ - /* - * For PPC64, we need to use some hand-written - * asm trampolines to get to OF. - */ - if (openfirm != NULL) - ofwcall = ofw_32bit_mode_entry; - #else - ofwcall = openfirm; - #endif - fdt = fdt_ptr; #ifdef FDT_DTB_STATIC @@ -345,7 +457,7 @@ OF_bootstrap() { boolean_t status = FALSE; - if (ofwcall != NULL) { + if (openfirmware_entry != NULL) { if (ofw_real_mode) { status = OF_install(OFW_STD_REAL, 0); } else { @@ -481,12 +593,7 @@ openfirmware(void *args) int result; #ifdef SMP struct ofw_rv_args rv_args; - #endif - - if (pmap_bootstrapped && ofw_real_mode) - args = (void *)pmap_kextract((vm_offset_t)args); - #ifdef SMP rv_args.args = args; rv_args.in_progress = 1; smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch, Modified: head/sys/powerpc/ofw/ofw_real.c ============================================================================== --- head/sys/powerpc/ofw/ofw_real.c Thu Jun 2 14:09:30 2011 (r222612) +++ head/sys/powerpc/ofw/ofw_real.c Thu Jun 2 14:12:37 2011 (r222613) @@ -205,13 +205,14 @@ ofw_real_bounce_alloc(void *junk) /* * Allocate a page of contiguous, wired physical memory that can - * fit into a 32-bit address space. + * fit into a 32-bit address space and accessed from real mode. */ mtx_lock(&of_bounce_mtx); - of_bounce_virt = contigmalloc(PAGE_SIZE, M_OFWREAL, 0, - 0, BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE, PAGE_SIZE); + of_bounce_virt = contigmalloc(PAGE_SIZE, M_OFWREAL, 0, 0, + ulmin(platform_real_maxaddr(), BUS_SPACE_MAXADDR_32BIT), PAGE_SIZE, + PAGE_SIZE); of_bounce_phys = vtophys(of_bounce_virt); of_bounce_size = PAGE_SIZE; Added: head/sys/powerpc/ofw/ofwcall32.S ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/powerpc/ofw/ofwcall32.S Thu Jun 2 14:12:37 2011 (r222613) @@ -0,0 +1,154 @@ +/*- + * Copyright (C) 2009-2011 Nathan Whitehorn + * 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 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. + * + * $FreeBSD$ + */ + +#include <sys/syscall.h> + +#include <machine/trap.h> +#include <machine/param.h> +#include <machine/spr.h> +#include <machine/asm.h> + +#define OFWSTKSZ 4096 /* 4K Open Firmware stack */ + +/* + * Globals + */ + .data +GLOBAL(ofmsr) + .long 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */ +GLOBAL(rtasmsr) + .long 0 +GLOBAL(openfirmware_entry) + .long 0 /* Open Firmware entry point */ +GLOBAL(rtas_entry) + .long 0 /* RTAS entry point */ + + .align 4 +ofwstk: + .space OFWSTKSZ +rtas_regsave: + .space 4 + +/* + * Open Firmware Entry Point. May need to enter real mode. + * + * C prototype: int ofwcall(void *callbuffer); + */ + +ASENTRY(ofwcall) + mflr %r0 + stw %r0,4(%r1) + + /* Record the old MSR */ + mfmsr %r6 + + /* read client interface handler */ + lis %r4,openfirmware_entry@ha + lwz %r4,openfirmware_entry@l(%r4) + + /* + * Set the MSR to the OF value. This has the side effect of disabling + * exceptions, which prevents preemption later. + */ + + lis %r5,ofmsr@ha + lwz %r5,ofmsr@l(%r5) + mtmsr %r5 + isync + + /* + * Set up OF stack. This needs to be potentially accessible in real mode + * The pointer to the current kernel stack is placed at the very + * top of the stack along with the old MSR so we can get them back + * later. + */ + mr %r5,%r1 + lis %r1,(ofwstk+OFWSTKSZ-16)@ha + addi %r1,%r1,(ofwstk+OFWSTKSZ-16)@l + stw %r5,8(%r1) /* Save real stack pointer */ + stw %r6,12(%r1) /* Save old MSR */ + li %r5,0 + stw %r5,4(%r1) + stw %r5,0(%r1) + + /* Finally, branch to OF */ + mtctr %r4 + bctrl + + /* Reload stack pointer and MSR from the OFW stack */ + lwz %r6,12(%r1) + lwz %r1,8(%r1) + + /* Now set the real MSR */ + mtmsr %r6 + isync + + /* Return */ + lwz %r0,4(%r1) + mtlr %r0 + blr + +/* + * RTAS Entry Point. Similar to the OF one, but simpler (no separate stack) + * + * C prototype: int rtascall(void *callbuffer, void *rtas_privdat); + */ + +ASENTRY(rtascall) + mflr %r0 + stw %r0,4(%r1) + + /* Record the old MSR to real-mode-accessible area */ + mfmsr %r0 + lis %r5,rtas_regsave@ha + stw %r0,rtas_regsave@l(%r5) + + /* read client interface handler */ + lis %r5,rtas_entry@ha + lwz %r5,rtas_entry@l(%r5) + + /* Set the MSR to the RTAS value */ + lis %r6,rtasmsr@ha + lwz %r6,rtasmsr@l(%r6) + mtmsr %r6 + isync + + /* Branch to RTAS */ + mtctr %r5 + bctrl + + /* Now set the MSR back */ + lis %r6,rtas_regsave@ha + lwz %r6,rtas_regsave@l(%r6) + mtmsr %r6 + isync + + /* And return */ + lwz %r0,4(%r1) + mtlr %r0 + blr + Added: head/sys/powerpc/ofw/ofwcall64.S ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/powerpc/ofw/ofwcall64.S Thu Jun 2 14:12:37 2011 (r222613) @@ -0,0 +1,290 @@ +/*- + * Copyright (C) 2009-2011 Nathan Whitehorn + * 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 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. + * + * $FreeBSD$ + */ + +#include <sys/syscall.h> + +#include <machine/trap.h> +#include <machine/param.h> +#include <machine/spr.h> +#include <machine/asm.h> + +#define OFWSTKSZ 4096 /* 4K Open Firmware stack */ + +/* + * Globals + */ + .data + .align 4 +ofwstk: + .space OFWSTKSZ +rtas_regsave: + .space 24 /* 3 * sizeof(register_t) */ +GLOBAL(ofmsr) + .llong 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */ +GLOBAL(rtasmsr) + .llong 0 +GLOBAL(openfirmware_entry) + .llong 0 /* Open Firmware entry point */ +GLOBAL(rtas_entry) + .llong 0 /* RTAS entry point */ + +/* + * Open Firmware Real-mode Entry Point. This is a huge pain. + */ + +ASENTRY(ofwcall) + mflr %r0 + std %r0,16(%r1) + stdu %r1,-208(%r1) + + /* + * We need to save the following, because OF's register save/ + * restore code assumes that the contents of registers are + * at most 32 bits wide: lr, cr, r2, r13-r31, the old MSR. These + * get placed in that order in the stack. + */ + + mfcr %r4 + std %r4,48(%r1) + std %r13,56(%r1) + std %r14,64(%r1) + std %r15,72(%r1) + std %r16,80(%r1) + std %r17,88(%r1) + std %r18,96(%r1) + std %r19,104(%r1) + std %r20,112(%r1) + std %r21,120(%r1) + std %r22,128(%r1) + std %r23,136(%r1) + std %r24,144(%r1) + std %r25,152(%r1) + std %r26,160(%r1) + std %r27,168(%r1) + std %r28,176(%r1) + std %r29,184(%r1) + std %r30,192(%r1) + std %r31,200(%r1) + + /* Record the old MSR */ + mfmsr %r6 + + /* read client interface handler */ + lis %r4,openfirmware_entry@ha + ld %r4,openfirmware_entry@l(%r4) + + /* + * Set the MSR to the OF value. This has the side effect of disabling + * exceptions, which is important for the next few steps. + */ + + lis %r5,ofmsr@ha + ld %r5,ofmsr@l(%r5) + mtmsrd %r5 + isync + + /* + * Set up OF stack. This needs to be accessible in real mode and + * use the 32-bit ABI stack frame format. The pointer to the current + * kernel stack is placed at the very top of the stack along with + * the old MSR so we can get them back later. + */ + mr %r5,%r1 + lis %r1,(ofwstk+OFWSTKSZ-32)@ha + addi %r1,%r1,(ofwstk+OFWSTKSZ-32)@l + std %r5,8(%r1) /* Save real stack pointer */ + std %r2,16(%r1) /* Save old TOC */ + std %r6,24(%r1) /* Save old MSR */ + li %r5,0 + stw %r5,4(%r1) + stw %r5,0(%r1) + + /* Finally, branch to OF */ + mtctr %r4 + bctrl + + /* Reload stack pointer and MSR from the OFW stack */ + ld %r6,24(%r1) + ld %r2,16(%r1) + ld %r1,8(%r1) + + /* Now set the real MSR */ + mtmsrd %r6 + isync + + /* Sign-extend the return value from OF */ + extsw %r3,%r3 + + /* Restore all the non-volatile registers */ + ld %r5,48(%r1) + mtcr %r5 + ld %r13,56(%r1) + ld %r14,64(%r1) + ld %r15,72(%r1) + ld %r16,80(%r1) + ld %r17,88(%r1) + ld %r18,96(%r1) + ld %r19,104(%r1) + ld %r20,112(%r1) + ld %r21,120(%r1) + ld %r22,128(%r1) + ld %r23,136(%r1) + ld %r24,144(%r1) + ld %r25,152(%r1) + ld %r26,160(%r1) + ld %r27,168(%r1) + ld %r28,176(%r1) + ld %r29,184(%r1) + ld %r30,192(%r1) + ld %r31,200(%r1) + + /* Restore the stack and link register */ + ld %r1,0(%r1) + ld %r0,16(%r1) + mtlr %r0 + blr + +/* + * RTAS 32-bit Entry Point. Similar to the OF one, but simpler (no separate + * stack) + * + * C prototype: int rtascall(void *callbuffer, void *rtas_privdat); + */ + +ASENTRY(rtascall) + mflr %r0 + std %r0,16(%r1) + stdu %r1,-208(%r1) + + /* + * We need to save the following, because RTAS's register save/ + * restore code assumes that the contents of registers are + * at most 32 bits wide: lr, cr, r2, r13-r31, the old MSR. These + * get placed in that order in the stack. + */ + + mfcr %r5 + std %r5,48(%r1) + std %r13,56(%r1) + std %r14,64(%r1) + std %r15,72(%r1) + std %r16,80(%r1) + std %r17,88(%r1) + std %r18,96(%r1) + std %r19,104(%r1) + std %r20,112(%r1) + std %r21,120(%r1) + std %r22,128(%r1) + std %r23,136(%r1) + std %r24,144(%r1) + std %r25,152(%r1) + std %r26,160(%r1) + std %r27,168(%r1) + std %r28,176(%r1) + std %r29,184(%r1) + std %r30,192(%r1) + std %r31,200(%r1) + + /* Record the old MSR */ + mfmsr %r6 + + /* read client interface handler */ + lis %r5,rtas_entry@ha + ld %r5,rtas_entry@l(%r5) + + /* + * Set the MSR to the RTAS value. This has the side effect of disabling + * exceptions, which is important for the next few steps. + */ + + lis %r7,rtasmsr@ha + ld %r7,rtasmsr@l(%r7) + mtmsrd %r7 + isync + + /* + * Set up RTAS register save area, so that we can get back all of + * our 64-bit pointers. Save our stack pointer, the TOC, and the MSR. + * Put this in r1, since RTAS is obliged to save it. Kernel globals + * are below 4 GB, so this is safe. + */ + mr %r7,%r1 + lis %r1,rtas_regsave@ha + addi %r1,%r1,rtas_regsave@l + std %r7,0(%r1) /* Save 64-bit stack pointer */ + std %r2,8(%r1) /* Save TOC */ + std %r6,16(%r1) /* Save MSR */ + + /* Finally, branch to RTAS */ + mtctr %r5 + bctrl + + /* + * Reload stack pointer and MSR from the reg save area in r1. We are + * running in 32-bit mode at this point, so it doesn't matter if r1 + * has become sign-extended. + */ + ld %r6,16(%r1) + ld %r2,8(%r1) + ld %r1,0(%r1) + + /* Now set the real MSR */ + mtmsrd %r6 + isync + + /* Sign-extend the return value from RTAS */ + extsw %r3,%r3 + + /* Restore all the non-volatile registers */ + ld %r5,48(%r1) + mtcr %r5 + ld %r13,56(%r1) + ld %r14,64(%r1) + ld %r15,72(%r1) + ld %r16,80(%r1) + ld %r17,88(%r1) + ld %r18,96(%r1) + ld %r19,104(%r1) + ld %r20,112(%r1) + ld %r21,120(%r1) + ld %r22,128(%r1) + ld %r23,136(%r1) + ld %r24,144(%r1) + ld %r25,152(%r1) + ld %r26,160(%r1) + ld %r27,168(%r1) + ld %r28,176(%r1) + ld %r29,184(%r1) + ld %r30,192(%r1) + ld %r31,200(%r1) + + /* Restore the stack and link register */ + ld %r1,0(%r1) + ld %r0,16(%r1) + mtlr %r0 *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106021412.p52ECbaK020881>