Ricky zhangrickycheung@21cn.com2005-2-141, experimental purpose: Understand how Minix encapsulates interrupt calls, and fuses with the kernel messaging mechanism. 2, experiment objective: dynamically track: On Bochs, the HWINT_MASTER01 breakpoint of the system's keyboard interrupt call code / kernel/mpx386.s, renew, and resume. Static tracking: Interrupt from the system has the source code, / kernel / mpx386.s, / kernel / proc.c3, experimental steps: dynamic tracking notes: 1. Upload Minix's kernel image (/ miniX / xxx) to Windows Use any anti-compiler to disassemble (Debug can also, but I use W32DASM).
Use STI to find the hwout_master01 code segment of /kernel/mpx386.s, the source code is used in the source code ---------------- / kernel / mpx386.s hwint_master01 Code segment -----------------------------! * =============== ============================================================================================================================================================================================================= ========== *! * Hwint00 - 07 *! * ================================ ===================================================== *! Note this is a Macro, IT Looks Like a Subroutine. # Define Hwint_master (IRQ) / Call Save / * Save Interrupted Process State * /; / INB INT_CTLMASK; / ORB AL, [1 << Irq]; / OUTB IRQ * /; / MOVB AL, ENABLE; / OUTB INT_CTL / * Reenable Master 8259 * /; / 459 * /; /; /; (* IRQ_TABLE [IRQ]) (IRQ) * /; / POP ECX; / CLI / * Disable Interrupts * /; / TEST EAX, EAX / * NEED TO Reenable Irq? * /; / jz 0f; / Inb INT_CTLMASK; / Andb Al, ~ [1 << Irq]; / OUTB INT_CTLMASK / * Enable the Irq * /; / 0: Ret / * R ESTART (Another) Process * /
! Each of these entry points is an expansion of the hwint_master macro .align 16_hwint00: Interrupt routine for irq 0 (the clock) hwint_master (0) .align 16_hwint01: Interrupt routine for irq 1 (keyboard) hwint_master (1) -!.! -------------------------------------------------- -------------------------------------------------- ------------------------------- Correspondence / kernel/mpx386.s The HWINT_MASTER01 core image Results of the HWINT_MASTER01: 000002F1 E8CB020000 call 000005C1: 000002F6 E421 in al, 21: 000002F8 0C02 or al, 02: 000002FA E621 out 21, al: 000002FC B020 mov al, 20: 000002FE E620 out 20, al: 00000300 FB sti: 00000301 6A01 push 00000001: 00000303 FF15C86C0000 Call Dword PTR [00006CC8]: 000000001000303315: IN Al, 21: 00000311 24fd and al, fd: 00000313 E621 OUT 21, Al: 00000315 C3 RET
00000000-00-00 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 BYTE 10 DUP (0)
00000320 00--------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------- ---------------------------------- 2, mention from note, by secondary boot, MINIX image Document (under / minix), loaded into memory physical 0x00800 addresses (source code in /boot/boot.h under /boot/boot.h under /boot/boot.h)) 3, use Bochs's Debug Function bochsdbg, add a physical address breakpoint because the MiniX image is 0x00800 in memory, and the offset of hwint_master01 is 0x000002F1 (the head inside with a.out.h, for some minus 200h) , So the physical start address of HWINT01 in memory is 0x00800 0x002f1-200h-1h = 0x8f0 in the background of Bochs, press Ctrl C, stop
468489601 (0) [0x00000BC0] 0030: 000003C0 (UNK. CTXT): CLD; FS
6833040000 00000Be6: (): xor EBP, EBP; 31ed 00000Be8: (): JMP DWORD PTR DS: [EAX 0x28]; FF6028 byte alignment (4 integrity .align 4) 00000BEC: (): push 0x455; 6855040000 00000BF1: (): JMP DWORD PTR DS: [EAX 0x28]; FF6028 Note: Pushhao is equivalent to TEMP ← (ESP); Push (EAX); Push (ECX); Push (EDX); Push (EBX); Push (TEMP); Push (EBP); Push (ESI); Push (EDI); put DS, ES, FS, GS, and stack. The last four total 2 * 4 = 8Byte, the PUSHAD has a stack size of 8 * 4 = 32byte. Therefore, Total is 0x28 (40D), so the address of JMP DWORD PTR DS: [EAX 0x28] is saved by CS: IP. With SAVE / Kenel/mpx386.s, SAVE comparison! * == ============================================================================================================================================================================================================= ======================== *! * Save *! * ====================== ============================================================================================================================================================================================================= ===== *! Save for protected mode.! This is much simpler Than for 8086 Mode, Because The Stack ALREADY POINTS! INTO The Process Table, or Has Already Been Switch To The Kernel Stack.
.align 16SAVE: CLD! SET DIRECTION FLAG TO A KNOWN VALUE PUSHAD! Save "General" Registers O16 Push DS! Save DS O16 Push ES! SAVE ES O16 PUSH FS! SAVE FS O16 PUSH GS! SAVE GS MOV DX, SS! SS IS KERNEL DATA Segment Mov DS, DX! Load Rest of Kernel Segments Mov ES, DX! KERNEL DOES NOT USE FS, GS MOV EAX, ESP! PREPARE TO RETURN INCB (_K_REENTER)! from -1 if not Reentering jnz set_restart1! Stack IS already kernel stack mov esp, k_stktop push _restart build return address for int handler xor ebp, ebp for stacktrace jmp RETADR-P_STACKBASE (eax) .align 4set_restart1:!! push restart1 jmp RETADR-P_STACKBASE (eax)
From the code, save the restore work divided, one is that there is no interrupt that has not been nested yet, and the other is an interrupted interrupt. The former should first restore the use of the Kernel stack, then let the _Restart get back to the interrupt to make a recovery work and call the un_hold in /proc.c, activate the hangful other interrupt routines. The latter only puts the restart1 in the stack, and then makes recovery after the interrupt is completed. The last two use JMP RetAdr-P_StackBase (EAX) to return to the code after Save.
The following is a dynamic debug result: single step to 0xBD4 (0) [0x00000BD4] 0030: 000003D4 (unk. Ctxt): increst PTR [DS: 0x6c58]; Fe05586C0000
MOV ESP, K_STKTOP PUSH _RESTART! Build Return Address for int handler The following is the _Restart program! * ================================ ============================================== *! * Restart *! * =============================================================================================================================================== =========================================== Reenter.! this does not matter, Because The Current Handler Is About To EXIT AND NO! Other Handlers Can Renerness Flushing is Only Done When K_Reenter == 0.
! Cmp (_held_head), 0 do fast test to usually avoid function call jz over_call_unhold call _unhold this is rare so overhead acceptableover_call_unhold:! Mov esp, (_proc_ptr) will assume P_STACKBASE == 0 lldt P_LDT_SEL (esp) enable segment descriptors for!! task lea eax, P_STACKTOP (esp) arrange for next interrupt mov (_tss TSS3_S_SP0), eax to save state in process tablerestart1:!! decb (_k_reenter) o16 pop gs o16 pop fs o16 pop es o16 pop ds popad add esp, 4 ! SKIP RETURN ADR IRETD! Continue Process Note: When k_reenter == 0, when the nested weight is 0, the UNHOLD routine of the proc.c is called, activating the suspended interrupt routine. Otherwise, the current stack is the Kernel stack, jump directly to set_restart1, and the recovery register works to the address of Restart1 PUSH to the stack, and after the interrupt is completed, execute. Restart1: decB (_K_REENTER) O16 POP GS O16 POP FS O16 POP ES O16 POP DS POPAD Add ESP, 4! Skip Return ADR IRETD! Continue Process Continue Dynamic debug, single step to return 00000Be8: (): JMP DWORD PTR DS: [EAX 0x28]; FF6028
Note: So the return IP is 0xF5, so CS is 0x30, jumps back 0x30: 0xF5 (currently protecting mode)