Skip to content

Instantly share code, notes, and snippets.

@hlgsdx
Created October 16, 2024 16:29
Show Gist options
  • Select an option

  • Save hlgsdx/d5d356509c5eb2cd7bb281c4d9240aa3 to your computer and use it in GitHub Desktop.

Select an option

Save hlgsdx/d5d356509c5eb2cd7bb281c4d9240aa3 to your computer and use it in GitHub Desktop.

Revisions

  1. hlgsdx created this gist Oct 16, 2024.
    191 changes: 191 additions & 0 deletions TimeInitDemo.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,191 @@
    #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;
    }
    26 changes: 26 additions & 0 deletions TimeInitDemo.inf
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,26 @@
    [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