2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 #include <ppc/proc_reg.h>
24 #include <ppc/exception.h>
25 #include <mach/ppc/vm_param.h>
29 * Classic atomic switch and fast trap code
30 * Written by: Mark Gorlinsky
35 ** Blue Box Fast Trap entry
38 ** The registers at entry are as hw_exceptions left them. Which means
39 ** that the Blue Box data area is pointed to be R26.
41 ** We exit here through the fast path exit point in hw_exceptions. That means that
42 ** upon exit, R4 must not change. It is the savearea with the current user context
45 ** Input registers are:
46 ** r0 = Syscall number
47 ** r4 = Current context savearea (do not modify)
48 ** r13 = THREAD_TOP_ACT pointer
49 ** r26 = base of ACT_MACH_BDA in kernel address space
51 ** r24 = Index into TWI table (x4)
57 ENTRY(atomic_switch_syscall, TAG_NO_FRAME_USED)
60 * Here's where we check for special Blue Box fast traps
61 * If we don't recognize the syscall, we'll go back to regular processing
63 cmpwi r0,-1 ; Is it NKIsPreemptiveTask
64 beq- isBBpretask ; It is a fast syscall...
65 cmpwi r0,-2 ; Is it kcNKIsPreemptiveTaskEnv
66 bne- nofastSC ; Not a fast syscall...
68 ; kcNKIsPreemptiveTaskEnv return task.taskEnv in r0
70 lwz r23, ACT_MACT_BTE(r13) ; Get the taskEnv
71 stw r23, saver0(r4) ; Return the taskEnv in R0
73 isBBpretask: ; answer the question is this a preemptive task ?
74 rlwinm r6,r26,0,0,19 ; Start of page is bttd
75 lwz r1,BTTD_INTERRUPT_VECTOR(r6) ; Get interrupt vector
76 lwz r6, savecr(r4) ; Get the current CCRs
77 cmpwi r1,0 ; Is this a preemptive thread ?
78 rlwinm r6,r6,0,cr0_eq+1,cr0_eq-1 ; Clear CR0 EQ bit
79 bne notpretask ; Only the cooperative thread has an interrupt vector
80 oris r6,r6,(0x8000 >> cr0_eq) ; Set CR0[eq] if task is preemptive.
82 stw r6, savecr(r4) ; Save the new current CCRs
84 b EXT(fastexit) ; Take the fast path exit...
87 li r5, BTTD_SYSCALL_VECTOR
90 ENTRY(atomic_switch_trap, TAG_NO_FRAME_USED)
93 ** functions 0-15 -> Call PseudoKernel
94 ** 16 -> Exit PseudoKernel
97 cmplwi cr7,r24,BB_RFI_TRAP ; Is this an RFI?
98 beq cr7,.L_ExitPseudoKernel ; Yes...
100 li r5, BTTD_TRAP_VECTOR
102 /******************************************************************************
103 * void CallPseudoKernel ( int vector, thread_act_t * act, BEDA_t * beda, savearea *sv )
105 * This op provides a means of invoking the BlueBox PseudoKernel from a
106 * system (68k) or native (PPC) context while changing BlueBox interruption
107 * state atomically. As an added bonus, this op leaves all but R1/PC of the user
108 * state registers intact. R1/PC are saved in a per thread save area, the base of
109 * which is located in the bbDescAddr member of the thread_act structure.
111 * This op is invoked from the Emulator Trap dispatch table or from a System
112 * Call when Mach SCs have been disabled. A vectorindex is passed in to indicate
113 * which vector should be taken.
115 * If this op is invoked from the Emulator Trap dispatch table, the kernel is
116 * aware of starting address of this table. It used the users PC (SRR0)
117 * and the start of the Trap dispatch table address to verify the trap exception
118 * as a atomic_switch trap. If a trap exception is verified as a atomic_switch
119 * trap we enter here with the following registers loaded.
121 * Input registers are:
122 * r5 = Vector to take
123 * r13 = Current thread context data
124 * r26 = Base address of BlueBox exception data area in kernel address space
125 * r4 = Current context savearea (do not modify)
127 ******************************************************************************/
131 rlwinm r6,r26,0,0,19 ; Start of page is bttd
132 lwz r7,ACT_MACT_SPF(r13) ; Get special flags
133 lwz r1,BTTD_INTERRUPT_VECTOR(r6) ; Get interrupt vector
134 rlwinm r7,r7,0,bbNoMachSCbit+1,bbNoMachSCbit-1
135 ; Reactivate Mach SCs
136 lwz r8,BTTD_INTCONTROLWORD(r6) ; Get Interrupt Control Word
137 cmpwi r1,0 ; Is this a preemptive thread ?
138 stw r7,ACT_MACT_SPF(r13) ; Update special flags
139 beq .L_CallFromPreemptiveThread ; No int vector means preemptive thread
141 rlwinm r1,r8,0,INTSTATEMASK_B,INTSTATEMASK_E
142 ; Extract current Interrupt state
143 rlwinm r8,r8,0,INTSTATEMASK_E+1,INTSTATEMASK_B-1
144 ; Clear current interrupt state
145 xoris r2,r1,SYSCONTEXTSTATE ; Setup for System Context check
146 lwz r1,savecr(r4) ; Load current CR bits
147 cmpwi r2,0 ; Check if state is System Context?
148 oris r8,r8,PSEUDOKERNELSTATE ; Update state for entering the PK
149 bne .L_CallFromAlternateContext ; No, then do not save CR2 bits
151 rlwimi r8,r1,32-INTCR2TOBACKUPSHIFT,INTBACKUPCR2MASK_B,INTBACKUPCR2MASK_E
152 ; Insert live CR2 in ICW BackupCR2
153 .L_CallFromAlternateContext:
155 stw r8,BTTD_INTCONTROLWORD(r6) ; Update ICW
157 .L_CallFromPreemptiveThread:
159 lwz r1,savesrr0(r4) ; Get current PC
160 lwz r2,saver1(r4) ; Get current R1
161 lwz r3,savesrr1(r4) ; Get current MSR
162 stw r1,BEDA_SRR0(r26) ; Save current PC
163 rlwinm r3,r3,0,MSR_BE_BIT+1,MSR_SE_BIT-1
164 ; Clear SE|BE bits in MSR
165 stw r2,BEDA_SPRG1(r26) ; Save current R1
166 stw r3,savesrr1(r4) ; Load new MSR
168 lwz r1,BEDA_SPRG0(r26) ; Get replacement R1
169 lwzx r2,r5,r6 ; Load vector address
170 stw r3,BEDA_SRR1(r26) ; Update saved MSR
171 stw r1,saver1(r4) ; Load up new R1
172 stw r2,savesrr0(r4) ; Save vector as PC
174 b EXT(fastexit) ; Go back and take the fast path exit...
176 /******************************************************************************
177 * void ExitPseudoKernel ( thread_act_t * act, BEDA_t * beda, savearea * sv )
179 * This op provides a means of exiting from the BlueBox PseudoKernel to a
180 * user context. This op attempts to simulate an RFI for the returning
181 * Traps (atomic_switch_trap) and SysCalls (atomic_switch_syscall). Only the
182 * Blue Thread handling interrupts is allowed to atomically change
183 * interruption state and handle pending interrupts.
185 * If an interrupt is pending and we are returning to the alternate context,
186 * the exit is aborted and we return to an pending interrupt handler in the
187 * Blue Box pseudokernel.
189 * It also allows the MSR's FE0, FE1, BE and SE bits to updated for the user
190 * and completes the PPC register loading.
192 * Input registers are:
193 * r4 = Current context savearea (do not modify)
194 * r13 = Pointer to the current active thread's data
195 * r26 = Base address of BlueBox Data in kernel address space
197 ******************************************************************************/
201 rlwinm r6,r26,0,0,19 ; Start of page is bttd
202 lwz r7,ACT_MACT_SPF(r13) ; Get special flags
203 lwz r2,BTTD_INTERRUPT_VECTOR(r6) ; Get the interrupt vector
204 lwz r1,BEDA_SPRG1(r26) ; Get saved CTR
205 oris r7,r7,(0x8000 >> bbNoMachSCbit) ; Disable Mach SCs for Blue Box
207 cmpwi r2,0 ; Is this a preemptive thread
208 stw r1,savectr(r4) ; Update CTR
209 beq .L_ExitFromPreemptiveThread
211 lwz r8,BTTD_INTCONTROLWORD(r6) ; Get ICW
212 lwz r1,BTTD_NEWEXITSTATE(r6) ; New interrupt state
213 lwz r2,BTTD_TESTINTMASK(r6) ; Get pending interrupt mask
214 lis r3,SYSCONTEXTSTATE ; Setup for check in system context
215 rlwimi r8,r1,0,INTSTATEMASK_B,INTSTATEMASK_E
217 cmplw cr1,r1,r3 ; System context ?
218 and. r2,r8,r2 ; Any pending interrupt?
219 lwz r1,savecr(r4) ; Get current CR
221 beq cr1,.L_ExitToSystemContext ; We are in system context
222 beq .L_ExitUpdateRuptControlWord ; We do not have a pending interrupt
224 lwz r2,saver1(r4) ; Get current R1
225 lwz r1,BEDA_SPRG0(r26) ; Get replacement R1
226 stw r2,BEDA_SPRG1(r26) ; Save current R1
227 stw r1,saver1(r4) ; Load up new R1
228 lwz r3,BTTD_PENDINGINT_VECTOR(r6) ; Get pending interrupt PC
229 b .L_ExitAbortExit ; Abort and Exit
231 .L_ExitToSystemContext:
232 rlwimi r1,r8,INTCR2TOBACKUPSHIFT,INTCR2MASK_B,INTCR2MASK_E
233 ; Insert live CR2 into backup CR2
234 .L_ExitUpdateRuptControlWord:
235 stw r8,BTTD_INTCONTROLWORD(r6) ; Update ICW
236 stw r1,savecr(r4) ; Update CR
238 .L_ExitFromPreemptiveThread:
239 lwz r2,savesrr1(r4) ; Get current MSR
240 lwz r1,BEDA_SRR1(r26) ; Get new MSR
241 stw r7,ACT_MACT_SPF(r13) ; Update special flags
242 rlwimi r2,r1,0,MSR_FE0_BIT,MSR_FE1_BIT
243 ; Insert FE0,FE1,SE,BE bits
244 lwz r3,BEDA_SRR0(r26) ; Get new PC
245 stw r2,savesrr1(r4) ; Update MSR
248 stw r3,savesrr0(r4) ; Update PC
250 b EXT(fastexit) ; Go back and take the fast path exit...