Step to UEFI (133)再试验 EFI_CPU_ARCH_PROTOCOL

前面提到了 EFI_CPU_ARCH_PROTOCOL ,这次试试这个Protocol的 EnableInterrput 和 DisableInterrupt。

ma1

实验的方法是使用 CpuSleep() 这个函数,在 \UDK2017\MdePkg\Library\BaseCpuLib\X64\CpuSleep.asm 中可以看到具体实现:

    .code
;------------------------------------------------------------------------------
; VOID
; EFIAPI
; CpuSleep (
;   VOID
;   );
;------------------------------------------------------------------------------
CpuSleep    PROC
    hlt
    ret
CpuSleep    ENDP

END

 

就是说他调用了 hlt 这个指令,这个指令的介绍如下,执行这个指令后 CPU 会停机,只有中断才能唤醒CPU。我们在这个函数之后再编写输出字符串的代码,如果能看到就说明CPU被中断唤醒了(更简单的判断:没唤醒就会死机)。
cpp2

最终的代码如下:

/** @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.
**/
#include <Library/BaseLib.h>
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/PrintLib.h>
#include <Library/ShellCEntryLib.h>

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

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

/***
  Demonstrates basic workings of the main() function by displaying a
  welcoming message.

  Note that the UEFI command line is composed of 16-bit UCS2 wide characters.
  The easiest way to access the command line parameters is to cast Argv as:
      wchar_t **wArgv = (wchar_t **)Argv;

  @param[in]  Argc    Number of argument tokens pointed to by Argv.
  @param[in]  Argv    Array of Argc pointers to command line tokens.

  @retval  0         The application exited normally.
  @retval  Other     An error occurred.
***/
int
main (
  IN int Argc,
  IN char **Argv
  )
{
  EFI_CPU_ARCH_PROTOCOL  *Cpu;
  EFI_STATUS             Status;
  
  //
  // Locate the Cpu Arch Protocol.
  //
  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, &Cpu);
  if (EFI_ERROR (Status)) {
    Print(L"Can't find EFI_CPU_ARCH_PROTOCOL\n");
    return Status;
  }

  Print(L"Running CpuSleep\n");
  CpuSleep();
  Print(L"CpuSleep Exit\n");

  Print(L"Disable CPU interrupt by EFI_CPU_ARCH_PROTOCOL\n");  
  Cpu->DisableInterrupt(Cpu);
  Print(L"Running CpuSleep\n");
  CpuSleep();
  Print(L"CpuSleep Exit\n");
  
  Print(L"Disable CPU interrupt by CLI\n");  
  Print(L"Running CpuSleep\n");  
  DisableInterrupts();
  CpuSleep();  
  EnableInterrupts();  
  Print(L"CpuSleep Exit\n");
  
  return 0;
}

 

运行结果如下(这是在实体机运行的结果):
cpp3
代码中调用了 CpuSleep 函数三次,第一次应该是被UEFI 中的Timer唤醒了,所以运行一下就出来了;第二次调用 CpuSleep函数之前,先用EFI_CPU_ARCH_PROTOCOL 的 DisableInterrupt,但是并没有作用;第三次,我们用CLI 指令关闭所有的中断,于是,程序停下来了,也死机了。

完整的代码下载:

CPUArchTest2

结论: 保险起见,如果你想 Disable Interrupt,那么请使用 cli 这样的指令。后面有空再探究一下为什么这两个函数没有效果。

发表评论

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