int.c

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

C
859
字号
/*++

Copyright (c)  1999 - 2002 Intel Corporation. All rights reserved
This software and associated documentation (if any) is furnished
under a license and may only be used or copied in accordance
with the terms of the license. Except as permitted by such
license, no part of this software or documentation may be
reproduced, stored in a retrieval system, or transmitted in any
form or by any means without the express written consent of
Intel Corporation.


Module Name:

    init.c

Abstract:

    Main entry point on EFI 32-bit emulation environment. This envirnment layers 
    on top of the of a legacy BIOS



Revision History

--*/

#include "efi.h"
#include "efilib.h"
#include "Int86.h"
#include "PlIntCtrl.h"
#include "PlTpl.h"

//
// Interesting CR0 flags
//

#define CR0_PE          0x00000001


//
// Processor structres are packed
//

#pragma pack (1)

//
// Define what a processor GDT looks like
//

typedef struct {
    UINT32  LimitLo     : 16;
    UINT32  BaseLo      : 16;

    UINT32  BaseMid     : 8;
    UINT32  Type        : 4;
    UINT32  System      : 1;
    UINT32  Dpl         : 2;
    UINT32  Present     : 1;
    UINT32  LimitHi     : 4;
    UINT32  Software    : 1;
    UINT32  Reserved    : 1;
    UINT32  DefaultSize : 1;
    UINT32  Granularity : 1;
    UINT32  BaseHi      : 8;
} GDT ;


//
// Define what a processor descriptor looks like
//


typedef struct {
    UINT16  Limit;
    UINT32  Base;
} DESCRIPTOR;

#pragma pack ()

//
// Low stub lay out
//

#define LOW_STACK_SIZE      (8*1024)            // 8k?

typedef struct {
    //
    // Space for the code
    //

    CHAR8               Code[4096];             // ?

    //
    // Data for the code (cs releative)
    //

    DESCRIPTOR          GdtDesc;                // Protected mode GDT
    DESCRIPTOR          IdtDesc;                // Protected mode IDT
    UINT32              FlatSs;
    UINT32              FlatEsp;

    UINT32              LowCodeSelector;        // Low code selector in GDT
    UINT32              LowDataSelector;        // Low data selector in GDT
    UINT32              LowStack;
    DESCRIPTOR          RealModeIdtDesc;

    //
    // A low memory stack
    //

    CHAR8               Stack[LOW_STACK_SIZE];

} LOW_MEMORY_THUNK;


//
// Globals
//

LOW_MEMORY_THUNK        *IntThunk;

STATIC BOOLEAN BiosIntCallerInitialized = FALSE;

//
//
//

BOOLEAN
Int86 (
    IN  UINT8               BiosInt,
    IN  IA32_RegisterSet_t  *Regs
    )
// returns carry flag
{
    UINTN               Status;
    UINT16              *S16;
    BOOLEAN             SavedInterruptState;

    Regs->x.Flags.Reserved1 = 1;
    Regs->x.Flags.Reserved2 = 0;
    Regs->x.Flags.Reserved3 = 0;
    Regs->x.Flags.Reserved4 = 0;
    Regs->x.Flags.IOPL      = 3;
    Regs->x.Flags.NT        = 0;
    Regs->x.Flags.IF        = 1;
    Regs->x.Flags.TF        = 0;

    S16 = (UINT16 *) (IntThunk->Stack + LOW_STACK_SIZE);

    //
    // Copy regs to low memory stack
    //

    S16 -=  sizeof(IA32_RegisterSet_t) / sizeof(UINT16);
    CopyMem (S16, Regs, sizeof(IA32_RegisterSet_t));

    //
    // Provide low stack esp
    //

    IntThunk->LowStack = ((UINT32) S16) - ((UINT32) IntThunk);

    SavedInterruptState = PlSetInterruptState(FALSE);   // insure interrupts are turned off
    PlSetupInterruptControllerMask(INT_CTRLR_BIOSMODE); // Save/Setup interrupt controller mask
    
    //
    // Call the real mode int thunk code
    //

    _asm {
        movzx   ecx, BiosInt
        mov     edx, 0
        mov     eax, IntThunk
        call    eax
        mov     Status, eax

    }

    PlSetupInterruptControllerMask(INT_CTRLR_EFIMODE); // Save/Setup interrupt controller mask
    PlSetInterruptState(SavedInterruptState);          // Restore interrupt flag

    PlGenerateIrq (0);

    //
    // Return the resulting registers
    //

    CopyMem (Regs, S16, sizeof(IA32_RegisterSet_t));

    return Regs->x.Flags.CF ? TRUE : FALSE;
}

BOOLEAN
FarCall86 (
    IN  UINT16              Segment,
    IN  UINT16              Offset,
    IN  IA32_RegisterSet_t  *Regs,
    IN  VOID                *Stack,
    IN  UINTN               StackSize
    )
// returns carry flag
{
    UINT32              CallAddress;
    UINTN               Status;
    UINT16              *S16;
    BOOLEAN             SavedInterruptState;

    CallAddress = (Segment<<16) | Offset;

    Regs->x.Flags.Reserved1 = 1;
    Regs->x.Flags.Reserved2 = 0;
    Regs->x.Flags.Reserved3 = 0;
    Regs->x.Flags.Reserved4 = 0;
    Regs->x.Flags.IOPL      = 3;
    Regs->x.Flags.NT        = 0;
    Regs->x.Flags.IF        = 1;
    Regs->x.Flags.TF        = 0;

    S16 = (UINT16 *) (IntThunk->Stack + LOW_STACK_SIZE);

    if (Stack!=NULL && StackSize!=0) {

        //
        // Copy Stack to low memory stack
        //

        S16 -=  StackSize / sizeof(UINT16);
        CopyMem (S16, Stack, StackSize);
    }

    //
    // Copy regs to low memory stack
    //

    S16 -=  sizeof(IA32_RegisterSet_t) / sizeof(UINT16);
    CopyMem (S16, Regs, sizeof(IA32_RegisterSet_t));

    //
    // Provide low stack esp
    //

    IntThunk->LowStack = ((UINT32) S16) - ((UINT32) IntThunk);

    SavedInterruptState = PlSetInterruptState(FALSE);
    PlSetupInterruptControllerMask(INT_CTRLR_BIOSMODE); // Save/Setup interrupt controller
    
    //
    // Call the real mode int thunk code
    //

    _asm {
        mov     ecx, 0
        mov     edx, CallAddress
        mov     eax, IntThunk
        call    eax
        mov     Status, eax
    }

    PlSetupInterruptControllerMask(INT_CTRLR_EFIMODE);
    PlSetInterruptState(SavedInterruptState); 

    PlGenerateIrq (0);

    //
    // Return the resulting registers
    //

    CopyMem (Regs, S16, sizeof(IA32_RegisterSet_t));
    S16 +=  sizeof(IA32_RegisterSet_t) / sizeof(UINT16);

    if (Stack!=NULL && StackSize!=0) {

        //
        // Copy low memory stack to Stack
        //

        CopyMem (Stack, S16, StackSize);
        S16 +=  StackSize / sizeof(UINT16);
    }

    return Regs->x.Flags.CF ? TRUE : FALSE;
}

VOID
RealModeTemplate (
    OUT UINT32          *LowCodeStart,
    OUT UINT32          *LowCodeEnd
    )
{
    _asm {
        mov     eax, LowCodeStart
        mov     ecx, offset LCS0
        mov     [eax], ecx

        mov     eax, LowCodeEnd
        mov     ecx, offset LCS99
        mov     [eax], ecx

        ; patch in the far jump to 16bit protected mode
        mov     eax, offset LCSP3
        mov     ecx, offset LCS1
        sub     ecx, offset LCS0
        mov     [eax], ecx
        mov     ecx, IntThunk
        mov     ecx, LOW_MEMORY_THUNK [ecx].LowCodeSelector
        mov     [eax+4], cx

        ; patch in the far jump to real-mode
        mov     eax, offset LCSP4
        mov     ecx, offset LCS40
        sub     ecx, offset LCS0
        mov     [eax], cx
        mov     edx, IntThunk
        shr     edx, 4
        mov     [eax+2], dx

        ; patch in the real-mode ss
        mov     word ptr [LCSP5], dx

        ; patch in the far jump back to flat mode
        mov     eax, offset LCSP1
        mov     ecx, offset LCS90
        mov     [eax], ecx
        mov     cx, cs
        mov     [eax+4], cx

        ; path in flat ds value for restore
        mov     ax, ds
        mov     word ptr [LCSP2], ax

        ; patch in GdtDesc
        mov     ecx, IntThunk
        mov     ax, LOW_MEMORY_THUNK [ecx].GdtDesc
        mov     word ptr [LGDT0], ax
        mov     ax, LOW_MEMORY_THUNK [ecx+2].GdtDesc
        mov     word ptr [LGDT1], ax
        mov     ax, LOW_MEMORY_THUNK [ecx+4].GdtDesc
        mov     word ptr [LGDT2], ax
    
    }

    // always return
    if (*LowCodeStart) {
        return ;
    }

    //
    // real mode int thunk code
    //

    _asm {
LCS0:
    ;
    ; Save protected mode registers
    ; CL = BiosInt to invoke
    ;

        pushfd                          ; Save flags
        cli

        push    edi                     ; Save C regs
        push    esi
        push    ebp
        push    edx
        push    ebx

        mov     esi, IntThunk           ; esi = IntThunk

    ;
    ; Save flat 32bit stack location
    ;

        mov     LOW_MEMORY_THUNK [esi].FlatEsp, esp

    ;
    ; Patch in BiosInt value into low memory thunk
    ;

        cmp     edx,0
        jne     PatchFarCall
        mov     eax, esi
        add     eax, offset LCSP6
        sub     eax, offset LCS0
        mov     [eax-1], 0xcd       ; INT inst
        mov     [eax], cl           ; INT #
        mov     [eax+1], 0x90       ; NOP
        mov     [eax+2], 0x90       ; NOP
        mov     [eax+3], 0x90       ; NOP
        jmp     PatchComplete
PatchFarCall:
        mov     eax, esi
        add     eax, offset LCSP6
        sub     eax, offset LCS0
        mov     [eax-1], 0x9a       ; CALL inst
        mov     [eax], edx          ; Fill in SEG:OFF
PatchComplete:

    ;
    ; Set idt for real mode IVT
    ;

        lidt    fword ptr LOW_MEMORY_THUNK [esi].RealModeIdtDesc

    ;
    ; Load real-mode style selectors limits
    ;

        mov     eax, LOW_MEMORY_THUNK [esi].LowDataSelector
        mov     ebx, LOW_MEMORY_THUNK [esi].LowStack

        mov     gs, ax
        mov     fs, ax
        mov     es, ax
        mov     ds, ax
        mov     ss, ax
        mov     esp, ebx

        _emit   0xEA                    ; jmp far 16:32
LCSP3:  _emit   0x00                    ; offset
        _emit   0x00                        ; (LCS1)
        _emit   0x00
        _emit   0x00
        _emit   0x00                    ; selector
        _emit   0x00                        ; (16bit CS)

LCS1:

    ;
    ; We are now in 16bit protcted mode, on the low memory

⌨️ 快捷键说明

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