3 #include <aros/system.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
;
14 #include <exec/lists.h>
15 #include <exec/execbase.h>
16 #include "kernel_intern.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
29 HANDLE IntObjects
[INTERRUPTS_NUM
];
32 struct SwitcherData SwData
;
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
)
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
;
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
)
72 core_Dispatch(Except
->ContextRecord
);
75 core_Switch(Except
->ContextRecord
);
78 core_Schedule(Except
->ContextRecord
);
81 CONTEXT_RESTORE_REGS(Except
->ContextRecord
);
83 return EXCEPTION_CONTINUE_EXECUTION
;
85 printf("[KRN] Exception 0x%08lX handler. Context @ %p, SysBase @ %p, KernelBase @ %p\n", Except
->ExceptionRecord
->ExceptionCode
, Except
->ContextRecord
, SysBase
, KernelBase
);
88 struct Task
*t
= SysBase
->ThisTask
;
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--");
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
)
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
));
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
));
131 user_handler(obj
, (*KernelBasePtr
)->kb_Interrupts
);
132 core_ExitInterrupt(&MainCtx
);
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
));
142 PendingInts
[obj
] = 1;
143 DS(bug("[KRN] Interrupts are disabled, interrupt %lu is pending\n", obj
));
146 /* We've entered sleep mode */
147 Sleep_Mode
= SLEEP_MODE_ON
;
149 DS(res
=) ResumeThread(args
->MainThread
);
150 DS(bug("[Task switcher] Resume thread result: %lu\n", res
));
156 /* ****** Interface functions ****** */
158 long __declspec(dllexport
) core_intr_disable(void)
160 DI(printf("[KRN] disabling interrupts\n"));
164 long __declspec(dllexport
) core_intr_enable(void)
168 DI(printf("[KRN] enabling interrupts\n"));
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
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 */
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)
199 BOOL
InitIntObjects(HANDLE
*Objs
)
203 for (i
= 0; i
< INTERRUPTS_NUM
; i
++) {
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
);
216 void CleanupIntObjects(HANDLE
*Objs
)
220 for (i
= 0; i
< INTERRUPTS_NUM
; i
++) {
222 CloseHandle(Objs
[i
]);
226 int __declspec(dllexport
) core_init(unsigned long TimerPeriod
, struct ExecBase
**SysBasePointer
, struct KernelBase
**KernelBasePointer
)
229 HANDLE SwitcherThread
;
230 LARGE_INTEGER VBLPeriod
;
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
;
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
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;
266 LastErrOffset
= 0x60;
269 case VER_PLATFORM_WIN32_NT
:
270 LastErrOffset
= 0x34;
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
));
282 TimerPeriod
= 1000/TimerPeriod
;
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");)
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
);
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
)
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
));