1 /** @file 2 * 3 * Copyright (c) 2011-2013, ARM Limited. All rights reserved. 4 * 5 * This program and the accompanying materials 6 * are licensed and made available under the terms and conditions of the BSD License 7 * which accompanies this distribution. The full text of the license may be found at 8 * http://opensource.org/licenses/bsd-license.php 9 * 10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 * 13 **/ 14 15 #include "BdsInternal.h" 16 17 EFI_STATUS 18 BootOptionParseLoadOption ( 19 IN EFI_LOAD_OPTION *EfiLoadOption, 20 IN UINTN EfiLoadOptionSize, 21 IN OUT BDS_LOAD_OPTION **BdsLoadOption 22 ) 23 { 24 BDS_LOAD_OPTION *LoadOption; 25 UINTN DescriptionLength; 26 UINTN EfiLoadOptionPtr; 27 28 if (EfiLoadOption == NULL) { 29 return EFI_INVALID_PARAMETER; 30 } 31 32 if (EfiLoadOptionSize < sizeof(UINT32) + sizeof(UINT16) + sizeof(CHAR16) + sizeof(EFI_DEVICE_PATH_PROTOCOL)) { 33 return EFI_BAD_BUFFER_SIZE; 34 } 35 36 if (*BdsLoadOption == NULL) { 37 LoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION)); 38 if (LoadOption == NULL) { 39 return EFI_OUT_OF_RESOURCES; 40 } 41 } else { 42 LoadOption = *BdsLoadOption; 43 } 44 45 EfiLoadOptionPtr = (UINTN)EfiLoadOption; 46 LoadOption->LoadOption = EfiLoadOption; 47 LoadOption->LoadOptionSize = EfiLoadOptionSize; 48 49 LoadOption->Attributes = *(UINT32*)EfiLoadOptionPtr; 50 LoadOption->FilePathListLength = *(UINT16*)(EfiLoadOptionPtr + sizeof(UINT32)); 51 LoadOption->Description = (CHAR16*)(EfiLoadOptionPtr + sizeof(UINT32) + sizeof(UINT16)); 52 DescriptionLength = StrSize (LoadOption->Description); 53 LoadOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)(EfiLoadOptionPtr + sizeof(UINT32) + sizeof(UINT16) + DescriptionLength); 54 55 // If ((End of EfiLoadOptiony - Start of EfiLoadOption) == EfiLoadOptionSize) then No Optional Data 56 if ((UINTN)((UINTN)LoadOption->FilePathList + LoadOption->FilePathListLength - EfiLoadOptionPtr) == EfiLoadOptionSize) { 57 LoadOption->OptionalData = NULL; 58 LoadOption->OptionalDataSize = 0; 59 } else { 60 LoadOption->OptionalData = (VOID*)((UINTN)(LoadOption->FilePathList) + LoadOption->FilePathListLength); 61 LoadOption->OptionalDataSize = EfiLoadOptionSize - ((UINTN)LoadOption->OptionalData - EfiLoadOptionPtr); 62 } 63 64 if (*BdsLoadOption == NULL) { 65 *BdsLoadOption = LoadOption; 66 } 67 68 return EFI_SUCCESS; 69 } 70 71 EFI_STATUS 72 BootOptionFromLoadOptionVariable ( 73 IN CHAR16* BootVariableName, 74 OUT BDS_LOAD_OPTION** BdsLoadOption 75 ) 76 { 77 EFI_STATUS Status; 78 EFI_LOAD_OPTION *EfiLoadOption; 79 UINTN EfiLoadOptionSize; 80 81 Status = GetGlobalEnvironmentVariable (BootVariableName, NULL, &EfiLoadOptionSize, (VOID**)&EfiLoadOption); 82 if (!EFI_ERROR(Status)) { 83 *BdsLoadOption = NULL; 84 Status = BootOptionParseLoadOption (EfiLoadOption, EfiLoadOptionSize, BdsLoadOption); 85 } 86 87 return Status; 88 } 89 90 EFI_STATUS 91 BootOptionFromLoadOptionIndex ( 92 IN UINT16 LoadOptionIndex, 93 OUT BDS_LOAD_OPTION **BdsLoadOption 94 ) 95 { 96 CHAR16 BootVariableName[9]; 97 EFI_STATUS Status; 98 99 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", LoadOptionIndex); 100 101 Status = BootOptionFromLoadOptionVariable (BootVariableName, BdsLoadOption); 102 if (!EFI_ERROR(Status)) { 103 (*BdsLoadOption)->LoadOptionIndex = LoadOptionIndex; 104 } 105 106 return Status; 107 } 108 109 EFI_STATUS 110 BootOptionToLoadOptionVariable ( 111 IN BDS_LOAD_OPTION* BdsLoadOption 112 ) 113 { 114 EFI_STATUS Status; 115 UINTN DescriptionSize; 116 //UINT16 FilePathListLength; 117 EFI_DEVICE_PATH_PROTOCOL* DevicePathNode; 118 UINTN NodeLength; 119 UINT8* EfiLoadOptionPtr; 120 VOID* OldLoadOption; 121 CHAR16 BootVariableName[9]; 122 UINTN BootOrderSize; 123 UINT16* BootOrder; 124 125 // If we are overwriting an existent Boot Option then we have to free previously allocated memory 126 if (BdsLoadOption->LoadOptionSize > 0) { 127 OldLoadOption = BdsLoadOption->LoadOption; 128 } else { 129 OldLoadOption = NULL; 130 131 // If this function is called at the creation of the Boot Device entry (not at the update) the 132 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry 133 BdsLoadOption->LoadOptionIndex = BootOptionAllocateBootIndex (); 134 135 //TODO: Add to the the Boot Entry List 136 } 137 138 DescriptionSize = StrSize(BdsLoadOption->Description); 139 140 // Ensure the FilePathListLength information is correct 141 ASSERT (GetDevicePathSize (BdsLoadOption->FilePathList) == BdsLoadOption->FilePathListLength); 142 143 // Allocate the memory for the EFI Load Option 144 BdsLoadOption->LoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + DescriptionSize + BdsLoadOption->FilePathListLength + BdsLoadOption->OptionalDataSize; 145 146 BdsLoadOption->LoadOption = (EFI_LOAD_OPTION *)AllocateZeroPool (BdsLoadOption->LoadOptionSize); 147 if (BdsLoadOption->LoadOption == NULL) { 148 return EFI_OUT_OF_RESOURCES; 149 } 150 151 EfiLoadOptionPtr = (UINT8 *) BdsLoadOption->LoadOption; 152 153 // 154 // Populate the EFI Load Option and BDS Boot Option structures 155 // 156 157 // Attributes fields 158 *(UINT32*)EfiLoadOptionPtr = BdsLoadOption->Attributes; 159 EfiLoadOptionPtr += sizeof(UINT32); 160 161 // FilePath List fields 162 *(UINT16*)EfiLoadOptionPtr = BdsLoadOption->FilePathListLength; 163 EfiLoadOptionPtr += sizeof(UINT16); 164 165 // Boot description fields 166 CopyMem (EfiLoadOptionPtr, BdsLoadOption->Description, DescriptionSize); 167 EfiLoadOptionPtr += DescriptionSize; 168 169 // File path fields 170 DevicePathNode = BdsLoadOption->FilePathList; 171 while (!IsDevicePathEndType (DevicePathNode)) { 172 NodeLength = DevicePathNodeLength(DevicePathNode); 173 CopyMem (EfiLoadOptionPtr, DevicePathNode, NodeLength); 174 EfiLoadOptionPtr += NodeLength; 175 DevicePathNode = NextDevicePathNode (DevicePathNode); 176 } 177 178 // Set the End Device Path Type 179 SetDevicePathEndNode (EfiLoadOptionPtr); 180 EfiLoadOptionPtr += sizeof(EFI_DEVICE_PATH); 181 182 // Fill the Optional Data 183 if (BdsLoadOption->OptionalDataSize > 0) { 184 CopyMem (EfiLoadOptionPtr, BdsLoadOption->OptionalData, BdsLoadOption->OptionalDataSize); 185 } 186 187 // Case where the fields have been updated 188 if (OldLoadOption) { 189 // Now, the old data has been copied to the new allocated packed structure, we need to update the pointers of BdsLoadOption 190 BootOptionParseLoadOption (BdsLoadOption->LoadOption, BdsLoadOption->LoadOptionSize, &BdsLoadOption); 191 // Free the old packed structure 192 FreePool (OldLoadOption); 193 } 194 195 // Create/Update Boot#### environment variable 196 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BdsLoadOption->LoadOptionIndex); 197 Status = gRT->SetVariable ( 198 BootVariableName, 199 &gEfiGlobalVariableGuid, 200 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 201 BdsLoadOption->LoadOptionSize, 202 BdsLoadOption->LoadOption 203 ); 204 205 // When it is a new entry we must add the entry to the BootOrder 206 if (OldLoadOption == NULL) { 207 // Add the new Boot Index to the list 208 Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder); 209 if (!EFI_ERROR(Status)) { 210 BootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof(UINT16), BootOrder); 211 // Add the new index at the end 212 BootOrder[BootOrderSize / sizeof(UINT16)] = BdsLoadOption->LoadOptionIndex; 213 BootOrderSize += sizeof(UINT16); 214 } else { 215 // BootOrder does not exist. Create it 216 BootOrderSize = sizeof(UINT16); 217 BootOrder = &(BdsLoadOption->LoadOptionIndex); 218 } 219 220 // Update (or Create) the BootOrder environment variable 221 gRT->SetVariable ( 222 L"BootOrder", 223 &gEfiGlobalVariableGuid, 224 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 225 BootOrderSize, 226 BootOrder 227 ); 228 DEBUG((EFI_D_ERROR,"Create %s\n",BootVariableName)); 229 230 // Free memory allocated by GetGlobalEnvironmentVariable 231 if (!EFI_ERROR(Status)) { 232 FreePool (BootOrder); 233 } 234 } else { 235 DEBUG((EFI_D_ERROR,"Update %s\n",BootVariableName)); 236 } 237 238 return EFI_SUCCESS; 239 } 240 241 UINT16 242 BootOptionAllocateBootIndex ( 243 VOID 244 ) 245 { 246 EFI_STATUS Status; 247 UINTN Index; 248 UINT32 BootIndex; 249 UINT16 *BootOrder; 250 UINTN BootOrderSize; 251 BOOLEAN Found; 252 253 // Get the Boot Option Order from the environment variable 254 Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder); 255 if (!EFI_ERROR(Status)) { 256 for (BootIndex = 0; BootIndex <= 0xFFFF; BootIndex++) { 257 Found = FALSE; 258 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) { 259 if (BootOrder[Index] == BootIndex) { 260 Found = TRUE; 261 break; 262 } 263 } 264 if (!Found) { 265 return BootIndex; 266 } 267 } 268 FreePool (BootOrder); 269 } 270 // Return the first index 271 return 0; 272 } 273