Created
October 16, 2024 16:29
-
-
Save hlgsdx/d5d356509c5eb2cd7bb281c4d9240aa3 to your computer and use it in GitHub Desktop.
UEFI application to initialize system time based on a timestamp saved in a text file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <Uefi.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <Library/UefiRuntimeServicesTableLib.h> | |
| #include <Library/UefiLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Protocol/SimpleFileSystem.h> | |
| #include <Protocol/LoadFile.h> | |
| #include <Guid/FileInfo.h> | |
| #include <Library/BaseLib.h> | |
| #include <Library/PrintLib.h> | |
| #include <Protocol/LoadedImage.h> // 加载EFI_LOADED_IMAGE_PROTOCOL | |
| #include <Library/DevicePathLib.h> // FileDevicePath 函数所在的库 | |
| // Windows Boot Loader的路径 | |
| #define WINDOWS_BOOT_LOADER_PATH L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi" | |
| // 用于存放时间戳文件的路径 | |
| #define TIME_SYNC_FILE L"timestamp.txt" | |
| // Function to convert Unix timestamp to EFI_TIME structure | |
| VOID ConvertUnixTimeToEfiTime(UINT64 UnixTime, EFI_TIME *EfiTime) { | |
| EfiTime->Year = 1970 + (UnixTime / 31556926); // 大致按年计算 | |
| UnixTime %= 31556926; | |
| EfiTime->Month = 1 + (UnixTime / 2629743); | |
| UnixTime %= 2629743; | |
| EfiTime->Day = 1 + (UnixTime / 86400); | |
| UnixTime %= 86400; | |
| EfiTime->Hour = (UINT8)(UnixTime / 3600); | |
| UnixTime %= 3600; | |
| EfiTime->Minute = (UINT8)(UnixTime / 60); | |
| EfiTime->Second = (UINT8)(UnixTime % 60); | |
| EfiTime->Nanosecond = 0; | |
| EfiTime->TimeZone = EFI_UNSPECIFIED_TIMEZONE; | |
| EfiTime->Daylight = 0; | |
| } | |
| // Function to print EFI_TIME in yyyy-mm-dd hh:mm:ss format | |
| VOID PrintEfiTime(EFI_TIME *Time) { | |
| Print(L"%04u-%02u-%02u %02u:%02u:%02u\n", | |
| Time->Year, | |
| Time->Month, | |
| Time->Day, | |
| Time->Hour, | |
| Time->Minute, | |
| Time->Second); | |
| } | |
| // Function to read the timestamp file and update the system time | |
| EFI_STATUS SyncTimeFromFile(EFI_HANDLE ImageHandle) { | |
| EFI_STATUS Status; | |
| EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem; | |
| EFI_FILE_PROTOCOL *Root; | |
| EFI_FILE_PROTOCOL *File; | |
| UINTN BufferSize; | |
| CHAR8 Buffer[64]; // 假设文件中的64位时间戳不会超过64字节 | |
| // 1. Locate the EFI partition | |
| Status = gBS->LocateProtocol(&gEfiSimpleFileSystemProtocolGuid, NULL, (VOID **)&SimpleFileSystem); | |
| if (EFI_ERROR(Status)) { | |
| Print(L"Failed to locate Simple File System Protocol: %r\n", Status); | |
| return Status; | |
| } | |
| // 2. Open the root directory of the EFI partition | |
| Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &Root); | |
| if (EFI_ERROR(Status)) { | |
| Print(L"Failed to open EFI partition root: %r\n", Status); | |
| return Status; | |
| } | |
| // 3. Open the timestamp file | |
| Status = Root->Open(Root, &File, TIME_SYNC_FILE, EFI_FILE_MODE_READ, 0); | |
| if (EFI_ERROR(Status)) { | |
| Print(L"Failed to open timestamp file: %r\n", Status); | |
| return Status; | |
| } | |
| // 4. Read the timestamp from the file | |
| BufferSize = sizeof(Buffer); | |
| Status = File->Read(File, &BufferSize, Buffer); | |
| if (EFI_ERROR(Status) || BufferSize == 0) { | |
| Print(L"Failed to read timestamp file: %r\n", Status); | |
| File->Close(File); | |
| return Status; | |
| } | |
| Buffer[BufferSize] = '\0'; // 确保字符串结尾 | |
| UINT64 UnixTime = AsciiStrDecimalToUint64(Buffer); | |
| // Close the file | |
| File->Close(File); | |
| // 5. Convert Unix timestamp to EFI_TIME structure | |
| EFI_TIME NewTime; | |
| ConvertUnixTimeToEfiTime(UnixTime, &NewTime); | |
| // 6. Set the UEFI system time | |
| Status = gRT->SetTime(&NewTime); | |
| if (EFI_ERROR(Status)) { | |
| Print(L"Failed to set system time: %r\n", Status); | |
| PrintEfiTime(&NewTime); | |
| return Status; | |
| } | |
| Print(L"System time updated successfully.\n"); | |
| return EFI_SUCCESS; | |
| } | |
| // Function to chainload Windows Boot Loader | |
| EFI_STATUS ChainloadWindowsBootLoader(EFI_HANDLE ImageHandle) { | |
| EFI_STATUS Status; | |
| EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| EFI_HANDLE BootLoaderHandle; | |
| // 1. Locate the Windows Boot Loader path on the EFI partition | |
| Status = gBS->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage); | |
| if (EFI_ERROR(Status)) { | |
| Print(L"Failed to locate loaded image protocol: %r\n", Status); | |
| return Status; | |
| } | |
| // Use FileDevicePath to get the device path for Windows Boot Loader | |
| DevicePath = FileDevicePath(LoadedImage->DeviceHandle, WINDOWS_BOOT_LOADER_PATH); | |
| if (DevicePath == NULL) { | |
| Print(L"Failed to locate Windows Boot Loader path.\n"); | |
| return EFI_NOT_FOUND; | |
| } | |
| // 2. Load the Windows Boot Loader | |
| Status = gBS->LoadImage(FALSE, ImageHandle, DevicePath, NULL, 0, &BootLoaderHandle); | |
| if (EFI_ERROR(Status)) { | |
| Print(L"Failed to load Windows Boot Loader: %r\n", Status); | |
| return Status; | |
| } | |
| // 3. Start the Windows Boot Loader | |
| Status = gBS->StartImage(BootLoaderHandle, NULL, NULL); | |
| if (EFI_ERROR(Status)) { | |
| Print(L"Failed to start Windows Boot Loader: %r\n", Status); | |
| return Status; | |
| } | |
| // Should never return | |
| return EFI_SUCCESS; | |
| } | |
| // Entry point of the UEFI application | |
| EFI_STATUS EFIAPI UefiMain(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) { | |
| EFI_STATUS Status; | |
| EFI_TIME CurrentTime; | |
| Print(L"Time Synchronization Application Started\n"); | |
| // 1. Get and print the current system time | |
| Status = gRT->GetTime(&CurrentTime, NULL); | |
| if (EFI_ERROR(Status)) { | |
| Print(L"Failed to get current time: %r\n", Status); | |
| } else { | |
| Print(L"Current System Time: "); | |
| PrintEfiTime(&CurrentTime); | |
| } | |
| // 2. Sync time from the file | |
| Status = SyncTimeFromFile(ImageHandle); | |
| if (EFI_ERROR(Status)) { | |
| Print(L"Failed to synchronize time: %r\n", Status); | |
| } | |
| // 3. Get and print the updated system time | |
| Status = gRT->GetTime(&CurrentTime, NULL); | |
| if (EFI_ERROR(Status)) { | |
| Print(L"Failed to get updated time: %r\n", Status); | |
| } else { | |
| Print(L"Updated System Time: "); | |
| PrintEfiTime(&CurrentTime); | |
| } | |
| // Wait 3 sec | |
| gBS->Stall(3000000); | |
| // 4. Chainload the Windows Boot Loader | |
| Status = ChainloadWindowsBootLoader(ImageHandle); | |
| if (EFI_ERROR(Status)) { | |
| Print(L"Failed to chainload Windows Boot Loader: %r\n", Status); | |
| } | |
| return Status; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [Defines] | |
| INF_VERSION = 0x00010005 | |
| BASE_NAME = TimeInitDemo | |
| FILE_GUID = 64c8307f-b5ec-47da-85c8-efb8de1a3f66 | |
| MODULE_TYPE = UEFI_APPLICATION | |
| VERSION_STRING = 1.0 | |
| ENTRY_POINT = UefiMain | |
| [Sources] | |
| TimeInitDemo.c | |
| [Packages] | |
| MdePkg/MdePkg.dec | |
| [LibraryClasses] | |
| UefiApplicationEntryPoint | |
| UefiLib | |
| UefiBootServicesTableLib | |
| UefiRuntimeServicesTableLib | |
| MemoryAllocationLib | |
| BaseLib | |
| PrintLib | |
| DevicePathLib | |
| [Protocols] | |
| gEfiLoadedImageProtocolGuid |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment