Updated PCI IDs to latest snapshot.
[tangerine.git] / arch / all-mingw32 / kernel / host_intr.c
blobf0a749b7b46a70c56b9bb054989d556527840264
1 #define DEBUG 0
3 #include <aros/system.h>
4 #include <windows.h>
5 #define __typedef_LONG /* LONG, ULONG, WORD, BYTE and BOOL are declared in Windows headers. Looks like everything */
6 #define __typedef_WORD /* is the same except BOOL. It's defined to short on AROS and to int on Windows. This means */
7 #define __typedef_BYTE /* that you can't use it in OS-native part of the code and can't use any AROS structure */
8 #define __typedef_BOOL /* definition that contains BOOL. */
9 typedef unsigned AROS_16BIT_TYPE UWORD;
10 typedef unsigned char UBYTE;
12 #include <stddef.h>
13 #include <stdio.h>
14 #include <exec/lists.h>
15 #include <exec/execbase.h>
16 #include "kernel_intern.h"
17 #include "syscall.h"
18 #include "host_debug.h"
19 #include "cpucontext.h"
21 #define DI(x) /* Interrupts debug */
22 #define DS(x) /* Task switcher debug */
23 #define DIRQ(x) /* IRQ debug */
25 #define AROS_EXCEPTION_SYSCALL 0x80000001
27 struct SwitcherData {
28 HANDLE MainThread;
29 HANDLE IntObjects[INTERRUPTS_NUM];
32 struct SwitcherData SwData;
33 DWORD *LastErrorPtr;
34 unsigned char Ints_Enabled;
35 unsigned char PendingInts[INTERRUPTS_NUM];
36 unsigned char Supervisor;
37 unsigned char Sleep_Mode;
38 struct ExecBase **SysBasePtr;
39 struct KernelBase **KernelBasePtr;
41 void user_handler(uint8_t exception, struct List *list)
43 if (!IsListEmpty(&list[exception]))
45 struct IntrNode *in, *in2;
47 ForeachNodeSafe(&list[exception], in, in2)
49 if (in->in_Handler)
50 in->in_Handler(in->in_HandlerData, in->in_HandlerData2);
55 LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS Except)
57 struct ExecBase *SysBase = *SysBasePtr;
58 struct KernelBase *KernelBase = *KernelBasePtr;
59 REG_SAVE_VAR;
61 Supervisor++;
62 switch (Except->ExceptionRecord->ExceptionCode) {
63 case AROS_EXCEPTION_SYSCALL:
64 CONTEXT_SAVE_REGS(Except->ContextRecord);
65 DI(printf("[KRN] Syscall exception %lu\n", *Except->ExceptionRecord->ExceptionInformation));
66 switch (*Except->ExceptionRecord->ExceptionInformation)
68 case SC_CAUSE:
69 core_Cause(SysBase);
70 break;
71 case SC_DISPATCH:
72 core_Dispatch(Except->ContextRecord);
73 break;
74 case SC_SWITCH:
75 core_Switch(Except->ContextRecord);
76 break;
77 case SC_SCHEDULE:
78 core_Schedule(Except->ContextRecord);
79 break;
81 CONTEXT_RESTORE_REGS(Except->ContextRecord);
82 Supervisor--;
83 return EXCEPTION_CONTINUE_EXECUTION;
84 default:
85 printf("[KRN] Exception 0x%08lX handler. Context @ %p, SysBase @ %p, KernelBase @ %p\n", Except->ExceptionRecord->ExceptionCode, Except->ContextRecord, SysBase, KernelBase);
86 if (SysBase)
88 struct Task *t = SysBase->ThisTask;
90 if (t)
91 printf("[KRN] %s %p (%s)\n", t->tc_Node.ln_Type == NT_TASK ? "Task":"Process", t, t->tc_Node.ln_Name ? t->tc_Node.ln_Name : "--unknown--");
92 else
93 printf("[KRN] No task\n");
95 PRINT_CPUCONTEXT(Except->ContextRecord);
96 printf("[KRN] **UNHANDLED EXCEPTION** stopping here...\n");
97 return EXCEPTION_EXECUTE_HANDLER;
101 DWORD WINAPI TaskSwitcher(struct SwitcherData *args)
103 HANDLE IntEvent;
104 DWORD obj;
105 CONTEXT MainCtx;
106 REG_SAVE_VAR;
107 DS(DWORD res);
108 MSG msg;
110 for (;;) {
111 obj = WaitForMultipleObjects(INTERRUPTS_NUM, args->IntObjects, FALSE, INFINITE);
112 DS(bug("[Task switcher] Object %lu signalled\n", obj));
113 if (Sleep_Mode != SLEEP_MODE_ON) {
114 DS(res =) SuspendThread(args->MainThread);
115 DS(bug("[Task switcher] Suspend thread result: %lu\n", res));
117 if (Ints_Enabled) {
118 Supervisor++;
119 PendingInts[obj] = 0;
121 * We will get and store the complete CPU context, but set only part of it.
122 * This can be a useful aid for future AROS debuggers.
124 CONTEXT_INIT_FLAGS(&MainCtx);
125 DS(res =) GetThreadContext(args->MainThread, &MainCtx);
126 DS(bug("[Task switcher] Get context result: %lu\n", res));
127 CONTEXT_SAVE_REGS(&MainCtx);
128 DS(OutputDebugString("[Task switcher] original CPU context: ****\n"));
129 DS(PrintCPUContext(&MainCtx));
130 if (*KernelBasePtr)
131 user_handler(obj, (*KernelBasePtr)->kb_Interrupts);
132 core_ExitInterrupt(&MainCtx);
133 if (!Sleep_Mode) {
134 DS(OutputDebugString("[Task switcher] new CPU context: ****\n"));
135 DS(PrintCPUContext(&MainCtx));
136 CONTEXT_RESTORE_REGS(&MainCtx);
137 DS(res =)SetThreadContext(args->MainThread, &MainCtx);
138 DS(bug("[Task switcher] Set context result: %lu\n", res));
140 Supervisor--;
141 } else {
142 PendingInts[obj] = 1;
143 DS(bug("[KRN] Interrupts are disabled, interrupt %lu is pending\n", obj));
145 if (Sleep_Mode)
146 /* We've entered sleep mode */
147 Sleep_Mode = SLEEP_MODE_ON;
148 else {
149 DS(res =) ResumeThread(args->MainThread);
150 DS(bug("[Task switcher] Resume thread result: %lu\n", res));
153 return 0;
156 /* ****** Interface functions ****** */
158 long __declspec(dllexport) core_intr_disable(void)
160 DI(printf("[KRN] disabling interrupts\n"));
161 Ints_Enabled = 0;
164 long __declspec(dllexport) core_intr_enable(void)
166 int i;
168 DI(printf("[KRN] enabling interrupts\n"));
169 Ints_Enabled = 1;
170 /* FIXME: here we do not force timer interrupt, probably this is wrong. However there's no way
171 to force-trigger a waitable timer in Windows. A workaround is possible, but the design will
172 be complicated then (we need a companion event in this case). Probably it will be implemented
173 in future. */
174 for (i = INT_IO; i < INTERRUPTS_NUM; i++) {
175 if (PendingInts[i]) {
176 DI(printf("[KRN] enable: sigalling about pending interrupt %lu\n", i));
177 SetEvent(SwData.IntObjects[i]);
182 void __declspec(dllexport) core_syscall(unsigned long n)
184 RaiseException(AROS_EXCEPTION_SYSCALL, 0, 1, &n);
185 /* If after RaiseException we are still here, but Sleep_Mode != 0, this likely means
186 we've just called SC_SCHEDULE, SC_SWITCH or SC_DISPATCH, and it is putting us to sleep.
187 Sleep mode will be committed as soon as timer IRQ happens */
188 while(Sleep_Mode) {
189 /* TODO: SwitchToThread() here maybe? But it's dangerous because context switch
190 will happen inside it and Windows will kill us */
194 unsigned char __declspec(dllexport) core_is_super(void)
196 return Supervisor;
199 BOOL InitIntObjects(HANDLE *Objs)
201 int i;
203 for (i = 0; i < INTERRUPTS_NUM; i++) {
204 Objs[i] = NULL;
205 PendingInts[i] = 0;
207 /* Timer interrupt is a waitable timer, it's not an event */
208 for (i = INT_IO; i < INTERRUPTS_NUM; i++) {
209 Objs[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
210 if (!Objs[i])
211 return FALSE;
213 return TRUE;
216 void CleanupIntObjects(HANDLE *Objs)
218 int i;
220 for (i = 0; i < INTERRUPTS_NUM; i++) {
221 if (Objs[i])
222 CloseHandle(Objs[i]);
226 int __declspec(dllexport) core_init(unsigned long TimerPeriod, struct ExecBase **SysBasePointer, struct KernelBase **KernelBasePointer)
228 HANDLE ThisProcess;
229 HANDLE SwitcherThread;
230 LARGE_INTEGER VBLPeriod;
231 OSVERSIONINFO osver;
232 void *MainTEB;
233 int i;
234 DWORD SwitcherId;
235 ULONG LastErrOffset = 0;
237 D(printf("[KRN] Setting up interrupts, SysBasePtr = 0x%08lX, KernelBasePtr = 0x%08lX\n", SysBasePointer, KernelBasePointer));
238 SysBasePtr = SysBasePointer;
239 KernelBasePtr = KernelBasePointer;
240 Ints_Enabled = 0;
241 Supervisor = 0;
242 Sleep_Mode = 0;
243 SetUnhandledExceptionFilter(ExceptionHandler);
244 if (InitIntObjects(SwData.IntObjects)) {
245 SwData.IntObjects[INT_TIMER] = CreateWaitableTimer(NULL, 0, NULL);
246 if (SwData.IntObjects[INT_TIMER]) {
247 ThisProcess = GetCurrentProcess();
248 if (DuplicateHandle(ThisProcess, GetCurrentThread(), ThisProcess, &SwData.MainThread, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
249 FillMemory(&osver, sizeof(osver), 0);
250 osver.dwOSVersionInfoSize = sizeof(osver);
251 GetVersionEx(&osver);
252 /* LastError value is part of our context. In order to manipulate it we have to hack
253 into Windows TEB (thread environment block).
254 Since this structure is private, error code offset changes from version to version.
255 The following offsets are known:
256 * Windows 95 and 98 - 0x60
257 * Windows Me - 0x74
258 * Windows NT (all family, fixed at last) - 0x34
260 switch(osver.dwPlatformId) {
261 case VER_PLATFORM_WIN32_WINDOWS:
262 if (osver.dwMajorVersion == 4) {
263 if (osver.dwMinorVersion > 10)
264 LastErrOffset = 0x74;
265 else
266 LastErrOffset = 0x60;
268 break;
269 case VER_PLATFORM_WIN32_NT:
270 LastErrOffset = 0x34;
271 break;
273 if (LastErrOffset) {
274 MainTEB = NtCurrentTeb();
275 LastErrorPtr = MainTEB + LastErrOffset;
276 SwitcherThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TaskSwitcher, &SwData, 0, &SwitcherId);
277 if (SwitcherThread) {
278 D(printf("[KRN] Task switcher started, ID %lu\n", SwitcherId));
279 #ifdef SLOW
280 TimerPeriod = 5000;
281 #else
282 TimerPeriod = 1000/TimerPeriod;
283 #endif
284 VBLPeriod.QuadPart = -10000*(LONGLONG)TimerPeriod;
285 return SetWaitableTimer(SwData.IntObjects[INT_TIMER], &VBLPeriod, TimerPeriod, NULL, NULL, 0);
287 D(else printf("[KRN] Failed to run task switcher thread\n");)
288 } else
289 printf("Unsupported Windows version %u.%u, platform ID %u\n", osver.dwMajorVersion, osver.dwMinorVersion, osver.dwPlatformId);
291 D(else printf("[KRN] failed to get thread handle\n");)
293 D(else printf("[KRN] Failed to create timer interrupt\n");)
295 D(else printf("[KRN] failed to create interrupt objects\n");)
296 CleanupIntObjects(SwData.IntObjects);
297 return 0;
301 * This is the only function to be called by modules other than kernel.resource.
302 * It is used for causing interrupts from within asynchronous threads of
303 * emul.handler and wingdi.hidd.
306 unsigned long __declspec(dllexport) KrnCauseIRQ(unsigned char irq)
308 unsigned long res;
310 D(printf("[kernel IRQ] Causing IRQ %u\n", irq));
311 res = SetEvent(SwData.IntObjects[irq]);
312 D(printf("[kernel IRQ] Result: %ld\n", res));
313 return res;