]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/notify_interrupt.c
4e1c4ef9e74f7517445555f7bd09a26498a52a3c
[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 * 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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 #include <mach/kern_return.h>
23 #include <kern/thread.h>
24 #include <ppc/exception.h>
25 #include <kern/ipc_tt.h>
26 #include <ipc/ipc_port.h>
27 #include <ppc/atomic_switch.h>
28 #include <kern/thread_act.h>
29
30 int debugNotify = 0;
31
32 /*
33 ** Function: NotifyInterruption
34 **
35 ** Inputs: port - mach_port for main thread
36 ** ppcInterrupHandler - interrupt handler to execute
37 ** interruptStatePtr - current interrupt state
38 ** emulatorDescriptor - where in emulator to notify
39 ** originalPC - where the emulator was executing
40 ** originalR2 - new R2
41 **
42 ** Outputs:
43 **
44 ** Notes:
45 **
46 */
47
48 unsigned long
49 syscall_notify_interrupt(mach_port_t, UInt32, UInt32 *, EmulatorDescriptor *,
50 void ** , void **, void *);
51
52 unsigned long
53 syscall_notify_interrupt( mach_port_t port_thread,
54 UInt32 ppcInterruptHandler,
55 UInt32 * interruptStatePtr,
56 EmulatorDescriptor * emulatorDescriptor,
57 void ** originalPC,
58 void ** originalR2,
59 void *othread )
60 {
61 kern_return_t result;
62 struct ppc_saved_state *mainPCB;
63 thread_t thread, nthread;
64 thread_act_t act;
65 UInt32 interruptState, currentState, postIntMask;
66 extern thread_act_t port_name_to_act(mach_port_t);
67 boolean_t isSelf, runningInKernel;
68 static unsigned long sequence =0;
69
70 #define COPYIN_INTSTATE() { \
71 (void) copyin((char *) interruptStatePtr, (char *)&interruptState, sizeof(interruptState)); \
72 if (emulatorDescriptor) \
73 (void) copyin((char *) &emulatorDescriptor->postIntMask, (char *)&postIntMask, sizeof(postIntMask)); }
74 #define COPYOUT_INTSTATE() (void) copyout((char *) &interruptState, (char *)interruptStatePtr, sizeof(interruptState))
75
76
77 act = port_name_to_act(port_thread);
78
79
80 if (act == THR_ACT_NULL)
81 return port_thread;
82
83 runningInKernel = (act->mact.ksp == 0);
84 isSelf = (current_act() == act);
85
86 if (!isSelf) {
87 /* First.. suspend the thread */
88 result = thread_suspend(act);
89
90 if (result) {
91 act_deallocate(act);
92 return port_thread;
93 }
94
95 /* Now try to find and wait for any pending activitations
96 * to complete.. (the following is an expansion of
97 * thread_set_state())
98 */
99
100 thread = act_lock_thread(act);
101 if (!act->active) {
102 act_unlock_thread(act);
103 act_deallocate(act);
104 return port_thread;
105 }
106
107 thread_hold(act);
108
109 while (1) {
110 if (!thread || act != thread->top_act)
111 break;
112
113 act_unlock_thread(act);
114 (void) thread_stop_wait(thread);
115 nthread = act_lock_thread(act);
116 if (nthread == thread)
117 break;
118 thread_unstop(thread);
119 thread = nthread;
120 }
121
122 }
123
124 COPYIN_INTSTATE()
125 if (isSelf)
126 currentState = kOutsideMain;
127 else
128 currentState = (interruptState & kInterruptStateMask) >> kInterruptStateShift;
129
130 if (debugNotify > 5) {
131 printf("\nNotifyInterruption: %X, %X, %X, %X, %X, %X\n",
132 port_thread, ppcInterruptHandler, interruptStatePtr,
133 emulatorDescriptor, originalPC, originalR2 );
134 }
135 mainPCB = USER_REGS(act);
136
137 switch (currentState)
138 {
139 case kNotifyPending:
140 case kInUninitialized:
141 if (debugNotify > 2)
142 printf("NotifyInterrupt: kInUninitialized\n");
143 break;
144
145 case kInPseudoKernel:
146 case kOutsideMain:
147 if (debugNotify > 2)
148 printf("NotifyInterrupt: kInPseudoKernel/kOutsideMain\n");
149 interruptState = interruptState
150 | ((postIntMask >> kCR2ToBackupShift) & kBackupCR2Mask);
151 COPYOUT_INTSTATE();
152 break;
153
154 case kInSystemContext:
155 if (debugNotify > 2)
156 printf("kInSystemContext: old CR %x, postIntMask %x, new CR %x\n",
157 mainPCB->cr, postIntMask, mainPCB->cr | postIntMask);
158 mainPCB->cr |= postIntMask;
159 break;
160
161 case kInAlternateContext:
162 if (debugNotify > 2)
163 printf("kInAlternateContext: IN InterruptState %x, postIntMask %x\n",
164 interruptState, postIntMask);
165 interruptState = interruptState | ((postIntMask >> kCR2ToBackupShift) & kBackupCR2Mask);
166 interruptState = (interruptState & ~kInterruptStateMask);
167
168 if (runningInKernel)
169 interruptState |= (kNotifyPending << kInterruptStateShift);
170 else
171 interruptState |= (kInPseudoKernel << kInterruptStateShift);
172
173 (void) copyout((char *)&mainPCB->srr0, (char *)originalPC, sizeof(originalPC));
174 (void) copyout((char *)&mainPCB->r2, (char *)originalR2, sizeof(originalR2));
175 COPYOUT_INTSTATE();
176 if (debugNotify > 2)
177 printf("kInAlternateContext: Out interruptState %x, Old PC %x, New %x, R2 %x\n",
178 interruptState, mainPCB->srr0, ppcInterruptHandler, mainPCB->r2);
179
180 mainPCB->srr0 = ppcInterruptHandler;
181 break;
182
183 case kInExceptionHandler:
184 if (debugNotify > 2)
185 printf("NotifyInterrupt: kInExceptionHandler\n");
186 interruptState = interruptState | ((postIntMask >> kCR2ToBackupShift) & kBackupCR2Mask);
187 COPYOUT_INTSTATE();
188 break;
189
190 default:
191 if (debugNotify)
192 printf("NotifyInterrupt: default ");
193 printf("Interruption while running in unknown state\n");
194 printf("interruptState = 0x%X\n",currentState);
195 break;
196 }
197
198 if (!isSelf) {
199 if (thread && act == thread->top_act)
200 thread_unstop(thread);
201 thread_release(act);
202 act_unlock_thread(act);
203 thread_resume(act);
204 }
205
206 act_deallocate(act);
207
208 return port_thread;
209 }