2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
7 * This little utility is specific for Windows-hosted port. It allows you to enter
8 * SAD even on completely frozen system.
9 * It is written specifically to facilitate finding long-standing lockup bug.
10 * Additionally it can serve as a short example showing how to interact with Windows
12 * The program installs a hook on Windows console, which generates a NMI whenever the
13 * user presses Ctrl-Break in the console.
16 #include <aros/debug.h>
17 #include <proto/exec.h>
18 #include <proto/hostlib.h>
19 #include <proto/kernel.h>
24 #define __stdcall __attribute__((ms_abi))
26 #define __stdcall __attribute__((stdcall))
29 #define WAIT_TIMEOUT 0x00000102
31 struct KernelInterface
33 int (*KrnAllocIRQ
)(void);
34 void (*KrnFreeIRQ
)(unsigned char irq
);
35 void (*KrnCauseIRQ
)(unsigned char irq
);
40 struct Kernel32Interface
42 ULONG
__stdcall (*SetConsoleCtrlHandler
)(void *HandlerRoutine
, ULONG Add
);
43 APTR
__stdcall (*CreateEvent
)(void *lpEventAttributes
, ULONG bManualReset
, ULONG bInitialState
, const char *lpName
);
44 ULONG
__stdcall (*CloseHandle
)(APTR hObject
);
45 ULONG
__stdcall (*SetEvent
)(APTR hEvent
);
46 ULONG
__stdcall (*WaitForSingleObject
)(void *hHandle
, ULONG dwMilliseconds
);
51 static struct KernelInterface
*kernelIf
;
52 static struct Kernel32Interface
*winIf
;
54 static const char *symbols
[] =
64 static const char *kern32_symbols
[] =
66 "SetConsoleCtrlHandler",
70 "WaitForSingleObject",
74 static void DebugInterrupt(void *a1
, void *a2
)
77 * Acknowledge the interrupt and call SAD.
78 * Acknowledgement mechanism is needed for very heavy lockups, when interrupts
79 * become inresponsive. Our console hook will wait for 3 seconds, and if this
80 * timeout expores, we consider that our virtualized CPU is dead, and run SAD
81 * right from within console hook. Doing this under normal circumstances results
82 * in crash because of asynchronous re-entering user-mode code.
84 winIf
->SetEvent(intAck
);
89 * Be careful! This function is executed by Windows, in console's context!
90 * So no AROS calls here!!!
92 static ULONG __stdcall
ConsoleHook(ULONG event
)
94 if (event
== 1) /* CTRL_BREAK_EVENT */
98 kernelIf
->KrnCauseIRQ(debugIRQ
);
99 status
= winIf
->WaitForSingleObject(intAck
, 3000);
101 if (status
!= WAIT_TIMEOUT
)
105 * This will set supervisor flag. After this it's OK to call kprintf().
106 * We add 1 instead of just setting 1 in order to be able to know
107 * its original value.
108 * Note that here we are running outside of both AROS threads
109 * (supervisor and user). It's OK only because if we are here, interrupt
110 * thread went defunct, and this is the only thread running.
112 *kernelIf
->Supervisor
+= 1;
114 kprintf("Timeout waiting for NMI ACK, entering emergency SAD\n");
120 int __nocommandline
= 1;
127 APTR KernelBase
, HostLibBase
;
130 KernelBase
= OpenResource("kernel.resource");
133 printf("Failed to open kernel.resource ???\n");
137 HostLibBase
= OpenResource("hostlib.resource");
140 printf("hostlib.resource not found, likely native system\n");
144 kern32
= HostLib_Open("kernel32.dll", &errStr
);
147 printf("kernel32.dll: %s\n", errStr
);
148 HostLib_FreeErrorStr(errStr
);
152 winIf
= (struct Kernel32Interface
*)HostLib_GetInterface(kern32
, kern32_symbols
, &unres
);
153 if ((!winIf
) || unres
)
155 printf("Failed to obtain kernel.dll interface, %u symbols unresolved\n", unres
);
158 HostLib_DropInterface((void **)winIf
);
159 HostLib_Close(kern32
, NULL
);
163 kernel
= HostLib_Open("Libs\\Host\\kernel.dll", &errStr
);
166 printf("kernel.dll: %s\n", errStr
);
167 HostLib_FreeErrorStr(errStr
);
168 HostLib_DropInterface((void **)winIf
);
169 HostLib_Close(kern32
, NULL
);
173 kernelIf
= (struct KernelInterface
*)HostLib_GetInterface(kernel
, symbols
, &unres
);
174 if ((!kernelIf
) || unres
)
176 printf("Failed to obtain kernel.dll interface, %u symbols unresolved\n", unres
);
179 HostLib_DropInterface((void **)kernelIf
);
180 HostLib_DropInterface((void **)winIf
);
181 HostLib_Close(kernel
, NULL
);
182 HostLib_Close(kern32
, NULL
);
186 debugIRQ
= kernelIf
->KrnAllocIRQ();
189 printf("Failed to create NMI interrupt!\n");
190 HostLib_DropInterface((void **)kernelIf
);
191 HostLib_DropInterface((void **)winIf
);
192 HostLib_Close(kernel
, NULL
);
193 HostLib_Close(kern32
, NULL
);
198 intHandle
= KrnAddIRQHandler(debugIRQ
, DebugInterrupt
, NULL
, NULL
);
201 printf("Failed to add IRQ handler\n");
203 HostLib_DropInterface((void **)kernelIf
);
204 HostLib_DropInterface((void **)winIf
);
205 HostLib_Close(kernel
, NULL
);
206 HostLib_Close(kern32
, NULL
);
211 intAck
= winIf
->CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
213 unres
= winIf
->SetConsoleCtrlHandler(ConsoleHook
, TRUE
);
218 /* Yes, NonMaskable IRQ exists solely for us dirty hackers */
219 *kernelIf
->NonMaskableIRQ
= debugIRQ
; /* This turns IRQ into NMI */
221 printf("Debug NMI#%d installed, press Ctrl-C to uninstall\n", debugIRQ
);
222 Wait(SIGBREAKF_CTRL_C
);
224 printf("Done, exiting\n");
226 /* Disable NMI, or bad things may happen if someone reuses this IRQ number */
227 *kernelIf
->NonMaskableIRQ
= -1;
230 printf("Failed to install console hook\n");
234 winIf
->SetConsoleCtrlHandler(ConsoleHook
, FALSE
);
235 winIf
->CloseHandle(intAck
);
238 KrnRemIRQHandler(intHandle
);
239 kernelIf
->KrnFreeIRQ(debugIRQ
);
240 HostLib_DropInterface((void **)kernelIf
);
241 HostLib_DropInterface((void **)winIf
);
242 HostLib_Close(kernel
, NULL
);
243 HostLib_Close(kern32
, NULL
);