/** @file ;****************************************************************************** ;* Copyright (c) 2021, 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 "LimitedToInternalStorage.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** Is Limited to internal storage. @param None. @retval TRUE Boot device will be limited to internal storage. @retval FALSE Boot device will not be limited to internal storage. **/ BOOLEAN L05IsLimitedToInternalStorage ( VOID ) { EFI_STATUS Status; UINTN BufferSize; SYSTEM_CONFIGURATION *SetupNvData; BOOLEAN IsLimited; SetupNvData = NULL; IsLimited = FALSE; BufferSize = sizeof (SYSTEM_CONFIGURATION); SetupNvData = AllocateZeroPool (BufferSize); if (SetupNvData == NULL) { return FALSE; } Status = CommonGetVariable ( L"Setup", &gSystemConfigurationGuid, &BufferSize, SetupNvData ); if (EFI_ERROR (Status)) { return FALSE; } if (SetupNvData->L05NaturalFileGuard == 1) { // 0:Disabled, 1:Enabled IsLimited = TRUE; } if (SetupNvData->L05DeviceGuard == 1) { // 0:Disabled, 1:Enabled IsLimited = TRUE; } FreePool (SetupNvData); return IsLimited; } /** Limited to Internal Storage Process. Check if platform is Limited to internal storage. YES - If boot option is not internal storage, set attributes to inactive. NO - Set attributes to active. @param None. **/ VOID LimitedToInternalStorageProcess ( VOID ) { EFI_STATUS Status; UINTN BlockIoHandleCount; EFI_HANDLE *BlockIoBuffer; UINTN BlockIndex; EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath; EFI_BLOCK_IO_PROTOCOL *BlkIo; UINT16 *BootOrder; UINTN BootOrderSize; UINTN BootDevNum; UINTN Index; UINT16 BootOptionName[BOOT_OPTION_MAX_CHAR]; UINT8 *BootOption; UINTN BootOptionSize; UINT8 *TempPtr; UINT32 *Attribute; CHAR16 *Description; UINTN DescriptionSize; EFI_DEVICE_PATH_PROTOCOL *DevicePath; UINT16 DevicePathSize; BOOLEAN InternalStorage; BlockIoHandleCount = 0; BlockIoBuffer = NULL; BlockIoDevicePath = NULL; BlkIo = NULL; BootOrder = NULL; BootOrderSize = 0; BootDevNum = 0; InternalStorage = FALSE; BlockIoBuffer = NULL; Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer ); if (EFI_ERROR (Status) || BlockIoBuffer == NULL) { return; } Status = CommonGetVariableDataAndSize ( L"BootOrder", &gEfiGlobalVariableGuid, &BootOrderSize, (VOID **) &BootOrder ); if (EFI_ERROR (Status) || BootOrder == NULL) { return; } BootDevNum = BootOrderSize / sizeof (UINT16); for (Index = 0; Index < BootDevNum; Index++) { InternalStorage = FALSE; UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", BootOrder[Index]); Status = CommonGetVariableDataAndSize ( BootOptionName, &gEfiGlobalVariableGuid, &BootOptionSize, (VOID **) &BootOption ); if (EFI_ERROR (Status) || BootOption == NULL) { continue; } TempPtr = BootOption; Attribute = (UINT32 *) TempPtr; TempPtr += sizeof (UINT32); DevicePathSize = *((UINT16 *) TempPtr); TempPtr += sizeof (UINT16); Description = (CHAR16 *) TempPtr; DescriptionSize = StrSize (Description); TempPtr += DescriptionSize; DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr; TempPtr += DevicePathSize; if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) { // // Find hard drive media device path. // if (BlockIoBuffer != NULL && BlockIoHandleCount != 0) { for (BlockIndex = 0; BlockIndex < BlockIoHandleCount; BlockIndex++) { BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[BlockIndex]); if (BlockIoDevicePath == NULL) { continue; } if (MatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) DevicePath)) { // // Find the matched partition device path. // Status = gBS->HandleProtocol ( BlockIoBuffer[BlockIndex], &gEfiBlockIoProtocolGuid, (VOID **) &BlkIo ); if (EFI_ERROR (Status)) { continue; } if (!BlkIo->Media->RemovableMedia) { // // Not removable media, that is internal storage. // InternalStorage = TRUE; break; } } } } } if (!InternalStorage && L05IsLimitedToInternalStorage ()) { // // The boot option is not internal storage. // So set Attributes to inactive for limited to internal storage. // *Attribute &= (~((UINT32) LOAD_OPTION_ACTIVE)); } else { *Attribute |= (((UINT32) LOAD_OPTION_ACTIVE)); } Status = CommonSetVariable ( BootOptionName, &gEfiGlobalVariableGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, BootOptionSize, BootOption ); FreePool (BootOption); } if (BootOrder != NULL) { FreePool (BootOrder); } return; } /** Limited to Internal Storage update Target HDD Variable. @param None. **/ VOID LimitedToInternalStorageUpdateTargetHddVariable ( VOID ) { EFI_STATUS Status; EFI_DEVICE_PATH_PROTOCOL *TargetHddDevPathVar; UINTN BufferSize; SYSTEM_CONFIGURATION *SetupNvData; UINT8 BootType; TargetHddDevPathVar = NULL; SetupNvData = NULL; if (!L05IsLimitedToInternalStorage ()) { return; } // // Get TargetHddDevPath variable of fast boot. // TargetHddDevPathVar = CommonGetVariableData ( L"TargetHddDevPath", &gEfiGenericVariableGuid ); if (TargetHddDevPathVar != NULL) { FreePool (TargetHddDevPathVar); return; } BufferSize = sizeof (SYSTEM_CONFIGURATION); SetupNvData = AllocateZeroPool (BufferSize); if (SetupNvData == NULL) { return; } Status = CommonGetVariable ( L"Setup", &gSystemConfigurationGuid, &BufferSize, SetupNvData ); if (EFI_ERROR (Status)) { return; } gBdsServices->GetBootType (gBdsServices, &BootType); if (SetupNvData->Win8FastBoot == 0 && BootType == EFI_BOOT_TYPE) { UpdateTargetHddVariable (); } FreePool (SetupNvData); return; } /** Limited to internal storage at Boot Device Enum After check point. It will update attribute of boot optoion to limited to internal storage. @param Event Event whose notification function is being invoked. @param Context Pointer to the notification function's context. **/ VOID EFIAPI LimitedToInternalStorageNotify ( IN EFI_EVENT Event, IN VOID *Context ) { BOOLEAN IsBootOrderHookEnabled; IsBootOrderHookEnabled = BdsLibIsBootOrderHookEnabled (); // // Update Option Attribute of BootOrder variable. // if (IsBootOrderHookEnabled) { BdsLibDisableBootOrderHook (); } LimitedToInternalStorageProcess (); // // Update Option Attribute of PhysicalBootOrder variable. // BdsLibEnableBootOrderHook (); LimitedToInternalStorageProcess (); if (!IsBootOrderHookEnabled) { BdsLibDisableBootOrderHook (); } // // Update Target HDD Variable // LimitedToInternalStorageUpdateTargetHddVariable (); return; } /** Limited dummy boot option to internal storage after gEfiVariableWriteArchProtocolGuid is installed. When platform is limited to internal storage, update attribute of dummy boot option to limited to internal storage. @param Event Pointer to this event @param Context Event hanlder private data **/ VOID EFIAPI LimitedDummyBootOptionToInternalStorageNotify ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; VOID *Interface; UINT16 BootOptionName[BOOT_OPTION_MAX_CHAR]; UINTN BootOptionSize; UINT8 *BootOption; UINTN Index; UINT32 *Attribute; Status = gBS->LocateProtocol ( &gEfiVariableWriteArchProtocolGuid, NULL, (VOID **) &Interface ); if (EFI_ERROR (Status)) { return; } gBS->CloseEvent (Event); for (Index = (DummyBootOptionStartNum + 1); Index < DummyBootOptionEndNum; Index++) { UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", Index); Status = CommonGetVariableDataAndSize ( BootOptionName, &gEfiGlobalVariableGuid, &BootOptionSize, (VOID **) &BootOption ); if (EFI_ERROR (Status) || BootOption == NULL) { continue; } Attribute = (UINT32 *) BootOption; if (L05IsLimitedToInternalStorage ()) { // // Set Attributes to inactive for limited to internal storage. // *Attribute &= (~((UINT32) LOAD_OPTION_ACTIVE)); } else { *Attribute |= (((UINT32) LOAD_OPTION_ACTIVE)); } Status = CommonSetVariable ( BootOptionName, &gEfiGlobalVariableGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, BootOptionSize, BootOption ); gBS->FreePool (BootOption); } return; } /** Limited boot next to internal storage after gEfiVariableWriteArchProtocolGuid is installed. When platform is limited to internal storage, delete BootNext variable if BootNext option is dummy boot option. @param Event Pointer to this event @param Context Event hanlder private data **/ VOID EFIAPI LimitedBootNextToInternalStorageNotify ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; VOID *Interface; UINT16 *BootNext; BootNext = NULL; Status = gBS->LocateProtocol ( &gEfiVariableWriteArchProtocolGuid, NULL, (VOID **) &Interface ); if (EFI_ERROR (Status)) { return; } gBS->CloseEvent (Event); if (!L05IsLimitedToInternalStorage ()) { return; } BootNext = CommonGetVariableData ( L"BootNext", &gEfiGlobalVariableGuid ); if (BootNext == NULL) { return; } if (BdsLibIsDummyBootOption (*BootNext)) { CommonSetVariable (L"BootNext", &gEfiGlobalVariableGuid, 0, 0, NULL); } if (BootNext != NULL) { FreePool (BootNext); } return; } /** Limited to internal storage. @retval EFI_SUCCESS The operation completed successfully. @retval Others An unexpected error occurred. **/ EFI_STATUS LimitedToInternalStorage ( VOID ) { EFI_STATUS Status; H2O_CP_HANDLE CpHandle; VOID *Registration; CpHandle = NULL; if (FeaturePcdGet (PcdH2OBdsCpBootDeviceEnumAfterSupported)) { Status = H2OCpRegisterHandler ( &gH2OBdsCpBootDeviceEnumAfterGuid, LimitedToInternalStorageNotify, H2O_CP_MEDIUM, &CpHandle ); if (EFI_ERROR (Status)) { DEBUG_CP ((DEBUG_ERROR, "Checkpoint Register Fail: %g (%r)\n", &gH2OBdsCpBootDeviceEnumAfterGuid, Status)); } else { DEBUG_CP ((DEBUG_INFO, "Checkpoint Registered: %g (%r)\n", &gH2OBdsCpBootDeviceEnumAfterGuid, Status)); } } Registration = NULL; EfiCreateProtocolNotifyEvent ( &gEfiVariableWriteArchProtocolGuid, TPL_CALLBACK, LimitedDummyBootOptionToInternalStorageNotify, NULL, &Registration ); Registration = NULL; EfiCreateProtocolNotifyEvent ( &gEfiVariableWriteArchProtocolGuid, TPL_CALLBACK, LimitedBootNextToInternalStorageNotify, NULL, &Registration ); return Status; }