99% BIOS工程师都不知道的方法

ME 对于大多数BIOS工程师来说都是非常神秘的黑盒子,出现问题时,唯一的方法只能去 Intel 寻求帮助。这样的好处是不用工程师一行行检查代码和设定,如何催Intel 解决问题更多是老板和 PM 的事情;缺点是老板和 PM 觉得你能更快的解决问题。
印象中十年前还有公开的ME 启动设置选项,但是随着Chipset的升级,ME成为必选项,没有办法直接关闭,我也不止一次直接拒绝要求“关闭 ME 试试”的要求。最近我在网上搜到了这样的介绍文章《如何通过未公开模式禁用Intel ME 11》【参考1】,就是说现在有人找到了Disable ME 的方法。
文章首先介绍了基本原理,以及无法关闭的主要原因“因为这项技术负责初始化、管理电源以及启动主处理器。另一个复杂原因在于,某些数据被集成在PCH芯片内部,而PCH正是现代主板上的南桥。某些爱好者尝试在维持计算机可操作性的前提下,移除了ME镜像中的所有“冗余”部分,实现对ME的禁用,这也是之前采用的主要方法。但这种方法没有那么简单,因为如果内置的PCH代码没有在闪存中找到ME模块,或者检测到相关模块处于损坏状态,那么系统将无法启动。” 就是说,从理论上说 Intel 完全可以让你无法关闭 ME,或者说关闭 ME 系统就重启。 但是,Positive Technologies研究团队使用工具解压了 ME 的Binary,在XML文件中发现了一个隐藏的BIT, 他在注释中写着是为了U.S. government’s High Assurance Platform (HAP) program 预留的。然后经过团队研究,发现这个位置可以用来设置 ME Disable。理论上 FITC 也可以完成这样的操作,只是没有开放。为此,研究团队放出了他们自己的工具me_cleaner 【参考2】。
我尝试在 Kabylake-R 平台上实验:

1.用工具生成新的 BIOS

2.比较前后的差别

3.刷写到板子上,ME 果真不见了

在刷写修改之前的BIOS,ME在设备管理器中是存在的

然后让系统运行>30分钟,一切正常。

参考:
1. https://www.anquanke.com/post/id/86740
2. https://github.com/corna/me_cleaner

Step to UEFI (147)先于Windows启动的Application

前面的一些实验涉及到修改 ACPI Table 之类的,都是要先进入 Shell 运行之后,再退出进入 Windows 中,如果能够自动调用Windows的引导程序,就不需要这么多复杂的步骤了。
结合前面的知识,可以使用gBS中的LoadImage 和StartImage加载和运行EFI 程序。难点在于这两个函数都需要被加载文件的DevicePath。近日恰好看到了【参考1】UEFI-Bootkit 项目,其中下面这个函数实现了我们需要的功能,对我们来说可以借用之。
//
// Try to find a file by browsing each device
//
EFI_STATUS LocateFile( IN CHAR16* ImagePath, OUT EFI_DEVICE_PATH** DevicePath )

这个函数的使用方法:
1. 用LocateHandleBuffer 找到所有带有SimpleFileSystemProtocol的设备(因为Windows只能从 FAT 格式的分区上加载引导的 EFI 文件)
2. 针对每一个上面找到的 Handle,使用 OpenVolume 打开上面的 EFI_FILE_PROTOCOL
3. 尝试打开EFI_FILE_PROTOCOL上面的文件(就是 Windows引导文件,路径和名称都是已知的),失败就是不存在,比如,找到U盘上去的;成功表示找到了,就可以获得需要的 DevicePath了
根据上面的编写自己的 Application 代码如下:

#include <Uefi.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h> //global gST gBS gImageHandle

#include <Protocol/LoadedImage.h>      //EFI_LOADED_IMAGE_PROTOCOL
#include <Protocol/DevicePath.h>       //EFI_DEVICE_PATH_PROTOCOL

#include <Library/DevicePathLib.h>     //link
#include <Protocol/SimpleFileSystem.h>

EFI_GUID        gEfiSimpleFileSystemProtocolGuid ={ 0x964E5B22, 0x6459, 0x11D2, 
                        { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};

// 
// Try to find a file by browsing each device
// 
EFI_STATUS LocateFile( IN CHAR16* ImagePath, OUT EFI_DEVICE_PATH** DevicePath )
{
        EFI_FILE_IO_INTERFACE *ioDevice;
        EFI_FILE_HANDLE handleRoots, bootFile;
        EFI_HANDLE* handleArray;
        UINTN nbHandles, i;
        EFI_STATUS efistatus;
        
        *DevicePath = (EFI_DEVICE_PATH *)NULL;
        //
        //Get all the Handles which have Simple File System Protocol 
        //
        efistatus = gBS->LocateHandleBuffer( ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &nbHandles, &handleArray );
        if (EFI_ERROR( efistatus ))
                return efistatus;
        
        Print( L"\r\nNumber of UEFI Filesystem Devices: %d\r\n", nbHandles );
        
        for (i = 0; i < nbHandles; i++)
        {
                efistatus = gBS->HandleProtocol( handleArray[i], &gEfiSimpleFileSystemProtocolGuid, &ioDevice );
                if (efistatus != EFI_SUCCESS)
                        continue;
        
                efistatus = ioDevice->OpenVolume( ioDevice, &handleRoots );
                if (EFI_ERROR( efistatus ))
                        continue;
                //
                //Try to open the specific path on the device
                //
                efistatus = handleRoots->Open( handleRoots, &bootFile, ImagePath, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY );
                if (!EFI_ERROR( efistatus ))
                {
                        handleRoots->Close( bootFile );
                        *DevicePath = FileDevicePath( handleArray[i], ImagePath );
                        Print( L"\r\nFound file at \'%s\'\r\n", ConvertDevicePathToText( *DevicePath, TRUE, TRUE ) );
                        break;
                }
        }
        
        return efistatus;
}
        
EFI_STATUS
EFIAPI
UefiMain(
    IN EFI_HANDLE ImageHandle,
    IN EFI_SYSTEM_TABLE *SystemTable)
{
        // Windows Boot Manager x64 image path
        static CHAR16    *gRuntimeDriverImagePath = L"\\EFI\\Microsoft\\Boot\\win.efi";
        EFI_DEVICE_PATH* RuntimeDriverDevicePath = NULL;
        EFI_HANDLE       RuntimeDriverHandle = NULL;        
        EFI_STATUS       efiStatus;
        
        //
        // Clear screen and make pretty
        //
        gST->ConOut->ClearScreen( gST->ConOut );
        gST->ConOut->SetAttribute( gST->ConOut, EFI_GREEN | EFI_BACKGROUND_LIGHTGRAY );
        
        //
        // Locate the runtime driver
        //
        efiStatus = LocateFile( gRuntimeDriverImagePath, &RuntimeDriverDevicePath );
        if (EFI_ERROR( efiStatus )) {
                Print(L"Can't find %s\n",gRuntimeDriverImagePath);
                goto Exit;
        }

        Print(L"Found %s\n",gRuntimeDriverImagePath);
        Print(L"Boot to it in 5 seconds \n");
        gBS->Stall(5000000UL);
        
        //
        // Load Runtime Driver into memory
        //
        efiStatus = gBS->LoadImage(TRUE, ImageHandle, RuntimeDriverDevicePath,NULL,0,&RuntimeDriverHandle);
        if (EFI_ERROR( efiStatus )) {
                Print(L"Loading %s failed\n",gRuntimeDriverImagePath);
                goto Exit;
        }
        
        //
        // Transfer executon to the Runtime Driver
        //
        efiStatus = gBS->StartImage( RuntimeDriverHandle, (UINTN *)NULL,(CHAR16**)NULL);
        if (EFI_ERROR( efiStatus )) {
                Print(L"Starting %s failed\n",gRuntimeDriverImagePath);
                goto Exit;
        }     
Exit:
        gBS->Stall(15000000UL);
  return EFI_SUCCESS;
}

 

对应的 INF 文件

[Defines]
  INF_VERSION                    = 0x00010005
  BASE_NAME                      = bf
  FILE_GUID                      = b931b80a-9c19-41e1-aa42-474da3f76013
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 1.0
  ENTRY_POINT                    = UefiMain

[Sources]
  bf.c

[Packages]
  MdePkg/MdePkg.dec
  
[LibraryClasses]
  UefiApplicationEntryPoint
  UefiLib

 

在实体机上测试,运行结果如下,随后就开始启动到 Windows中了:

fbw

编写这样的程序特别需要注意地方:
1. 不要在代码中使用 Shell 相关的函数,因为BIOS直接加载你的 EFI Application, 没有其他的人供给你 Shell 提供服务;
2. 可以使用BIOS中直接 Boot From File 功能测试你的代码,这是验证的最简单方法;
3. 将原装的 Windows引导程序改名为 Win.efi,代码会尝试启动这个文件;
4. 确保BIOS中的 Secure Boot 是 Disabled;
5. 能找到或者无法找到启动文件都会停留一段时间再继续。
上面的代码写好之后,就可以去替换 Windows的引导程序了。根据观察正常启动之后,Windows 会创建一个Boot选项,这个选项会加载 fsX:\EFI\Microsoft\Boot\ 下面 , 有时候是 Bootmgr.efi 有时候是Bootmgrw.efi这两个文件(这个可以在 Boot 相关的 Variable 中看到,其中写的是Bootmgr.efi,但是不知道为什么,有时候会用Bootmgrw.efi)。对于我们来说简单起见都替换掉即可。

完整的代码和编译后的X64 EFI Application下载

BeforeWinloader

最后多说一句: 前几天给家里的台式机重装系统,结果中了MBR引导区病毒(Win7系统,GHOST安装的),难以想象时隔将近二十年,仍然活跃着这样的病毒。万幸,现在有了GPT分区,不再需要从MBR进行引导(MBR跑的代码完全没有文件显而易见)再加上现在的 Secure Boot 功能, 相信这样的问题会越来越少吧。

参考:
1. https://github.com/dude719/UEFI-Bootkit

System Power States (转载)

最近在使用 Pets ,研究了一下 Power States, 找到一篇微软的文章【参考1】,有兴趣的朋友可以看一下:

To the user, the system appears to be either on or off. There are no other detectable states. However, the system supports multiple power states that correspond to the power states defined in the Advanced Configuration and Power Interface (ACPI) specification. There are also variations of these states, such as hybrid sleep and fast startup. This topic introduces these states and describes how they relate to each other.

Note  System integrators and developers creating drivers or applications with a system service should be particularly careful of driver quality issues, such as memory leaks. While driver quality has always been important, the up time between kernel reboots may be significantly longer than on previous versions of the OS because on user initiated sleeps and shutdowns, the kernel, drivers, and services will be preserved and restored, not re-started.

The following table lists the ACPI power states from highest to lowest power consumption.

Power state ACPI state Description
Working S0 The system is fully usable. Hardware components that are not in use can save power by entering a lower power state.
Sleep

(Modern Standby)

S0 low-power idle Some SoC systems support a low-power idle state known as Modern Standby. In this state, the system can very quickly switch from a low-power state to high-power state, so that it can respond quickly to hardware and network events. Systems that support Modern Standby do not use S1-S3.
Sleep S1

S2

S3

The system appears to be off. Power consumed in these states (S1-S3) is less than S0 and more than S4; S3 consumes less power than S2, and S2 consumes less power than S1. Systems typically support one of these three states, not all three.

In these states (S1-S3), volatile memory is kept refreshed to maintain the system state. Some components remain powered so the computer can wake from input from the keyboard, LAN, or a USB device.

Hybrid sleep, used on desktops, is where a system uses a hibernation file with S1-S3. The hibernation file saves the system state in case the system loses power while in sleep.

Note  SoC systems that support modern standby (the low-power idle state) do not use S1-S3.
Hibernate S4 The system appears to be off. Power consumption is reduced to the lowest level. The system saves the contents of volatile memory to a hibernation file to preserve system state. Some components remain powered so the computer can wake from input from the keyboard, LAN, or a USB device. The working context can be restored if it is stored on nonvolatile media.

Fast startup is where the user is logged off before the hibernation file is created. This allows for a smaller hibernation file, more appropriate for systems with less storage capabilities.

Soft Off S5 The system appears to be off. This state is comprised of a full shutdown and boot cycle.
Mechanical Off G3 The system is completely off and consumes no power. The system returns to the working state only after a full reboot.

 

The SYSTEM_POWER_STATE enumeration defines values that are used to specify system power states.

Working state (S0)

During the working state, the system is awake and running. In simple terms, the device is “on.” Whether the screen is on or off, the device is in a full running state. To conserve energy, especially on battery powered devices, we highly recommend powering-down hardware components when they’re not being used.

Important  Power-down hardware components whenever they’re not being used – regardless of the state. Low power consumption is an important consideration for mobile device consumers.

Sleep state (Modern Standby)

In the S0 low-power idle mode of the working state, also referred to as Modern Standby, the system remains partially running. During Modern Standby, the system can stay up-to-date whenever a suitable network is available and also wake when real-time action is required, such as OS maintenance. Modern Standby wakes significantly faster than S1-S3. For more info, see Modern Standby.

Note  Modern Standby is only available on some SoC systems. When it’s supported, the system does not support S1-S3.

Sleep state (S1-S3)

The system enters sleep based on a number of criteria, including user or application activity and preferences that the user sets on the Power & sleep page of the Settings app. By default, the system uses the lowest-powered sleep state supported by all enabled wake-up devices. For more information about how the system determines when to enter sleep, see System Sleep Criteria.

Before the system enters sleep, it determines the appropriate sleep state, notifies applications and drivers of the pending transition, and then transitions the system to the sleep state. In the case of a critical transition, such as when the critical battery threshold is reached, the system does not notify applications and drivers. Applications need to be prepared for this and take the appropriate action when the system returns to the working state.

In these states (S1-S3), volatile memory is kept refreshed to maintain the system state. Some components remain powered so the computer can wake from input from the keyboard, LAN, or a USB device.

The system also wakes from sleep in response to user activity or a wake-up event defined by an application. For more information, see System Wake-up Events. The amount of time it takes the system to wake depends on the sleep state it is waking from. The system takes more time to wake from a lower-powered state (S3) than from a higher-powered state (S1) because of the extra work the hardware may have to do (stabilize the power supply, reinitialize the processor, and so forth).

Caution  When calling SetThreadExecutionState, the ES_AWAYMODE_REQUIRED value should be used only when absolutely necessary by media applications that require the system to perform background tasks such as recording television content or streaming media to other devices while the system appears to be sleeping. Applications that do not require critical background processing or that run on portable computers should not enable away mode because it prevents the system from conserving power by entering true sleep.

Hybrid sleep (S1-S3 + hibernation file)

Hybrid sleep is a special state that’s a combination of the sleep and hibernation states, it’s when a system uses a hibernation file with S1-S3. It’s only available on some systems. When enabled, the system writes a hibernation file but enters a higher-powered sleep state. If power is lost while the system is sleeping, the system wakes from hibernation, which takes longer but restores the user’s system state.

Hibernate state (S4)

Windows uses hibernation to provide a fast startup experience. When available, it’s also used on mobile devices to extend the usable battery life of a system by giving a mechanism to save all of the user’s state prior to shutting down the system. In a Hibernate transition, all the contents of memory are written to a file on the primary system drive, the hibernation file. This preserves the state of the operating system, applications, and devices. In the case where the combined memory footprint consumes all of physical memory, the hibernation file must be large enough to ensure there will be space to save all the contents of physical memory. Since data is written to non-volatile storage, DRAM does not need to maintain self-refresh and can be powered off, which means power consumption of hibernation is very low, almost the same as power off.

During a full shutdown and boot (S5), the entire user session is torn down and restarted on the next boot. In contrast, during a hibernation (S4), the user session is closed and the user state is saved.

Fast startup (reduced hibernation file)

Fast startup is a type of shutdown that uses a hibernation file to speed up the subsequent boot. During this type of shutdown, the user is logged off before the hibernation file is created. Fast startup allows for a smaller hibernation file, more appropriate for systems with less storage capabilities. For more info, see Hibernation file types.

When using fast startup, the system appears to the user as though a full shutdown (S5) has occurred, even though the system has actually gone through S4. This includes how the system responds to device wake alarms.

Fast startup logs off user sessions, but the contents of kernel (session 0) are written to hard disk. This enables faster boot.

To programmatically initiate a fast startup-style shutdown, call the InitiateShutdown function with the SHUTDOWN_HYBRID flag or the ExitWindowsEx function with the EWX_HYBRID_SHUTDOWN flag.

Note  Starting in Windows 8, fast startup is the default transition when a system shutdown is requested. A full shutdown (S5) occurs when a system restart is requested (or an application calls a shutdown API).

Entering hibernation

When a hibernate request is made, the following steps occur as the system enters hibernation:

  1. Apps and services are notified
  2. Drivers are notified
  3. User and system state is saved to disk in a compressed format
  4. Firmware is notified
Note  Starting in Windows 8, all cores on the system are used to compress the data in memory and write it to disk.

To programmatically initiate a hibernate transition, call the SetSuspendState function.

Resuming from hibernation

When a system resumes from hibernation.

When a system is powered on, the following steps occur as the system resumes from hibernation.

  1. System POST
  2. System memory is decompressed and restored from the hibernation file
  3. Device initialization
  4. Drivers are restored to the state they were in prior to hibernation
  5. Services are restored to the state they were in prior to hibernation
  6. System becomes available for login

A resume from hibernation starts with a system POST that is similar to an S5 shutdown. The OS boot manager determines that a resume from hibernation is required by detecting a valid hibernation file. Then it directs the system to resume, restoring the contents of memory and all architectural registers. In the case of a resume from hibernation, the contents of the system memory are read back in from the disk, decompressed, and restored, putting the system in the exact state it was in when it was hibernated. After memory is restored, the devices are re-started, the machine returns to a running state, ready for login.

Note  During a resume from hibernation, drivers and services are notified, but are not restarted. They are only restored to the state they were in prior to hibernation.

Hibernation file types

Hibernation files are used for hybrid sleep, fast startup, and standard hibernation (described earlier). There are two types, differentiated by size, a full and reduced size hibernation file. Only fast startup can use a reduced hibernation file.

Hibernation file type Default size Supports…
Full 40% of physical memory hibernate, hybrid sleep, fast startup
Reduced 20% of physical memory fast startup

 

To verify or change the type of hibernation file used, run the powercfg.exe utility. The following examples demonstrate how. For more information, run powercfg /? hibernate.

Example Description
powercfg /a Verify the hibernation file type. When a full hibernation file is used, the results state that hibernation is an available option. When a reduced hibernation file is used, the results will say hibernation is not supported. If the system has no hibernation file at all, the results will say hibernation has not been enabled.
powercfg /h /type full Change the hibernation file type to full. This is not recommended on systems with less than 32GB of storage.
powercfg /h /type reduced Change the hibernation file type to reduced. If the command returns “the parameter is incorrect”, see the following example.
powercfg /h /size 0

powercfg /h /type reduced

Retry changing the hibernation file type to reduced. If the hibernation file is set to a custom size greater than 40%, you must first set the size of the file to zero. Then retry the reduced configuration.

 

Soft Off state (S5)

The soft off state is when the system fully shuts down without a hibernation file. Soft off is also known as a “full shutdown.” During a full shutdown and boot, the entire user session is torn down and restarted on the next boot. Consequently, a boot/startup from this state takes significantly longer than S1-S4. A full shutdown (S5) occurs when a system restart is requested (or an application calls a shutdown API).

Mechanical Off state (G3)

In this state, the system is completely off and consumes no power. The system returns to the working state only after a full reboot.

Wake-on-LAN behavior

The wake-on-LAN (WOL) feature wakes the computer from a low power state when a network adapter detects a WOL event (typically, a specially constructed Ethernet packet).

WOL is supported from sleep (S3) or hibernate (S4). It is not supported from fast startup or soft off (S5) shutdown states. NICs are not armed for wake in these states because users do not expect their systems to wake up on their own.

Note  WOL is not officially supported from soft off (S5). However, the BIOS on some systems may support arming NICs for wake, even though Windows is not involved in the process.
参考:
1.https://msdn.microsoft.com/en-us/library/windows/desktop/aa373229(v=vs.85).aspx

ACPI 内存变量查看工具

这是一个查看ACPI变量的工具。运行在 Windows 64下面:

acpivar

原理介绍:BIOS将数据传递给ASL 的方法是通过内存,比如,在Source Code 中你会看到下面的定义:
C头文件:
typedef struct {
//
// Miscellaneous Dynamic Registers:
//
UINT16 OperatingSystem; ///< Offset 0 Operating System UINT8 SmiFunction; ///< Offset 2 SMI Function Call (ASL to SMI via I/O Trap) UINT8 SmiParameter0; ///< Offset 3 SMIF – Parameter 0 UINT8 SmiParameter1; ///< Offset 4 SMIF – Parameter 1 ………… ASL 定义如下 OperationRegion(GNVS,SystemMemory,0xFFFF0000,0xAA55) Field(GNVS,AnyAcc,Lock,Preserve) { // // Miscellaneous Dynamic Registers: // Offset(0), OSYS, 16, // Offset(0), Operating System Offset(2), SMIF, 8, // Offset(2), SMI Function Call (ASL to SMI via I/O Trap) Offset(3), PRM0, 8, // Offset(3), SMIF – Parameter 0 Offset(4), PRM1, 8, // Offset(4), SMIF – Parameter 1 ….. 可以看到这两个定义是相同的。在平台启动后,反编译ASL会看到类似如下的结果 OperationRegion(GNVS,SystemMemory,0xFFFFF800,0xAA55) Field(GNVS,AnyAcc,Lock,Preserve) 就是说,内存0xFFFFF800地址处,Offset 4 中的SmiParameter1也就是PRM1。这个工具的作用就是将 GNVS 中定义的变量读取显示出来方便Debug。 使用的例子(以KBL-R HDK 平台为例): 1. 在Setup中将HD Audio 方面的 Waves Post-process 选项勾选上,再进入系统运行工具,将结果Dump到文本文件中; 2. 再取消Waves Post-process 选项的勾选,再进入系统运行工具,将结果Dump到文本文件中; 3. 比较两个文本文件,结果如下: acpivar2

这个工具首先取得本机ASL 然后得到内存偏移,再对ASL进行解析取得偏移,最终在内存中读取每个变量的值显示出来。

工具下载(无源程序):

VarAnalyzer

2021年8月23日 Windows 11 下测试成功运行

 

Win11 运行结果

Python 处理大Log文件

最近研究 process monitor,对于取得的Log 需要进行简单的统计得出操作的类型,结果是一个 620000行左右的文件。数据示例如下:

“15:20:33.9935624″,”cmd.exe”,”1784″,”IRP_MJ_CREATE”,”C:\EDK”,”SUCCESS”,”Desired Access: Read Data/List Directory, Synchronize, Disposition: Open, Options: Directory, Synchronous IO Non-Alert, Attributes: n/a, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened”
“15:20:33.9935792″,”cmd.exe”,”1784″,”IRP_MJ_DIRECTORY_CONTROL”,”C:\EDK\build.*”,”SUCCESS”,”Type: QueryDirectory, Filter: build.*, 2: Build”
“15:20:33.9936119″,”cmd.exe”,”1784″,”IRP_MJ_DIRECTORY_CONTROL”,”C:\EDK”,”NO MORE FILES”,”Type: QueryDirectory”
“15:20:33.9936272″,”cmd.exe”,”1784″,”IRP_MJ_CLEANUP”,”C:\EDK”,”SUCCESS”,””
“15:20:33.9936306″,”cmd.exe”,”1784″,”IRP_MJ_CLOSE”,”C:\EDK”,”SUCCESS”,””
“15:20:33.9937049″,”cmd.exe”,”1784″,”IRP_MJ_CREATE”,”C:\EDK”,”SUCCESS”,”Desired Access: Read Data/List Directory, Synchronize, Disposition: Open, Options: Directory, Synchronous IO Non-Alert, Attributes: n/a, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened”
“15:20:33.9937169″,”cmd.exe”,”1784″,”IRP_MJ_DIRECTORY_CONTROL”,”C:\EDK\build”,”SUCCESS”,”Type: QueryDirectory, Filter: build, 2: Build”
“15:20:33.9937342″,”cmd.exe”,”1784″,”IRP_MJ_DIRECTORY_CONTROL”,”C:\EDK”,”NO MORE FILES”,”Type: QueryDirectory”
“15:20:33.9937476″,”cmd.exe”,”1784″,”IRP_MJ_CLEANUP”,”C:\EDK”,”SUCCESS”,””
“15:20:33.9937541″,”cmd.exe”,”1784″,”IRP_MJ_CLOSE”,”C:\EDK”,”SUCCESS”,””
“15:20:33.9938281″,”cmd.exe”,”1784″,”IRP_MJ_CREATE”,”C:\EDK\BaseTools\Bin”,”SUCCESS”,”Desired Access: Read Data/List Directory, Synchronize, Disposition: Open, Options: Directory, Synchronous IO Non-Alert, Attributes: n/a, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened”
“15:20:33.9938586″,”cmd.exe”,”1784″,”IRP_MJ_DIRECTORY_CONTROL”,”C:\EDK\BaseTools\Bin\build.*”,”NO SUCH FILE”,”Type: QueryDirectory, Filter: build.*”
“15:20:33.9938787″,”cmd.exe”,”1784″,”IRP_MJ_CLEANUP”,”C:\EDK\BaseTools\Bin”,”SUCCESS”,””

我需要提取出来IRP_MJ_DIRECTORY_CONTROL 和IRP_MJ_CLEANUP这样的操作记录下来。

听说Python擅长于此,于是简单学习一下进行统计。

第一个问题是如何处理大文件(目前的数据不算大,200MB),在【参考1】找到方法;
第二个问题是如何进行统计的问题。我只需要记录一个操作有还是没有,所以使用字典类型最合适不过;
最终代码如下(Python2.7环境下运行)

class Load_Corpus_with_Iteration(object):
    def __init__(self,path):
        self.path=path

    def __iter__(self):
        for line in open(self.path):
            yield line.split()

corpus = Load_Corpus_with_Iteration('logfile.csv')
operate = {}
index=0
for item in corpus:
    list1 = (item[0].split(','))
    opStr=list1[3]
    operate[opStr]=1
    index=index+1
    if index % 10000 ==0:
        print index,str(operate)

 

结果如下(为了便于阅读,经过简单排版)

620000 {
‘”IRP_MJ_DIRECTORY_CONTROL”‘: 1,
‘”FASTIO_READ”‘: 1,
‘”IRP_MJ_READ”‘: 1,
‘”FASTIO_LOCK”‘: 1,
‘”FASTIO_RELEASE_FOR_SECTION_SYNCHRONIZATION”‘: 1,
‘”IRP_MJ_CLOSE”‘: 1,
‘”IRP_MJ_QUERY_INFORMATION”‘: 1,
‘”IRP_MJ_SET_INFORMATION”‘: 1,
‘”FASTIO_ACQUIRE_FOR_SECTION_SYNCHRONIZATION”‘: 1,
‘”FASTIO_QUERY_INFORMATION”‘: 1,
‘”IRP_MJ_WRITE”‘: 1,
‘”FASTIO_ACQUIRE_FOR_CC_FLUSH”‘: 1,
‘”IRP_MJ_FILE_SYSTEM_CONTROL”‘: 1,
‘”IRP_MJ_QUERY_VOLUME_INFORMATION”‘: 1,
‘”FASTIO_WRITE”‘: 1,
‘”IRP_MJ_CREATE”‘: 1,
‘”FASTIO_NETWORK_QUERY_OPEN”‘: 1,
‘”FASTIO_RELEASE_FOR_CC_FLUSH”‘: 1,
‘”FASTIO_UNLOCK_SINGLE”‘: 1, ‘
“IRP_MJ_CLEANUP”‘: 1,
‘”FASTIO_CHECK_IF_POSSIBLE”‘: 1}

参考:
1. https://blog.csdn.net/chixujohnny/article/details/53069988

WinDBG 做 APCI debug 后续

之前介绍过如何在RS1 之后的 Windows使用WinDBG做ASL 的Debug。最近我在 RS3 上再次实验发现有如下错误:

6: kd> !amli find _ptsAMLI_DBGERR: failed to read NameSpace root object

该做的动作都做了,但是仍然无法调试。查找资料在【参考1】看到这个问题的可能原因如下

  1. Checked Acpi.sys和Acpi.pdb文件和debuggee版本不符导致的。
  2. WinDbg没有load Acpi符号文件,只要.reload即可。

首先检查 Acpi.sys 和系统的版本,匹配无误。接下来就是没有 Load 起来 acpi.pdb的问题了。

运行 .reload 看到下面的信息:

SYMSRV:  UNC: C:\ProgramData\Dbg\sym\acpi.pdb\63383A79DFA1FA1BCAF8F9BE8ADA117E1\acpi.pdb – path not found

SYMSRV:  UNC: C:\ProgramData\Dbg\sym\acpi.pdb\63383A79DFA1FA1BCAF8F9BE8ADA117E1\acpi.pd_ – path not found

SYMSRV:  UNC: C:\ProgramData\Dbg\sym\acpi.pdb\63383A79DFA1FA1BCAF8F9BE8ADA117E1\file.ptr – path not found

SYMSRV:  HTTPGET: /download/symbols/acpi.pdb/63383A79DFA1FA1BCAF8F9BE8ADA117E1/acpi.pdb

 

SYMSRV:  HttpQueryInfo: 80190194 – HTTP_STATUS_NOT_FOUND

SYMSRV:  HTTPGET: /download/symbols/acpi.pdb/63383A79DFA1FA1BCAF8F9BE8ADA117E1/acpi.pd_

SYMSRV:  HttpQueryInfo: 80190194 – HTTP_STATUS_NOT_FOUND

SYMSRV:  HTTPGET: /download/symbols/acpi.pdb/63383A79DFA1FA1BCAF8F9BE8ADA117E1/file.ptr

 

SYMSRV:  HttpQueryInfo: 80190194 – HTTP_STATUS_NOT_FOUND

SYMSRV:  RESULT: 0x80190194

DBGHELP: acpi.pdb – file not found

*** ERROR: Symbol file could not be found.  Defaulted to export symbols for ACPI.sys –

DBGHELP: ACPI – export symbols

 

确实无法找到能和我给系统装入的 acpi.sys 匹配的 ACPI.pdb。接下来尝试使用.reload /f 强制更新

结果是仍然无法找到:

SYMSRV:  BYINDEX: 0x3B

C:\ProgramData\Dbg\sym

acpi.pdb

63383A79DFA1FA1BCAF8F9BE8ADA117E1

SYMSRV:  UNC: C:\ProgramData\Dbg\sym\acpi.pdb\63383A79DFA1FA1BCAF8F9BE8ADA117E1\acpi.pdb – path not found

SYMSRV:  UNC: C:\ProgramData\Dbg\sym\acpi.pdb\63383A79DFA1FA1BCAF8F9BE8ADA117E1\acpi.pd_ – path not found

SYMSRV:  UNC: C:\ProgramData\Dbg\sym\acpi.pdb\63383A79DFA1FA1BCAF8F9BE8ADA117E1\file.ptr – path not found

SYMSRV:  RESULT: 0x80070003

SYMSRV:  BYINDEX: 0x3C

https://msdl.microsoft.com/download/symbols

acpi.pdb

63383A79DFA1FA1BCAF8F9BE8ADA117E1

SYMSRV:  UNC: C:\ProgramData\Dbg\sym\acpi.pdb\63383A79DFA1FA1BCAF8F9BE8ADA117E1\acpi.pdb – path not found

SYMSRV:  UNC: C:\ProgramData\Dbg\sym\acpi.pdb\63383A79DFA1FA1BCAF8F9BE8ADA117E1\acpi.pd_ – path not found

SYMSRV:  UNC: C:\ProgramData\Dbg\sym\acpi.pdb\63383A79DFA1FA1BCAF8F9BE8ADA117E1\file.ptr – path not found

SYMSRV:  HTTPGET: /download/symbols/acpi.pdb/63383A79DFA1FA1BCAF8F9BE8ADA117E1/acpi.pdb

SYMSRV:  HttpQueryInfo: 80190194 – HTTP_STATUS_NOT_FOUND

SYMSRV:  HTTPGET: /download/symbols/acpi.pdb/63383A79DFA1FA1BCAF8F9BE8ADA117E1/acpi.pd_

SYMSRV:  HttpQueryInfo: 80190194 – HTTP_STATUS_NOT_FOUND

SYMSRV:  HTTPGET: /download/symbols/acpi.pdb/63383A79DFA1FA1BCAF8F9BE8ADA117E1/file.ptr

 

SYMSRV:  HttpQueryInfo: 80190194 – HTTP_STATUS_NOT_FOUND

SYMSRV:  RESULT: 0x80190194

DBGHELP: acpi.pdb – file not found

*** ERROR: Symbol file could not be found.  Defaulted to export symbols for ACPI.sys –

DBGHELP: ACPI – export symbols

 

在另外一篇文章【参考2】中,提到了另外的检查方法,使用这个方法检查 ACPI 模块的情况,结果相同,还是没有找到 ACPI.SYS对应的 PDB:

1: kd> !lmi acpiLoaded Module Info: [acpi]          Module: ACPI   Base Address: fffff80605c50000     Image Name: ACPI.sys   Machine Type: 34404 (X64)     Time Stamp: 64683d0c (This is a reproducible build file hash, not a true timestamp)           Size: 124000       CheckSum: c515bCharacteristics: 22  Debug Data Dirs: Type  Size     VA  Pointer             CODEVIEW    21, 7a69c,   7909c RSDS – GUID: {63383A79-DFA1-FA1B-CAF8-F9BE8ADA117E}               Age: 1, Pdb: acpi.pdb                 POGO   208, 7a6c0,   790c0 [Data not mapped]                REPRO     0,     0,       0  [Debug data not mapped]     Image Type: MEMORY   – Image read successfully from loaded memory.    Symbol Type: EXPORT   – PDB not found    Load Report: export symbols

 

至此,问题很明确:无法找到 acpi.pdb所以无法调试。再回去提供 checked 版本的ACPI.SYS的包中查找,其中提供了 ACPI.PDB。因此,就是说如果我将这个指定给 ACPI.SYS应该就可以继续调试了。直接将这个文件COPY到工作机的Software目录下。

 

检查当前 symbol 的路径

1: kd> .sympath Symbol search path is: srv*Expanded Symbol search path is: cache*;SRV*https://msdl.microsoft.com/download/symbols

 

将software 目录添加到symbol 的path下【参考3】

 

1: kd> .sympath+ C:\software\DBGHELP: Symbol Search Path: cache*;SRV*https://msdl.microsoft.com/download/symbols;c:\software\SYMSRV:  BYINDEX: 0x11B         C:\ProgramData\Dbg\sym         ntkrnlmp.pdb         83DB42404EFD4AB6AFB6FA864B700CB31SYMSRV:  PATH: C:\ProgramData\Dbg\sym\ntkrnlmp.pdb\83DB42404EFD4AB6AFB6FA864B700CB31\ntkrnlmp.pdbSYMSRV:  RESULT: 0x00000000DBGHELP: C:\ProgramData\Dbg\sym\ntkrnlmp.pdb\83DB42404EFD4AB6AFB6FA864B700CB31\ntkrnlmp.pdb cached to C:\ProgramData\Dbg\sym\ntkrnlmp.pdb\83DB42404EFD4AB6AFB6FA864B700CB31\ntkrnlmp.pdb DBGHELP: nt – public symbols          C:\ProgramData\Dbg\sym\ntkrnlmp.pdb\83DB42404EFD4AB6AFB6FA864B700CB31\ntkrnlmp.pdbSymbol search path is: srv*;C:\software\Expanded Symbol search path is: cache*;SRV*https://msdl.microsoft.com/download/symbols;c:\software\ ************* Path validation summary **************Response                         Time (ms)     LocationDeferred                                       srv*OK                                             C:\software\

执行一次 .reload指令,再检查acpi

1: kd> !lmi acpi

Loaded Module Info: [acpi]

Module: ACPI

Base Address: fffff80605c50000

Image Name: ACPI.sys

Machine Type: 34404 (X64)

Time Stamp: 64683d0c (This is a reproducible build file hash, not a true timestamp)

Size: 124000

CheckSum: c515b

Characteristics: 22

Debug Data Dirs: Type  Size     VA  Pointer

CODEVIEW    21, 7a69c,   7909c RSDS – GUID: {63383A79-DFA1-FA1B-CAF8-F9BE8ADA117E}

Age: 1, Pdb: acpi.pdb

POGO   208, 7a6c0,   790c0 [Data not mapped]

REPRO     0,     0,       0  [Debug data not mapped]   

Symbol Type: DEFERRED – No error – symbol load deferred   

Load Report: no symbols loaded

 

再次使用命令调试 acpi 就可以正常的工作了

 

1: kd> !amli dl

0:01:46.655 [ffffca82185a62c0] FinishedContext       Context=ffffca821f847010 rc=8004

QTh=0 QCt=0 QFg=00000000

 

0:01:46.655 [ffffca82185a62c0] QueueWorkItem

QTh=0 QCt=0 QFg=00000000 rc=8004

总结:出现这样的问题应该是我的Win10版本比较特殊,无法在微软公共Server上找到对应的 ACPI.SYS Symbol 所以导致的解析错误。手工加载对应的 PDB 文件即可。

参考:

  1. http://www.xuebuyuan.com/611480.html
  2. http://blog.csdn.net/whatday/article/details/7100292
  3. https://www.2cto.com/kf/201611/562340.html

 

说说 Arduino 101的 PWM频率

之前介绍过 Arduino Uno 的 PWM 频率问题,最近因为需要研究了一下 Arduino 101 的 PWM 频率问题。经过一番研究,发现在Arduino15\packages\Intel-Test@arduino.cn\hardware\arc32\2.0.0\cores\arduino\wiring_analog.c 中提供了analogWriteFrequency 函数。

/*
 * brief Set the frequency of analogWrite parameters.
 *
 * param res
 */
extern void analogWriteFrequency(uint8_t pin, uint32_t freq);

 

从参数上来看,只要在 freq 指定一个频率,就可以输出这个频率的 PWM信号。
首先,测试一下 PWM 的默认频率:

void setup() {
  // initialize digital pin 13 as an output.
  pinMode(6, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  analogWrite(6,127);
}

 

pwma

可以看到,对于 Pin6 默认的PWM 频率是 980Hz
接下来,试试 64KHz:

void setup() {
  // initialize digital pin 13 as an output.
  pinMode(6, OUTPUT);
  analogWriteFrequency(6, 64000);
}

 

pwmb

频率为 63.747Khz。
继续用这样的方法,升高频率到 250K,可以看到频率是 246.18Khz。

pwmc

继续升高到1Mhz
pwmd

实验程序,最高可以发出 16Mhz的频率。
然后就是区分度的问题,这个词是我创造的,我想表达的是 pwm升高1之后是否有正常的变化。比如:我们PWM 写入8位,就是分成256份。一份对应 1/256=0.39%。就是说,正常情况下,anglogWrite(PinX,1) 和anglogWrite(PinX,2)在占空比上应该有 0.39%的差别。份数越少,区分度越差。

Step to UEFI (146)Grayoutif ,Suppressif和Setup联动的探索

Grayoutif和Suppressif是比较常用的控制命令。Grayoutif的作用是设定某一个 item 跟随另一个 item 的变化而被设置为灰色无法修改【参考1】。Suppressif的作用是设定某一个 item 跟随另一个 item 的变化而被自动隐藏【参考2】。除了在使用的时候特别需要注意和 XXX_END 配对之外,这两个选项都不会影响被设置的Item的设定值,比如,选项隐藏之前是 Enabled 的,那么虽然隐藏掉了, 实际取值还是 Enabled。上面的结论可以通过设置之后进入 Shell 使用 dmpstore 命令查看对应的变量来验证。

此外有些时候,我们需要设定当选中一个选项后,另外的Item取值跟着变化(我记得有一个名词叫做“联动”)。下面就在 NT32 的环境中编写代码实现这个需求。
实验的环境是UDK2017。在 Setup -> Device Manager -> Browser Testcase Engine 下面有一个 Item “My one-of prompt #1”,我们在上面添加更多的选项来进行实验。

ss1

首先找到“My one-of prompt #1” Item,再其中加入一个选项“Disable Checkbox”,然后再声明这个为 INTERACTIVE

    //
    // Define oneof (EFI_IFR_ONE_OF)
    //
    oneof name = MyOneOf,                                // Define reference name for Question
      varid   = MyIfrNVData.SuppressGrayOutSomething,    // Use "DataStructure.Member" to reference Buffer Storage
      questionid = 0x2018,
      prompt  = STRING_TOKEN(STR_ONE_OF_PROMPT),
      help    = STRING_TOKEN(STR_ONE_OF_HELP),
      flags  = INTERACTIVE,
      //
      // Define an option (EFI_IFR_ONE_OF_OPTION)
      //
      option text = STRING_TOKEN(STR_ONE_OF_TEXT4), value = 0x0, flags = 0;
      option text = STRING_TOKEN(STR_ONE_OF_TEXT5), value = 0x1, flags = 0;
      //
      // DEFAULT indicate this option will be marked with EFI_IFR_OPTION_DEFAULT
      //
      option text = STRING_TOKEN(STR_ONE_OF_TEXT6), value = 0x2, flags = DEFAULT;
      option text = STRING_TOKEN(STR_ONE_OF_TEXT7), value = 0x3, flags = DEFAULT;      
endoneof;

 

处理的代码在 \MdeModulePkg\Universal\DriverSampleDxe\DriverSample.c 中
EFI_BROWSER_ACTION_CHANGING 处理的是之前的选项,比如,打开 Item 之后,你从第三项选择为第一项,那么Configuration->SuppressGrayOutSomething 的值是0;
EFI_BROWSER_ACTION_CHANGED处理的是当前的选项,比如,打开 Item 之后,你从第三项选择为第一项,那么Configuration->SuppressGrayOutSomething 的值是2;
例如,我们从 Enable Checkbox 切换为 Disable Checkboxss5

Debug 信息会有如下输出:

ss3

代码如下:

  case EFI_BROWSER_ACTION_CHANGED:
    switch (QuestionId) {
     //LABZ_Start
     case 0x2018:
      {
      //
      // Set initial vlaue of dynamic created oneof Question in Form Browser
      //
      Configuration = AllocateZeroPool (sizeof (DRIVER_SAMPLE_CONFIGURATION));
      ASSERT (Configuration != NULL);
      if (HiiGetBrowserData (&gDriverSampleFormSetGuid, VariableName, sizeof (DRIVER_SAMPLE_CONFIGURATION), (UINT8 *) Configuration)) {
                DEBUG ((EFI_D_ERROR, "Changed to[%d]\n",Configuration->SuppressGrayOutSomething));
                if (Configuration->SuppressGrayOutSomething == 2) {
                        Configuration->ChooseToActivateNuclearWeaponry=TRUE;
                }
                if (Configuration->SuppressGrayOutSomething == 3) {
                        Configuration->ChooseToActivateNuclearWeaponry=FALSE;
                }
        //
        // Update uncommitted data of Browser
        //
        HiiSetBrowserData (
          &gDriverSampleFormSetGuid,
          VariableName,
          sizeof (DRIVER_SAMPLE_CONFIGURATION),
          (UINT8 *) Configuration,
          NULL
          );
              
      }
       FreePool (Configuration);
      }
    break;             
    //LABZ_End

设置这个选项为 Disable 和 Enable 后,下面的 CheckBox 会跟着发生变化.

ss4

ss5

通过这样的功能,可以设计出方便用户使用的功能。比如,通过一个选项关闭多个影响OS 下 BIOS 刷写的选项,这样就免得用户一个个进行查找和设置。因为实验可以在NT32的模拟环境下方便的进行,有兴趣的朋友可以直接试试。

参考:

1. http://wiki.phoenix.com/wiki/index.php/EFI_IFR_SUPPRESS_IF
EFI IFR SUPPRESS IF
Creates a group of statements or questions which are conditionally invisible.

Prototype
#define EFI_IFR_SUPPRESS_IF_OP 0x0a
typedef struct _EFI_IFR_SUPPRESS_IF {
EFI_IFR_OP_HEADER Header;
} EFI_IFR_SUPRESS_IF;
Members
Member Description
Header The byte sequence that defines the type of opcode as well as the length of the opcode being defined. Header.OpCode = EFI_IFR_SUPPRESS_IF_OP.
Description
The suppress tag causes the nested objects to be hidden from the user if the expression appearing as the first nested object evaluates to TRUE. If the expression consists of more than a single opcode, then the first opcode in the expression must have the Scope bit set and the expression must end with EFI_IFR_END.

This display form is maintained until the scope for this opcode is closed.

2. http://wiki.phoenix.com/wiki/index.php/EFI_IFR_GRAY_OUT_IF
EFI IFR GRAY OUT IF
Creates a group of statements or questions which are conditionally grayed-out.

Prototype
#define EFI_IFR_GRAY_OUT_IF_OP 0x19
typedef struct _EFI_IFR_GRAY_OUT_IF {
EFI_IFR_OP_HEADER Header;
} EFI_IFR_GRAY_OUT_IF;
Members
Member Description
Header The byte sequence that defines the type of opcode as well as the length of the opcode being defined. Header.OpCode = EFI_IFR_GRAY_OUT_IF_OP.
Description
All nested statements or questions will be grayed out (not selectable and visually distinct) if the expression appearing as the first nested object evaluates to TRUE. If the expression consists of more than a single opcode, then the first opcode in the expression must have the Scope bit set and the expression must end with EFI_IFR_END.

Different browsers may support this option to varying degrees. For example, HTML has no similar construct so it may not support this facility.

示波器测量串口电压

测试的是串口输出上的 TX Pin,

1. 测试下面这个USB转串口公头模块(FTDI),测试Pin3

uart1

结果如下,特别注意,单位是 5V/Div, 出现了负电压

uart12

2. 再测试下面这个模块(FTDI),上面有一个拨动开关可以选择 切换5V和3.3V
uart13

2.1 先测试一下 3.3,结果如下

uart14

2.2 我们再测试一下 5V 项
uart15

从上面可以看到,当我们谈论串口的时候,电压有可能是从-12v到5v。特别是当我们看到标准的串口头时,一定要多留心一下他的电压,贸然的连接很可能导致设备的悲剧。