Step to UEFI (89) 内存访问

初学 Watcom C的时候遇到一个问题“如何访问指定的内存”。当时为了这个问题花费了不少功夫,最后才发现直接用指针就可以进行访问,因为过于简单以至于网上都没有人问过…….
最近看 UEFI 编程,同样也遇到了这个问题,我去查找了 mm命令的source code,看到了它使用了PCI Root Bridge I/O Protocol 这个Protocol,然后就去研究之。同样越研究越迷糊,最终发现虽然这个Protocol提供了内存访问函数,但是本质上依然使用指针来直接访问。出于保护模式下的内存,任何其他方法都有“脱了裤子放屁-----多此一举”之嫌。
参考 mm 源程序,很快写出代码:

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

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

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

typedef enum {
  EfiPciWidthUint8,
  EfiPciWidthUint16,
  EfiPciWidthUint32,
  EfiPciWidthUint64
} DUMMY;

VOID
ReadMem (
  EFI_IO_WIDTH  Width,
  UINT64        Address,
  UINTN         Size,
  VOID          *Buffer
  )
{
  do {
    if (Width == EfiPciWidthUint8) {
      *(UINT8 *) Buffer = *(UINT8 *) (UINTN) Address;
      Address -= 1;
    } else if (Width == EfiPciWidthUint16) {
      *(UINT16 *) Buffer = *(UINT16 *) (UINTN) Address;
      Address -= 2;
    } else if (Width == EfiPciWidthUint32) {
      *(UINT32 *) Buffer = *(UINT32 *) (UINTN) Address;
      Address -= 4;
    } else if (Width == EfiPciWidthUint64) {
      *(UINT64 *) Buffer = *(UINT64 *) (UINTN) Address;
      Address -= 8;
    } else {
      Print(L"Can't read memory at %X",Width);
      break;
    }
    //
    //
    //
    Size--;
  } while (Size > 0);
}

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
	CHAR8		*Mem1;
	UINT32		Buffer;

	Mem1=AllocatePool(4);
	*(Mem1+0)='L'; 
	*(Mem1+1)='A';
	*(Mem1+2)='B';
	*(Mem1+3)='Z';
	Print(L"Memory Address: %X\n",Mem1);
	Print(L"%X\n",*Mem1);
	Print(L"%X\n",*(Mem1+1));
	Print(L"%X\n",*(Mem1+2));
	Print(L"%X\n",*(Mem1+3));
	
	ReadMem(EfiPciWidthUint32, (UINT64)Mem1, 1, &Buffer);
	
	Print(L"Read[%X]=%X\n",Mem1,Buffer);
	
	FreePool(Mem1);
	
  return EFI_SUCCESS;
}

 

在NT32模拟器中实验时发现,模拟环境中不是所有的内存空间都是可以直接访问的。稍有不慎就会得到错误信息,模拟器也会随之崩溃。于是,代码是创建一个4 Bytes长的内存空间,写入一些字符,然后再 ReadMem 读取出来,这样做能够保证访问的内存是可以被正常操作的。

运行结果:

ma

参考的 mm.c 来自EfiShell 1.06\Shell\mm\mm.c。
mm

本文提到的完整代码下载
ReadMEM

Step to UEFI (89) 内存访问》上有 2 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注