]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/notify_interrupt.c
9a25a9594bd6a7eed0f210d63d482ecbf52e2012
[apple/xnu.git] / osfmk / ppc / notify_interrupt.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 #include <mach/kern_return.h>
26 #include <kern/thread.h>
27 #include <ppc/exception.h>
28 #include <kern/ipc_tt.h>
29 #include <ipc/ipc_port.h>
30 #include <ppc/atomic_switch.h>
31 #include <kern/thread_act.h>
32
33 int debugNotify = 0;
34
35 /*
36 ** Function: NotifyInterruption
37 **
38 ** Inputs: port - mach_port for main thread
39 ** ppcInterrupHandler - interrupt handler to execute
40 ** interruptStatePtr - current interrupt state
41 ** emulatorDescriptor - where in emulator to notify
42 ** originalPC - where the emulator was executing
43 ** originalR2 - new R2
44 **
45 ** Outputs:
46 **
47 ** Notes:
48 **
49 */
50
51 unsigned long
52 syscall_notify_interrupt(mach_port_t, UInt32, UInt32 *, EmulatorDescriptor *,
53 void ** , void **, void *);
54
55 unsigned long
56 syscall_notify_interrupt( mach_port_t port_thread,
57 UInt32 ppcInterruptHandler,
58 UInt32 * interruptStatePtr,
59 EmulatorDescriptor * emulatorDescriptor,
60 void ** originalPC,
61 void ** originalR2,
62 void *othread )
63 {
64 kern_return_t result;
65 struct ppc_saved_state *mainPCB;
66 thread_t thread, nthread;
67 thread_act_t act;
68 UInt32 interruptState, currentState, postIntMask;
69 extern thread_act_t port_name_to_act(mach_port_t);
70 boolean_t isSelf, runningInKernel;
71 static unsigned long sequence =0;
72
73 #define COPYIN_INTSTATE() { \
74 (void) copyin((char *) interruptStatePtr, (char *)&interruptState, sizeof(interruptState)); \
75 if (emulatorDescriptor) \
76 (void) copyin((char *) &emulatorDescriptor->postIntMask, (char *)&postIntMask, sizeof(postIntMask)); }
77 #define COPYOUT_INTSTATE() (void) copyout((char *) &interruptState, (char *)interruptStatePtr, sizeof(interruptState))
78
79
80 act = port_name_to_act(port_thread);
81
82
83 if (act == THR_ACT_NULL)
84 return port_thread;
85
86 runningInKernel = (act->mact.ksp == 0);
87 isSelf = (current_act() == act);
88
89 if (!isSelf) {
90 /* First.. suspend the thread */
91 result = thread_suspend(act);
92
93 if (result) {
94 act_deallocate(act);
95 return port_thread;
96 }
97
98 /* Now try to find and wait for any pending activitations
99 * to complete.. (the following is an expansion of
100 * thread_set_state())
101 */
102
103 thread = act_lock_thread(act);
104 if (!act->active) {
105 act_unlock_thread(act);
106 act_deallocate(act);
107 return port_thread;
108 }
109
110 thread_hold(act);
111
112 while (1) {
113 if (!thread || act != thread->top_act)
114 break;
115
116 act_unlock_thread(act);
117 (void) thread_stop_wait(thread);
118 nthread = act_lock_thread(act);
119 if (nthread == thread)
120 break;
121 thread_unstop(thread);
122 thread = nthread;
123 }
124
125 }
126
127 COPYIN_INTSTATE()
128 if (isSelf)
129 currentState = kOutsideMain;
130 else
131 currentState = (interruptState & kInterruptStateMask) >> kInterruptStateShift;
132
133 if (debugNotify > 5) {
134 printf("\nNotifyInterruption: %X, %X, %X, %X, %X, %X\n",
135 port_thread, ppcInterruptHandler, interruptStatePtr,
136 emulatorDescriptor, originalPC, originalR2 );
137 }
138 mainPCB = USER_REGS(act);
139
140 switch (currentState)
141 {
142 case kNotifyPending:
143 case kInUninitialized:
144 if (debugNotify > 2)
145 printf("NotifyInterrupt: kInUninitialized\n");
146 break;
147
148 case kInPseudoKernel:
149 case kOutsideMain:
150 if (debugNotify > 2)
151 printf("NotifyInterrupt: kInPseudoKernel/kOutsideMain\n");
152 interruptState = interruptState
153 | ((postIntMask >> kCR2ToBackupShift) & kBackupCR2Mask);
154 COPYOUT_INTSTATE();
155 break;
156
157 case kInSystemContext:
158 if (debugNotify > 2)
159 printf("kInSystemContext: old CR %x, postIntMask %x, new CR %x\n",
160 mainPCB->cr, postIntMask, mainPCB->cr | postIntMask);
161 mainPCB->cr |= postIntMask;
162 break;
163
164 case kInAlternateContext:
165 if (debugNotify > 2)
166 printf("kInAlternateContext: IN InterruptState %x, postIntMask %x\n",
167 interruptState, postIntMask);
168 interruptState = interruptState | ((postIntMask >> kCR2ToBackupShift) & kBackupCR2Mask);
169 interruptState = (interruptState & ~kInterruptStateMask);
170
171 if (runningInKernel)
172 interruptState |= (kNotifyPending << kInterruptStateShift);
173 else
174 interruptState |= (kInPseudoKernel << kInterruptStateShift);
175
176 (void) copyout((char *)&mainPCB->srr0, (char *)originalPC, sizeof(originalPC));
177 (void) copyout((char *)&mainPCB->r2, (char *)originalR2, sizeof(originalR2));
178 COPYOUT_INTSTATE();
179 if (debugNotify > 2)
180 printf("kInAlternateContext: Out interruptState %x, Old PC %x, New %x, R2 %x\n",
181 interruptState, mainPCB->srr0, ppcInterruptHandler, mainPCB->r2);
182
183 mainPCB->srr0 = ppcInterruptHandler;
184 break;
185
186 case kInExceptionHandler:
187 if (debugNotify > 2)
188 printf("NotifyInterrupt: kInExceptionHandler\n");
189 interruptState = interruptState | ((postIntMask >> kCR2ToBackupShift) & kBackupCR2Mask);
190 COPYOUT_INTSTATE();
191 break;
192
193 default:
194 if (debugNotify)
195 printf("NotifyInterrupt: default ");
196 printf("Interruption while running in unknown state\n");
197 printf("interruptState = 0x%X\n",currentState);
198 break;
199 }
200
201 if (!isSelf) {
202 if (thread && act == thread->top_act)
203 thread_unstop(thread);
204 thread_release(act);
205 act_unlock_thread(act);
206 thread_resume(act);
207 }
208
209 act_deallocate(act);
210
211 return port_thread;
212 }