; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; * clock1 Stephen A. Shectman 1998 March 24 * ; * --------------------------------------------------------------- * ; * * ; * Improved assembly-language part of clock service routine. * ; * This version captures the actual hardware interrupt (08h). * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; assume cs:codeseg assume ds:dataseg .387 dataseg segment para rw public use32 'data' align 16 public clktop db 4096 dup (?) ;reserve space for a new stack clktop label byte ;pointer to new stack db 16 dup (?) ;make sure there's a space ndpsav db 128 dup (?) ;reserve space for 387 state align 16 dataseg ends codeseg segment para er public use32 'code' align 4 public _clock1_ public _clock0_ public _int162_ extrn _clock2_:near ; CLOCK1 changes the real-time clock interrupt vector ; to point to the protected-mode subroutine ACLOCK ; instead of to the BIOS clock routine. ; Since it is still necessary to call the BIOS routine ; periodically, CLOCK1 also sets an unused software ; interrupt vector (162 = A2h) to point to the BIOS ; clock routine. The BIOS vector is also returned in ; register eax. _clock1_ proc near push ebx ;save register mov cl, 08h ;DOS interrupt number mov ax, 2503h ;Phar Lap function call int 21h ;system call push ebx ;save real mode vector mov cl, 0A2h ;software interrupt number mov ax, 2505h ;Phar Lap function call int 21h ;system call lea edx, aclock ;address of subroutine mov cl, 08h ;DOS interrupt number mov ax, 2506h ;Phar Lap function call push ds ;save ds push cs ;transfer cs pop ds ;to ds int 21h ;system call pop ds ;restore ds pop eax ;return i*4 real mode vector pop ebx ;restore register ret ;return _clock1_ endp ; ACLOCK is the new target for the real-time clock ; interrupt. It establishes the appropriate data ; and stack segments for a high-level language, and ; sets up a new stack in local static storage. It ; also saves the state of the numeric coprocessor. ; Then it calls the routine CLOCK2 which can be ; written in FORTRAN or C. ; When the high-level routine is finished, ACLOCK ; restores the coprocessor state, the old data and ; stack segements, and performs an interrupt return. ; Note that the high-level routine must issue an ; end-of-interrupt command, or else invoke the BIOS ; interrupt routine. aclock proc near ; Phar Lap is supposed to call the interrupt service ; routine with the interrupt flag disabled. ; DON'T re-enable interrupts, because the new stack, ; which is really static storage, will be overwritten ; if the clock interrupt is re-entered. What you ; should do instead is to set a semaphore and check ; for re-entrance before switching to the new stack, ; and return immediately if the clock interrupt is ; being re-entered. THEN it would be OK to re-enable ; interrupts and switch to the new stack. ; sti ;re-enable interrupts pushad ;save general registers push ds ;save segment registers push es ; " push fs ; " push gs ; " mov ax, 0014h ;protected mode data seg mov ds, ax ;set ds segment reg mov es, ax ;set es segment reg mov dx, ss ;get old stack segment mov ecx, esp ;get old stack pointer mov ss, ax ;set new stack segment lea esp, clktop ;set new stack pointer push edx ;save old stack segment push ecx ;save old stack pointer fsave ndpsav ;save coprocessor state call _clock2_ ;call the interrupt service routine frstor ndpsav ;restore coprocessor state pop ecx ;get old stack pointer pop edx ;get old stack segment mov esp, ecx ;restore old stack pointer mov ss, dx ;restore old stack segment pop gs ;restore segment registers pop fs ; " pop es ; " pop ds ; " popad ;restore general registers iretd ;return from interrupt align 4 aclock endp ; CLOCK0 restores the real-time clock interrupt vector ; to the original BIOS routine. _clock0_ proc near push ebx ;save register mov cl, 08h ;DOS interrupt number mov ebx, [esp]+8 ;address of real mode vector mov ebx, [ebx] ;load real mode vector mov ax, 2505h ;Phar Lap function call int 21h ;system call pop ebx ;restore register ret ;return _clock0_ endp align 4 ; INT162 calls the BIOS clock-service routine. Note ; that the interrupt flag should still be disabled. ; I think the IRET instruction in the BIOS routine ; restores the interrupt flag to the state on entry, ; so interrupts should STILL be disabled. _int162_ proc near int 0A2h ;perform interrupt ret ;return _int162_ endp align 4 codeseg ends end