分离GOP和VBT文件的工具

一个用于分离GOP和VBT文件的工具

这个工具是用来分离Intel Baytrail公版BIOS中的VBT和GOP文件的。其中的GOP是传统意义上的VBIOS,VBT文件是他的配置文件。在之前,配置

信息通常会写入到VBIOS中,但是在BayTrail上他们是分开独立的。

用法:

BTYGVS [文件名]

比如:BTYGVS IFWI_2013_10_01 即可在当前目录下生成这个BIOS中

包括的GOP和VBT。

gvs

下载

bytgvs

Step to UEFI (9)—-使用RDTSC计算当前CPU 频率

很早之前Intel曾经提供过一个使用RDTSC在DOS下计算CPU频率的程序(在CPUID的Datasheet中)。简单的说就是延时一个固定的时间,然后看这个时间内经过了多少个指令周期,经过计算就能得到CPU的频率。下面的程序实现了在UEFI环境下计算频率的功能,同时也可以作为插入汇编指令的参考。需要注意,这是32位UEFI环境下,如果在64位的Shell环境下这样做是不行的。

//
// FreqCalc.C
//

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

EFI_SYSTEM_TABLE	*gST;
EFI_BOOT_SERVICES  	*gBS;

UINT64 rdtsc()
{
  UINT64 value;
  __asm
  {
     rdtsc
     mov dword ptr value,eax
     mov dword ptr [value + 4],edx
  } 

  return  value;
}

//
// Entry point function - ShowVersion
//
EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{

  UINT64  elsp;

  gST = SystemTable;
  gBS = SystemTable->BootServices;

  elsp=rdtsc();
  gBS -> Stall(1000000);  
  Print(L"CPU Frequency: %ld \n", rdtsc()-elsp);

  return EFI_SUCCESS;
}

 

程序运行的结果:

cpuz

虚拟机中运行的CPUZ读取的结果:

freqcalc

代码下载

FreqCalc

特别的,有资料指出在当前的多核环境下,这样的方法并不准确,具体的原因请参考下面的文章

1. http://blog.csdn.net/solstice/article/details/5196544 “多核时代不宜再用 x86 的 RDTSC 指令测试指令周期和时间”
2. http://blog.chinaunix.net/uid-24774106-id-2779245.html “使用rdtsc指令,测量程序的运行速度”

介绍几个 UEFI Shell下的命令 (下)

继续介绍 Shell 下面的命令。

ECHO 和DOS下的这个命令相同,这是用来回显“字符串的”,比如下面的例子

echo

MAP 这是一个“定义用户名和设备handle映射关系”的命令。最常见的用途就是给支持文件protocol的设备分配一个盘符,比如: fs0:

另外,最常见的用法是当你进入shell之后发现忘记插入U盘,插入之后U盘的盘符不会马上可以使用,这时候可以使用 map -r 一下,让他识别。

map1

SET 和DOS下的这个命令相同,设置环境变量。SPEC中提到,不加额外参数设定的变量是“易非失”的,这次启动在,断电再上电还是在(我试验过)。

如果使用 -v 可以设置一个“易失”的变量,断电一次就没了。前面有 “×” 表示这个变量是易失的。

set1

VOL 显示当前的硬盘/分区容量,如果你发现Windows无法正常安装不妨试试这个命令检查一下是否使用了错误的eMMC. (后面会查看一下这个命令的代码确定究竟查看的是硬盘容量还是分区容量)

vol

VER 显示当前使用的UEFI版本信息

ver

TIME 显示和设置当前的时间信息(不知道如何设置时区?)

time

TYPE 和DOS下的这个命令相同,显示文件的内容,支持普通的ASCII和UNICODE编码。

type

介绍几个 UEFI Shell下的命令 (上)

这里只介绍常用的,因为不常用的我也搞不明白。第一个需要了解的是:很多命令可以在后面加入 -b 来做分屏显示。这个参数在查看help的时候非常有用。

比如下面就是运行 help -b 的结果

x1

下面是简单介绍一些命令。

alias 可以用来给一些命令设置“别名”。比如:我们在Shell下可以用 dir 和ls一样列出当前目录就是因为设置 dir 为 ls的别名。

alias1

实验一下,我们设置 alias dog ls,那么输入 dog 也和ls一样

alias2

attribute 更改文件属性,和DOS下面的那个命令一样

直接运行可以列出文件的属性

attributea

支持通配符,比如下面给这几个文件加上只读属性之后就无法删除了

attributeb

cls 清屏幕,它后面可以跟着一个参数,清屏之后设置背景的颜色

color – New background color
0 – Black
1 – Blue
2 – Green
3 – Cyan
4 – Red
5 – Magenta
6 – Yellow
7 – Light gray

例如:

cls

cp 拷贝,和DOS下面著名的copy命令一样。它提供了一个参数 -r, 可以用来递归进入目录进行拷贝。简单的说就是你可以用这个参数来copy目录

cpr

LZMA 压缩的例子

前一段时间研究了一下 LZ77 算法,后来又看了一下它的改进版本 LZMA。虽然基本思想已经完全领悟,但是要想具体写出代码还是很有难度,直接研究实现算法又被很多细节阻挡。好在时代不同了,虽然你无法写出具体代码,但是也有现成的库供你调用。

目前开源的比较好用的就是 7-zip 了,这里可以看到中文的介绍:http://sparanoid.com/lab/7z/

同时他还提供了 SDK 供以调用 http://sparanoid.com/lab/7z/sdk.html 。

对于 Delphi 的用户,能够使用的 SDK 在 http://www.birtles.org.uk/programming/ 这里可以下载到。是原生的 Delphi 编写无需第三方库。为了测试我编写了一个Console模式下压缩的小程序,并且在程序中我避免使用这个库内部定义的 Stream 而是直接使用 TMemoryStream。

program LZMAencoder;

{$APPTYPE CONSOLE}

{$R *.res}

uses
System.SysUtils, Windows, Classes,ULZMAEncoder,ULZMACommon;

var
FInput,Foutput:TMemoryStream; //直接使用基础的 MemoryStream
encoder:TLZMAEncoder; //编码器
i:integer; //算法方面的要求,最后要补零。具体请查看LZ77描述
begin
FInput:=TMemoryStream.Create; //创建和读取一个文件作为压缩的源
FInput.LoadFromFile('C:\Users\Administrator\Documents\RAD Studio\Projects\LZMAEncoder\original.txt');

encoder:=TLZMAEncoder.Create;

encoder.SetAlgorithm(2); //设置压缩比,看代码似乎没有真正实现
encoder.SetDictionarySize(1 shl 23); //设置字典大小
encoder.SeNumFastBytes(128); //不知道这个是什么
encoder.SetMatchFinder(1); //找到1个匹配
encoder.SetLcLpPb(3, 0, 2); //应该是LZ77算法用到的几个参数
encoder.SetEndMarkerMode(false); //是否写入流结束标志。因为压缩之后的头上有大小
//所以这里完全不用写入
FOutput:=TMemoryStream.Create;
encoder.WriteCoderProperties(FOutput); //写入头信息
for i := 0 to 7 do
WriteByte(FOutput,(FInput.Size shr (8 * i)) and $FF); //补全完整流

encoder.Code(Finput, FOutput, -1, -1); //解压过程
encoder.free;
FOutput.SaveToFile('C:\Users\Administrator\Documents\RAD Studio\Projects\LZMAEncoder\result.7z');
FOutput.Destroy;
Finput.Destroy;
readln;
end.

压缩结果可以直接用 7-zip 打开(WinZip, WinRar不行)。

Capture

原始的  LZMA 代码 LZMA.442b

本文提到的例子:LZMAEncoder

Step to UEFI (8)—-显示版本号

UEFI 2.4 SPEC 第四章介绍 EFI System Table 如下

getvendora

看到其中 Vendor 和 Revision信息便着手写了一个小程序来验证,核心代码如下

EFI_SYSTEM_TABLE	*gST;

//
// Entry point function - ShowVersion
//
EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{

  gST = SystemTable;

  Print(L"Firmware Vendor  :  %s \n", gST->FirmwareVendor);
  Print(L"Firmware Revision:  %d \n", gST->FirmwareRevision);

  return EFI_SUCCESS;
}

编译运行之后得到如下结果:

ShowVersion

手边暂时没有其他EFI的主板所以没有进一步实验。

下载 ShowVersion

 

Step to UEFI (7)—-加速 UEFI 模拟环境的启动

前面的例子都是在 NT32 模拟环境中运行的,在启动这个环境的时候会有一个5秒的滚动条。为了更爽快一些,可以将这个滚动条设置为一闪而过,马上进入Shell环境。“以文找文”,搜索“Start showing progress bar”字样,确定下面的代码显示这个字符串:

\IntelFrameworkModulePkg\Universal\BdsDxe\FrontPage.c (Experiment)

/**

  Function show progress bar to wait for user input.

  @param TimeoutDefault  - The fault time out value before the system

                         continue to boot.

  @retval  EFI_SUCCESS       User pressed some key except "Enter"

  @retval  EFI_TIME_OUT      Timout expired or user press "Enter"

**/

EFI_STATUS

ShowProgress (

  IN UINT16                       TimeoutDefault

  )

{

  EFI_STATUS                    Status;

  CHAR16                        *TmpStr;

  EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;

  EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;

  EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;

  EFI_INPUT_KEY                 Key;

  UINT16                        TimeoutRemain;

  if (TimeoutDefault == 0) {

    return EFI_TIMEOUT;

  }

  DEBUG ((EFI_D_INFO, "\n\nStart showing progress bar... Press any key to stop it! .\n"));

  SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);

  SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);

  SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);

  //

  // Clear the progress status bar first

  //

  TmpStr = GetStringById (STRING_TOKEN (STR_START_BOOT_OPTION));

  if (TmpStr != NULL) {

    PlatformBdsShowProgress (Foreground, Background, TmpStr, Color, 0, 0);

  }

 

 

追踪发现是下面的代码调用到上面的  \IntelFrameworkModulePkg\Universal\BdsDxe\FrontPage.c (Experiment)

/**

  This function is the main entry of the platform setup entry.

  The function will present the main menu of the system setup,

  this is the platform reference part and can be customize.

  @param TimeoutDefault     The fault time out value before the system

                            continue to boot.

  @param ConnectAllHappened The indicater to check if the connect all have

                            already happened.

**/

VOID

PlatformBdsEnterFrontPage (

  IN UINT16                       TimeoutDefault,

  IN BOOLEAN                      ConnectAllHappened

  )

…………………………

…………………………

  HotkeyBoot ();

  if (TimeoutDefault != 0xffff) {

    Status = ShowProgress (TimeoutDefault);

    StatusHotkey = HotkeyBoot ();

 

上面的代码又是下面调用到的

  //

  // Init the time out value

  //

  Timeout = PcdGet16 (PcdPlatformBootTimeOut);

 

 

最后确定参数是来自 PCD ,修改 \Nt32Pkg\Nt32Pkg.dsc

[PcdsDynamicHii.common.DEFAULT]

gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdSetupConOutColumn|L”SetupConsoleConfig”|gEfiGlobalVariableGuid|0x0|80

gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdSetupConOutRow|L”SetupConsoleConfig”|gEfiGlobalVariableGuid|0x4|25

gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPlatformBootTimeOut|L”Timeout”|gEfiGlobalVariableGuid|0x0|10

gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdHardwareErrorRecordLevel|L”HwErrRecSupport”|gEfiGlobalVariableGuid|0x0|1

将上面红色标记的修改为你希望的即可.

这里是一个修改为20秒的例子

Step2UEFI7

Step to UEFI Shell (6) —- Shell 中使用 Float

如果你在Shell下直接使用 Float 或者 Double 在编译的时候会遇到这样的问题

Architecture(s) = IA32
Build target = DEBUG
Toolchain = VS2008

Active Platform = c:\edk2\Nt32Pkg\Nt32Pkg.dsc
Flash Image Definition = c:\edk2\Nt32Pkg\Nt32Pkg.fdf

Processing meta-data … done!
“C:\Program Files\Microsoft Visual Studio 9.0\Vc\bin\link.exe” /out:”c:\edk2\Build\NT32\DEBUG_VS2008\IA32\SecMain.exe” /base:0x10000000 /pdb:”c:\edk2\Build\NT32\DEBUG_VS2008\IA32\SecMain.pdb” /LIBPATH:”C:\Program Files\Microsoft Visual Studio 9.0\VC\Lib” /LIBPATH:”C:\Program Files\Microsoft Visual Studio 9.0\VC\PlatformSdk\Lib” /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /MAP /OPT:REF /DEBUG /MACHINE:I386 /LTCG Kernel32.lib MSVCRTD.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib /EXPORT:InitializeDriver=_ModuleEntryPoint /ALIGN:4096 /FILEALIGN:4096 /SUBSYSTEM:CONSOLE @c:\edk2\Build\NT32\DEBUG_VS2008\IA32\Nt32Pkg\Sec\SecMain\OUTPUT\static_library_files.lst
LINK : warning LNK4108: /ALIGN specified without /DRIVER; image may not run
LINK : warning LNK4001: no object files specified; libraries used
Creating library c:\edk2\Build\NT32\DEBUG_VS2008\IA32\SecMain.lib and object c:\edk2\Build\NT32\DEBUG_VS2008\IA32\SecMain.exp
Generating code
Finished generating code
“C:\Program Files\Microsoft Visual Studio 9.0\Vc\bin\link.exe” /OUT:c:\edk2\Build\NT32\DEBUG_VS2008\IA32\MdeModulePkg\Application\floattest\floattest\DEBUG\FloatTest.dll /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /MACHINE:X86 /LTCG /DLL /ENTRY:_ModuleEntryPoint /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG /EXPORT:InitializeDriver=_ModuleEntryPoint /ALIGN:4096 /FILEALIGN:4096 /SUBSYSTEM:CONSOLE @c:\edk2\Build\NT32\DEBUG_VS2008\IA32\MdeModulePkg\Application\floattest\floattest\OUTPUT\static_library_files.lst
Creating library c:\edk2\Build\NT32\DEBUG_VS2008\IA32\MdeModulePkg\Application\floattest\floattest\DEBUG\FloatTest.lib and object c:\edk2\Build\NT32\DEBUG_VS2008\IA32\MdeModulePkg\Application\floattest\floattest\DEBUG\FloatTest.exp
Generating code
Finished generating code
c:\edk2\Build\NT32\DEBUG_VS2008\IA32\MdeModulePkg\Application\floattest\floattest\DEBUG\FloatTest.dll : warning LNK4086: entrypoint ‘__ModuleEntryPoint’ is not __stdcall with 12 bytes of arguments; image may not run
FloatTest.lib(floattest.obj) : error LNK2001: unresolved external symbol __fltused
c:\edk2\Build\NT32\DEBUG_VS2008\IA32\MdeModulePkg\Application\floattest\floattest\DEBUG\FloatTest.dll : fatal error LNK1120: 1 unresolved externals

我baidu和google之后得到的大概的结论是:UEFI 替换了Link中的默认库(CRT.LIB?),但是因为MS的编译器存在一个bug,所以导致仍然使用部分的默认库,所以导致这样的问题【这个解释存疑,不确定】。至于解决方法,经过我的实验确认就是使用 EADK 库【参考1】。我的理解是这个库是用来替代标准C库编写EDKII程序的,因此Float之类在其中也有重新定义。

加入方法:

1.解压EADK,然后将其中三个目录放到你EDK2的根目录下

2.修改 Nt32Pkg.dsc 加入红色部分

#
# Misc
#
DebugLib|IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf
DebugPrintErrorLevelLib|MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.inf
PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
#LABZ_Start
SortLib|ShellPkg/Library/UefiSortLib/UefiSortLib.inf
FileHandleLib|ShellPkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf
ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf
LibC|StdLib/LibC/LibC.inf
LibStdLib|StdLib/LibC/StdLib/StdLib.inf
LibString|StdLib/LibC/String/String.inf
LibWchar|StdLib/LibC/Wchar/Wchar.inf
LibCType|StdLib/LibC/Ctype/Ctype.inf
LibTime|StdLib/LibC/Time/Time.inf
LibStdio|StdLib/LibC/Stdio/Stdio.inf
LibGdtoa|StdLib/LibC/gdtoa/gdtoa.inf
LibLocale|StdLib/LibC/Locale/Locale.inf
LibUefi|StdLib/LibC/Uefi/Uefi.inf
LibMath|StdLib/LibC/Math/Math.inf
LibSignal|StdLib/LibC/Signal/Signal.inf
LibNetUtil|StdLib/LibC/NetUtil/NetUtil.inf
#LABZ_End
[LibraryClasses.common.USER_DEFINED]
DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
OemHookStatusCodeLib|Nt32Pkg/Library/PeiNt32OemHookStatusCodeLib/PeiNt32OemHookStatusCodeLib.inf
MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf

3. floattest.inf 中必须加入下面2个

[LibraryClasses]
UefiApplicationEntryPoint
UefiLib
PcdLib
ShellCEntryLib
ShellLib
LibMath
LibC|

下面就可以在你的代码中放心大胆的使用Float了。

一个计算 Pi 的Shell Application

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

//
// Based on code found at http://code.google.com/p/my-itoa/
//
int 
Integer2AsciiString(int val, char* buf)
{
    const unsigned int radix = 10;

    char* p = buf;
    unsigned int a; 
    int len;
    char* b;
    char temp;
    unsigned int u;

    if (val < 0) {
        *p++ = '-';
        val = 0 - val;
    }
    u = (unsigned int)val;
    b = p;

    do {
        a = u % radix;
        u /= radix;
        *p++ =(char) a + '0';
    } while (u > 0);

    len = (int)(p - buf);
    *p-- = 0;

    // swap 
    do {
       temp = *p; *p = *b; *b = temp;
       --p; ++b;
    } while (b < p);

    return len;
}

//
// Based on code found on the Internet (author unknown)
// Search for ftoa implementations
//
int 
Float2AsciiString(float f, char *buffer, int numdecimals)
{
    int status = 0;
    char *s = buffer;
    long mantissa, int_part, frac_part;
    short exp2;
    char m;

    typedef union {
        long L;
        float F;
    } LF_t;
    LF_t x;

    if (f == 0.0) {           // return 0.00
        *s++ = '0'; *s++ = '.'; *s++ = '0'; *s++ = '0'; 
        *s = 0;
       return status;
    }

    x.F = f;

    exp2 = (unsigned char)(x.L >> 23) - 127;
    mantissa = (x.L & 0xFFFFFF) | 0x800000;
    frac_part = 0;
    int_part = 0;

    if (exp2 >= 31 || exp2 < -23) {
        *s = 0;
        return 1;
    } 

    if (exp2 >= 0) {
        int_part = mantissa >> (23 - exp2);
        frac_part = (mantissa << (exp2 + 1)) & 0xFFFFFF;
    } else {
        frac_part = (mantissa & 0xFFFFFF) >> -(exp2 + 1);
    }

    if (int_part == 0)
       *s++ = '0';
    else {
        Integer2AsciiString(int_part, s);
        while (*s) s++;
    }
    *s++ = '.';

    if (frac_part == 0)
        *s++ = '0';
    else {
        for (m = 0; m < numdecimals; m++) {                       // print BCD
            frac_part = (frac_part << 3) + (frac_part << 1);      // frac_part *= 10
            *s++ = (frac_part >> 24) + '0';
            frac_part &= 0xFFFFFF;
        }
    }
    *s = 0;

    return status;
}

VOID
Ascii2UnicodeString(CHAR8 *String, CHAR16 *UniString)
{
    while (*String != '\0') {
        *(UniString++) = (CHAR16) *(String++);
    }
    *UniString = '\0';
}

//PI= 4- /3+4/5-4/7+4/9
EFI_STATUS 
EFIAPI
CalcPI()
{
    char str[8];
    static CHAR16 wstr[8];
    int i;

    float g1 = (float) 1;
    float g2 = (float) 0;

    for (i=0;i<100;i++)
     {
	if (i%2==0) {g2=g2+ 4/ g1;}
        else {g2=g2-4/ g1;}
	Float2AsciiString(g2, str, 4);         
	Ascii2UnicodeString(str, wstr);
	Print(L" PI: %s\n", wstr);
        g1=g1+2;
     }

    return EFI_SUCCESS;
}

EFI_STATUS 
EFIAPI
UefiMain(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
{

    CalcPI();

    return EFI_SUCCESS;
}

运行结果:

floattest

示例代码下载 floattest

参考:

1.http://sourceforge.net/apps/mediawiki/tianocore/index.php?title=EDKII_EADK

EDK II Application Development Kit for include the Standard C Libraries in UEFI Shell Applications

 

Step to UEFI Shell (5)—-获得Shell下内存分配状况

在Shell下面可以使用 memmap 命令查看到当前的内存状况:

step51

UEFI下面没有了E820 Table。取而代之的是GetMemoryMap()。UEFI spec Version 2.4 中 P143有如下的描述,实际上是一个长得和E820很像的东西。

step52

在网上可以搜索到一个示例[参考1],原文是用Toolkit 写成的,经过一些改造成为可以直接在EDK2下面的编译的代码。

GetMap.c:

#include <Uefi.h>
#include <Library/PcdLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiApplicationEntryPoint.h>

#define PAGE_SIZE 4096 

const CHAR16 *memory_types[] = { 
    L"EfiReservedMemoryType", 
    L"EfiLoaderCode", 
    L"EfiLoaderData", 
    L"EfiBootServicesCode", 
    L"EfiBootServicesData", 
    L"EfiRuntimeServicesCode", 
    L"EfiRuntimeServicesData", 
    L"EfiConventionalMemory", 
    L"EfiUnusableMemory", 
    L"EfiACPIReclaimMemory", 
    L"EfiACPIMemoryNVS", 
    L"EfiMemoryMappedIO", 
    L"EfiMemoryMappedIOPortSpace", 
    L"EfiPalCode", 
    L"EfiMaxMemoryType"
}; 

EFI_BOOT_SERVICES *gBS;  
const CHAR16 * 
memory_type_to_str(UINT32 type) 
{ 
    if (type > sizeof(memory_types)/sizeof(CHAR16 *)) 
        return L"Unknown"; 

    return memory_types[type]; 
} 

EFI_STATUS 
memory_map(EFI_MEMORY_DESCRIPTOR **map_buf, UINTN *map_size, 
           UINTN *map_key, UINTN *desc_size, UINT32 *desc_version) 
{ 
    EFI_STATUS err = EFI_SUCCESS; 

    *map_size = sizeof(**map_buf) * 31; 

get_map: 
    *map_size += sizeof(**map_buf); 

    err = gBS->AllocatePool(EfiLoaderData, *map_size, (void **)map_buf); 
    if (err != EFI_SUCCESS) { 
        Print(L"ERROR: Failed to allocate pool for memory map"); 
        return err; 
    } 

    err = gBS->GetMemoryMap(map_size, *map_buf, map_key, desc_size, desc_version); 
    if (err != EFI_SUCCESS) { 
        if (err == EFI_BUFFER_TOO_SMALL) { 
            gBS->FreePool((void *)*map_buf); 
            goto get_map; 
        } 
        Print(L"ERROR: Failed to get memory map"); 
    } 
    return err; 
} 

GetMap.inf

[Defines]
  INF_VERSION                    = 0x00010005
  BASE_NAME                      = GetMap
  FILE_GUID                      = 6987936E-ED34-44db-AE97-1FA5E4ED2318
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 1.0
  ENTRY_POINT                    = UefiMain

#
# The following information is for reference only and not required by the build tools.
#
#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
#

[Sources]
  GetMap.c

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

[LibraryClasses]
  UefiApplicationEntryPoint
  UefiLib
  PcdLib
  ShellCEntryLib
  ShellLib

[FeaturePcd]
  gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable

[Pcd]
  gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintString || gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable  ## Valid when gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable
  gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintTimes  || gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable  ## Valid when gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable

EFI_STATUS  
print_memory_map(void) 
{ 
    EFI_MEMORY_DESCRIPTOR *buf; 
    UINTN desc_size; 
    UINT32 desc_version; 
    UINTN size, map_key, mapping_size; 
    EFI_MEMORY_DESCRIPTOR *desc; 
    EFI_STATUS err = EFI_SUCCESS; 
    int i = 0; 

    err = memory_map(&buf, &size, &map_key, &desc_size, &desc_version); 
    if (err != EFI_SUCCESS) 
        return err; 

    Print(L"Memory Map Size: %d\n", size); 
    Print(L"Map Key: %d\n", map_key); 
    Print(L"Descriptor Version: %d\n", desc_version); 
    Print(L"Descriptor Size: %d\n\n", desc_size); 
    Print(L"Descriptor Size: %d\n\n", sizeof(EFI_MEMORY_DESCRIPTOR)); 

    desc = buf; 
    while ((UINT8 *)desc <  (UINT8 *)buf + size) { 
        mapping_size =(UINTN) desc->NumberOfPages * PAGE_SIZE; 

        Print(L"[#%02d] Type: %s  Attr: 0x%x\n", i, memory_type_to_str(desc->Type), desc->Attribute); 
        Print(L"      Phys: %016llx-%016llx\n", desc->PhysicalStart, desc->PhysicalStart + mapping_size -1 ); 

        desc = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)desc + desc_size); 
        i++; 
    } 

    gBS->FreePool (buf); 
    return err; 
} 

EFI_STATUS 
EFIAPI
UefiMain(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) 
{ 

    print_memory_map(); 

    return EFI_SUCCESS; 
}

 

运行结果如下:

step53

我们使用 GetMap >> result.txt 得到完整的输出结果如下:

Memory Map Size: 960
Map Key: 2841
Descriptor Version: 1
Descriptor Size: 48

Descriptor Size: 40

[#00] Type: EfiBootServicesData Attr: 0xF
Phys: 0000000000CB0000-0000000000CCFFFF
[#01] Type: EfiConventionalMemory Attr: 0xF
Phys: 0000000000CD0000-000000000383FFFF
[#02] Type: EfiLoaderData Attr: 0xF
Phys: 0000000003840000-0000000003841FFF
[#03] Type: EfiLoaderCode Attr: 0xF
Phys: 0000000003842000-0000000003848FFF
[#04] Type: EfiLoaderData Attr: 0xF
Phys: 0000000003849000-000000000385EFFF
[#05] Type: EfiLoaderCode Attr: 0xF
Phys: 000000000385F000-00000000038ABFFF
[#06] Type: EfiConventionalMemory Attr: 0xF
Phys: 00000000038AC000-0000000003B09FFF
[#07] Type: EfiBootServicesData Attr: 0xF
Phys: 0000000003B0A000-0000000003B56FFF
[#08] Type: EfiConventionalMemory Attr: 0xF
Phys: 0000000003B57000-0000000003B74FFF
[#09] Type: EfiBootServicesData Attr: 0xF
Phys: 0000000003B75000-0000000003B75FFF
[#10] Type: EfiConventionalMemory Attr: 0xF
Phys: 0000000003B76000-0000000003B76FFF
[#11] Type: EfiBootServicesData Attr: 0xF
Phys: 0000000003B77000-00000000048ABFFF
[#12] Type: EfiConventionalMemory Attr: 0xF
Phys: 00000000048AC000-0000000004990FFF
[#13] Type: EfiBootServicesCode Attr: 0xF
Phys: 0000000004991000-0000000004BABFFF
[#14] Type: EfiRuntimeServicesData Attr: 0xF
Phys: 0000000004BAC000-0000000004BEBFFF
[#15] Type: EfiRuntimeServicesCode Attr: 0xF
Phys: 0000000004BEC000-0000000004C2BFFF
[#16] Type: EfiReservedMemoryType Attr: 0xF
Phys: 0000000004C2C000-0000000004C2FFFF
[#17] Type: EfiBootServicesData Attr: 0xF
Phys: 0000000004C30000-0000000004CAFFFF
[#18] Type: EfiConventionalMemory Attr: 0xF
Phys: 0000000004CB0000-0000000008CAFFFF
[#19] Type: EfiMemoryMappedIO Attr: 0x0
Phys: 0000000000BE0000-0000000000BEBFFF

和直接使用memmap取得的结果相同。需要注意的是:

1. 返回的Descriptor Size 并不是 sizeof(EFI_MEMORY_DESCRIPTOR)
2. 不知道EFI_VIRTUAL_ADDRESS VirtualStart; 是干什么用的

GetMap

参考:
1. http://blog.fpmurphy.com/2012/08/uefi-memory-v-e820-memory.html
可以在附件中找到该网页。它使用的是EFI_Toolkit 我没有编译过

Step to UEFI Shell(4)—-清屏功能

下面的代码展示了在Shell下如何编写一个清屏功能

EFI_SYSTEM_TABLE	*gST;

//
// Entry point function - HelloMain
//
EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{

  gST = SystemTable;

  gST->ConOut->ClearScreen(gST->ConOut);
  gST->ConOut->EnableCursor(gST->ConOut,TRUE);

  return EFI_SUCCESS;
}

 

运行之后,会清屏并将光标至于屏幕左上角。

完整的代码 HelloWorld3