前面介绍了 IDT ,这里继续研究Shell 下是如何处理 Exception的。

同样,前面提到过,Shell下当一个中断发生之后会从 IDT 中查找Vector入口,然后跳转进去执行。

1.代码在\UefiCpuPkg\Library\CpuExceptionHandlerLib\X64\ExceptionHandlerAsm.nasm 可以看作用是在尽量短的代码中跳转到对应的处理代码

AsmIdtVectorBegin:
%rep  32
    db      0x6a        ; push  #VectorNum
    db      ($ - AsmIdtVectorBegin)...								 > Read More
			

前面介绍了静态条件下的分析,下面研究一下EFI 文件加载在内存中的情况。

用一个图来说明情况:

左侧是文件,右侧是加载到内存后的情况,可以看到对于头是照搬到内存中。对于Section 的话,看起来就比较麻烦,一般情况下内存的对齐要求会比PE文件要求的大。比如:PE 中按照 16Bytes对齐,在内存中可能要求按照 64Bytes对齐,相比是因为 PE文件希望紧凑一些,内存的数据希望读取更快所以要做成这样的。

用一个GenCRC32.exe为例:

加载到内存中的是按照 0x1000对齐,数据在文件中存放是按照 0x200对齐。

继续查看 .text Section 可以看到 RVA=0x1000,意思是:当这个PE被加载到内存后,会放在 BaseAddress+0x1000的内存地址;Pointer to Raw Data 给出 0x400意思是这个段在文件中的位置是从 0x400开始的。

2019年10月19-20日,本站会参加位于上海市杨浦区五角场市级副中心国和路 346 号江湾体育场举办的创客嘉年华活动,展位编号 M10。主要展示 Arduino 设计相关内容。

展览中出售的模块如下:

  1. USB Host Mini http://www.lab-z.com/cuhm/
  2. USB Host Shield http://www.lab-z.com/arduinousb1/
  3. Leonardo2UNO Shield http://www.lab-z.com/l2u/
  4. ProtoShield V1 http://www.lab-z.com/prototype-shield-v3/
  5. ProtoShield V3 http://www.lab-z.com/prototype-shield-v3/

欢迎新老朋友前来捧场。

> Read More

很多年前我去 DELL 面试,里面的BIOS工程师问如何实现一个delay。我讲了一些使用硬件Timer的方法来实现精确的delay,他都一直摇头。最后我实在忍不住问他正确答案是什么。他的回答是 90h 也就是 NOP指令。当然,NOP是最简单的方法,但是这种方法密切和CPU速度相关的,在不同的CPU上实现的效果不同。

最近查看UEFI 发现其中实现了一个delay使用的是 PAUSE 指令看起来很有意思,于是做了一番研究。具体代码在 \MdePkg\Library\BaseLib\Ia32\CpuPause.c 和\MdePkg\Library\BaseLib\X64\CpuPause.nasm 中。殊途同归,最终都是通过pause 指令来实现。

PAUSE Spin Loop Hint

Opcode Mnemonic           Description

F3 90     PAUSE   Gives hint to processor that improves performance of spin-wait loops.

Description

Improves the performance of spin-wait loops. When executing a... > Read More

前面的文章“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);