/** @file Library Instance implementation for IRSI Update Capsule Function ;****************************************************************************** ;* Copyright (c) 2012, Insyde Software Corp. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include #define INSYDE_CAPSULE_UPDATE_LOADER_DESC L"Insyde Capsule Update Loader" #define DEFAULT_CAPSULE_UPDATE_LOADER_PATH L"EFI\\Insyde\\IsCapLoader.efi" #define EFI_PATH_SIGNATURE L"EFI\\" #define INSYDE_MAGIC_BOOT_INDEX 0x1688 #define MAX_BOOT_OPTION_DATA_SIZE 2048 /** Get the offset of the boot loader file path from system partition for the boot device path of the current boot option @param[in] BootDevicePath Unicode string of the loader path from the system partition @param[in] BootDevicePathSize Size of the BootPath string @param[out] BootPathOffset @retval EFI_SUCCESS Next boot option successfully created @return others Unable to set next boot option **/ EFI_STATUS EFIAPI GetFileDevicePathOffset ( IN EFI_DEVICE_PATH_PROTOCOL *BootDevicePath, OUT UINTN *FileDevicePathOffset ) { EFI_DEVICE_PATH_PROTOCOL *DevicePath; if (BootDevicePath == NULL || FileDevicePathOffset == NULL) { return EFI_INVALID_PARAMETER; } DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)BootDevicePath; while (!IsDevicePathEnd(DevicePath)) { if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType (DevicePath) == MEDIA_FILEPATH_DP)) { *FileDevicePathOffset = (UINTN)((UINT8 *)DevicePath - (UINT8 *)BootDevicePath); break; } DevicePath = NextDevicePathNode (DevicePath); if (DevicePath == NULL) { return EFI_NOT_FOUND; } } *FileDevicePathOffset = (UINTN)((UINT8 *)DevicePath - (UINT8 *)BootDevicePath); return EFI_SUCCESS; } /** Set capsule update loader as the next boot option @param BootPath Unicode string of the loader path from the system partition @param BootPathSize Size of the BootPath string @retval EFI_SUCCESS Next boot option successfully created @return others Unable to set next boot option **/ EFI_STATUS EFIAPI SetNextBootOption ( CHAR16 *InputBootPath, UINT32 BootPathSize ) { EFI_STATUS Status; UINT16 BootIndex; CHAR16 BootOption[] = L"Boot0000"; UINT8 BootCurrentData[MAX_BOOT_OPTION_DATA_SIZE]; UINT8 BootNextData[MAX_BOOT_OPTION_DATA_SIZE]; UINT8 *BootDevicePathBuf; UINT16 BootDevicePathSize; CHAR16 *BootOptionDesc; UINTN FileDevicePathOffset; UINT8 *BufPtr; UINTN Size; CHAR16 BootPath[256]; if (BootPathSize == 0 || InputBootPath == NULL) { // // Default Capsule Update boot loader is used // BootPathSize = sizeof (DEFAULT_CAPSULE_UPDATE_LOADER_PATH); CopyMem (BootPath, DEFAULT_CAPSULE_UPDATE_LOADER_PATH, BootPathSize); } else { BootPathSize = (UINT16)StrSize (InputBootPath); CopyMem (BootPath, InputBootPath, BootPathSize); } Size = sizeof(UINT16); Status = EfiGetVariable ( L"BootCurrent", &gEfiGlobalVariableGuid, NULL, &Size, &BootIndex ); if (EFI_ERROR(Status)) { return Status; } UnicodeSPrint (BootOption, sizeof(BootOption), L"Boot%04x", (UINTN)BootIndex); Size = MAX_BOOT_OPTION_DATA_SIZE; Status = EfiGetVariable ( BootOption, &gEfiGlobalVariableGuid, NULL, &Size, BootCurrentData ); if (Status != EFI_SUCCESS) { return Status; } BootOptionDesc = (CHAR16 *)(BootCurrentData + sizeof(UINT32) + sizeof(UINT16)); BootDevicePathBuf = BootCurrentData + sizeof(UINT32) + sizeof(UINT16) + StrSize(BootOptionDesc); BootDevicePathSize = *(UINT16 *)(BootCurrentData + sizeof(UINT32)); Status = GetFileDevicePathOffset ( (EFI_DEVICE_PATH_PROTOCOL *)BootDevicePathBuf, &FileDevicePathOffset); if (EFI_ERROR(Status)) { return Status; } if (Status == EFI_SUCCESS) { // // Boot Option Attributes // BufPtr = BootNextData; *(UINT32 *)BufPtr = LOAD_OPTION_ACTIVE; BufPtr += sizeof(UINT32); // // Boot DevicePath size // BootDevicePathSize = (UINT16)(FileDevicePathOffset + sizeof(EFI_DEVICE_PATH_PROTOCOL) + BootPathSize + END_DEVICE_PATH_LENGTH); *(UINT16 *)BufPtr = BootDevicePathSize; BufPtr += sizeof(UINT16); // // Boot Option Description // CopyMem (BufPtr, INSYDE_CAPSULE_UPDATE_LOADER_DESC, sizeof(INSYDE_CAPSULE_UPDATE_LOADER_DESC)); BufPtr += sizeof(INSYDE_CAPSULE_UPDATE_LOADER_DESC); // // Boot Device Path // CopyMem (BufPtr, BootDevicePathBuf, FileDevicePathOffset); BufPtr += FileDevicePathOffset; // // File Device Path Protocol // *BufPtr++ = MEDIA_DEVICE_PATH; *BufPtr++ = MEDIA_FILEPATH_DP; // // File Device Path Size // *(UINT16 *)BufPtr = (UINT16)(sizeof(EFI_DEVICE_PATH_PROTOCOL) + BootPathSize); BufPtr += 2; // // File Path String // CopyMem (BufPtr, BootPath, BootPathSize); BufPtr += BootPathSize; // // End of Device Path // *BufPtr++ = 0x7F; *BufPtr++ = 0xFF; *BufPtr++ = 0x04; *BufPtr = 0x00; Size = sizeof(UINT32) + sizeof(UINT16) + sizeof (INSYDE_CAPSULE_UPDATE_LOADER_DESC) + BootDevicePathSize; UnicodeSPrint (BootOption, sizeof(BootOption), L"Boot%04x", INSYDE_MAGIC_BOOT_INDEX); Status = EfiSetVariable ( BootOption, &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, Size, BootNextData ); ASSERT_EFI_ERROR(Status); if (Status == EFI_SUCCESS) { BootIndex = INSYDE_MAGIC_BOOT_INDEX; Status = EfiSetVariable ( L"BootNext", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, sizeof(UINT16), &BootIndex ); ASSERT_EFI_ERROR(Status); } } return Status; } /** Irsi Update Capsule function @param UpdateCapsule pointer to IRSI_UPDATE_CAPSULE structure @retval EFI_SUCCESS **/ EFI_STATUS EFIAPI IrsiUpdateCapsule ( VOID *UpdateCapsuleBuf ) { EFI_STATUS Status; IRSI_UPDATE_CAPSULE *UpdateCapsule; UpdateCapsule = (IRSI_UPDATE_CAPSULE *)UpdateCapsuleBuf; Status = SetNextBootOption((CHAR16 *)(UINTN)UpdateCapsule->BootPath, UpdateCapsule->BootPathSize); return Status; } /** Irsi BootNext Update Initialization @param ImageHandle A handle for the image that is initializing this driver @param SystemTable A pointer to the EFI system table @retval EFI_SUCCESS: Module initialized successfully @retval Others : Module initialization failed **/ EFI_STATUS EFIAPI IrsiUpdateCapsuleInit ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; Status = IrsiRegisterFunction ( &gIrsiServicesGuid, IRSI_UPDATE_CAPSULE_COMMAND, IrsiUpdateCapsule ); return Status; }