前面提到了 EFI_CPU_ARCH_PROTOCOL ,这次试试这个Protocol的 EnableInterrput 和 DisableInterrupt。
实验的方法是使用 CpuSleep() 这个函数,在 \UDK2017\MdePkg\Library\BaseCpuLib\X64\CpuSleep.asm 中可以看到具体实现:
.code ;------------------------------------------------------------------------------ ; VOID ; EFIAPI ; CpuSleep ( ; VOID ; ); ;------------------------------------------------------------------------------ CpuSleep PROC hlt ret CpuSleep ENDP END
就是说他调用了 hlt 这个指令,这个指令的介绍如下,执行这个指令后 CPU 会停机,只有中断才能唤醒CPU。我们在这个函数之后再编写输出字符串的代码,如果能看到就说明CPU被中断唤醒了(更简单的判断:没唤醒就会死机)。
最终的代码如下:
/** @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; }
运行结果如下(这是在实体机运行的结果):
代码中调用了 CpuSleep 函数三次,第一次应该是被UEFI 中的Timer唤醒了,所以运行一下就出来了;第二次调用 CpuSleep函数之前,先用EFI_CPU_ARCH_PROTOCOL 的 DisableInterrupt,但是并没有作用;第三次,我们用CLI 指令关闭所有的中断,于是,程序停下来了,也死机了。
完整的代码下载:
结论: 保险起见,如果你想 Disable Interrupt,那么请使用 cli 这样的指令。后面有空再探究一下为什么这两个函数没有效果。