Пример №3 – «Ядро крошечной операционной системы – Kernel». В этом примере «параллельно» выполняются две задачи, их выполнение можно наблюдать на экране. Так же обрабатывается прерывание от клавиатуры: скан-код нажатой клавиши выводится на экране. Ниже приведен исходный текст программы (сначала главный модуль, а за ним «включаемые» *.inc модули). kernel.asm .386P .MODEL LARGE INCLUDE MACROSES.INC SIZE_STACK EQU ; MAIN DEFINITIONS 1000H ;-----------------------------------------; ; 16-BIT REAL/PROTECTED NODE CODE SEGMENT ; ;-----------------------------------------; CODE16 SEGMENT PARA USE16 CODE16_BEGIN = $ ASSUME CS:CODE16,DS:DATA,ES:DATA START: MOV MOV MOV AX, DATA DS, AX ES, AX ; LOAD DATA SEGMENTS LEA DX, MSG_STARTUP MOV AH, 9 INT 21H ; MOV EAX, CR0 SMSW AX TEST AL, 1 JZ START_NO_PM LEA DX, MSG_VM MOV AH, 9 INT 21H JMP START_EXIT ; DOESN'T WORK UNDER WIN :( ; BUT THIS WORKS PERFECTLY :) ; IS PROTECTED MODE ACTIVE? ; NO, IT ISN'T ; YES, IT IS. EXITING... START_NO_PM: MOV EAX, 3 CALL delayRTC @ENABLE_A20 ; ENABLE A20 LINE IN AL, PORT_INT_MASK_M MOV INT_MASK_M, AL ; SAVE MASK OF HARDWARE INTS AT MASTER CNTRLR IN AL, PORT_INT_MASK_S MOV INT_MASK_S, AL ; SAVE MASK OF HARDWARE INTS AT SLAVE CNTRLR CLI ; DISABLE MASKABLE INTS @DISABLE_NMI ; DISABLE NON-MASKABLE INTS INCLUDE SETUPGDT.INC INCLUDE SETUPIDT.INC LGDT FWORD PTR GDT_GDT LIDT FWORD PTR IDTR ; FILL GDT ; FILL IDT ; LOAD GDTR ; LOAD IDTR MOV EAX, CR0 OR AL, 1 MOV CR0, EAX @JUMP MOV AX, DS_DESC MOV DS, AX MOV ES, AX MOV AX, SS_DESC MOV SS, AX XOR AX, AX MOV FS, AX MOV GS, AX LLDT AX ; SET UP PROTECTED MODE ; OVERLOAD CODE SELECTOR ; LOAD DS WITH DATA SELECTOR ; LOAD ES WITH DATA SELECTOR ; LOAD SS WITH STACK SELECTOR ; LOAD FS WITH 0 ; LOAD GS WITH 0 ; LOAD LDTR WITH 0 MOVZX ESP, SP ; EXPAND SP TO ESP PUSH CS ; PREPARE FOR RETURNING BACK PUSH OFFSET START_BACK_TO_16 ; TO 16-BIT PM CODE MOV DS:[ESP32], ESP LEA EDI, ENTER_32 MOV EAX, CS32_DESC PUSH EAX PUSH EDI ; PUSH 32-BIT CODE ADDRESS INCLUDE SETUPTSS.INC ; FILL TSSs MOV AX, TSS_MAIN_DESC LTR AX ; LOAD TR REGISTER @SET_INT_CTRLR 20H, 28H ; REINITIALISE MASTER & SLAVE INT CONTROLLERS MOV AL, 0 ; MASK = 0 OUT PORT_INT_MASK_M, AL ; UNMASK INTS OUT PORT_INT_MASK_S, AL ; UNMASK INTS @ENABLE_NMI ; ENABLE NON-MASKABLE INTS STI ; ENABLE MASKABLE INTS @RETF START_BACK_TO_16: CLI @DISABLE_NMI MOV AX, DS_DESC MOV DS, AX ; "RETURN" TO 32-BIT CODE ; DISABLE MASKABLE INTS ; DISABLE NON-MASKABLE INTS INCLUDE SET_RM1.INC ; SAFETY IS WHAT WE NEED!!! ; BACK TO REAL MODE MOV AL, INT_MASK_M OUT PORT_INT_MASK_M, AL ; RESTORE MASK OF HARDWARE INTS AT MASTER CNTRLR MOV AL, INT_MASK_S OUT PORT_INT_MASK_S, AL ; RESTORE MASK OF HARDWARE INTS AT SLAVE CNTRLR @ENABLE_NMI ; ENABLE NON-MASKABLE INTS STI ; ENABLE MASKABLE INTS @DISABLE_A20 ; DISABLE A20 LINE START_EXIT: MOV EAX, 3 CALL delayRTC MOV AX, 3 INT 10H LEA DX, MSG_CONTACT MOV AH, 9 INT 21H MOV AX, 4C00H INT 21H ; EXIT TO DOS delayRTC PROC NEAR ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Input : eax = number of seconds for delay ;; ;; Output: None, registers are preserved ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; PUSH EAX PUSH EBX PUSH ECX MOV XOR OUT JMP DRL1: IN MOV DRLL: XOR OUT JMP DRL2: IN CMP JE MOV LOOP ;; ECX, EAX AL, AL 70H, AL DRL1 AL, 71H BL, AL AL, AL 70H, AL DRL2 AL, 71H AL, BL DRLL BL, AL DRLL POP ECX POP EBX POP EAX RET delayRTC ENDP SIZE_CSEG16 = ($ - CODE16_BEGIN) CODE16 ENDS ;------------------------------------; ; 32-BIT PROTECTED MODE CODE SEGMENT ; ;------------------------------------; CODE32 SEGMENT PARA USE32 CODE32_BEGIN = $ ASSUME CS:CODE32,DS:DATA,ES:DATA ;--------------------; ; MAIN TASK (RING 0) ; ;--------------------; ENTER_32: CALL CLRSCR XOR EDI, EDI LEA CALL ADD LEA CALL ADD ESI, MSG_TASK_MAIN W_ASCIIZ EDI, 80*2 ESI, MSG_SCAN_CODE W_ASCIIZ EDI, 15*2 ENTER_32_WAIT_KEY: MOV BL, KEY_SCAN_CODE MOVZX EAX, BL CALL W_EAX ADD MOV CALL SUB EDI, (80-15)*2 EAX, ESP W_EAX EDI, (80-15)*2 ; VISUAL TEST OF ESP CMP BL, 1 ; ESC? JNE ENTER_32_WAIT_KEY ; NOT ESC ; MOV ECX, 0FFFFFFFH ; LOOP $ ; DOES A FEW SECOND DELAY ON MY P233 @RETF ; BACK TO 16-BIT CODE ;----------------------------------------------; ; MAIN ROUTINES AND HANDLERS ARE INCLUDED HERE ; ;----------------------------------------------; INCLUDE SCREENIO.INC ; SCREEN I/O ROUTINES INCLUDE EXC.INC ; EXCEPTION HANDLER INCLUDE IRET.INC ; TIMER INTERRUPT HANDLER INCLUDE TIMER.INC ; KEYBOARD INTERRUPT HANDLER INCLUDE KEYBOARD.INC ; ROUTINE FOR DISPLAYING TSS INCLUDE SHOW_TSS.INC ; SERVICE INTERRUPT INCLUDE SERVICE.INC SIZE_CSEG32 = ($ - CODE32_BEGIN) CODE32 ENDS ;-----------------------------------------; ; COMMON REAL/PROTECTED MODE DATA SEGMENT ; ;-----------------------------------------; DATA SEGMENT PARA USE16 DATA_BEGIN = $ INCLUDE GDT.INC INCLUDE IDT.INC INCLUDE TSS.INC ; GDT TABLE ; IDT TABLE ; TSS TABLES MSG_STARTUP DB "Tiny OS Kernel by Alexei A. Frounze (C) 2000",13,10,"$" MSG_CONTACT DB "Contact information:",13,10 DB "E-mail : alexfru@chat.ru",13,10 DB "Homepage: http://alexfru.chat.ru",13,10 DB "Mirror : http://members.xoom.com/alexfru",13,10,"$" MSG_VM DB "PROCESSOR IS ALREADY IN PROTECTED MODE.",13,10 DB "PROBABLY WINDOWS OR EMM386.EXE IS LOADED.",13,10 DB "LOAD PURE DOS OR WINDOWS IN COMMAND PROMPT ONLY MODE.",13,10 DB "EXITING...",13,10,"$" HEX_TAB DB "0123456789ABCDEF" EXC_ERR DB 0,0,0,0,0,0,0,0, 1,0,1,1,1,1,1,0, 0,1 MSG_EXC DB "EXCEPTION: ",0 MSG_EXC_ERR DB "ERROR CODE: ",0 MSG_CSEIP DB "CS=XXXXXXXX EIP=XXXXXXXX",0 INT_MASK_M DB INT_MASK_S DB ESP32 DD ? ? ? TIMER_CNT DW 0 KEY_SCAN_CODE DB 0 MSG_TASK_MAIN DB "MAIN TASK",0 MSG_SCAN_CODE DB "KBD SCAN CODE: ",0 MSG_TASK_0 DB "TASK #0",0 MSG_TASK_1 DB "TASK #1",0 MSG_TSS LABEL BYTE DB "CR3 = XXXXXXXX FLAGS= XXXXXXXX",0 DB "EIP = XXXXXXXX CS = XXXXXXXX",0 DB "ESP = XXXXXXXX SS = XXXXXXXX",0 DB "DS = XXXXXXXX ES = XXXXXXXX",0 DB "FS = XXXXXXXX GS = XXXXXXXX",0 DB "EAX = XXXXXXXX EBX = XXXXXXXX",0 DB "ECX = XXXXXXXX EDX = XXXXXXXX",0 DB "ESI = XXXXXXXX EDI = XXXXXXXX",0 DB "EBP = XXXXXXXX LINK = XXXXXXXX",0 DB "ESP0 = XXXXXXXX SS0 = XXXXXXXX",0 DB "ESP1 = XXXXXXXX SS1 = XXXXXXXX",0 DB "ESP2 = XXXXXXXX SS2 = XXXXXXXX",0 DB "LDTR = XXXXXXXX IO/T = XXXXXXXX",0 OFFS_TSS LABEL DWORD DD 1CH, 24H DD 20H, 4CH DD 38H, 50H DD 54H, 48H DD 58H, 5CH DD 28H, 34H DD 2CH, 30H DD 40H, 44H DD 3CH, 00H DD 04H, 08H DD 0CH, 10H DD 14H, 18H DD 60H, 64H SIZE_DSEG = DATA ENDS ($ - DATA_BEGIN) ;-----------------------------------; ; REAL/PROTECTED MODE STACK SEGMENT ; ;-----------------------------------; SSTACK SEGMENT PARA STACK DB SIZE_STACK DUP (?) SSTACK ENDS ;-----------------------------; ; 2 ADDITIONAL TASKS (RING 3) ; ;-----------------------------; INCLUDE TASKS.INC END START gdt.inc (Описание GDT) ;-----------; ; GDT Table ; ;-----------; GDT_BEGIN = $ GDT LABEL WORD GDT_0 S_DESC <0,0,0,0,0,0> ; 00 GDT_GDT S_DESC ; 08 GDT_CS16 S_DESC ; 10 GDT_DS S_DESC ; 18 GDT_SS S_DESC ; 20 GDT_BIOS S_DESC ; 28 GDT_TEXT S_DESC ; 30 GDT_GRAPH S_DESC ;38 GDT_FLAT S_DESC <0FFFFH,0,0,ACS_DATA,08FH,0> ; 4 GB SEGMENT ;)) ; 40 GDT_CS32 S_DESC ; 48 GDT_IDT S_DESC ; 50 GDT_CS_0 S_DESC ; 58 GDT_CS_1 S_DESC ; 60 GDT_SS_0 S_DESC ; 68 GDT_SS_1 S_DESC ; 70 GDT_TSS_MAIN S_DESC ; 78 GDT_TSS_0 S_DESC GDT_TSS_1 ; 88 GDT_SIZE = ; 80 S_DESC ($ - GDT_BEGIN) CS16_DESC = DS_DESC = SS_DESC = BIOS_DESC = TEXT_DESC = GRAPH_DESC = FLAT_DESC = CS32_DESC = IDT_DESC = CS_0_DESC = CS_1_DESC = SS_0_DESC = SS_1_DESC = TSS_MAIN_DESC = TSS_0_DESC = TSS_1_DESC = (GDT_CS16 - GDT_0) (GDT_DS - GDT_0) + RPL_3 (GDT_SS - GDT_0) (GDT_BIOS - GDT_0) + RPL_3 (GDT_TEXT - GDT_0) + RPL_3 (GDT_GRAPH - GDT_0) + RPL_3 (GDT_FLAT - GDT_0) (GDT_CS32 - GDT_0) (GDT_IDT - GDT_0) (GDT_CS_0 - GDT_0) + RPL_3 (GDT_CS_1 - GDT_0) + RPL_3 (GDT_SS_0 - GDT_0) + RPL_3 (GDT_SS_1 - GDT_0) + RPL_3 (GDT_TSS_MAIN - GDT_0) (GDT_TSS_0 - GDT_0) (GDT_TSS_1 - GDT_0) idt.inc (Описание IDT) ;-----------; ; IDT Table ; ;-----------; IDTR R_IDTR DUMMY_IDT DF 0 IDT LABEL WORD IDT_BEGIN = $ IRPC N, 0123456789ABCDEF IDT_0&N I_DESC <0, CS32_DESC, 0, ACS_TRAP, 0> ; 00...0F ENDM IRPC N, 0123456789ABCDEF IDT_1&N I_DESC <0, CS32_DESC, 0, ACS_TRAP, 0> ; 10...1F ENDM IDT_TIMER I_DESC <0, CS32_DESC, 0, ACS_INT, 0> ; 20 IDT_KEYBOARD I_DESC <0, CS32_DESC, 0, ACS_INT, 0> ; 21 IRPC N, 23456789ABCDEF IDT_2&N I_DESC <0, CS32_DESC, 0, ACS_INT, 0> ; 22...2F ENDM IDT_SERVICE I_DESC <0, CS32_DESC, 0, ACS_TRAP+ACS_DPL_3, 0> ; 30 SIZE_IDT = ($ - IDT_BEGIN) macroses.inc (Определение основных структур) ;--------------------------------------------------------------------; ; Macroses that define useful structures, constants and other things ; ;--------------------------------------------------------------------; ; Pushes several registers to the stack @PUSH MACRO REGLIST IRP REG, PUSH REG ENDM ENDM ; Popes several registers from the stack @POP MACRO REGLIST IRP REG, POP REG ENDM ENDM ; Sets up GDT table entry @SET_GDT_ENTRY MACRO MOV [BX][S_DESC.BASE_L], AX MOV [BX][S_DESC.BASE_M], DL MOV [BX][S_DESC.BASE_H], DH ENDM ; Segment Descriptor structure S_DESC STRUC LIMIT DW 0 BASE_L DW 0 BASE_M DB 0 ACCESS DB 0 ATTRIBS DB 0 BASE_H DB 0 S_DESC ENDS ; Interrupt Descriptor structure I_DESC STRUC OFFS_L DW 0 SEL DW 0 PARAM_CNT DB 0 ACCESS DB 0 OFFS_H DW 0 I_DESC ENDS ; IDTR register structure R_IDTR STRUC LIMIT DW 0 IDT_L DW 0 IDT_H DW 0 R_IDTR ENDS ; Task State Segment structure S_TSS STRUC LINK DW 0, 0 ; 0 ESP0 DD 0 ; 4 SS0 DW 0, 0 ; 8 ESP1 DD 0 ; 0C SS1 DW 0, 0 ; 10 ESP2 DD 0 ; 14 SS2 DW 0, 0 ; 18 R_CR3 DD 0 ; 1C R_EIP DD 0 ; 20 R_EFLAGS DD 0 ; 24 R_EAX DD 0 ; 28 R_ECX DD 0 ; 2C R_EDX DD 0 ; 30 R_EBX DD 0 ; 34 R_ESP DD 0 ; 38 R_EBP DD 0 ; 3C R_ESI DD 0 ; 40 R_EDI DD 0 ; 44 R_ES DW 0, 0 ; 48 R_CS DW 0, 0 ; 4C R_SS DW 0, 0 ; 50 R_DS DW 0, 0 ; 54 R_FS DW 0, 0 ; 58 R_GS DW 0, 0 ; 5C R_LDTR DW 0, 0 ; 60 TRACE DW 0 ; 64 IO_MAP_ADDR DW 68H ; 66 IO_MAP DB (400H SHR 3) DUP (0) ; 400H PORTS AVAILABLE S_TSS ENDS ; DIFFERENT CONSTANTS AND FLAGS FOR PM SIZE_TSS EQU 68H + (400H SHR 3) ; Access byte's flags ACS_PRESENT EQU ACS_CSEG EQU ACS_DSEG EQU ACS_EXPDOWN EQU ACS_CONFORM EQU ACS_READ EQU ACS_WRITE EQU ACS_CODE = ACS_CONFORM 10000000B 00011000B 00010000B 00000100B 00000100B 00000010B 00000010B ACS_PRESENT OR ACS_CSEG; OR ACS_DATA = ACS_PRESENT OR ACS_DSEG OR ACS_WRITE ACS_STACK = ACS_PRESENT OR ACS_DSEG OR ACS_WRITE OR ACS_EXPDOWN ACS_INT_GATE EQU 00001110B ACS_TRAP_GATE EQU 00001111B ACS_IDT EQU ACS_DATA ACS_INT EQU ACS_PRESENT OR ACS_INT_GATE ACS_TRAP EQU ACS_PRESENT OR ACS_TRAP_GATE ACS_TSS EQU ACS_PRESENT OR 00001001B ACS_DPL_0 ACS_DPL_1 ACS_DPL_2 ACS_DPL_3 RPL_0 RPL_1 RPL_2 RPL_3 EQU EQU EQU EQU EQU EQU EQU EQU 00000000B 00100000B 01000000B 01100000B 0 1 2 3 ; CONSTANTS FOR BIOS DATA AREA SEG_BIOS EQU 00040H SIZE_BIOS EQU 00300H LOW_BIOS EQU 00400H HIGH_BIOS EQU 0 ; CONSTANTS FOR TEXT VIDEO MODES SEG_TEXT EQU 0B800H SIZE_TEXT EQU 02000H ; > 80*50*2 LOW_TEXT EQU 08000H HIGH_TEXT EQU 0BH ; CONSTANTS FOR GRAPHICS VIDEO MODES SEG_GRAPH EQU 0A000H SIZE_GRAPH EQU 10000H LOW_GRAPH HIGH_GRAPH EQU EQU 0 0AH ; DIFFERENT CONSTANTS FOR PORT I/O PORT_CMOS EQU 070H PORT_6845 EQU 00063H PORT_TEXT EQU 003D4H PORT_STATUS EQU 064H SHUT_DOWN EQU 0FEH MODE_VIRTUAL EQU 00001H PORT_A20 EQU 0D1H A20_ON EQU 0DFH A20_OFF EQU 0DDH PORT_KBD_A EQU 060H PORT_KBD_B EQU 061H PORT_INT_MASK_M EQU 021H PORT_INT_MASK_S EQU 0A1H EOI EQU 020H PORT_8259M EQU 020H PORT_8259S EQU 0A0H PORT_COM_REG EQU PORT_CHANNEL2 EQU 043H 042H ; Enables A20 line @ENABLE_A20 MACRO MOV AL, PORT_A20 OUT PORT_STATUS, AL MOV AL, A20_ON OUT PORT_KBD_A, AL ENDM ; Disables A20 line @DISABLE_A20 MACRO MOV AL, PORT_A20 OUT PORT_STATUS, AL MOV OUT ENDM AL, A20_OFF PORT_KBD_A, AL ; Enables non-maskable interrupts @ENABLE_NMI MACRO MOV AL, 0DH OUT PORT_CMOS, AL JMP $+2 ENDM ; Disables non-maskable interrupts @DISABLE_NMI MACRO MOV AL, 8FH OUT PORT_CMOS, AL JMP $+2 ENDM ; This macro reprograms PIC (master and slave) to other interrupt vectors @SET_INT_CTRLR MACRO INT_MASTER, INT_SLAVE MOV AL, 11H ; START 8259 INITIALIZATION OUT PORT_8259M, AL OUT PORT_8259S, AL MOV AL, INT_MASTER ; BASE INTERRUPT VECTOR OUT PORT_8259M+1, AL MOV AL, INT_SLAVE OUT PORT_8259S+1, AL MOV AL, 1 SHL 2 ; BITMASK FOR CASCADE ON IRQ 2 OUT PORT_8259M+1, AL MOV AL, 2 ; CASCADE ON IRQ 2 OUT PORT_8259S+1, AL MOV AL, 1 ; FINISH 8259 INITIALIZATION OUT PORT_8259M+1, AL OUT PORT_8259S+1, AL MOV AL, 0FFH ; MASK ALL INTERRUPTS OUT PORT_INT_MASK_M, AL OUT ENDM PORT_INT_MASK_S, AL @JUMP MACRO ; OVERLOADS CODE SELECTOR AFTER CHANGING ITS DESCRIPTOR DB 0EAH DW $+4 DW CS16_DESC ENDM @JUMPR MACRO DB 0EAH DW $+4 DW CODE16 ENDM @RETF MACRO VICE VERSA DB 66H RETF ENDM ; OVERLOADS CODE SEGMENT ; FAR RETURN FROM 16-BIT TO 32-BIT CODE & tss.inc (Описание TSS) ;---------------------------------------; ; TSSs of main and few additional tasks ; ;---------------------------------------; TSS_MAIN S_TSS <> TSS_0 S_TSS <> TSS_1 S_TSS <> ; TASK LIST TASK_LIST DW TSS_MAIN_DESC, TSS_0_DESC, TSS_1_DESC, 0 ; THIS INDEX VARIABLE IS USED TO CHOSE THE TASK TO SWITCH TO TASK_INDEX DW 2 ; THIS 6-BYTE PM ADDRESS IS USED TO PERFORM FAR JUMP TO TSS TASK_ADDR DF 0 iret.inc (Программирование контроллера прерываний) ;-------------------------------------; ; Dummy IRets for hardware interrupts ; ;-------------------------------------; DUMMY_IRET0 PROC NEAR PUSH EAX MOV AL, EOI OUT PORT_8259M, AL POP EAX IRETD DUMMY_IRET0 ENDP DUMMY_IRET1 PROC NEAR PUSH EAX MOV AL, EOI OUT PORT_8259M, AL OUT PORT_8259S, AL POP EAX IRETD DUMMY_IRET1 ENDP keyboard.inc (Обработчик прерывания от клавиатуры) ;-------------------------------------; ; Keyboard hardware interrupt handler ; ;-------------------------------------; KEYBOARD_HANDLER PROC NEAR @PUSH MOV AX, DS_DESC MOV DS, AX IN AL, PORT_KBD_A MOV AH, AL AND AL, 07FH MOV DS:[KEY_SCAN_CODE], AL ; ; ; ; ; ; ; IN AL, PORT_KBD_B OR AL, 080H OUT PORT_KBD_B, AL IN AL, PORT_KBD_B AND AL, 07FH OUT PORT_KBD_B, AL ;¦ MOV AL, EOI OUT PORT_8259M, AL @POP IRETD KEYBOARD_HANDLER ENDP ;¦ 0 ;¦ ; ; L----¬ ; ¦ 1 ¦ ; ------ 0 timer.inc (Обработчик прерывания от таймера) ;----------------------------------; ; Timer hardware interrupt handler ; ;----------------------------------; TIMER_HANDLER PROC NEAR @PUSH PUSHAD MOV AX, DS_DESC MOV DS, AX MOV AX, BIOS_DESC MOV ES, AX INC DWORD PTR ES:[06CH] COUNTER ; UPDATE BIOS TICK MOV AX, DS:[TIMER_CNT] ; INTERNAL TICK COUNTER INC AX CMP AX, 9 ; IS TIME FOR "*" OR " "? JNE TIMER_END ; NO, IT ISN'T MOV AX, TEXT_DESC MOV ES, AX MOV AL, ES:[2*79] MOV BYTE PTR ES:[2*79], 0 CMP AL, '*' JE TIMER_FLAG MOV BYTE PTR ES:[2*79], '*' ; " " <-> "*" ; "*" <-> " " TIMER_FLAG: XOR AX, AX TIMER_END: ; UPDATE INTERNAL TICK COUNTER MOV DS:[TIMER_CNT], AX MOV AL, EOI OUT PORT_8259M, AL OF INTERRUPT ; ACKNOWLEDGE HANDLING ; LOOKING FOR THE NEXT TASK BEING CONTINUED MOVZX EAX, DS:[TASK_INDEX] ADD DS:[TASK_INDEX], 2 MOVZX EAX, DS:[TASK_LIST+EAX] OR EAX, EAX ; END OF TASK LIST? JNZ TIMER_NEXT_TASK ; NOT END, RUNNING NEXT TASK MOVZX EAX, DS:[TASK_LIST] MOV DS:[TASK_INDEX], 2 ; END, RUNNING FIRST TASK TIMER_NEXT_TASK: MOV WORD PTR DS:[TASK_ADDR+4], AX ; FAR POINTER TO TSS JMP TASK :) FWORD PTR DS:[TASK_ADDR] ; SWITCH TO ANOTHER POPAD @POP IRETD TIMER_HANDLER ENDP screenio.inc (Работа с видеокартой) ;---------------------------------; ; Subroutines for screen text I/O ; ;---------------------------------; ; FUNCTION: CLEARS THE SCREEN ; IN: NONE ; OUT: NONE, ALL REGS ARE SAVED CLRSCR PROC NEAR PUSH ES PUSHAD MOV AX, TEXT_DESC MOV ES, AX XOR EDI, EDI MOV ECX, 80*25 MOV AX, 700H;1B00H REP STOSW POPAD POP ES RET CLRSCR ENDP ; FUNCTION: PRINTS THE EAX VALUE TO THE SCREEN ; IN: EAX = 32-BIT VALUE, EDI = SCREEN OFFSET ; OUT: NONE, ALL REGS ARE SAVED W_EAX PROC NEAR @PUSH PUSHAD MOV DX, DS_DESC MOV DS, DX MOV DX, TEXT_DESC MOV ES, DX MOV ECX, 8 LEA ESI, HEX_TAB W_EAX_1: ROL EAX, 4 MOVZX EBX, AL AND BL, 0FH MOV BL, DS:[ESI+EBX] MOV ES:[EDI], BL ADD EDI, 2 LOOP W_EAX_1 POPAD @POP RET W_EAX ENDP ; FUNCTION: PRINTS ASCIIZ STRING TO THE SCREEN ; IN: DS:ESI -> STRING, EDI = SCREEN OFFSET ; OUT: NONE, ALL REGS ARE SAVED W_ASCIIZ PROC NEAR PUSH ES PUSHAD MOV AX, TEXT_DESC MOV ES, AX W_ASCIIZ_1: LODSB OR AL, AL JZ W_ASCIIZ_2 STOSB INC EDI JMP W_ASCIIZ_1 W_ASCIIZ_2: POPAD POP ES RET W_ASCIIZ ENDP service.inc (Формирование обработчика прерывания) ;----------------------------------; ; SERVICE SOFTWARE INTERRUPT (30H) ; ;----------------------------------; SERVICE_INTERRUPT PROC NEAR PUSHAD AND EBX, 0FF00H ; BH = FUNCTION CODE SHR EBX, 8 CMP EBX, 3 JNC SERV_INT_END ; ONLY 3 FUNCTIONS AVAILABLE SHL EBX, 2 ; ADDRESS OFFSET TABLE CALL DWORD PTR CS:[FUNC_TAB+EBX] SERV_INT_END: POPAD IRETD F_00 LABEL NEAR JMP CLRSCR F_01 LABEL NEAR JMP W_ASCIIZ F_02 LABEL NEAR JMP W_EAX ; CLEAR SCREEN ; OUT ASCIIZ STRING ; OUT 32-BIT EAX AS HEX FUNC_TAB LABEL DWORD DD F_00, F_01, F_02 SERVICE_INTERRUPT ENDP set_rm1.inc (Возврат в RealMode – способ 1) ;--------------------------------------------------------------------------; ; Sets Real Mode using CR0, overloading segs and reprogramming PIC ; ; Ver 1: Unfortunately, works quite buggy. I don't know why. :(( ; ; Ver 2: It seems to be everything is OK after changing order of the ; ; @SET_INT_CTRLR 08H, 70H and ; ; LIDT FWORD PTR IDTR ; ; instructions ; ; Ver 3: unchanged vesrsion 2, but it doesn't work again when the task ; ; switching is enabled ; ; Ver 4: added a "CLTS" instructio. Every DPMI-based program, that I tried ; ; to run immediately after quitting from this program, just hanged ; ; with nonzero "task switched" flag. The solution is inside this ; ; simple instruction. Viola! it works! ; ;--------------------------------------------------------------------------; CLTS ; THE SOLUTION!!! ;-) @SET_INT_CTRLR 08H, 70H SLAVE INT CONTROLLERS ; REINITIALISE MASTER & MOV GDT_CS16.LIMIT, 0FFFFH 64KB LIMIT MOV GDT_DS.LIMIT, 0FFFFH LIMIT MOV GDT_SS.LIMIT, 0FFFFH 64KB LIMIT ; LGDT FWORD PTR GDT_GDT @JUMP MOV AX, DS_DESC MOV DS, AX ; CODE SEGMENT HAS ; DATA SEGMENT HAS 64KB ; STACK SEGMENT HAS ; LOAD GDTR ; OVERLOAD CODE SELECTOR ; OVERLOAD DATA SELECTOR MOV MOV MOV MOV MOV ES, AX FS, AX GS, AX AX, SS_DESC SS, AX MOV AND MOV EAX, CR0 AL, 0FEH CR0, EAX @JUMPR MOV AX, SSTACK MOV SS, AX MOV AX, DATA MOV DS, AX MOV ES, AX XOR AX, AX MOV FS, AX MOV GS, AX ; OVERLOAD DATA SELECTOR ; OVERLOAD DATA SELECTOR ; OVERLOAD DATA SELECTOR ; OVERLOAD STACK SELECTOR ; BACK TO THE REAL MODE ; RESTORE RM CODE SEGMENT ; RESTORE RM STACK SEGMENT ; RESTORE RM DATA SEGMENT MOV IDTR.LIMIT, 3FFH TABLE SIZE MOV DWORD PTR IDTR+2, 0 TABLE ADDRESS LIDT FWORD PTR IDTR TABLE ; REAL MODE INTERRUPT ; REAL MODE INTERRUPT ; LOAD REAL MODE INT set_rm2.inc (Возврат в RealMode – способ 2) ;--------------------------------; ; Sets Real Mode using CPU reset ; ; Works perfectly. :)) ; ;--------------------------------; MOV MOV MOV ESP32, ESP AX, BIOS_DESC ES, AX MOV WORD PTR ES:[067H], OFFSET SHUTDOWN_RET MOV WORD PTR ES:[069H], CODE16 MOV AL, 5 OUT PORT_CMOS+1, AL ; MOV AL, SHUT_DOWN ; OUT PORT_STATUS, AL ;START_RESET: ; HLT ; JMP START_RESET LIDT [DUMMY_IDT] INT 0 SHUTDOWN_RET LABEL FAR MOV AX, DATA MOV DS, AX MOV ES, AX MOV AX, SSTACK MOV SS, AX MOV ESP, ESP32 XOR AX, AX MOV FS, AX MOV GS, AX setupgdt.inc (Инициализация GDT) ;-----------; ; Fills GDT ; ;-----------; MOV AX, DATA MOV DL, AH XOR DH, DH SHL AX, 4 SHR DX, 4 MOV SI, AX MOV DI, DX ; GDT GOES HERE LEA BX, GDT_GDT MOV AX, SI MOV DX, DI ADD AX, OFFSET GDT ADC DX, 0 @SET_GDT_ENTRY ; 16-BIT REAL/PROTECTED MODE MAIN TASK CODE GOES HERE LEA BX, GDT_CS16 MOV AX, CS XOR DH, DH MOV DL, AH SHL AX, 4 SHR DX, 4 @SET_GDT_ENTRY ; COMMON DATA SEGMENT GOES HERE LEA BX, GDT_DS MOV AX, SI MOV DX, DI @SET_GDT_ENTRY ; STACK FOR 16/32 REAL/PROTECTED MODE MAIN TASK GOES HERE LEA BX, GDT_SS MOV AX, SS XOR DH, DH MOV DL, AH SHL AX, 4 SHR DX, 4 @SET_GDT_ENTRY ; 32-BIT PROTECTED MODE MAIN TASK CODE GOES HERE LEA BX, GDT_CS32 MOV AX, CODE32 XOR DH, DH MOV DL, AH SHL AX, 4 SHR DX, 4 @SET_GDT_ENTRY OR [BX][S_DESC.ATTRIBS], 40H ; 32-BIT STUFF ; IDT GOES HERE LEA BX, GDT_IDT MOV AX, SI MOV DX, DI ADD AX, OFFSET IDT ADC DX, 0 @SET_GDT_ENTRY MOV IDTR.IDT_L, AX MOV IDTR.IDT_H, DX ; TASKS' CODES GO HERE LEA BX, GDT_CS_0 MOV AX, CODE_0 XOR DH, DH MOV DL, AH SHL AX, 4 SHR DX, 4 @SET_GDT_ENTRY OR [BX][S_DESC.ATTRIBS], 40H LEA BX, GDT_CS_1 MOV AX, CODE_1 XOR DH, DH MOV DL, AH ; 32-BIT STUFF SHL AX, 4 SHR DX, 4 @SET_GDT_ENTRY OR [BX][S_DESC.ATTRIBS], 40H ; TASKS' STACKS GO HERE LEA BX, GDT_SS_0 MOV AX, STCK_0 XOR DH, DH MOV DL, AH SHL AX, 4 SHR DX, 4 @SET_GDT_ENTRY LEA BX, GDT_SS_1 MOV AX, STCK_1 XOR DH, DH MOV DL, AH SHL AX, 4 SHR DX, 4 @SET_GDT_ENTRY ; TSSs GO HERE LEA BX, GDT_TSS_MAIN MOV AX, SI MOV DX, DI ADD AX, OFFSET TSS_MAIN ADC DX, 0 @SET_GDT_ENTRY LEA BX, GDT_TSS_0 MOV AX, SI MOV DX, DI ADD AX, OFFSET TSS_0 ADC DX, 0 ; 32-BIT STUFF @SET_GDT_ENTRY LEA BX, GDT_TSS_1 MOV AX, SI MOV DX, DI ADD AX, OFFSET TSS_1 ADC DX, 0 @SET_GDT_ENTRY setupidt.inc (Инициализация IDT) ;-----------; ; Fills IDT ; ;-----------; IRPC LEA MOV SHR MOV ENDM IRPC LEA MOV SHR MOV ENDM N, 0123456789ABCDEF EAX, EXC_0&N IDT_0&N.OFFS_L, AX EAX, 16 IDT_0&N.OFFS_H, AX ; 00...0F N, 0123456789ABCDEF EAX, EXC_1&N IDT_1&N.OFFS_L, AX EAX, 16 IDT_1&N.OFFS_H, AX ; 10...1F LEA EAX, TIMER_HANDLER MOV IDT_TIMER.OFFS_L, AX SHR EAX, 16 MOV IDT_TIMER.OFFS_H, AX LEA EAX, KEYBOARD_HANDLER MOV IDT_KEYBOARD.OFFS_L, AX SHR EAX, 16 MOV IDT_KEYBOARD.OFFS_H, AX ; 20 ; 21 IRPC LEA MOV SHR MOV ENDM IRPC LEA MOV SHR MOV ENDM N, 234567 EAX, DUMMY_IRET0 IDT_2&N.OFFS_L, AX EAX, 16 IDT_2&N.OFFS_H, AX ; 22...27 N, 89ABCDEF EAX, DUMMY_IRET1 IDT_2&N.OFFS_L, AX EAX, 16 IDT_2&N.OFFS_H, AX ; 28...2F LEA EAX, SERVICE_INTERRUPT MOV IDT_SERVICE.OFFS_L, AX SHR EAX, 16 MOV IDT_SERVICE.OFFS_H, AX ; 30 setuptss.inc (Формирование TSS) ;--------------------------------; ; Fills TSSs of additional tasks ; ;--------------------------------; OR TSS_0.R_EFLAGS, 3200H ; IOPL=3, ENABLED INTERRUPTS MOV TSS_0.R_CS, CS_0_DESC MOV TSS_0.R_EIP, OFFSET TASK_0 MOV TSS_0.R_SS, SS_0_DESC MOV TSS_0.R_ESP, SIZE_STACK MOV AX, 0 MOV TSS_0.R_DS, AX MOV TSS_0.R_ES, AX MOV TSS_0.R_FS, AX MOV TSS_0.R_GS, AX MOV TSS_0.SS0, SS_DESC MOV TSS_0.ESP0, SIZE_STACK SHR 1 OR TSS_1.R_EFLAGS, 3200H ; IOPL=3, ENABLED INTERRUPTS MOV TSS_1.R_CS, CS_1_DESC MOV TSS_1.R_EIP, OFFSET TASK_1 MOV TSS_1.R_SS, SS_1_DESC MOV TSS_1.R_ESP, SIZE_STACK MOV AX, 0 MOV TSS_1.R_DS, AX MOV TSS_1.R_ES, AX MOV TSS_1.R_FS, AX MOV TSS_1.R_GS, AX MOV TSS_1.SS0, SS_DESC MOV TSS_1.ESP0, SIZE_STACK SHR 2 show_tss.inc (Просмотр) ; IN: EAX = TSS OFFSET SHOW_TSS PROC NEAR PUSH DS PUSHAD MOV EBX, EAX MOV AX, DS_DESC MOV DS, AX MOV EDI, 10*80*2 LEA ESI, MSG_TSS LEA EDX, OFFS_TSS MOV ECX, 13 SHOW_TSS_CYCLE: CALL W_ASCIIZ ADD ESI, 32 ADD EBX, DS:[EDX] MOV EAX, DS:[EBX] SUB EBX, DS:[EDX] ADD EDI, 7*2 CALL W_EAX ADD EDX, 4 ADD MOV SUB ADD CALL ADD EBX, DS:[EDX] EAX, DS:[EBX] EBX, DS:[EDX] EDI, 16*2 W_EAX EDX, 4 ADD EDI, (80-7-16)*2 LOOP SHOW_TSS_CYCLE POPAD POP DS RET SHOW_TSS ENDP tasks.inc (Описание задач) ;-----------------------------; ; 2 ADDITIONAL TASKS (RING 3) ; ;-----------------------------; ;----------------------; ; TASK #0 CODE SEGMENT ; ;----------------------; CODE_0 SEGMENT PARA USE32 ASSUME CS:CODE_0 CS_0_BEGIN = $ TASK_0 PROC NEAR MOV AX, DS_DESC MOV DS, AX MOV ES, AX LEA ESI, MSG_TASK_0 MOV EDI, 5*80*2 MOV BH, 1 INT 30H MOV EAX, 0 ADD EDI, 80*2 TASK_0_L: MOV BH, 2 INT 30H INC EAX MOV EDX, EAX ADD EDI, 80*2 MOV EAX, ESP MOV BH, 2 INT 30H ; VISUAL TEST OF ESP SUB EDI, 80*2 MOV EAX, EDX JMP TASK_0_L TASK_0 ENDP SIZE_CS_0 = ($ - CS_0_BEGIN) CODE_0 ENDS ;----------------------; ; TASK #1 CODE SEGMENT ; ;----------------------; CODE_1 SEGMENT PARA USE32 ASSUME CS:CODE_1 CS_1_BEGIN = $ TASK_1 PROC NEAR MOV AX, DS_DESC MOV DS, AX MOV ES, AX LEA ESI, MSG_TASK_1 MOV EDI, 5*80*2+10*2 MOV BH, 1 INT 30H MOV EAX, -1 ADD EDI, 80*2 TASK_1_L: MOV BH, 2 INT 30H DEC EAX MOV EDX, EAX ADD EDI, 80*2 MOV EAX, ESP MOV BH, 2 INT 30H ; VISUAL TEST OF ESP SUB EDI, 80*2 MOV EAX, EDX JMP TASK_1_L TASK_1 ENDP SIZE_CS_1 = ($ - CS_1_BEGIN) CODE_1 ENDS ;-----------------------; ; TASK #0 STACK SEGMENT ; ;-----------------------; STCK_0 SEGMENT PARA DB SIZE_STACK DUP (?) STCK_0 ENDS ;-----------------------; ; TASK #1 STACK SEGMENT ; ;-----------------------; STCK_1 SEGMENT PARA DB SIZE_STACK DUP (?) STCK_1 ENDS exc.inc ;----------------------; ; Exception handler(s) ; ;----------------------; M = 0 IRPC N, 0123456789ABCDEF EXC_0&N LABEL WORD CLI PUSH EBP MOV EBP, ESP PUSHAD MOV EAX, M M = M+1 JMP EXC_HANDLER ENDM M = 010H IRPC N, 0123456789ABCDEF EXC_1&N LABEL WORD CLI PUSH EBP MOV EBP, ESP PUSHAD MOV EAX, M M = M+1 JMP EXC_HANDLER ENDM EXC_HANDLER PUSH DS MOV PROC NEAR BX, DS_DESC MOV ; DS, BX CALL LEA MOV CALL ADD CALL SUB CLRSCR ESI, MSG_EXC EDI, 40*2 W_ASCIIZ EDI, 11*2 W_EAX EDI, 11*2 MOV ADD EBX, EBP EBX, 4 ; "EXCEPTION: " ; EXCEPTION NUMBER ; EBX = ^CS:EIP MOVZX EAX, BYTE PTR DS:[EXC_ERR+EAX] OR EAX, EAX JZ EXC_HANDLER_NO_ERR_CODE ; THE EXCEPTION HAS NO ERROR CODE ADD EBX, 4 ; CORRECT EBX LEA ESI, MSG_EXC_ERR ADD EDI, 80*2 CALL W_ASCIIZ MOV AND ADD CALL SUB SUB ; "ERROR CODE: " EAX, SS:[EBP+4] EAX, 0FFFFH EDI, 12*2 W_EAX EDI, 12*2 EDI, 80*2 EXC_HANDLER_NO_ERR_CODE: LEA ESI, MSG_CSEIP ADD EDI, 2*80*2 CALL W_ASCIIZ EIP=XXXXXXXX" ADD EDI, 3*2 ; "CS=XXXXXXXX MOVZX EAX, WORD PTR SS:[EBX+4] CALL W_EAX ; CS ADD EDI, 13*2 MOV EAX, SS:[EBX] CALL W_EAX ; EIP SUB EDI, (3+13)*2 ; jmp $ ; INFINITE LOOP MOV AX, SS_DESC MOV SS, AX MOV ESP, DS:[ESP32] @RETF IRETD EXC_HANDLER ENDP