前面的文章“EFI 文件研究(1)”提到了入口地方有一个奇怪的现象,直接从ProcessLibraryConstructorList 函数跳到了ProcessModuleEntryPointList。百思不得其解之后咨询天杀,他提到有编译器有一种优化方式,针对“连续两个函数的调用 ,在优化后可能会将第一个函数的尾部返回优化成对第二个函数的跳转,然后由第二个函数来进行返回”。经过这样的提醒后,我在代码中查找,找到了非常类似的代码。

在\MdePkg\Library\UefiApplicationEntryPoint\ApplicationEntryPoint.c 定义了Application 的入口:

/**
  Entry point to UEFI Application.

  This function is the entry point for a UEFI Application. This function must call
  ProcessLibraryConstructorList(), ProcessModuleEntryPointList(), and ProcessLibraryDestructorList().
  The return value from ProcessModuleEntryPointList() is returned.
  If _gUefiDriverRevision is not zero and...								 > Read More
			

EFI 文件使用的是 PE 格式(PE文件的全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件【参考1】),所以很多关于PE文件的知识在 EFI 文件上仍然是通用的。

我们编写一个代码来进行研究。功能非常简单,如果运行时加入 a 参数,那么打印一串字符,否则无任何动作。具体代码如下:

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

/***
  Print a welcoming message.

  Establishes the main structure of the application.

  @retval  0         The application exited normally.
  @retval  Other ...								 > Read More
			

有一千个读者便有一千个哈姆雷特。又好比鲁迅先生评价《红楼梦》 “经学家看见《易》,道学家看见淫,才子看见缠绵,革命家看见排满,流言家看见宫闱秘事。” 再比如经常被人批判的《古惑仔》系列电影,觉得它教坏小朋友,我觉得并不是。在我看起来应该属于青春励志题材。展现了“以陈浩南为首的香港下层青年人不甘平庸,通过打拼努力向上”的故事。当然,还可以说他是批判现实主义题材的作品,也包含了做人的道理。比如,影片中靓坤转眼间就被几个小时前羞辱的小警察射杀。

再比如3Q大战之时,记者采访了红衣教主,没成想有牛人直接从采访的视频声音中分析出来了他的电话【参考1】。谁能想到流氓软件之父竟然栽倒这样的事情中。

这次我们使用 Teensy 和数字麦克风来实现这个功能。

先介绍一下原理。电话实现拨号有两种方式:脉冲拨号和音频拨号。

脉冲拨号是一种时域处理方法,它用脉冲的个数来表示号码数字。脉冲拨号方式对脉冲的宽度、大小、间距、形状都有着严格的要求,如果由于线路的干扰或其他原因而使得这些参数发生了变化,则可能引起号码接收的错误。另一方面,由于每个脉冲都占有一定的时间(一般每个脉冲占用的时间为100ms),而使得这种拨号方式比较慢。当拨号时,用户通常会听到一串拨号音,老式的转盘电话就使用脉冲拨号。比如,拨号“0”时,电路“断”、“续”10次,代表数字“0”。可以看到,如果号码较长拨号耗时也会很长。因此,这种拨号方式逐渐为音频拨号所取代。

我们常用的音频拨号是双音多频 DTMF(Dual Tone Multi Frequency),双音多频,由高频群和低频群组成,低频群包含3个频率,高频群包含4个频率。一个高频信号和一个低频信号叠加组成一个组合信号,代表一个数字。

 120913361447
697123
770456
852789
941*0#

比如,用频率为770Hz 的正弦波加到1366Hz 的正弦波合成一个声音表示数字“5”

这个合成过程用Matlab 模拟如下:

首先是 770Hz 的正弦波:

> Read More

前面做过了 GDT 的解析,这次研究一下 IDT。

X86 上有2种中断模式:中断(interrupts)和异常(exceptions )

Interrupt 是异步,通常由 I/O 设备来生成,比如:设置一个定时器在某个时间之后发生;

Exception 是同步的,当处理器执行某个指令之后产生的。对于 Exception 还分为 faults, traps 和 abort. X86处理器对于上面两种处理方式相同,当某一个中断发生之后,CPU会通过 IDT来找到对应的处理函数。处理完成之后将控制权返回产生的位置。

X86处理器有32个预定义中断异常,余下224个可以由用户自己定义。每个IDT有一个定义的数值: vector。当然,我们更常见的是IRQXX 的说法,在X86中还有一套让 IRQ 和 Vector对应起来的机制,未来会继续研究。

和 GDT 非常类似,可以通过 IDTR寄存器获得IDT 长度和它在内存中的位置。

其中的描述符定义在\MdePkg\Include\Library\BaseLib.h... > Read More

INI 文件是一种有简单格式的文本文件(ASCII),可以用来提供一些配置信息。比如下面这个文件:

; exp ini file
[port]
Portname=COM4
Port=4
[settings]
Baud=115200 ;Speed

第一行是注释。然后  port 和 settings 都被称作 section。其中的 Portname Port 和 Baud 都是 Key,相应的,每一个 Key 都有 value 。

虽然这样的结构并不复杂,但是如果完全自己来写还是很麻烦的。经过搜索,找到了 iniparser 【参考1】这个开源项目。对应的库需要有一点修改才能编译成功, iniparser.c 中需要如下改动:  

return last - s;    ---->    return (unsigned int) (last - s);

最近在 “Intel® 64 and IA-32 Architectures Software Developer’s Manual Combined Volumes: 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D and 4”看到下面这一段话:

以是说,在 64Bits模式下 CS DS ES SS 的 Base 无论设置为什么,都会被认为是0.

于是,做实验进行验证:

1.我尝试直接在BIOS中修改 GDT 发现会导致 Post 死机。

最近发现开机之后桌面有一个弹出窗口,郁闷的是上面没有关闭按钮,也无法通过 ALT+F4关闭。

从上面也可以看出来制作广告的人非常不用心

为了确认这个窗口的归属,使用 SPY++

再进一步查看属性就得知他是多玩坦克世界盒子的广告窗口。关掉坦克世界盒子这个窗口也会随之消失。

我挺喜欢这个法系小炮的。射速快8s,一局时间越久,战绩通常越好。
> Read More

最近偶然看到BaseLib 提供了AsmReadMm0() 和AsmWriteMm0()函数,于是进行了下面的实验。

首先,用AsmReadMm0 读取当前 MM0 寄存器的值,然后随机生成一个再写入 MM0 中。

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

EFI_STATUS
EFIAPI
MMXTestMain (
  IN     EFI_HANDLE                 ImageHandle,
  IN     EFI_SYSTEM_TABLE   ...								 > Read More