Channagoud Kadabi | f8aa763 | 2015-11-12 14:27:01 -0800 | [diff] [blame] | 1 | /* |
Bhanuprakash Modem | 937fc4a | 2018-06-12 16:11:26 +0530 | [diff] [blame] | 2 | * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. |
Channagoud Kadabi | f8aa763 | 2015-11-12 14:27:01 -0800 | [diff] [blame] | 3 | * |
| 4 | * Redistribution and use in source and binary forms, with or without |
| 5 | * modification, are permitted provided that the following conditions are met: |
| 6 | * * Redistributions of source code must retain the above copyright |
| 7 | * notice, this list of conditions and the following disclaimer. |
| 8 | * * Redistributions in binary form must reproduce the above copyright |
| 9 | * notice, this list of conditions and the following disclaimer in the |
| 10 | * documentation and/or other materials provided with the distribution. |
| 11 | * * Neither the name of The Linux Foundation nor |
| 12 | * the names of its contributors may be used to endorse or promote |
| 13 | * products derived from this software without specific prior written |
| 14 | * permission. |
| 15 | * |
| 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 19 | * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| 20 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| 23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| 25 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| 26 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | * |
| 28 | */ |
| 29 | #include "PartitionTableUpdate.h" |
lijuang | f0bbcad | 2017-08-16 16:59:18 +0800 | [diff] [blame] | 30 | #include "AutoGen.h" |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 31 | #include <Library/Board.h> |
| 32 | #include <Library/BootLinux.h> |
| 33 | #include <Library/LinuxLoaderLib.h> |
| 34 | #include <Library/UefiLib.h> |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 35 | #include <Library/DebugLib.h> |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 36 | #include <Uefi.h> |
| 37 | #include <Uefi/UefiSpec.h> |
| 38 | #include <VerifiedBoot.h> |
lijuang | f0bbcad | 2017-08-16 16:59:18 +0800 | [diff] [blame] | 39 | |
Channagoud Kadabi | 8ad76a7 | 2016-02-16 17:26:59 -0800 | [diff] [blame] | 40 | STATIC BOOLEAN FlashingGpt; |
| 41 | STATIC BOOLEAN ParseSecondaryGpt; |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 42 | struct StoragePartInfo Ptable[MAX_LUNS]; |
| 43 | struct PartitionEntry PtnEntries[MAX_NUM_PARTITIONS]; |
| 44 | STATIC UINT32 MaxLuns; |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 45 | STATIC UINT32 PartitionCount; |
Shivaprasad Hongal | 340f687 | 2017-04-26 16:15:27 -0700 | [diff] [blame] | 46 | STATIC BOOLEAN FirstBoot; |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 47 | STATIC struct PartitionEntry PtnEntriesBak[MAX_NUM_PARTITIONS]; |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 48 | |
Vijay Kumar Pendoti | a7e72a0 | 2016-11-11 15:36:56 +0530 | [diff] [blame] | 49 | STATIC struct BootPartsLinkedList *HeadNode; |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 50 | STATIC EFI_STATUS |
| 51 | GetActiveSlot (Slot *ActiveSlot); |
Vijay Kumar Pendoti | a7e72a0 | 2016-11-11 15:36:56 +0530 | [diff] [blame] | 52 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 53 | Slot GetCurrentSlotSuffix (VOID) |
Shivaprasad Hongal | c017e81 | 2017-04-26 16:15:27 -0700 | [diff] [blame] | 54 | { |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 55 | Slot CurrentSlot = {{0}}; |
| 56 | BOOLEAN IsMultiSlot = PartitionHasMultiSlot ((CONST CHAR16 *)L"boot"); |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 57 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 58 | if (IsMultiSlot == FALSE) { |
| 59 | return CurrentSlot; |
| 60 | } |
lijuang | a4c1b08 | 2016-12-08 19:12:48 +0800 | [diff] [blame] | 61 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 62 | GetActiveSlot (&CurrentSlot); |
| 63 | return CurrentSlot; |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 64 | } |
| 65 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 66 | UINT32 GetMaxLuns (VOID) |
Jeevan Shriram | ab43668 | 2016-09-23 07:08:06 -0700 | [diff] [blame] | 67 | { |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 68 | return MaxLuns; |
Jeevan Shriram | ab43668 | 2016-09-23 07:08:06 -0700 | [diff] [blame] | 69 | } |
| 70 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 71 | UINT32 |
| 72 | GetPartitionLunFromIndex (UINT32 Index) |
Jeevan Shriram | ab43668 | 2016-09-23 07:08:06 -0700 | [diff] [blame] | 73 | { |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 74 | return PtnEntries[Index].lun; |
Jeevan Shriram | ab43668 | 2016-09-23 07:08:06 -0700 | [diff] [blame] | 75 | } |
| 76 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 77 | VOID |
| 78 | GetPartitionCount (UINT32 *Val) |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 79 | { |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 80 | *Val = PartitionCount; |
| 81 | return; |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 82 | } |
| 83 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 84 | INT32 |
| 85 | GetPartitionIdxInLun (CHAR16 *Pname, UINT32 Lun) |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 86 | { |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 87 | UINT32 n; |
| 88 | UINT32 RelativeIndex = 0; |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 89 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 90 | for (n = 0; n < PartitionCount; n++) { |
| 91 | if (Lun == PtnEntries[n].lun) { |
| 92 | if (!StrnCmp (Pname, PtnEntries[n].PartEntry.PartitionName, |
| 93 | ARRAY_SIZE (PtnEntries[n].PartEntry.PartitionName))) { |
| 94 | return RelativeIndex; |
| 95 | } |
| 96 | RelativeIndex++; |
lijuang | 46df844 | 2017-09-28 19:06:36 +0800 | [diff] [blame] | 97 | } |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 98 | } |
| 99 | return INVALID_PTN; |
| 100 | } |
| 101 | |
| 102 | VOID UpdatePartitionEntries (VOID) |
| 103 | { |
| 104 | UINT32 i; |
| 105 | UINT32 j; |
| 106 | UINT32 Index = 0; |
| 107 | EFI_STATUS Status; |
| 108 | EFI_PARTITION_ENTRY *PartEntry; |
| 109 | |
| 110 | PartitionCount = 0; |
| 111 | /*Nullify the PtnEntries array before using it*/ |
| 112 | gBS->SetMem ((VOID *)PtnEntries, |
| 113 | (sizeof (PtnEntries[0]) * MAX_NUM_PARTITIONS), 0); |
| 114 | |
| 115 | for (i = 0; i < MaxLuns; i++) { |
| 116 | for (j = 0; (j < Ptable[i].MaxHandles) && (Index < MAX_NUM_PARTITIONS); |
| 117 | j++, Index++) { |
| 118 | Status = |
| 119 | gBS->HandleProtocol (Ptable[i].HandleInfoList[j].Handle, |
| 120 | &gEfiPartitionRecordGuid, (VOID **)&PartEntry); |
| 121 | PartitionCount++; |
| 122 | if (EFI_ERROR (Status)) { |
| 123 | DEBUG ((EFI_D_VERBOSE, "Selected Lun : %d, handle: %d does not have " |
| 124 | "partition record, ignore\n", |
| 125 | i, j)); |
| 126 | PtnEntries[Index].lun = i; |
| 127 | continue; |
| 128 | } |
| 129 | |
| 130 | gBS->CopyMem ((&PtnEntries[Index]), PartEntry, sizeof (PartEntry[0])); |
| 131 | PtnEntries[Index].lun = i; |
| 132 | } |
| 133 | } |
Nagireddy Annem | 672b53f | 2019-11-11 13:55:48 +0530 | [diff] [blame] | 134 | if (NAND == CheckRootDeviceType ()) { |
| 135 | NandABUpdatePartition (PTN_ENTRIES_FROM_MISC); |
| 136 | } |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 137 | /* Back up the ptn entries */ |
| 138 | gBS->CopyMem (PtnEntriesBak, PtnEntries, sizeof (PtnEntries)); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 139 | } |
| 140 | |
| 141 | INT32 |
| 142 | GetPartitionIndex (CHAR16 *Pname) |
| 143 | { |
| 144 | INT32 i; |
| 145 | |
| 146 | for (i = 0; i < PartitionCount; i++) { |
| 147 | if (!StrnCmp (PtnEntries[i].PartEntry.PartitionName, Pname, |
| 148 | ARRAY_SIZE (PtnEntries[i].PartEntry.PartitionName))) { |
| 149 | return i; |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | return INVALID_PTN; |
| 154 | } |
| 155 | |
| 156 | STATIC EFI_STATUS |
| 157 | GetStorageHandle (INT32 Lun, HandleInfo *BlockIoHandle, UINT32 *MaxHandles) |
| 158 | { |
| 159 | EFI_STATUS Status = EFI_INVALID_PARAMETER; |
| 160 | UINT32 Attribs = 0; |
| 161 | PartiSelectFilter HandleFilter; |
| 162 | // UFS LUN GUIDs |
| 163 | EFI_GUID LunGuids[] = { |
| 164 | gEfiUfsLU0Guid, gEfiUfsLU1Guid, gEfiUfsLU2Guid, gEfiUfsLU3Guid, |
| 165 | gEfiUfsLU4Guid, gEfiUfsLU5Guid, gEfiUfsLU6Guid, gEfiUfsLU7Guid, |
| 166 | }; |
| 167 | |
| 168 | Attribs |= BLK_IO_SEL_SELECT_ROOT_DEVICE_ONLY; |
| 169 | HandleFilter.PartitionType = NULL; |
| 170 | HandleFilter.VolumeName = NULL; |
| 171 | |
| 172 | if (Lun == NO_LUN) { |
| 173 | HandleFilter.RootDeviceType = &gEfiEmmcUserPartitionGuid; |
| 174 | Status = |
| 175 | GetBlkIOHandles (Attribs, &HandleFilter, BlockIoHandle, MaxHandles); |
| 176 | if (EFI_ERROR (Status)) { |
| 177 | DEBUG ((EFI_D_ERROR, "Error getting block IO handle for Emmc\n")); |
| 178 | return Status; |
| 179 | } |
| 180 | } else { |
| 181 | HandleFilter.RootDeviceType = &LunGuids[Lun]; |
| 182 | Status = |
| 183 | GetBlkIOHandles (Attribs, &HandleFilter, BlockIoHandle, MaxHandles); |
| 184 | if (EFI_ERROR (Status)) { |
| 185 | DEBUG ((EFI_D_ERROR, "Error getting block IO handle for Lun:%x\n", Lun)); |
| 186 | return Status; |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | return Status; |
| 191 | } |
| 192 | |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 193 | STATIC BOOLEAN IsUpdatePartitionAttributes () |
| 194 | { |
| 195 | if (CompareMem (PtnEntries, PtnEntriesBak, sizeof (PtnEntries))) { |
| 196 | return TRUE; |
| 197 | } |
| 198 | return FALSE; |
| 199 | } |
| 200 | |
Lijuan Gao | be74b9e | 2020-09-21 20:29:27 +0800 | [diff] [blame] | 201 | UINT64 GetPartitionSize (EFI_BLOCK_IO_PROTOCOL *BlockIo) |
| 202 | { |
| 203 | UINT64 PartitionSize; |
| 204 | |
| 205 | if (!BlockIo) { |
| 206 | DEBUG ((EFI_D_ERROR, "Invalid parameter, pleae check BlockIo info!!!\n")); |
| 207 | return 0; |
| 208 | } |
| 209 | |
| 210 | if (CHECK_ADD64 (BlockIo->Media->LastBlock, 1)) { |
| 211 | DEBUG ((EFI_D_ERROR, "Integer overflow while adding LastBlock and 1\n")); |
| 212 | return 0; |
| 213 | } |
| 214 | |
| 215 | if ((MAX_UINT64 / (BlockIo->Media->LastBlock + 1)) < |
| 216 | (UINT64)BlockIo->Media->BlockSize) { |
| 217 | DEBUG ((EFI_D_ERROR, |
| 218 | "Integer overflow while multiplying LastBlock and BlockSize\n")); |
| 219 | return 0; |
| 220 | } |
| 221 | |
| 222 | PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize; |
| 223 | return PartitionSize; |
| 224 | } |
| 225 | |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 226 | VOID UpdatePartitionAttributes (UINT32 UpdateType) |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 227 | { |
| 228 | UINT32 BlkSz; |
| 229 | UINT8 *GptHdr = NULL; |
| 230 | UINT8 *GptHdrPtr = NULL; |
| 231 | UINTN MaxGptPartEntrySzBytes; |
| 232 | UINT32 Offset; |
| 233 | UINT32 MaxPtnCount = 0; |
| 234 | UINT32 PtnEntrySz = 0; |
| 235 | UINT32 i = 0; |
| 236 | UINT8 *PtnEntriesPtr; |
| 237 | UINT8 *Ptn_Entries; |
| 238 | UINT32 CrcVal = 0; |
| 239 | UINT32 Iter; |
| 240 | UINT32 HdrSz = GPT_HEADER_SIZE; |
| 241 | UINT64 DeviceDensity; |
| 242 | UINT64 CardSizeSec; |
| 243 | EFI_STATUS Status; |
| 244 | INT32 Lun; |
| 245 | EFI_BLOCK_IO_PROTOCOL *BlockIo = NULL; |
| 246 | HandleInfo BlockIoHandle[MAX_HANDLEINF_LST_SIZE]; |
| 247 | UINT32 MaxHandles = MAX_HANDLEINF_LST_SIZE; |
| 248 | CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX]; |
| 249 | UINT32 PartEntriesblocks = 0; |
| 250 | BOOLEAN SkipUpdation; |
| 251 | UINT64 Attr; |
Mukesh Ojha | 8c4f272 | 2017-11-23 15:09:55 +0530 | [diff] [blame] | 252 | struct PartitionEntry *InMemPtnEnt; |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 253 | |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 254 | /* The PtnEntries is the same as PtnEntriesBak by default |
| 255 | * It needs to update attributes or GUID when PtnEntries is changed |
| 256 | */ |
| 257 | if (!IsUpdatePartitionAttributes ()) { |
| 258 | return; |
| 259 | } |
| 260 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 261 | GetRootDeviceType (BootDeviceType, BOOT_DEV_NAME_SIZE_MAX); |
| 262 | for (Lun = 0; Lun < MaxLuns; Lun++) { |
| 263 | |
| 264 | if (!AsciiStrnCmp (BootDeviceType, "EMMC", AsciiStrLen ("EMMC"))) { |
| 265 | Status = GetStorageHandle (NO_LUN, BlockIoHandle, &MaxHandles); |
| 266 | } else if (!AsciiStrnCmp (BootDeviceType, "UFS", AsciiStrLen ("UFS"))) { |
| 267 | Status = GetStorageHandle (Lun, BlockIoHandle, &MaxHandles); |
Nagireddy Annem | 672b53f | 2019-11-11 13:55:48 +0530 | [diff] [blame] | 268 | } else if (!AsciiStrnCmp (BootDeviceType, "NAND", AsciiStrLen ("NAND"))) { |
| 269 | if (UpdateType & PARTITION_ATTRIBUTES_MASK) { |
| 270 | NandABUpdatePartition (PTN_ENTRIES_TO_MISC); |
| 271 | gBS->CopyMem (PtnEntriesBak, PtnEntries, sizeof (PtnEntries)); |
| 272 | } |
| 273 | return; |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 274 | } else { |
| 275 | DEBUG ((EFI_D_ERROR, "Unsupported boot device type\n")); |
| 276 | return; |
| 277 | } |
| 278 | |
| 279 | if (Status != EFI_SUCCESS) { |
| 280 | DEBUG ((EFI_D_ERROR, |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 281 | "Failed to get BlkIo for device. MaxHandles:%d - %r\n", |
| 282 | MaxHandles, Status)); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 283 | return; |
| 284 | } |
| 285 | if (MaxHandles != 1) { |
| 286 | DEBUG ((EFI_D_VERBOSE, |
| 287 | "Failed to get the BlockIo for device. MaxHandle:%d, %r\n", |
| 288 | MaxHandles, Status)); |
| 289 | continue; |
| 290 | } |
| 291 | |
| 292 | BlockIo = BlockIoHandle[0].BlkIo; |
Lijuan Gao | be74b9e | 2020-09-21 20:29:27 +0800 | [diff] [blame] | 293 | DeviceDensity = GetPartitionSize (BlockIo); |
| 294 | if (!DeviceDensity) { |
| 295 | return; |
| 296 | } |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 297 | BlkSz = BlockIo->Media->BlockSize; |
| 298 | PartEntriesblocks = MAX_PARTITION_ENTRIES_SZ / BlkSz; |
| 299 | MaxGptPartEntrySzBytes = (GPT_HDR_BLOCKS + PartEntriesblocks) * BlkSz; |
| 300 | CardSizeSec = (DeviceDensity) / BlkSz; |
| 301 | Offset = PRIMARY_HDR_LBA; |
Bhanuprakash Modem | 763cdd5 | 2018-11-01 14:49:55 +0530 | [diff] [blame] | 302 | GptHdr = AllocateZeroPool (MaxGptPartEntrySzBytes); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 303 | if (!GptHdr) { |
| 304 | DEBUG ((EFI_D_ERROR, "Unable to Allocate Memory for GptHdr \n")); |
| 305 | return; |
| 306 | } |
| 307 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 308 | GptHdrPtr = GptHdr; |
| 309 | |
| 310 | /* This loop iterates twice to update both primary and backup Gpt*/ |
| 311 | for (Iter = 0; Iter < 2; |
| 312 | Iter++, (Offset = CardSizeSec - MaxGptPartEntrySzBytes / BlkSz)) { |
| 313 | SkipUpdation = TRUE; |
| 314 | Status = BlockIo->ReadBlocks (BlockIo, BlockIo->Media->MediaId, Offset, |
| 315 | MaxGptPartEntrySzBytes, GptHdr); |
| 316 | |
| 317 | if (EFI_ERROR (Status)) { |
| 318 | DEBUG ((EFI_D_ERROR, "Unable to read the media \n")); |
| 319 | goto Exit; |
| 320 | } |
| 321 | |
| 322 | if (Iter == 0x1) { |
| 323 | /* This is the back up GPT */ |
| 324 | Ptn_Entries = GptHdr; |
| 325 | GptHdr = GptHdr + ((PartEntriesblocks)*BlkSz); |
| 326 | } else |
| 327 | /* otherwise we are at the primary gpt */ |
| 328 | Ptn_Entries = GptHdr + BlkSz; |
| 329 | |
| 330 | PtnEntriesPtr = Ptn_Entries; |
| 331 | |
| 332 | for (i = 0; i < PartitionCount; i++) { |
Mukesh Ojha | 8c4f272 | 2017-11-23 15:09:55 +0530 | [diff] [blame] | 333 | InMemPtnEnt = (struct PartitionEntry *)PtnEntriesPtr; |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 334 | /*If GUID is not present, then it is BlkIo Handle of the Lun. Skip*/ |
| 335 | if (!(PtnEntries[i].PartEntry.PartitionTypeGUID.Data1)) { |
| 336 | DEBUG ((EFI_D_VERBOSE, " Skipping Lun:%d, i=%d\n", Lun, i)); |
| 337 | continue; |
| 338 | } |
| 339 | |
| 340 | if (!AsciiStrnCmp (BootDeviceType, "UFS", AsciiStrLen ("UFS"))) { |
| 341 | /* Partition table is populated with entries from lun 0 to max lun. |
| 342 | * break out of the loop once we see the partition lun is > current |
| 343 | * lun */ |
| 344 | if (PtnEntries[i].lun > Lun) |
| 345 | break; |
| 346 | /* Find the entry where the partition table for 'lun' starts and then |
| 347 | * update the attributes */ |
| 348 | if (PtnEntries[i].lun != Lun) |
| 349 | continue; |
| 350 | } |
| 351 | Attr = GET_LLWORD_FROM_BYTE (&PtnEntriesPtr[ATTRIBUTE_FLAG_OFFSET]); |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 352 | if (UpdateType & PARTITION_GUID_MASK) { |
| 353 | if (CompareMem (&InMemPtnEnt->PartEntry.PartitionTypeGUID, |
| 354 | &PtnEntries[i].PartEntry.PartitionTypeGUID, |
| 355 | sizeof (EFI_GUID))) { |
| 356 | /* Update the partition GUID values */ |
| 357 | gBS->CopyMem ((VOID *)PtnEntriesPtr, |
| 358 | (VOID *)&PtnEntries[i].PartEntry.PartitionTypeGUID, |
| 359 | GUID_SIZE); |
| 360 | /* Update the PtnEntriesBak for next comparison */ |
| 361 | gBS->CopyMem ( |
| 362 | (VOID *)&PtnEntriesBak[i].PartEntry.PartitionTypeGUID, |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 363 | (VOID *)&PtnEntries[i].PartEntry.PartitionTypeGUID, |
| 364 | GUID_SIZE); |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 365 | SkipUpdation = FALSE; |
| 366 | } |
| 367 | } |
| 368 | |
| 369 | if (UpdateType & PARTITION_ATTRIBUTES_MASK) { |
| 370 | /* If GUID is not present, then it is back up GPT, update it |
| 371 | * If GUID is present, and the GUID is matched, update it |
| 372 | */ |
| 373 | if (!(InMemPtnEnt->PartEntry.PartitionTypeGUID.Data1) || |
| 374 | !CompareMem (&InMemPtnEnt->PartEntry.PartitionTypeGUID, |
| 375 | &PtnEntries[i].PartEntry.PartitionTypeGUID, |
| 376 | sizeof (EFI_GUID))) { |
| 377 | if (Attr != PtnEntries[i].PartEntry.Attributes) { |
| 378 | /* Update the partition attributes */ |
| 379 | PUT_LONG_LONG (&PtnEntriesPtr[ATTRIBUTE_FLAG_OFFSET], |
| 380 | PtnEntries[i].PartEntry.Attributes); |
| 381 | /* Update the PtnEntriesBak for next comparison */ |
| 382 | PtnEntriesBak[i].PartEntry.Attributes = |
| 383 | PtnEntries[i].PartEntry.Attributes; |
| 384 | SkipUpdation = FALSE; |
| 385 | } |
| 386 | } else { |
| 387 | if (InMemPtnEnt->PartEntry.PartitionTypeGUID.Data1) { |
| 388 | DEBUG ((EFI_D_ERROR, |
| 389 | "Error in GPT header, GUID is not match!\n")); |
| 390 | continue; |
| 391 | } |
| 392 | } |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 393 | } |
| 394 | |
| 395 | /* point to the next partition entry */ |
| 396 | PtnEntriesPtr += PARTITION_ENTRY_SIZE; |
| 397 | } |
| 398 | |
| 399 | if (SkipUpdation) |
| 400 | continue; |
| 401 | |
| 402 | MaxPtnCount = GET_LWORD_FROM_BYTE (&GptHdr[PARTITION_COUNT_OFFSET]); |
| 403 | PtnEntrySz = GET_LWORD_FROM_BYTE (&GptHdr[PENTRY_SIZE_OFFSET]); |
| 404 | |
| 405 | if (((UINT64) (MaxPtnCount)*PtnEntrySz) > MAX_PARTITION_ENTRIES_SZ) { |
| 406 | DEBUG ((EFI_D_ERROR, |
| 407 | "Invalid GPT header fields MaxPtnCount = %x, PtnEntrySz = %x\n", |
| 408 | MaxPtnCount, PtnEntrySz)); |
| 409 | goto Exit; |
| 410 | } |
| 411 | |
| 412 | Status = gBS->CalculateCrc32 (Ptn_Entries, ((MaxPtnCount) * (PtnEntrySz)), |
| 413 | &CrcVal); |
| 414 | if (Status != EFI_SUCCESS) { |
| 415 | DEBUG ((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n", |
| 416 | Status)); |
| 417 | goto Exit; |
| 418 | } |
| 419 | |
| 420 | PUT_LONG (&GptHdr[PARTITION_CRC_OFFSET], CrcVal); |
| 421 | |
| 422 | /*Write CRC to 0 before we calculate the crc of the GPT header*/ |
| 423 | CrcVal = 0; |
| 424 | PUT_LONG (&GptHdr[HEADER_CRC_OFFSET], CrcVal); |
| 425 | |
| 426 | Status = gBS->CalculateCrc32 (GptHdr, HdrSz, &CrcVal); |
| 427 | if (Status != EFI_SUCCESS) { |
| 428 | DEBUG ((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n", |
| 429 | Status)); |
| 430 | goto Exit; |
| 431 | } |
| 432 | |
| 433 | PUT_LONG (&GptHdr[HEADER_CRC_OFFSET], CrcVal); |
| 434 | |
| 435 | if (Iter == 0x1) |
| 436 | /* Write the backup GPT header, which is at an offset of CardSizeSec - |
| 437 | * MaxGptPartEntrySzBytes/BlkSz in blocks*/ |
| 438 | Status = |
| 439 | BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, Offset, |
| 440 | MaxGptPartEntrySzBytes, (VOID *)Ptn_Entries); |
| 441 | else |
| 442 | /* Write the primary GPT header, which is at an offset of BlkSz */ |
| 443 | Status = BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, Offset, |
| 444 | MaxGptPartEntrySzBytes, (VOID *)GptHdr); |
| 445 | |
| 446 | if (EFI_ERROR (Status)) { |
| 447 | DEBUG ((EFI_D_ERROR, "Error writing primary GPT header: %r\n", Status)); |
| 448 | goto Exit; |
| 449 | } |
| 450 | } |
| 451 | FreePool (GptHdrPtr); |
| 452 | GptHdrPtr = NULL; |
| 453 | } |
lijuang | 46df844 | 2017-09-28 19:06:36 +0800 | [diff] [blame] | 454 | |
| 455 | Exit: |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 456 | if (GptHdrPtr) { |
| 457 | FreePool (GptHdrPtr); |
| 458 | GptHdrPtr = NULL; |
| 459 | } |
| 460 | } |
| 461 | |
| 462 | STATIC VOID |
| 463 | MarkPtnActive (CHAR16 *ActiveSlot) |
| 464 | { |
| 465 | UINT32 i; |
| 466 | for (i = 0; i < PartitionCount; i++) { |
| 467 | /* Mark all the slots with current ActiveSlot as active */ |
| 468 | if (StrStr (PtnEntries[i].PartEntry.PartitionName, ActiveSlot)) |
| 469 | PtnEntries[i].PartEntry.Attributes |= PART_ATT_ACTIVE_VAL; |
| 470 | else |
| 471 | PtnEntries[i].PartEntry.Attributes &= ~PART_ATT_ACTIVE_VAL; |
| 472 | } |
| 473 | |
| 474 | /* Update the partition table */ |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 475 | UpdatePartitionAttributes (PARTITION_ATTRIBUTES); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 476 | } |
| 477 | |
| 478 | STATIC VOID |
| 479 | SwapPtnGuid (EFI_PARTITION_ENTRY *p1, EFI_PARTITION_ENTRY *p2) |
| 480 | { |
| 481 | EFI_GUID Temp; |
| 482 | |
| 483 | if (p1 == NULL || p2 == NULL) |
| 484 | return; |
| 485 | gBS->CopyMem ((VOID *)&Temp, (VOID *)&p1->PartitionTypeGUID, |
| 486 | sizeof (EFI_GUID)); |
| 487 | gBS->CopyMem ((VOID *)&p1->PartitionTypeGUID, (VOID *)&p2->PartitionTypeGUID, |
| 488 | sizeof (EFI_GUID)); |
| 489 | gBS->CopyMem ((VOID *)&p2->PartitionTypeGUID, (VOID *)&Temp, |
| 490 | sizeof (EFI_GUID)); |
| 491 | } |
| 492 | |
| 493 | STATIC EFI_STATUS GetMultiSlotPartsList (VOID) |
| 494 | { |
| 495 | UINT32 i = 0; |
| 496 | UINT32 j = 0; |
| 497 | UINT32 Len = 0; |
Mukesh Ojha | 28736ad | 2017-11-23 14:34:03 +0530 | [diff] [blame] | 498 | UINT32 PtnLen = 0; |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 499 | CHAR16 *SearchString = NULL; |
| 500 | struct BootPartsLinkedList *TempNode = NULL; |
| 501 | |
| 502 | for (i = 0; i < PartitionCount; i++) { |
| 503 | SearchString = PtnEntries[i].PartEntry.PartitionName; |
| 504 | if (!SearchString[0]) |
| 505 | continue; |
| 506 | |
| 507 | for (j = i + 1; j < PartitionCount; j++) { |
| 508 | if (!PtnEntries[j].PartEntry.PartitionName[0]) |
| 509 | continue; |
| 510 | Len = StrLen (SearchString); |
Mukesh Ojha | 28736ad | 2017-11-23 14:34:03 +0530 | [diff] [blame] | 511 | PtnLen = StrLen (PtnEntries[j].PartEntry.PartitionName); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 512 | |
| 513 | /*Need to compare till "boot_"a hence skip last Char from StrLen value*/ |
Mukesh Ojha | 28736ad | 2017-11-23 14:34:03 +0530 | [diff] [blame] | 514 | if ((PtnLen == Len) && |
| 515 | !StrnCmp (PtnEntries[j].PartEntry.PartitionName, |
| 516 | SearchString, Len - 1) && |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 517 | (StrStr (SearchString, (CONST CHAR16 *)L"_a") || |
Mukesh Ojha | 28736ad | 2017-11-23 14:34:03 +0530 | [diff] [blame] | 518 | StrStr (SearchString, (CONST CHAR16 *)L"_b"))) { |
Bhanuprakash Modem | 763cdd5 | 2018-11-01 14:49:55 +0530 | [diff] [blame] | 519 | TempNode = AllocateZeroPool (sizeof (struct BootPartsLinkedList)); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 520 | if (TempNode) { |
| 521 | /*Skip _a/_b from partition name*/ |
| 522 | StrnCpyS (TempNode->PartName, sizeof (TempNode->PartName), |
| 523 | SearchString, Len - 2); |
| 524 | TempNode->Next = HeadNode; |
| 525 | HeadNode = TempNode; |
| 526 | } else { |
| 527 | DEBUG ((EFI_D_ERROR, |
| 528 | "Unable to Allocate Memory for MultiSlot Partition list\n")); |
| 529 | return EFI_OUT_OF_RESOURCES; |
| 530 | } |
| 531 | break; |
| 532 | } |
lijuang | 46df844 | 2017-09-28 19:06:36 +0800 | [diff] [blame] | 533 | } |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 534 | } |
| 535 | return EFI_SUCCESS; |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 536 | } |
| 537 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 538 | STATIC VOID |
| 539 | SwitchPtnSlots (CONST CHAR16 *SetActive) |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 540 | { |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 541 | UINT32 i; |
| 542 | struct PartitionEntry *PtnCurrent = NULL; |
| 543 | struct PartitionEntry *PtnNew = NULL; |
| 544 | CHAR16 CurSlot[BOOT_PART_SIZE]; |
| 545 | CHAR16 NewSlot[BOOT_PART_SIZE]; |
| 546 | CHAR16 SetInactive[MAX_SLOT_SUFFIX_SZ]; |
| 547 | UINT32 UfsBootLun = 0; |
| 548 | BOOLEAN UfsGet = TRUE; |
| 549 | BOOLEAN UfsSet = FALSE; |
| 550 | struct BootPartsLinkedList *TempNode = NULL; |
| 551 | EFI_STATUS Status; |
| 552 | CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX]; |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 553 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 554 | /* Create the partition name string for active and non active slots*/ |
| 555 | if (!StrnCmp (SetActive, (CONST CHAR16 *)L"_a", |
| 556 | StrLen ((CONST CHAR16 *)L"_a"))) |
| 557 | StrnCpyS (SetInactive, MAX_SLOT_SUFFIX_SZ, (CONST CHAR16 *)L"_b", |
| 558 | StrLen ((CONST CHAR16 *)L"_b")); |
| 559 | else |
| 560 | StrnCpyS (SetInactive, MAX_SLOT_SUFFIX_SZ, (CONST CHAR16 *)L"_a", |
| 561 | StrLen ((CONST CHAR16 *)L"_a")); |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 562 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 563 | if (!HeadNode) { |
| 564 | Status = GetMultiSlotPartsList (); |
| 565 | if (Status != EFI_SUCCESS) { |
| 566 | DEBUG ((EFI_D_INFO, "Unable to get GetMultiSlotPartsList\n")); |
| 567 | return; |
| 568 | } |
| 569 | } |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 570 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 571 | for (TempNode = HeadNode; TempNode; TempNode = TempNode->Next) { |
| 572 | gBS->SetMem (CurSlot, BOOT_PART_SIZE, 0); |
| 573 | gBS->SetMem (NewSlot, BOOT_PART_SIZE, 0); |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 574 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 575 | StrnCpyS (CurSlot, BOOT_PART_SIZE, TempNode->PartName, |
| 576 | StrLen (TempNode->PartName)); |
| 577 | StrnCatS (CurSlot, BOOT_PART_SIZE, SetInactive, StrLen (SetInactive)); |
Vijay Kumar Pendoti | a7e72a0 | 2016-11-11 15:36:56 +0530 | [diff] [blame] | 578 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 579 | StrnCpyS (NewSlot, BOOT_PART_SIZE, TempNode->PartName, |
| 580 | StrLen (TempNode->PartName)); |
| 581 | StrnCatS (NewSlot, BOOT_PART_SIZE, SetActive, StrLen (SetActive)); |
Vijay Kumar Pendoti | a7e72a0 | 2016-11-11 15:36:56 +0530 | [diff] [blame] | 582 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 583 | /* Find the pointer to partition table entry for active and non-active |
| 584 | * slots*/ |
| 585 | for (i = 0; i < PartitionCount; i++) { |
| 586 | if (!StrnCmp (PtnEntries[i].PartEntry.PartitionName, CurSlot, |
| 587 | StrLen (CurSlot))) { |
| 588 | PtnCurrent = &PtnEntries[i]; |
| 589 | } else if (!StrnCmp (PtnEntries[i].PartEntry.PartitionName, NewSlot, |
| 590 | StrLen (NewSlot))) { |
| 591 | PtnNew = &PtnEntries[i]; |
| 592 | } |
| 593 | } |
| 594 | /* Swap the guids for the slots */ |
| 595 | SwapPtnGuid (&PtnCurrent->PartEntry, &PtnNew->PartEntry); |
| 596 | PtnCurrent = PtnNew = NULL; |
| 597 | } |
Vijay Kumar Pendoti | a7e72a0 | 2016-11-11 15:36:56 +0530 | [diff] [blame] | 598 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 599 | GetRootDeviceType (BootDeviceType, BOOT_DEV_NAME_SIZE_MAX); |
| 600 | if (!AsciiStrnCmp (BootDeviceType, "UFS", AsciiStrLen ("UFS"))) { |
| 601 | UfsGetSetBootLun (&UfsBootLun, UfsGet); |
| 602 | // Special case for XBL is to change the bootlun instead of swapping the |
| 603 | // guid |
| 604 | if (UfsBootLun == 0x1 && |
| 605 | !StrnCmp (SetActive, (CONST CHAR16 *)L"_b", |
| 606 | StrLen ((CONST CHAR16 *)L"_b"))) { |
| 607 | DEBUG ((EFI_D_INFO, "Switching the boot lun from 1 to 2\n")); |
| 608 | UfsBootLun = 0x2; |
| 609 | } else if (UfsBootLun == 0x2 && |
| 610 | !StrnCmp (SetActive, (CONST CHAR16 *)L"_a", |
| 611 | StrLen ((CONST CHAR16 *)L"_a"))) { |
| 612 | DEBUG ((EFI_D_INFO, "Switching the boot lun from 2 to 1\n")); |
| 613 | UfsBootLun = 0x1; |
| 614 | } |
| 615 | UfsGetSetBootLun (&UfsBootLun, UfsSet); |
| 616 | } |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 617 | |
| 618 | UpdatePartitionAttributes (PARTITION_GUID); |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 619 | } |
| 620 | |
| 621 | EFI_STATUS |
lijuang | f0bbcad | 2017-08-16 16:59:18 +0800 | [diff] [blame] | 622 | EnumeratePartitions (VOID) |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 623 | { |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 624 | EFI_STATUS Status; |
| 625 | PartiSelectFilter HandleFilter; |
| 626 | UINT32 Attribs = 0; |
| 627 | UINT32 i; |
| 628 | // UFS LUN GUIDs |
| 629 | EFI_GUID LunGuids[] = { |
| 630 | gEfiUfsLU0Guid, gEfiUfsLU1Guid, gEfiUfsLU2Guid, gEfiUfsLU3Guid, |
| 631 | gEfiUfsLU4Guid, gEfiUfsLU5Guid, gEfiUfsLU6Guid, gEfiUfsLU7Guid, |
| 632 | }; |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 633 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 634 | gBS->SetMem ((VOID *)Ptable, (sizeof (struct StoragePartInfo) * MAX_LUNS), 0); |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 635 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 636 | /* By default look for emmc partitions if not found look for UFS */ |
| 637 | Attribs |= BLK_IO_SEL_MATCH_ROOT_DEVICE; |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 638 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 639 | Ptable[0].MaxHandles = ARRAY_SIZE (Ptable[0].HandleInfoList); |
| 640 | HandleFilter.PartitionType = NULL; |
| 641 | HandleFilter.VolumeName = NULL; |
| 642 | HandleFilter.RootDeviceType = &gEfiNandUserPartitionGuid; |
Jeevan Shriram | 749ea92 | 2017-08-15 13:50:12 -0700 | [diff] [blame] | 643 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 644 | Status = |
| 645 | GetBlkIOHandles (Attribs, &HandleFilter, &Ptable[0].HandleInfoList[0], |
| 646 | &Ptable[0].MaxHandles); |
| 647 | /* For Emmc/NAND devices the Lun concept does not exist, we will always one |
| 648 | * lun and the lun number is '0' |
| 649 | * to have the partition selection implementation same acros |
| 650 | */ |
| 651 | if (Status == EFI_SUCCESS && Ptable[0].MaxHandles > 0) { |
| 652 | MaxLuns = 1; |
| 653 | return Status; |
| 654 | } |
Jeevan Shriram | 749ea92 | 2017-08-15 13:50:12 -0700 | [diff] [blame] | 655 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 656 | Ptable[0].MaxHandles = ARRAY_SIZE (Ptable[0].HandleInfoList); |
| 657 | HandleFilter.PartitionType = NULL; |
| 658 | HandleFilter.VolumeName = NULL; |
| 659 | HandleFilter.RootDeviceType = &gEfiEmmcUserPartitionGuid; |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 660 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 661 | Status = |
| 662 | GetBlkIOHandles (Attribs, &HandleFilter, &Ptable[0].HandleInfoList[0], |
| 663 | &Ptable[0].MaxHandles); |
| 664 | if (Status == EFI_SUCCESS && Ptable[0].MaxHandles > 0) { |
| 665 | MaxLuns = 1; |
| 666 | } |
| 667 | /* If the media is not emmc then look for UFS */ |
| 668 | else if (EFI_ERROR (Status) || Ptable[0].MaxHandles == 0) { |
| 669 | /* By default max 8 luns are supported but HW could be configured to use |
| 670 | * only few of them or all of them |
| 671 | * Based on the information read update the MaxLuns to reflect the max |
| 672 | * supported luns */ |
| 673 | for (i = 0; i < MAX_LUNS; i++) { |
| 674 | Ptable[i].MaxHandles = ARRAY_SIZE (Ptable[i].HandleInfoList); |
| 675 | HandleFilter.PartitionType = NULL; |
| 676 | HandleFilter.VolumeName = NULL; |
| 677 | HandleFilter.RootDeviceType = &LunGuids[i]; |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 678 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 679 | Status = |
| 680 | GetBlkIOHandles (Attribs, &HandleFilter, &Ptable[i].HandleInfoList[0], |
| 681 | &Ptable[i].MaxHandles); |
| 682 | /* If we fail to get block for a lun that means the lun is not configured |
| 683 | * and unsed, ignore the error |
| 684 | * and continue with the next Lun */ |
| 685 | if (EFI_ERROR (Status)) { |
| 686 | DEBUG ((EFI_D_ERROR, |
| 687 | "Error getting block IO handle for %d lun, Lun may be unused\n", |
| 688 | i)); |
| 689 | continue; |
| 690 | } |
| 691 | } |
| 692 | MaxLuns = i; |
| 693 | } else { |
| 694 | DEBUG ((EFI_D_ERROR, "Error populating block IO handles\n")); |
| 695 | return EFI_NOT_FOUND; |
| 696 | } |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 697 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 698 | return Status; |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 699 | } |
| 700 | |
| 701 | /*Function to provide has-slot info |
| 702 | *Pname: the partition name |
| 703 | *return: 1 or 0. |
| 704 | */ |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 705 | BOOLEAN |
| 706 | PartitionHasMultiSlot (CONST CHAR16 *Pname) |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 707 | { |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 708 | UINT32 i; |
| 709 | UINT32 SlotCount = 0; |
| 710 | UINT32 Len = StrLen (Pname); |
Vijay Kumar Pendoti | c3e0a4f | 2016-08-27 03:31:40 +0530 | [diff] [blame] | 711 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 712 | for (i = 0; i < PartitionCount; i++) { |
| 713 | if (!(StrnCmp (PtnEntries[i].PartEntry.PartitionName, Pname, Len))) { |
| 714 | if (PtnEntries[i].PartEntry.PartitionName[Len] == L'_' && |
| 715 | (PtnEntries[i].PartEntry.PartitionName[Len + 1] == L'a' || |
| 716 | PtnEntries[i].PartEntry.PartitionName[Len + 1] == L'b')) |
| 717 | if (++SlotCount > MIN_SLOTS) { |
| 718 | return TRUE; |
Zhen Kong | 4c788f5 | 2017-07-19 16:51:58 -0700 | [diff] [blame] | 719 | } |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 720 | } |
| 721 | } |
| 722 | return FALSE; |
Zhen Kong | 4c788f5 | 2017-07-19 16:51:58 -0700 | [diff] [blame] | 723 | } |
| 724 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 725 | VOID FindPtnActiveSlot (VOID) |
Shivaprasad Hongal | c017e81 | 2017-04-26 16:15:27 -0700 | [diff] [blame] | 726 | { |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 727 | Slot ActiveSlot = {{0}}; |
Shivaprasad Hongal | c017e81 | 2017-04-26 16:15:27 -0700 | [diff] [blame] | 728 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 729 | GetActiveSlot (&ActiveSlot); |
| 730 | return; |
Shivaprasad Hongal | c017e81 | 2017-04-26 16:15:27 -0700 | [diff] [blame] | 731 | } |
| 732 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 733 | STATIC UINT32 |
| 734 | PartitionVerifyMbrSignature (UINT32 Sz, UINT8 *Gpt) |
Shivaprasad Hongal | c017e81 | 2017-04-26 16:15:27 -0700 | [diff] [blame] | 735 | { |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 736 | if ((MBR_SIGNATURE + 1) >= Sz) { |
| 737 | DEBUG ((EFI_D_ERROR, "Gpt Image size is invalid\n")); |
| 738 | return FAILURE; |
| 739 | } |
Shivaprasad Hongal | c017e81 | 2017-04-26 16:15:27 -0700 | [diff] [blame] | 740 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 741 | /* Check for the signature */ |
| 742 | if ((Gpt[MBR_SIGNATURE] != MBR_SIGNATURE_BYTE_0) || |
| 743 | (Gpt[MBR_SIGNATURE + 1] != MBR_SIGNATURE_BYTE_1)) { |
| 744 | DEBUG ((EFI_D_ERROR, "MBR signature do not match\n")); |
| 745 | return FAILURE; |
| 746 | } |
| 747 | return SUCCESS; |
| 748 | } |
Shivaprasad Hongal | c017e81 | 2017-04-26 16:15:27 -0700 | [diff] [blame] | 749 | |
Prakruthi Deepak Heragu | d84bac2 | 2019-09-26 16:02:18 -0700 | [diff] [blame] | 750 | UINT32 |
| 751 | PartitionVerifyMibibImage (UINT8 *Image) |
| 752 | { |
| 753 | |
| 754 | /* Check for the MIBIB Magic */ |
| 755 | if ((((UINT32 *)Image)[0] != MIBIB_MAGIC1) || |
| 756 | (((UINT32 *)Image)[1] != MIBIB_MAGIC2)) { |
| 757 | DEBUG ((EFI_D_ERROR, "Mibib Magic do not match\n")); |
| 758 | return FAILURE; |
| 759 | } |
| 760 | return SUCCESS; |
| 761 | } |
| 762 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 763 | STATIC UINT32 |
| 764 | MbrGetPartitionType (UINT32 Sz, UINT8 *Gpt, UINT32 *Ptype) |
| 765 | { |
| 766 | UINT32 PtypeOffset = MBR_PARTITION_RECORD + OS_TYPE; |
Shivaprasad Hongal | c017e81 | 2017-04-26 16:15:27 -0700 | [diff] [blame] | 767 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 768 | if (Sz <= PtypeOffset) { |
| 769 | DEBUG ((EFI_D_ERROR, |
| 770 | "Input gpt image does not have gpt partition record data\n")); |
| 771 | return FAILURE; |
| 772 | } |
Shivaprasad Hongal | c017e81 | 2017-04-26 16:15:27 -0700 | [diff] [blame] | 773 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 774 | *Ptype = Gpt[PtypeOffset]; |
Shivaprasad Hongal | c017e81 | 2017-04-26 16:15:27 -0700 | [diff] [blame] | 775 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 776 | return SUCCESS; |
| 777 | } |
Shivaprasad Hongal | c017e81 | 2017-04-26 16:15:27 -0700 | [diff] [blame] | 778 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 779 | STATIC UINT32 |
| 780 | PartitionGetType (UINT32 Sz, UINT8 *Gpt, UINT32 *Ptype) |
| 781 | { |
| 782 | UINT32 Ret; |
| 783 | |
| 784 | Ret = PartitionVerifyMbrSignature (Sz, Gpt); |
| 785 | if (!Ret) { |
| 786 | /* MBR signature match, this coulb be MBR, MBR + EBR or GPT */ |
| 787 | Ret = MbrGetPartitionType (Sz, Gpt, Ptype); |
| 788 | if (!Ret) { |
| 789 | if (*Ptype == GPT_PROTECTIVE) |
| 790 | *Ptype = PARTITION_TYPE_GPT; |
| 791 | else |
| 792 | *Ptype = PARTITION_TYPE_MBR; |
| 793 | } |
| 794 | } else { |
| 795 | /* This could be GPT back up */ |
| 796 | *Ptype = PARTITION_TYPE_GPT_BACKUP; |
| 797 | Ret = SUCCESS; |
| 798 | } |
| 799 | |
| 800 | return Ret; |
| 801 | } |
| 802 | |
| 803 | STATIC UINT32 |
| 804 | ParseGptHeader (struct GptHeaderData *GptHeader, |
| 805 | UINT8 *GptBuffer, |
| 806 | UINT64 DeviceDensity, |
| 807 | UINT32 BlkSz) |
| 808 | { |
| 809 | UINT32 CrcOrig; |
| 810 | UINT32 CrcVal; |
| 811 | UINT32 CurrentLba; |
| 812 | EFI_STATUS Status; |
| 813 | |
| 814 | if (((UINT32 *)GptBuffer)[0] != GPT_SIGNATURE_2 || |
| 815 | ((UINT32 *)GptBuffer)[1] != GPT_SIGNATURE_1) { |
| 816 | DEBUG ((EFI_D_ERROR, "Gpt signature is not correct\n")); |
| 817 | return FAILURE; |
| 818 | } |
| 819 | |
| 820 | GptHeader->HeaderSz = GET_LWORD_FROM_BYTE (&GptBuffer[HEADER_SIZE_OFFSET]); |
| 821 | /* Validate the header size */ |
| 822 | if (GptHeader->HeaderSz < GPT_HEADER_SIZE) { |
| 823 | DEBUG ((EFI_D_ERROR, "GPT Header size is too small: %u\n", |
| 824 | GptHeader->HeaderSz)); |
| 825 | return FAILURE; |
| 826 | } |
| 827 | |
| 828 | if (GptHeader->HeaderSz > BlkSz) { |
| 829 | DEBUG ((EFI_D_ERROR, "GPT Header is too large: %u\n", GptHeader->HeaderSz)); |
| 830 | return FAILURE; |
| 831 | } |
| 832 | |
| 833 | CrcOrig = GET_LWORD_FROM_BYTE (&GptBuffer[HEADER_CRC_OFFSET]); |
| 834 | /* CRC value is computed by setting this field to 0, and computing the 32-bit |
| 835 | * CRC for HeaderSize bytes */ |
| 836 | CrcVal = 0; |
| 837 | PUT_LONG (&GptBuffer[HEADER_CRC_OFFSET], CrcVal); |
| 838 | |
| 839 | Status = gBS->CalculateCrc32 (GptBuffer, GptHeader->HeaderSz, &CrcVal); |
| 840 | if (Status != EFI_SUCCESS) { |
| 841 | DEBUG ((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n", |
| 842 | Status)); |
| 843 | return FAILURE; |
| 844 | } |
| 845 | |
| 846 | if (CrcVal != CrcOrig) { |
| 847 | DEBUG ((EFI_D_ERROR, "Header CRC mismatch CrcVal = %u and CrcOrig = %u\n", |
| 848 | CrcVal, CrcOrig)); |
| 849 | return FAILURE; |
| 850 | } else |
| 851 | PUT_LONG (&GptBuffer[HEADER_CRC_OFFSET], CrcVal); |
| 852 | |
| 853 | CurrentLba = GET_LLWORD_FROM_BYTE (&GptBuffer[PRIMARY_HEADER_OFFSET]); |
| 854 | GptHeader->FirstUsableLba = |
| 855 | GET_LLWORD_FROM_BYTE (&GptBuffer[FIRST_USABLE_LBA_OFFSET]); |
| 856 | GptHeader->MaxPtCnt = |
| 857 | GET_LWORD_FROM_BYTE (&GptBuffer[PARTITION_COUNT_OFFSET]); |
| 858 | GptHeader->PartEntrySz = GET_LWORD_FROM_BYTE (&GptBuffer[PENTRY_SIZE_OFFSET]); |
| 859 | GptHeader->LastUsableLba = |
| 860 | GET_LLWORD_FROM_BYTE (&GptBuffer[LAST_USABLE_LBA_OFFSET]); |
| 861 | if (!ParseSecondaryGpt) { |
| 862 | if (CurrentLba != GPT_LBA) { |
| 863 | DEBUG ((EFI_D_ERROR, "GPT first usable LBA mismatch\n")); |
| 864 | return FAILURE; |
| 865 | } |
| 866 | } |
| 867 | |
| 868 | /* Check for first lba should be within valid range */ |
| 869 | if (GptHeader->FirstUsableLba > (DeviceDensity / BlkSz)) { |
| 870 | DEBUG ((EFI_D_ERROR, "FirstUsableLba: %u out of Device capacity\n", |
| 871 | GptHeader->FirstUsableLba)); |
| 872 | return FAILURE; |
| 873 | } |
| 874 | |
| 875 | /* Check for Last lba should be within valid range */ |
| 876 | if (GptHeader->LastUsableLba > (DeviceDensity / BlkSz)) { |
| 877 | DEBUG ((EFI_D_ERROR, "LastUsableLba: %u out of device capacity\n", |
| 878 | GptHeader->LastUsableLba)); |
| 879 | return FAILURE; |
| 880 | } |
| 881 | |
| 882 | if (GptHeader->PartEntrySz != GPT_PART_ENTRY_SIZE) { |
| 883 | DEBUG ((EFI_D_ERROR, "Invalid partition entry size: %u\n", |
| 884 | GptHeader->PartEntrySz)); |
| 885 | return FAILURE; |
| 886 | } |
| 887 | |
| 888 | if (GptHeader->MaxPtCnt > |
| 889 | (MIN_PARTITION_ARRAY_SIZE / (GptHeader->PartEntrySz))) { |
| 890 | DEBUG ((EFI_D_ERROR, "Invalid Max Partition Count: %u\n", |
| 891 | GptHeader->MaxPtCnt)); |
| 892 | return FAILURE; |
| 893 | } |
| 894 | |
| 895 | /* Todo: Check CRC during reading partition table*/ |
| 896 | if (!FlashingGpt) { |
| 897 | } |
| 898 | |
| 899 | return SUCCESS; |
| 900 | } |
| 901 | |
| 902 | STATIC UINT32 |
| 903 | PatchGpt (UINT8 *Gpt, |
| 904 | UINT64 DeviceDensity, |
| 905 | UINT32 PartEntryArrSz, |
| 906 | struct GptHeaderData *GptHeader, |
| 907 | UINT32 BlkSz) |
| 908 | { |
| 909 | UINT8 *PrimaryGptHeader; |
| 910 | UINT8 *SecondaryGptHeader; |
jianzhou | 8e3a230 | 2018-07-05 18:07:40 +0800 | [diff] [blame] | 911 | //define as 64 bit unsigned int |
| 912 | UINT64 *LastPartitionEntry; |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 913 | UINT64 NumSectors; |
| 914 | UINT32 Offset; |
| 915 | UINT32 TotalPart = 0; |
| 916 | UINT32 LastPartOffset; |
| 917 | UINT8 *PartitionEntryArrStart; |
| 918 | UINT32 CrcVal; |
| 919 | EFI_STATUS Status; |
Bhanuprakash Modem | 937fc4a | 2018-06-12 16:11:26 +0530 | [diff] [blame] | 920 | UINT32 PtnEntryBlks = (MAX_PARTITION_ENTRIES_SZ / BlkSz) + GPT_HDR_BLOCKS; |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 921 | NumSectors = DeviceDensity / BlkSz; |
| 922 | |
| 923 | /* Update the primary and backup GPT header offset with the sector location */ |
| 924 | PrimaryGptHeader = (Gpt + BlkSz); |
| 925 | /* Patch primary GPT */ |
| 926 | PUT_LONG_LONG (PrimaryGptHeader + BACKUP_HEADER_OFFSET, |
| 927 | (UINT64) (NumSectors - 1)); |
| 928 | PUT_LONG_LONG (PrimaryGptHeader + LAST_USABLE_LBA_OFFSET, |
Bhanuprakash Modem | 937fc4a | 2018-06-12 16:11:26 +0530 | [diff] [blame] | 929 | (UINT64) (NumSectors - (PtnEntryBlks + 1))); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 930 | |
| 931 | /* Patch Backup GPT */ |
| 932 | Offset = (2 * PartEntryArrSz); |
| 933 | SecondaryGptHeader = Offset + BlkSz + PrimaryGptHeader; |
| 934 | PUT_LONG_LONG (SecondaryGptHeader + PRIMARY_HEADER_OFFSET, (UINT64)1); |
| 935 | PUT_LONG_LONG (SecondaryGptHeader + LAST_USABLE_LBA_OFFSET, |
Bhanuprakash Modem | 937fc4a | 2018-06-12 16:11:26 +0530 | [diff] [blame] | 936 | (UINT64) (NumSectors - (PtnEntryBlks + 1))); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 937 | PUT_LONG_LONG (SecondaryGptHeader + PARTITION_ENTRIES_OFFSET, |
Bhanuprakash Modem | 937fc4a | 2018-06-12 16:11:26 +0530 | [diff] [blame] | 938 | (UINT64) (NumSectors - (PtnEntryBlks))); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 939 | |
| 940 | /* Patch the last partition */ |
jianzhou | 8e3a230 | 2018-07-05 18:07:40 +0800 | [diff] [blame] | 941 | LastPartitionEntry = (UINT64 *) |
| 942 | (PrimaryGptHeader + BlkSz + TotalPart * PARTITION_ENTRY_SIZE); |
| 943 | |
| 944 | //need check 128 bit for GUID |
Mukesh Ojha | 3ede872 | 2018-04-10 14:32:26 +0530 | [diff] [blame] | 945 | while ((TotalPart < GptHeader->MaxPtCnt) && |
jianzhou | 8e3a230 | 2018-07-05 18:07:40 +0800 | [diff] [blame] | 946 | ((*LastPartitionEntry != 0) || |
| 947 | (*(LastPartitionEntry + 1) != 0))) { |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 948 | TotalPart++; |
jianzhou | 8e3a230 | 2018-07-05 18:07:40 +0800 | [diff] [blame] | 949 | LastPartitionEntry = (UINT64 *) |
| 950 | (PrimaryGptHeader + BlkSz + TotalPart * PARTITION_ENTRY_SIZE); |
Mukesh Ojha | 3ede872 | 2018-04-10 14:32:26 +0530 | [diff] [blame] | 951 | } |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 952 | |
| 953 | LastPartOffset = |
| 954 | (TotalPart - 1) * PARTITION_ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA; |
| 955 | |
| 956 | PUT_LONG_LONG (PrimaryGptHeader + BlkSz + LastPartOffset, |
Bhanuprakash Modem | 937fc4a | 2018-06-12 16:11:26 +0530 | [diff] [blame] | 957 | (UINT64) (NumSectors - (PtnEntryBlks + 1))); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 958 | PUT_LONG_LONG (PrimaryGptHeader + BlkSz + LastPartOffset + PartEntryArrSz, |
Bhanuprakash Modem | 937fc4a | 2018-06-12 16:11:26 +0530 | [diff] [blame] | 959 | (UINT64) (NumSectors - (PtnEntryBlks + 1))); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 960 | |
| 961 | /* Update CRC of the partition entry array for both headers */ |
| 962 | PartitionEntryArrStart = PrimaryGptHeader + BlkSz; |
| 963 | Status = gBS->CalculateCrc32 (PartitionEntryArrStart, |
| 964 | (GptHeader->MaxPtCnt * GptHeader->PartEntrySz), |
| 965 | &CrcVal); |
| 966 | if (EFI_ERROR (Status)) { |
| 967 | DEBUG ( |
| 968 | (EFI_D_ERROR, "Error calculating CRC for primary partition entry\n")); |
| 969 | return FAILURE; |
| 970 | } |
| 971 | PUT_LONG (PrimaryGptHeader + PARTITION_CRC_OFFSET, CrcVal); |
| 972 | |
| 973 | Status = gBS->CalculateCrc32 (PartitionEntryArrStart + PartEntryArrSz, |
| 974 | (GptHeader->MaxPtCnt * GptHeader->PartEntrySz), |
| 975 | &CrcVal); |
| 976 | if (EFI_ERROR (Status)) { |
| 977 | DEBUG ( |
| 978 | (EFI_D_ERROR, "Error calculating CRC for secondary partition entry\n")); |
| 979 | return FAILURE; |
| 980 | } |
| 981 | PUT_LONG (SecondaryGptHeader + PARTITION_CRC_OFFSET, CrcVal); |
| 982 | |
| 983 | /* Clear Header CRC field values & recalculate */ |
| 984 | PUT_LONG (PrimaryGptHeader + HEADER_CRC_OFFSET, 0); |
| 985 | Status = gBS->CalculateCrc32 (PrimaryGptHeader, GPT_HEADER_SIZE, &CrcVal); |
| 986 | if (EFI_ERROR (Status)) { |
| 987 | DEBUG ((EFI_D_ERROR, "Error calculating CRC for primary gpt header\n")); |
| 988 | return FAILURE; |
| 989 | } |
| 990 | PUT_LONG (PrimaryGptHeader + HEADER_CRC_OFFSET, CrcVal); |
| 991 | PUT_LONG (SecondaryGptHeader + HEADER_CRC_OFFSET, 0); |
| 992 | Status = gBS->CalculateCrc32 (SecondaryGptHeader, GPT_HEADER_SIZE, &CrcVal); |
| 993 | if (EFI_ERROR (Status)) { |
| 994 | DEBUG ((EFI_D_ERROR, "Error calculating CRC for secondary gpt header\n")); |
| 995 | return FAILURE; |
| 996 | } |
| 997 | PUT_LONG (SecondaryGptHeader + HEADER_CRC_OFFSET, CrcVal); |
| 998 | |
| 999 | return SUCCESS; |
| 1000 | } |
| 1001 | |
| 1002 | STATIC UINT32 |
| 1003 | WriteGpt (INT32 Lun, UINT32 Sz, UINT8 *Gpt) |
| 1004 | { |
| 1005 | UINT32 Ret = 1; |
| 1006 | struct GptHeaderData GptHeader; |
| 1007 | UINT8 *PartEntryArrSt; |
| 1008 | UINT32 Offset; |
| 1009 | UINT32 PartEntryArrSz; |
| 1010 | UINT64 DeviceDensity; |
| 1011 | UINT32 BlkSz; |
| 1012 | UINT8 *PrimaryGptHdr = NULL; |
| 1013 | UINT8 *SecondaryGptHdr = NULL; |
| 1014 | EFI_STATUS Status; |
| 1015 | UINTN BackUpGptLba; |
| 1016 | UINTN PartitionEntryLba; |
| 1017 | EFI_BLOCK_IO_PROTOCOL *BlockIo = NULL; |
| 1018 | HandleInfo BlockIoHandle[MAX_HANDLEINF_LST_SIZE]; |
| 1019 | UINT32 MaxHandles = MAX_HANDLEINF_LST_SIZE; |
| 1020 | |
| 1021 | Ret = GetStorageHandle (Lun, BlockIoHandle, &MaxHandles); |
| 1022 | if (Ret || (MaxHandles != 1)) { |
| 1023 | DEBUG ((EFI_D_ERROR, "Failed to get the BlockIo for the device\n")); |
| 1024 | return Ret; |
| 1025 | } |
| 1026 | |
| 1027 | BlockIo = BlockIoHandle[0].BlkIo; |
Lijuan Gao | be74b9e | 2020-09-21 20:29:27 +0800 | [diff] [blame] | 1028 | DeviceDensity = GetPartitionSize (BlockIo); |
| 1029 | if (!DeviceDensity) { |
| 1030 | return FAILURE; |
| 1031 | } |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1032 | BlkSz = BlockIo->Media->BlockSize; |
| 1033 | |
Lijuan Gao | e53c24c | 2020-09-28 18:43:16 +0800 | [diff] [blame] | 1034 | /* Verity that passed block has valid GPT primary header |
| 1035 | * Sz is from mNumDataBytes and it will check at CmdDownload |
| 1036 | * if it is mNumDataBytes > MaxDownLoadSize it will fail early and |
| 1037 | * will not cause any oob |
| 1038 | */ |
| 1039 | if (Sz <= BlkSz * 2) { |
| 1040 | DEBUG ((EFI_D_ERROR, "Gpt Image size is invalid!\n")); |
| 1041 | return FAILURE; |
| 1042 | } |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1043 | PrimaryGptHdr = (Gpt + BlkSz); |
| 1044 | Ret = ParseGptHeader (&GptHeader, PrimaryGptHdr, DeviceDensity, BlkSz); |
| 1045 | if (Ret) { |
| 1046 | DEBUG ((EFI_D_ERROR, "GPT: Error processing primary GPT header\n")); |
| 1047 | return Ret; |
| 1048 | } |
| 1049 | |
| 1050 | /* Check if a valid back up GPT is present */ |
| 1051 | PartEntryArrSz = GptHeader.PartEntrySz * GptHeader.MaxPtCnt; |
| 1052 | if (PartEntryArrSz < MIN_PARTITION_ARRAY_SIZE) |
| 1053 | PartEntryArrSz = MIN_PARTITION_ARRAY_SIZE; |
| 1054 | |
| 1055 | /* Back up partition is stored in the reverse order with back GPT, followed by |
| 1056 | * part entries, find the offset to back up GPT */ |
| 1057 | Offset = (2 * PartEntryArrSz); |
Lijuan Gao | e53c24c | 2020-09-28 18:43:16 +0800 | [diff] [blame] | 1058 | if (Sz < (Offset + (BlkSz * 3))) { |
| 1059 | DEBUG ((EFI_D_ERROR, "Gpt Image size is invalid!!\n")); |
| 1060 | return FAILURE; |
| 1061 | } |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1062 | SecondaryGptHdr = Offset + BlkSz + PrimaryGptHdr; |
| 1063 | ParseSecondaryGpt = TRUE; |
| 1064 | |
| 1065 | Ret = ParseGptHeader (&GptHeader, SecondaryGptHdr, DeviceDensity, BlkSz); |
| 1066 | if (Ret) { |
| 1067 | DEBUG ((EFI_D_ERROR, "GPT: Error processing backup GPT header\n")); |
| 1068 | return Ret; |
| 1069 | } |
| 1070 | |
| 1071 | Ret = PatchGpt (Gpt, DeviceDensity, PartEntryArrSz, &GptHeader, BlkSz); |
| 1072 | if (Ret) { |
| 1073 | DEBUG ((EFI_D_ERROR, "Failed to patch GPT\n")); |
| 1074 | return Ret; |
| 1075 | } |
| 1076 | /* Erase the entire card */ |
| 1077 | Status = ErasePartition (BlockIo, BlockIoHandle[0].Handle); |
| 1078 | if (Status != EFI_SUCCESS) { |
| 1079 | DEBUG ((EFI_D_ERROR, "Error erasing the storage device: %r\n", Status)); |
| 1080 | return FAILURE; |
| 1081 | } |
| 1082 | |
| 1083 | /* write the protective MBR */ |
| 1084 | Status = BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, 0, BlkSz, |
| 1085 | (VOID *)Gpt); |
| 1086 | if (EFI_ERROR (Status)) { |
| 1087 | DEBUG ((EFI_D_ERROR, "Error writing protective MBR: %x\n", Status)); |
| 1088 | return FAILURE; |
| 1089 | } |
| 1090 | |
| 1091 | /* Write the primary GPT header, which is at an offset of BlkSz */ |
| 1092 | Status = BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, 1, BlkSz, |
| 1093 | (VOID *)PrimaryGptHdr); |
| 1094 | if (EFI_ERROR (Status)) { |
| 1095 | DEBUG ((EFI_D_ERROR, "Error writing primary GPT header: %r\n", Status)); |
| 1096 | return FAILURE; |
| 1097 | } |
| 1098 | |
| 1099 | /* Write the back up GPT header */ |
| 1100 | BackUpGptLba = GET_LLWORD_FROM_BYTE (&PrimaryGptHdr[BACKUP_HEADER_OFFSET]); |
| 1101 | Status = BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, BackUpGptLba, |
| 1102 | BlkSz, (VOID *)SecondaryGptHdr); |
| 1103 | if (EFI_ERROR (Status)) { |
| 1104 | DEBUG ((EFI_D_ERROR, "Error writing secondary GPT header: %x\n", Status)); |
| 1105 | return FAILURE; |
| 1106 | } |
| 1107 | |
| 1108 | /* write Partition Entries for primary partition table*/ |
| 1109 | PartEntryArrSt = PrimaryGptHdr + BlkSz; |
| 1110 | PartitionEntryLba = |
| 1111 | GET_LLWORD_FROM_BYTE (&PrimaryGptHdr[PARTITION_ENTRIES_OFFSET]); |
| 1112 | Status = |
| 1113 | BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, PartitionEntryLba, |
| 1114 | PartEntryArrSz, (VOID *)PartEntryArrSt); |
| 1115 | if (EFI_ERROR (Status)) { |
| 1116 | DEBUG ((EFI_D_ERROR, |
| 1117 | "Error writing partition entries array for Primary Table: %x\n", |
| 1118 | Status)); |
| 1119 | return FAILURE; |
| 1120 | } |
| 1121 | |
| 1122 | /* write Partition Entries for secondary partition table*/ |
| 1123 | PartEntryArrSt = PrimaryGptHdr + BlkSz + PartEntryArrSz; |
| 1124 | PartitionEntryLba = |
| 1125 | GET_LLWORD_FROM_BYTE (&SecondaryGptHdr[PARTITION_ENTRIES_OFFSET]); |
| 1126 | Status = |
| 1127 | BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, PartitionEntryLba, |
| 1128 | PartEntryArrSz, (VOID *)PartEntryArrSt); |
| 1129 | if (EFI_ERROR (Status)) { |
| 1130 | DEBUG ((EFI_D_ERROR, |
| 1131 | "Error writing partition entries array for Secondary Table: %x\n", |
| 1132 | Status)); |
| 1133 | return FAILURE; |
| 1134 | } |
| 1135 | FlashingGpt = 0; |
Lijuan Gao | e53c24c | 2020-09-28 18:43:16 +0800 | [diff] [blame] | 1136 | gBS->SetMem ((VOID *)Gpt, Sz, 0x0); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1137 | |
| 1138 | DEBUG ((EFI_D_ERROR, "Updated Partition Table Successfully\n")); |
| 1139 | return SUCCESS; |
| 1140 | } |
| 1141 | |
| 1142 | EFI_STATUS |
| 1143 | UpdatePartitionTable (UINT8 *GptImage, |
| 1144 | UINT32 Sz, |
| 1145 | INT32 Lun, |
| 1146 | struct StoragePartInfo *Ptable) |
| 1147 | { |
| 1148 | EFI_STATUS Status = EFI_SUCCESS; |
| 1149 | UINT32 Ptype; |
| 1150 | UINT32 Ret; |
| 1151 | |
| 1152 | /* Check if the partition type is GPT */ |
| 1153 | Ret = PartitionGetType (Sz, GptImage, &Ptype); |
| 1154 | if (Ret != 0) { |
| 1155 | DEBUG ( |
| 1156 | (EFI_D_ERROR, "Failed to get partition type from input gpt image\n")); |
| 1157 | return EFI_NOT_FOUND; |
| 1158 | } |
| 1159 | |
| 1160 | switch (Ptype) { |
| 1161 | case PARTITION_TYPE_GPT: |
| 1162 | DEBUG ((EFI_D_INFO, "Updating GPT partition\n")); |
| 1163 | FlashingGpt = TRUE; |
| 1164 | Ret = WriteGpt (Lun, Sz, GptImage); |
| 1165 | if (Ret != 0) { |
| 1166 | DEBUG ((EFI_D_ERROR, "Failed to write Gpt partition: %x\n", Ret)); |
| 1167 | return EFI_VOLUME_CORRUPTED; |
| 1168 | } |
| 1169 | break; |
| 1170 | default: |
| 1171 | DEBUG ((EFI_D_ERROR, "Invalid Partition type: %x\n", Ptype)); |
| 1172 | Status = EFI_UNSUPPORTED; |
| 1173 | break; |
| 1174 | } |
| 1175 | |
| 1176 | return Status; |
| 1177 | } |
| 1178 | |
| 1179 | STATIC CONST struct PartitionEntry * |
| 1180 | GetPartitionEntry (CHAR16 *Partition) |
| 1181 | { |
| 1182 | INT32 Index = GetPartitionIndex (Partition); |
| 1183 | |
| 1184 | if (Index == INVALID_PTN) { |
| 1185 | DEBUG ((EFI_D_ERROR, "GetPartitionEntry: No partition entry for " |
| 1186 | "%s, invalid index\n", |
| 1187 | Partition)); |
| 1188 | return NULL; |
| 1189 | } |
| 1190 | return &PtnEntries[Index]; |
| 1191 | } |
| 1192 | |
| 1193 | STATIC struct PartitionEntry * |
| 1194 | GetBootPartitionEntry (Slot *BootSlot) |
| 1195 | { |
| 1196 | INT32 Index = INVALID_PTN; |
| 1197 | |
| 1198 | if (StrnCmp ((CONST CHAR16 *)L"_a", BootSlot->Suffix, |
| 1199 | StrLen (BootSlot->Suffix)) == 0) { |
| 1200 | Index = GetPartitionIndex ((CHAR16 *)L"boot_a"); |
| 1201 | } else if (StrnCmp ((CONST CHAR16 *)L"_b", BootSlot->Suffix, |
| 1202 | StrLen (BootSlot->Suffix)) == 0) { |
| 1203 | Index = GetPartitionIndex ((CHAR16 *)L"boot_b"); |
| 1204 | } else { |
| 1205 | DEBUG ((EFI_D_ERROR, "GetBootPartitionEntry: No boot partition " |
| 1206 | "entry for slot %s\n", |
| 1207 | BootSlot->Suffix)); |
| 1208 | return NULL; |
| 1209 | } |
| 1210 | |
| 1211 | if (Index == INVALID_PTN) { |
| 1212 | DEBUG ((EFI_D_ERROR, "GetBootPartitionEntry: No boot partition entry " |
| 1213 | "for slot %s, invalid index\n", |
| 1214 | BootSlot->Suffix)); |
| 1215 | return NULL; |
| 1216 | } |
| 1217 | return &PtnEntries[Index]; |
| 1218 | } |
| 1219 | |
| 1220 | BOOLEAN IsCurrentSlotBootable (VOID) |
| 1221 | { |
| 1222 | Slot CurrentSlot = {{0}}; |
| 1223 | struct PartitionEntry *BootPartition = NULL; |
| 1224 | EFI_STATUS Status = GetActiveSlot (&CurrentSlot); |
| 1225 | |
| 1226 | if (Status != EFI_SUCCESS) { |
| 1227 | DEBUG ((EFI_D_ERROR, "IsCurrentSlotBootable: no active slots found!\n")); |
| 1228 | return FALSE; |
| 1229 | } |
| 1230 | |
| 1231 | BootPartition = GetBootPartitionEntry (&CurrentSlot); |
| 1232 | if (BootPartition == NULL) { |
| 1233 | DEBUG ((EFI_D_ERROR, "IsCurrentSlotBootable: No boot partition " |
| 1234 | "entry for slot %s\n", |
| 1235 | CurrentSlot.Suffix)); |
| 1236 | return FALSE; |
| 1237 | } |
| 1238 | DEBUG ((EFI_D_VERBOSE, "Slot suffix %s Part Attr 0x%lx\n", CurrentSlot.Suffix, |
| 1239 | BootPartition->PartEntry.Attributes)); |
| 1240 | |
| 1241 | if (!(BootPartition->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) && |
| 1242 | BootPartition->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) { |
| 1243 | DEBUG ((EFI_D_VERBOSE, "Slot %s is bootable\n", CurrentSlot.Suffix)); |
| 1244 | return TRUE; |
| 1245 | } |
| 1246 | |
| 1247 | DEBUG ((EFI_D_VERBOSE, "Slot %s is unbootable \n", CurrentSlot.Suffix)); |
| 1248 | return FALSE; |
| 1249 | } |
| 1250 | |
| 1251 | BOOLEAN |
| 1252 | IsSuffixEmpty (Slot *CheckSlot) |
| 1253 | { |
| 1254 | if (CheckSlot == NULL) { |
| 1255 | return TRUE; |
| 1256 | } |
| 1257 | |
| 1258 | if (StrLen (CheckSlot->Suffix) == 0) { |
| 1259 | return TRUE; |
| 1260 | } |
| 1261 | return FALSE; |
| 1262 | } |
| 1263 | |
| 1264 | STATIC EFI_STATUS |
| 1265 | GetActiveSlot (Slot *ActiveSlot) |
| 1266 | { |
| 1267 | EFI_STATUS Status = EFI_SUCCESS; |
| 1268 | Slot Slots[] = {{L"_a"}, {L"_b"}}; |
| 1269 | UINT64 Priority = 0; |
| 1270 | |
| 1271 | if (ActiveSlot == NULL) { |
| 1272 | DEBUG ((EFI_D_ERROR, "GetActiveSlot: bad parameter\n")); |
| 1273 | return EFI_INVALID_PARAMETER; |
| 1274 | } |
| 1275 | |
| 1276 | for (UINTN SlotIndex = 0; SlotIndex < ARRAY_SIZE (Slots); SlotIndex++) { |
| 1277 | struct PartitionEntry *BootPartition = |
| 1278 | GetBootPartitionEntry (&Slots[SlotIndex]); |
| 1279 | UINT64 BootPriority = 0; |
| 1280 | if (BootPartition == NULL) { |
| 1281 | DEBUG ((EFI_D_ERROR, "GetActiveSlot: No boot partition " |
| 1282 | "entry for slot %s\n", |
| 1283 | Slots[SlotIndex].Suffix)); |
| 1284 | return EFI_NOT_FOUND; |
| 1285 | } |
| 1286 | |
| 1287 | BootPriority = |
| 1288 | (BootPartition->PartEntry.Attributes & PART_ATT_PRIORITY_VAL) >> |
| 1289 | PART_ATT_PRIORITY_BIT; |
| 1290 | |
| 1291 | if ((BootPartition->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) && |
| 1292 | (BootPriority > Priority)) { |
| 1293 | GUARD (StrnCpyS (ActiveSlot->Suffix, ARRAY_SIZE (ActiveSlot->Suffix), |
| 1294 | Slots[SlotIndex].Suffix, |
| 1295 | StrLen (Slots[SlotIndex].Suffix))); |
| 1296 | Priority = BootPriority; |
| 1297 | } |
| 1298 | } |
| 1299 | |
| 1300 | DEBUG ((EFI_D_VERBOSE, "GetActiveSlot: found active slot %s, priority %d\n", |
| 1301 | ActiveSlot->Suffix, Priority)); |
| 1302 | |
| 1303 | if (IsSuffixEmpty (ActiveSlot) == TRUE) { |
| 1304 | /* Check for first boot and set default slot */ |
| 1305 | /* For First boot all A/B attributes for the slot would be 0 */ |
| 1306 | UINT64 BootPriority = 0; |
| 1307 | UINT64 RetryCount = 0; |
| 1308 | struct PartitionEntry *SlotA = GetBootPartitionEntry (&Slots[0]); |
| 1309 | if (SlotA == NULL) { |
| 1310 | DEBUG ((EFI_D_ERROR, "GetActiveSlot: First Boot: No boot partition " |
| 1311 | "entry for slot %s\n", |
| 1312 | Slots[0].Suffix)); |
| 1313 | return EFI_NOT_FOUND; |
| 1314 | } |
| 1315 | |
| 1316 | BootPriority = (SlotA->PartEntry.Attributes & PART_ATT_PRIORITY_VAL) >> |
| 1317 | PART_ATT_PRIORITY_BIT; |
| 1318 | RetryCount = (SlotA->PartEntry.Attributes & PART_ATT_MAX_RETRY_COUNT_VAL) >> |
| 1319 | PART_ATT_MAX_RETRY_CNT_BIT; |
| 1320 | |
| 1321 | if ((SlotA->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) == 0 && |
| 1322 | (SlotA->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) == 0 && |
| 1323 | (SlotA->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) == 0 && |
| 1324 | BootPriority == 0) { |
| 1325 | |
| 1326 | DEBUG ((EFI_D_INFO, "GetActiveSlot: First boot: set " |
| 1327 | "default slot _a\n")); |
| 1328 | SlotA->PartEntry.Attributes &= |
| 1329 | (~PART_ATT_SUCCESSFUL_VAL & ~PART_ATT_UNBOOTABLE_VAL); |
| 1330 | SlotA->PartEntry.Attributes |= |
| 1331 | (PART_ATT_PRIORITY_VAL | PART_ATT_ACTIVE_VAL | |
| 1332 | PART_ATT_MAX_RETRY_COUNT_VAL); |
| 1333 | |
| 1334 | GUARD (StrnCpyS (ActiveSlot->Suffix, ARRAY_SIZE (ActiveSlot->Suffix), |
| 1335 | Slots[0].Suffix, StrLen (Slots[0].Suffix))); |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 1336 | UpdatePartitionAttributes (PARTITION_ATTRIBUTES); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1337 | FirstBoot = TRUE; |
| 1338 | return EFI_SUCCESS; |
| 1339 | } |
| 1340 | |
| 1341 | DEBUG ((EFI_D_ERROR, "GetActiveSlot: No active slot found\n")); |
| 1342 | DEBUG ((EFI_D_ERROR, "GetActiveSlot: Slot attr: Priority %ld, Retry " |
| 1343 | "%ld, Active %ld, Success %ld, unboot %ld\n", |
| 1344 | BootPriority, RetryCount, |
| 1345 | (SlotA->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) >> |
| 1346 | PART_ATT_ACTIVE_BIT, |
| 1347 | (SlotA->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL), |
| 1348 | (SlotA->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL))); |
| 1349 | |
| 1350 | return EFI_NOT_FOUND; |
| 1351 | } |
| 1352 | |
| 1353 | return EFI_SUCCESS; |
| 1354 | } |
| 1355 | |
| 1356 | EFI_STATUS |
Jeevan Shriram | 39c9b7e | 2018-09-21 12:21:22 -0700 | [diff] [blame] | 1357 | SetActiveSlot (Slot *NewSlot, BOOLEAN ResetSuccessBit) |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1358 | { |
| 1359 | EFI_STATUS Status = EFI_SUCCESS; |
| 1360 | Slot CurrentSlot = {{0}}; |
| 1361 | Slot *AlternateSlot = NULL; |
| 1362 | Slot Slots[] = {{L"_a"}, {L"_b"}}; |
Jeevan Shriram | b1cbe92 | 2017-12-11 19:14:18 -0800 | [diff] [blame] | 1363 | BOOLEAN UfsGet = TRUE; |
| 1364 | BOOLEAN UfsSet = FALSE; |
| 1365 | UINT32 UfsBootLun = 0; |
| 1366 | CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX]; |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1367 | struct PartitionEntry *BootEntry = NULL; |
| 1368 | |
| 1369 | if (NewSlot == NULL) { |
| 1370 | DEBUG ((EFI_D_ERROR, "SetActiveSlot: input parameter invalid\n")); |
| 1371 | return EFI_INVALID_PARAMETER; |
| 1372 | } |
| 1373 | |
| 1374 | GUARD (GetActiveSlot (&CurrentSlot)); |
| 1375 | |
| 1376 | if (StrnCmp (NewSlot->Suffix, Slots[0].Suffix, StrLen (Slots[0].Suffix)) == |
| 1377 | 0) { |
| 1378 | AlternateSlot = &Slots[1]; |
| 1379 | } else { |
| 1380 | AlternateSlot = &Slots[0]; |
| 1381 | } |
| 1382 | |
| 1383 | BootEntry = GetBootPartitionEntry (NewSlot); |
| 1384 | if (BootEntry == NULL) { |
| 1385 | DEBUG ((EFI_D_ERROR, "SetActiveSlot: No boot partition entry for slot %s\n", |
| 1386 | NewSlot->Suffix)); |
| 1387 | return EFI_NOT_FOUND; |
| 1388 | } |
| 1389 | |
| 1390 | BootEntry->PartEntry.Attributes |= |
| 1391 | (PART_ATT_PRIORITY_VAL | PART_ATT_ACTIVE_VAL | |
| 1392 | PART_ATT_MAX_RETRY_COUNT_VAL); |
Jeevan Shriram | 39c9b7e | 2018-09-21 12:21:22 -0700 | [diff] [blame] | 1393 | |
| 1394 | BootEntry->PartEntry.Attributes &= (~PART_ATT_UNBOOTABLE_VAL); |
| 1395 | |
| 1396 | if (ResetSuccessBit && |
| 1397 | (BootEntry->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL)) { |
| 1398 | BootEntry->PartEntry.Attributes &= (~PART_ATT_SUCCESSFUL_VAL); |
| 1399 | } |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1400 | |
| 1401 | /* Reduce the priority and clear the active flag for alternate slot*/ |
| 1402 | BootEntry = GetBootPartitionEntry (AlternateSlot); |
| 1403 | if (BootEntry == NULL) { |
| 1404 | DEBUG ((EFI_D_ERROR, "SetActiveSlot: No boot partition entry for slot %s\n", |
| 1405 | AlternateSlot->Suffix)); |
| 1406 | return EFI_NOT_FOUND; |
| 1407 | } |
| 1408 | |
| 1409 | BootEntry->PartEntry.Attributes &= |
| 1410 | (~PART_ATT_PRIORITY_VAL & ~PART_ATT_ACTIVE_VAL); |
| 1411 | BootEntry->PartEntry.Attributes |= |
| 1412 | (((UINT64)MAX_PRIORITY - 1) << PART_ATT_PRIORITY_BIT); |
| 1413 | |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 1414 | UpdatePartitionAttributes (PARTITION_ATTRIBUTES); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1415 | if (StrnCmp (CurrentSlot.Suffix, NewSlot->Suffix, |
| 1416 | StrLen (CurrentSlot.Suffix)) == 0) { |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1417 | DEBUG ((EFI_D_INFO, "SetActiveSlot: %s already active slot\n", |
| 1418 | NewSlot->Suffix)); |
Jeevan Shriram | b1cbe92 | 2017-12-11 19:14:18 -0800 | [diff] [blame] | 1419 | |
| 1420 | /* Check if BootLun is matching with Slot */ |
| 1421 | GetRootDeviceType (BootDeviceType, BOOT_DEV_NAME_SIZE_MAX); |
| 1422 | if (!AsciiStrnCmp (BootDeviceType, "UFS", AsciiStrLen ("UFS"))) { |
| 1423 | UfsGetSetBootLun (&UfsBootLun, UfsGet); |
| 1424 | if (UfsBootLun == 0x1 && |
| 1425 | !StrnCmp (CurrentSlot.Suffix, (CONST CHAR16 *)L"_b", |
| 1426 | StrLen ((CONST CHAR16 *)L"_b"))) { |
| 1427 | DEBUG ((EFI_D_INFO, "Boot lun mismatch switch from 1 to 2\n")); |
| 1428 | DEBUG ((EFI_D_INFO, "Reboot Required\n")); |
| 1429 | UfsBootLun = 0x2; |
| 1430 | UfsGetSetBootLun (&UfsBootLun, UfsSet); |
| 1431 | } else if (UfsBootLun == 0x2 && |
| 1432 | !StrnCmp (CurrentSlot.Suffix, (CONST CHAR16 *)L"_a", |
| 1433 | StrLen ((CONST CHAR16 *)L"_a"))) { |
| 1434 | DEBUG ((EFI_D_INFO, "Boot lun mismatch switch from 2 to 1\n")); |
| 1435 | DEBUG ((EFI_D_INFO, "Reboot Required\n")); |
| 1436 | UfsBootLun = 0x1; |
| 1437 | UfsGetSetBootLun (&UfsBootLun, UfsSet); |
| 1438 | } |
| 1439 | } |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1440 | } else { |
| 1441 | DEBUG ((EFI_D_INFO, "Alternate slot %s, New slot %s\n", |
| 1442 | AlternateSlot->Suffix, NewSlot->Suffix)); |
| 1443 | SwitchPtnSlots (NewSlot->Suffix); |
| 1444 | MarkPtnActive (NewSlot->Suffix); |
| 1445 | } |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1446 | return EFI_SUCCESS; |
| 1447 | } |
| 1448 | |
| 1449 | EFI_STATUS HandleActiveSlotUnbootable (VOID) |
| 1450 | { |
| 1451 | EFI_STATUS Status = EFI_SUCCESS; |
| 1452 | struct PartitionEntry *BootEntry = NULL; |
| 1453 | Slot ActiveSlot = {{0}}; |
| 1454 | Slot *AlternateSlot = NULL; |
| 1455 | Slot Slots[] = {{L"_a"}, {L"_b"}}; |
| 1456 | UINT64 Unbootable = 0; |
| 1457 | UINT64 BootSuccess = 0; |
| 1458 | |
| 1459 | /* Mark current Slot as unbootable */ |
| 1460 | GUARD (GetActiveSlot (&ActiveSlot)); |
| 1461 | BootEntry = GetBootPartitionEntry (&ActiveSlot); |
| 1462 | if (BootEntry == NULL) { |
| 1463 | DEBUG ((EFI_D_ERROR, "HandleActiveSlotUnbootable: No boot " |
| 1464 | "partition entry for slot %s\n", |
| 1465 | ActiveSlot.Suffix)); |
| 1466 | return EFI_NOT_FOUND; |
| 1467 | } |
| 1468 | |
| 1469 | if (FirstBoot && !TargetBuildVariantUser ()) { |
| 1470 | DEBUG ((EFI_D_VERBOSE, "FirstBoot, skipping slot Unbootable\n")); |
| 1471 | FirstBoot = FALSE; |
| 1472 | } else { |
| 1473 | BootEntry->PartEntry.Attributes |= |
| 1474 | (PART_ATT_UNBOOTABLE_VAL) & (~PART_ATT_SUCCESSFUL_VAL); |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 1475 | UpdatePartitionAttributes (PARTITION_ATTRIBUTES); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1476 | } |
| 1477 | |
| 1478 | if (StrnCmp (ActiveSlot.Suffix, Slots[0].Suffix, StrLen (Slots[0].Suffix)) == |
| 1479 | 0) { |
| 1480 | AlternateSlot = &Slots[1]; |
| 1481 | } else { |
| 1482 | AlternateSlot = &Slots[0]; |
| 1483 | } |
| 1484 | |
| 1485 | /* Validate Aternate Slot is bootable */ |
| 1486 | BootEntry = GetBootPartitionEntry (AlternateSlot); |
| 1487 | if (BootEntry == NULL) { |
| 1488 | DEBUG ((EFI_D_ERROR, "HandleActiveSlotUnbootable: No boot " |
| 1489 | "partition entry for slot %s\n", |
| 1490 | AlternateSlot->Suffix)); |
| 1491 | return EFI_NOT_FOUND; |
| 1492 | } |
| 1493 | |
| 1494 | Unbootable = (BootEntry->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) >> |
| 1495 | PART_ATT_UNBOOTABLE_BIT; |
| 1496 | BootSuccess = (BootEntry->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) >> |
| 1497 | PART_ATT_SUCCESS_BIT; |
| 1498 | |
| 1499 | if (Unbootable == 0 && BootSuccess == 1) { |
| 1500 | DEBUG ( |
| 1501 | (EFI_D_INFO, "Alternate Slot %s is bootable\n", AlternateSlot->Suffix)); |
Jeevan Shriram | 39c9b7e | 2018-09-21 12:21:22 -0700 | [diff] [blame] | 1502 | GUARD (SetActiveSlot (AlternateSlot, FALSE)); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1503 | |
| 1504 | DEBUG ((EFI_D_INFO, "HandleActiveSlotUnbootable: Rebooting\n")); |
| 1505 | gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); |
| 1506 | |
| 1507 | // Shouldn't get here |
| 1508 | DEBUG ((EFI_D_ERROR, "HandleActiveSlotUnbootable: " |
| 1509 | "gRT->Resetystem didn't work\n")); |
| 1510 | return EFI_LOAD_ERROR; |
| 1511 | } |
| 1512 | |
| 1513 | return EFI_LOAD_ERROR; |
| 1514 | } |
| 1515 | |
| 1516 | EFI_STATUS ClearUnbootable (VOID) |
| 1517 | { |
| 1518 | EFI_STATUS Status = EFI_SUCCESS; |
| 1519 | Slot ActiveSlot = {{0}}; |
| 1520 | struct PartitionEntry *BootEntry = NULL; |
| 1521 | |
| 1522 | Status = GetActiveSlot (&ActiveSlot); |
| 1523 | if (Status != EFI_SUCCESS) { |
| 1524 | DEBUG ((EFI_D_ERROR, "ClearUnbootable: GetActiveSlot failed.\n")); |
| 1525 | return Status; |
| 1526 | } |
| 1527 | BootEntry = GetBootPartitionEntry (&ActiveSlot); |
| 1528 | if (BootEntry == NULL) { |
| 1529 | DEBUG ((EFI_D_ERROR, |
| 1530 | "ClearUnbootable: No boot partition entry for slot %s\n", |
| 1531 | ActiveSlot.Suffix)); |
| 1532 | return EFI_NOT_FOUND; |
| 1533 | } |
| 1534 | BootEntry->PartEntry.Attributes &= ~PART_ATT_UNBOOTABLE_VAL; |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 1535 | UpdatePartitionAttributes (PARTITION_ATTRIBUTES); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1536 | return EFI_SUCCESS; |
| 1537 | } |
| 1538 | |
| 1539 | STATIC EFI_STATUS |
| 1540 | ValidateSlotGuids (Slot *BootableSlot) |
| 1541 | { |
| 1542 | EFI_STATUS Status = EFI_SUCCESS; |
| 1543 | struct PartitionEntry *BootEntry = NULL; |
Mayank Grover | f70d1a8 | 2019-02-26 17:52:19 +0530 | [diff] [blame] | 1544 | CHAR16 PartitionName[] = L"abl_x"; |
| 1545 | CONST struct PartitionEntry *PartEntry = NULL; |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1546 | CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX]; |
| 1547 | UINT32 UfsBootLun = 0; |
| 1548 | |
| 1549 | BootEntry = GetBootPartitionEntry (BootableSlot); |
| 1550 | if (BootEntry == NULL) { |
| 1551 | DEBUG ((EFI_D_ERROR, "ValidateSlotGuids: No boot partition " |
| 1552 | "entry for slot %s\n", |
| 1553 | BootableSlot->Suffix)); |
| 1554 | return EFI_NOT_FOUND; |
| 1555 | } |
| 1556 | |
Mayank Grover | f70d1a8 | 2019-02-26 17:52:19 +0530 | [diff] [blame] | 1557 | PartitionName[StrLen (PartitionName) - 1] = |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1558 | BootableSlot->Suffix[StrLen (BootableSlot->Suffix) - 1]; |
Mayank Grover | f70d1a8 | 2019-02-26 17:52:19 +0530 | [diff] [blame] | 1559 | PartEntry = GetPartitionEntry (PartitionName); |
| 1560 | if (PartEntry == NULL) { |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1561 | DEBUG ((EFI_D_ERROR, "ValidateSlotGuids: No partition entry for %s\n", |
Mayank Grover | f70d1a8 | 2019-02-26 17:52:19 +0530 | [diff] [blame] | 1562 | PartitionName)); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1563 | return EFI_NOT_FOUND; |
| 1564 | } |
| 1565 | |
| 1566 | if (CompareMem (&BootEntry->PartEntry.PartitionTypeGUID, |
Mayank Grover | f70d1a8 | 2019-02-26 17:52:19 +0530 | [diff] [blame] | 1567 | &PartEntry->PartEntry.PartitionTypeGUID, |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1568 | sizeof (EFI_GUID)) == 0) { |
| 1569 | DEBUG ((EFI_D_ERROR, "ValidateSlotGuids: BootableSlot %s does " |
| 1570 | "not have valid guids\n", |
| 1571 | BootableSlot->Suffix)); |
| 1572 | DEBUG ((EFI_D_INFO, "Boot GUID %g\n", |
| 1573 | &BootEntry->PartEntry.PartitionTypeGUID)); |
Mayank Grover | f70d1a8 | 2019-02-26 17:52:19 +0530 | [diff] [blame] | 1574 | DEBUG ((EFI_D_INFO, "%s GUID %g\n", |
| 1575 | PartitionName, &PartEntry->PartEntry.PartitionTypeGUID)); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1576 | return EFI_DEVICE_ERROR; |
| 1577 | } |
| 1578 | |
| 1579 | GetRootDeviceType (BootDeviceType, BOOT_DEV_NAME_SIZE_MAX); |
| 1580 | if (!AsciiStrnCmp (BootDeviceType, "UFS", AsciiStrLen ("UFS"))) { |
| 1581 | GUARD (UfsGetSetBootLun (&UfsBootLun, TRUE)); |
| 1582 | if (UfsBootLun == 0x1 && |
| 1583 | !StrCmp (BootableSlot->Suffix, (CONST CHAR16 *)L"_a")) { |
| 1584 | } else if (UfsBootLun == 0x2 && |
| 1585 | !StrCmp (BootableSlot->Suffix, (CONST CHAR16 *)L"_b")) { |
| 1586 | } else { |
| 1587 | DEBUG ((EFI_D_ERROR, "Boot lun: %x and BootableSlot: %s " |
| 1588 | "do not match\n", |
| 1589 | UfsBootLun, BootableSlot->Suffix)); |
| 1590 | return EFI_DEVICE_ERROR; |
| 1591 | } |
| 1592 | } else if (!AsciiStrnCmp (BootDeviceType, "EMMC", AsciiStrLen ("EMMC"))) { |
| 1593 | } else { |
| 1594 | DEBUG ((EFI_D_ERROR, "Unsupported Device Type\n")); |
| 1595 | return EFI_DEVICE_ERROR; |
| 1596 | } |
| 1597 | |
| 1598 | DEBUG ((EFI_D_INFO, "Booting from slot (%s)\n", BootableSlot->Suffix)); |
| 1599 | return EFI_SUCCESS; |
| 1600 | } |
| 1601 | |
| 1602 | EFI_STATUS |
| 1603 | FindBootableSlot (Slot *BootableSlot) |
| 1604 | { |
| 1605 | EFI_STATUS Status = EFI_SUCCESS; |
| 1606 | struct PartitionEntry *BootEntry = NULL; |
| 1607 | UINT64 Unbootable = 0; |
| 1608 | UINT64 BootSuccess = 0; |
| 1609 | UINT64 RetryCount = 0; |
| 1610 | |
| 1611 | if (BootableSlot == NULL) { |
| 1612 | DEBUG ((EFI_D_ERROR, "FindBootableSlot: input parameter invalid\n")); |
| 1613 | return EFI_INVALID_PARAMETER; |
| 1614 | } |
| 1615 | |
jianzhou | 71e1ea6 | 2017-12-01 16:27:17 +0800 | [diff] [blame] | 1616 | GUARD (GetActiveSlot (BootableSlot)); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1617 | |
| 1618 | /* Validate Active Slot is bootable */ |
| 1619 | BootEntry = GetBootPartitionEntry (BootableSlot); |
| 1620 | if (BootEntry == NULL) { |
| 1621 | DEBUG ((EFI_D_ERROR, "FindBootableSlot: No boot partition entry " |
| 1622 | "for slot %s\n", |
| 1623 | BootableSlot->Suffix)); |
| 1624 | return EFI_NOT_FOUND; |
| 1625 | } |
| 1626 | |
| 1627 | Unbootable = (BootEntry->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) >> |
| 1628 | PART_ATT_UNBOOTABLE_BIT; |
| 1629 | BootSuccess = (BootEntry->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) >> |
| 1630 | PART_ATT_SUCCESS_BIT; |
| 1631 | RetryCount = |
| 1632 | (BootEntry->PartEntry.Attributes & PART_ATT_MAX_RETRY_COUNT_VAL) >> |
| 1633 | PART_ATT_MAX_RETRY_CNT_BIT; |
| 1634 | |
| 1635 | if (Unbootable == 0 && BootSuccess == 1) { |
| 1636 | DEBUG ( |
| 1637 | (EFI_D_VERBOSE, "Active Slot %s is bootable\n", BootableSlot->Suffix)); |
| 1638 | } else if (Unbootable == 0 && BootSuccess == 0 && RetryCount > 0) { |
lijuang | b53e91c | 2019-08-14 18:22:20 +0800 | [diff] [blame] | 1639 | if ((!IsABRetryCountDisabled () && |
| 1640 | !IsBootDevImage ()) && |
| 1641 | IsABRetryCountUpdateRequired ()) { |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1642 | RetryCount--; |
| 1643 | BootEntry->PartEntry.Attributes &= ~PART_ATT_MAX_RETRY_COUNT_VAL; |
| 1644 | BootEntry->PartEntry.Attributes |= RetryCount |
| 1645 | << PART_ATT_MAX_RETRY_CNT_BIT; |
lijuang | 5b76296 | 2019-03-15 20:40:45 +0800 | [diff] [blame] | 1646 | UpdatePartitionAttributes (PARTITION_ATTRIBUTES); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1647 | DEBUG ((EFI_D_INFO, "Active Slot %s is bootable, retry count %ld\n", |
| 1648 | BootableSlot->Suffix, RetryCount)); |
Jeevan Shriram | 0a3ba0b | 2019-01-02 23:21:12 -0800 | [diff] [blame] | 1649 | } else { |
| 1650 | DEBUG ((EFI_D_INFO, "A/B retry count NOT decremented\n")); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1651 | } |
| 1652 | } else { |
| 1653 | DEBUG ((EFI_D_INFO, "Slot %s is unbootable, trying alternate slot\n", |
| 1654 | BootableSlot->Suffix)); |
| 1655 | GUARD_OUT (HandleActiveSlotUnbootable ()); |
| 1656 | } |
| 1657 | |
| 1658 | /* Validate slot suffix and partition guids */ |
Nagireddy Annem | 672b53f | 2019-11-11 13:55:48 +0530 | [diff] [blame] | 1659 | if (Status == EFI_SUCCESS && |
| 1660 | NAND != CheckRootDeviceType ()) { |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1661 | GUARD_OUT (ValidateSlotGuids (BootableSlot)); |
| 1662 | } |
| 1663 | MarkPtnActive (BootableSlot->Suffix); |
Shivaprasad Hongal | c017e81 | 2017-04-26 16:15:27 -0700 | [diff] [blame] | 1664 | out: |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1665 | if (Status != EFI_SUCCESS) { |
| 1666 | /* clear bootable slot */ |
| 1667 | BootableSlot->Suffix[0] = '\0'; |
| 1668 | } |
| 1669 | return Status; |
Vijay Kumar Pendoti | 644a20b | 2017-03-15 18:22:17 +0530 | [diff] [blame] | 1670 | } |
| 1671 | |
lijuang | 3df1faf | 2018-04-10 21:59:25 +0800 | [diff] [blame] | 1672 | /* This functions should be called only if header revision > 0 */ |
| 1673 | STATIC EFI_STATUS GetRecoveryDtboInfo (BootInfo *Info, |
| 1674 | BootParamlist *BootParamlistPtr, |
| 1675 | UINT64 *DtboImageSize) |
| 1676 | { |
| 1677 | UINT32 HeaderVersion = 0; |
| 1678 | UINT64 RecoveryDtboOffset = 0; |
| 1679 | UINT32 RecoveryDtboSize = 0; |
| 1680 | UINT32 ImageHeaderSize = 0; |
| 1681 | struct boot_img_hdr_v1 *BootImgHdrV1Addr; |
| 1682 | |
| 1683 | if (Info == NULL || |
| 1684 | BootParamlistPtr == NULL || |
| 1685 | DtboImageSize == NULL) { |
| 1686 | DEBUG ((EFI_D_ERROR, "Invalid input parameters\n")); |
| 1687 | return EFI_INVALID_PARAMETER; |
| 1688 | } |
| 1689 | |
| 1690 | HeaderVersion = Info->HeaderVersion; |
| 1691 | |
| 1692 | /* Finds out the location of recovery dtbo size and offset */ |
| 1693 | BootImgHdrV1Addr = (struct boot_img_hdr_v1 *) |
| 1694 | ((UINT64) BootParamlistPtr->ImageBuffer + |
| 1695 | BOOT_IMAGE_HEADER_V1_RECOVERY_DTBO_SIZE_OFFSET); |
| 1696 | |
| 1697 | if (HeaderVersion == BOOT_HEADER_VERSION_ONE) { |
| 1698 | ImageHeaderSize = BootImgHdrV1Addr->header_size; |
| 1699 | |
| 1700 | if ((ImageHeaderSize != (sizeof (struct boot_img_hdr_v1) + |
| 1701 | BOOT_IMAGE_HEADER_V1_RECOVERY_DTBO_SIZE_OFFSET)) || |
| 1702 | ImageHeaderSize > BootParamlistPtr->PageSize) { |
| 1703 | DEBUG ((EFI_D_ERROR, |
| 1704 | "Invalid boot image header: %d\n", ImageHeaderSize)); |
| 1705 | return EFI_BAD_BUFFER_SIZE; |
| 1706 | } |
| 1707 | } |
| 1708 | |
| 1709 | RecoveryDtboOffset = BootImgHdrV1Addr->recovery_dtbo_offset; |
| 1710 | RecoveryDtboSize = ROUND_TO_PAGE (BootImgHdrV1Addr->recovery_dtbo_size, |
| 1711 | BootParamlistPtr->PageSize - 1); |
| 1712 | |
| 1713 | if (CHECK_ADD64 (RecoveryDtboOffset, RecoveryDtboSize)) { |
Mukesh Ojha | 82911f8 | 2018-04-30 16:45:07 +0530 | [diff] [blame] | 1714 | DEBUG ((EFI_D_ERROR, "Integer Overflow: RecoveryDtboOffset=%u " |
lijuang | 3df1faf | 2018-04-10 21:59:25 +0800 | [diff] [blame] | 1715 | "RecoveryDtboSize=%u\n", RecoveryDtboOffset, RecoveryDtboSize)); |
| 1716 | return EFI_BAD_BUFFER_SIZE; |
| 1717 | } |
| 1718 | |
| 1719 | if (RecoveryDtboOffset + RecoveryDtboSize > |
| 1720 | BootParamlistPtr->ImageSize) { |
| 1721 | DEBUG ((EFI_D_ERROR, "Invalid recovery dtbo: RecoveryDtboOffset=%u," |
| 1722 | " RecoveryDtboSize=%u, ImageSize=%u\n", |
| 1723 | RecoveryDtboOffset, RecoveryDtboSize, |
| 1724 | BootParamlistPtr->ImageSize)); |
| 1725 | return EFI_BAD_BUFFER_SIZE; |
| 1726 | } |
| 1727 | |
| 1728 | BootParamlistPtr->DtboImgBuffer = (VOID *) |
| 1729 | ((UINT64) BootParamlistPtr->ImageBuffer + |
| 1730 | RecoveryDtboOffset); |
| 1731 | |
| 1732 | *DtboImageSize = RecoveryDtboSize; |
| 1733 | |
| 1734 | DEBUG ((EFI_D_VERBOSE, "Image Header Version: 0x%x\n", HeaderVersion)); |
| 1735 | DEBUG ((EFI_D_VERBOSE, "Recovery Dtbo Offset: 0x%x\n", |
| 1736 | RecoveryDtboOffset)); |
| 1737 | DEBUG ((EFI_D_VERBOSE, "Recovery Dtbo Size: 0x%x\n", *DtboImageSize)); |
| 1738 | |
| 1739 | return EFI_SUCCESS; |
| 1740 | } |
| 1741 | |
Vijay Kumar Pendoti | 644a20b | 2017-03-15 18:22:17 +0530 | [diff] [blame] | 1742 | /*Function to provide Dtbo Present info |
| 1743 | *return: TRUE or FALSE. |
| 1744 | */ |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1745 | BOOLEAN |
lijuang | 3df1faf | 2018-04-10 21:59:25 +0800 | [diff] [blame] | 1746 | LoadAndValidateDtboImg (BootInfo *Info, |
| 1747 | BootParamlist *BootParamlistPtr) |
Vijay Kumar Pendoti | 644a20b | 2017-03-15 18:22:17 +0530 | [diff] [blame] | 1748 | { |
lijuang | 3df1faf | 2018-04-10 21:59:25 +0800 | [diff] [blame] | 1749 | UINT64 DtboImgSize = 0; |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1750 | EFI_STATUS Status = EFI_SUCCESS; |
| 1751 | struct DtboTableHdr *DtboTableHdr = NULL; |
Vijay Kumar Pendoti | 644a20b | 2017-03-15 18:22:17 +0530 | [diff] [blame] | 1752 | |
Mayank Grover | f70d1a8 | 2019-02-26 17:52:19 +0530 | [diff] [blame] | 1753 | if ((!Info->MultiSlotBoot || |
| 1754 | IsDynamicPartitionSupport ()) && |
lijuang | 3df1faf | 2018-04-10 21:59:25 +0800 | [diff] [blame] | 1755 | Info->BootIntoRecovery && |
Raghavendra Rao Ananta | 0746956 | 2019-10-11 08:53:20 -0700 | [diff] [blame] | 1756 | Info->HeaderVersion > BOOT_HEADER_VERSION_ZERO && |
| 1757 | Info->HeaderVersion < BOOT_HEADER_VERSION_THREE) { |
lijuang | 3df1faf | 2018-04-10 21:59:25 +0800 | [diff] [blame] | 1758 | Status = GetRecoveryDtboInfo (Info, BootParamlistPtr, &DtboImgSize); |
| 1759 | } else { |
| 1760 | Status = GetImage (Info, &BootParamlistPtr->DtboImgBuffer, |
| 1761 | (UINTN *)&DtboImgSize, "dtbo"); |
| 1762 | } |
| 1763 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1764 | if (Status != EFI_SUCCESS) { |
lijuang | 3df1faf | 2018-04-10 21:59:25 +0800 | [diff] [blame] | 1765 | DEBUG ((EFI_D_ERROR, "BootLinux: failed to get dtbo image\n")); |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1766 | return FALSE; |
| 1767 | } |
lijuang | 3df1faf | 2018-04-10 21:59:25 +0800 | [diff] [blame] | 1768 | |
| 1769 | if (!BootParamlistPtr->DtboImgBuffer) { |
lijuang | c336a29 | 2017-08-22 19:48:49 +0800 | [diff] [blame] | 1770 | DEBUG ((EFI_D_ERROR, "DtboImgBuffer is NULL")); |
| 1771 | return FALSE; |
| 1772 | } |
Vijay Kumar Pendoti | 6fc41c4 | 2017-05-09 19:41:26 +0530 | [diff] [blame] | 1773 | |
lijuang | 3df1faf | 2018-04-10 21:59:25 +0800 | [diff] [blame] | 1774 | DtboTableHdr = BootParamlistPtr->DtboImgBuffer; |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1775 | if (fdt32_to_cpu (DtboTableHdr->Magic) != DTBO_TABLE_MAGIC) { |
| 1776 | DEBUG ((EFI_D_ERROR, "Dtbo hdr magic mismatch %x, with %x\n", |
| 1777 | DtboTableHdr->Magic, DTBO_TABLE_MAGIC)); |
| 1778 | return FALSE; |
| 1779 | } |
Vijay Kumar Pendoti | 6fc41c4 | 2017-05-09 19:41:26 +0530 | [diff] [blame] | 1780 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1781 | if (DtboImgSize > DTBO_MAX_SIZE_ALLOWED) { |
| 1782 | DEBUG ((EFI_D_ERROR, "Dtbo Size too big %x, Allowed size %x\n", DtboImgSize, |
| 1783 | DTBO_MAX_SIZE_ALLOWED)); |
| 1784 | return FALSE; |
| 1785 | } |
Vijay Kumar Pendoti | 6fc41c4 | 2017-05-09 19:41:26 +0530 | [diff] [blame] | 1786 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1787 | /*Check for TotalSize of Dtbo image*/ |
| 1788 | if ((fdt32_to_cpu (DtboTableHdr->TotalSize) > DTBO_MAX_SIZE_ALLOWED) || |
| 1789 | (fdt32_to_cpu (DtboTableHdr->TotalSize) == 0)) { |
| 1790 | DEBUG ((EFI_D_ERROR, "Dtbo Table TotalSize got corrupted\n")); |
| 1791 | return FALSE; |
| 1792 | } |
Vijay Kumar Pendoti | 6fc41c4 | 2017-05-09 19:41:26 +0530 | [diff] [blame] | 1793 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1794 | /*Check for HeaderSize of Dtbo image*/ |
| 1795 | if (fdt32_to_cpu (DtboTableHdr->HeaderSize) != sizeof (struct DtboTableHdr)) { |
| 1796 | DEBUG ((EFI_D_ERROR, "Dtbo Table HeaderSize got corrupted\n")); |
| 1797 | return FALSE; |
| 1798 | } |
Vijay Kumar Pendoti | 6fc41c4 | 2017-05-09 19:41:26 +0530 | [diff] [blame] | 1799 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1800 | /*Check for DtEntrySize of Dtbo image*/ |
| 1801 | if (fdt32_to_cpu (DtboTableHdr->DtEntrySize) != |
| 1802 | sizeof (struct DtboTableEntry)) { |
| 1803 | DEBUG ((EFI_D_ERROR, "Dtbo Table DtEntrySize got corrupted\n")); |
| 1804 | return FALSE; |
| 1805 | } |
Vijay Kumar Pendoti | 6fc41c4 | 2017-05-09 19:41:26 +0530 | [diff] [blame] | 1806 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1807 | /*Check for DtEntryOffset of Dtbo image*/ |
| 1808 | if (fdt32_to_cpu (DtboTableHdr->DtEntryOffset) > DTBO_MAX_SIZE_ALLOWED) { |
| 1809 | DEBUG ((EFI_D_ERROR, "Dtbo Table DtEntryOffset got corrupted\n")); |
| 1810 | return FALSE; |
| 1811 | } |
Vijay Kumar Pendoti | 6fc41c4 | 2017-05-09 19:41:26 +0530 | [diff] [blame] | 1812 | |
jianzhou | 3241219 | 2017-11-10 14:22:47 +0800 | [diff] [blame] | 1813 | if ((UINT64)fdt32_to_cpu (DtboTableHdr->DtEntryCount) * |
| 1814 | fdt32_to_cpu (DtboTableHdr->DtEntrySize) > DtboImgSize) { |
| 1815 | DEBUG ((EFI_D_ERROR, |
| 1816 | "DTB header is corrupted, DtEntryCount %x, DtEntrySize %x," |
| 1817 | " DtboImgSize %x\n", fdt32_to_cpu (DtboTableHdr->DtEntryCount), |
| 1818 | fdt32_to_cpu (DtboTableHdr->DtEntrySize), DtboImgSize)); |
| 1819 | return FALSE; |
| 1820 | } |
| 1821 | |
| 1822 | if (fdt32_to_cpu (DtboTableHdr->DtEntryOffset) + |
| 1823 | (UINT64)fdt32_to_cpu (DtboTableHdr->DtEntryCount) * |
| 1824 | fdt32_to_cpu (DtboTableHdr->DtEntrySize) > DtboImgSize) { |
| 1825 | DEBUG ((EFI_D_ERROR, |
| 1826 | "DTB header is corrupted, DtEntryOffset %x, DtEntryCount %x," |
| 1827 | "DtEntrySize %x, DtboImgSize %x\n", |
| 1828 | fdt32_to_cpu (DtboTableHdr->DtEntryOffset), |
| 1829 | fdt32_to_cpu (DtboTableHdr->DtEntryCount), |
| 1830 | fdt32_to_cpu (DtboTableHdr->DtEntrySize), DtboImgSize)); |
| 1831 | return FALSE; |
| 1832 | } |
| 1833 | |
Jeevan Shriram | 17f173d | 2017-10-24 22:11:07 -0700 | [diff] [blame] | 1834 | return TRUE; |
Vijay Kumar Pendoti | 644a20b | 2017-03-15 18:22:17 +0530 | [diff] [blame] | 1835 | } |
Nagireddy Annem | 672b53f | 2019-11-11 13:55:48 +0530 | [diff] [blame] | 1836 | |
| 1837 | EFI_STATUS NandABUpdatePartition (UINT32 UpdateType) |
| 1838 | { |
| 1839 | Slot Slots[] = {{L"_a"}, {L"_b"}}; |
| 1840 | NandABAttr *NandAttr = NULL; |
| 1841 | EFI_GUID Ptype = gEfiMiscPartitionGuid; |
| 1842 | EFI_STATUS Status; |
| 1843 | UINT32 PageSize; |
| 1844 | size_t Size1 = sizeof (PtnEntries[0].PartEntry.PartitionName); |
| 1845 | size_t Size2 = sizeof (NandAttr->Slots[0].SlotName); |
| 1846 | |
| 1847 | GetPageSize (&PageSize); |
| 1848 | Status = GetNandMiscPartiGuid (&Ptype); |
| 1849 | if (Status != EFI_SUCCESS) { |
| 1850 | return Status; |
| 1851 | } |
| 1852 | |
| 1853 | Status = ReadFromPartition (&Ptype, (VOID **)&NandAttr, PageSize); |
| 1854 | if (Status != EFI_SUCCESS) { |
| 1855 | DEBUG ((EFI_D_ERROR, "Error Reading from misc partition: %r\n", Status)); |
| 1856 | return Status; |
| 1857 | } |
| 1858 | |
| 1859 | if (!NandAttr) { |
| 1860 | DEBUG ((EFI_D_ERROR, "Error in loading Data from misc partition\n")); |
| 1861 | return EFI_INVALID_PARAMETER; |
| 1862 | } |
| 1863 | |
| 1864 | for (UINTN SlotIndex = 0; SlotIndex < ARRAY_SIZE (Slots); SlotIndex++) { |
| 1865 | struct PartitionEntry *BootPartition = |
| 1866 | GetBootPartitionEntry (&Slots[SlotIndex]); |
| 1867 | if (BootPartition == NULL) { |
| 1868 | DEBUG ((EFI_D_ERROR, "GetActiveSlot: No boot partition " |
| 1869 | "entry for slot %s\n", Slots[SlotIndex].Suffix)); |
| 1870 | Status = EFI_NOT_FOUND; |
| 1871 | goto Exit; |
| 1872 | } |
| 1873 | |
| 1874 | if (UpdateType == PTN_ENTRIES_TO_MISC) { |
| 1875 | NandAttr->Slots[SlotIndex].Attributes = |
| 1876 | (CHAR8)((BootPartition->PartEntry.Attributes >> |
| 1877 | PART_ATT_PRIORITY_BIT)&0xff); |
| 1878 | StrnCpyS (NandAttr->Slots[SlotIndex].SlotName, Size2 , |
| 1879 | (BootPartition->PartEntry.PartitionName), Size1); |
| 1880 | } else if (!StrnCmp (BootPartition->PartEntry.PartitionName, |
| 1881 | NandAttr->Slots[SlotIndex].SlotName, Size2)) { |
| 1882 | BootPartition->PartEntry.Attributes = |
| 1883 | (((UINT64)((NandAttr->Slots[SlotIndex].Attributes)&0xff)) << |
| 1884 | PART_ATT_PRIORITY_BIT); |
| 1885 | } |
| 1886 | } |
| 1887 | |
| 1888 | if (UpdateType == PTN_ENTRIES_TO_MISC) { |
| 1889 | WriteToPartition (&Ptype, NandAttr, sizeof (struct NandABAttr)); |
| 1890 | } |
| 1891 | |
| 1892 | Exit: |
| 1893 | if (NandAttr) { |
| 1894 | FreePool (NandAttr); |
| 1895 | NandAttr = NULL; |
| 1896 | } |
| 1897 | |
| 1898 | return Status; |
| 1899 | } |