]>
Commit | Line | Data |
---|---|---|
c7de829c WD |
1 | ;**************************************************************************** |
2 | ;* | |
3 | ;* SciTech OS Portability Manager Library | |
4 | ;* | |
5 | ;* ======================================================================== | |
6 | ;* | |
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 | |
11 | ;* | |
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. | |
16 | ;* | |
17 | ;* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc. | |
18 | ;* | |
19 | ;* The Initial Developer of the Original Code is SciTech Software, Inc. | |
20 | ;* All Rights Reserved. | |
21 | ;* | |
22 | ;* ======================================================================== | |
23 | ;* | |
24 | ;* Language: 80386 Assembler, TASM 4.0 or NASM | |
25 | ;* Environment: 32-bit SMX embedded systems development | |
26 | ;* | |
27 | ;* Description: Low level assembly support for the PM library specific to | |
28 | ;* SMX interrupt handling. | |
29 | ;* | |
30 | ;**************************************************************************** | |
31 | ||
32 | IDEAL | |
33 | ||
34 | include "scitech.mac" ; Memory model macros | |
35 | ||
36 | header _pmsmx ; Set up memory model | |
37 | ||
38 | ; Define the size of our local stacks. For real mode code they cant be | |
39 | ; that big, but for 32 bit protected mode code we can make them nice and | |
40 | ; large so that complex C functions can be used. | |
41 | ||
42 | MOUSE_STACK EQU 4096 | |
43 | TIMER_STACK EQU 4096 | |
44 | KEY_STACK EQU 1024 | |
45 | INT10_STACK EQU 1024 | |
46 | ||
47 | ifdef USE_NASM | |
48 | ||
49 | ; Macro to load DS and ES registers with correct value. | |
50 | ||
51 | %imacro LOAD_DS 0 | |
52 | mov ds,[cs:_PM_savedDS] | |
53 | mov es,[cs:_PM_savedDS] | |
54 | %endmacro | |
55 | ||
56 | ; Note that interrupts we disable interrupts during the following stack | |
57 | ; %imacro for correct operation, but we do not enable them again. Normally | |
58 | ; these %imacros are used within interrupt handlers so interrupts should | |
59 | ; already be off. We turn them back on explicitly later if the user code | |
60 | ; needs them to be back on. | |
61 | ||
62 | ; Macro to switch to a new local stack. | |
63 | ||
64 | %imacro NEWSTK 1 | |
65 | cli | |
66 | mov [seg_%1],ss | |
67 | mov [ptr_%1],_sp | |
68 | mov [TempSeg],ds | |
69 | mov ss,[TempSeg] | |
70 | mov _sp,offset %1 | |
71 | %endmacro | |
72 | ||
73 | ; %imacro to switch back to the old stack. | |
74 | ||
75 | %imacro RESTSTK 1 | |
76 | cli | |
77 | mov ss,[seg_%1] | |
78 | mov _sp,[ptr_%1] | |
79 | %endmacro | |
80 | ||
81 | ; %imacro to swap the current stack with the one saved away. | |
82 | ||
83 | %imacro SWAPSTK 1 | |
84 | cli | |
85 | mov ax,ss | |
86 | xchg ax,[seg_%1] | |
87 | mov ss,ax | |
88 | xchg _sp,[ptr_%1] | |
89 | %endmacro | |
90 | ||
91 | else | |
92 | ||
93 | ; Macro to load DS and ES registers with correct value. | |
94 | ||
95 | MACRO LOAD_DS | |
96 | mov ds,[cs:_PM_savedDS] | |
97 | mov es,[cs:_PM_savedDS] | |
98 | ENDM | |
99 | ||
100 | ; Note that interrupts we disable interrupts during the following stack | |
101 | ; macro for correct operation, but we do not enable them again. Normally | |
102 | ; these macros are used within interrupt handlers so interrupts should | |
103 | ; already be off. We turn them back on explicitly later if the user code | |
104 | ; needs them to be back on. | |
105 | ||
106 | ; Macro to switch to a new local stack. | |
107 | ||
108 | MACRO NEWSTK stkname | |
109 | cli | |
110 | mov [seg_&stkname&],ss | |
111 | mov [ptr_&stkname&],_sp | |
112 | mov [TempSeg],ds | |
113 | mov ss,[TempSeg] | |
114 | mov _sp,offset stkname | |
115 | ENDM | |
116 | ||
117 | ; Macro to switch back to the old stack. | |
118 | ||
119 | MACRO RESTSTK stkname | |
120 | cli | |
121 | mov ss,[seg_&stkname&] | |
122 | mov _sp,[ptr_&stkname&] | |
123 | ENDM | |
124 | ||
125 | ; Macro to swap the current stack with the one saved away. | |
126 | ||
127 | MACRO SWAPSTK stkname | |
128 | cli | |
129 | mov ax,ss | |
130 | xchg ax,[seg_&stkname&] | |
131 | mov ss,ax | |
132 | xchg _sp,[ptr_&stkname&] | |
133 | ENDM | |
134 | ||
135 | endif | |
136 | ||
137 | begdataseg _pmsmx | |
138 | ||
139 | cextern _PM_savedDS,USHORT | |
140 | cextern _PM_critHandler,CPTR | |
141 | cextern _PM_breakHandler,CPTR | |
142 | cextern _PM_timerHandler,CPTR | |
143 | cextern _PM_rtcHandler,CPTR | |
144 | cextern _PM_keyHandler,CPTR | |
145 | cextern _PM_key15Handler,CPTR | |
146 | cextern _PM_mouseHandler,CPTR | |
147 | cextern _PM_int10Handler,CPTR | |
148 | ||
149 | cextern _PM_ctrlCPtr,DPTR | |
150 | cextern _PM_ctrlBPtr,DPTR | |
151 | cextern _PM_critPtr,DPTR | |
152 | ||
153 | cextern _PM_prevTimer,FCPTR | |
154 | cextern _PM_prevRTC,FCPTR | |
155 | cextern _PM_prevKey,FCPTR | |
156 | cextern _PM_prevKey15,FCPTR | |
157 | cextern _PM_prevBreak,FCPTR | |
158 | cextern _PM_prevCtrlC,FCPTR | |
159 | cextern _PM_prevCritical,FCPTR | |
160 | cextern _PM_prevRealTimer,ULONG | |
161 | cextern _PM_prevRealRTC,ULONG | |
162 | cextern _PM_prevRealKey,ULONG | |
163 | cextern _PM_prevRealKey15,ULONG | |
164 | cextern _PM_prevRealInt10,ULONG | |
165 | ||
166 | cpublic _PM_pmsmxDataStart | |
167 | ||
168 | ; Allocate space for all of the local stacks that we need. These stacks | |
169 | ; are not very large, but should be large enough for most purposes | |
170 | ; (generally you want to handle these interrupts quickly, simply storing | |
171 | ; the information for later and then returning). If you need bigger | |
172 | ; stacks then change the appropriate value in here. | |
173 | ||
174 | ALIGN 4 | |
175 | dclb MOUSE_STACK ; Space for local stack (small) | |
176 | MsStack: ; Stack starts at end! | |
177 | ptr_MsStack DUINT 0 ; Place to store old stack offset | |
178 | seg_MsStack dw 0 ; Place to store old stack segment | |
179 | ||
180 | ALIGN 4 | |
181 | dclb INT10_STACK ; Space for local stack (small) | |
182 | Int10Stack: ; Stack starts at end! | |
183 | ptr_Int10Stack DUINT 0 ; Place to store old stack offset | |
184 | seg_Int10Stack dw 0 ; Place to store old stack segment | |
185 | ||
186 | ALIGN 4 | |
187 | dclb TIMER_STACK ; Space for local stack (small) | |
188 | TmStack: ; Stack starts at end! | |
189 | ptr_TmStack DUINT 0 ; Place to store old stack offset | |
190 | seg_TmStack dw 0 ; Place to store old stack segment | |
191 | ||
192 | ALIGN 4 | |
193 | dclb TIMER_STACK ; Space for local stack (small) | |
194 | RtcStack: ; Stack starts at end! | |
195 | ptr_RtcStack DUINT 0 ; Place to store old stack offset | |
196 | seg_RtcStack dw 0 ; Place to store old stack segment | |
197 | RtcInside dw 0 ; Are we still handling current interrupt | |
198 | ||
199 | ALIGN 4 | |
200 | dclb KEY_STACK ; Space for local stack (small) | |
201 | KyStack: ; Stack starts at end! | |
202 | ptr_KyStack DUINT 0 ; Place to store old stack offset | |
203 | seg_KyStack dw 0 ; Place to store old stack segment | |
204 | KyInside dw 0 ; Are we still handling current interrupt | |
205 | ||
206 | ALIGN 4 | |
207 | dclb KEY_STACK ; Space for local stack (small) | |
208 | Ky15Stack: ; Stack starts at end! | |
209 | ptr_Ky15Stack DUINT 0 ; Place to store old stack offset | |
210 | seg_Ky15Stack dw 0 ; Place to store old stack segment | |
211 | ||
212 | TempSeg dw 0 ; Place to store stack segment | |
213 | ||
214 | cpublic _PM_pmsmxDataEnd | |
215 | ||
216 | enddataseg _pmsmx | |
217 | ||
218 | begcodeseg _pmsmx ; Start of code segment | |
219 | ||
220 | cpublic _PM_pmsmxCodeStart | |
221 | ||
222 | ;---------------------------------------------------------------------------- | |
223 | ; PM_mouseISR - Mouse interrupt subroutine dispatcher | |
224 | ;---------------------------------------------------------------------------- | |
225 | ; Interrupt subroutine called by the mouse driver upon interrupts, to | |
226 | ; dispatch control to high level C based subroutines. Interrupts are on | |
227 | ; when we call the user code. | |
228 | ; | |
229 | ; It is _extremely_ important to save the state of the extended registers | |
230 | ; as these may well be trashed by the routines called from here and not | |
231 | ; restored correctly by the mouse interface module. | |
232 | ; | |
233 | ; NOTE: This routine switches to a local stack before calling any C code, | |
234 | ; and hence is _not_ re-entrant. For mouse handlers this is not a | |
235 | ; problem, as the mouse driver arbitrates calls to the user mouse | |
236 | ; handler for us. | |
237 | ; | |
238 | ; Entry: AX - Condition mask giving reason for call | |
239 | ; BX - Mouse button state | |
240 | ; CX - Horizontal cursor coordinate | |
241 | ; DX - Vertical cursor coordinate | |
242 | ; SI - Horizontal mickey value | |
243 | ; DI - Vertical mickey value | |
244 | ; | |
245 | ;---------------------------------------------------------------------------- | |
246 | cprocfar _PM_mouseISR | |
247 | ||
248 | push ds ; Save value of DS | |
249 | push es | |
250 | pushad ; Save _all_ extended registers | |
251 | cld ; Clear direction flag | |
252 | ||
253 | LOAD_DS ; Load DS register | |
254 | NEWSTK MsStack ; Switch to local stack | |
255 | ||
256 | ; Call the installed high level C code routine | |
257 | ||
258 | clrhi dx ; Clear out high order values | |
259 | clrhi cx | |
260 | clrhi bx | |
261 | clrhi ax | |
262 | sgnhi si | |
263 | sgnhi di | |
264 | ||
265 | push _di | |
266 | push _si | |
267 | push _dx | |
268 | push _cx | |
269 | push _bx | |
270 | push _ax | |
271 | sti ; Enable interrupts | |
272 | call [CPTR _PM_mouseHandler] | |
273 | _add sp,12,24 | |
274 | ||
275 | RESTSTK MsStack ; Restore previous stack | |
276 | ||
277 | popad ; Restore all extended registers | |
278 | pop es | |
279 | pop ds | |
280 | ret ; We are done!! | |
281 | ||
282 | cprocend | |
283 | ||
284 | ;---------------------------------------------------------------------------- | |
285 | ; PM_timerISR - Timer interrupt subroutine dispatcher | |
286 | ;---------------------------------------------------------------------------- | |
287 | ; Hardware interrupt handler for the timer interrupt, to dispatch control | |
288 | ; to high level C based subroutines. We save the state of all registers | |
289 | ; in this routine, and switch to a local stack. Interrupts are *off* | |
290 | ; when we call the user code. | |
291 | ; | |
292 | ; NOTE: This routine switches to a local stack before calling any C code, | |
293 | ; and hence is _not_ re-entrant. Make sure your C code executes as | |
294 | ; quickly as possible, since a timer overrun will simply hang the | |
295 | ; system. | |
296 | ;---------------------------------------------------------------------------- | |
297 | cprocfar _PM_timerISR | |
298 | ||
299 | push ds ; Save value of DS | |
300 | push es | |
301 | pushad ; Save _all_ extended registers | |
302 | cld ; Clear direction flag | |
303 | ||
304 | LOAD_DS ; Load DS register | |
305 | ||
306 | NEWSTK TmStack ; Switch to local stack | |
307 | call [CPTR _PM_timerHandler] | |
308 | RESTSTK TmStack ; Restore previous stack | |
309 | ||
310 | popad ; Restore all extended registers | |
311 | pop es | |
312 | pop ds | |
313 | iret ; Return from interrupt | |
314 | ||
315 | cprocend | |
316 | ||
317 | ;---------------------------------------------------------------------------- | |
318 | ; PM_chainPrevTimer - Chain to previous timer interrupt and return | |
319 | ;---------------------------------------------------------------------------- | |
320 | ; Chains to the previous timer interrupt routine and returns control | |
321 | ; back to the high level interrupt handler. | |
322 | ;---------------------------------------------------------------------------- | |
323 | cprocstart PM_chainPrevTimer | |
324 | ||
325 | ifdef TNT | |
326 | push eax | |
327 | push ebx | |
328 | push ecx | |
329 | pushfd ; Push flags on stack to simulate interrupt | |
330 | mov ax,250Eh ; Call real mode procedure function | |
331 | mov ebx,[_PM_prevRealTimer] | |
332 | mov ecx,1 ; Copy real mode flags to real mode stack | |
333 | int 21h ; Call the real mode code | |
334 | popfd | |
335 | pop ecx | |
336 | pop ebx | |
337 | pop eax | |
338 | ret | |
339 | else | |
340 | SWAPSTK TmStack ; Swap back to previous stack | |
341 | pushf ; Save state of interrupt flag | |
342 | pushf ; Push flags on stack to simulate interrupt | |
343 | ifdef USE_NASM | |
344 | call far dword [_PM_prevTimer] | |
345 | else | |
346 | call [_PM_prevTimer] | |
347 | endif | |
348 | popf ; Restore state of interrupt flag | |
349 | SWAPSTK TmStack ; Swap back to C stack again | |
350 | ret | |
351 | endif | |
352 | ||
353 | cprocend | |
354 | ||
355 | ; Macro to delay briefly to ensure that enough time has elapsed between | |
356 | ; successive I/O accesses so that the device being accessed can respond | |
357 | ; to both accesses even on a very fast PC. | |
358 | ||
359 | ifdef USE_NASM | |
360 | %macro DELAY 0 | |
361 | jmp short $+2 | |
362 | jmp short $+2 | |
363 | jmp short $+2 | |
364 | %endmacro | |
365 | %macro IODELAYN 1 | |
366 | %rep %1 | |
367 | DELAY | |
368 | %endrep | |
369 | %endmacro | |
370 | else | |
371 | macro DELAY | |
372 | jmp short $+2 | |
373 | jmp short $+2 | |
374 | jmp short $+2 | |
375 | endm | |
376 | macro IODELAYN N | |
377 | rept N | |
378 | DELAY | |
379 | endm | |
380 | endm | |
381 | endif | |
382 | ||
383 | ;---------------------------------------------------------------------------- | |
384 | ; PM_rtcISR - Real time clock interrupt subroutine dispatcher | |
385 | ;---------------------------------------------------------------------------- | |
386 | ; Hardware interrupt handler for the timer interrupt, to dispatch control | |
387 | ; to high level C based subroutines. We save the state of all registers | |
388 | ; in this routine, and switch to a local stack. Interrupts are *off* | |
389 | ; when we call the user code. | |
390 | ; | |
391 | ; NOTE: This routine switches to a local stack before calling any C code, | |
392 | ; and hence is _not_ re-entrant. Make sure your C code executes as | |
393 | ; quickly as possible, since a timer overrun will simply hang the | |
394 | ; system. | |
395 | ;---------------------------------------------------------------------------- | |
396 | cprocfar _PM_rtcISR | |
397 | ||
398 | push ds ; Save value of DS | |
399 | push es | |
400 | pushad ; Save _all_ extended registers | |
401 | cld ; Clear direction flag | |
402 | ||
403 | ; Clear priority interrupt controller and re-enable interrupts so we | |
404 | ; dont lock things up for long. | |
405 | ||
406 | mov al,20h | |
407 | out 0A0h,al | |
408 | out 020h,al | |
409 | ||
410 | ; Clear real-time clock timeout | |
411 | ||
412 | in al,70h ; Read CMOS index register | |
413 | push _ax ; and save for later | |
414 | IODELAYN 3 | |
415 | mov al,0Ch | |
416 | out 70h,al | |
417 | IODELAYN 5 | |
418 | in al,71h | |
419 | ||
420 | ; Call the C interrupt handler function | |
421 | ||
422 | LOAD_DS ; Load DS register | |
423 | cmp [BYTE RtcInside],1 ; Check for mutual exclusion | |
424 | je @@Exit | |
425 | mov [BYTE RtcInside],1 | |
426 | sti ; Re-enable interrupts | |
427 | NEWSTK RtcStack ; Switch to local stack | |
428 | call [CPTR _PM_rtcHandler] | |
429 | RESTSTK RtcStack ; Restore previous stack | |
430 | mov [BYTE RtcInside],0 | |
431 | ||
432 | @@Exit: pop _ax | |
433 | out 70h,al ; Restore CMOS index register | |
434 | popad ; Restore all extended registers | |
435 | pop es | |
436 | pop ds | |
437 | iret ; Return from interrupt | |
438 | ||
439 | cprocend | |
440 | ||
441 | ;---------------------------------------------------------------------------- | |
442 | ; PM_keyISR - keyboard interrupt subroutine dispatcher | |
443 | ;---------------------------------------------------------------------------- | |
444 | ; Hardware interrupt handler for the keyboard interrupt, to dispatch control | |
445 | ; to high level C based subroutines. We save the state of all registers | |
446 | ; in this routine, and switch to a local stack. Interrupts are *off* | |
447 | ; when we call the user code. | |
448 | ; | |
449 | ; NOTE: This routine switches to a local stack before calling any C code, | |
450 | ; and hence is _not_ re-entrant. However we ensure within this routine | |
451 | ; mutual exclusion to the keyboard handling routine. | |
452 | ;---------------------------------------------------------------------------- | |
453 | cprocfar _PM_keyISR | |
454 | ||
455 | push ds ; Save value of DS | |
456 | push es | |
457 | pushad ; Save _all_ extended registers | |
458 | cld ; Clear direction flag | |
459 | ||
460 | LOAD_DS ; Load DS register | |
461 | ||
462 | cmp [BYTE KyInside],1 ; Check for mutual exclusion | |
463 | je @@Reissued | |
464 | ||
465 | mov [BYTE KyInside],1 | |
466 | NEWSTK KyStack ; Switch to local stack | |
467 | call [CPTR _PM_keyHandler] ; Call C code | |
468 | RESTSTK KyStack ; Restore previous stack | |
469 | mov [BYTE KyInside],0 | |
470 | ||
471 | @@Exit: popad ; Restore all extended registers | |
472 | pop es | |
473 | pop ds | |
474 | iret ; Return from interrupt | |
475 | ||
476 | ; When the BIOS keyboard handler needs to change the SHIFT status lights | |
477 | ; on the keyboard, in the process of doing this the keyboard controller | |
478 | ; re-issues another interrupt, while the current handler is still executing. | |
479 | ; If we recieve another interrupt while still handling the current one, | |
480 | ; then simply chain directly to the previous handler. | |
481 | ; | |
482 | ; Note that for most DOS extenders, the real mode interrupt handler that we | |
483 | ; install takes care of this for us. | |
484 | ||
485 | @@Reissued: | |
486 | ifdef TNT | |
487 | push eax | |
488 | push ebx | |
489 | push ecx | |
490 | pushfd ; Push flags on stack to simulate interrupt | |
491 | mov ax,250Eh ; Call real mode procedure function | |
492 | mov ebx,[_PM_prevRealKey] | |
493 | mov ecx,1 ; Copy real mode flags to real mode stack | |
494 | int 21h ; Call the real mode code | |
495 | popfd | |
496 | pop ecx | |
497 | pop ebx | |
498 | pop eax | |
499 | else | |
500 | pushf | |
501 | ifdef USE_NASM | |
502 | call far dword [_PM_prevKey] | |
503 | else | |
504 | call [_PM_prevKey] | |
505 | endif | |
506 | endif | |
507 | jmp @@Exit | |
508 | ||
509 | cprocend | |
510 | ||
511 | ;---------------------------------------------------------------------------- | |
512 | ; PM_chainPrevkey - Chain to previous key interrupt and return | |
513 | ;---------------------------------------------------------------------------- | |
514 | ; Chains to the previous key interrupt routine and returns control | |
515 | ; back to the high level interrupt handler. | |
516 | ;---------------------------------------------------------------------------- | |
517 | cprocstart PM_chainPrevKey | |
518 | ||
519 | ifdef TNT | |
520 | push eax | |
521 | push ebx | |
522 | push ecx | |
523 | pushfd ; Push flags on stack to simulate interrupt | |
524 | mov ax,250Eh ; Call real mode procedure function | |
525 | mov ebx,[_PM_prevRealKey] | |
526 | mov ecx,1 ; Copy real mode flags to real mode stack | |
527 | int 21h ; Call the real mode code | |
528 | popfd | |
529 | pop ecx | |
530 | pop ebx | |
531 | pop eax | |
532 | ret | |
533 | else | |
534 | ||
535 | ; YIKES! For some strange reason, when execution returns from the | |
536 | ; previous keyboard handler, interrupts are re-enabled!! Since we expect | |
537 | ; interrupts to remain off during the duration of our handler, this can | |
538 | ; cause havoc. However our stack macros always turn off interrupts, so they | |
539 | ; will be off when we exit this routine. Obviously there is a tiny weeny | |
540 | ; window when interrupts will be enabled, but there is nothing we can | |
541 | ; do about this. | |
542 | ||
543 | SWAPSTK KyStack ; Swap back to previous stack | |
544 | pushf ; Push flags on stack to simulate interrupt | |
545 | ifdef USE_NASM | |
546 | call far dword [_PM_prevKey] | |
547 | else | |
548 | call [_PM_prevKey] | |
549 | endif | |
550 | SWAPSTK KyStack ; Swap back to C stack again | |
551 | ret | |
552 | endif | |
553 | ||
554 | cprocend | |
555 | ||
556 | ;---------------------------------------------------------------------------- | |
557 | ; PM_key15ISR - Int 15h keyboard interrupt subroutine dispatcher | |
558 | ;---------------------------------------------------------------------------- | |
559 | ; This routine gets called if we have been called to handle the Int 15h | |
560 | ; keyboard interrupt callout from real mode. | |
561 | ; | |
562 | ; Entry: AX - Hardware scan code to process | |
563 | ; Exit: AX - Hardware scan code to process (0 to ignore) | |
564 | ;---------------------------------------------------------------------------- | |
565 | cprocfar _PM_key15ISR | |
566 | ||
567 | push ds | |
568 | push es | |
569 | LOAD_DS | |
570 | cmp ah,4Fh | |
571 | jnz @@NotOurs ; Quit if not keyboard callout | |
572 | ||
573 | pushad | |
574 | cld ; Clear direction flag | |
575 | xor ah,ah ; AX := scan code | |
576 | NEWSTK Ky15Stack ; Switch to local stack | |
577 | push _ax | |
578 | call [CPTR _PM_key15Handler] ; Call C code | |
579 | _add sp,2,4 | |
580 | RESTSTK Ky15Stack ; Restore previous stack | |
581 | test ax,ax | |
582 | jz @@1 | |
583 | stc ; Set carry to process as normal | |
584 | jmp @@2 | |
585 | @@1: clc ; Clear carry to ignore scan code | |
586 | @@2: popad | |
587 | jmp @@Exit ; We are done | |
588 | ||
589 | @@NotOurs: | |
590 | ifdef TNT | |
591 | push eax | |
592 | push ebx | |
593 | push ecx | |
594 | pushfd ; Push flags on stack to simulate interrupt | |
595 | mov ax,250Eh ; Call real mode procedure function | |
596 | mov ebx,[_PM_prevRealKey15] | |
597 | mov ecx,1 ; Copy real mode flags to real mode stack | |
598 | int 21h ; Call the real mode code | |
599 | popfd | |
600 | pop ecx | |
601 | pop ebx | |
602 | pop eax | |
603 | else | |
604 | pushf | |
605 | ifdef USE_NASM | |
606 | call far dword [_PM_prevKey15] | |
607 | else | |
608 | call [_PM_prevKey15] | |
609 | endif | |
610 | endif | |
611 | @@Exit: pop es | |
612 | pop ds | |
613 | retf 4 | |
614 | ||
615 | cprocend | |
616 | ||
617 | ;---------------------------------------------------------------------------- | |
618 | ; PM_breakISR - Control Break interrupt subroutine dispatcher | |
619 | ;---------------------------------------------------------------------------- | |
620 | ; Hardware interrupt handler for the Ctrl-Break interrupt. We simply set | |
621 | ; the Ctrl-Break flag to a 1 and leave (note that this is accessed through | |
622 | ; a far pointer, as it may well be located in conventional memory). | |
623 | ;---------------------------------------------------------------------------- | |
624 | cprocfar _PM_breakISR | |
625 | ||
626 | sti | |
627 | push ds ; Save value of DS | |
628 | push es | |
629 | push _bx | |
630 | ||
631 | LOAD_DS ; Load DS register | |
632 | mov ebx,[_PM_ctrlBPtr] | |
633 | mov [UINT _ES _bx],1 | |
634 | ||
635 | ; Run alternate break handler code if installed | |
636 | ||
637 | cmp [CPTR _PM_breakHandler],0 | |
638 | je @@Exit | |
639 | ||
640 | pushad | |
641 | mov _ax,1 | |
642 | push _ax | |
643 | call [CPTR _PM_breakHandler] ; Call C code | |
644 | pop _ax | |
645 | popad | |
646 | ||
647 | @@Exit: pop _bx | |
648 | pop es | |
649 | pop ds | |
650 | iret ; Return from interrupt | |
651 | ||
652 | cprocend | |
653 | ||
654 | ;---------------------------------------------------------------------------- | |
655 | ; int PM_ctrlBreakHit(int clearFlag) | |
656 | ;---------------------------------------------------------------------------- | |
657 | ; Returns the current state of the Ctrl-Break flag and possibly clears it. | |
658 | ;---------------------------------------------------------------------------- | |
659 | cprocstart PM_ctrlBreakHit | |
660 | ||
661 | ARG clearFlag:UINT | |
662 | ||
663 | enter_c | |
664 | pushf ; Save interrupt status | |
665 | push es | |
666 | mov ebx,[_PM_ctrlBPtr] | |
667 | cli ; No interrupts thanks! | |
668 | mov _ax,[_ES _bx] | |
669 | test [BYTE clearFlag],1 | |
670 | jz @@Done | |
671 | mov [UINT _ES _bx],0 | |
672 | ||
673 | @@Done: pop es | |
674 | popf ; Restore interrupt status | |
675 | leave_c | |
676 | ret | |
677 | ||
678 | cprocend | |
679 | ||
680 | ;---------------------------------------------------------------------------- | |
681 | ; PM_ctrlCISR - Control Break interrupt subroutine dispatcher | |
682 | ;---------------------------------------------------------------------------- | |
683 | ; Hardware interrupt handler for the Ctrl-C interrupt. We simply set | |
684 | ; the Ctrl-C flag to a 1 and leave (note that this is accessed through | |
685 | ; a far pointer, as it may well be located in conventional memory). | |
686 | ;---------------------------------------------------------------------------- | |
687 | cprocfar _PM_ctrlCISR | |
688 | ||
689 | sti | |
690 | push ds ; Save value of DS | |
691 | push es | |
692 | push _bx | |
693 | ||
694 | LOAD_DS ; Load DS register | |
695 | mov ebx,[_PM_ctrlCPtr] | |
696 | mov [UINT _ES _bx],1 | |
697 | ||
698 | ; Run alternate break handler code if installed | |
699 | ||
700 | cmp [CPTR _PM_breakHandler],0 | |
701 | je @@Exit | |
702 | ||
703 | pushad | |
704 | mov _ax,0 | |
705 | push _ax | |
706 | call [CPTR _PM_breakHandler] ; Call C code | |
707 | pop _ax | |
708 | popad | |
709 | ||
710 | @@Exit: pop _bx | |
711 | pop es | |
712 | pop ds | |
713 | iret ; Return from interrupt | |
714 | iretd | |
715 | ||
716 | cprocend | |
717 | ||
718 | ;---------------------------------------------------------------------------- | |
719 | ; int PM_ctrlCHit(int clearFlag) | |
720 | ;---------------------------------------------------------------------------- | |
721 | ; Returns the current state of the Ctrl-C flag and possibly clears it. | |
722 | ;---------------------------------------------------------------------------- | |
723 | cprocstart PM_ctrlCHit | |
724 | ||
725 | ARG clearFlag:UINT | |
726 | ||
727 | enter_c | |
728 | pushf ; Save interrupt status | |
729 | push es | |
730 | mov ebx,[_PM_ctrlCPtr] | |
731 | cli ; No interrupts thanks! | |
732 | mov _ax,[_ES _bx] | |
733 | test [BYTE clearFlag],1 | |
734 | jz @@Done | |
735 | mov [UINT _ES _bx],0 | |
736 | ||
737 | @@Done: | |
738 | pop es | |
739 | popf ; Restore interrupt status | |
740 | leave_c | |
741 | ret | |
742 | ||
743 | cprocend | |
744 | ||
745 | ;---------------------------------------------------------------------------- | |
746 | ; PM_criticalISR - Control Error handler interrupt subroutine dispatcher | |
747 | ;---------------------------------------------------------------------------- | |
748 | ; Interrupt handler for the MSDOS Critical Error interrupt, to dispatch | |
749 | ; control to high level C based subroutines. We save the state of all | |
750 | ; registers in this routine, and switch to a local stack. We also pass | |
751 | ; the values of the AX and DI registers to the as pointers, so that the | |
752 | ; values can be modified before returning to MSDOS. | |
753 | ;---------------------------------------------------------------------------- | |
754 | cprocfar _PM_criticalISR | |
755 | ||
756 | sti | |
757 | push ds ; Save value of DS | |
758 | push es | |
759 | push _bx ; Save register values changed | |
760 | cld ; Clear direction flag | |
761 | ||
762 | LOAD_DS ; Load DS register | |
763 | mov ebx,[_PM_critPtr] | |
764 | mov [_ES _bx],ax | |
765 | mov [_ES _bx+2],di | |
766 | ||
767 | ; Run alternate critical handler code if installed | |
768 | ||
769 | cmp [CPTR _PM_critHandler],0 | |
770 | je @@NoAltHandler | |
771 | ||
772 | pushad | |
773 | push _di | |
774 | push _ax | |
775 | call [CPTR _PM_critHandler] ; Call C code | |
776 | _add sp,4,8 | |
777 | popad | |
778 | ||
779 | pop _bx | |
780 | pop es | |
781 | pop ds | |
782 | iret ; Return from interrupt | |
783 | ||
784 | @@NoAltHandler: | |
785 | mov ax,3 ; Tell MSDOS to fail the operation | |
786 | pop _bx | |
787 | pop es | |
788 | pop ds | |
789 | iret ; Return from interrupt | |
790 | ||
791 | cprocend | |
792 | ||
793 | ;---------------------------------------------------------------------------- | |
794 | ; int PM_criticalError(int *axVal,int *diVal,int clearFlag) | |
795 | ;---------------------------------------------------------------------------- | |
796 | ; Returns the current state of the critical error flags, and the values that | |
797 | ; MSDOS passed in the AX and DI registers to our handler. | |
798 | ;---------------------------------------------------------------------------- | |
799 | cprocstart PM_criticalError | |
800 | ||
801 | ARG axVal:DPTR, diVal:DPTR, clearFlag:UINT | |
802 | ||
803 | enter_c | |
804 | pushf ; Save interrupt status | |
805 | push es | |
806 | mov ebx,[_PM_critPtr] | |
807 | cli ; No interrupts thanks! | |
808 | xor _ax,_ax | |
809 | xor _di,_di | |
810 | mov ax,[_ES _bx] | |
811 | mov di,[_ES _bx+2] | |
812 | test [BYTE clearFlag],1 | |
813 | jz @@NoClear | |
814 | mov [ULONG _ES _bx],0 | |
815 | @@NoClear: | |
816 | _les _bx,[axVal] | |
817 | mov [_ES _bx],_ax | |
818 | _les _bx,[diVal] | |
819 | mov [_ES _bx],_di | |
820 | pop es | |
821 | popf ; Restore interrupt status | |
822 | leave_c | |
823 | ret | |
824 | ||
825 | cprocend | |
826 | ||
827 | ;---------------------------------------------------------------------------- | |
828 | ; void PM_setMouseHandler(int mask, PM_mouseHandler mh) | |
829 | ;---------------------------------------------------------------------------- | |
830 | cprocstart _PM_setMouseHandler | |
831 | ||
832 | ARG mouseMask:UINT | |
833 | ||
834 | enter_c | |
835 | push es | |
836 | ||
837 | mov ax,0Ch ; AX := Function 12 - install interrupt sub | |
838 | mov _cx,[mouseMask] ; CX := mouse mask | |
839 | mov _dx,offset _PM_mouseISR | |
840 | push cs | |
841 | pop es ; ES:_DX -> mouse handler | |
842 | int 33h ; Call mouse driver | |
843 | ||
844 | pop es | |
845 | leave_c | |
846 | ret | |
847 | ||
848 | cprocend | |
849 | ||
850 | ;---------------------------------------------------------------------------- | |
851 | ; void PM_mousePMCB(void) | |
852 | ;---------------------------------------------------------------------------- | |
853 | ; Mouse realmode callback routine. Upon entry to this routine, we recieve | |
854 | ; the following from the DPMI server: | |
855 | ; | |
856 | ; Entry: DS:_SI -> Real mode stack at time of call | |
857 | ; ES:_DI -> Real mode register data structure | |
858 | ; SS:_SP -> Locked protected mode stack to use | |
859 | ;---------------------------------------------------------------------------- | |
860 | cprocfar _PM_mousePMCB | |
861 | ||
862 | pushad | |
863 | mov eax,[es:_di+1Ch] ; Load register values from real mode | |
864 | mov ebx,[es:_di+10h] | |
865 | mov ecx,[es:_di+18h] | |
866 | mov edx,[es:_di+14h] | |
867 | mov esi,[es:_di+04h] | |
868 | mov edi,[es:_di] | |
869 | call _PM_mouseISR ; Call the mouse handler | |
870 | popad | |
871 | ||
872 | mov ax,[ds:_si] | |
873 | mov [es:_di+2Ah],ax ; Plug in return IP address | |
874 | mov ax,[ds:_si+2] | |
875 | mov [es:_di+2Ch],ax ; Plug in return CS value | |
876 | add [WORD es:_di+2Eh],4 ; Remove return address from stack | |
877 | iret ; Go back to real mode! | |
878 | ||
879 | cprocend | |
880 | ||
881 | ;---------------------------------------------------------------------------- | |
882 | ; void PM_int10PMCB(void) | |
883 | ;---------------------------------------------------------------------------- | |
884 | ; int10 realmode callback routine. Upon entry to this routine, we recieve | |
885 | ; the following from the DPMI server: | |
886 | ; | |
887 | ; Entry: DS:ESI -> Real mode stack at time of call | |
888 | ; ES:EDI -> Real mode register data structure | |
889 | ; SS:ESP -> Locked protected mode stack to use | |
890 | ;---------------------------------------------------------------------------- | |
891 | cprocfar _PM_int10PMCB | |
892 | ||
893 | pushad | |
894 | push ds | |
895 | push es | |
896 | push fs | |
897 | ||
898 | pushfd | |
899 | pop eax | |
900 | mov [es:edi+20h],ax ; Save return flag status | |
901 | mov ax,[ds:esi] | |
902 | mov [es:edi+2Ah],ax ; Plug in return IP address | |
903 | mov ax,[ds:esi+2] | |
904 | mov [es:edi+2Ch],ax ; Plug in return CS value | |
905 | add [WORD es:edi+2Eh],4 ; Remove return address from stack | |
906 | ||
907 | ; Call the install int10 handler in protected mode. This function gets called | |
908 | ; with DS set to the current data selector, and ES:EDI pointing the the | |
909 | ; real mode DPMI register structure at the time of the interrupt. The | |
910 | ; handle must be written in assembler to be able to extract the real mode | |
911 | ; register values from the structure | |
912 | ||
913 | push es | |
914 | pop fs ; FS:EDI -> real mode registers | |
915 | LOAD_DS | |
916 | NEWSTK Int10Stack ; Switch to local stack | |
917 | ||
918 | call [_PM_int10Handler] | |
919 | ||
920 | RESTSTK Int10Stack ; Restore previous stack | |
921 | pop fs | |
922 | pop es | |
923 | pop ds | |
924 | popad | |
925 | iret ; Go back to real mode! | |
926 | ||
927 | cprocend | |
928 | ||
929 | cpublic _PM_pmsmxCodeEnd | |
930 | ||
931 | endcodeseg _pmsmx | |
932 | ||
933 | END ; End of module |