int.c

来自「Next BIOS Source code : Extensible Firmw」· C语言 代码 · 共 859 行 · 第 1/2 页

C
859
字号
    ;


    ;
    ; Turn protected mode off
    ;

        _emit   0x66
        mov     eax, cr0
        _emit   0x66
        and     eax, not CR0_PE
        _emit   0x66
        mov     cr0, eax

        _emit   0xEA                    ; jmp far 16:16
LCSP4:  _emit   0x00                    ; offset
        _emit   0x00                        ; (LCS40)
        _emit   0x00                    ; segment
        _emit   0x00                        ; (realmode cs)

LCS40:

    ;
    ; We are now in real mode
    ; Fix SS
    ;
        _emit   0xb8                    ; mov ax,
LCSP5:  _emit   0x00                        ; (readmode ss)
        _emit   0x00

        _emit   0x8e                    ; mov ss, ax
        _emit   0xd0

        sti
    ;
    ; Load regs with callers request
    ; NOTE1: that this pop sequence matches the
    ;        IA32_RegisterSet_t structure.
    ; NOTE2: the follow instructions are really executed
    ;        as 16 bit instructions as we are in real mode
    ;

        pop     eax
        pop     ebx
        pop     ecx
        pop     edx
        pop     esi
        pop     edi
        popfd
        pop     es
        pop     ebp         ; throw away cs
        pop     ebp         ; throw away ss
        pop     ds
        pop     ebp

        _emit   0xcd        ; issue NT or a FAR CALL
LCSP6:  _emit   00          ; INT # or OFFSET
        _emit   0x90        ; NOP or OFFSET
        _emit   0x90        ; NOP or SEGMENT
        _emit   0x90        ; NOP or SEGMENT

    ;
    ; Save the result regs
    ; See the above NOTEs
    ;

        push    ebp
        mov     ebp, eax    ; save eax

        push    ds
        push    eax         ; throw away ss
        push    eax         ; throw away cs
        push    es
        pushfd
        push    edi
        push    esi
        push    edx
        push    ecx
        push    ebx
        push    ebp         ; ax results are in bp


;
; Test to see if the A20 Gate needs to be enabled
;

TestA20Gate:
        cli
        push    es
        push    ds
        _emit   0x31        ; xor ax,ax         ax = 0
        _emit   0xc0
        _emit   0x89        ; mov si,ax         si = 0
        _emit   0xc6
        _emit   0x89        ; mov bp,ax         bp = 0
        _emit   0xc5
        _emit   0x8e        ; mov ds,ax         ds = 0
        _emit   0xd8
        _emit   0x48        ; dec ax            ax = ffff
        _emit   0x8e        ; mov es,ax         es = ffff
        _emit   0xc0
        _emit   0x8a        ; mov cl,[si]       cl = ds:[si] = 0000:0000
        _emit   0x0c
        _emit   0x26        ; es:
        _emit   0x8a        ; mov ch,[bp+10]    ch = es:[bp+10] = ffff:0000+10 = ffff:0010
        _emit   0x6e
        _emit   0x10
        _emit   0xc6        ; mov byte ptr [si],aa      ds:[si] = aa    0000:0000 = aa
        _emit   0x04
        _emit   0xaa
        _emit   0x26        ; es:
        _emit   0xc6        ; mov byte ptr [bp+10],55   es:[bp+10] = 55 ffff:0010 = 55
        _emit   0x46
        _emit   0x10
        _emit   0x55
        _emit   0x80        ; cmp byte ptr [si],aa      ds:[si] = 0000:0000
        _emit   0x3c
        _emit   0xaa
        _emit   0x88        ; mov [si],cl               ds:[si] = 0000:0000
        _emit   0x0c
        _emit   0x26        ; es:
        _emit   0x88        ; mov [bp+10],ch            es:[bp+10] = ffff:0010
        _emit   0x6e
        _emit   0x10
        jnz     EnableA20Gate        
        pop     ds
        pop     es
        sti
        jmp     A20GateEnabled
EnableA20Gate:
        pop     ds
        pop     es
        sti


;
; Enable A20 Mask
;


        _emit   0xb8                    ; mov ax,2401h
        _emit   0x01
        _emit   0x24
        _emit   0xcd                    ; INT 15h
        _emit   0x15
        jnc     TestA20Gate             ; Jump if it suceeded

        mov     ecx,0
Empty8042Loop0:
        _emit   0xe7            ; out DELAYPORT,ax
        _emit   0xed
        _emit   0xe4            ; in  al,KBD_STATUS_PORT
        _emit   0x64
        _emit   0x24            ; and al,02h
        _emit   0x02
        loopnz  Empty8042Loop0
        jnz     Timeout8042

        _emit   0xe7            ; out DELAYPORT,ax
        _emit   0xed
        _emit   0xb0            ; mov al,WRITE_DATA_PORT_CMD
        _emit   0xd1
        _emit   0xe6            ; out KBD_STATUS_PORT,al
        _emit   0x64

        mov     ecx,0
Empty8042Loop1:
        _emit   0xe7            ; out DELAYPORT,ax
        _emit   0xed
        _emit   0xe4            ; in  al,KBD_STATUS_PORT
        _emit   0x64
        _emit   0x24            ; and al,02h
        _emit   0x02
        loopnz  Empty8042Loop1
        jnz     Timeout8042

        _emit   0xb0            ; mov al,ENABLE_A20_CMD
        _emit   0xdf
        _emit   0xe6            ; out KBD_CONTROL_PORT,al
        _emit   0x60

        mov     ecx,0
Empty8042Loop2:
        _emit   0xe7            ; out DELAYPORT,ax
        _emit   0xed
        _emit   0xe4            ; in  al,KBD_STATUS_PORT
        _emit   0x64
        _emit   0x24            ; and al,02h
        _emit   0x02
        loopnz  Empty8042Loop2

        mov     ecx,25
Delay25uS:
        _emit   0xe7            ; out DELAYPORT,ax
        _emit   0xed
        loop    Delay25uS
        jmp     TestA20Gate
Timeout8042:
A20GateEnabled:

        cli

        _emit   0xb8                    ; mov ax,
LGDT2:  _emit   0x00                    ; GDTR
        _emit   0x00

        push    eax

        _emit   0xb8                    ; mov ax,
LGDT1:  _emit   0x00                    ; GDTR
        _emit   0x00

        push    eax

        _emit   0xb8                    ; mov ax,
LGDT0:  _emit   0x00                    ; GDTR
        _emit   0x00

        push    eax

        push    ss
        pop     ds
        mov     ebx,esp

        pop     eax
        pop     eax
        pop     eax

    ; lgdt    fword ptr [bx]
        _emit   0x66
        _emit   0x0f
        _emit   0x01
        _emit   0x17

    ;
    ; Turn protected mode on
    ;

        _emit   0x66
        mov     eax, cr0
        _emit   0x66
        or      eax, CR0_PE
        _emit   0x66
        mov     cr0, eax

    ;
    ; Return to 32 bit flat mode
   ; Put flat DS in ax
    ;
        _emit   0xb8                    ; mov ax,
LCSP2:  _emit   0x00                    ; flat ds
        _emit   0x00

    ;
    ; Return to 32 bit cs
    ;

        _emit   0x66
        _emit   0xEA                    ; jmp far 16:32
LCSP1:  _emit   0x00                    ; offset
        _emit   0x00                        ; (LCS90)
        _emit   0x00
        _emit   0x00
        _emit   0x00                    ; selector
        _emit   0x00                        ; (flat CS)

LCS90:
    ; restore data selector
        mov     ds, ax
        mov     es, ax
        mov     fs, ax
        mov     gs, ax

    ;
    ; Restore 32bit Idt
    ;

        mov     esi, IntThunk
        lidt    fword ptr LOW_MEMORY_THUNK [esi].IdtDesc

    ;
    ; Restore 32bit stack
    ;
        mov     ecx, LOW_MEMORY_THUNK [esi].FlatSs
        mov     ss, cx
        mov     esp, LOW_MEMORY_THUNK [esi].FlatEsp

        xor     eax, eax
        lldt    ax

    ;
    ; Restore c regs
    ;

        pop     ebx
        pop     edx
        pop     ebp
        pop     esi
        pop     edi
        popfd
        ret
LCS99:  nop
    }
}

VOID
InitializeBiosIntCaller (
    VOID
    )
{
    EFI_PHYSICAL_ADDRESS        MemPage;
    EFI_STATUS                  Status;
    GDT                         *CodeGdt, *DataGdt;
    UINT32                      LowCodeStart, LowCodeEnd, Base;

    //
    // Allocate 1 page below 1MB to put real mode thunk code in
    //

    MemPage = ONEMB - 1;
    Status = BS->AllocatePages (    
                    AllocateMaxAddress,
                    EfiBootServicesCode,
                    sizeof(LOW_MEMORY_THUNK) / 4096 + 1,
                    &MemPage
                    );

    ASSERT (!EFI_ERROR(Status));
    IntThunk = (LOW_MEMORY_THUNK *) MemPage;

    //
    // Capture the flat gdt, idt, and selector values
    //

    _asm {
        mov     ecx, IntThunk
        sgdt    [ecx].GdtDesc
        sidt    [ecx].IdtDesc
        mov     ax, ss
        movzx   eax, ax
        mov     [ecx].FlatSs, eax
    }

    //
    // Allocate a new GDT for real-mode code
    //
    // BUGBUG: we're just assuming that the first selector
    // that is not is use is something we can allocate
    //

    for (CodeGdt = ((GDT *) IntThunk->GdtDesc.Base) + 1; CodeGdt->Present; CodeGdt += 1) ;

    //
    // Fill in the new descriptor to by our real-mode segment value
    //

    CodeGdt->Type        = 0xA;         // code/read
    CodeGdt->System      = 1;
    CodeGdt->Dpl         = 0;
    CodeGdt->Present     = 1;
    CodeGdt->Software    = 0;
    CodeGdt->Reserved    = 0;
    CodeGdt->DefaultSize = 0;           // 16 bit operands
    CodeGdt->Granularity = 0;

    CodeGdt->LimitHi     = 0;
    CodeGdt->LimitLo     = 0xffff;

    Base = ((UINT32) IntThunk);
    CodeGdt->BaseHi      = (Base >> 24) & 0xFF;
    CodeGdt->BaseMid     = (Base >> 16) & 0xFF;
    CodeGdt->BaseLo      = Base & 0xFFFF;

    //
    // Allocate a new GDT for read-mode data
    //

    for (DataGdt = CodeGdt; DataGdt->Present; DataGdt += 1) ;
    CopyMem (DataGdt, CodeGdt, sizeof(GDT));
    DataGdt->Type = 0x2;                // read/write data

    //
    // Compute selector value
    //

    IntThunk->LowCodeSelector  = ((UINT32) CodeGdt) - IntThunk->GdtDesc.Base;
    IntThunk->LowDataSelector  = ((UINT32) DataGdt) - IntThunk->GdtDesc.Base;
    IntThunk->RealModeIdtDesc.Limit = 0xFFFF;
    IntThunk->RealModeIdtDesc.Base  = 0;

    //
    // Initialize low real-mode code thunk
    //

    RealModeTemplate (&LowCodeStart, &LowCodeEnd);
    CopyMem (IntThunk->Code, (VOID *) LowCodeStart, LowCodeEnd-LowCodeStart);

    BiosIntCallerInitialized = TRUE;

}

BOOLEAN
Int86Available (
    VOID
    )
{
    return BiosIntCallerInitialized;
}

VOID
PlGenerateIrq(
    UINT8 irq
    )
{
	UINT8 interrupt;
  
  interrupt = PlGetVectorFromIrq(irq);

	if (interrupt) _asm {
		mov		ecx, offset PatchInt
		mov 		al, [interrupt]
		mov		[ecx], al
		jmp		DoInterrupt
DoInterrupt:
		_emit	0xcd
PatchInt:	_emit	0
	}
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?