;//--------------------------------------------------------------- ;// myos.s (A mini-solution for CS630 Project 3) ;// ;// See project description for details on disk-image setup. ;// ;// assemble with: $ as86 myos.s -b myos.b ;// install using: $ dd if=myos.b of=/dev/fd0 seek=1 ;// ;// NOTE: This code begins executing with CS:IP = 1000:0002. ;// ;// programmer: ALLAN CRUSE ;// date begun: 27 MAY 2004 ;// completion: 28 MAY 2004 ;//--------------------------------------------------------------- .SECT .TEXT ;----------------------------------------------------------------- .WORD 0xABCD ; programming signature ;----------------------------------------------------------------- main: mov ax, cs ; address this segment mov ds, ax ; with DS register pop dword return_address ; store return-address mov ss, ax ; adjust SS register lea esp, tos0 ; and set new stacktop call load_elf_executables call initialize_os_tables call program_PIC_maskbits call enter_protected_mode call setup_the_pagetables call setup_the_taskstates call execute_program_demo call leave_protected_mode call restore_PIC_maskbits push dword return_address ; recover our exit-address retf ; exit to program launcher ;----------------------------------------------------------------- return_address: .LONG 0 ; to store exit-address ;----------------------------------------------------------------- ; EQUATES realCS EQU 0x1000 ; segment-address of code limGDT EQU 0x0067 ; allocate 13 descriptors sel_es EQU 0x0008 ; vram-segment selector sel_cs EQU 0x0010 ; code-segment selector sel_ss EQU 0x0018 ; data-segment selector sel_fs EQU 0x0020 ; flat-segment selector sel_SS EQU 0x0028 ; data-segment selector sel_CS EQU 0x0030 ; code-segment selector userDS EQU 0x003B ; data-segment selector userCS EQU 0x0043 ; code-segment selector sel_t0 EQU 0x0048 ; task-segment selector sel_t1 EQU 0x0050 ; task-segment selector sel_t2 EQU 0x0058 ; task-segment selector sel_bs EQU 0x0060 ; task-segment selector ;----------------------------------------------------------------- ;----------------------------------------------------------------- .ALIGN 8 theGDT: .WORD 0x0000, 0x0000, 0x0000, 0x0000 ; null descriptor .WORD 0x7FFF, 0x8000, 0x920B, 0x0000 ; vram descriptor .WORD 0xFFFF, 0x0000, 0x9A01, 0x0000 ; code descriptor .WORD 0xFFFF, 0x0000, 0x9201, 0x0000 ; data descriptor .WORD 0xFFFF, 0x0000, 0x9200, 0x008F ; flat descriptor .WORD 0xFFFF, 0x0000, 0x9201, 0x0040 ; data descriptor .WORD 0xFFFF, 0x0000, 0x9A01, 0x0040 ; code descriptor .WORD 0xFFFF, 0x0000, 0xF200, 0x00CF ; data descriptor .WORD 0xFFFF, 0x0000, 0xFA00, 0x00CF ; code descriptor .WORD 0x0067, myTSS0, 0x8901, 0x0000 ; TSS0 descriptor .WORD 0x0067, myTSS1, 0x8901, 0x0000 ; TSS1 descriptor .WORD 0x0067, myTSS2, 0x8901, 0x0000 ; TSS2 descriptor .WORD 0x0100, 0x0400, 0x9200, 0x0000 ; bios descriptor ;----------------------------------------------------------------- theIDT: .SPACE 2048 ; enough for 256 gate-descriptors ;----------------------------------------------------------------- myTSS0: .SPACE 0x68 ; storage for Task-State myTSS1: .SPACE 0x68 ; storage for Task-State myTSS2: .SPACE 0x68 ; storage for Task-State ;----------------------------------------------------------------- load_elf_executables: ; load ELF image for task #1 at 2000:0000 mov ax, #0x2000 ; address transfer area mov es, ax ; using ES register xor bx, bx ; point ES:BX to origin mov cx, #0x0001 ; cyln=0, recd=1 mov dx, #0x0100 ; head=1, drive=/fd0 call get_executable_image ; load ELF image for task #2 at 3000:0000 mov ax, #0x3000 ; address transfer area mov es, ax ; using ES register xor bx, bx ; point ES:BX to origin mov cx, #0x0101 ; cyln=1, recd=1 mov dx, #0x0000 ; head=0, drive=/fd0 call get_executable_image ret ;----------------------------------------------------------------- get_executable_image: mov bp, #5 ; max number of tries nxrd: mov ax, #0x0212 ; read 18 sectors int 0x13 ; request BIOS service jnc rdok ; success? exit early xor ah, ah ; reset_controller int 0x13 ; request BIOS service dec bp ; decrement counter jnz nxrd ; nonzero? try again failed: jmp failed ; TODO: show message here rdok: ret ;----------------------------------------------------------------- ;----------------------------------------------------------------- initialize_os_tables: ; initialize IDT descriptor for gate 0x80 mov edi, #0x80 ; ID-number for the gate lea di, theIDT[edi*8] ; gate's offset-address mov 0[di], #isrSVC ; entry-point's loword mov 2[di], #sel_CS ; code-segment selector mov 4[di], #0xEF00 ; 386 trap-gate mov 6[di], #0x0000 ; entry-point's hiword ; initialize IDT descriptor for gate 0x0D mov edi, #0x0D ; ID-number for the gate lea di, theIDT[edi*8] ; gate's offset-address mov 0[di], #isrGPF ; entry-point's loword mov 2[di], #sel_CS ; code-segment selector mov 4[di], #0x8E00 ; 386 interrupt-gate mov 6[di], #0x0000 ; entry-point's hiword ; initialize IDT descriptor for gate 0x08 mov edi, #0x08 ; ID-number for the gate lea di, theIDT[edi*8] ; gate's offset-address mov 0[di], #isrPIT ; entry-point's loword mov 2[di], #sel_CS ; code-segment selector mov 4[di], #0x8E00 ; 386 interrupt-gate mov 6[di], #0x0000 ; entry-point's hiword ; initialize IDT descriptor for gate 0x09 mov edi, #0x09 ; ID-number for the gate lea di, theIDT[edi*8] ; gate's offset-address mov 0[di], #isrKBD ; entry-point's loword mov 2[di], #sel_CS ; code-segment selector mov 4[di], #0x8E00 ; 386 interrupt-gate mov 6[di], #0x0000 ; entry-point's hiword ret ; back to main routine ;----------------------------------------------------------------- mask1: .BYTE 0xFC ; store mask for 8259A-1 mask2: .BYTE 0xFF ; store mask for 8259A-2 ;----------------------------------------------------------------- program_PIC_maskbits: restore_PIC_maskbits: in al, #0xA1 ; read slave PIC's mask xchg al, mask2 ; swap with stored value out #0xA1, al ; write slave PIC's mask in al, #0x21 ; read master PIC's mask xchg al, mask1 ; swap with stored value out #0x21, al ; write master PIC's mask ret ;----------------------------------------------------------------- ASCII_LINE_FEED EQU 0x0A ; control-code for '\n' ASCII_CARR_RETN EQU 0x0D ; control-code for '\r' ;----------------------------------------------------------------- ;----------------------------------------------------------------- enter_protected_mode: cli ; no device interrupts mov eax, cr0 ; get machine status bts eax, #0 ; set PE-bit to 1 mov cr0, eax ; enable protection push #0x0001 ; push base-address hiword push #theGDT ; push base-address loword push #limGDT ; push GDT's segment-limit lgdt [esp] ; load GDTR register-image add sp, #6 ; discard three stackwords push #0x0001 ; push base-address hiword push #theIDT ; push base-address loword push #0x07FF ; push IDT's segment-limit lidt [esp] ; load IDTR register-image add sp, #6 ; discard three stackwords jmpf #pm, #sel_cs ; reload register CS pm: mov ax, #sel_ss mov ss, ax ; reload register SS mov ds, ax ; reload register DS xor ax, ax ; use "null" selector mov es, ax ; to purge invalid ES mov fs, ax ; to purge invalid FS mov gs, ax ; to purge invalid GS ret ; back to main routine ;----------------------------------------------------------------- leave_protected_mode: mov ax, ss ; address 64KB r/w segment mov ds, ax ; using DS register mov es, ax ; and ES register mov eax, cr0 ; get machine status btr eax, #0 ; reset PE-bit to 0 btr eax, #31 ; reset PG-bit to 0 mov cr0, eax ; disable protection push #0x0000 ; push base-address hiword push #0x0000 ; push base-address loword push #0x03FF ; push IDT's segment-limit lidt [esp] ; load IDTR register-image add sp, #6 ; discard three stackwords jmpf #rm, #realCS ; reload register CS rm: mov ax, cs mov ss, ax ; reload register SS mov ds, ax ; reload register DS sti ; interrupts allowed ret ; back to main routine ;----------------------------------------------------------------- ;----------------------------------------------------------------- pgdir0: .LONG 0x0001A000 ; task #0 pgdir address pgdir1: .LONG 0x0001B000 ; task #1 pgdir address pgdir2: .LONG 0x0001C000 ; task #2 pgdir address pgtbl0: .LONG 0x0001D000 ; task #0 pgtbl address pgtbl1: .LONG 0x0001E000 ; task #1 pgtbl address pgtbl2: .LONG 0x0001F000 ; task #2 pgtbl address ;----------------------------------------------------------------- setup_the_taskstates: lea di, myTSS0 ; address TSS for task0 mov eax, [pgdir0] ; setup the address of mov dword 0x1C[di], eax ; task0 page-directory mov dword 0x60[di], #0 ; setup image for LDTR mov dword 0x64[di], #0 ; clear trap and iomap lea di, myTSS1 ; address TSS for task1 mov eax, [pgdir1] ; setup the address of mov dword 0x1C[di], eax ; task1 page-directory mov dword 0x04[di], #0x9000 ; for ESP0 mov dword 0x08[di], #sel_SS ; for SS0 mov dword 0x20[di], #0x08048074 ; for EIP mov dword 0x24[di], #0x00000200 ; for EFLAGS mov dword 0x38[di], #0x08048000 ; for ESP mov dword 0x48[di], #userDS ; for ES mov dword 0x4C[di], #userCS ; for CS mov dword 0x50[di], #userDS ; for SS mov dword 0x54[di], #userDS ; for DS mov dword 0x58[di], #0 ; for FS mov dword 0x5C[di], #0 ; for GS mov dword 0x60[di], #0 ; setup image for LDTR mov dword 0x64[di], #0 ; clear and iomap lea di, myTSS2 ; address TSS for task2 mov eax, [pgdir2] ; setup the address of mov dword 0x1C[di], eax ; task2 page-directory mov dword 0x04[di], #0xA000 ; for ESP0 mov dword 0x08[di], #sel_SS ; for SS0 mov dword 0x20[di], #0x08048074 ; for EIP mov dword 0x24[di], #0x00000200 ; for EFLAGS mov dword 0x38[di], #0x08048000 ; for ESP mov dword 0x48[di], #userDS ; for ES mov dword 0x4C[di], #userCS ; for CS mov dword 0x50[di], #userDS ; for SS mov dword 0x54[di], #userDS ; for DS mov dword 0x58[di], #0 ; for FS mov dword 0x5C[di], #0 ; for GS mov dword 0x60[di], #0 ; setup image for LDTR mov dword 0x64[di], #0 ; clear trap and iomap ret ;----------------------------------------------------------------- MACRO stos32 ; convenient abbreviation .byte 0x67, 0x66, 0xAB ; stosw -- with overrides MEND ; for use in 'USE16' code ;----------------------------------------------------------------- ;----------------------------------------------------------------- setup_the_pagetables: push es mov ax, #sel_fs ; address flat segment mov es, ax ; with ES register ; first we zero the sequence of six paging frames mov edi, [pgdir0] ; point to page-array xor eax, eax ; fill-value is zero cld ; forward processing mov ecx, #1024 ; entries-per-table imul ecx, #6 ; number of frames rep stos32 ; fill tables w/zeros ; setup identity-mapping of lowest megabyte in pgtbl0 mov edi, [pgtbl0] ; point to page-table 0 mov eax, #7 ; setup the permissions mov ecx, #256 ; entries-per-megabyte .P0: stos32 ; store page-table entry add eax, #0x1000 ; next page-frame address loop .P0 ; again for other entries ; all three tasks will "map" our kernel (including vram) mov eax, [pgtbl0] ; address of page-table 0 or eax, #7 ; setup the permissions mov edi, [pgdir0] ; point to directory 0 stos32 ; store its initial entry mov edi, [pgdir1] ; point to directory 1 stos32 ; store its initial entry mov edi, [pgdir2] ; point to directory 2 stos32 ; store its initial entry ; task #1 also maps frames at 0x08048000 and 0x08049000 mov edi, [pgtbl1] ; address of page-table mov ebx, #0x48 ; index into page-table lea edi, [edi+ebx*4] ; address for the entry mov eax, #0x00020000 ; location of elf-image or eax, #0x00000007 ; setup the permissions stos32 ; store entry of 'text' stos32 ; store entry of 'data' ; task #1 maps frame at 0x08047000 for its user-stack sub edi, #12 ; back up to stack page mov eax, #0x00028000 ; address for the stack or eax, #0x00000007 ; setup the permissions stos32 ; store entry for stack ; now put entry for this page-table into page-directory mov edi, [pgdir1] ; page-directory address mov ebx, #0x20 ; page-table entry index lea edi, [edi+ebx*4] ; address for this entry mov eax, [pgtbl1] ; page-table's address or eax, #0x00000007 ; setup its permissions stos32 ; write directory-entry ; task #2 also maps frames at 0x08048000 and 0x08049000 mov edi, [pgtbl2] ; address of page-table mov ebx, #0x48 ; index into page-table lea edi, [edi+ebx*4] ; address for the entry mov eax, #0x00030000 ; location of elf-image or eax, #0x00000007 ; setup the permissions stos32 ; store entry of 'text' stos32 ; store entry of 'data' ; task #1 maps frame at 0x08047000 for its user-stack sub edi, #12 ; back up to stack page mov eax, #0x00038000 ; address for the stack or eax, #0x00000007 ; setup the permissions stos32 ; store entry for stack ; now put entry for this page-table into page-directory mov edi, [pgdir2] ; page-directory address mov ebx, #0x20 ; page-table entry index lea edi, [edi+ebx*4] ; address for this entry mov eax, [pgtbl2] ; page-table's address or eax, #0x00000007 ; setup its permissions stos32 ; write directory-entry pop es ret ;----------------------------------------------------------------- tossave: .WORD 0, 0, 0 ; stores 48-bit pointer ;----------------------------------------------------------------- execute_program_demo: ; save our 16-bit stack's address (for return to 'main') mov tossave+0, esp ; preserve 32-bit offset mov tossave+4, ss ; plus 16-bit selector ; setup control registers CR3 and CR0 to enable paging mov edx, [pgdir0] ; prepare register CR3 mov cr3, edx ; for paging support mov eax, cr0 ; get machine status bts eax, #31 ; turn on the PG-bit mov cr0, eax ; to enable paging jmp pg ; flush prefetch queue pg: ; initialize register TR to prepare for task-switching mov ax, #sel_t0 ; address task segment ltr ax ; with TR register ; execute direct far-jump (for transfer to task #1) jmpf #0, #sel_t1 ; begin task-switching ;----------------------------------------------------------------- finish_up_main_thread: CSEG ; address this segment lss esp, tossave ; to reload SS and ESP ret ; back to main routine ;----------------------------------------------------------------- ;----------------------------------------------------------------- USE32 ; assemble instructions for a 32-bit code-segment ;----------------------------------------------------------------- ;----------------------------------------------------------------- place: .LONG 3800 ; screen-address for dump names: .ASCII " ES DS" ; list of register-labels .ASCII " EDI ESI EBP ESP EBX EDX ECX EAX" .ASCII " err EIP CS EFL" nitem: .LONG (* - names)/4 ; number of items to dump color: .BYTE 0x70 ; color-attribute in dump buffer: .ASCII "nnnn=xxxxxxxx " ; buffer for display-item buflen: .LONG * - buffer ; length of output-buffer ;----------------------------------------------------------------- isrGPF: ; fault-handler for General Protection Exceptions pushad ; save registers on stack mov ebp, esp ; setup pointer for stack push dword #0 ; make space on stack mov [esp], ds ; for saving DS value push dword #0 ; make space on stack mov [esp], es ; for saving ES value mov ax, #sel_ss ; address program data mov ds, ax ; with DS register mov ax, #sel_es ; address video memory mov es, ax ; with ES register ; loop to display the items on the kernel stack xor ebx, ebx ; initial item-number nxitm: ; setup next item-label in buffer mov eax, names[ebx*4] ; fetch item's label mov [buffer], eax ; store item's label ; setup next item-value in buffer lea edi, [buffer+5] ; setup field pointer mov eax, [ebp + ebx*4 - 8] ; fetch item's value call eax2hex ; convert value to hex ; transfer buffer-contents to the screen mov edi, [place] ; point ES:EDI to screen imul eax, ebx, #160 ; compute width of rows sub edi, eax ; and adjust pointer lea esi, [buffer] ; point DS:ESI to string cld ; do forward processing mov ah, [color] ; setup attribute byte mov ecx, [buflen] ; setup string's length nxchr: lodsb ; fetch next character stosw ; store char and color loop nxchr ; again if other chars inc ebx ; increment item-number cmp ebx, [nitem] ; final item displayed? jb nxitm ; no, show another item ; make an early exit (i.e., back to 'main' procedure) jmpf #finish_up_main_thread, #sel_cs ; to 16-bit code ;----------------------------------------------------------------- ;----------------------------------------------------------------- eax2hex: ; converts EAX to hexadecimal digit-string at ES:EDI pushad mov edx, eax ; transfer datum to EDX mov ecx, #8 ; setup count of nybbles nxnyb: rol edx, #4 ; next nybble into DL mov al, dl ; copy nybble into AL and al, #0x0F ; isolate nybble's bits cmp al, #10 ; -- Lopez algorithm -- sbb al, #0x69 ; -- converts binary -- das ; -- to hex numeral -- mov [edi], al ; store numeral in buffer inc edi ; advance buffer pointer loop nxnyb ; process other nybbles popad ret ;----------------------------------------------------------------- sys_call_table: ; the jump-table for our system-call dispatcher .LONG do_nothing ; for system-call 0 .LONG do_nothing ; for system-call 1 .LONG do_nothing ; for system-call 2 .LONG do_nothing ; for system-call 3 .LONG do_write ; for system-call 4 NR_SYSTEM_CALLS EQU (* - sys_call_table)/4 ; number of entries ;----------------------------------------------------------------- isrSVC: ; entry-point for the Supervisor-Call trap-handler cmp eax, #NR_SYSTEM_CALLS ; is ID-number valid? jb idok ; yes, keep ID-number xor eax, eax ; else wipe ID-number idok: CSEG ; address this segment jmp dword sys_call_table[eax*4] ; for SVC routine ;----------------------------------------------------------------- do_nothing: ; this routine is for any unimplemented system-calls mov eax, #-1 ; setup error-code in EAX iretd ; resume the calling task ;----------------------------------------------------------------- get_cursor_location: ; expects EBX = display page-number push ax push ds mov ax, #sel_bs ; address ROM-BIOS data mov ds, ax ; using DS register mov dx, 0x50[ebx*2] ; get page's cursor-locn pop ds pop ax ret ;----------------------------------------------------------------- put_cursor_location: ; expects EBX = display page-number push ax push ds mov ax, #sel_bs ; address ROM-BIOS data mov ds, ax ; using DS register mov 0x50[ebx*2], dx ; set page's cursor-locn pop ds pop ax ret ;----------------------------------------------------------------- ;----------------------------------------------------------------- do_write: ; ; This is our implementation for the 'write' system-call. ; ; EXPECTS: ebx = device ID-number ; ecx = offset of message ; edx = length of message ; RETURNS: eax = number of bytes written, or -1 ; push ebp ; preserve frame-pointer mov ebp, esp ; address our own frame pushad ; preserve cpu registers push ds push es ; check the validity of the device-ID cmp ebx, #1 ; is STDOUT device-ID? je devok ; yes, we can continue mov dword [ebp-4], #-1 ; else setup -1 in EAX jmp wrxx ; and skip other steps devok: mov ax, #sel_es ; address video memory mov es, ax ; with ES register ; compute display page-number (based on task-selector) str bx ; get task-selector sub bx, #sel_t0 ; minus base-offset shr bx, #3 ; setup page-number movzx ebx, bx ; extended to dword ; fetch and process each ASCII code in the user-buffer mov esi, ecx ; point DS:ESI to message mov ecx, edx ; setup length in ECX cld ; do forward processing .W0: lodsb ; fetch next ASCII-code call write_ascii_tty ; write that character loop .W0 ; again for other chars ; return-value in EAX is number of characters written mov eax, [ebp-12] ; use character-count mov [ebp-4], eax ; as the return-value ; move cursor to screen-location following the message call sync_crt_cursor ; set hardware cursor wrxx: pop es ; restore saved registers pop ds popad mov esp, ebp ; reset the stack-address pop ebp ; restore frame-pointer iretd ; resume the calling task ;----------------------------------------------------------------- ;----------------------------------------------------------------- write_ascii_tty: ; EXPECTS: AL = ascii-code, EBX=page-number call get_cursor_location ; (row,col) = (DH,DL) ; certain ASCII-codes receive special handling cmp al, #ASCII_CARR_RETN ; carriage-return? je do_cr cmp al, #ASCII_LINE_FEED ; line-feed? je do_lf ; otherwise, write character and attribute to screen call compute_vram_offset ; get cursor-position mov ah, #0x07 ; normal attribute stosw ; store char w/color ; and then adjust the cursor-coordinates in DH,DL inc dl ; increment column-number cmp dl, #80 ; beyond end-of-line? jb ttyxx ; no, keep position as is jmp do_lf ; else do newline (CR/LF) do_cr: xor dl, dl ; set column-number to 0 jmp ttyxx do_lf: inc dh ; increment the row-number xor dl, dl ; and reset column-number cmp dh, #12 ; beyond end-of-halfpage? jb ttyxx ; no, keep position as is dec dh ; else decrement row-number call scroll_vpage_up ; and scroll screen-image jmp ttyxx ttyxx: call put_cursor_location ; (row,col) = (DH,DL) ret ;----------------------------------------------------------------- compute_vram_offset: push eax mov edi, ebx ; display page-number dec edi ; minus one imul edi, #2080 ; times 13*160 movzx eax, dh ; current row-number imul eax, #160 ; times row-width add edi, eax ; added to page-base movzx eax, dl ; current column-number imul eax, #2 ; times cell-width add edi, eax ; added to row-location pop eax ret ;----------------------------------------------------------------- ;----------------------------------------------------------------- scroll_vpage_up: ; EXPECTS: EBX = display page-number for task pushad push ds push es mov ax, #sel_es ; address video memory mov es, ax ; with DS register mov ds, ax ; alse ES register cld ; forward processing xor dx, dx ; (row,col) for 'home' call compute_vram_offset ; address on half-page lea esi, [edi+160] ; address of next line mov ecx, #960 ; # cells on 12 lines rep movsw ; copy 12-lines upward mov ax, #0x0720 ; setup the fill-value mov ecx, #80 ; # cells on one line rep stosw ; fill bottom 80-cells pop es pop ds popad ret ;----------------------------------------------------------------- sync_crt_cursor: ; EXPECTS: EBX=page-number, (DH,DL)=(row,col) pusha push ds mov ax, #sel_bs ; address ROM-BIOS data mov ds, ax ; using DS register mov dx, 0x50[ebx*2] ; get cursor coordinates mov ax, #80 ; number of columns mul dh ; times row-number add al, dl ; plus column-number adc ah, #0 ; as word-value mov cx, bx ; page-number dec cx ; less one imul cx, #1040 ; times 13*80 add cx, ax ; cursor's offset mov dx, #0x3D4 ; CRT port-address mov al, #0x0E ; cursor_hi index mov ah, ch ; cursor_hi value out dx, ax ; write the MSB mov al, #0x0F ; cursor_lo index mov ah, cl ; cursor_lo value out dx, ax ; write the LSB pop ds popa ret ;----------------------------------------------------------------- ;----------------------------------------------------------------- tasklst: .LONG sel_t1, sel_t2 ; array of task-selectors n_tasks: .LONG (* - tasklst)/4 ; number of array-entries taskidx: .LONG 0 ; the current array-index taskptr: .LONG 0, 0 ; storage for jump-target ;----------------------------------------------------------------- task_schedule: mov eax, [taskidx] ; get current array-index mov edx, tasklst[eax*4] ; fetch entry from array mov [taskptr+4], edx ; store entry in pointer inc eax ; increment array-index xor edx, edx ; extended to quadword div dword [n_tasks] ; divide by task-count mov [taskidx], edx ; new index is remainder str ax ; check: current task cmp ax, [taskptr+4] ; is now the target? je task_schedule ; yes, then change it! ret ;----------------------------------------------------------------- isrPIT: ; interrupt-service routine for the timer-tick interrupt pushad push ds mov ax, #sel_bs ; address ROM-BIOS data mov ds, ax ; using DS register inc dword [0x006C] ; increment tick-counter cmp dword [0x006C], #0x180000 ; past midnight? jb ttok ; no, skip rollover mov dword [0x006C], #0 ; else reset tick-counter mov byte [0x70], #1 ; and set rollover flag ttok: dec byte [0x0040] ; decrement diskette timeout jnz fdok ; nonzero? leave motors on and byte [0x003F], #0xF0 ; clear motors-on bits mov dx, #0x3F2 ; FDC digital output mov al, #0xC0 ; motors-off command out dx, al ; turn drive motors off fdok: mov al, #0x20 ; EOI-command out #0x20, al ; send to Master PIC mov ax, #sel_ss ; address program data mov ds, ax ; with DS register cmp byte [kbflag], #3 ; Control-C? jne continue ; no, keep running jmpf #0, #sel_t0 ; exit to main task continue: call task_schedule ; point to next task jmpf dword [taskptr] ; do 'task_dispatch' pop ds popad iretd ;----------------------------------------------------------------- ;----------------------------------------------------------------- kbflag: .LONG 0 ; status of control-key ;----------------------------------------------------------------- isrKBD: ; interrupt-service routine for the keyboard interrupts pushad push ds mov ax, #sel_ss ; address this segment mov ds, ax ; with DS register in al, #0x64 ; get conroller status shl ax, #8 ; shift to register AH test ah, #0x1 ; new datum available? jz ignore ; no, then disregard ; see if the key was one that we care about in al, #0x60 ; else get new scancode cmp al, #0x1D ; control-key pressed? je do_mkc cmp al, #0x9D ; control-key released? je do_bkc cmp al, #0x2E ; C-key pressed? je do_mkC cmp al, #0xAE ; C-key released? je do_bkC jmp ignore ; others we disregard do_mkc: bts dword [kbflag], #0 ; set bit #0 ('C' is down) jmp ignore do_bkc: btr dword [kbflag], #0 ; clear bit #0 ('C' is up) jmp ignore do_mkC: bts dword [kbflag], #1 ; set bit #1 (CTL is down) jmp ignore do_bkC: btr dword [kbflag], #1 ; clear bit #0 (CTL is up) jmp ignore ignore: mov al, #0x20 ; nonspecific EOI-command out #0x20, al ; is sent to master PIC pop ds popad iretd ;----------------------------------------------------------------- .ALIGN 16 ; alignment at paragraph .SPACE 512 ; reserved for stack use tos0: ; label fop top-of-stack ;----------------------------------------------------------------- END