/*-1* Copyright (C) 2009-2011 Nathan Whitehorn2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR14* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES15* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.16* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,17* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,18* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;19* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,20* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR21* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF22* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.23*/2425#include <sys/syscall.h>2627#include <machine/trap.h>28#include <machine/param.h>29#include <machine/spr.h>30#include <machine/asm.h>3132#include "opt_platform.h"3334#define OFWSTKSZ 4096 /* 4K Open Firmware stack */3536/*37* Globals38*/39.data40.align 441ofwstk:42.space OFWSTKSZ43rtas_regsave:44.space 32 /* 4 * sizeof(register_t) */45GLOBAL(ofmsr)46.llong 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */47GLOBAL(rtasmsr)48.llong 049GLOBAL(openfirmware_entry)50.llong 0 /* Open Firmware entry point */51GLOBAL(rtas_entry)52.llong 0 /* RTAS entry point */5354TOC_ENTRY(ofmsr)55TOC_ENTRY(ofwstk)56TOC_ENTRY(rtasmsr)57TOC_ENTRY(openfirmware_entry)58TOC_ENTRY(rtas_entry)59TOC_ENTRY(rtas_regsave)6061/*62* Open Firmware Real-mode Entry Point. This is a huge pain.63*/6465ASENTRY_NOPROF(ofwcall)66mflr %r867std %r8,16(%r1)68stdu %r1,-208(%r1)6970/*71* We need to save the following, because OF's register save/72* restore code assumes that the contents of registers are73* at most 32 bits wide: lr, cr, r2, r13-r31, the old MSR. These74* get placed in that order in the stack.75*/7677mfcr %r478std %r4,48(%r1)79std %r13,56(%r1)80std %r14,64(%r1)81std %r15,72(%r1)82std %r16,80(%r1)83std %r17,88(%r1)84std %r18,96(%r1)85std %r19,104(%r1)86std %r20,112(%r1)87std %r21,120(%r1)88std %r22,128(%r1)89std %r23,136(%r1)90std %r24,144(%r1)91std %r25,152(%r1)92std %r26,160(%r1)93std %r27,168(%r1)94std %r28,176(%r1)95std %r29,184(%r1)96std %r30,192(%r1)97std %r31,200(%r1)9899/* Record the old MSR */100mfmsr %r6101102/* read client interface handler */103addis %r4,%r2,TOC_REF(openfirmware_entry)@ha104ld %r4,TOC_REF(openfirmware_entry)@l(%r4)105ld %r4,0(%r4)106107/* Get OF stack pointer */108addis %r7,%r2,TOC_REF(ofwstk)@ha109ld %r7,TOC_REF(ofwstk)@l(%r7)110addi %r7,%r7,OFWSTKSZ-40111112/*113* Set the MSR to the OF value. This has the side effect of disabling114* exceptions, which is important for the next few steps.115* This does NOT, however, cause us to switch endianness.116*/117118addis %r5,%r2,TOC_REF(ofmsr)@ha119ld %r5,TOC_REF(ofmsr)@l(%r5)120ld %r5,0(%r5)121#if defined(__LITTLE_ENDIAN__) && defined(QEMU)122/* QEMU hack: qemu does not emulate mtmsrd correctly! */123ori %r5,%r5,1 /* Leave PSR_LE set */124#endif125mtmsrd %r5126isync127128/*129* Set up OF stack. This needs to be accessible in real mode and130* use the 32-bit ABI stack frame format. The pointer to the current131* kernel stack is placed at the very top of the stack along with132* the old MSR so we can get them back later.133*/134mr %r5,%r1135mr %r1,%r7136std %r5,8(%r1) /* Save real stack pointer */137std %r2,16(%r1) /* Save old TOC */138std %r6,24(%r1) /* Save old MSR */139std %r8,32(%r1) /* Save high 32-bits of the kernel's PC */140141li %r5,0142stw %r5,4(%r1)143stw %r5,0(%r1)144145#ifdef __LITTLE_ENDIAN__146/* Atomic context switch w/ endian change */147mtmsrd %r5, 1 /* Clear PSL_EE|PSL_RI */148addis %r5,%r2,TOC_REF(ofmsr)@ha149ld %r5,TOC_REF(ofmsr)@l(%r5)150ld %r5,0(%r5)151mtsrr0 %r4152mtsrr1 %r5153LOAD_LR_NIA1541:155mflr %r5156addi %r5, %r5, (2f-1b)157mtlr %r5158li %r5, 0159rfid1602:161RETURN_TO_NATIVE_ENDIAN162#else163/* Finally, branch to OF */164mtctr %r4165bctrl166#endif167168/* Reload stack pointer, MSR, and reference PC from the OFW stack */169ld %r7,32(%r1)170ld %r6,24(%r1)171ld %r2,16(%r1)172ld %r1,8(%r1)173174/* Get back to the MSR/PC we want, using the cached high bits of PC */175mtsrr1 %r6176clrrdi %r7,%r7,32177bl 1f1781: mflr %r8179or %r8,%r8,%r7180addi %r8,%r8,2f-1b181mtsrr0 %r8182rfid /* Turn on MMU, exceptions, and 64-bit mode */1831842:185/* Sign-extend the return value from OF */186extsw %r3,%r3187188/* Restore all the non-volatile registers */189ld %r5,48(%r1)190mtcr %r5191ld %r13,56(%r1)192ld %r14,64(%r1)193ld %r15,72(%r1)194ld %r16,80(%r1)195ld %r17,88(%r1)196ld %r18,96(%r1)197ld %r19,104(%r1)198ld %r20,112(%r1)199ld %r21,120(%r1)200ld %r22,128(%r1)201ld %r23,136(%r1)202ld %r24,144(%r1)203ld %r25,152(%r1)204ld %r26,160(%r1)205ld %r27,168(%r1)206ld %r28,176(%r1)207ld %r29,184(%r1)208ld %r30,192(%r1)209ld %r31,200(%r1)210211/* Restore the stack and link register */212ld %r1,0(%r1)213ld %r0,16(%r1)214mtlr %r0215blr216ASEND(ofwcall)217218/*219* RTAS 32-bit Entry Point. Similar to the OF one, but simpler (no separate220* stack)221*222* C prototype: int rtascall(void *callbuffer, void *rtas_privdat);223*/224225ASENTRY_NOPROF(rtascall)226mflr %r9227std %r9,16(%r1)228stdu %r1,-208(%r1)229230/*231* We need to save the following, because RTAS's register save/232* restore code assumes that the contents of registers are233* at most 32 bits wide: lr, cr, r2, r13-r31, the old MSR. These234* get placed in that order in the stack.235*/236237mfcr %r5238std %r5,48(%r1)239std %r13,56(%r1)240std %r14,64(%r1)241std %r15,72(%r1)242std %r16,80(%r1)243std %r17,88(%r1)244std %r18,96(%r1)245std %r19,104(%r1)246std %r20,112(%r1)247std %r21,120(%r1)248std %r22,128(%r1)249std %r23,136(%r1)250std %r24,144(%r1)251std %r25,152(%r1)252std %r26,160(%r1)253std %r27,168(%r1)254std %r28,176(%r1)255std %r29,184(%r1)256std %r30,192(%r1)257std %r31,200(%r1)258259/* Record the old MSR */260mfmsr %r6261262/* Read RTAS entry and reg save area pointers */263addis %r5,%r2,TOC_REF(rtas_entry)@ha264ld %r5,TOC_REF(rtas_entry)@l(%r5)265ld %r5,0(%r5)266addis %r8,%r2,TOC_REF(rtas_regsave)@ha267ld %r8,TOC_REF(rtas_regsave)@l(%r8)268269/*270* Set the MSR to the RTAS value. This has the side effect of disabling271* exceptions, which is important for the next few steps.272*/273274addis %r7,%r2,TOC_REF(rtasmsr)@ha275ld %r7,TOC_REF(rtasmsr)@l(%r7)276ld %r7,0(%r7)277#ifdef __LITTLE_ENDIAN__278/* QEMU hack: qemu does not emulate mtmsrd correctly! */279ori %r7,%r7,1 /* Leave PSR_LE set */280#endif281mtmsrd %r7282isync283284/*285* Set up RTAS register save area, so that we can get back all of286* our 64-bit pointers. Save our stack pointer, the TOC, and the MSR.287* Put this in r1, since RTAS is obliged to save it. Kernel globals288* are below 4 GB, so this is safe.289*/290mr %r7,%r1291mr %r1,%r8292std %r7,0(%r1) /* Save 64-bit stack pointer */293std %r2,8(%r1) /* Save TOC */294std %r6,16(%r1) /* Save MSR */295std %r9,24(%r1) /* Save reference PC for high 32 bits */296297#ifdef __LITTLE_ENDIAN__298/* Atomic context switch w/ endian change */299li %r7, 0300mtmsrd %r7, 1 /* Clear PSL_EE|PSL_RI */301addis %r7,%r2,TOC_REF(rtasmsr)@ha302ld %r7,TOC_REF(rtasmsr)@l(%r7)303ld %r7,0(%r7)304mtsrr0 %r5305mtsrr1 %r7306LOAD_LR_NIA3071:308mflr %r5309addi %r5, %r5, (2f-1b)310mtlr %r5311li %r5, 0312rfid3132:314RETURN_TO_NATIVE_ENDIAN315#else316/* Finally, branch to RTAS */317mtctr %r5318bctrl319#endif320321/*322* Reload stack pointer, MSR, reg PC from the reg save area in r1. We323* are running in 32-bit mode at this point, so it doesn't matter if r1324* has become sign-extended.325*/326ld %r7,24(%r1)327ld %r6,16(%r1)328ld %r2,8(%r1)329ld %r1,0(%r1)330331/*332* Get back to the right PC. We need to atomically re-enable333* exceptions, 64-bit mode, and the MMU. One thing that has likely334* happened is that, if we were running in the high-memory direct335* map, we no longer are as a result of LR truncation in RTAS.336* Fix this by copying the high-order bits of the LR at function337* entry onto the current PC and then jumping there while flipping338* all the MSR bits.339*/340mtsrr1 %r6341clrrdi %r7,%r7,32342bl 1f3431: mflr %r8344or %r8,%r8,%r7345addi %r8,%r8,2f-1b346mtsrr0 %r8347rfid /* Turn on MMU, exceptions, and 64-bit mode */3483492:350/* Sign-extend the return value from RTAS */351extsw %r3,%r3352353/* Restore all the non-volatile registers */354ld %r5,48(%r1)355mtcr %r5356ld %r13,56(%r1)357ld %r14,64(%r1)358ld %r15,72(%r1)359ld %r16,80(%r1)360ld %r17,88(%r1)361ld %r18,96(%r1)362ld %r19,104(%r1)363ld %r20,112(%r1)364ld %r21,120(%r1)365ld %r22,128(%r1)366ld %r23,136(%r1)367ld %r24,144(%r1)368ld %r25,152(%r1)369ld %r26,160(%r1)370ld %r27,168(%r1)371ld %r28,176(%r1)372ld %r29,184(%r1)373ld %r30,192(%r1)374ld %r31,200(%r1)375376/* Restore the stack and link register */377ld %r1,0(%r1)378ld %r0,16(%r1)379mtlr %r0380blr381ASEND(rtascall)382383384