Compiler Warning C4131

在尝试编译老旧的代码时,你可能遇到 C4131 Warning, 给出来的提示是 “uses old-style declarator”。 这是因为你的代码使用了旧式的生命方式

比如:

// C4131.c
// compile with: /W4 /c
void addrec( name, id ) // C4131 expected
char *name;
int id;
{ }

 

这个定义会导致上面的 warning。修改为下面的即可

 void addrec( char *name, int id )
 { }

 

更多信息可以在
https://msdn.microsoft.com/en-us/library/b92s55e9(v=vs.90).aspx 看到

Debug Message 标记工具

对于庞大的代码,串口 Message 提供了最好的追踪方法。但是很多时候,我们的代码会有重复的文件,在对照阅读的时候就会非常麻烦。一种方法是之前文章介绍过的使用 __FILE__ 的方法,唯一的问题是这个宏经常导致代码在Debug 模式下爆掉(很大原因是因为Debug模式下这个宏会加入路径信息)。因此,编写这个工具,具体的原理是:打开所有的 C 文件,查找 DEBUG宏,然后在它的字符串起始处加入 “(序号)”这样的标记。序号是由 0-9和A-Z组成的。更改代码之后,再次编译,串口输出的内容就有序号+原先的字符串,能够很方便的分析出来源。

特别注意:某些情况下可能会导致源文件的错误,这是目前分析的手法决定的。不过从我的实践来看,EDK代码不会有问题,某些工程文件可能会有1到2处标记错误,手动修改去掉即可。

这是我在某个BIOS工程上直接实验的结果:

dm

可执行程序和完整代码下载

DebugMark

MPR121 触摸传感器模块

MPR121 是一款触摸传感器芯片,原理是通过检测电容变化来判断当前是否有触摸(接近)。

主要电器特性如下【参考1】:
1. 工作电压1.71-3.6v(芯片工作电压)
2. 通讯接口为 I2C
3. 12个检测端口
4. 带有1个 IRQ端口

我是在Taobao购买的模块,价格是16元【参考3】。经过搜索,这是仿sparkfun的,更多资料可以在【参考2】看到。

模块长得下面这样,有一个降压芯片,看起来可以直接使用 5V 供电。上面有12个口,可以接12个触摸按钮。IRQ 的作用是发出中断通知上面有触摸。ADD是芯片的I2C地址选择,接GND VDD SDA或者 SCL 地址分别是 0x5A 0x5B 0x5C 和 0x5D【来自参考4】。

image001

图片来自【参考2】

下面的代码可以正常工作(卖家的例程,有一些修改可以在 1.6.0 上编译通过)

#include "mpr121.h"
#include <Wire.h>

#define SENSORS       13
#define TOU_THRESH    0x1F
#define REL_THRESH    0x1A
#define PROX_THRESH   0x3f
#define PREL_THRESH   0x3c

// variables: capacitive sensing
bool touchStates[SENSORS];    // holds the current touch/prox state of all sensors
bool activeSensors[SENSORS] = {1,1,1,1,1,1,1,1,1,1,1,1,1}; // holds which sensors are active (0=inactive, 1=active)
bool newData = false;         // flag that is set to true when new data is available from capacitive sensor
int irqpin = 2;               // pin that connects to notifies when data is available from capacitive sensor

void setup(){

  // attach interrupt to pin - interrupt 1 is on pin 2 of the arduino (confusing I know)
  attachInterrupt(0, dataAvailable, FALLING);

  // set-up the Serial and I2C/Wire connections
  Serial.begin(9600);
  Wire.begin();

  // set the registers on the capacitive sensing IC
  setupCapacitiveRegisters();

}

void loop(){
  readCapacitiveSensor();
}

/**
 * dataAvailable Callback method that runs whenever new data becomes available on from the capacitive sensor. 
 *   This method was attached to the interrupt on pin 2, and is called whenever that pins goes low.
 */
void dataAvailable() {
  newData = true;
}

/**
 * readCapacitiveSensor Reads the capacitive sensor values from the MP121 IC. It makes a request to
 *   the sensor chip via the I2C/Wire connection, and then parses the sensor values which are stored on
 *   the first 13 bits of the 16-bit response msg.
 */
void readCapacitiveSensor(){
  if(newData){    
            Serial.println("yes");      
    //read the touch state from the MPR121
    Wire.requestFrom(0x5A,2); 
    byte tLSB = Wire.read();
    byte tMSB = Wire.read();
    uint16_t touched = ((tMSB << 8) | tLSB); //16bits that make up the touch states

    for (int i = 0; i < SENSORS; i++){  // Check what electrodes were pressed
      if (activeSensors[i] == 0) continue;
      char sensor_id [] = {'\0','\0','\0'};
      switch (i) {
        case 12:
          sensor_id[0] = 'P';
          break;
        default:
          if (i < 10) {
            sensor_id[0] = char( i+48 );
          } 
          else if (i < 12) {
            sensor_id[0] = char('1');
            sensor_id[1] = char( ( i % 10 ) + 48 );
          } 
      }
      if (sensor_id != '\0') {
        // read the humidity level

        // if current sensor was touched (check appropriate bit on touched var)
        if(touched & (1<<i)){      
          // if current pin was not previously touched send a serial message
          if(touchStates[i] == 0){          
            Serial.print(sensor_id);        
            Serial.print(":");
            Serial.println("1");
          } 
          touchStates[i] = 1;      
        } else {
          // if current pin was just touched send serial message
          if(touchStates[i] == 1){
            Serial.print(sensor_id);
            Serial.print(":");
            Serial.println("0");
          }
          touchStates[i] = 0;
        }        
      }
    }
    newData = false;
  }
}

/**
 * setupCapacitiveRegisters Updates all of configurations on the MP121 capacitive sensing IC. This includes
 *   setting levels for all filters, touch and proximity sensing activation and release thresholds, debounce,
 *   and auto-configurations options. At the end it activates all of the electrodes.
 */
void setupCapacitiveRegisters(){

  set_register(0x5A, ELE_CFG, 0x00); 
  
  // Section A - filtering when data is > baseline.
    // touch sensing
    set_register(0x5A, MHD_R, 0x01);
    set_register(0x5A, NHD_R, 0x01);
    set_register(0x5A, NCL_R, 0x00);
    set_register(0x5A, FDL_R, 0x00);

    // prox sensing 
    set_register(0x5A, PROX_MHDR, 0xFF);
    set_register(0x5A, PROX_NHDAR, 0xFF);
    set_register(0x5A, PROX_NCLR, 0x00);
    set_register(0x5A, PROX_FDLR, 0x00);

  // Section B - filtering when data is < baseline.
    // touch sensing
    set_register(0x5A, MHD_F, 0x01);
    set_register(0x5A, NHD_F, 0x01);
    set_register(0x5A, NCL_F, 0xFF);
    set_register(0x5A, FDL_F, 0x02);
  
    // prox sensing
    set_register(0x5A, PROX_MHDF, 0x01);
    set_register(0x5A, PROX_NHDAF, 0x01);
    set_register(0x5A, PROX_NCLF, 0xFF);
    set_register(0x5A, PROX_NDLF, 0xFF);

  // Section C - Sets touch and release thresholds for each electrode
    set_register(0x5A, ELE0_T, TOU_THRESH);
    set_register(0x5A, ELE0_R, REL_THRESH);
   
    set_register(0x5A, ELE1_T, TOU_THRESH);
    set_register(0x5A, ELE1_R, REL_THRESH);
    
    set_register(0x5A, ELE2_T, TOU_THRESH);
    set_register(0x5A, ELE2_R, REL_THRESH);
    
    set_register(0x5A, ELE3_T, TOU_THRESH);
    set_register(0x5A, ELE3_R, REL_THRESH);
    
    set_register(0x5A, ELE4_T, TOU_THRESH);
    set_register(0x5A, ELE4_R, REL_THRESH);
    
    set_register(0x5A, ELE5_T, TOU_THRESH);
    set_register(0x5A, ELE5_R, REL_THRESH);
    
    set_register(0x5A, ELE6_T, TOU_THRESH);
    set_register(0x5A, ELE6_R, REL_THRESH);
    
    set_register(0x5A, ELE7_T, TOU_THRESH);
    set_register(0x5A, ELE7_R, REL_THRESH);
    
    set_register(0x5A, ELE8_T, TOU_THRESH);
    set_register(0x5A, ELE8_R, REL_THRESH);
    
    set_register(0x5A, ELE9_T, TOU_THRESH);
    set_register(0x5A, ELE9_R, REL_THRESH);
    
    set_register(0x5A, ELE10_T, TOU_THRESH);
    set_register(0x5A, ELE10_R, REL_THRESH);
    
    set_register(0x5A, ELE11_T, TOU_THRESH);
    set_register(0x5A, ELE11_R, REL_THRESH);

  // Section D - Set the touch filter Configuration
    set_register(0x5A, FIL_CFG, 0x04);  

  // Section E - Set proximity sensing threshold and release
    set_register(0x5A, PRO_T, PROX_THRESH);   // sets the proximity sensor threshold
    set_register(0x5A, PRO_R, PREL_THRESH);   // sets the proximity sensor release

  // Section F - Set proximity sensor debounce
    set_register(0x59, PROX_DEB, 0x50);  // PROX debounce

  // Section G - Set Auto Config and Auto Reconfig for prox sensing
    set_register(0x5A, ATO_CFGU, 0xC9);  // USL = (Vdd-0.7)/vdd*256 = 0xC9 @3.3V   
    set_register(0x5A, ATO_CFGL, 0x82);  // LSL = 0.65*USL = 0x82 @3.3V
    set_register(0x5A, ATO_CFGT, 0xB5);  // Target = 0.9*USL = 0xB5 @3.3V
    set_register(0x5A, ATO_CFG0, 0x0B);

  // Section H - Start listening to all electrodes and the proximity sensor
    set_register(0x5A, ELE_CFG, 0x3C);
}

/**
 * set_register Sets a register on a device connected via I2C. It accepts the device's address, 
 *   register location, and the register value.
 * @param address The address of the I2C device
 * @param r       The register's address on the I2C device
 * @param v       The new value for the register
 */
void set_register(int address, unsigned char r, unsigned char v){
  Wire.beginTransmission(address);
  Wire.write(r);
  Wire.write(v);
  Wire.endTransmission();
}

 

运行结果:

image004

完整的代码下载

MPR121

参考:
1. http://wenku.baidu.com/link?url=77EtEpflHOBF9LmqwOvIwe5ONZ6I548h4BcBk4Ep1XWVO_RVDj9fycwoku44RENseV48lzvnrnDasY3UAMHsBuuU7yVdxFsAfxq-zbDiEhy MPR121中文数据手册
2. https://learn.sparkfun.com/tutorials/mpr121-hookup-guide
3. https://item.taobao.com/item.htm?spm=a1z09.2.0.0.kpoNRc&id=19968128319&_u=pkf8s90f4c
4. MPR121 DataSheet

===============================================================================
额外说一下这个传感器在 Pro Micro 上的连接方法:

1. Pro Micro 的中断:“The Pro Micro has five external interrupts, which allow you to instantly trigger a function when a pin goes either high or low (or both). If you attach an interrupt to an interrupt-enabled pin, you’ll need to know the specific interrupt that pin triggers: pin 3 maps to interrupt 0, pin 2 is interrupt 1, pin 0 is interrupt 2, pin 1 is interrupt 3, and pin 7 is interrupt 4.”
推荐 使用 Pin7-Interrupt 4
2. Pro Micro Pin2- SDA Pin3-SCL

VC 中的 __FILE__ 宏

VC 中有一个 __FILE__ 宏定义,表示当前文件,比如,下面的程序就可以输出编译期的源文件名。

#include "stdafx.h"
#include "stdio.h"

int _tmain(int argc, _TCHAR* argv[])
{
	printf(__FILE__);
	getchar();
	return 0;
}

 

我们在BIOS中经常看到的 ASSERT 就使用这个宏来准确的输出出现错误的位置。

此外,在 Release 模式下这个宏只包括文件名,Debug 模式下这个宏会输出完整的路径。

debug

release

从屏幕输出的方法

之前,我写过一篇“Arduino 打造自动输入器”【参考1】。文章的应用场景是“某些时候因为一些特殊的原因,使得我们不能直接使用U盘之类的存储设备”。在这样的条件下,我们可以用 Arduino打造一个虚拟键盘,一个字节一个字节的敲入我们期望的程序。有了输入内容的方法,接下来的问题是:如何把需要的内容输出出来。本文给出一个方法:将要输出的文件,转化为二维码通过屏幕输出,用户再用手机对着屏幕进行识别。
大多数人都不希望看着长篇的代码,这里我只是列出来大概的思路,有需要的朋友可以在后面下载到Delphi编写的代码。
具体方法是:将欲传文件切为一定的大小(决定大小的是QR Code的容量【参考2】,屏幕分辨率和你手机的摄像头的分辨率),然后通过程序将十六进制表示的字节转换为字符串,再通过程序生成一张张二维码,之后显示在屏幕上就可以通过手机来识别,识别之后可以发送到邮箱,再用另外的程序把所有的文件“粘”起来就恢复原样了。
下面是一个具体的操作例子。
首先选择文件,这里我们选一个比较小的文件。

image001

程序会将文件转换为 QR_Code,这里我直接生成的是BMP,体积较大。切成了 6 个图片。

image002

image003

然后一边显示,一边用手机拍照(半自动)。

image004

这个照片中展示的是 ZXing 软件进行识别,不过最后我发现小米手机的二维码扫描工具,感觉识别率和容错能力更好。

image005

这里手工粘贴下来(我使用的二维码生成控件有问题,无法生成数字0 ,所以我代码上用 “-” 来替代了所有的 “0”)。
image006

把每个文件的扫描结果单独存放在一个个*.labz文件中,使用替换方法将“-”替换为“0”,再使用另外的Delphi编写的工具把他们转换为十六进制。
image007

替换之后会生成 0001.bin 这样的文件,最终用批处理将他们粘在一起就好了。

image008

最终结果和原始文件没有差别。

image009

完整的工具下载
Demo

File2Image

TxtToBin

参考:
1. http://www.lab-z.com/ardkey/ Arduino 打造自动输入器
2. GBT 18284-2000 快速响应矩阵码

Step to UEFI Tips

最近写程序遇到了一个非常奇怪的问题,化简问题如下:
1. 定义 CHAR8 大小的 Buffer[4]
2. 其中赋值为 128 82 0 0
3. 将他们通过下面的公式合成为一个 INT32
Buffer[0]+(Buffer[1]<<8) +(Buffer[2]<<16)+ (Buffer[3]<<24); 4. 我们期望得到 0x5280=21120, 但是给出来的结果却是 20864 编写程序如下,我们从命令行接收参数,然后转换为数值。

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


extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
	CHAR8	Buffer[4];
	UINTN	FileSize=0;

	Print(L"Argv [%s %s %s %s]\n",
			Argv[1],Argv[2],Argv[3],Argv[4]);	
			
	#pragma warning(disable:4244)
	Buffer[0]=StrDecimalToUintn(Argv[1]);
	Buffer[1]=StrDecimalToUintn(Argv[2]);
	Buffer[2]=StrDecimalToUintn(Argv[3]);
	Buffer[3]=StrDecimalToUintn(Argv[4]);

	Print(L"Buffer [%x %x %x %x]\n",
			Buffer[0],Buffer[1],Buffer[2],Buffer[3]);		
			
	FileSize=Buffer[0]+
		(Buffer[1]<<8)+
		(Buffer[2]<<16)+
		(Buffer[3]<<24);	

	Print(L"File Size = [%d]\n",FileSize);		
				
  return EFI_SUCCESS;
}

 

运行结果:

tipsa

为了Debug,需要打开生成汇编代码的功能,方法是在工程的 inf 文件 [BuildOptions] 下面加入如下语句:

[BuildOptions]
  MSFT:*_*_IA32_CC_FLAGS  = /FAsc

 

再次编译即可在Build目录下看到生成的 cod 文件

tipsb

关键代码部分:

; 28   : 
; 29   : 	Print(L"Buffer [%x %x %x %x]\n",
; 30   : 			Buffer[0],Buffer[1],Buffer[2],Buffer[3]);		

  00048	0f be 7c 24 3e	 movsx	 edi, BYTE PTR _Buffer$[esp+50]
  0004d	0f be 6c 24 3d	 movsx	 ebp, BYTE PTR _Buffer$[esp+49]
  00052	0f be f0	 movsx	 esi, al
  00055	56		 push	 esi
  00056	57		 push	 edi
  00057	0f be db	 movsx	 ebx, bl
  0005a	55		 push	 ebp
  0005b	53		 push	 ebx
  0005c	68 00 00 00 00	 push	 OFFSET ??_C@_1CM@LIBNEIP@?$AAB?$AAu?$AAf?$AAf?$AAe?$AAr?$AA?5?$AA?$FL?$AA?$CF?$AAx?$AA?5?$AA?$CF?$AAx?$AA?5?$AA?$CF?$AAx?$AA?5?$AA?$CF?$AAx?$AA?$FN?$AA?6?$AA?$AA@
  00061	e8 00 00 00 00	 call	 _Print

 

其中 push esi是 Buffer[3], push edi是 Buffer[2], push ebp 是 Buffer[1] , push ebx 是 Buffer[0],看起来一切正常。我们根据简单的结果进行计算0xFFFFFF80+0x5200+0x00+0x00=0x5180 就是说出现问题出在运行期的取值,和 Printf函数 没有关系。所以,关注点在为什么 1byte的0x80被定义成了 0xFFFFFF80。之后,我尝试化简程序,直接定义变量输出查看。我们定义三个变量 a b c用 printf 输出之:

	CHAR8	a=129;
	UINT8	b=130;
	unsigned char	c=131;

	Print(L"A= [%x]\n",a);					
	Print(L"B= [%x]\n",b);		
	Print(L"C= [%x]\n",c);	

 

运行结果:
tipsc

可以看到,如同我们的假设的, CHAR8 的 128被定义为 -127.
具体的 CHAR8定义可以在 MdePkg 中的 ProcessorBind.h 中找到:

  ///
  /// 1-byte Character.
  ///
  typedef char                CHAR8;

 

CHAR 本身是一种有符号的整数(所以才会有 unsigned char)。因此,这就是一个错误的定义数据类型而导致的问题,解决方法很简单,用 UINT8 做定义就好了(从ProcessorBind.h可以看出,UINT8是 unsigned char)。

最后,贴一下修改后的完整INF 文件以便参考:

## @file
#   A simple, basic, application showing how the Hello application could be
#   built using the "Standard C Libraries" from StdLib.
#
#  Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
#  This program and the accompanying materials
#  are licensed and made available under the terms and conditions of the BSD License
#  which accompanies this distribution. The full text of the license may be found at
#  http://opensource.org/licenses/bsd-license.
#
#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
##

[Defines]
  INF_VERSION                    = 0x00010006
  BASE_NAME                      = tipsa
  FILE_GUID                      = 4ea97c46-7491-4dfd-0064-747010f3ce5f
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 0.1
  ENTRY_POINT                    = ShellCEntryLib

#   
#  VALID_ARCHITECTURES           = IA32 X64 IPF
#

[Sources]
  tipsa.c

[Packages]
  StdLib/StdLib.dec   
  MdePkg/MdePkg.dec
  ShellPkg/ShellPkg.dec 


[LibraryClasses]
  LibC
  ShellCEntryLib   
  ShellLib
  
[Protocols]
	
[BuildOptions]
  MSFT:*_*_IA32_CC_FLAGS  = /FAsc
  

 

Delphi 二维码生成工具 DelphiZXingQRCode

我最近在编写一个二维码生成的代码,使用了 Debenu-DelphiZXingQRCode 这个 VCL ,但是在使用中发现这个工具在编码上存在 bug。

具体来说,我需要对一组十六进制字符串编码(0-9,A-F)但是发现设置为 qrAuto, qrNumeric 以及 qrAlphanumeric 都无法对 0 进行编码。

意思是比如: 55AA000011 生成二维码之后再用手机识别,结果只是 55AA11,中间的 0000 会被删除(我尝试了手机上的2款不同识别内核

的软件,都是这样);如果切换为 qrISO88591 编码之后的结果可以正常识别,但是如果字符串很长效率又低了很多。

暂时不推荐大家使用这个 VCL

DelphiZXingQRCode-master

ACPI 工具的编译

ACPI 已经成为 x86 Firmware 密不可分的一部分,这里介绍一下对应工具组的编译。

编译工具
1. vs2008 (我使用的是能够编译UDK2014的环境)
2. Bison 可以在http://gnuwin32.sourceforge.net/packages/bison.htm 下载
3. Flex 可以在 http://gnuwin32.sourceforge.net/packages/flex.htm 下载
4. ACPICA 的 Windows Source Code https://www.acpica.org/downloads/windows-source 下载

安装 1 2 3,特别注意: 2 3 需要安装在 c:\GnuWin32目录下。然后在“我的电脑”“属性”“高级”“环境变量”的 Path 中加入 c:\GnuWin32\bin。之后打开一个控制台窗口,输入Path 要确保能找到这个目录。
asl1

之后解压4的内容到 acpica 目录下
asl2
打开源程序下面的 generate\msvc9中的 AcpiComponents.sln 即可编译(我用的是 VS2008)

asl4

直接编译,即可在对应目录中找到重新编译后的结果
asl3

个人建议根据需要下载你需要的版本(不同版本 ASL 编译工具之间差别很大,容易出现彼此之间无法识别的问题)。

本文提到的工具和源代码下载 链接: http://pan.baidu.com/s/1o7zRo2A 密码: jhbd

Step to UEFI Tips

有一句话, 是福尔摩斯的名言“排除一切不可能的,剩下的即使再不可能,那也是真相”。我很多次在《名侦探柯南》上看到这句话,在 Debug方面也快成为我的座右铭了,只是中文读起来逻辑上不是很严谨,原文是: When you have eliminated the impossibles,whatever remains,however improbable,must be the truth.

这次,在调试中又遇到了这样的事情。

我编写一个程序,只是简单的把1K大小的内存值写入到一个文件中,但是我惊奇的发现,对内存写入不同值,打开之后的结果和期望会有不同。

先上源代码

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

#include <Protocol/SimpleFileSystem.h>
#include <Library/MemoryAllocationLib.h>

extern EFI_BOOT_SERVICES         *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 	 *gRT;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
	UINTN 							FileSize=1024;
    EFI_STATUS          			Status;	
	EFI_FILE_PROTOCOL    			*Root;
	EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
	EFI_FILE_PROTOCOL 				*FileHandle=0;	
	UINTN							*HandleBuffer;

	Status = gBS->LocateProtocol(
				&gEfiSimpleFileSystemProtocolGuid, 
				NULL,
				(VOID **)&SimpleFileSystem);

	if (EFI_ERROR(Status)) {
		Print(L"Cannot find EFI_SIMPLE_FILE_SYSTEM_PROTOCOL \r\n");
		return Status;	
	}

	Status = SimpleFileSystem->OpenVolume(SimpleFileSystem,&Root);
    if (EFI_ERROR(Status)) {
		    Print(L"OpenVolume error \r\n");
            return Status;	
	}

    Status = Root -> Open(Root,
			&FileHandle,
			(CHAR16 *) L"wre.bin",
			EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
			0);

    if (EFI_ERROR(Status) || (FileHandle==0)) {
		    Print(L"Open error \r\n");
            return Status;	
	}	

	HandleBuffer = AllocateZeroPool(FileSize);
    if (HandleBuffer == NULL) {
		Print(L"Not enough memory!\n");
		return Status;
    }

	*(HandleBuffer)  =1;
	*(HandleBuffer+1)=2;
	*(HandleBuffer+2)=3;
	*(HandleBuffer+3)=4;

	Print(L"%d\n",(FileSize-4)/4);	
	Print(L"%d\n",sizeof(UINTN));	
	Print(L"%d\n",sizeof(UINT32));		
	Print(L"%x\n",HandleBuffer);		
	Print(L"%x\n",HandleBuffer+1);		

	Status = FileHandle -> Write(FileHandle, &FileSize, HandleBuffer);

	Print(L"Write Done \r\n");	
	FreePool(HandleBuffer);
	Status  = FileHandle -> Close (FileHandle);

  return EFI_SUCCESS;
}

运行结果会生成 wre.bin, 我用 Notepad++ 打开之后看到的结果是下面,看起来是按照 WORD 写入的而不是我期望的UINT32

wrA

而如果把 *(HandleBuffer) =1; 这行修改为 *(HandleBuffer) =0x1111 1111;

打开同样的文件看到的是下面的结果,很明显这才是我期望的:

wrb

<此处空白,有兴趣的朋友可以猜测一下,真相到底是什么>
kenan

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

真正的原因是我用的 Notepad++ 有问题,如果我换一款十六进制编辑软件即可看到正确的结果。比如, HHD Hex Editor Noe。

下面是用 Beyond Compare 比较两次生成文件,查看是否有差别

wreR

由此完全可以看出,二者没有差别,我遇到的奇怪现象完全是查看工具导致的。

看到这里,你完全可以和我一起默念“排除一切不可能的,剩下的即使再不可能,那也是真相”。

Intel FMMT 工具的编译

AMI 有 MMTOOL 这样的可以替换模块的工具,Intel有自己的BIOS,也有自己的工具: FMMT ,全称是 Firmware Module Management Tools。可以在 http://firmware.intel.com/develop 页面下载到。

(特别注意:编译必须在 UDK2015下面进行,http://sourceforge.net/projects/edk2/files/UDK2015_Releases/)

编译 FMMT 对于其他工具有依赖,需要把 UDK2015中的 Basetools(Windows)解压出来。这里我直接解压在 c: 下面的UDK2015目录中。

fmmt1

将FMMT的source code解压到 BaseTools\Source\C 下面

fmmt3

打开 Vistual Studio VS2008 的命令行窗口,进入 UDK2015 目录,运行 EdkSetup.bat

fmmt2

进入 BaseTools 运行 toolsetup.bat 。然后运行 nmake (因为 FMMT对于其他模块有依赖,所以这里需要先Build一下)

fmmt4

再进入 source\c\fmmt 目录下, 再次运行 Nmake

fmmt5

编译结果在 BaseTools\Bin\Win32 下面

fmmt6

本文相关内容下载:

1.FMMT WW48 v0.19 fMMT
2.完整的编译环境下载,主要是 UDK2015 BaseTools 和 FMMT 的 Source Code 链接: http://pan.baidu.com/s/1c0Ur2cK 密码: srp4
3.XP下面可以运行的 FMMT (不知道为什么,2 中的 FMMT 无法在XP下直接运行,但是用上面的方法在 XP 下编译一次的结果可以 官方工具在发布时,选择使用 vs2013或者更高的版本编译,并且没有选择 XP 兼容模式造成的。)
2015-WW48-FMMT.19