在這個章節我會討論關於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);
留言
張貼留言