Step to UEFI (135)EFI_CPU_ARCH_PROTOCOL 注册的 INTx

前面提到的 EFI_CPU_ARCH_PROTOCOL ,这次试试这个Protocol RegisterInterrupt,注册一个我们自己的中断试试。

rd3

为了完成这个目标,我们设计下面的方案:
1. 编写一个驱动,在这个驱动里面注册我们自己的 Interrupt,我使用的是 0x41 作为中断向量(经过检查,实际机器上使用了0x40作为给HPET Timer的Interrupt,这里我们选择一个不冲突的即可)。方便起见,选择使用之前我们设计的 Print9 Protocol 的代码,这个代码会在系统中注册我们自己定义的 Protocol,然后这个 Protocol 中留出来一个输出变量(Var2)的函数,以便调用。我们的InterruptHandler也在这个文件中,内容很简单,就是将 Var2 加一;
2. 编写一个 Application 来在系统中查找上面驱动注册的Protocol,找到之后调用输出变量的函数,这样我们可以知道这个函数是否有变化;
3. 最后再编写一个 Application 用来产生 int 0x41。
首先是第一个的代码,这个需要放置在 MdeModule 中编译而不是我们经常用的 AppPkg中,插入在 MdeModulePkg.dsc 文件中

  MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
  MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf

#LabZDebug_Start
  MdeModulePkg/PrintDriver3/PrintDriver3.inf
#LabZDebug_End

 [Components.IA32, Components.X64, Components.IPF, Components.AARCH64]
  MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf
  MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxe.inf

 

代码如下:

/** @file
  This driver produces Print9 protocol layered on top of the PrintLib from the MdePkg.

Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution.  The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php

THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

**/

#include <PiDxe.h>
#include <Library/UefiLib.h>

#include <Library/PrintLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/MemoryAllocationLib.h>
#include "Print9.h"

#include <Protocol/Cpu.h>
#include <Library/CpuLib.h>

extern EFI_SYSTEM_TABLE         *gST;

EFI_GUID gEfiPrint9ProtocolGuid =
                { 0xf05976ef, 0x83f1, 0x4f3d, 
                  { 0x86, 0x19, 0xf7, 0x59,0x5d, 0x41, 0xe5, 0x61 } };

EFI_GUID gEfiCpuArchProtocolGuid = 
                { 0x26BACCB1, 0x6F42, 0x11D4, 
                  { 0xBC, 0xE7, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }};

EFI_PRINT9_PRIVATE_DATA         *Image;
EFI_HANDLE  mPrintThunkHandle   = NULL;

//Copied from \MdeModulePkg\Library\DxePrintLibPrint2Protocol\PrintLib.c
UINTN
EFIAPI
MyPrint ()
{
  CHAR16  *Buffer=L"1 2 3 4 5 6 7 8 9 0 A B C E D F ";
  
  UnicodeSPrint(Buffer,16,L"%d\r\n",Image->Var2);
  gST->ConOut->OutputString(gST->ConOut,Buffer); 
  
  return 0;
}

VOID
EFIAPI
MyInterruptHandler (
  IN EFI_EXCEPTION_TYPE   InterruptType,
  IN EFI_SYSTEM_CONTEXT   SystemContext
  )
{
       Image->Var2++; 
}  
/**
  The user Entry Point for Print module.

  This is the entry point for Print DXE Driver. It installs the Print2 Protocol.

  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
  @param[in] SystemTable    A pointer to the EFI System Table.

  @retval EFI_SUCCESS       The entry point is executed successfully.
  @retval Others            Some error occurs when executing this entry point.

**/
EFI_STATUS
EFIAPI
PrintEntryPoint (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  )
{
        EFI_STATUS              Status;
        EFI_CPU_ARCH_PROTOCOL  *Cpu;
        
        //
        // Allocate a new image structure
        //
        Image = AllocateZeroPool (sizeof(EFI_PRINT9_PRIVATE_DATA));
        if (Image == NULL) {
                Status = EFI_OUT_OF_RESOURCES;
                ASSERT_EFI_ERROR (Status);
        }

        Image->Signature         = PRINT9_PRIVATE_DATA_SIGNATURE;
  
        Image->PRINT9.UnicodeBSPrint=UnicodeBSPrint;
        Image->PRINT9.UnicodeSPrint=UnicodeSPrint;
        Image->PRINT9.UnicodeBSPrintAsciiFormat=UnicodeBSPrintAsciiFormat;
        Image->PRINT9.UnicodeSPrintAsciiFormat=MyPrint;
        //Image->PRINT9.UnicodeValueToString=UnicodeValueToString;
        Image->PRINT9.AsciiBSPrint=AsciiBSPrint;
        Image->PRINT9.AsciiSPrint=AsciiSPrint;        
        Image->PRINT9.AsciiBSPrintUnicodeFormat=AsciiBSPrintUnicodeFormat;
        Image->PRINT9.AsciiSPrintUnicodeFormat=AsciiSPrintUnicodeFormat;
        //Image->PRINT9.AsciiValueToString=AsciiValueToString;

        Image->Var2=1984;
        
        Status = gBS->InstallMultipleProtocolInterfaces (
                  &mPrintThunkHandle,
                  &gEfiPrint9ProtocolGuid, 
                  &Image->PRINT9,
                  NULL
                );
        ASSERT_EFI_ERROR (Status);

        //
        // Locate the Cpu Arch Protocol.
        //
        Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, &Cpu);
        ASSERT_EFI_ERROR (Status);

        Status = Cpu->RegisterInterruptHandler (Cpu, 0x41, MyInterruptHandler);
        ASSERT_EFI_ERROR (Status);
        
  return Status;
}

 

上述代码有两个需要特别注意的地方:
1. 之前的 Print9代码是在 UDK2014中编译通过的,但是在 UDK2017中无法编译通过,根本原因是 UDK2017中因为安全原因删除了 UnicodeValueToString 和AsciiValueToString两个函数,对我们来说,在代码中注视掉这两个函数不使用即可;
2. MyPrint 是我们输出函数,他会输出 Image->Var2 的值;
3. MyInterruptHandler 是我们的中断函数,里面只是简单的对 Image->Var2 加一。

第二个代码,在系统中查找我们自定义的 Print9Protocol,相对来说简单多了:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>

#include "Print9.h"

EFI_GUID gEfiPrint9ProtocolGuid =
                { 0xf05976ef, 0x83f1, 0x4f3d, 
                  { 0x86, 0x19, 0xf7, 0x59, 
                    0x5d, 0x41, 0xe5, 0x61 } };

extern EFI_BOOT_SERVICES         *gBS;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
        EFI_PRINT9_PROTOCOL     *Print9Protocol;
        EFI_STATUS              Status;

        // Search for the Print9 Protocol
        Status = gBS->LocateProtocol(
                        &gEfiPrint9ProtocolGuid,
                        NULL,
                        (VOID **)&Print9Protocol
                );
        if (EFI_ERROR(Status)) {
                Print(L"Can't find Print9Protocol.\n");
                return EFI_SUCCESS;
        }
        
        Print(L"Find Print9Protocol.\n"); 
        Print9Protocol->UnicodeSPrintAsciiFormat();
        Print(L"\n"); 
        return EFI_SUCCESS;
}

 

第三个代码,发出 Int 0x41 中断。起初我打算使用 int al 这样的指令,后来查了一下手册,原来 int 后面只能接立即数,于是直接写成 int 0x41 。因为,Vistual Studio 的 X64无法使用内嵌汇编,我们只好单独写一个 asm 出来。

intx1

IntX.c:

/** @file
  Simple interrupt test.

Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution.  The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php

THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

**/
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/UefiLib.h>

#include "IntX.h"

/**
  The user Entry Point for Application. The user code starts with this function
  as the real entry point for the application.

  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
  @param[in] SystemTable    A pointer to the EFI System Table.

  @retval EFI_SUCCESS       The entry point is executed successfully.
  @retval other             Some error occurs when executing this entry point.

**/
EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
        Print (L"Generate a Interrupt\n");
        
        SimpleInterrupt();
        
        return EFI_SUCCESS;
}

 

IntDemo.inf:

## @file
#   A simple, basic, application showing how the Hello application could be
#   built using the "Standard C Libraries" from StdLib.
#
#  Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
#  This program and the accompanying materials
#  are licensed and made available under the terms and conditions of the BSD License
#  which accompanies this distribution. The full text of the license may be found at
#  http://opensource.org/licenses/bsd-license.
#
#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
##

[Defines]
  INF_VERSION                    = 0x00010006
  BASE_NAME                      = IntDemo
  FILE_GUID                      = 4ea97c01-7491-4dfd-0090-747010f3ce5f
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 0.1
  ENTRY_POINT                    = UefiMain

#   
#  VALID_ARCHITECTURES           = X64
#

[Sources.common]
  IntX.c
  IntX.h

[Sources.IA32]

[Sources.X64]
  X64/AsmInt.asm

[Packages]
  MdePkg/MdePkg.dec
  ShellPkg/ShellPkg.dec 

[LibraryClasses]
  UefiApplicationEntryPoint
  UefiLib

 

用来定义 Int X 的源代码 \x64\AsmInt.asm

;------------------------------------------------------------------------------
;
; Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
; This program and the accompanying materials
; are licensed and made available under the terms and conditions of the BSD License
; which accompanies this distribution.  The full text of the license may be found at
; http://opensource.org/licenses/bsd-license.php.
;
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
;
; Module Name:
;
;   AsmRdRand.Asm
;
; Abstract:
;
;   Generate an Interrupt by INT x
;
; Notes:
;
;   Visual Studio coding practices do not use inline asm since multiple compilers and 
;   architectures are supported assembler not recognizing rdrand instruction so using DB's.
;
;------------------------------------------------------------------------------

    .code
 
;------------------------------------------------------------------------------
;  Generates a interrupt by Int(CD).
;------------------------------------------------------------------------------
SimpleInterrupt  PROC
    int         0x41
    ret
SimpleInterrupt ENDP

    END

 

最终运行结果,可以看到每次运行 IntDemo之后,会有中断触发,数值不断变大。
intx2
完整的代码和编译后的 efi 文件下载(我只在X64 上测试过,NT32模拟环境不支持)
IntTest

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注