Skip to content

Instantly share code, notes, and snippets.

@hlgsdx
Created October 16, 2024 16:29
Show Gist options
  • Save hlgsdx/d5d356509c5eb2cd7bb281c4d9240aa3 to your computer and use it in GitHub Desktop.
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
#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;
}
[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