1 ;****************************************************************************
3 ;* SciTech OS Portability Manager Library
5 ;* ========================================================================
7 ;* The contents of this file are subject to the SciTech MGL Public
8 ;* License Version 1.0 (the "License"); you may not use this file
9 ;* except in compliance with the License. You may obtain a copy of
10 ;* the License at http://www.scitechsoft.com/mgl-license.txt
12 ;* Software distributed under the License is distributed on an
13 ;* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 ;* implied. See the License for the specific language governing
15 ;* rights and limitations under the License.
17 ;* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
19 ;* The Initial Developer of the Original Code is SciTech Software, Inc.
20 ;* All Rights Reserved.
22 ;* ========================================================================
24 ;* Language: 80386 Assembler, TASM 4.0 or NASM
25 ;* Environment: 32-bit Windows NT device driver
27 ;* Description: Low level assembly support for the PM library specific to
28 ;* Windows NT device drivers.
30 ;****************************************************************************
34 include "scitech.mac" ; Memory model macros
36 header _irq ; Set up memory model
40 cextern _PM_rtcHandler,CPTR
41 cextern _PM_prevRTC,FCPTR
43 RtcInside dw 0 ; Are we still handling current interrupt
44 sidtBuf df 0 ; Buffer for sidt instruction
48 begcodeseg _irq ; Start of code segment
50 cpublic _PM_irqCodeStart
52 ; Macro to delay briefly to ensure that enough time has elapsed between
53 ; successive I/O accesses so that the device being accessed can respond
54 ; to both accesses even on a very fast PC.
80 ;----------------------------------------------------------------------------
81 ; PM_rtcISR - Real time clock interrupt subroutine dispatcher
82 ;----------------------------------------------------------------------------
83 ; Hardware interrupt handler for the timer interrupt, to dispatch control
84 ; to high level C based subroutines. We save the state of all registers
85 ; in this routine, and switch to a local stack. Interrupts are *off*
86 ; when we call the user code.
88 ; NOTE: This routine switches to a local stack before calling any C code,
89 ; and hence is _not_ re-entrant. Make sure your C code executes as
90 ; quickly as possible, since a timer overrun will simply hang the
92 ;----------------------------------------------------------------------------
95 ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
96 ; If we enable interrupts and call into any C based interrupt handling code,
97 ; we need to setup a bunch of important information for the NT kernel. The
98 ; code below takes care of this housekeeping for us (see Undocumented NT for
99 ; details). If we don't do this housekeeping and interrupts are enabled,
100 ; the kernel will become very unstable and crash within 10 seconds or so.
101 ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
112 ; Setup the exception frame to NULL
114 mov ebx,[DWORD cs:0FFDFF000h]
115 mov [DWORD ds:0FFDFF000h], 0FFFFFFFFh
118 ; Save away the existing KSS ebp
120 mov esi,[DWORD cs:0FFDFF124h]
121 mov ebx,[DWORD esi+00000128h]
122 mov [DWORD ebp+4h],ebx
123 mov [DWORD esi+00000128h],ebp
125 ; Save away the kernel time and the thread mode (kernel/user)
127 mov edi,[DWORD esi+00000137h]
128 mov [DWORD ebp+8h],edi
130 ; Set the thread mode (kernel/user) based on the code selector
132 mov ebx,[DWORD ebp+7Ch]
134 mov [BYTE esi+00000137h],bl
136 ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
137 ; End of special interrupt Prolog code
138 ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
140 ; Clear priority interrupt controller and re-enable interrupts so we
141 ; dont lock things up for long.
147 ; Clear real-time clock timeout
149 in al,70h ; Read CMOS index register
150 push eax ; and save for later
157 ; Call the C interrupt handler function
159 cmp [BYTE RtcInside],1 ; Check for mutual exclusion
161 mov [BYTE RtcInside],1
162 sti ; Enable interrupts
163 cld ; Clear direction flag for C code
164 call [CPTR _PM_rtcHandler]
165 cli ; Disable interrupts on exit!
166 mov [BYTE RtcInside],0
169 out 70h,al ; Restore CMOS index register
171 ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
172 ; Start of special epilog code to restore stuff on exit from handler
173 ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
175 ; Restore the KSS ebp
177 mov esi,[DWORD cs:0FFDFF124h]
178 mov ebx,[DWORD ebp+4]
179 mov [DWORD esi+00000128h],ebx
181 ; Restore the exception frame
184 mov [DWORD fs:00000000],ebx
186 ; Restore the thread mode
188 mov ebx,[DWORD ebp+8h]
189 mov esi,[DWORD fs:00000124h]
190 mov [BYTE esi+00000137h],bl
196 ; Return from interrupt
202 cpublic _PM_irqCodeEnd
204 ;----------------------------------------------------------------------------
205 ; void _PM_getISR(int irq,PMFARPTR *handler);
206 ;----------------------------------------------------------------------------
207 ; Function to return the specific IRQ handler direct from the IDT.
208 ;----------------------------------------------------------------------------
209 cprocstart _PM_getISR
211 ARG idtEntry:UINT, handler:DPTR
214 mov ecx,[handler] ; Get address of handler to fill in
215 sidt [sidtBuf] ; Get IDTR register into sidtBuf
216 mov eax,[DWORD sidtBuf+2] ; Get address of IDT into EAX
218 lea eax,[eax+ebx*8] ; Get entry in the IDT
219 movzx edx,[WORD eax+6] ; Get high order 16-bits
220 shl edx,16 ; Move into top 16-bits of address
221 mov dx,[WORD eax] ; Get low order 16-bits
222 mov [DWORD ecx],edx ; Store linear address of handler
223 mov dx,[WORD eax+2] ; Get selector value
224 mov [WORD ecx+4],dx ; Store selector value
230 ;----------------------------------------------------------------------------
231 ; void _PM_setISR(int irq,void *handler);
232 ;----------------------------------------------------------------------------
233 ; Function to set the specific IRQ handler direct in the IDT.
234 ;----------------------------------------------------------------------------
235 cprocstart _PM_setISR
237 ARG irq:UINT, handler:CPTR
240 mov ecx,[handler] ; Get address of new handler
241 mov dx,cs ; Get selector for new handler
242 sidt [sidtBuf] ; Get IDTR register into sidtBuf
243 mov eax,[DWORD sidtBuf+2] ; Get address of IDT into EAX
245 lea eax,[eax+ebx*8] ; Get entry in the IDT
247 mov [WORD eax+2],dx ; Store code segment selector
248 mov [WORD eax],cx ; Store low order bits of handler
250 mov [WORD eax+6],cx ; Store high order bits of handler
257 ;----------------------------------------------------------------------------
258 ; void _PM_restoreISR(int irq,PMFARPTR *handler);
259 ;----------------------------------------------------------------------------
260 ; Function to set the specific IRQ handler direct in the IDT.
261 ;----------------------------------------------------------------------------
262 cprocstart _PM_restoreISR
264 ARG irq:UINT, handler:CPTR
268 mov dx,[WORD ecx+4] ; Get selector for old handler
269 mov ecx,[DWORD ecx] ; Get address of old handler
270 sidt [sidtBuf] ; Get IDTR register into sidtBuf
271 mov eax,[DWORD sidtBuf+2] ; Get address of IDT into EAX
273 lea eax,[eax+ebx*8] ; Get entry in the IDT
275 mov [WORD eax+2],dx ; Store code segment selector
276 mov [WORD eax],cx ; Store low order bits of handler
278 mov [WORD eax+6],cx ; Store high order bits of handler
283 cprocend _PM_restoreISR