在這個章節我會討論關於OS Loader的細節,OS Loader是一個特別的 EFI Application,
主要的任務是擔任 platform firmware 跟 the operating system runtime中間的橋梁,也就是將板子帶到開進OS的狀態。
- OS Loader要決定它自己要從那裡被戴入進 System Memory
- OS Loader要知道OS是存放在那裡,通常是會在HDD裡,透過Block I/O Read/Write,接著會實做或戴入File System Driver存取OS的檔案
- 必需實作 memory map of physical memory,讓OS知道在Memory這邊 實際上可以管理的東西。 OS loader必須使用EFI API去取得系統目前的記憶體對映。
- OS會有一些儲存Boot Path的選項以及Boot Option, 用環境變數的形式存在非揮發的儲存裝置(nonvolatile storage)裡
- 呼叫ExitBootServices(),這個呼叫可以由OS Loader或試OS Kernel來完成, 要特別注意的是必須要在呼叫這個Function之前,要取得目前記憶體對映(Current Memory Map)。
- 一旦呼叫了ExitBootServices(),就再也沒有EFI Boot Service可以使用了,只能使用EFI Runtime Service。
OS Loader的範例程式呼叫了幾種EFI Library來做一些簡單的實作.
- Print出OS Loader自己的Device Path以及File Path.
- Print出OS Loader存在的記憶體位址,,以及使用了多少Bytes
- OS Loader 載入OSKERNEL.BIN到Memory, 而OSKERNEL.BIN是從OS Loader相同的目錄中取得.
- Print數個Block Device的第一個Block。 第一個Block是Floppy Drive的FAT12 File System. 第二個是HDD的MBR(Master Boot Record)。 第三個則是相同HDD的大FAT32分割區。 第四個是相同HDD的小FAT16分割區。
- Print所有System Configuration Table, 系統目前記憶體對映的指標以及列出所有系統的環境變數
- 最後OS Loader呼叫ExitBootServices()。
1.Print出OS Loader自己的Device Path以及File Path。
2.Print出OS Loader存在的記憶體位址,,以及使用了多少Bytes
2.Print出OS Loader存在的記憶體位址,,以及使用了多少Bytes
- 從ImageHandle取得LOADED_IMAGE_PROTOCOL interface放進LoadedImage
- 再從DeviceHandle取得DEVICE_PATH_PROTOCOL interface存到 DevicePath
後面就將找到的DevicePath & FilePath &ImageBase及ImageSize印出來
BS->HandleProtocol(
ImageHandle,
&LoadedImageProtocol,
LoadedImage);
BS->HandleProtocol(
LoadedImage->DeviceHandle,
&DevicePathProtocol,
&DevicePath);
Print (
L"Image device : %s\n",
DevicePathToStr (DevicePath));
Print (
L"Image file : %s\n",
DevicePathToStr (LoadedImage->FilePath));
Print (
L"Image Base : %X\n",
LoadedImage->ImageBase);
Print (
L"Image Size : %X\n",
LoadedImage->ImageSize);
3.OS Loader 載入OSKERNEL.BIN到Memory, 而OSKERNEL.BIN是從OS Loader相同的目錄中取得。
- 從DeviceHandle取得FILE_SYSTEM_PROTOCOL interface放進Vol
- 再透過Vol的OpenVolume取得跟OS Loader一樣Partition位置的file handle(CurDir)。
BS->HandleProtocol(
LoadedImage->DeviceHandle,
&FileSystemProtocol,
&Vol);
Vol->OpenVolume(
Vol,
&RootFs);
CurDir = RootFs;
3.Build OSKERNEL.BIN的File PATH,這個OSKERNEL.BIN跟OS Loader Image存放在一樣的Directory,將OSKERNEL.BIN存進OsKernelBuffer
StrCpy(FileName,DevicePathToStr(LoadedImage->FilePath));
for(i=StrLen(FileName);i>=0 && FileName[i] != '\\';i--);
FileName[i] = 0;
StrCat(FileName,L"\\OSKERNEL.BIN");
CurDir->Open (CurDir, &FileHandle,FileName,
EFI_FILE_MODE_READ,0);
Size = 0x00100000;
BS->AllocatePool(EfiloaderData,Size,&OsKernelBuffer);
FileHandle->Read(FileHandle,&Size,OsKernelBuffer);
FileHandle->Close(FileHandle);
4.Print數個Block Device的第一個Block
- 使用LibLocateHandle找到Block Io Device的List 後存在 HandleBuffer
- BlkIo->ReadBlocks 將找到的第一個Block讀取出來
NoHandles = 0; HandleBuffer = NULL; LibLocateHandle (ByProtocol, &BlockIoProtocol,NULL, &NoHandles, &HandleBuffer); for(i=0;iHandleProtocol( HandleBuffer[i], &DevicePathProtocol, &DevicePath ); BS->HandleProtocol( HandleBuffer[i], &BlockIoProtocol, &BlkIo ); Block = AllocatePool (BlkIo->BlockSize); MediaId = BlkIo->MediaId; BlkIo->ReadBlocks( BlkIo, MediaId, (EFI_LAB)0. BlkIo->BlockSize, Block ); Print( L"\nBlock #0 of device %s\n",DevicePathToStr(DevicePath)); DumpHex(0,0,BlkIo->BlockSize,Block); }
5.Print所有System Configuration Table, 系統目前記憶體對映的指標以及列出所有系統的環境變數
1.在下面會列出所有的System Configuration Table
LibGetSystemConfigurationTable(
&AcpiTableGuid,&AcpiTable
);
LibGetSystemConfigurationTable(
&SMBIOSTableGuid,&SMBIOSTable
);
LibGetSystemConfigurationTable(
&SalSystemTableGuid,&SalSystemTable
);
LibGetSystemConfigurationTable(
&MpsTableGuid,&MpsTable
);
Print(
L" ACPI Table is ad address
%X\n",AcpiTable
);
Print(
L" SMBIOS Table is ad address
%X\n",SMBIOSTable
);
Print(
L" AcPI Table is ad address
%X\n",SalSystemTable
);
Print(
L" MPS Table is ad address
%X\n",MpsTable
);
2.在下面會列出所有記憶體對映的指標
MemoryMap = LibMemoryMap(
&NoEntries,
&MapKey,
&DescriptorSize,
&DescriptorVersion,
);
Print(
L"Memory Descriptor List:\n\n"
);
Print(
L"Type Start Address End Address Attributes \n"
);
Print(
L"============== ============== ==============\n"
);
MemoryMapEntry = MemoryMap;
for(i=0;iType],
MemoryMapEntry->PhysicalStart,
MemoryMapEntry->PhysicalStart +
LShiftU64(
MemoryMapEntry->NumberOfPages,
PAGE_SHIFT)-1,
MemoryMapEntry->Attribute
);
MemoryMapEntry = NextMemoryDescriptor(
MemoryMapEntry.
DescriptorSize
);
}
3.列出所有系統的環境變數
VariableName[0] = 0x0000;
VendorGuid = NullGuid;
Print(
L"GUID
Value\n");
Print(
L"=======================================
===================\n");
do{
VariableNameSize = 256;
Status = RT->GetNextVariableName(
&VariableNameSize,
VariableName,
&VendorGuid
);
if (Status == EFI_SUCCESS) {
VariableValue = LibGetVariable(
VariableName,
&VendorGuid
);
Print(
L"%.-35g %.-20s
%X\n",&VendorGuid,VariableName,VariableValue
);
}
}while (Status == EFI_SUCESS);

留言
張貼留言