title 'Software Interrupt Init & Handlers' include system.lib include sysdat.lib include flags.equ OVEC1 equ 1 * 4 ;; Equates for SID's interrupt vector. SVEC1 equ OVEC1 + 2 ;; They are used during initialization. OVEC3 equ 3 * 4 SVEC3 equ OVEC3 + 2 OVECE1 equ 0E1H * 4 SVECE1 equ OVECE1 + 2 LOW_NIBBLE EQU 0FH ;; used by outbyte dseg extrn debugflag:byte cseg public nmiint, int_init extrn sysdat:word extrn supif:near extrn dispatch:dword extrn pmsg:near ;;====== nmiint: ;;====== ;; ;; Non-maskable interrupt handler ;; ;; This handler sets a flag when an NMI is executed. ;; A process is expected to be sleeping on this flag. push ds ;; establish a data segment mov ds, sysdat mov nmi_ssreg,ss ;; establish a stack mov nmi_spreg,sp mov ss,sysdat mov sp,offset nmi_tos push ax ! push bx ;; save the environment push cx ! push dx push di ! push si push bp ! push es mov dx, nmi_flag ;; wake up the sleeping NMI mov cl, f_flagset ;; process call supif pop es ! pop bp ;; restore the environment pop si ! pop di pop dx ! pop cx pop bx ! pop ax mov ss,nmi_ssreg ;; restore the stack mov sp,nmi_spreg pop ds ;; restore the data segment jmpf cs:dispatch ;; exit through the dispatcher eject int_trap: ;;unknown interrupts go here ... ;;------- ;; ;; We will terminate the process that caused this ;; after writing a message to the process's default ;; console. If the process is in KEEP mode, we will ;; force it to terminate anyway... ;; ;; We don't need to save any registers since we are ;; not going to return to the process. mov ds,sysdat ;; print first 6 chars of PD Name mov bx,rlr ;; get the PD add bx,p_name ;; get the process name mov byte ptr 6[bx],':' ;; step on the process name mov byte ptr 7[bx],0ffh call pmsg ;; print the first 6 letters ;; calculate and print the ;; Illegal Interrupt message pop ax ;; get the addr of the int 3 sub ax,offset int_work + 1 ;; subtract from this addr ;; the base of the INT 3 table mov bx,offset int_trpcode ;; point to where the ascii will go call outbyte ;; convert the int number to ascii mov bx,offset int_trp ;; print the message call pmsg ;; terminate process mov bx,rlr ;; get the PD and p_flag[bx], not pf_keep ;; turn off the process's keep flag mov cx,f_terminate ;; set the terminate code mov dx,0ffffh ;; free its memory int 224 ;; go to the system hlt ;; this instruction should ;; never execute outbyte: ;;------- ;; ENTRY: al = binary of an unsigned byte ;; bx = where to put the ascii ;; ;; EXIT: [bx] = ascii of high nibble of byte ;; [bx+1] = ascii of low nibble of byte push ax ;; save the byte mov di, bx ;; save where to put the ascii mov bx, offset xlate_tbl mov cl, 4 shr al, cl ;; move the high nibble into place xlat xlate_tbl ;; translate the highest nibble mov [di], al ;; stash it, di -> destination inc di ;; next ascii position pop ax ;; get the byte back and al, LOW_NIBBLE ;; mask out the upper nibble xlat xlate_tbl ;; tanslate the lower nibble mov [di], al ;; di -> destination ret eject ;;======== int_init: ;;======== ;; ;; Un-initialized interrupt initialization ;; cli ;; interrupts should be off on entry,but... ;; setup an INT 3 for each possible interrupt mov cx,256 ;; # of interrupt vectors mov di,offset int_work ;; base of the INT 3 table mov al,0cch ;; opcode for INT 3 rep stosb ;; store INT 3 in interrupt table push ds ;; Setup all interrupt vectors in low xor ax,ax ;; memory to their respective INT 3 in the INT 3 table mov ds,ax ;; set DS to zero ;; save SID's interrupt vectors mov ax, word ptr .OVEC1 ;; vector 1 mov es:vec1_off, ax mov ax, word ptr.SVEC1 mov es:vec1_seg, ax mov ax, word ptr.OVEC3 ;; vector 3 mov es:vec3_off, ax mov ax, word ptr.SVEC3 mov es:vec3_seg, ax mov ax, word ptr.OVECE1 ;; vector E1 mov es:vece1_off, ax mov ax, word ptr.SVECE1 mov es:vece1_seg, ax xor di,di ;; start with vector 0 mov bx,offset int_work ;; bx -> base of interrupt 3 table mov cx,256 ;; cx = # of interrupt vectors setint: mov word ptr [di],bx ;; interrupt vector offset mov word ptr 2[di],cs ;; interrupt vector segment (INT 3 table) add di,004H ;; next vector inc bx ;; next table entry loop setint ;; initialize all the int vectors ... mov word ptr .0008h,offset nmiint mov word ptr .000ah,cs ;; initialize the NMI ;; if we're in a debugging environment put sids interrupt vectors ;; back. If we're not in an interrupt environment then make ;; the interrupt 3 vector point to the un-initialized interrupt ;; handler. test es:debugflag, 002H ;; do we want to put SID'S vector back ? jz set_int_trap ;; no ... mov ax, es:vec1_off ;; yes, do vector 1 mov word ptr .OVEC1, ax mov ax, es:vec1_seg mov word ptr .SVEC1, ax mov ax, es:vec3_off ;; vector 3 mov word ptr .OVEC3, ax mov ax, es:vec3_seg mov word ptr .SVEC3, ax mov ax, es:vece1_off ;; vector E1 mov word ptr .OVECE1, ax mov ax, es:vece1_seg mov word ptr .SVECE1, ax jmps intie set_int_trap: ;; point to our trap. mov word ptr .OVEC3, offset int_trap ;; setup INT 3's offset mov word ptr .SVEC3, cs ;; and segment intie: pop ds ;; restore the data segment ret eject dseg nmi_tos rw 80 nmi_ssreg rw 1 ;; nonmaskable interrupt stack nmi_spreg rw 1 nmi_instk rb 1 rw 48 ;; tick's interrupt stack tick_tos rw 0 tick_ssreg rw 1 tick_spreg rw 1 ;; this translate table is used by outbyte ;; to translate from binary to ascii xlate_tbl db '0123456789ABCDEF' ;; this message is printed by the uninitialized interrupt ;; routine. int_trp db ' Uninitialized interrupt, code = 0' int_trpcode db 'xxH',0dh,0ah,0ffh ;; SID's interrupt vectors are stored ;; here during initialization. vec1_off dw 0 ;; interrupt vector 1 vec1_seg dw 0 vec3_off dw 0 ;; interrupt vector 3 vec3_seg dw 0 vece1_off dw 0 ;; interrupt vector E1 vece1_seg dw 0 ;; scratch area ;; dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch ;; Int 3 table for the unintialized interrupts int_work rb 256 ;;interrupt vector routines end