VC 宏展开

相信很多人入门时都使用 MASM,这的 MASM 就是 Microsoft‘s Macro Assembler。其中的 Macro 就是宏的意思。相比函数,宏具有更加简洁,运行速度快(编译器会对代码进行“宏展开”,直接修改代码)等等特点。但是,如果需要调试和阅读具有多层宏定义就非常痛苦了。很多年前我接触到的P公司的BIOS代码就是这样,乍一看代码非常规整,每一行就像一个洋葱,追踪起来一层又一层,让人感叹阅读代码是个系统工程。

最近偶然看到 GCC 有展开宏功能,同样的在Microsoft 的Visual C++上也有类似功能,通过编译指令 /p 或者 /ep 即可实现。这两个参数的区别在于生成的” 预编译文件”是否有行号。例如,编写下面的代码,其中定义一个名为 SUM 的宏:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>
#define SUM(a,b) a+b


/***
  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
  )
{
        int c =3,d=4;

  Print(L"Hello there fellow Programmer.\n");
  Print(L"Welcome to the world of EDK II.\n");

  Print(L"Macro test %d\n",SUM(c,d));
  
  return(0);
}

在 INF 中定义如下:

[BuildOptions]
  MSFT:*_*_X64_CC_FLAGS  = /P

在Build 目录下有生成一个 hello.i 其中有如下代码断,可以看到 SUM 宏已经展开。

INTN
__cdecl
ShellAppMain (
   UINTN Argc,
   CHAR16 **Argv
  )
{
        int c =3,d=4;

  Print(L"Hello there fellow Programmer.\n");
  Print(L"Welcome to the world of EDK II.\n");

  Print(L"Macro test %d\n",c+d);
  
  return(0);
}

如果使用 /EP  /P 参数,那么生成的预编译文件中不会有行号:

[BuildOptions]
  MSFT:*_*_X64_CC_FLAGS  = /EP /P

下图中,左侧是 /EP /P 参数的运行结果,右侧是/P 的结果:

UEFI TIPS: 定义一个注释宏

最近看了一下C语言中 Define 的用法,这个可以看成是C 语言的宏定义,在使用时会进行展开。从这个角度来说,可以用它实现编译过程中自动删除代码的功能。

比如下面的代码中,当定义LAB_APP_DEBUG 1 后,编译过程中 zPrint  会被解释成为 “\\” 这样对应的一行就会被注释掉。

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

#include  <stdio.h>
#include  <stdlib.h>

#define LAB_APP_DEBUG 1
#if defined(LAB_APP_DEBUG)
        #define        zPrint   Print
#else   
        #define        zPrint   /\
/
#endif

INTN
EFIAPI
main (
  IN UINTN Argc,
  IN CHAR8 **Argv
  )
{
    zPrint(L"StringAAAA\n");
    zPrint(L"StringBBBB\n");
    
    return EFI_SUCCESS;
}

运行结果,第一个是定义了LAB_APP_DEBUG=1的结果,第二个是删除了这定义的结果

此外,EDK2 中一些宏将一些函数定义为空,在编译时通过当前时 DEBUG 还是 REALSE 进行区分,可以做到和上面相同的效果。

Arduino CH376 模块调试指南

去年的时候,介绍过通过串口来和 CH376 通讯【参考1】,最近又将它拿出来玩,和之前不同,这次是和 ESP32 通讯,没想到遇到了奇怪的问题,以此为契机仔细研读 datasheet 总结如下。

  1. 硬件连接:USB 转串口卡,上面的 5V(必须5V),接VCC;GND 接 GND;TX接 RX; RX 接TX; 特别注意,这种板子上有一个5V转3.3V的ASM1117,就是说5V提供给USB 设备,但是芯片是工作在3.3V 下,这种情况下串口一般都能正常工作,但是如果用 SPI 模式,需要特别注意和单片机的电平匹配问题;
  2. 串口发送 CHECK_EXIST (57 AB 06 AA),正确的回复是 0x55 如果没有回复或者是错误的,请检查硬件连接,还有波特率设定;默认情况下波特率为 9600
测试串口参数如图

3.串口发送CMD_SET_USB_MOD (57 AB 15 06), 模式代码为 06H 时切换到已启用的 USB 主机方式,自动产生 SOF 包,正确回答是CMD_RET_SUCCESS 和 USB_INT_CONNECT (0x51 0x15)

  1. 串口发送 DISK_CONNECT(57 AB 30),检查U盘连接,正确回答是 0x14;如果有问题,请更换U盘或者检查格式,在【参考2】给出了一个Bug:如果保留扇区数>255,在老的芯片上会有问题;
  2. 串口发送 DISK_MOUNT (57 AB 31),初始化U盘,并且检测,正确回答是 0x14;
  3. 串口发送 DISK_CAPACITY (57 AB 3E), 查询U盘容量。查询结果需要发送 RD_USB_DATA0查询(57 AB 27),收到返回值 04 FF 7F 7D 00 ,意思是 4个字节,0x7D7FFF= 8224767个扇区电脑上查看如下(感觉这个命令查询的结果是“U盘上最大的扇区号”,所以数量等于这个值加1):

参考:

  1. https://www.lab-z.com/ardch376/
  2. http://www.wch.cn/bbs/thread-63674-1.html 工作人员回复说老版本芯片会有问题

FT232H UART 速度测试

很早之前入手过一块 FT232H 的板卡,这次进行一下 UART 最高速度的测试。测试条件是 Windows 10 操作系统,系统默认的驱动(VCP)。

FT232H 长江智动产的

FT232 上 TXD 是 Pin13 (AD0), RXD 是Pin14(AD1)

FT232H 做 Uart 通讯时的引脚定义
不同功能下引脚的功能

使用串口工具直接发送 HEX 55 55 55 55 55 55 55 55 55 55 值(这样从信号看起来就是不断变化的0 1 信号),示波器查看结果如下:

上面是FT232H uart 12M (波特率  12 000 000)的结果
上面是 6Mhz 的结果

此外,有一些波特率是无法使用的比如:10Mhz ,测试显示无信号输出。测试板子上的晶振是 12Mhz 的,可能是因为这个原因,所有有些分频是无法出来的。从上面可以看出, FT232H UART 模式下,最高的有效传输速度可以达到 12Mhz*(8/10)=9 600 000 bits/s = 1.444Mbytes/s。

本文数据根据实验得出,有问题欢迎朋友直接指出共同探讨。

参考:

1. http://ftdichip.cn/Support/Documents/DataSheets/ICs/DS_FT232H.pdf

D3hot 和 D3Cold

从 Windows8 开始,操作系统将设备的 D3 状态分为2种: D3hot 和 D3Cold。

设备可以直接从 D0 状态进入D3Hot,D3Cold 只能从 D3Hot 状态进入。 从 D0 到 D3Hot 的状态切换是通过驱动程序来完成的。进入 D3Hot 后,仍然能够在这个设备连接的总线(Bus)上看到这个设备。当这个总线上的设备进入 D3Hot 后,总线必须处于 D0 状态。进入 D3Hot 后,设备可以返回 D0 状态,或者进入 D3Cold 状态。

当设备进入 D3Cold 后,总线上无法检测到这个设备(设备完全断电)。当设备进入 D3Cold 后,它所处的总线可以进入低功耗状态。同时这个设备不会响应总线上的检测动作。进入 D3Cold 后,设备只能返回 D0 状态,不能直接切换为 D3Hot 状态。

参考:

1.https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/device-sleeping-states

2.https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/supporting-d3cold-in-a-driver

3.https://blog.csdn.net/qq_38180524/article/details/106079187

4.http://blog.chinaunix.net/uid-7374279-id-5838168.html

WinDbg 查看OS 版本命令:vertarget

5: kd> vertarget
Windows 10 Kernel Version 19041 MP (8 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Edition build lab: 19041.1.amd64fre.vb_release.191206-1406
Machine Name:
Kernel base = 0xfffff805`0da00000 PsLoadedModuleList = 0xfffff805`0e62a2b0
Debug session time: Wed Feb 10 15:55:42.009 2021 (UTC + 8:00)
System Uptime: 7 days 23:02:38.960

参考:

1.https://www.cnblogs.com/yilang/p/12009225.html

Kabylake PCH UART 测试工具 UEFI Shell 版

在 KablyLake/AmberLake的PCH上存在着3个UART,默认情况下使用 UART2(第三个UART,INTEL RVP上使用的就是这个Port作为UEFI Debug Log 输出)。为此,编写一个 UEFI Shell Application 能够让三个 UART 分别发送 “This is PCH UART0/1/2”。在通过串口连接出去的机器上可以收到。这样能够方便的确认硬件连接以及配置是否工作正常。

运行结果:

ZUART UEFI Shell 下运行结果

工具下载(无 SourceCode):

ESP32 S2 进一步测试

春节这几天趁着有空再进一步研究了一下 ESP32 S2 的 USB 玩法。线路连接方法和之前介绍的相同【参考1】,特别注意,这次没有连接 ESP32S2 的5V和 USB 端口的5V,  这是防止 USB 端口上的5V和板子上的5V不同导致的电流倒灌。首先测试 HID的例子:

选择 ESP32 Tiny USB 中的 HID 例子

烧写代码后设备管理器中可以看到多出的 HID 设备。

新出现的 ESP32 S2 模拟出来的设备

我手上的开发板是ESP32-S2-Saola-1R,引脚入下图:

ESP32-S2-Saola-1R 引脚图

调试方法:

打开当前 Verbose 模式

这样,可以在 Arduino 串口监视器中看到 Debug 信息,比如插入时有如下信息:

插入时的Debug 信息

接下来研究一下 MSD (MassStorageDevice,U盘)的例子,在Example->ESP32 TinyUSB->MSC。这个例子需要使用1.5MB的 PSRAM ,对于我入手的板子来说 Flash 是4MB ,PSRAM 是2MB,完全能够满足要求。此外,需要 Enable PSRAM,否则会出现不断重启的问题:

需要Enable PSRAM

烧写之后系统中就会出现如下的硬盘。

很小的一个U盘

测试发现最新版本的 ESPTinyUSB 库似乎有问题,下面是我这边正常使用的老版本的库:

参考:

  1. http://www.lab-z.com/esp32s2/ 支持原生USB 的ESP32 :ESP32 S2
  2. https://www.mischianti.org/wp-content/uploads/2020/11/ESP32-S2-Saola-1MI-pinout-mischianti.png

常见 X86 平台TPM 相关缩写介绍

之前看到过很多人用一些词组来证明中文的简洁和高效,比如:人们看到“炮闩”,通过“闩”就能猜到它的用途。这让我想起最近网上的一个笑话:“老师在群里发消息说明天开始一元二次方程。有家长问。能不能一元三次?打个折?” 缺少必要知识,就无法理解“元”的含义。 “一元二次方程” 的英文名是“quadratic equation with one unknown”,从上面大抵能看明白这个方程中有一个未知数以及它的二次方。所以,懂和不懂是取决于知识的储备和语言文字并没有太多关系。

缩写原始词组解释
ACMAuthenticated Code Module用于验证当前密钥之类的模块,放在 BIOS 中的,这个可以看作是 BootGuard 功能的一部分(换句话说,如果想 Enabled BootGuard 功能,除了在  FIT  中 Enable BootGuard,还要保证BIOS中有这个模块。某些情况下,IBV Enabled Debug 功能后,因为 Size 的原因会关闭 ACM ,这样做出来的Debug BIOS 无法在 Fuse 后,并且Enable BootGuard的板子上运行。现象会是:上电之后马上掉电)。
BtGBootGuardBootGuard 在【参考1】有介绍。
BUPBring-Up主板上电过程,有时候指新打出来板子然后Porting BIOS 的过程。
CSEConverged Security Engine系统上的 CSME 系统
dTPMDiscrete TPM分立式TPM。对应有一颗专用芯片,通常使用 SPI 接口和PCH 相连。Intel PTT 相当于将一个 dTPM 集成到SOC 中。
EKEndorsement Key签署密钥,或背书密码。它是一个TPM平台的不可迁移的解密密钥,它是一个2048bit的RSA密钥对。它生成于平台的生产过程中,代表着每个平台的真实身份,每个平台都拥有唯一的一个。在确定平台所有者时,用于解密所有者的授权数据,还有解密与生成AIK相关的数据。签署密钥从不用作数据加密和签名。签署密钥的主要功能是生成身份证明密钥(AIK)和建立TPM平台的所有者,由TPM的所有者来生成存储根密钥SRK,使用SRK来加密、存储其他的密钥。【参考2】
FIPSFederal Information Processing Standard美国联邦信息处理标准
FITFlash Image Tool有时缩写为 FITC, 是一个用于设置 IFWI 的工具,由Intel 提供,跟随 CSME 分发。
FPFField Programmable Fuses可编程熔丝位。在 PCH 中有一些只能编写一次的熔丝位。可以理解成类似保险丝一样的东西,需要的时候通过编程能够将这个位置写死。比如,Enable PTT之后通过设置对应的熔丝位会使得这个功能无法再次 Disabled。
fTPMFirmware TPM固件模拟TPM。通过在 CPU 上运行的代码来模拟实现 TPM 的功能。为了增加安全性,相关代码是放在 Protected Execution Environment (PEE) 来执行的。
IBBInitial Boot Block这是 UEFI 中的概念,用于校验 BIOS 其余部分。
PEEProtected Execution Environment受保护运行环境,能够独立于普通CPU 运行环境来运行代码。  
PRTCProtected Real Time Clock受保护的时钟,能够抵御 Hammering 和 Replay 攻击。对于这两种攻击介绍如下【参考4】   重放攻击(Replay Attacks)又称重播攻击、回放攻击,是指攻击者发送一个目的主机已接收过的包,来达到欺骗系统的目的,主要用于身份认证过程,破坏认证的正确性。重放攻击可以由发起者,也可以由拦截并重发该数据的敌方进行。攻击者利用网络监听或者其他方式盗取认证凭据,之后再把它重新发给认证服务器。重放攻击在任何网络通过程中都可能发生,是计算机世界黑客常用的攻击方式之一。   重放操作 一个电子商务网站,要求客户对电子订单签名以防止非授权用户下订单。攻击者如要冒充某位客户下订单,最好可以获得他的私钥,如果不成功,攻击者可以监听这位顾客的通信,将顾客以前发送的订单记录下来,然后他就可以直接将这些订单发给网站了。因为这些订单的确是合法客户签名过的,如果网站没有一种识别重放订单的机制,它就会不加犹豫地接收这些订单。
PTPPlatform TPM Profile 
RBEROM Boot Extension   
RNGRandom Number Generator随机数生成器
ROTRoot of Trust根信任节点
RPMBReplay Protected Memory Block 防重放攻击内存块, 将PTT数据存放在独立的 NVM 区域。
RPMCReplay Protection Monotonic Counters防重放攻击单调递增计数器。这个计数器只能增加不能减小,通过这样的方式来对抗重放攻击。
RTCReal Time Clock   
RTMRoot of Trust for Measurement   
RTR  Root of Trust for Reporting 
RTSRoot of Trust for Storage   
TCGTrusted Computing Group  可信计算组织。TCG组织制定了TPM(Trusted Platform Module)的标准,很多安全芯片都是符合这个规范的。而且由于其硬件实现安全防护,正逐渐成为PC,尤其是便携式PC的标准配置。
TPMTrusted Platform Module可信平台模块。
VSCVirtual Smart Cards 虚拟智能卡。常见的公交卡就是一种智能卡。可以看到它能够实现身份验证,支付等等的功能。同样的,虚拟智能卡也能实现这样的功能。可以想象下面的应用场景:通过 TPM 实现了 Virtual Smart Cards 的功能,然后 Windows 就可以访问企业内部的敏感资源。比如,你将一份文档发送到企业内部打印机上,之前需要刷胸卡来完成打印,现在有了 VSC 可以通在打印机上刷笔记本电脑的方式完成打印。

可以看到,上面的很多词,如果不是专业人员,无论是英文还是中文都是需要多加解释的。再比如:“有一个机械中特别重要的装置,叫活塞,英文是piston。不过在中国,这个词最早不叫活塞,而叫“鞲鞴”。来,眼睛别晕,先扶着墙把晚饭吐出来,然后把这个字复制到word里,放大三倍字号。这个词,念“勾背”。据李文、戴吾三两位考证,是中国第一艘火轮船的制造者徐寿发明的,徐寿1871年在《汽机发轫》首次把piston翻成鞲鞴。别看这词冷僻古怪又麻烦,还真是有典故的。“鞲”字意义是革制的皮套,引申成皮制的鼓风机,也就是风箱;“鞴”字就更精妙了,它的意思是:水受压而喷涌而出。唐代皮日休的《通玄子栖宾亭记》:“源内橐籥鞴出琉璃液。”一鼓一压,正是活塞工作之象。徐寿文化水平太高,用这两个字来译piston,真是用典贴切,古今妙译里,也排得上号,就是他妈太麻烦了……所以后来大家普遍都使用“活塞”这个更浅显的词,鞲鞴则只留存在专业领域。”【参考3】

参考:

1.https://www.lab-z.com/btg/ Boot Guard 简介

2.https://www.cnblogs.com/embedded-linux/p/6716740.html TPM Key相关概念

3.https://www.zhihu.com/question/24449484/answer/27850454 作者:马伯庸

4.https://baike.baidu.com/item/%E9%87%8D%E6%94%BE%E6%94%BB%E5%87%BB 重放攻击

5.https://docs.microsoft.com/en-us/windows/security/identity-protection/virtual-smart-cards/virtual-smart-card-overview

6.https://baike.baidu.com/item/%E6%99%BA%E8%83%BD%E5%8D%A1 智能卡

智能卡(Smart Card) :内嵌有微芯片的塑料卡(通常是一张信用卡的大小)的通称。一些智能卡包含一个微电子芯片,智能卡需要通过读写器进行数据交互。智能卡配备有CPU、RAM和I/O,可自行处理数量较多的数据而不会干扰到主机CPU的工作。智能卡还可过滤错误的数据,以减轻主机CPU的负担。适应于端口数目较多且通信速度需求较快的场合。 卡内的集成电路包括中央处理器CPU、可编程只读存储器EEPROM、随机存储器RAM和固化在只读存储器ROM中的卡内操作系统COS(Chip Operating System)。卡中数据分为外部读取和内部处理部分。

智能卡(Smart Card) :内嵌有微芯片的塑料卡(通常是一张信用卡的大小)的通称。一些智能卡包含一个微电子芯片,智能卡需要通过读写器进行数据交互。智能卡配备有CPU、RAM和I/O,可自行处理数量较多的数据而不会干扰到主机CPU的工作。智能卡还可过滤错误的数据,以减轻主机CPU的负担。适应于端口数目较多且通信速度需求较快的场合。 卡内的集成电路包括中央处理器CPU、可编程只读存储器EEPROM、随机存储器RAM和固化在只读存储器ROM中的卡内操作系统COS(Chip Operating System)。卡中数据分为外部读取和内部处理部分。