用于报告系统平台能够产生的错误来源。比如,对于 X86 架构的 MCE和CMC,以及PCIe AER, OS 能够处理的 MSI 和 PCI INTs 错误。
The HEST table enables host firmware to declare all errors that platform component can generate and error signaling for those. The host firmware shall create Error source entries in HEST for each component (such as, processor, PCIe device, PCIe bridge, etc) and each type of error with corresponding error notification mechanism (singling) to OS. These error entries include x86 architectural errors, industry standard errors and generic hardware error source for platform errors. The x86 architectural errors, MCE and CMC, and standard errors PCIe AER, MSI and PCI INTx can be handled by OS natively. The generic hardware error source can be used for all firmware 1st errors and platform errors (such as memory, board logic) that do not have OS native signaling, so they have to use platform signaling SCI or NMI
ERST:Error Record Serialization table
通过这个 Table 给 OS 提供一个能够存放错误的接口,通过这个接口,OS可以将一些信息存放在不受断电影响的存储器上,比如: NVRAM。
The ERST table provides a generic interface for the OS to store and retrieve error records in the platform persistent storage, such as NVRAM (Non-volatile RAM). The error records stored through this interface shall persist across system resets till OS clears it. The OS will use this interface store error information during critical error handling for later extensive error analysis. Host firmware shall provide serialization instruction using ACPI specification defined actions to facilitate read, write and clear error records
EINJ:Error Injection Table 通过这个 Table OS 可以给错误处理函数增加限定条件(具体使用场景我没有碰到过,对此不理解,有知道的朋友可以在评论指教一下)。
One of the important functions required in implementing the error is the ability to inject error conditions by the OS to evaluate the correct functionality of the entire error handling in the platform hardware, host firmware and the OS. The EINJ table interface facilitates error injection from the OS. The host firmware shall provide at minimum one error injection method per error type supported in the platform. The host firmware will provide the generic error serialization instructions to trigger the error in the hardware
BERT:Boot Error Record Table
记录启动时的错误信息并报告给OS,对于我们平常使用的X86来说一般是放在内存中的。
The BERT table provides the interface to report errors that occurred system boot time. In addition BERT also can be used to report fatal errors that resulted in surprise system reset or shutdown before OS had the chance to see the error. The host firmware shall build this table with error record entries for each error that occurred
可以看到,上面的 Descriptor 红色部分和其余部分的区别只是 Report ID 不同。 Report ID 是USB HID 设备用来区分功能的一个设计。例如,我们经常遇到同时带有键盘和鼠标的混合设备。通常它的Descriptor 写法就是:
Report ID 1
鼠标数据[0], 鼠标数据[1], ……鼠标数据[M-1],
Report ID 2
键盘数据[0], 键盘数据[1],……键盘数据[N-1],
当设备上有鼠标动作发生时,鼠标动作描述为 :M 长度的鼠标数据;设备对主机的报告是:
1, 鼠标数据[0], 鼠标数据[1],…… 鼠标数据[M-1]
当设备上有键盘动作发生时,键盘动作描述为 :N 长度的键盘数据;设备对主机的报告是:
2,键盘数据[0], 键盘数据[1],…… 键盘数据[N-1]
当然,你还可以继续给这个设备加入功能。比如:Report ID 3 , 键盘数据[0], 键盘数据[1],……键盘数据[P-1] 这样就又加入了一个键盘的功能(实际上这样做是有意义的,比如,通常的USB键盘数据包只有8个按键信息,如果我们同时按下9个按键就会超出它的运载能力。这就是一种“键位冲突”。如果你的设备同时声明了2个键盘,那么可以用将第九个按键的信息放置在第二个键盘的数据中发出去。如果你肯声明三个键盘设备,每个带有8个按键,理论上对于人类是完全够用的)。显而易见,通过 Report ID 主机能够分清楚当收到的数据属于哪个设备。
这次的设计,USB 手柄产生数据如下:
1, 手柄数据[0], 手柄数据[1],…… 手柄数据[M-1]
(第一个1是来自USB 手柄 Descriptor 的 Report ID 1)
我们无需解析了解每一位的含义,去掉最前面的 Report ID 然后将剩余数据转发出去即可。具体代码如下:
基本原理:通过 GetSystemPowerStatus 这个 API 获得当前系统的电池电量信息,以1秒为间隔进行查询,查询结果保存到文件中同时输出到屏幕上。收到按键后退出。
代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Threading;
using System.IO;
namespace GeetBatter
{
class Program
{
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_POWER_STATUS
{
public byte ACLineStatus;
public byte BatteryFlag;
public byte BatteryLifePercent;
public byte Reserved1;
public int BatteryLifeTime;
public int BatteryFullLifeTime;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool GetSystemPowerStatus([In, Out] ref SYSTEM_POWER_STATUS systemPowerStatus);
static void Main(string[] args)
{
// The system power charger struct
SYSTEM_POWER_STATUS status = new SYSTEM_POWER_STATUS();
Boolean Running = true;
DateTime currentTime;
String Result;
String Filename = DateTime.Now.ToString("HHmmss")+".txt";
FileStream fs = new FileStream(Filename, FileMode.Append);
StreamWriter wr = new StreamWriter(fs);
while (Running)
{
Thread.Sleep(1000);
while (Console.KeyAvailable)
{
Console.ReadKey(true);
Running = false;
}
// Get Power status from Kernell
GetSystemPowerStatus(ref status);
currentTime = DateTime.Now;
Result = currentTime.ToString("HH:mm:ss") + "," + status.BatteryLifePercent;
Console.WriteLine(Result);
wr.WriteLine(Result);
}
wr.Close();
Console.WriteLine("Program would exit");
Console.ReadLine();
}
}
}