推荐《从零开始的UEFI裸机编程》

最近偶然看到这本书,大概浏览了一下,非常适合初学者阅读。

从零开始的UEFI裸机编程
フルスクラッチで作る!UEFIベアメタルプログラミング

大神 祐真 著, 神楽坂琴梨 译

Gitbub 页面的简单介绍

本书的目录:

  1. 从零开始的UEFI裸机编程
  2. 译者的话
  3. 1. 第一部分
    1. 1.1. 引言
    2. 1.2. Hello UEFI!
      1. 1.2.1. 遵循UEFI标准编写程序
      2. 1.2.2. 交叉编译为UEFI可执行格式
      3. 1.2.3. 引导并运行UEFI应用程序
    3. 1.3. 获取按键输入
      1. 1.3.1. 简单文本输入协议
      2. 1.3.2. 编写一个回显程序
      3. 1.3.3. 编写一个简单的Shell
    4. 1.4. 在屏幕上绘制图形
      1. 1.4.1. 图形输出协议
      2. 1.4.2. 在屏幕上画一个矩形
      3. 1.4.3. 制作一个简单的GUI
    5. 1.5. 获取鼠标输入
      1. 1.5.1. 简单指针协议
      2. 1.5.2. 查看鼠标状态
      3. 1.5.3. 实现鼠标指针
    6. 1.6. 文件读写
      1. 1.6.1. 文件相关的协议
      2. 1.6.2. 列出目录下文件
      3. 1.6.3. GUI下列出文件
      4. 1.6.4. 读取文本文件
      5. 1.6.5. GUI下浏览文本文件
      6. 1.6.6. 编辑文本文件
      7. 1.6.7. GUI下编辑文本文件
    7. 1.7. 扩展poiOS的功能
      1. 1.7.1. 显示图片
      2. 1.7.2. 实现退出功能
      3. 1.7.3. 更大的鼠标指针
      4. 1.7.4. 功能展示
    8. 1.8. 后记
    9. 1.9. 参考资料
  4. 2. 第二部分
    1. 2.1. 引言
    2. 2.2. 控制台输出
      1. 2.2.1. 设置文字颜色和背景色
      2. 2.2.2. 检测字符串是否能被显示
      3. 2.2.3. 获取支持的文本显示模式
      4. 2.2.4. 设置文本显示模式
    3. 2.3. 键盘输入
      1. 2.3.1. 绑定按键事件
    4. 2.4. 加载和执行UEFI应用程序
      1. 2.4.1. 查看当前设备路径
      2. 2.4.2. 创建设备路径
      3. 2.4.3. 从设备路径加载镜像
      4. 2.4.4. 设备路径的“设备”
      5. 2.4.5. 创建完整的设备路径
      6. 2.4.6. 从完整的设备路径加载镜像
      7. 2.4.7. 运行加载的镜像
      8. 2.4.8. 启动Linux: 编译并启动内核
      9. 2.4.9. 启动Linux: 内核启动参数
    5. 2.5. 计时器事件
      1. 2.5.1. 暂停程序执行
      2. 2.5.2. 利用事件处理函数异步操作
    6. 2.6. 其他功能
      1. 2.6.1. 内存分配器
      2. 2.6.2. 软关机
    7. 2.7. 后记
    8. 2.8. 参考资料
  5. 关于本书

中译本在 https://kagurazakakotori.github.io/ubmp-cn/index.html 可以看到,有兴趣的朋友可以查看。

Step to UEFI (219)Windows 下的 IoApic

前面介绍了 Shell 下的 IoApic 的读写,这次研究一下 Windows 下面的。在 Windows 下面,我们可以直接使用 RW_Everything 来进行读取,设定如下:

RW_Everything 读取 IoApic

读取结果如下:

RW_Everything 读取 IoApic 结果

我们特别关注 0x12 偏移处的值为 0x980 (这台机器和之前的 WinDBG 调试的不是同一个机器,IoApic 不同)。我猜测这里是PS/2 keyboard 的 IRQ0。参照资料修改 Bit16 (Interrupt Mask),设置为1会 Disable 这个中断。于是 x012 会被写为 0x0001 0980,这时候我发现键盘无法工作了。

IoApic Interrupt Mask

测试的这个机器是笔记本,键盘是挂在EC 下面的,EC汇报给系统的是PS/2键盘。

Device Manager PS/2 Keyboard

于是,通过这样的方式我阻止了 IRQ1 的产生,因此按键会无效。接下来,再将这个恢复为之前的 0x980,但是笔记本键盘是不工作的。我猜测应该有可能是按键堵住了 Buffer,所以再使用 RW 读取 0x60 IO port(就是打开 0x60 IO Port 页面看一下),键盘即恢复了工作。有兴趣的朋友可以自行尝试,记得需要连接一个 USB 键盘。

结论:我们现在谈论的IRQ 只的是针对 IOAPIC的Number, 比如,IRQ1 位于 I/O Redirection Table Register 1 的位置,同时这个 Register 会给出对应的 Vector。当中断发生时,CPU 会根据 Vector 找到 IDT 中给出来的ISR (Interrupt Service Routine)。

额外的实验,我们可以编写一个 Python Script 来配合 Dbc实现 IoApic 的读取,代码如下:

def Test():
    def get_APIC_DAT(index):
        _base.mem(0xfec00000 , 1, index)
        return _base.mem(0xfec00010, 4)
    import common.baseaccess as _baseaccess
    _base = _baseaccess.getglobalbase()    
    print("Script from www.lab-z.com")
    for i in range(0,0x77):
        print("%02x:%08X %08X" %(i,get_APIC_DAT(0x10+i*2),get_APIC_DAT(0x10+i*2+1)))        

上述代码命名为 myscript.py, 运行结果如下:

PythonSv 读取 IoApic

20220114 RW_Everything 访问 0x60 port 的方法如下:

RW_Everything 访问 IO 60Port

Step to UEFI (218)UEFI Shell下读取 IoApic

最近在编写一个Shell 下读取 IoApic 的工具,首先实验直接调用 IoApicLib来实现,为此,在 AppPkg.dsc 中加入下面三个 Lib:

 IoApicLib|PcAtChipsetPkg/Library/BaseIoApicLib/BaseIoApicLib.inf
 LocalApicLib|UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf
 TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf

之后在自己的App 中引用IoApicLib。但是这样编译出来的EFI 在运行期会死机,甚至没有运行到 Application第一行就会死机。经过研究发现在 DxeAcpiTimerLib.inf 中有如下设定:

CONSTRUCTOR                    = DxeAcpiTimerLibConstructor

因此,DxeAcpiTimerLibConstructor会先于我们的Application入口执行,其中的代码会导致运行时死机(但是具体原因我没有分析)。

所以,需要手工编写一个读取的工具。

首先,研究一下读取的方法,根据【参考1】给出的指引,在内存中有暴露出2个内存地址作为 Index 和Data,在目前我们的电脑上都是 0xFEC0 0000h

和0xFEC 0010h. 具体的读取操作是在 Index 给出的内存地址写入要访问的寄存器索引,之后 Data 给出的内存位置就是这个寄存器的值。

IoApic Index

具体的寄存器分布如下:

IoApic Version Register

上面的 01h(IOAPICVER) 中会给出来 Redirection Table 的实际数量,Spec 中给出只有24个,但是现在通常会多于这个数量。

最终的代码如下(其中的 IoApicLib.h 等代码也都是直接从 ED2 代码中提取组合而成):

#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/DebugLib.h>
#include <Library/ShellCEntryLib.h>
#include <Library/IoLib.h>
#include <Library/ShellLib.h>
#include "IoApicLib.h"

INTN
EFIAPI
ShellAppMain (
  IN UINTN Argc,
  IN CHAR16 **Argv
  )
{
    IO_APIC_VERSION_REGISTER         Version;
    IO_APIC_REDIRECTION_TABLE_ENTRY  Entry;
    UINTN       Irq;

    ShellSetPageBreakMode(TRUE);
    
    Version.Uint32 = IoApicRead (IO_APIC_VERSION_REGISTER_INDEX);
    Print(L"Version  : %X \n",Version.Bits.Version);
    Print(L"Max Entry: %X \n",Version.Bits.MaximumRedirectionEntry);
    
    for (Irq=0;Irq<Version.Bits.MaximumRedirectionEntry; Irq++) {
        Entry.Uint32.Low = IoApicRead (IO_APIC_REDIRECTION_TABLE_ENTRY_INDEX + Irq * 2);
        Entry.Uint32.High = IoApicRead(IO_APIC_REDIRECTION_TABLE_ENTRY_INDEX + Irq * 2+1);
        Print(L"Int%02X: %08X %08X \n",Irq,Entry.Uint32.Low,Entry.Uint32.High);
    }

    return EFI_SUCCESS;
}

运行结果:

IceLake-U 运行结果

如果觉得上面的读取方式过于复杂,还可以直接使用 MMIO 的方式来访问,通过调用 IoLib 的方式实现 MmIo 的访问代码非常简单:

    for (Irq=0;Irq<Version.Bits.MaximumRedirectionEntry; Irq++) {
            MmioWrite8 (0xFEC00000, IO_APIC_REDIRECTION_TABLE_ENTRY_INDEX+(UINT8)Irq*2);
            Entry.Uint32.Low=MmioRead32 (0xFEC00000+0x10);
            MmioWrite8 (0xFEC00000, IO_APIC_REDIRECTION_TABLE_ENTRY_INDEX+(UINT8)Irq*2+1);
            Entry.Uint32.High=MmioRead32 (0xFEC00000+0x10);   
            Print(L"%08X %08X \n",Entry.Uint32.Low,Entry.Uint32.High);            
}

在实体机上这两种方法没有差别,结果是相同的。完整代码和 X64 EFI 可以在这里下载:

ESP32 测试EC11旋转编码器

最近研究了一下旋转编码器的使用。入手的是 ALPS EC11系列的:

ALPS EC11 旋转编码器

为了让它工作,自己做了电路板电阻配合【参考1】。电路图和 PCB 设计如下:

EC11 旋转编码器电路图
EC11 旋转编码器 PCB

工程可以在这里下载:

软件方面使用了ai-esp32-rotary-encoder 库,下面是一个同时使用2个旋转编码器的例子(特特别注意:不是任何的GPIO 都能选择成为和旋转编码器连接的引脚,某些连接之后会导致无法启动,有可能是因为部分ESP32在启动时会选做接口VSPI,如果你了解原因不妨在评论中指出。谢谢! ):

#include "AiEsp32RotaryEncoder.h"
#include "Arduino.h"

/*
connecting Rotary encoder
CLK (A pin) - to any microcontroler intput pin with interrupt -> in this example pin 32
DT (B pin) - to any microcontroler intput pin with interrupt -> in this example pin 21
SW (button pin) - to any microcontroler intput pin -> in this example pin 25
VCC - to microcontroler VCC (then set ROTARY_ENCODER_VCC_PIN -1) or in this example pin 25
GND - to microcontroler GND
*/

#define ROTARY_ENCODER1_A_PIN 4
#define ROTARY_ENCODER1_B_PIN 16
#define ROTARY_ENCODER1_BUTTON_PIN 2

AiEsp32RotaryEncoder rotaryEncoder1 = AiEsp32RotaryEncoder(ROTARY_ENCODER1_A_PIN, ROTARY_ENCODER1_B_PIN, ROTARY_ENCODER1_BUTTON_PIN, -1);

void rotary1_onButtonClick() {
  Serial.println("Button1 Pressed!");
}

void rotary1_loop() {
	//first lets handle rotary encoder button click
	if (rotaryEncoder1.currentButtonState() == BUT_RELEASED) {
		//we can process it here or call separate function like:
	 	rotary1_onButtonClick();
	}

	//lets see if anything changed
	int16_t encoderDelta = rotaryEncoder1.encoderChanged();
	
	//for some cases we only want to know if value is increased or decreased (typically for menu items)
	if (encoderDelta>0) Serial.print("+");
	if (encoderDelta<0) Serial.print("-");

	//for other cases we want to know what is current value. Additionally often we only want if something changed
	//example: when using rotary encoder to set termostat temperature, or sound volume etc
	
	//if value is changed compared to our last read
	if (encoderDelta!=0) {
		//now we need current value
		int16_t encoderValue = rotaryEncoder1.readEncoder();
		//process new value. Here is simple output.
		Serial.print("Rot 1 value: ");
		Serial.println(encoderValue);
	} 
	
}

#define ROTARY_ENCODER2_A_PIN 26
#define ROTARY_ENCODER2_B_PIN 27
#define ROTARY_ENCODER2_BUTTON_PIN 14

AiEsp32RotaryEncoder rotaryEncoder2 = AiEsp32RotaryEncoder(ROTARY_ENCODER2_A_PIN, ROTARY_ENCODER2_B_PIN, ROTARY_ENCODER2_BUTTON_PIN, -1);

void rotary2_onButtonClick() {
  Serial.println("Button2 Pressed!");
}

void rotary2_loop() {
  //first lets handle rotary encoder button click
  if (rotaryEncoder2.currentButtonState() == BUT_RELEASED) {
    //we can process it here or call separate function like:
    rotary2_onButtonClick();
  }

  //lets see if anything changed
  int16_t encoderDelta = rotaryEncoder2.encoderChanged();
  
  //for some cases we only want to know if value is increased or decreased (typically for menu items)
  if (encoderDelta>0) Serial.print("+");
  if (encoderDelta<0) Serial.print("-");

  //for other cases we want to know what is current value. Additionally often we only want if something changed
  //example: when using rotary encoder to set termostat temperature, or sound volume etc
  
  //if value is changed compared to our last read
  if (encoderDelta!=0) {
    //now we need current value
    int16_t encoderValue = rotaryEncoder2.readEncoder();
    //process new value. Here is simple output.
    Serial.print("Rot 2 value: ");
    Serial.println(encoderValue);
  } 
  
}

void setup() {

	Serial.begin(115200);
  Serial.println("Starttesting");

	//we must initialize rorary encoder 
	rotaryEncoder1.begin();
	rotaryEncoder1.setup([]{rotaryEncoder1.readEncoder_ISR();});
	//optionally we can set boundaries and if values should cycle or not
	rotaryEncoder1.setBoundaries(0, 10, true); //minValue, maxValue, cycle values (when max go to min and vice versa)

  //we must initialize rorary encoder 
  rotaryEncoder2.begin();
  rotaryEncoder2.setup([]{rotaryEncoder2.readEncoder_ISR();});
  //optionally we can set boundaries and if values should cycle or not
  rotaryEncoder2.setBoundaries(0, 10, true); //minValue, maxValue, cycle values (when max go to min and vice versa)

}

void loop() {
	//in loop call your custom function which will process rotary encoder values
	rotary1_loop();
  rotary2_loop();
                             
   delay(50);   
}

上述测试代码:

库可以在这里下载:

测试的照片:

双旋转编码器测试

参考:

1.

https://www.cnblogs.com/AChenWeiqiangA/p/12785276.html

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