;; @file ; This is the code that supports IA32 CPU architectural protocol ; ;****************************************************************************** ;* Copyright (c) 2015, Insyde Software Corporation. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** page ,132 title CPU ARCHITECTURAL PEI ASSEMBLY HOOKS ;------------------------------------------------------------------------------ ; ; Copyright (c) 1999 - 2011, 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: ; ; CpuAsm.asm ; ; Abstract: ; ; Assembly code that supports IA32 CPU architectural Ppi ; ;------------------------------------------------------------------------------ .686p .model flat .data ExternalVectorTablePtr DD ? ; Table of call backs CommonInterruptEntry DD CommonEntry ; Address of CommonEntry Idtr DW ? ; FWORD for IDT register Idtr1 DD ? ; MUST BE IMMEDIATELY AFTER Idtr EXTRN _mErrorCodeFlag:DWORD ; Error code flags for exceptions .stack .code .MMX .XMM UINT8 TYPEDEF BYTE UINT16 TYPEDEF WORD UINT32 TYPEDEF DWORD UINT64 TYPEDEF QWORD UINTN TYPEDEF UINT32 ;---------------------------------------; ; _InitializeIdt ; ;----------------------------------------------------------------------------; ; ; Protocol prototype ; InitializeIdt ( ; IN EFI_CPU_INTERRUPT_HANDLER TableStart, ; IN UINTN *IdtTablePtr, ; IN UINT16 IdtLimit ; ) ; ; Routine Description: ; ; Creates an IDT table starting at IdtTablPtr. It has IdtLimit/8 entries. ; Table is initialized to intxx where xx is from 00 to number of entries or ; 100h, whichever is smaller. After table has been initialized the LIDT ; instruction is invoked. ; ; TableStart is the pointer to the callback table and is not used by ; InitializedIdt but by commonEntry. CommonEntry handles all interrupts, ; does the context save and calls the callback entry, if non-NULL. ; It is the responsibility of the callback routine to do hardware EOIs. ; ; Arguments: ; ; TableStart - Pointer to interrupt callback table ; ; IdtTablePtr - Pointer to IDT table ; ; IdtLimit - IDT Table limit = number of interrupt entries * 8 ; ; Returns: ; ; Nothing ; ; ; Input: [ebp][0] = Original ebp ; [ebp][4] = Return address ; [ebp][8] = TableStart ; [ebp][0c] = *IdtTablePtr ; [ebp][10] = IdtLimit ; ; Output: Nothing ; ; Destroys: Nothing ;-----------------------------------------------------------------------------; _InitializeIdt proc near public push ebp ; C prolog mov ebp, esp push edi mov eax, [ebp+8] ; Get ExternalVectorTable Address mov ExternalVectorTablePtr, eax mov ax, [ebp+10h] ; Get IDT Table limit dec ax mov Idtr, ax mov eax, [ebp+0ch] ; Get Start of IDT mov Idtr1, eax mov edi, OFFSET Idtr ; Load IDT register lidt FWORD PTR es:[edi] pop edi pop ebp ret _InitializeIdt endp ;----------------------------------------------------------------------------; ; ; Protocol prototype ; None ; ; Routine Description: ; ; These routines handle the individual interrupts. These routines always ; gain control on any interrupt or exception. They save EAX and place ; the interrupt number in EAX. CommonEntry is then jumped to. ; instruction is invoked. ; ; CommonEntry handles all interrupts,does the context save and calls the ; callback entry, if non-NULL. It is the responsibility of the callback ; routine to do hardware EOIs. Callbacks are entered into the table ; located at TableStart. Entries are modified by the InstallInterruptHandler ; and UninstallInterruptHandler protocols. ; ; Arguments to CommonEntry: ; ; EAX - Interrupt or exception number ; ; TableStart - Pointer to interrupt callback table ; ; Returns: ; ; Nothing ; ; ; Output: Nothing ; ; Destroys: Nothing ;-----------------------------------------------------------------------------; TemplateStart: push eax ;mov eax, 0nnh (nn stands for vector number, which will be fixed at runtime DB 0b8h VectorNumber: DD 00h jmp dword ptr [CommonInterruptEntry]; TemplateEnd: CommonEntry: ;---------------------------------------; ; _CommonEntry ; ;----------------------------------------------------------------------------; ; The follow algorithm is used for the common interrupt routine. ; Entry from each interrupt with a push eax and eax=interrupt number ; ; +---------------------+ ; + EFlags + ; +---------------------+ ; + CS + ; +---------------------+ ; + EIP + ; +---------------------+ ; + Error Code + ; +---------------------+ ; + EAX / Vector Number + ; +---------------------+ ; + EBP + ; +---------------------+ <-- EBP ; cli ; ; All interrupt handlers are invoked through interrupt gates, so ; IF flag automatically cleared at the entry point ; cmp eax, 32 ; Intel reserved vector for exceptions? jae NoErrorCode bt cs:_mErrorCodeFlag, eax jc @F NoErrorCode: ; ; Push a dummy error code on the stack ; to maintain coherent stack map ; push [esp] mov dword ptr [esp + 4], 0 @@: push ebp mov ebp, esp ; ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 ; is 16-byte aligned ; and esp, 0fffffff0h sub esp, 12 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; push dword ptr [ebp + 4] ; EAX push ecx push edx push ebx lea ecx, [ebp + 24] push ecx ; ESP push dword ptr [ebp] ; EBP push esi push edi mov [ebp + 4], eax ; save vector number ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; mov eax, ss push eax movzx eax, word ptr [ebp + 16] push eax mov eax, ds push eax mov eax, es push eax mov eax, fs push eax mov eax, gs push eax ;; UINT32 Eip; push dword ptr [ebp + 12] ;; UINT32 Gdtr[2], Idtr[2]; sub esp, 8 sidt fword ptr [esp] sub esp, 8 sgdt fword ptr [esp] ;; UINT32 Ldtr, Tr; xor eax, eax str ax push eax sldt ax push eax ;; UINT32 EFlags; push dword ptr [ebp + 20] ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; mov eax, cr4 or eax, 208h mov cr4, eax push eax mov eax, cr3 push eax mov eax, cr2 push eax xor eax, eax push eax mov eax, cr0 push eax ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; mov eax, dr7 push eax mov eax, dr6 push eax mov eax, dr3 push eax mov eax, dr2 push eax mov eax, dr1 push eax mov eax, dr0 push eax ;; FX_SAVE_STATE_IA32 FxSaveState; sub esp, 512 mov edi, esp db 0fh, 0aeh, 00000111y ;fxsave [edi] ;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear cld ;; UINT32 ExceptionData; push dword ptr [ebp + 8] ;; call into exception handler mov ebx, [ebp + 4] mov eax, ExternalVectorTablePtr mov eax, [eax + ebx * 4] or eax, eax ; NULL? je nonNullValue; ;; Prepare parameter and call mov edx, esp push edx push ebx call eax add esp, 8 nonNullValue: cli ;; UINT32 ExceptionData; add esp, 4 ;; FX_SAVE_STATE_IA32 FxSaveState; mov esi, esp db 0fh, 0aeh, 00001110y ; fxrstor [esi] add esp, 512 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; ;; Skip restoration of DRx registers to support in-circuit emualators ;; or debuggers set breakpoint in interrupt/exception context add esp, 4 * 6 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; pop eax mov cr0, eax add esp, 4 ; not for Cr1 pop eax mov cr2, eax pop eax mov cr3, eax pop eax mov cr4, eax ;; UINT32 EFlags; pop dword ptr [ebp + 20] ;; UINT32 Ldtr, Tr; ;; UINT32 Gdtr[2], Idtr[2]; ;; Best not let anyone mess with these particular registers... add esp, 24 ;; UINT32 Eip; pop dword ptr [ebp + 12] ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; ;; NOTE - modified segment registers could hang the debugger... We ;; could attempt to insulate ourselves against this possibility, ;; but that poses risks as well. ;; pop gs pop fs pop es pop ds pop dword ptr [ebp + 16] pop ss ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; pop edi pop esi add esp, 4 ; not for ebp add esp, 4 ; not for esp pop ebx pop edx pop ecx pop eax mov esp, ebp pop ebp add esp, 8 iretd ;---------------------------------------; ; _GetTemplateAddressMap ; ;----------------------------------------------------------------------------; ; ; Protocol prototype ; GetTemplateAddressMap ( ; INTERRUPT_HANDLER_TEMPLATE_MAP *AddressMap ; ); ; ; Routine Description: ; ; Return address map of interrupt handler template so that C code can generate ; interrupt handlers, and dynamically do address fix. ; ; Arguments: ; ; ; Returns: ; ; Nothing ; ; ; Input: [ebp][0] = Original ebp ; [ebp][4] = Return address ; ; Output: Nothing ; ; Destroys: Nothing ;-----------------------------------------------------------------------------; _GetTemplateAddressMap proc near public push ebp ; C prolog mov ebp, esp pushad mov ebx, dword ptr [ebp+08h] mov dword ptr [ebx], TemplateStart mov dword ptr [ebx+4h], TemplateEnd - TemplateStart ; if code in Template is updated, the value fills into the 3rd parameter ; also needs update mov dword ptr [ebx+8h], VectorNumber - TemplateStart popad pop ebp ret _GetTemplateAddressMap endp END