]>
Commit | Line | Data |
---|---|---|
1c79356b A |
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 | } |