AdaFriut 库驱动 ILI9431

之前在 Teensy上使用过 ILI9341 的屏幕【参考1】,这次在 FireBeelte(ESP32)上使用这个屏幕,相比之下 ESP32 可以很轻松的使用 40Mhz的SPI 频率。

连接如下:

ILI9341屏幕GNDVCCCLKMOSRESDCBLKMIS
FireBeelteGNDVCC (推荐) 3.3V也可以SCK/IO18MOSI/IO23D2/IO25D9/IO2NAMISO/IO19
ILI9341 对 FireBeelte(ESP32)的连接

在程序开头有2种定义方式:

1.类似  Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);  这种是指定使用硬件 SPI,速度快(我看资料理论可以达到 80Mhz, 实际测试 40Mhz 完全没问题)

2.类似 Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO); 这种定义是 SW SPI 最高在 1.2Mhz 左右

测试代码是 Adafruit_GFX_Library的例子 mock_ili9341.ino, 有修过如下:

/***************************************************
  This is our GFX example for the Adafruit ILI9341 Breakout and Shield
  ----> http://www.adafruit.com/products/1651

  Check out the links above for our tutorials and wiring diagrams
  These displays use SPI to communicate, 4 or 5 pins are required to
  interface (RST is optional)
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  MIT license, all text above must be included in any redistribution
 ****************************************************/


#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

// For the Adafruit shield, these are the default.
//#define TFT_DC 9
//#define TFT_CS 10

// For the Adafruit shield, these are the default.
//#define TFT_DC D9
#define TFT_DC 21
#define TFT_CS D8
#define TFT_MOSI MOSI
#define TFT_CLK SCK
//#define TFT_RST D2
#define TFT_RST 22
#define TFT_MISO MISO

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
// If using the breakout, change pins as desired
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);

void setup() {
  Serial.begin(9600);
  Serial.println("ILI9341 Test!"); 
 
  tft.begin(2000000UL);

  // read diagnostics (optional but can help debug problems)
  uint8_t x = tft.readcommand8(ILI9341_RDMODE);
  Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDMADCTL);
  Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDPIXFMT);
  Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDIMGFMT);
  Serial.print("Image Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDSELFDIAG);
  Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); 
  
  Serial.println(F("Benchmark                Time (microseconds)"));
  delay(10);
  Serial.print(F("Screen fill              "));
  Serial.println(testFillScreen());
  delay(500);

  Serial.print(F("Text                     "));
  Serial.println(testText());
  delay(3000);

  Serial.print(F("Lines                    "));
  Serial.println(testLines(ILI9341_CYAN));
  delay(500);

  Serial.print(F("Horiz/Vert Lines         "));
  Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE));
  delay(500);

  Serial.print(F("Rectangles (outline)     "));
  Serial.println(testRects(ILI9341_GREEN));
  delay(500);

  Serial.print(F("Rectangles (filled)      "));
  Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA));
  delay(500);

  Serial.print(F("Circles (filled)         "));
  Serial.println(testFilledCircles(10, ILI9341_MAGENTA));

  Serial.print(F("Circles (outline)        "));
  Serial.println(testCircles(10, ILI9341_WHITE));
  delay(500);

  Serial.print(F("Triangles (outline)      "));
  Serial.println(testTriangles());
  delay(500);

  Serial.print(F("Triangles (filled)       "));
  Serial.println(testFilledTriangles());
  delay(500);

  Serial.print(F("Rounded rects (outline)  "));
  Serial.println(testRoundRects());
  delay(500);

  Serial.print(F("Rounded rects (filled)   "));
  Serial.println(testFilledRoundRects());
  delay(500);

  Serial.println(F("Done!"));

}


void loop(void) {
  for(uint8_t rotation=0; rotation<4; rotation++) {
    tft.setRotation(rotation);
    testText();
    delay(1000);
  }
}

unsigned long testFillScreen() {
  unsigned long start = micros();
  tft.fillScreen(ILI9341_BLACK);
  yield();
  tft.fillScreen(ILI9341_RED);
  yield();
  tft.fillScreen(ILI9341_GREEN);
  yield();
  tft.fillScreen(ILI9341_BLUE);
  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();
  return micros() - start;
}

unsigned long testText() {
  tft.fillScreen(ILI9341_BLACK);
  unsigned long start = micros();
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(1);
  tft.println("Hello World!");
  tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
  tft.println(1234.56);
  tft.setTextColor(ILI9341_RED);    tft.setTextSize(3);
  tft.println(0xDEADBEEF, HEX);
  tft.println();
  tft.setTextColor(ILI9341_GREEN);
  tft.setTextSize(5);
  tft.println("Groop");
  tft.setTextSize(2);
  tft.println("I implore thee,");
  tft.setTextSize(1);
  tft.println("my foonting turlingdromes.");
  tft.println("And hooptiously drangle me");
  tft.println("with crinkly bindlewurdles,");
  tft.println("Or I will rend thee");
  tft.println("in the gobberwarts");
  tft.println("with my blurglecruncheon,");
  tft.println("see if I don't!");
  return micros() - start;
}

unsigned long testLines(uint16_t color) {
  unsigned long start, t;
  int           x1, y1, x2, y2,
                w = tft.width(),
                h = tft.height();

  tft.fillScreen(ILI9341_BLACK);
  yield();
  
  x1 = y1 = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t     = micros() - start; // fillScreen doesn't count against timing

  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();

  x1    = w - 1;
  y1    = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();

  x1    = 0;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();

  x1    = w - 1;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);

  yield();
  return micros() - start;
}

unsigned long testFastLines(uint16_t color1, uint16_t color2) {
  unsigned long start;
  int           x, y, w = tft.width(), h = tft.height();

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
  for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);

  return micros() - start;
}

unsigned long testRects(uint16_t color) {
  unsigned long start;
  int           n, i, i2,
                cx = tft.width()  / 2,
                cy = tft.height() / 2;

  tft.fillScreen(ILI9341_BLACK);
  n     = min(tft.width(), tft.height());
  start = micros();
  for(i=2; i<n; i+=6) {
    i2 = i / 2;
    tft.drawRect(cx-i2, cy-i2, i, i, color);
  }

  return micros() - start;
}

unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
  unsigned long start, t = 0;
  int           n, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  n = min(tft.width(), tft.height());
  for(i=n; i>0; i-=6) {
    i2    = i / 2;
    start = micros();
    tft.fillRect(cx-i2, cy-i2, i, i, color1);
    t    += micros() - start;
    // Outlines are not included in timing results
    tft.drawRect(cx-i2, cy-i2, i, i, color2);
    yield();
  }

  return t;
}

unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(x=radius; x<w; x+=r2) {
    for(y=radius; y<h; y+=r2) {
      tft.fillCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int           x, y, r2 = radius * 2,
                w = tft.width()  + radius,
                h = tft.height() + radius;

  // Screen is not cleared for this one -- this is
  // intentional and does not affect the reported time.
  start = micros();
  for(x=0; x<w; x+=r2) {
    for(y=0; y<h; y+=r2) {
      tft.drawCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testTriangles() {
  unsigned long start;
  int           n, i, cx = tft.width()  / 2 - 1,
                      cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  n     = min(cx, cy);
  start = micros();
  for(i=0; i<n; i+=5) {
    tft.drawTriangle(
      cx    , cy - i, // peak
      cx - i, cy + i, // bottom left
      cx + i, cy + i, // bottom right
      tft.color565(i, i, i));
  }

  return micros() - start;
}

unsigned long testFilledTriangles() {
  unsigned long start, t = 0;
  int           i, cx = tft.width()  / 2 - 1,
                   cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(i=min(cx,cy); i>10; i-=5) {
    start = micros();
    tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(0, i*10, i*10));
    t += micros() - start;
    tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(i*10, i*10, 0));
    yield();
  }

  return t;
}

unsigned long testRoundRects() {
  unsigned long start;
  int           w, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  w     = min(tft.width(), tft.height());
  start = micros();
  for(i=0; i<w; i+=6) {
    i2 = i / 2;
    tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 0, 0));
  }

  return micros() - start;
}

unsigned long testFilledRoundRects() {
  unsigned long start;
  int           i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(i=min(tft.width(), tft.height()); i>20; i-=6) {
    i2 = i / 2;
    tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0));
    yield();
  }

  return micros() - start;
}

这里是上述三个库:

参考:

1. http://www.lab-z.com/teensyucglib/

2022年7月17日 我又一次尝试使用这个屏幕,但是惊奇的发现无法点亮,最终研究得出了如下结论:

屏幕引脚分别是GND/VCC/CLK/MOSI/RES/DC/BLK/MISO

首先是 VCC, 经过实验最好使用5V供电,否则会概率性无法显示(屏幕是白色无内容);其中CLK 和 MOIS 需要连接到你板子上的 SPI 上;RES 是 RESET 引脚,并不是CS (卖家说的 CS 可能指的是整体省电),因此你可以将RES直接接到3.3V上(注意不要接5V),这是是最大的坑;BLK和MISO 可以悬空不接。

// Ili9341 LCD panel
#define TFT_DC          21
#define TFT_CS          -1
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

我在 FireBeetle板子上运行示例代码\libraries\Adafruit_ILI9341\examples\graphicstest.ino 头部做如下声明即可:

// Ili9341 LCD panel
#define TFT_DC          21
#define TFT_CS          -1

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

连接方式:

ILI9341屏幕GNDVCCCLKMOSRESDCBLKMIS
FireBeelteGNDVCC 5VSCK/IO18MOSI/IO233.3V21N/AN/A
ILI9341 对 FireBeelte(ESP32)的连接

此外Adafruit_BusIO 在编译时有一点小问题,我修改了一下,有需要的可以试试:

同样的连接,在 ESP32 WROOM 上也可以正常工作:

Step to UEFI (217)UEFI Shell 下读获取分区信息

最近看到 Github 上的Intel Hao Wu 提供了一个读取“EFI Partition Infomation Protocol”的工具,在 https://github.com/hwu25/edk2/tree/partition_info_test/MdeModulePkg/Application/DumpPartInfo 可以看到(https://github.com/hwu25/edk2 branch:partition_info_test)。于是进行了一番研究。

首先对于 Partition Information Protocol 可以在 UEFI Spec 2.7 中的 13.18 章节看到,通过它可以获得当前系统中的分区信息:

Partition Information Protocol
EFI_PARTITION_INFO_PROTOCOL

DumpPartInfo代码不复杂,放到 \MdeModulePkg\Application中,然后修改MdeModulePkg.dsc 即可正常编译。但是在实体机上运行的时候没有任何输出。转过头查看 DumpPartInfo.c代码发现其中使用 DEBUG() 宏作为输出。对于DEBUG这个宏,在之前的文章【参考1】中有过研究。这个宏在 \MdePkg\Include\Library\DebugLib.h 中有定义,所有的调用都是相同的头文件,但是在链接的时候会使用不同的文件作为实现。

为了确定具体实现的文件,查看Build 过程中生成的Makefile 在\Build\MdeModule\DEBUG_VS2015x86\X64\MdeModulePkg\Application\DumpPartInfo\DumpPartInfo\Makefile 可以看到,链接过程中使用了 UefiDebugLibStdErr ,因此我们需要查看 \MdePkg\Library\UefiDebugLibStdErr\DebugLib.c 才能看到具体的实现:

1.DebugPrintEnabled()函数,代码如下:

/**  
  Returns TRUE if DEBUG() macros are enabled.

  This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of 
  PcdDebugProperyMask is set.  Otherwise FALSE is returned.

  @retval  TRUE    The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is set.
  @retval  FALSE   The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is clear.

**/
BOOLEAN
EFIAPI
DebugPrintEnabled (
  VOID
  )
{
  return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) &amp; DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);
}

这里提示我们需要在 MdeModulePkg.dsc 打开下面的开关:

第一部分:

[Defines]
  PLATFORM_NAME                  = MdeModule
  PLATFORM_GUID                  = 587CE499-6CBE-43cd-94E2-186218569478
  PLATFORM_VERSION               = 0.98
  DSC_SPECIFICATION              = 0x00010005
  OUTPUT_DIRECTORY               = Build/MdeModule
  SUPPORTED_ARCHITECTURES        = IA32|IPF|X64|EBC|ARM|AARCH64
  BUILD_TARGETS                  = DEBUG|RELEASE|NOOPT
  SKUID_IDENTIFIER               = DEFAULT
#LABZ_Debug_Start
#
#  Debug output control
#
  DEFINE DEBUG_ENABLE_OUTPUT      = TRUE       # Set to TRUE to enable debug output
  DEFINE DEBUG_PRINT_ERROR_LEVEL  = 0x80000040  # Flags to control amount of debug output
  DEFINE DEBUG_PROPERTY_MASK      = 2
#LABZ_Debug_End

[LibraryClasses]

第二部分:


2.实现上面的代码后,在 NT32Pkg 虚拟机中我们可以看到 DEBUG()能够实现在屏幕上的输出了,但实体机上仍然无输出。继续研究,输出的具体代码在UefiDebugLibStdErr\DebugLib.c 中下面这个函数:

VOID
EFIAPI
DebugPrint (
  IN  UINTN        ErrorLevel,
  IN  CONST CHAR8  *Format,
  ...
  )
{
  CHAR16   Buffer[MAX_DEBUG_MESSAGE_LENGTH];
  VA_LIST  Marker;

  //
  // If Format is NULL, then ASSERT().
  //
  ASSERT (Format != NULL);
  //
  // Check driver debug mask value and global mask
  //
  if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) {
    return;
  }
  //
  // Convert the DEBUG() message to a Unicode String
  //
  VA_START (Marker, Format);
  UnicodeVSPrintAsciiFormat (Buffer, MAX_DEBUG_MESSAGE_LENGTH, Format, Marker);
  VA_END (Marker);
  //
  // Send the print string to the Standard Error device
  //
  if ((gST != NULL) && (gST->StdErr != NULL)) {
    gST->StdErr->OutputString (gST->StdErr, Buffer);
  }
}

追踪显示 gST-> StdErr 并不是 NULL,但有可能是定义为串口。对于我们来说最简单的办法是将 StdErr 赋值为 StdOut 。修改DumpPartInfo.c代码如下:

EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS                          Status;
  EFI_HANDLE                          *Handles;
  UINTN                               HandleCount;
  UINTN                               HandleIndex;
  EFI_DEVICE_PATH_PROTOCOL            *DevicePath;
  CHAR16                              *DPText;
  EFI_PARTITION_INFO_PROTOCOL         *PartInfo;

  gST->StdErr=gST->ConOut;
  
  Status = gBS->LocateHandleBuffer (
                ByProtocol,
                &gEfiPartitionInfoProtocolGuid,
                NULL,
                &HandleCount,
                &Handles
                );

之后,实体机中工作正常了:

完整代码和 X64 EFI 文件下载:

参考:

1. http://www.lab-z.com/stu170dbg/ Application 中使用 DEBUG 宏

WinDBG 分析键盘生成的 Dump 文件

本文介绍如何使用USB 键盘在 Windows 下生成一个 Dump 文件,然后通过工具进行分析。

在【参考1】,微软提供了一个使用键盘触发蓝屏生成 Dump 文件的方法。具体操作是:

1.对于 USB 键盘,需要在注册表:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\kbdhid\Parameters 下面创建 CrashOnCtrlScroll 类型为 REG_DWORD ,值为0x01:

设置注册表,打开 CrashOnCtrlScroll

2.重启之后可以通过按下右侧 ctrl 然后快速按下2次 Scroll 键实现蓝屏:

生成蓝屏

3.重启后在被测机的 Windows 目录下查找 *.dmp 文件:

Windows 目录中查找生成的 dmp 文件

4.可以使用nirsoft的   BlueScreenView v1.55 【参考2】,进行简单的分析,使用方法很简单:打开文件然后将 Dump 文件放进去。从下面可以看到,蓝屏是 kbdhid.sys 文件导致的:

BlueScreenView 查看 dmp 文件

5.正规的方法是使用 WinDBG,在下面的位置打开 dump 文件

WinDbg 打开 dmp 文件

运行结果:

Executable search path is: 
Windows 10 Kernel Version 18362 MP (12 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Edition build lab: 18362.1.amd64fre.19h1_release.190318-1202
Machine Name:
Kernel base = 0xfffff806`0e200000 PsLoadedModuleList = 0xfffff806`0e648210
Debug session time: Tue Sep 15 12:19:54.203 2020 (UTC + 8:00)
System Uptime: 0 days 0:00:13.012
Loading Kernel Symbols
...............................................................
................................................................
................................
Loading User Symbols
Loading unloaded module list
......
For analysis of this file, run !analyze -v
nt!KeBugCheckEx:
fffff806`0e3c1220 48894c2408      mov     qword ptr [rsp+8],rcx ss:0018:fffff806`1309acc0=00000000000000e2

之后运行  !analyze -v 命令
0: kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

MANUALLY_INITIATED_CRASH (e2)
The user manually initiated this crash dump.
Arguments:
Arg1: 0000000000000000
Arg2: 0000000000000000
Arg3: 0000000000000000
Arg4: 0000000000000000

Debugging Details:
------------------
BLACKBOXWINLOGON: 1

CUSTOMER_CRASH_COUNT:  1

PROCESS_NAME:  System

STACK_TEXT:  
fffff806`1309acb8 fffff806`15764170     : 00000000`000000e2 00000000`00000000 00000000`00000000 00000000`00000000 : nt!KeBugCheckEx
fffff806`1309acc0 fffff806`15763a7f     : ffffa80e`a2d0d602 fffff806`11c1208d ffffa80e`a2d321d0 00000000`000000c0 : kbdhid!KbdHidProcessCrashDump+0x1f0
fffff806`1309ad00 fffff806`15064d99     : ffffa80e`a2d0d6a0 ffffa80e`a2e6ac4c ffffa80e`00000000 fffff806`15068110 : kbdhid!KbdHid_InsertCodesIntoQueue+0xbf
fffff806`1309ad60 fffff806`15064f09     : ffffa80e`000000c6 fffff806`0e231f39 ffffa80e`a2c51470 00000000`00000001 : HIDPARSE!HidP_KbdPutKey+0x45
fffff806`1309ad90 fffff806`15065084     : ffffa80e`a2e6ac4c 00000000`0000000e ffffa80e`a2d30010 fffff806`15001a27 : HIDPARSE!HidP_ModifierCode+0xa9
fffff806`1309adc0 fffff806`15065173     : ffffa80e`a2e6ad18 ffffa80e`a2d2c6d0 ffffa80e`a2d2c6d0 fffff806`15063e9a : HIDPARSE!HidP_TranslateUsage+0x8c
fffff806`1309ae10 fffff806`157637b5     : 00000000`00000000 ffffa80e`a2d2c6d0 ffffa80e`a2d0d6a0 ffffa80e`a28fe300 : HIDPARSE!HidP_TranslateUsageAndPagesToI8042ScanCodes+0xb3
fffff806`1309ae80 fffff806`0e32b136     : 00000000`00000000 ffffa80e`a77aff02 ffffa80e`00000000 00000000`0007fe01 : kbdhid!KbdHid_ReadComplete+0x445
fffff806`1309af10 fffff806`0e247799     : ffffa80e`a2d2c6d0 fffff806`1309afe9 00000000`00000000 ffffa80e`a2d2cc6b : nt!IopUnloadSafeCompletion+0x56
fffff806`1309af40 fffff806`0e247667     : ffffa80e`a28fe310 00000000`00000006 00000000`00000000 ffffa80e`a2da21d0 : nt!IopfCompleteRequest+0x119
fffff806`1309b050 fffff806`1502acb1     : ffffa80e`a28fe300 ffffa80e`a28fe302 fffff806`1309b0f1 00000000`00000009 : nt!IofCompleteRequest+0x17
fffff806`1309b080 fffff806`1502a7ba     : ffffa80e`a2da21d0 ffffa80e`a2da2102 ffffa80e`a290d730 00000000`00000009 : HIDCLASS!HidpDistributeInterruptReport+0x25d
fffff806`1309b150 fffff806`0e247799     : ffffa80e`a2d2f9a0 ffffa80e`a2d2f9a0 fffff806`1309b201 ffffa80e`a2d2fe1b : HIDCLASS!HidpInterruptReadComplete+0x34a
fffff806`1309b1f0 fffff806`0e247667     : ffffa80e`a2bc99b0 fffff806`14c48f00 00000000`00000001 00000000`00000001 : nt!IopfCompleteRequest+0x119
fffff806`1309b300 fffff806`11b383fd     : 00000000`00000000 ffffa80e`a2bc89c0 00000000`00000002 fffff806`14c39700 : nt!IofCompleteRequest+0x17
fffff806`1309b330 fffff806`11b37ecb     : ffffa80e`a2bc8b02 fffff806`1309b451 ffffa80e`a2d2f9a0 00000000`00000000 : Wdf01000!FxRequest::CompleteInternal+0x22d [minkernel\wdf\framework\shared\core\fxrequest.cpp @ 869] 
fffff806`1309b3c0 fffff806`14c47e80     : 00000000`ffffff02 ffffa80e`a2bc89c0 ffffa80e`a2c28400 ffffa80e`a2c28400 : Wdf01000!imp_WdfRequestComplete+0x8b [minkernel\wdf\framework\shared\core\fxrequestapi.cpp @ 436] 
fffff806`1309b420 fffff806`14c45cf4     : ffffa80e`a2bc8b60 ffffa80e`a2c28460 ffffa80e`a2bc8bf0 fffff806`1309b6f8 : USBXHCI!Bulk_Transfer_CompleteCancelable+0x19c
fffff806`1309b480 fffff806`14c44460     : ffffa80e`a25c97e0 00000000`00000003 00000000`00000000 fffff806`11c1208d : USBXHCI!Bulk_ProcessTransferEventWithED1+0x464
fffff806`1309b540 fffff806`14c398d3     : ffffa80e`a107e901 fffff806`14df8301 00000000`02400280 fffff806`1309b670 : USBXHCI!Bulk_EP_TransferEventHandler+0x10
fffff806`1309b570 fffff806`14c2ba4f     : 00000000`0000002b fffff806`1309b661 ffffa80e`a2af58a0 fffff806`14c134b9 : USBXHCI!TR_TransferEventHandler+0x17
fffff806`1309b5a0 fffff806`14c4c2be     : fffff806`1309b6f8 fffff806`1309b6c8 00000000`00000000 fffff806`1309b6d0 : USBXHCI!Endpoint_TransferEventHandler+0x167
fffff806`1309b620 fffff806`14c2ea3c     : ffffa80e`a2969ab0 fffff806`1309b719 00000000`00000000 ffffa80e`a2b35510 : USBXHCI!UsbDevice_TransferEventHandler+0xa6
fffff806`1309b680 fffff806`14c2f55c     : 00000000`00000000 00000000`00000001 00000000`00000000 ffffa80e`a29698b0 : USBXHCI!Interrupter_DeferredWorkProcessor+0x578
fffff806`1309b780 fffff806`11b326ad     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : USBXHCI!Interrupter_WdfEvtInterruptDpc+0xc
fffff806`1309b7b0 fffff806`0e26ae85     : fffff806`0bb04180 00000000`00000001 fffff806`1309b7a8 00000000`00000000 : Wdf01000!FxInterrupt::_InterruptDpcThunk+0x9d [minkernel\wdf\framework\shared\irphandlers\pnp\km\interruptobjectkm.cpp @ 410] 
fffff806`1309b7f0 fffff806`0e26a4df     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!KiExecuteAllDpcs+0x305
fffff806`1309b930 fffff806`0e3c4d64     : 00000000`00000000 fffff806`0bb04180 fffff806`0e791400 ffffa80e`a6adf040 : nt!KiRetireDpcList+0x1ef
fffff806`1309bb60 00000000`00000000     : fffff806`1309c000 fffff806`13095000 00000000`00000000 00000000`00000000 : nt!KiIdleLoop+0x84


SYMBOL_NAME:  kbdhid!KbdHidProcessCrashDump+1f0

MODULE_NAME: kbdhid

IMAGE_NAME:  kbdhid.sys

IMAGE_VERSION:  10.0.18362.418

STACK_COMMAND:  .thread ; .cxr ; kb

BUCKET_ID_FUNC_OFFSET:  1f0

FAILURE_BUCKET_ID:  MANUALLY_INITIATED_CRASH_kbdhid!KbdHidProcessCrashDump

OS_VERSION:  10.0.18362.1

BUILDLAB_STR:  19h1_release

OSPLATFORM_TYPE:  x64

OSNAME:  Windows 10

FAILURE_ID_HASH:  {a90fbd35-7a19-bced-0f76-fa89d249d332}

Followup:     MachineOwner
---------

同样的,蓝屏原因指向 KBDHID.sys

参考:

  1. https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/forcing-a-system-crash-from-the-keyboard
  2. https://www.nirsoft.net/utils/blue_screen_view.html

WinDBG 查看 PEP Table

检查 PEP  Table 是Modern Standby 调试过程中必不可少的一环。通常的做法是运行 PEPChecker 这个工具,然后根据结果修改 PEPD  设定。此外还可以使用RW 或者其他工具读取 ACPI DSDT ,但是这样的做法看到的是静态的信息并没有办法得知运行期的值。这次介绍使用 WinDBG 查看测试机的 PEPD 设定,本质上是 WinDDBG ACPI Debug,在 RS2/3 上进行 ACPI Debug 会比较麻烦【参考1】,但是从 Win 10  1803 开始,MS 修改了Windows,不再需要替换文件(“For Windows* 10 version lower than 1803, checked builds of the Windows* ACPI driver (Acpi.sys) are used. Starting from version 1803, checked builds are no longer required for using Microsoft* AMLI Debugger” )。

首先,被测机MSConfig 设定 USB Debug 名称是 labz:

WinDBG 调试 ACPI

接下来,主机端设定 WinDBG, Target name 为 labz:

WinDBG 调试 ACPI

将两台机器用 USB Debug Cable连接起来即可。

8: kd> !amli find PEPD
\_SB.PEPD

8: kd> !amli find devy
\_SB.PEPD.DEVY

8: kd> !amli dns /v \_SB.PEPD.DEVY

ACPI Name Space: \_SB.PEPD.DEVY (ffff8e0ac79f8cf0)
Package(DEVY:NumElements=71){
| Package(:NumElements=3){
| | String(:Str="\_SB.PR00")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR01")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR02")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR03")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR04")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR05")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR06")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR07")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.GFX0")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.UA00")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.UA01")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.I2C0")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.I2C1")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.XHC")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.HDAS")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.PEMC")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.PSDC")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.I2C2")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.I2C3")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="Reserved For UART2 D3")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SPI0")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SPI1")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP01.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP02.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP03.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP04.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP05.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP06.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP07.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP08.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP09.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP10.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP11.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP12.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP13.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP14.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP15.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP16.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP17.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP18.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP19.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.RP20.PXSX")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0.VOL0")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR08")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR09")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR10")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR11")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR12")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR13")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR14")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR15")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.IPU0")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.HECI")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=3){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | | Integer(:Value=0x0000000000000081[129])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.GLAN")
| | Integer(:Value=0x0000000000000001[1])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.PEG0")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="USB\VID_8087&amp;PID_0AC9&amp;MI*")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000002[2])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0.PRT0")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0.PRT1")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0.PRT2")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0.PRT3")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0.PRT4")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PCI0.SAT0.PRT5")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="Reserved For TBT RP0")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="Reserved For TBT RP1")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR16")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR17")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR18")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="\_SB.PR19")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000000[0])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="Reserved For WWAN D3")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
| Package(:NumElements=3){
| | String(:Str="Reserved For DG1 D3")
| | Integer(:Value=0x0000000000000000[0])
| | Package(:NumElements=2){
| | | Integer(:Value=0x0000000000000000[0])
| | | Package(:NumElements=2){
| | | | Integer(:Value=0x00000000000000ff[255])
| | | | Integer(:Value=0x0000000000000003[3])
| | | }
| | }
| }
}

从上面可以看到 DEVY 的结构以及数值。

参考:

1. http://www.lab-z.com/windbg2/

EDK2 编译遇到无法Link GDI32.LIB的问题

昨天在编译 EDK2 的代码时,忽然遇到无法 Link 到 GDI32.LIB 的情况。百思不得其解中回想了一下,最近重装了 SDK,并且编译的目标是 NT32Pkg,它需要Window32 API, 所以问题应该出现在 SDK 上。

最终经过研究,原来是我在安装最新的 10.0.19041.0 时,没有选择 X64 的Library:

这里要选中 X86 和 AMD64

如果你也遇到类似问题,不妨检查一下 \Windows Kits\10\Lib\10.0.19041.0\um\x64 下面是否有 GDI32.LIB, 如果没有的话,请再检查当前系统中的 SDK安装情况。

支持原生USB 的ESP32 :ESP32 S2

当我们谈论 ESP32 支持USB 时,谈论的并不是最常见的ESP32而是乐鑫信息科技(上海)股份有限公司(ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD.)新出品的一个型号:ESP32 S2。具体的比对可以从下图看到。主要的变化是变成单核(对 Arduino玩家几乎没有影响),去掉了蓝牙功能,另外就是增加了USB OTG 的功能。这意味着可以用 S2 方便的实现USB Device或者 Host 功能(目前还没有看到 Arduino 版本的 USB Host支持):

图片来自 【参考1】
图片来自 【参考1】

为了进行实验,需要入手一个开发板,在【参考2】可以目前的模块有如下四种:

ESP32-S2-WROOM

ESP32-S2-WROOM-I

ESP32-S2-WROVER

ESP32-S2-WROVER-I

其中 WROOM  和  WROVER 的差别在于 PRAM 大小的差别,有 -I 和没有的在于天线是否存在于模组之上。最终选择的是 ESP32-S2-Saola-1开发板,直接在taobao 上的 乐鑫科技 Espressif Online 买了一块 ESP32-S2-Saola-1R (这个应该算是官方正版了)。相比之下,这个板子价格要比普通的贵上很多,达到48元/块。

接下来就是软件的问题了,ESP32 S2 并不能用普通的 Arduino 支持的 ESP32 环境进行编译,更准确的说是不能用他来完成 USB Device的支持。具体的支持方法可以在【参考4】看到。这里简单说一下我实验成功的方法。

1. 如果你当前Arduino 安装过 ESP32 的支持,请在 Board manager 中卸载之;
2.安装 Git,然后创建一个目录用于存放编译工具;
3.进入这个目录使用 Git Bash Here打开窗口输入下面的命令
4.git clone https://github.com/espressif/arduino-esp32.git -b esp32s2
(有可能会很慢,从我的经验上来看,用手机热点会快很多)
5.上述结束之后运行 tools 下面的get.exe

6.      安装 USBTiny , 在 https://github.com/chegewara/EspTinyUSB 其中硬件方面,按照如下设定【参考5】

7.安装 USBTiny , 在 https://github.com/chegewara/EspTinyUSB

硬件方面,按照如下连接【参考5】

参考:

1.     https://blog.csdn.net/toopoo/article/details/104299011

2.     https://www.espressif.com/zh-hans/node/4458

3.     https://item.taobao.com/item.htm?spm=a1z10.5-c-s.w4002-22443450244.11.741d27e6IeGkuO&id=612711016956

4.     https://github.com/espressif/arduino-esp32/blob/611ba8ea8acfd504174e2eec1e198a64e67cd748/docs/arduino-ide/windows.md

5.     http://bbs.eeworld.com.cn/thread-1131171-1-1.html

Step to UEFI (216)InstallProtocolInterface 的简单研究

InstallProcotolInterface() 是用来安装 Protocol 的函数,之前有提及【参考1】。这次研究和实验了一下它的具体代码。

在\MdeModulePkg\Core\Dxe\DxeMain\DxeMain.c有定义 BootService 的函数:

//
// DXE Core Module Variables
//
EFI_BOOT_SERVICES mBootServices = {
  {
    EFI_BOOT_SERVICES_SIGNATURE,                                                          // Signature
    EFI_BOOT_SERVICES_REVISION,                                                           // Revision
    sizeof (EFI_BOOT_SERVICES),                                                           // HeaderSize
    0,                                                                                    // CRC32
    0                                                                                     // Reserved
  },
………………………………………
  (EFI_CHECK_EVENT)                             CoreCheckEvent,                           // CheckEvent
  (EFI_INSTALL_PROTOCOL_INTERFACE)              CoreInstallProtocolInterface,             // InstallProtocolInterface
  (EFI_REINSTALL_PROTOCOL_INTERFACE)            CoreReinstallProtocolInterface,           // ReinstallProtocolInterface
………………………………………

具体实现在 \MdeModulePkg\Core\Dxe\Hand\Handle.c 文件中:

/**
  Wrapper function to CoreInstallProtocolInterfaceNotify.  This is the public API which
  Calls the private one which contains a BOOLEAN parameter for notifications

  @param  UserHandle             The handle to install the protocol handler on,
                                 or NULL if a new handle is to be allocated
  @param  Protocol               The protocol to add to the handle
  @param  InterfaceType          Indicates whether Interface is supplied in
                                 native form.
  @param  Interface              The interface for the protocol being added

  @return Status code

**/
EFI_STATUS
EFIAPI
CoreInstallProtocolInterface (
  IN OUT EFI_HANDLE     *UserHandle,
  IN EFI_GUID           *Protocol,
  IN EFI_INTERFACE_TYPE InterfaceType,
  IN VOID               *Interface
  )
{
  return CoreInstallProtocolInterfaceNotify (
            UserHandle,
            Protocol,
            InterfaceType,
            Interface,
            TRUE
            );
}

上述会跳转到同一个文件中的下面这个函数:

EFI_STATUS
CoreInstallProtocolInterfaceNotify (
  IN OUT EFI_HANDLE     *UserHandle,
  IN EFI_GUID           *Protocol,
  IN EFI_INTERFACE_TYPE InterfaceType,
  IN VOID               *Interface,
  IN BOOLEAN            Notify
  )
{
  PROTOCOL_INTERFACE  *Prot;
  PROTOCOL_ENTRY      *ProtEntry;
  IHANDLE             *Handle;
  EFI_STATUS          Status;
  VOID                *ExistingInterface;

  //
  // returns EFI_INVALID_PARAMETER if InterfaceType is invalid.
  // Also added check for invalid UserHandle and Protocol pointers.
  //
  if (UserHandle == NULL || Protocol == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (InterfaceType != EFI_NATIVE_INTERFACE) {
    return EFI_INVALID_PARAMETER;
  }

  //
  // Print debug message
  //
  DEBUG((DEBUG_INFO, "LABZ InstallProtocolInterface: %g %p\n", Protocol, Interface));

  Status = EFI_OUT_OF_RESOURCES;
  Prot = NULL;
  Handle = NULL;

比如,按照上述修改之后,运行下面的命令 build -a X64 -p OvmfPkg\OvmfPkgX64.dsc   即可生成 QEMU 的 BIOS:OVMF.fd,在 \Build\OvmfX64\DEBUG_VS2015x86\FV\ 。

将它copy 到 QEMU 的目录后,运行 qemu-system-x86_64.exe -m 256 -bios ovmf.fd -debugcon file:debug.log -global isa-debugcon.iobase=0x402 -net none 即可抓到串口 log。例如:

Memory Allocation 0x00000003 0xFEA4000 - 0xFEC8FFF
Memory Allocation 0x00000003 0xFEA4000 - 0xFEC8FFF
Memory Allocation 0x00000004 0xFE84000 - 0xFEA3FFF
Memory Allocation 0x00000004 0xFC00000 - 0xFDFFFFF
Memory Allocation 0x00000007 0xFE00000 - 0xFE83FFF
Memory Allocation 0x00000004 0xBF36000 - 0xBF55FFF
FV Hob            0x900000 - 0x12FFFFF
LABZ InstallProtocolInterface: D8117CFE-94A6-11D4-9A3A-0090273FC14D FEC3E30
LABZ InstallProtocolInterface: 8F644FA9-E850-4DB1-9CE2-0B44698E8DA4 FA11EB0
LABZ InstallProtocolInterface: 09576E91-6D3F-11D2-8E39-00A0C969723B FA11C18
LABZ InstallProtocolInterface: 220E73B6-6BDB-4413-8405-B974B108619A FA10BB0
LABZ InstallProtocolInterface: EE4E5898-3914-4259-9D6E-DC7BD79403CF FEC4B10

参考:

1. http://www.lab-z.com/stu100/

C# EXE 自动检验功能

最近比较恼火,因为测试机中毒了,除了在 Idle 状态下 CPU 占用率不断升高还有就是在测试 MS 的时候会遇到稀奇古怪的问题。比我更惨的是有同事收到了 IT 的警告邮件…….

因此,我有一个问题:能否设计出一个自我检查的程序,保证没有被篡改过?研究一番之后就开始动手编写。从原理上说,使用 WinPE头部没有用到的位置写入校验值,然后在代码中加入校验的内容,每次执行时先校验即可得知是否篡改。

因此,有2个程序,第一个是给被校验EXE 添加校验值的程序,另外一个是被校验的程序。

1.给 EXE 添加校验值的程序,选择在 DOS MZ 头的e_res2 位置添加 MD5值:

// DOS MZ头,大小为64个字节
typedef struct _IMAGE_DOS_HEADER {     
    WORD   e_magic;                     // EXE标志,“MZ”(有用,解析时作为是否是PE文件的第一个标志)
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // 非常重要,操作系统通过它找到NT头,NT头相对于文件的偏移地址
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; 【参考1】

代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Security.Cryptography;

namespace ConsoleApplication1
{
    class Program
    {
        public const int WINPEHEADERSize = 0x40;
        public const int RVSOffset = 0x28;
        private static byte[] GetMD5(byte[] message)
        {
            MD5 hashString = new MD5CryptoServiceProvider();
            return hashString.ComputeHash(message);
        }

        static void Main(string[] args)
        {
            byte[] TotalFile;
            byte[] FileNoHeader;
            byte[] MD5;

            if (args.Length != 1) {
                Console.WriteLine("Please input a file name");
                Console.ReadKey();
                Environment.Exit(0);
            }

            TotalFile = File.ReadAllBytes(args[0]);
            FileNoHeader = new byte[TotalFile.Length - WINPEHEADERSize];

            Buffer.BlockCopy(TotalFile, WINPEHEADERSize, FileNoHeader, 0, FileNoHeader.Length);

            MD5 = GetMD5(FileNoHeader);

            for (int i = 0; i < MD5.Length; i++)
            {
                TotalFile[i + RVSOffset] = MD5[i];
            }
            File.WriteAllBytes("E"+args[0], TotalFile);
            File.WriteAllBytes("Ex" + args[0], FileNoHeader); 
            Console.WriteLine("Complete. New file:"+ " E" + args[0]);
            Console.ReadKey();
        }
    }
}

程序接收一个文件名作为参数,然后将这个文件内容读取到TotalFile[] 中,去掉DOS 文件头后复制到FileNoHeader[] 中,之后计算这个数组的 MD5值,再将MD5放在前面提到的  e_res2 偏移处,将新生成的 EXE 写入  “E”+原文件名 的文件中。

2.带有自校验功能的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Security.Cryptography;

namespace ConsoleApplication3
{
    class Program
    {
        public const int WINPEHEADERSize = 0x40;
        public const int RVSOffset = 0x28;
        private static byte[] GetMD5(byte[] message)
        {
            MD5 hashString = new MD5CryptoServiceProvider();
            return hashString.ComputeHash(message);
        }

        static void Main(string[] args)
        {
            byte[] TotalFile;
            byte[] FileNoHeader;
            byte[] MD5;

            TotalFile = File.ReadAllBytes(System.Reflection.Assembly.GetExecutingAssembly().Location);
            FileNoHeader = new byte[TotalFile.Length - WINPEHEADERSize];

            Buffer.BlockCopy(TotalFile, WINPEHEADERSize, FileNoHeader, 0, FileNoHeader.Length);

            MD5 = GetMD5(FileNoHeader);

            int i = 0;
            while (i < MD5.Length) {
                if (MD5[i]!= TotalFile[RVSOffset+i]) {
                    Console.WriteLine("File is modified!");
                    Environment.Exit(0);
                }
                i++;
            }
            Console.WriteLine("File is OK!");
        }
    }
}

大部分和前面的程序类似,不同在于计算FileNoHeader的 MD5之后有一个比较过程,如果不一样就提示之后退出。

下面是一个测试的过程。首先用工具给 TestOK 添加签名,加入校验头的文件是 eTestOK;直接运行 TestOK, 因为头部并没有 MD5校验值,所以显示校验失败;运行 eTestOK 可以通过验证;之后用一个十六进制工具修改任意一个 BIT 都会有报错。

测试修改之前和修改之后

参考:

1. https://blog.csdn.net/weixin_30878501/article/details/99825394 WinPE基础知识之头部

Arduino 科学记数法库

科学记数法是一种记数的方法。把一个数表示成a与10的n次幂相乘的形式(1≤|a|<10,a不为分数形式,n为整数),这种记数法叫做科学记数法。 例如:19971400000000=1.99714×10^13。计算器或电脑表达10的幂是一般是用E或e,也就是1.99714E13=19971400000000。[参考1]

https://github.com/RobTillaart/Arduino/tree/master/libraries/MathHelpers 提供了一个 Arduino 科学计数法的库,能够将一个浮点数转化为科学计数法的表示。

测试代码:

//
//    FILE: mathHelperTest.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.0.1
// PURPOSE:
//
// HISTORY:

#include "MathHelpers.h"

uint32_t start;
uint32_t stop;

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("MATHHELPERS_VERSION: ");
  Serial.println(MATHHELPERS_VERSION);

  test1();
  test2();
  test3();
  test4();
  test5();

  test10();
  test11();
  test12();

}

void loop()
{}


void test1()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  float f = 1;
  for (int i = 0; i < 40; i++)
  {
    f *= 10;
    Serial.println(sci(f, 6));
  }
  Serial.println();

  f = 1;
  for (int i = 0; i < 50; i++)
  {
    f /= 10;
    Serial.println(sci(f, 6));
  }
  Serial.println();

  f = -1;
  for (int i = 0; i < 40; i++)
  {
    f *= 10;
    Serial.println(sci(f, 6));
  }
  Serial.println();

  f = -1;
  for (int i = 0; i < 50; i++)
  {
    f /= 10;
    Serial.println(sci(f, 6));
  }
  Serial.println();
  Serial.println();
}

void test2()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  float f = 1;
  for (int i = 0; i < 40; i++)
  {
    f *= (PI * PI);
    Serial.println(sci(f, 6));
  }
  Serial.println();
  f = 1;
  for (int i = 0; i < 50; i++)
  {
    f /= (PI * PI);
    Serial.println(sci(f, 6));
  }
  Serial.println();
  f = -1;
  for (int i = 0; i < 40; i++)
  {
    f *= (PI * PI);
    Serial.println(sci(f, 6));
  }
  Serial.println();
  f = -1;
  for (int i = 0; i < 50; i++)
  {
    f /= (PI * PI);
    Serial.println(sci(f, 6));
  }
  Serial.println();
  Serial.println();
}

void test3()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  float f = PI;
  for (int i = 0; i < 8; i++)
  {
    Serial.println(sci(f, i));
  }
  Serial.println();
}

void test4()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  float f = PI;
  for (int i = 0; i < 8; i++)
  {
    sci(Serial, f, i);
    Serial.println();
  }
  Serial.println();
}


void test5()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  float f = 1.0 / 0.0;
  Serial.println(sci(f, 6));
  f = 0.0 / 0.0;
  Serial.println(sci(f, 6));
  f = -1.0 / 0.0;
  Serial.println(sci(f, 6));
  // TODO find a -inf

  Serial.println();
}


void test10()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  Serial.println("HH:MM:SS");
  for (int i = 0; i < 7; i++)
  {
    uint32_t now = micros();
    Serial.println(seconds2clock(now));
  }
  Serial.println();
}

void test11()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  Serial.println("HH:MM:SS.nnn");
  for (int i = 0; i < 7; i++)
  {
    uint32_t now = micros();
    Serial.println(millis2clock(now));
  }
  Serial.println();
}

void test12()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  Serial.println("time\tweeks\tdays\thours\tminutes");
  for (int i = 0; i < 7; i++)
  {
    uint32_t now = micros();
    Serial.print(now);
    Serial.print('\t');
    Serial.print(weeks(now), 3);
    Serial.print('\t');
    Serial.print(days(now), 3);
    Serial.print('\t');
    Serial.print(hours(now), 2);
    Serial.print('\t');
    Serial.println(minutes(now), 2);
  }
  Serial.println();
}


// END OF FILE
Arduino 科学计数法

库下载

参考:
1.https://baike.baidu.com/item/%E7%A7%91%E5%AD%A6%E8%AE%B0%E6%95%B0%E6%B3%95?fromtitle=%E7%A7%91%E5%AD%A6%E8%AE%A1%E6%95%B0%E6%B3%95&fromid=756685 科学记数法