UEFI 下 RU.EFI 工具介绍

Ru 是AMI 的 James Wang(个人主页http://ruexe.blogspot.tw/)推出的系列工具,其中包括IA32 X64版本的Ru.EFI和一个 Windows 版本的 RU.EXE。最新版本可以在https://github.com/JamesAmiTw/ru-uefi 下载到。

本文简单介绍它的功能和使用。

UEFI X64 版本初始界面如下:

  1. File 菜单,提供了 Load
    Save 和 Compare 功能,可以保存和读取当前页面的数据,一般情况下不会使用,主要原因是操作没有 Windows 下方便。

2.Config 菜单用来进行寄存器的访问。

2.1 PCI 可以访问 PCI 设备

选中后输入要查看设备的 Bus Dev Func:

2.2 ISA

ISA IO是 Index/Data 这种形式的访问IO Port:

2.3 ISA IO

选择之后会出现2个选项让你选择:

例如,下面是查看 CMOS 的结果。个人感觉这个和上面的 ISA 选项通过手动输入端口号没有差别。

2.4 IO Space

选择后出现额外菜单如下:

选择 Normal IO Space 后会要求输入要查看的端口。

2.5 IDE Identify。这个功能能够查看当前系统中的SATA接口的硬盘信息(PCIE接口的SSD不行)。

选中后会出现提示继续选择要查看的硬盘。

之后可以查看硬盘信息。

额外说一句:不知道什么原因,这个功能和截图软件(CrScreenshotDxe)有冲突,运行这个功能后,会导致死机。本篇的截图都是使用 HDMI 转 USB 设备完成的。

2.6 ACPI

选中后可以看到系统中的 ACPI Table

能够查看每一项Table

2.7 Memory (Flat)

选择这个项目后输入要查看的内存位置即可:

特别注意,目前只支持查看最高 4G的内存。

2.8 CPU MSR

这个功能只能查看固定几个 MSR 的值。并且在我试验的机台上有问题无法正常看到。如果确实有这方面的需求,建议使用 Rw Everything 这样工具。

2.9 SMBIOS

查看本机的SMBIOS:

2.10 SMBus

选择这个功能后,会要求选择你的PCH。

接下来要选择你要查看的设备。

我的测试机台没有SPD,因此没有进一步试验。

2.11 ATi PCI Space

因为目前没有 ATI 主板所以没有进行试验。

2.12 UEFI variable

这个功能可以用来查看 UEFI 的变量,感觉上似乎不太准,推荐用 Shell 下的命令直接进行查看。

2.13 AHCI MMIO

这个功能在我的Kabylake-U 上无法工作,死机。

2.14 USB MMIO

这个功能这个功能在我的Kabylake-U 上无法工作,调不出来。

3.Go 菜单。

3.1 Next 切换

查看下一个项目,比如:当前显示的是 PCI Bus0 Dev0 FunC 0,那么下一个设备是 Bus:0 Dev 0 Func 2。

3.2 Previous 切换

查看上一个项目。

3.3 Clear all history

不知道什么意思

3.4 Mem/IO space

不知道什么意思。

4. Tools 菜单

 4.1 List PCI devices

这个选项能够列出当前系统中的全部 PCI 设备,快捷键是 F6。

4.2 Toggle 8/16/32 bit

使得当前界面在 1Byte 2Bytes 4bytes 显示之间切换,快捷键是 F7 。在查看寄存器时是很有用的功能。

4.2 Toggle ASCII/Info

切换界面在 ASCII显示和信息显示模式切换,快捷键为 F4。例如:当前是ASCII显示模式

切换为信息显示模式:

4.3 System Info

  显示当前系统基本信息

4.4 Help

显示帮助信息

5.System Group

5.1 Change Color

               切换界面配色

           通常看到的是 Normal 模式,User Defined 是黑白的

  5.2 Toggle Sound

   我的主板上没有 Beeper 所以不得而知是否有效果

5.3Reboot INT19

通过 INT19 启动下一个设备,对于 UEFI 是无效的

5.4 Turn Off system

关机,在 UEFI 下是无效的

6.Quit  退出 RU

从上面也可以看到,对于 X86 来说,访问硬件信息需要的基本操作有:

1. PCI 信息的访问

2. 访问IO Port 直接访问

3. IO Port Index/Data 方式的访问

4. Memory 的访问

5. Memory Index/Data 方式的访问

6. MSR 的访问

掌握了上述的访问方法就可以触碰到 X86 上的全部空间和寄存器了。

=============================================================

2025年2月27日

Teensy 打造热成像仪

当我还是一个孩子的时候,荧幕上充斥的还是史泰龙施瓦辛格这样的硬汉,他们用肌肉而不是今天这样的小鲜肉那样用兰花指打败敌人,看起来非常过瘾。一次偶然的机会,在父亲的朋友家看了电视台播出的《铁血战士》。这部影片给我留下很深的印象,神秘的丛林,还有影片中拥有着高科技武器的外星人。譬如说,大反派的铁血战士有一个很酷的带在手腕上能显示当前心率的个人电脑。还有就是他可以切换到红外线模式,看到人类无法看到的红外线。这样的功能在夜战中尽占便宜。最后施瓦辛格州长大人凭借主角光环发现了对手这一特性,用泥巴将自己包裹起来阻挡身体上的红外线躲过搜查实现反杀。

最近发现市面上有一种红外阵列传感器:MLX90640 ,分辨率可以达到 32*24。忽发奇想尝试用它DIY一个简易的热成像仪。MLX90640对内存要求比较高,普通的 Arduino 无法胜任。最终选用  Teensy 3.2 作为主控,主要原因是它性能远超 Arduino ,主频可以达到 120Mhz (Overclock状态)。为了实现在液晶屏上面的显示,需要主控能够快速的将数据发送到屏幕上,否则刷新速度慢非常影响效果。此外,Teensy 3.2内存有 64KB,取得数据和处理数据需要在足够的内存中进行,因此大内存必不可少。之后,从淘宝入手了 320*240 分辨率的SPI 接口的液晶屏作为显示界面。硬件方案确定之后即可着手进行代码编写。

从整体上来说,代码操作需要三部分:第一步,获得传感器数据;第二步,处理数据(因为屏幕明显比传感器大,因此,需要将少量数据变换成大量数据,这里使用的是双线性插值算法);第三步,将数据显示在屏幕上。下面就是详细步骤:

第一步:传感器数据的获得。MLX90640 有对应的 Arduino 库,这使得用户能够方便的获得红外数据。特别需要注意的取得的数据是从右上到左下排列的。

这部分代码很简单,配合调用库函数即可:

  for (byte x = 0 ; x < 2 ; x++){
    uint16_t mlx90640Frame[834];
    int status = MLX90640_GetFrameData(MLX90640_address, mlx90640Frame);

    float vdd = MLX90640_GetVdd(mlx90640Frame, &mlx90640);
    float Ta = MLX90640_GetTa(mlx90640Frame, &mlx90640);

    float tr = Ta - TA_SHIFT; //Reflected temperature based on the sensor ambient temperature
    float emissivity = 0.95;

    MLX90640_CalculateTo(mlx90640Frame, &mlx90640, emissivity, tr, mlx90640To);
  }

第二步,处理数据。传感器获得的实际数据是32X24,最终需要呈现在 320X240的LCD上。可以看到两者之间分辨率差别很大。这里就需要通过一些算法推理补充出更多的数据以便更好的观感。通俗的解释这个过程和“脑补”类似。例如,即便下面的图片上非常模糊,但是观看者还是会认出来这是著名的《蒙娜丽莎》。当人们看到画面之后,大脑会进行处理,处理的结果就是识别出来这幅名画。

这里选择双线性插值算法来完成这个目的。这种算法是假设中间的点收到周围的点均匀的影响。用一维的例子来说明这个算法,比如,已知下面 A 点的值为 100,B点的值为200,那么如果中间有一个C点,算法推理出来 C 点的值应该是 150。

有了上面的经验,推广到二维世界,下面图片中,已知Q(X,Y) 四个点的取值,想推算出 P 的取值。可以先推算出R1 R2的取值

最终再计算出 P 的取值【参考】

代码中使用同样的方法,将4个点插值为100个点,这样整体从 32×24=768个点变换为76800个点。这样的计算量对于 Teensy 来说并不是问题,可以在1ms 内处理完毕。

第三步,数据的现实。代码使用Arduino 的 UcgLib来驱动屏幕。UcgLib 没有提供按照帧发送数据的函数(当然如果有的话,因为数据量太大,也不可能在内存中存放一帧然后完整发送之)。所以使用 DrawPixel 这样的函数一个点一个点的在屏幕上绘制。这样就会牵扯到效率的问题需要进行优化。对此,使用了两个方法:

1.绝对的提升 SPI 传输速度。Teensy 默认频率为 72Mh,超频到 120Mhz 之后,SPI 可以提升到 30Mhz,代码中通过下面这个语句来实现:

  SPI.beginTransaction(SPISettings(30000000, MSBFIRST, SPI_MODE0));

2.相对的减少绘制数据量。通过查看UcgLib 的代码可以看到,绘制每一个点时,都会发送位置信息这对于用户来说是不必要的开销。所谓显示,就是将必要的数据送到LCD显示内存中。因此,代码设计了混合的方式。先用 DrawPixel 绘制Y坐标上的第一个点,之后直接发送这一行上其余各点的颜色信息。从实验数据来看,这样可以节省3/5的时间。此外,默认情况下库使用 18Bits 显示模式,每个点由三个Bytes来给出。此外还可以将屏幕设置为 16Bits显示模式,这样每个点可以由2个Bytes给出。但是相应的屏幕颜色数量会大大减少,经过试验显示效果不佳就放弃了。如果用户对速度有更高的要求,可以考虑使用这种模式。

最终成品如下,用亚克力制作了一个简单的外壳,下面是一个把柄,同时可以放置一个充电宝来为整体进行供电。顺便说一句,我原本的设计是要完全包裹起来的,后来计算失误导致尺寸上的差异才变成现象这个样子的…….

工作的视频可以在知乎专栏看到

https://zhuanlan.zhihu.com/p/76527719

最后,关于视力,讲个有意思的事情“当年,在日本海军部队,有这么一个特殊的群体:每天吃鳗鱼喝鱼肝油,服用特制的维生素A,目的是为了保持一双眼睛炯炯有神。他们是军舰上的瞭望员,夜战之前,他们像猴子一样爬得高高的,用一双肉眼在茫茫大海上搜索敌方舰只的踪影。

  据笔者考证,这个兵种仅仅存在于当年的日本海军。美国海军名将尼米茨特地为他的奇葩对手冠名为“猫眼”(CAT EYES LOOKOUT),因为猫的夜视能力极强嘛,可以异乎寻常地采集摄取到有效的光线,研究发现,猫的瞳孔在昏暗中可扩大至眼球表面的90%,一点微弱的光亮就足够它们觅取猎物。日本海军的瞭望员也练就了“猫眼神功”,在一片漆黑中,有效搜索远方的猎物。

  二战期间,日本政府征召一批作家从军组成“笔部队”,撰写战地报告文学或战地通信稿。“珍珠港事件”后,小说家丹羽文雄随日本海军参加了太平洋战争,他撰写过一篇在当时非常著名的报告文学《海战》,其中就描写了“猫眼神功”:“周围伸手不见五指,就只有手持望远镜的瞭望员的呼喊”左41度,发现一艘舰影”,”左30度,敌舰,敌舰向我而来”……”

  在丹羽文雄的笔下,充满了对这些征战太平洋的“勇士”们的崇敬,更是对猫眼瞭望员钦佩有加。“猫眼神功”有多厉害?据当时记载,他们在黑夜里能够看清万米前后的军舰,然后日军在8千米内以探照灯和水上飞机扔照明弹实施攻击。

不得不承认,日本民族的一大特点是能把事情做到极限,在舰队夜战这一块,日本人曾吹嘘“大日本帝国海军夜战技术誉满全球”,他们倒也有一些吹牛的本钱,日本海军以训练刻苦甚至残酷著称,兵员素质确实相当不错,且不论海军的炮术和操船技术,还是以“猫眼神功”为例,日本人练就了“斜眼”——人类的眼球上,夜间感光细胞的分布在眼球侧面的比眼球正面的多,所以,斜眼能在晚上看得更加清楚。”

起初,猫眼比雷达更厉害:

“美日瓜岛战役历时半年,共爆发数十次海战,争夺瓜岛的第一次海战爆发于1942年8月9日凌晨,夜战,一时许,日舰驶抵战场时,日军猫眼瞭望员确实厉害,先发现了两艘巡逻的美军驱逐舰,而装备新型雷达的美军驱逐舰却未能发现日舰。一直到日舰下达总攻击令十分钟后,美军才反应过来。当时日军实施了轻车熟路的夜战模式:日军的水上飞机投下了照明弹,将美舰照得清清楚楚,日军的炮弹和鱼雷接踵而来。

在瓜岛,这样的海战持续发生,总体而言,猫眼表现得不比雷达差。在1942年11月14日深夜发生的第二次瓜达尔卡纳尔海战中,美军于22点55分以雷达发现了日军舰队,5分钟后,猫眼瞭望员也发现美军舰队,又是一场在漆黑大海上的恶战。此战中,威利斯·李指挥的美军主力战斗舰南达科他号还发生了电力故障,无法使用雷达与火炮控制,自动装弹装置也失效,结果成了活靶子。

  后人分析说,瓜岛战役日军猫眼没怎么输给雷达,原因还是地理环境,当时美军所装备的雷达,虽然在洋面上搜索距离可以达到20海里,但是在瓜岛附近由于受陆地上山包的干扰,搜索距离一下子就降到了6000米。还有一个不可忽略的因素,是当时雷达的技术与雷达操纵者的水平——后者当然无法跟苦练猫眼技术的日本海军瞭望员相比。

  但是,“猫眼神功”再厉害,对于日本海军来说,也是个“然并卵”的结果。在日美双方历时半年多对瓜岛的残酷争夺中,均损失惨重,最终日本因无力进行消耗作战,而选择撤军。美军完全占据瓜岛,而后是整个南太平洋的制海权,因此开始战略反攻。在二战中,瓜岛之战是中途岛之后日本的再次失败,也是日本从战略优势走向劣势的转折点。

  此后日本海军仍然依靠“猫眼神功”与雷达对抗,但是已江河日下,屡战屡败。说来也是,人总有用眼过度的时候,训练有素的猫眼瞭望员也是死一个少一个,但雷达技术却在不断进步之中。”【参考】

所以,从我个人角度来说,更相信武器和物资是决定战争成败的主要因素…….

参考:

1. https://baike.baidu.com/item/%E5%8F%8C%E7%BA%BF%E6%80%A7%E6%8F%92%E5%80%BC  双线性插值

1. http://roll.sohu.com/20150918/n421429328.shtml 日本二战“猫眼神功”PK雷达之鉴(图)

Step to UEFI (202)IoRead 研究

IO Port 的访问是对硬件的最基本操作,在 UEFI Shell 下我们通过 IoLib 中的IoRead8 IoRead16 IoRead32 这样的来进行读取。本文介绍Shell 下的 IoRead8 的具体实现。

首先编写一个代码用于测试:

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

extern  EFI_SYSTEM_TABLE    *gST;
extern  EFI_BOOT_SERVICES   *gBS;

/***
  Print a welcoming message.

  Establishes the main structure of the application.

  @retval  0         The application exited normally.
  @retval  Other     An error occurred.
***/
INTN
EFIAPI
ShellAppMain (
  IN UINTN Argc,
  IN CHAR16 **Argv
  )
{
        Print(L"Read 80Port=%x\n",IoRead8(0x80));

    return(0);
}

编译之后,在 \Build\AppPkg\DEBUG_VS2015x86\X64\AppPkg\Applications\IOStudy\IOStudy\Makefile 可以看到使用了下面的 Library:

$(BIN_DIR)\MdePkg\Library\BaseIoLibIntrinsic\BaseIoLibIntrinsic\OUTPUT\BaseIoLibIntrinsic.lib

进一步研究,在 \MdePkg\Library\BaseIoLibIntrinsic\IoLibMsc.c 可以看到如下的实现:

/**
  Reads an 8-bit I/O port.

  Reads the 8-bit I/O port specified by Port. The 8-bit read value is returned.
  This function must guarantee that all I/O read and write operations are
  serialized.

  If 8-bit I/O port operations are not supported, then ASSERT().

  @param  Port  The I/O port to read.

  @return The value read.

**/
UINT8
EFIAPI
IoRead8 (
  IN      UINTN                     Port
  )
{
  UINT8                             Value;

  _ReadWriteBarrier ();
  Value = (UINT8)_inp ((UINT16)Port);
  _ReadWriteBarrier ();
  return Value;
}

为了证明这里就是我们要找到的具体实现,可以在  \MdePkg\Library\BaseIoLibIntrinsic\BaseIoLibIntrinsic.inf 加入如下代码:

 [BuildOptions]
  MSFT:*_*_X64_CC_FLAGS  = /FAsc /Od

重新编译(同时还需要删除 \Build\AppPkg\DEBUG_VS2015x86\X64\MdePkg\Library 中的BaseIoLibIntrinsic),之后可以在\Build\AppPkg\DEBUG_VS2015x86\X64\AppPkg\Applications\IOStudy\IOStudy 看到多出来一个IoLibMsc.cod 文件。

IoRead8	PROC						; COMDAT

; 73   : {

$LN3:
  00000	48 89 4c 24 08	 mov	 QWORD PTR [rsp+8], rcx
  00005	48 83 ec 18	 sub	 rsp, 24

; 74   :   UINT8                             Value;
; 75   : 
; 76   :   _ReadWriteBarrier ();
; 77   :   Value = (UINT8)_inp ((UINT16)Port);

  00009	0f b7 54 24 20	 movzx	 edx, WORD PTR Port$[rsp]
  0000e	ec		 in	 al, dx
  0000f	88 04 24	 mov	 BYTE PTR Value$[rsp], al

; 78   :   _ReadWriteBarrier ();
; 79   :   return Value;

  00012	8a 04 24	 mov	 al, BYTE PTR Value$[rsp]

; 80   : }

  00015	48 83 c4 18	 add	 rsp, 24
  00019	c3		 ret	 0
IoRead8	ENDP

在这里可以证明确实是IoLibMsc.c 中实现的。

_inp() 的作用是“从某个端口输入一个字节 (_inp)、一个字 (_inpw) 或一个双字 (_inpd)。” 但是看起来目前已经过时【参考1】。

与这个函数类似,还可以使用__inword 来实现读取某一个 Port,__outword直接写入某一个Port【参考2】。

参考:

  1. https://docs.microsoft.com/zh-cn/cpp/c-runtime-library/inp-inpw-inpd?view=vs-2019这些函数已过时。 从 Visual Studio 2015 开始,CRT 中不再提供这些函数。
  2. https://docs.microsoft.com/zh-cn/cpp/intrinsics/inword?view=vs-2017

=============================================================

2024年2月22日 IoLib 提供了如下的函数:

#define IO_LIB_ADDRESS(Segment, Port) \
  ( ((Port) & 0xffff) | (((Segment) & 0xffff) << 16) )

UINT8
EFIAPI
IoRead8 (
  IN      UINTN  Port
  );

UINT8
EFIAPI
IoWrite8 (
  IN      UINTN  Port,
  IN      UINT8  Value
  );

VOID
EFIAPI
IoReadFifo8 (
  IN      UINTN  Port,
  IN      UINTN  Count,
  OUT     VOID   *Buffer
  );

VOID
EFIAPI
IoWriteFifo8 (
  IN      UINTN  Port,
  IN      UINTN  Count,
  IN      VOID   *Buffer
  );

UINT8
EFIAPI
IoOr8 (
  IN      UINTN  Port,
  IN      UINT8  OrData
  );

UINT8
EFIAPI
IoAnd8 (
  IN      UINTN  Port,
  IN      UINT8  AndData
  );

UINT8
EFIAPI
IoAndThenOr8 (
  IN      UINTN  Port,
  IN      UINT8  AndData,
  IN      UINT8  OrData
  );

UINT8
EFIAPI
IoBitFieldRead8 (
  IN      UINTN  Port,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit
  );

UINT8
EFIAPI
IoBitFieldWrite8 (
  IN      UINTN  Port,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit,
  IN      UINT8  Value
  );

UINT8
EFIAPI
IoBitFieldOr8 (
  IN      UINTN  Port,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit,
  IN      UINT8  OrData
  );

UINT8
EFIAPI
IoBitFieldAnd8 (
  IN      UINTN  Port,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit,
  IN      UINT8  AndData
  );

UINT8
EFIAPI
IoBitFieldAndThenOr8 (
  IN      UINTN  Port,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit,
  IN      UINT8  AndData,
  IN      UINT8  OrData
  );

UINT16
EFIAPI
IoRead16 (
  IN      UINTN  Port
  );

UINT16
EFIAPI
IoWrite16 (
  IN      UINTN   Port,
  IN      UINT16  Value
  );

VOID
EFIAPI
IoReadFifo16 (
  IN      UINTN  Port,
  IN      UINTN  Count,
  OUT     VOID   *Buffer
  );

VOID
EFIAPI
IoWriteFifo16 (
  IN      UINTN  Port,
  IN      UINTN  Count,
  IN      VOID   *Buffer
  );

UINT16
EFIAPI
IoOr16 (
  IN      UINTN   Port,
  IN      UINT16  OrData
  );

UINT16
EFIAPI
IoAnd16 (
  IN      UINTN   Port,
  IN      UINT16  AndData
  );

UINT16
EFIAPI
IoAndThenOr16 (
  IN      UINTN   Port,
  IN      UINT16  AndData,
  IN      UINT16  OrData
  );

UINT16
EFIAPI
IoBitFieldRead16 (
  IN      UINTN  Port,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit
  );

UINT16
EFIAPI
IoBitFieldWrite16 (
  IN      UINTN   Port,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT16  Value
  );

UINT16
EFIAPI
IoBitFieldOr16 (
  IN      UINTN   Port,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT16  OrData
  );

UINT16
EFIAPI
IoBitFieldAnd16 (
  IN      UINTN   Port,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT16  AndData
  );

UINT16
EFIAPI
IoBitFieldAndThenOr16 (
  IN      UINTN   Port,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT16  AndData,
  IN      UINT16  OrData
  );

UINT32
EFIAPI
IoRead32 (
  IN      UINTN  Port
  );

UINT32
EFIAPI
IoWrite32 (
  IN      UINTN   Port,
  IN      UINT32  Value
  );

VOID
EFIAPI
IoReadFifo32 (
  IN      UINTN  Port,
  IN      UINTN  Count,
  OUT     VOID   *Buffer
  );

VOID
EFIAPI
IoWriteFifo32 (
  IN      UINTN  Port,
  IN      UINTN  Count,
  IN      VOID   *Buffer
  );

UINT32
EFIAPI
IoOr32 (
  IN      UINTN   Port,
  IN      UINT32  OrData
  );

UINT32
EFIAPI
IoAnd32 (
  IN      UINTN   Port,
  IN      UINT32  AndData
  );

UINT32
EFIAPI
IoAndThenOr32 (
  IN      UINTN   Port,
  IN      UINT32  AndData,
  IN      UINT32  OrData
  );

UINT32
EFIAPI
IoBitFieldRead32 (
  IN      UINTN  Port,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit
  );

UINT32
EFIAPI
IoBitFieldWrite32 (
  IN      UINTN   Port,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT32  Value
  );

UINT32
EFIAPI
IoBitFieldOr32 (
  IN      UINTN   Port,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT32  OrData
  );

UINT32
EFIAPI
IoBitFieldAnd32 (
  IN      UINTN   Port,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT32  AndData
  );

UINT32
EFIAPI
IoBitFieldAndThenOr32 (
  IN      UINTN   Port,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT32  AndData,
  IN      UINT32  OrData
  );

UINT64
EFIAPI
IoRead64 (
  IN      UINTN  Port
  );

UINT64
EFIAPI
IoWrite64 (
  IN      UINTN   Port,
  IN      UINT64  Value
  );

UINT64
EFIAPI
IoOr64 (
  IN      UINTN   Port,
  IN      UINT64  OrData
  );

UINT64
EFIAPI
IoAnd64 (
  IN      UINTN   Port,
  IN      UINT64  AndData
  );

UINT64
EFIAPI
IoAndThenOr64 (
  IN      UINTN   Port,
  IN      UINT64  AndData,
  IN      UINT64  OrData
  );

UINT64
EFIAPI
IoBitFieldRead64 (
  IN      UINTN  Port,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit
  );

UINT64
EFIAPI
IoBitFieldWrite64 (
  IN      UINTN   Port,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT64  Value
  );

UINT64
EFIAPI
IoBitFieldOr64 (
  IN      UINTN   Port,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT64  OrData
  );

UINT64
EFIAPI
IoBitFieldAnd64 (
  IN      UINTN   Port,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT64  AndData
  );

UINT64
EFIAPI
IoBitFieldAndThenOr64 (
  IN      UINTN   Port,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT64  AndData,
  IN      UINT64  OrData
  );

UINT8
EFIAPI
MmioRead8 (
  IN      UINTN  Address
  );

UINT8
EFIAPI
MmioWrite8 (
  IN      UINTN  Address,
  IN      UINT8  Value
  );

UINT8
EFIAPI
MmioOr8 (
  IN      UINTN  Address,
  IN      UINT8  OrData
  );

UINT8
EFIAPI
MmioAnd8 (
  IN      UINTN  Address,
  IN      UINT8  AndData
  );

UINT8
EFIAPI
MmioAndThenOr8 (
  IN      UINTN  Address,
  IN      UINT8  AndData,
  IN      UINT8  OrData
  );

UINT8
EFIAPI
MmioBitFieldRead8 (
  IN      UINTN  Address,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit
  );

UINT8
EFIAPI
MmioBitFieldWrite8 (
  IN      UINTN  Address,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit,
  IN      UINT8  Value
  );

UINT8
EFIAPI
MmioBitFieldOr8 (
  IN      UINTN  Address,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit,
  IN      UINT8  OrData
  );

UINT8
EFIAPI
MmioBitFieldAnd8 (
  IN      UINTN  Address,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit,
  IN      UINT8  AndData
  );

UINT8
EFIAPI
MmioBitFieldAndThenOr8 (
  IN      UINTN  Address,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit,
  IN      UINT8  AndData,
  IN      UINT8  OrData
  );

UINT16
EFIAPI
MmioRead16 (
  IN      UINTN  Address
  );

UINT16
EFIAPI
MmioWrite16 (
  IN      UINTN   Address,
  IN      UINT16  Value
  );

UINT16
EFIAPI
MmioOr16 (
  IN      UINTN   Address,
  IN      UINT16  OrData
  );

UINT16
EFIAPI
MmioAnd16 (
  IN      UINTN   Address,
  IN      UINT16  AndData
  );

UINT16
EFIAPI
MmioAndThenOr16 (
  IN      UINTN   Address,
  IN      UINT16  AndData,
  IN      UINT16  OrData
  );

UINT16
EFIAPI
MmioBitFieldRead16 (
  IN      UINTN  Address,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit
  );

UINT16
EFIAPI
MmioBitFieldWrite16 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT16  Value
  );

UINT16
EFIAPI
MmioBitFieldOr16 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT16  OrData
  );

UINT16
EFIAPI
MmioBitFieldAnd16 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT16  AndData
  );

UINT16
EFIAPI
MmioBitFieldAndThenOr16 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT16  AndData,
  IN      UINT16  OrData
  );

UINT32
EFIAPI
MmioRead32 (
  IN      UINTN  Address
  );

UINT32
EFIAPI
MmioWrite32 (
  IN      UINTN   Address,
  IN      UINT32  Value
  );

UINT32
EFIAPI
MmioOr32 (
  IN      UINTN   Address,
  IN      UINT32  OrData
  );

UINT32
EFIAPI
MmioAnd32 (
  IN      UINTN   Address,
  IN      UINT32  AndData
  );

UINT32
EFIAPI
MmioAndThenOr32 (
  IN      UINTN   Address,
  IN      UINT32  AndData,
  IN      UINT32  OrData
  );

UINT32
EFIAPI
MmioBitFieldRead32 (
  IN      UINTN  Address,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit
  );

UINT32
EFIAPI
MmioBitFieldWrite32 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT32  Value
  );

UINT32
EFIAPI
MmioBitFieldOr32 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT32  OrData
  );

UINT32
EFIAPI
MmioBitFieldAnd32 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT32  AndData
  );

UINT32
EFIAPI
MmioBitFieldAndThenOr32 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT32  AndData,
  IN      UINT32  OrData
  );

UINT64
EFIAPI
MmioRead64 (
  IN      UINTN  Address
  );

UINT64
EFIAPI
MmioWrite64 (
  IN      UINTN   Address,
  IN      UINT64  Value
  );

UINT64
EFIAPI
MmioOr64 (
  IN      UINTN   Address,
  IN      UINT64  OrData
  );

UINT64
EFIAPI
MmioAnd64 (
  IN      UINTN   Address,
  IN      UINT64  AndData
  );

UINT64
EFIAPI
MmioAndThenOr64 (
  IN      UINTN   Address,
  IN      UINT64  AndData,
  IN      UINT64  OrData
  );

UINT64
EFIAPI
MmioBitFieldRead64 (
  IN      UINTN  Address,
  IN      UINTN  StartBit,
  IN      UINTN  EndBit
  );

UINT64
EFIAPI
MmioBitFieldWrite64 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT64  Value
  );

UINT64
EFIAPI
MmioBitFieldOr64 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT64  OrData
  );

UINT64
EFIAPI
MmioBitFieldAnd64 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT64  AndData
  );

UINT64
EFIAPI
MmioBitFieldAndThenOr64 (
  IN      UINTN   Address,
  IN      UINTN   StartBit,
  IN      UINTN   EndBit,
  IN      UINT64  AndData,
  IN      UINT64  OrData
  );

UINT8 *
EFIAPI
MmioReadBuffer8 (
  IN  UINTN  StartAddress,
  IN  UINTN  Length,
  OUT UINT8  *Buffer
  );

UINT16 *
EFIAPI
MmioReadBuffer16 (
  IN  UINTN   StartAddress,
  IN  UINTN   Length,
  OUT UINT16  *Buffer
  );

UINT32 *
EFIAPI
MmioReadBuffer32 (
  IN  UINTN   StartAddress,
  IN  UINTN   Length,
  OUT UINT32  *Buffer
  );

UINT64 *
EFIAPI
MmioReadBuffer64 (
  IN  UINTN   StartAddress,
  IN  UINTN   Length,
  OUT UINT64  *Buffer
  );

UINT8 *
EFIAPI
MmioWriteBuffer8 (
  IN  UINTN        StartAddress,
  IN  UINTN        Length,
  IN  CONST UINT8  *Buffer
  );

UINT16 *
EFIAPI
MmioWriteBuffer16 (
  IN  UINTN         StartAddress,
  IN  UINTN         Length,
  IN  CONST UINT16  *Buffer
  );

UINT32 *
EFIAPI
MmioWriteBuffer32 (
  IN  UINTN         StartAddress,
  IN  UINTN         Length,
  IN  CONST UINT32  *Buffer
  );

UINT64 *
EFIAPI
MmioWriteBuffer64 (
  IN  UINTN         StartAddress,
  IN  UINTN         Length,
  IN  CONST UINT64  *Buffer
  );

Step to UEFI (201)直接取得函数返回地址

在64位模式下,Microsoft Visual Studio 不支持内嵌汇编。但是编译器本身支持一些intrinsic 预定义的指令,这次就研究一下_AddressOfReturnAddress。他的作用是“提供保存当前函数的返回地址的内存位置的地址。 此地址不能用于访问其他内存位置 (例如, 函数的参数)。”【参考1】

编写一个简单的Application 验证之:

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

/**
  Microsoft Visual Studio 7.1 Function Prototypes for I/O Intrinsics.
**/

void* _AddressOfReturnAddress (VOID);

#pragma intrinsic(_AddressOfReturnAddress)

void func() {
   void* pvAddressOfReturnAddress = _AddressOfReturnAddress();
   Print(L"%lx\n", pvAddressOfReturnAddress);
   Print(L"%lx\n", *((void**) pvAddressOfReturnAddress));
   Print(L"%lx\n", _ReturnAddress());
}

/***
  Print a welcoming message.

  Establishes the main structure of the application.

  @retval  0         The application exited normally.
  @retval  Other     An error occurred.
***/
INTN
EFIAPI
ShellAppMain (
  IN UINTN Argc,
  IN CHAR16 **Argv
  )
{
        CpuBreakpoint();
        func();
        return(0);
}

运行结果如下(NT32环境)

为了便于观察我们在代码中使用 CPU BreakPoint 触发中断用 VS2015进行调试:1.触发中断

2. 从Break 中返回,call 到void func()

可以看到,当前处于call func() 的指令下,他的下一条地址是 0x1BE56C75638。和运行的结果显示一样,因此就是说可以用_AddressOfReturnAddress得到当前的函数返回的地址(就是调用语句的下一条指令)。

查看对应的汇编语句,这是通过直接将堆栈中保存的值取出来实现的。

;	COMDAT func
_TEXT	SEGMENT
pvAddressOfReturnAddress$ = 32
__$ReturnAddr$ = 56
func	PROC						; COMDAT

; 15   : void func() {

$LN3:
  00000	48 83 ec 38	 sub	 rsp, 56			; 00000038H

; 16   :    void* pvAddressOfReturnAddress = _AddressOfReturnAddress();

  00004	48 8d 44 24 38	 lea	 rax, QWORD PTR __$ReturnAddr$[rsp]
  00009	48 89 44 24 20	 mov	 QWORD PTR pvAddressOfReturnAddress$[rsp], rax

; 17   :    Print(L"%lx\n", pvAddressOfReturnAddress);

  0000e	48 8b 54 24 20	 mov	 rdx, QWORD PTR pvAddressOfReturnAddress$[rsp]
  00013	48 8d 0d 00 00
	00 00		 lea	 rcx, OFFSET FLAT:??_C@_19LKIJIFCB@?$AA?$CF?$AAl?$AAx?$AA?6?$AA?$AA@
  0001a	e8 00 00 00 00	 call	 Print

; 18   :    Print(L"%lx\n", *((void**) pvAddressOfReturnAddress));

  0001f	48 8b 44 24 20	 mov	 rax, QWORD PTR pvAddressOfReturnAddress$[rsp]
  00024	48 8b 10	 mov	 rdx, QWORD PTR [rax]
  00027	48 8d 0d 00 00
	00 00		 lea	 rcx, OFFSET FLAT:??_C@_19LKIJIFCB@?$AA?$CF?$AAl?$AAx?$AA?6?$AA?$AA@
  0002e	e8 00 00 00 00	 call	 Print

; 19   :    Print(L"%lx\n", _ReturnAddress());

  00033	48 8b 44 24 38	 mov	 rax, QWORD PTR __$ReturnAddr$[rsp]
  00038	48 8b d0	 mov	 rdx, rax
  0003b	48 8d 0d 00 00
	00 00		 lea	 rcx, OFFSET FLAT:??_C@_19LKIJIFCB@?$AA?$CF?$AAl?$AAx?$AA?6?$AA?$AA@
  00042	e8 00 00 00 00	 call	 Print

; 20   : }

  00047	48 83 c4 38	 add	 rsp, 56			; 00000038H
  0004b	c3		 ret	 0
func	ENDP

完整的代码下载:

参考:

1. https://docs.microsoft.com/zh-cn/cpp/intrinsics/addressofreturnaddress?view=vs-2017

Step to UEFI (200)按键实现音量控制的一种方法

这篇文章其实和BIOS关系不大,之所以放在这里更关键的是给大家提供一种Windows 下针对IRQ, Interrupt Vector 的分析方法。

我有一台 WHL HDK ,上面有4个实体按键,分别是 Power Button ,Volume Up, Volume Down 和Reset。从电路图上来看,Volume Up 和 Down 是直接连接进入EC的。起初我以为按下时会产生Q Event,但始终无法在 ASL 中触发对应的 Event。后来仔细琢磨:所谓“条条大路通罗马”,抓不到的原因非常可能是EC 并不是通过 Q_Event 的方式来通知的系统,很可能是通过多媒体按键的键值方式传递这个消息的。为此,进行下面的实验:

1.打开设备管理器查看一下 PS2 键盘,上面给出的 IRQ1:

2.连接好 WinDBG 后查看IRQ1 的中断号(如果出错,那么需要用 .reload 加载一下Symbols),可以看到对应的Vector 是 80:

||0:1: kd> !ioapic
Controller at 0xfffff798800537f0 I/O APIC at VA 0xfffff79880057000
IoApic @ FEC00000  ID:2 (20)  Arb:0
Inti00.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti01.: 00150000`00000080  Vec:80  FixedDel  IrtIdx:000a      edg high        
Inti02.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti03.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti04.: 00170000`00000070  Vec:70  FixedDel  IrtIdx:000b      edg high       
Inti05.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti06.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti07.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti08.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti09.: 000f0000`000080b0  Vec:B0  FixedDel  IrtIdx:0007      lvl high       
Inti0A.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti0B.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti0C.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti0D.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti0E.: 00130000`0000a0a0  Vec:A0  FixedDel  IrtIdx:0009      lvl low        
Inti0F.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti10.: 001d0000`0000a0a1  Vec:A1  FixedDel  IrtIdx:000e      lvl low        
Inti11.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti12.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti13.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti14.: 001f0000`0000a091  Vec:91  FixedDel  IrtIdx:000f      lvl low        
Inti15.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti16.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti17.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti18.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti19.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti1A.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti1B.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti1C.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti1D.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti1E.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti1F.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti20.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti21.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti22.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti23.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti24.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti25.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti26.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti27.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti28.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti29.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti2A.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti2B.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti2C.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti2D.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti2E.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti2F.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti30.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti31.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti32.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti33.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti34.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti35.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti36.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti37.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti38.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti39.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti3A.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti3B.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti3C.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti3D.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti3E.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti3F.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti40.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti41.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti42.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti43.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti44.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti45.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti46.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti47.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti48.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti49.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti4A.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti4B.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti4C.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti4D.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti4E.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti4F.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti50.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti51.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti52.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti53.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti54.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti55.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti56.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti57.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti58.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti59.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti5A.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti5B.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti5C.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti5D.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti5E.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti5F.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti60.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti61.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti62.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti63.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti64.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti65.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti66.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti67.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti68.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti69.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti6A.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti6B.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti6C.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti6D.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti6E.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti6F.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti70.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti71.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti72.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti73.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti74.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti75.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti76.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m
Inti77.: 00000000`000100ff  Vec:FF  FixedDel  Ph:00000000      edg high      m

Controller at 0xfffff79880053a38 PIC
Controller at 0xfffff79880053c60 PIC

3.接下来使用 IDT 查看0x80 这个 Vector,描述为i8042prt!I8042KeyboardInterruptService

||0:1: kd> !idt

Dumping IDT: ffff920126fb1000

00:	fffff801ff7a7d00 nt!KiDivideErrorFault
01:	fffff801ff7a8080 nt!KiDebugTrapOrFault
02:	fffff801ff7a84c0 nt!KiNmiInterrupt	Stack = 0xFFFF920126FB0200
03:	fffff801ff7a8980 nt!KiBreakpointTrap
04:	fffff801ff7a8d00 nt!KiOverflowTrap
05:	fffff801ff7a9080 nt!KiBoundFault
06:	fffff801ff7a9640 nt!KiInvalidOpcodeFault
07:	fffff801ff7a9bc0 nt!KiNpxNotAvailableFault
08:	fffff801ff7a9f00 nt!KiDoubleFaultAbort	Stack = 0xFFFF920126FAC200
09:	fffff801ff7aa240 nt!KiNpxSegmentOverrunAbort
0a:	fffff801ff7aa580 nt!KiInvalidTssFault
0b:	fffff801ff7aa8c0 nt!KiSegmentNotPresentFault
0c:	fffff801ff7aacc0 nt!KiStackFault
0d:	fffff801ff7ab080 nt!KiGeneralProtectionFault
0e:	fffff801ff7ab400 nt!KiPageFault
10:	fffff801ff7abb00 nt!KiFloatingErrorFault
11:	fffff801ff7abf00 nt!KiAlignmentFault
12:	fffff801ff7ac280 nt!KiMcheckAbort	Stack = 0xFFFF920126FAE200
13:	fffff801ff7acdc0 nt!KiXmmException
14:	fffff801ff7ad1c0 nt!KiVirtualizationException
1f:	fffff801ff7a0890 nt!KiApcInterrupt
20:	fffff801ff7a15a0 nt!KiSwInterrupt
29:	fffff801ff7ad780 nt!KiRaiseSecurityCheckFailure
2c:	fffff801ff7adb00 nt!KiRaiseAssertion
2d:	fffff801ff7ade80 nt!KiDebugServiceTrap
2f:	fffff801ff7a36d0 nt!KiDpcInterrupt
30:	fffff801ff7a0ed0 nt!KiHvInterrupt
31:	fffff801ff7a1c00 nt!KiVmbusInterrupt0
32:	fffff801ff7a22b0 nt!KiVmbusInterrupt1
33:	fffff801ff7a2960 nt!KiVmbusInterrupt2
34:	fffff801ff7a3010 nt!KiVmbusInterrupt3
35:	fffff801ff79f0d8 hal!HalpInterruptCmciService (KINTERRUPT fffff801fffcceb0)

50:	fffff801ff79f1b0 USBXHCI!Interrupter_WdfEvtInterruptIsr (KMDF) (KINTERRUPT ffff9201281edc80)

60:	fffff801ff79f230 iaStorAC+0xf4b4 (STORPORT) (KINTERRUPT ffff920127556c80)

70:	fffff801ff79f2b0 serial!SerialCIsrSw (KINTERRUPT ffff920127556b40)

80:	fffff801ff79f330 i8042prt!I8042KeyboardInterruptService (KINTERRUPT ffff920127556500)

81:	fffff801ff79f338 TeeDriverW8x64+0x129e0 (KMDF) (KINTERRUPT ffff9201281eda00)

91:	fffff801ff79f3b8 ISH+0xa840 (KMDF) (KINTERRUPT ffff9201281ed8c0)

a0:	fffff801ff79f430 msgpioclx!GpioClxEvtInterruptIsr (KMDF) (KINTERRUPT ffff920127556a00)

	                 msgpioclx!GpioClxEvtInterruptIsr (KMDF) (KINTERRUPT ffff9201275568c0)

	                 msgpioclx!GpioClxEvtInterruptIsr (KMDF) (KINTERRUPT ffff920127556780)

	                 msgpioclx!GpioClxEvtInterruptIsr (KMDF) (KINTERRUPT ffff920127556640)

	                 msgpioclx!GpioClxEvtInterruptIsr (KMDF) (KINTERRUPT ffff9201275563c0)

	                 msgpioclx!GpioClxEvtInterruptIsr (KMDF) (KINTERRUPT ffff920127556280)

	                 msgpioclx!GpioClxEvtInterruptIsr (KMDF) (KINTERRUPT ffff920127556140)

	                 msgpioclx!GpioClxEvtInterruptIsr (KMDF) (KINTERRUPT ffff920127556000)

	                 msgpioclx!GpioClxEvtInterruptIsr (KMDF) (KINTERRUPT ffff9201281eddc0)

	                 msgpioclx!GpioClxEvtInterruptIsr (KMDF) (KINTERRUPT ffff9201281edb40)

a1:	fffff801ff79f438 iaLPSS2_I2C+0x5470 (KMDF) (KINTERRUPT ffff9201281ed780)

	                 HDAudBus!HdaController::Isr (KINTERRUPT ffff9201281ed640)

b0:	fffff801ff79f4b0 ACPI!ACPIInterruptServiceRoutine (KINTERRUPT ffff920127556dc0)

b1:	fffff801ff79f4b8 dxgkrnl!DpiFdoMessageInterruptRoutine (KINTERRUPT ffff9201281ed500)

cd:	fffff801ff79f598 hal!HalpInterruptThermalService (KINTERRUPT ffffaa82d3cf3400)

ce:	fffff801ff79f5a0 hal!HalpIommuInterruptRoutine (KINTERRUPT ffffaa82d3cef100)

d1:	fffff801ff79f5b8 hal!HalpTimerClockInterrupt (KINTERRUPT ffffaa82d3cef300)

d2:	fffff801ff79f5c0 hal!HalpTimerClockIpiRoutine (KINTERRUPT ffffaa82d3cef200)

d7:	fffff801ff79f5e8 hal!HalpInterruptRebootService (KINTERRUPT fffff801fffcd1b0)

d8:	fffff801ff79f5f0 hal!HalpInterruptStubService (KINTERRUPT fffff801fffcd0b0)

df:	fffff801ff79f628 hal!HalpInterruptSpuriousService (KINTERRUPT fffff801fffccfb0)

e1:	fffff801ff7a3c60 nt!KiIpiInterrupt
e2:	fffff801ff79f640 hal!HalpInterruptLocalErrorService (KINTERRUPT fffff801fffcd2b0)

e3:	fffff801ff79f648 hal!HalpInterruptDeferredRecoveryService (KINTERRUPT ffffaa82d3cef000)

fe:	fffff801ff79f720 hal!HalpPerfInterrupt (KINTERRUPT fffff801fffcd3b0)

4.直接对其下中断

bp i8042prt!I8042KeyboardInterruptService

5. 随后按下VolumeUp或者VolumeDown即可触发这个中断

Breakpoint 0 hit
i8042prt!I8042KeyboardInterruptService:
fffff80b`da5d5e40 488bc4          mov     rax,rsp

最终证明当前的 WHL HDK 是用发PS2键盘消息的方式来实现音量的增减的。如果想修改为Q_Event 的方式,那么需要 EC 工程师配合才能实现。

Windows 命令 “where”

当我们在 cmd 窗口下输入一个命令后,首先Windows会在当前目录中查找,之后会在 Path 指定的路径下查找。我们在编译过程中经常会遇到:输入一个可执行文件,但是又不知道是从哪里执行的。特别是当系统中有很多个同名文件的时候。最近发现Windows下有一个命令能够帮助我们很快完成查找的工作,就是 Where 命令。

例如,我想知道当前 python 执行的是哪个,可以输入 where python

WHERE.exe【参考1】

Locate and display files in a directory tree.

The WHERE command is roughly equivalent to the UNIX ‘which’ command. By default, the search is done in the current directory and in the PATH.

Syntax
      WHERE [/r Dir] [/q] [/f] [/t] Pattern ...

      WHERE [/q] [/f] [/t] [$ENV:Pattern

      In PowerShell:
      C:\Windows\System32\WHERE.exe ..options as above

key
   /r      A recursive search, starting with the specified Dir directory.

   /q      Don’t display the files but return either an exit code of 0 for success
           or 1 for failure.

   /f      Display the output file name in quotation marks.

   /t      Display the size, time stamp, and date stamp of the file.

  pattern  The Drive\Directory\file, or set of files to be found.
           you can use wildcard characters ( ? * ) and UNC paths.

   ENV     Path to search where ENV is an existing environment variable containing one or more paths.

By default, WHERE searches the current directory and the paths specified in the PATH environment variable.

The WHERE command is particularly useful to reveal multiple versions of the same comand/script on the system PATH such as a Resource Kit utility – Robocopy or ForFiles.

To run the WHERE command from PowerShell it is necessary to give the full path C:\Windows\System32\WHERE.exe otherwise the Where-Object cmdlet will take precedence.

Optional search paths (in pattern) should not be used in conjunction with /r Dir.

Examples

Find all copies of robocopy.exe in the current system path:

C:\Windows\System32\WHERE robocopy.exe

Find all files named ‘Zappa’ on the remote computer ‘Server64’ searching the subdirectories of Share1:

WHERE /r \\Server64\Share1 Zappa.*

参考:

1: https://ss64.com/nt/where.html