blob: 96098b4b4922676b414268a041e8793f7589f6de [file] [log] [blame]
Channagoud Kadabif8aa7632015-11-12 14:27:01 -08001/*
2 * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
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 */
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053029#include <stdlib.h>
30#include <Uefi.h>
31#include <Library/UefiLib.h>
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -080032#include <Uefi/UefiSpec.h>
Channagoud Kadabif8aa7632015-11-12 14:27:01 -080033#include "PartitionTableUpdate.h"
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053034#include <Library/LinuxLoaderLib.h>
Channagoud Kadabif8aa7632015-11-12 14:27:01 -080035
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -080036STATIC BOOLEAN FlashingGpt;
37STATIC BOOLEAN ParseSecondaryGpt;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053038struct StoragePartInfo Ptable[MAX_LUNS];
39struct PartitionEntry PtnEntries[MAX_NUM_PARTITIONS];
40STATIC UINT32 MaxLuns;
41STATIC CHAR8 CurrentSlot[MAX_SLOT_SUFFIX_SZ];
42STATIC CHAR8 ActiveSlot[MAX_SLOT_SUFFIX_SZ];
43STATIC UINT32 PartitionCount;
44STATIC BOOLEAN MultiSlotBoot;
45
46VOID GetCurrentSlotSuffix(CHAR8* SlotSuffix) {
47 CopyMem(SlotSuffix, ActiveSlot, sizeof(ActiveSlot));
48 return;
49}
50
51VOID SetCurrentSlotSuffix(CHAR8* SlotSuffix) {
52 CopyMem(ActiveSlot, SlotSuffix, sizeof(SlotSuffix));
53 return;
54}
55
56UINT32 GetMaxLuns() {
57 return MaxLuns;
58}
59
60VOID GetPartitionCount(UINT32 *Val) {
61 *Val = PartitionCount;
62 return;
63}
64
65VOID SetMultiSlotBootVal() {
66 MultiSlotBoot = TRUE;
67 return;
68}
69
70VOID UpdatePartitionEntries()
71{
72 UINT32 i;
73 UINT32 j;
74 UINT32 Index = 0;
75 EFI_STATUS Status;
76 EFI_PARTITION_ENTRY *PartEntry;
77 CHAR8 PartitionNameAscii[MAX_GPT_NAME_SIZE];
78
79 PartitionCount = 0;
80 /*Nullify the PtnEntries array before using it*/
81 SetMem((VOID*) PtnEntries, (sizeof(PtnEntries[0]) * MAX_NUM_PARTITIONS), 0);
82
83 for (i = 0; i < MaxLuns; i++) {
84 for (j = 0; (j < Ptable[i].MaxHandles) && (Index < MAX_NUM_PARTITIONS); j++, Index++) {
85 Status = gBS->HandleProtocol(Ptable[i].HandleInfoList[j].Handle, &gEfiPartitionRecordGuid, (VOID **)&PartEntry);
86 PartitionCount++;
87 if (EFI_ERROR(Status)) {
88 DEBUG((EFI_D_VERBOSE, "Selected Lun : %d, handle: %d does not have partition record, ignore\n", i,j));
89 continue;
90 }
91 CopyMem((&PtnEntries[Index]), PartEntry, sizeof(PartEntry[0]));
92 PtnEntries[Index].lun = i;
93 }
94 }
95}
96
97INT32 GetPartitionIndex(CHAR8 *pname)
98{
99 INT32 i;
100 CHAR8 PartitionNameAscii[MAX_GPT_NAME_SIZE];
101
102 for (i = 0; i < PartitionCount; i++) {
103 UnicodeStrToAsciiStr(PtnEntries[i].PartEntry.PartitionName, PartitionNameAscii);
104 if (!AsciiStrCmp(PartitionNameAscii, pname))
105 return i;
106 }
107
108 return INVALID_PTN;
109}
110
111STATIC EFI_STATUS GetStorageHandle(INTN Lun, HandleInfo *BlockIoHandle, UINTN *MaxHandles)
112{
113 EFI_STATUS Status = EFI_INVALID_PARAMETER;
114 UINT32 Attribs = 0;
115 PartiSelectFilter HandleFilter;
116 //UFS LUN GUIDs
117 EFI_GUID LunGuids[] = {
118 gEfiUfsLU0Guid,
119 gEfiUfsLU1Guid,
120 gEfiUfsLU2Guid,
121 gEfiUfsLU3Guid,
122 gEfiUfsLU4Guid,
123 gEfiUfsLU5Guid,
124 gEfiUfsLU6Guid,
125 gEfiUfsLU7Guid,
126 };
127
128 Attribs |= BLK_IO_SEL_SELECT_ROOT_DEVICE_ONLY;
129 HandleFilter.PartitionType = 0;
130 HandleFilter.VolumeName = 0;
131
132 if (Lun == NO_LUN) {
133 HandleFilter.RootDeviceType = &gEfiEmmcUserPartitionGuid;
134 Status = GetBlkIOHandles(Attribs, &HandleFilter, BlockIoHandle, MaxHandles);
135 if (EFI_ERROR (Status)) {
136 DEBUG((EFI_D_ERROR, "Error getting block IO handle for Emmc\n"));
137 return Status;
138 }
139 } else {
140 HandleFilter.RootDeviceType = &LunGuids[Lun];
141 Status = GetBlkIOHandles(Attribs, &HandleFilter, BlockIoHandle, MaxHandles);
142 if (EFI_ERROR (Status)) {
143 DEBUG((EFI_D_ERROR, "Error getting block IO handle for Lun:%x\n", Lun));
144 return Status;
145 }
146 }
147
148 return Status;
149}
150
151void UpdatePartitionAttributes()
152{
153 UINT32 BlkSz;
154 UINT8 *GptHdr = NULL;
155 UINT8 *GptHdrPtr = NULL;
156 UINTN MaxGptSz;
157 UINT32 Offset;
158 UINT32 MaxPtnCount = 0;
159 UINT32 PtnEntrySz = 0;
160 UINT32 i = 0;
161 UINT8 *PtnEntriesPtr;
162 UINT8 *Ptn_Entries;
163 UINT32 CrcVal = 0;
164 UINT32 Iter;
165 UINT32 HdrSz = GPT_HEADER_SIZE;
166 UINT64 DeviceDensity;
167 UINT64 CardSizeSec;
168 EFI_STATUS Status;
169 INTN Lun;
170 EFI_BLOCK_IO_PROTOCOL *BlockIo=NULL;
171 HandleInfo BlockIoHandle[MAX_HANDLEINF_LST_SIZE];
172 UINTN MaxHandles = MAX_HANDLEINF_LST_SIZE;
173
174 for( Lun = 0; Lun < MaxLuns; Lun++) {
175
176 Status = GetStorageHandle(Lun, BlockIoHandle, &MaxHandles);
177 if (Status || (MaxHandles != 1)) {
178 DEBUG((EFI_D_ERROR, "Failed to get the BlockIo for the device %r\n",Status));
179 return;
180 }
181 BlockIo = BlockIoHandle[0].BlkIo;
182 DeviceDensity = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
183 BlkSz = BlockIo->Media->BlockSize;
184 MaxGptSz = GPT_HDR_AND_PTN_ENTRIES * BlkSz;
185 CardSizeSec = (DeviceDensity) / BlkSz;
186 Offset = PRIMARY_HDR_LBA;
187 GptHdr = AllocatePool(MaxGptSz);
188
189 if (!GptHdr) {
190 DEBUG ((EFI_D_ERROR, "Unable to Allocate Memory for GptHdr \n"));
191 return;
192 }
193 SetMem((VOID *) GptHdr, MaxGptSz, 0);
194 GptHdrPtr = GptHdr;
195
196 /* This loop iterates twice to update both primary and backup Gpt*/
197 for (Iter= 0; Iter < 2; Iter++) {
198
199 Status = BlockIo->ReadBlocks (BlockIo, BlockIo->Media->MediaId, Offset, MaxGptSz, GptHdr);
200
201 if(EFI_ERROR(Status)) {
202 DEBUG ((EFI_D_ERROR, "Unable to read the media \n"));
203 return;
204 }
205 if(Iter == 0x1) {
206 /* This is the back up GPT */
207 Ptn_Entries = (CHAR8 *)GptHdr;
208 GptHdr = GptHdr + ((GPT_HDR_AND_PTN_ENTRIES - 1) * BlkSz);
209 } else
210 /* otherwise we are at the primary gpt */
211 Ptn_Entries = (CHAR8 *)GptHdr + BlkSz;
212
213 PtnEntriesPtr = Ptn_Entries;
214
215 for (i = 0;i < PartitionCount;i++) {
216 /* Partition table is populated with entries from lun 0 to max lun.
217 * break out of the loop once we see the partition lun is > current lun */
218 if (PtnEntries[i].lun > Lun)
219 break;
220 /* Find the entry where the partition table for 'lun' starts and then update the attributes */
221 if (PtnEntries[i].lun != Lun)
222 continue;
223
224 /* Update the partition attributes and partiton GUID values */
225 PUT_LONG_LONG(&PtnEntriesPtr[ATTRIBUTE_FLAG_OFFSET], PtnEntries[i].PartEntry.Attributes);
226 CopyMem((VOID *)PtnEntriesPtr, (VOID *)&PtnEntries[i].PartEntry.PartitionTypeGUID, GUID_SIZE);
227 /* point to the next partition entry */
228 PtnEntriesPtr += PARTITION_ENTRY_SIZE;
229 }
230
231 MaxPtnCount = GET_LWORD_FROM_BYTE(&GptHdr[PARTITION_COUNT_OFFSET]);
232 PtnEntrySz = GET_LWORD_FROM_BYTE(&GptHdr[PENTRY_SIZE_OFFSET]);
233
234 Status = gBS->CalculateCrc32(Ptn_Entries, ((MaxPtnCount) * (PtnEntrySz)),&CrcVal);
235 if (Status != EFI_SUCCESS) {
236 DEBUG((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n", Status));
237 return;
238 }
239
240 PUT_LONG(&GptHdr[PARTITION_CRC_OFFSET], CrcVal);
241
242 /*Write CRC to 0 before we calculate the crc of the GPT header*/
243 CrcVal = 0;
244 PUT_LONG(&GptHdr[HEADER_CRC_OFFSET], CrcVal);
245
246 Status = gBS->CalculateCrc32(GptHdr, HdrSz, &CrcVal);
247 if (Status != EFI_SUCCESS) {
248 DEBUG((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n", Status));
249 return;
250 }
251
252 PUT_LONG(&GptHdr[HEADER_CRC_OFFSET], CrcVal);
253
254 if (Iter == 0x1)
255 /* Write the backup GPT header, which is at an offset of CardSizeSec - GPT_HDR_AND_PTN_ENTRIES in blocks*/
256 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, Offset, MaxGptSz, (VOID *)Ptn_Entries);
257 else
258 /* Write the primary GPT header, which is at an offset of BlkSz */
259 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, Offset, MaxGptSz, (VOID *)GptHdr);
260
261 if (EFI_ERROR(Status)) {
262 DEBUG((EFI_D_ERROR, "Error writing primary GPT header: %r\n", Status));
263 return;
264 }
265
266 Offset = CardSizeSec - GPT_HDR_AND_PTN_ENTRIES;
267 }
268 FreePool(GptHdrPtr);
269 }
270}
271
272VOID MarkPtnActive(CHAR8 *ActiveSlot)
273{
274 UINT32 i;
275 CHAR8 Slot[MAX_SLOT_SUFFIX_SZ];
276 CHAR8 PartitionNameAscii[MAX_GPT_NAME_SIZE];
277
278 AsciiStrnCpy(Slot, ActiveSlot, MAX_SLOT_SUFFIX_SZ);
279
280 for (i = 0; i < PartitionCount; i++) {
281 UnicodeStrToAsciiStr(PtnEntries[i].PartEntry.PartitionName, PartitionNameAscii);
282
283 /* Mark all the slots with current ActiveSlot as active */
284 if (AsciiStrStr(PartitionNameAscii, Slot))
285 PtnEntries[i].PartEntry.Attributes |= PART_ATT_ACTIVE_VAL;
286 else
287 PtnEntries[i].PartEntry.Attributes &= ~PART_ATT_ACTIVE_VAL;
288 }
289
290 /* Update the partition table */
291 UpdatePartitionAttributes();
292}
293
294STATIC VOID SwapPtnGuid(EFI_PARTITION_ENTRY *p1, EFI_PARTITION_ENTRY *p2)
295{
296 UINT32 Temp[PARTITION_TYPE_GUID_SIZE];
297
298 if (p1 == NULL || p2 == NULL)
299 return;
300 CopyMem((VOID *)&Temp, (VOID *)&p1->PartitionTypeGUID, sizeof(p1->PartitionTypeGUID));
301 CopyMem((VOID *)&p1->PartitionTypeGUID, (VOID *)&p2->PartitionTypeGUID, sizeof(p2->PartitionTypeGUID));
302 CopyMem((VOID *)&p2->PartitionTypeGUID, (VOID *)&Temp, sizeof(Temp));
303}
304
305VOID SwitchPtnSlots(CONST CHAR8 *SetActive)
306{
307 UINT32 i, j;
308 CONST CHAR8 *BootParts[] = { "rpm", "tz", "pmic", "modem", "hyp", "cmnlib", "cmnlib64", "keymaster", "devcfg", "abl", "apdp"};
309 size_t Sz = ARRAY_SIZE(BootParts);
310 struct PartitionEntry *PtnCurrent = NULL;
311 struct PartitionEntry *PtnNew = NULL;
312 CHAR8 CurSlot[BOOT_PART_SIZE];
313 CHAR8 NewSlot[BOOT_PART_SIZE];
314 CHAR8 SetInactive[MAX_SLOT_SUFFIX_SZ];
315 CHAR8 PartitionNameAscii[MAX_GPT_NAME_SIZE];
316 UINT32 UfsBootLun = 0;
317 BOOLEAN UfsGet = TRUE;
318 BOOLEAN UfsSet = FALSE;
319 EFI_STATUS Status;
320
321 /* Create the partition name string for active and non active slots*/
322 if (!AsciiStrnCmp(SetActive, "_a", 2))
323 AsciiStrnCpy(SetInactive, "_b", MAX_SLOT_SUFFIX_SZ);
324 else
325 AsciiStrnCpy(SetInactive, "_a", MAX_SLOT_SUFFIX_SZ);
326
327 for (j = 0; j < Sz; j++) {
328 AsciiStrnCpy(CurSlot, BootParts[j], BOOT_PART_SIZE);
329 AsciiStrnCat(CurSlot, SetInactive, BOOT_PART_SIZE);
330
331 AsciiStrnCpy(NewSlot, BootParts[j], BOOT_PART_SIZE);
332 AsciiStrnCat(NewSlot, SetActive, BOOT_PART_SIZE);
333
334 /* Find the pointer to partition table entry for active and non-active slots*/
335 for (i = 0; i < PartitionCount; i++) {
336 UnicodeStrToAsciiStr(PtnEntries[i].PartEntry.PartitionName, PartitionNameAscii);
337 if (!AsciiStrCmp(PartitionNameAscii, CurSlot)) {
338 PtnCurrent = &PtnEntries[i];
339 } else if (!AsciiStrCmp(PartitionNameAscii, NewSlot)) {
340 PtnNew = &PtnEntries[i];
341 }
342 }
343 /* Swap the guids for the slots */
344 SwapPtnGuid(&PtnCurrent->PartEntry, &PtnNew->PartEntry);
345 SetMem(CurSlot, BOOT_PART_SIZE, 0);
346 SetMem(NewSlot, BOOT_PART_SIZE, 0);
347 PtnCurrent = PtnNew = NULL;
348 }
349 UfsGetSetBootLun(&UfsBootLun, UfsGet);
350 // Special case for XBL is to change the bootlun instead of swapping the guid
351 if (UfsBootLun == 0x1 && !AsciiStrCmp(SetActive, "_b")) {
352 DEBUG((EFI_D_INFO, "Switching the boot lun from 1 to 2\n"));
353 UfsBootLun = 0x2;
354 }
355 else if (UfsBootLun == 0x2 && !AsciiStrCmp(SetActive, "_a")) {
356 DEBUG((EFI_D_INFO, "Switching the boot lun from 2 to 1\n"));
357 UfsBootLun = 0x1;
358 }
359 UfsGetSetBootLun(&UfsBootLun, UfsSet);
360}
361
362EFI_STATUS
363EnumeratePartitions ()
364{
365 EFI_STATUS Status;
366 PartiSelectFilter HandleFilter;
367 UINT32 Attribs = 0;
368 UINT32 i;
369 INT32 Lun = NO_LUN;
370 //UFS LUN GUIDs
371 EFI_GUID LunGuids[] = {
372 gEfiUfsLU0Guid,
373 gEfiUfsLU1Guid,
374 gEfiUfsLU2Guid,
375 gEfiUfsLU3Guid,
376 gEfiUfsLU4Guid,
377 gEfiUfsLU5Guid,
378 gEfiUfsLU6Guid,
379 gEfiUfsLU7Guid,
380 };
381
382 SetMem((VOID*) Ptable, (sizeof(struct StoragePartInfo) * MAX_LUNS), 0);
383
384 /* By default look for emmc partitions if not found look for UFS */
385 Attribs |= BLK_IO_SEL_MATCH_ROOT_DEVICE;
386
387 Ptable[0].MaxHandles = ARRAY_SIZE(Ptable[0].HandleInfoList);
388 HandleFilter.PartitionType = 0;
389 HandleFilter.VolumeName = 0;
390 HandleFilter.RootDeviceType = &gEfiEmmcUserPartitionGuid;
391
392 Status = GetBlkIOHandles(Attribs, &HandleFilter, &Ptable[0].HandleInfoList[0], &Ptable[0].MaxHandles);
393 /* For Emmc devices the Lun concept does not exist, we will always one lun and the lun number is '0'
394 * to have the partition selection implementation same acros
395 */
396 if (Status == EFI_SUCCESS && Ptable[0].MaxHandles > 0) {
397 Lun = 0;
398 MaxLuns = 1;
399 }
400 /* If the media is not emmc then look for UFS */
401 else if (EFI_ERROR (Status) || Ptable[0].MaxHandles == 0) {
402 /* By default max 8 luns are supported but HW could be configured to use only few of them or all of them
403 * Based on the information read update the MaxLuns to reflect the max supported luns */
404 for (i = 0 ; i < MAX_LUNS; i++) {
405 Ptable[i].MaxHandles = ARRAY_SIZE(Ptable[i].HandleInfoList);
406 HandleFilter.PartitionType = 0;
407 HandleFilter.VolumeName = 0;
408 HandleFilter.RootDeviceType = &LunGuids[i];
409
410 Status = GetBlkIOHandles(Attribs, &HandleFilter, &Ptable[i].HandleInfoList[0], &Ptable[i].MaxHandles);
411 /* If we fail to get block for a lun that means the lun is not configured and unsed, ignore the error
412 * and continue with the next Lun */
413 if (EFI_ERROR (Status)) {
414 DEBUG((EFI_D_ERROR, "Error getting block IO handle for %d lun, Lun may be unused\n", i));
415 continue;
416 }
417 }
418 MaxLuns = i;
419 } else {
420 DEBUG((EFI_D_ERROR, "Error populating block IO handles\n"));
421 return EFI_NOT_FOUND;
422 }
423
424 return Status;
425}
426
427/*Function to provide has-slot info
428 *Pname: the partition name
429 *return: 1 or 0.
430 */
431BOOLEAN PartitionHasMultiSlot(CONST CHAR8 *Pname)
432{
433 UINT32 i;
434 UINT32 j;
435 UINT32 SlotCount = 0;
436 UINT32 Len = AsciiStrLen(Pname);
437 CHAR8 PartitionNameAscii[MAX_GPT_NAME_SIZE];
438
439 /*If MultiSlot is set just return the value avoid for loop everytime*/
440 if (MultiSlotBoot)
441 return MultiSlotBoot;
442
443 for (i = 0; i < PartitionCount; i++) {
444 UnicodeStrToAsciiStr(PtnEntries[i].PartEntry.PartitionName, PartitionNameAscii);
445 if(!(AsciiStrnCmp(PartitionNameAscii, Pname, Len))) {
446 if (PartitionNameAscii[Len] == '_' &&
447 (PartitionNameAscii[Len+1] == 'a' ||
448 PartitionNameAscii[Len+1] == 'b'))
449 SlotCount++;
450 }
451 }
452
453 if (SlotCount > MIN_SLOTS)
454 MultiSlotBoot = TRUE;
455 else
456 MultiSlotBoot = FALSE;
457
458 return MultiSlotBoot;
459}
460
461VOID FindPtnActiveSlot()
462{
463 UINT32 i;
464 CHAR8 *Suffix = NULL;
465 UINT32 HighPriority = 0;
466 CHAR8 DefaultActive[MAX_SLOT_SUFFIX_SZ]= "_a";
467 UINT32 Unbootable = 0;
468 CHAR8 SlotInfo[MAX_SLOT_SUFFIX_SZ];
469 CHAR8 PartitionNameAscii[MAX_GPT_NAME_SIZE];
470
471 /*Traverse through partition entries,count matching slots with boot */
472 for (i = 0; i < PartitionCount; i++) {
473 UnicodeStrToAsciiStr(PtnEntries[i].PartEntry.PartitionName, PartitionNameAscii);
474 /* We determine the active slot chain based on the attributes of boot partition */
475 if(!(AsciiStrnCmp(PartitionNameAscii,"boot",AsciiStrLen("boot")))) {
476 Suffix = PartitionNameAscii + AsciiStrLen("boot");
477
478
479 if ((HighPriority < (PtnEntries[i].PartEntry.Attributes & PART_ATT_PRIORITY_VAL))
480 && !(PtnEntries[i].PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) &&
481 PtnEntries[i].PartEntry.Attributes & PART_ATT_ACTIVE_VAL) {
482 HighPriority = (PtnEntries[i].PartEntry.Attributes & PART_ATT_PRIORITY_VAL);
483 AsciiStrnCpy(ActiveSlot,Suffix,MAX_SLOT_SUFFIX_SZ);
484 }
485 if (PtnEntries[i].PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) {
486 AsciiStrnCpy(SlotInfo, Suffix, MAX_SLOT_SUFFIX_SZ);
487 SetMem(ActiveSlot, sizeof(ActiveSlot), 0);
488 Unbootable++;
489 }
490 }
491 }
492 if (Unbootable == (MAX_SLOTS - 1)) {
493 if (SlotInfo[1] == 'a')
494 AsciiStrnCpy(ActiveSlot, "_b", MAX_SLOT_SUFFIX_SZ);
495 else
496 AsciiStrnCpy(ActiveSlot, "_a", MAX_SLOT_SUFFIX_SZ);
497 }
498
499 /* Probably we are booting for the first time and the active slot is not set using
500 * fastboot set_active, so default to slot 'a'
501 */
502 if (!Unbootable && !ActiveSlot[0] && !HighPriority) {
503 AsciiStrnCpy(ActiveSlot, DefaultActive, MAX_SLOT_SUFFIX_SZ);
504 for (i = 0; i < PartitionCount; i++) {
505 UnicodeStrToAsciiStr(PtnEntries[i].PartEntry.PartitionName, PartitionNameAscii);
506 if (!(AsciiStrnCmp(PartitionNameAscii, "boot_a", AsciiStrLen("boot_a")))) {
507 PtnEntries[i].PartEntry.Attributes |=
508 (PART_ATT_PRIORITY_VAL | PART_ATT_ACTIVE_VAL | PART_ATT_MAX_RETRY_COUNT_VAL) &
509 (~PART_ATT_SUCCESSFUL_VAL & ~PART_ATT_UNBOOTABLE_VAL);
510 }
511 }
512 }
513
514 if (!ActiveSlot[0] && !ActiveSlot[1]) {
515 DEBUG((EFI_D_ERROR, "ERROR: NO ACTIVE SLOT FOUND\n"));
516 ASSERT(0);
517 }
518 UpdatePartitionAttributes();
519 AsciiStrnCpy(CurrentSlot, ActiveSlot, MAX_SLOT_SUFFIX_SZ);
520 return;
521}
522
523/* If we are here after marking the current slot as unbootable, then we
524 * switch the slots for the entire bootchain so we are booting all the images
525 * from the new slot and reboot the device so that bootchain is picked from new slot
526 */
527STATIC VOID MarkSlotUnbootable()
528{
529 CHAR8 PartName[MAX_GPT_NAME_SIZE];
530 UINT32 i;
531 CHAR8 PartitionNameAscii[MAX_GPT_NAME_SIZE];
532 SwitchPtnSlots(CurrentSlot);
533 AsciiStrnCpy(PartName, "boot", MAX_GPT_NAME_SIZE);
534 AsciiStrnCat(PartName, CurrentSlot, MAX_GPT_NAME_SIZE);
535 for (i = 0; i < PartitionCount; i++) {
536 UnicodeStrToAsciiStr(PtnEntries[i].PartEntry.PartitionName, PartitionNameAscii);
537 if(!AsciiStrnCmp(PartitionNameAscii, PartName, MAX_GPT_NAME_SIZE)) {
538 /*select the slot and increase the priority = 7,retry-count =7,slot_successful = 0 and slot_unbootable =0*/
539 PtnEntries[i].PartEntry.Attributes =
540 (PtnEntries[i].PartEntry.Attributes | PART_ATT_PRIORITY_VAL |
541 PART_ATT_ACTIVE_VAL | PART_ATT_MAX_RETRY_COUNT_VAL) &
542 (~PART_ATT_SUCCESSFUL_VAL & ~PART_ATT_UNBOOTABLE_VAL);
543 }
544 }
545 UpdatePartitionAttributes();
546
547 DEBUG((EFI_D_INFO, "Rebooting\n"));
548 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
549
550 // Shouldn't get here
551 DEBUG ((EFI_D_ERROR, "Fastboot: gRT->Resetystem didn't work\n"));
552 return;
553}
554
555/*Function to get high priority bootable slot
556 *Note: Updates the BootableSlot with high
557 *priority boot slot. If no high priority slot
558 *avaiable and all slots marked as unbootable,
559 *then update BootableSlot with recovery.
560 */
561VOID FindBootableSlot(CHAR8 *BootableSlot)
562{
563 /* Only two slots are supported */
564 UINT32 RetryCount = 0;
565 INT32 Index;
566 UINT32 SlotUnbootable = 0;
567 UINT32 i;
568 CHAR8 PartName[MAX_GPT_NAME_SIZE];
569 CHAR8 PartitionNameAscii[MAX_GPT_NAME_SIZE];
570 UINT32 BootLun = 0;
571 struct PartitionEntry *PartEntryPtr;
572 UINT32 UfsBootLun = 0;
573 BOOLEAN UfsGet = TRUE;
574
575TryNextSlot:
576 FindPtnActiveSlot();
577
578 /* If we are here after marking the current slot as unbootable, then we
579 * switch the slots for the entire bootchain so we are booting all the images
580 * from the new slot and reboot the device so that bootchain is picked from new slot
581 */
582 if (SlotUnbootable)
583 MarkSlotUnbootable();
584 AsciiStrnCpy(BootableSlot, "boot", MAX_GPT_NAME_SIZE);
585 AsciiStrnCat(BootableSlot, CurrentSlot, MAX_GPT_NAME_SIZE);
586
587 UfsGetSetBootLun(&UfsBootLun,UfsGet);
588 if (UfsBootLun == 0x1 && !AsciiStrCmp(CurrentSlot, "_a"))
589 DEBUG((EFI_D_INFO,"Booting from slot (%a) , BootableSlot = %a\n",CurrentSlot, BootableSlot));
590 else if (UfsBootLun == 0x2 && !AsciiStrCmp(CurrentSlot, "_b"))
591 DEBUG((EFI_D_INFO,"Booting from slot (%a) , BootableSlot = %a\n",CurrentSlot, BootableSlot));
592 else {
593 DEBUG((EFI_D_ERROR,"Boot lun: %x and Currentslot: %a do not match\n",UfsBootLun, CurrentSlot));
594 *BootableSlot = '\0';
595 }
596 Index = GetPartitionIndex(BootableSlot);
597 if (Index == INVALID_PTN) {
598 DEBUG((EFI_D_ERROR, "Invalid partition index for BootableSlot=%a \n",BootableSlot));
599 return;
600 }
601 PartEntryPtr = &PtnEntries[Index];
602 /*if slot_successful is set do normal bootup*/
603 if (PartEntryPtr->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) {
604 return;
605 } else {
606 /*if retry-count > 0,decrement it, do normal boot*/
607 if((RetryCount = ((PartEntryPtr->PartEntry.Attributes & PART_ATT_MAX_RETRY_COUNT_VAL) >> PART_ATT_MAX_RETRY_CNT_BIT))) {
608 PartEntryPtr->PartEntry.Attributes = (PartEntryPtr->PartEntry.Attributes & ~PART_ATT_MAX_RETRY_COUNT_VAL) |(((UINT64)RetryCount-1) << PART_ATT_MAX_RETRY_CNT_BIT);
609 } else {
610 /*else mark slot as unbootable update fields then go for next slot*/
611 PartEntryPtr->PartEntry.Attributes |= PART_ATT_UNBOOTABLE_VAL & ~PART_ATT_ACTIVE_VAL & ~PART_ATT_PRIORITY_VAL;
612 AsciiStrnCpy(BootableSlot,"",MAX_GPT_NAME_SIZE);
613 SlotUnbootable++;
614 goto TryNextSlot;
615 }
616 }
617 UpdatePartitionAttributes();
618}
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800619
620STATIC INTN PartitionVerifyMbrSignature(UINT32 Sz, UINT8 *Gpt)
621{
622 if ((MBR_SIGNATURE + 1) > Sz)
623 {
624 DEBUG((EFI_D_ERROR, "Gpt Image size is invalid\n"));
625 return FAILURE;
626 }
627
628 /* Check for the signature */
629 if ((Gpt[MBR_SIGNATURE] != MBR_SIGNATURE_BYTE_0) ||
630 (Gpt[MBR_SIGNATURE + 1] != MBR_SIGNATURE_BYTE_1))
631 {
632 DEBUG((EFI_D_ERROR, "MBR signature do not match\n"));
633 return FAILURE;
634 }
635 return SUCCESS;
636}
637
638STATIC INTN MbrGetPartitionType(UINT32 Sz, UINT8 *Gpt, UINT32 *Ptype)
639{
640 UINT32 PtypeOffset = MBR_PARTITION_RECORD + OS_TYPE;
641
642 if (Sz < (PtypeOffset + sizeof(*Ptype)))
643 {
644 DEBUG((EFI_D_ERROR, "Input gpt image does not have gpt partition record data\n"));
645 return FAILURE;
646 }
647
648 *Ptype = Gpt[PtypeOffset];
649
650 return SUCCESS;
651}
652
653STATIC INTN PartitionGetType(UINT32 Sz, UINT8 *Gpt, UINT32 *Ptype)
654{
655 INTN Ret;
656
657 Ret = PartitionVerifyMbrSignature(Sz, Gpt);
658 if (!Ret)
659 {
660 /* MBR signature match, this coulb be MBR, MBR + EBR or GPT */
661 Ret = MbrGetPartitionType(Sz, Gpt, Ptype);
662 if (!Ret)
663 {
664 if (*Ptype == GPT_PROTECTIVE)
665 *Ptype = PARTITION_TYPE_GPT;
666 else
667 *Ptype = PARTITION_TYPE_MBR;
668 }
669 }
670 else
671 {
672 /* This could be GPT back up */
673 *Ptype = PARTITION_TYPE_GPT_BACKUP;
674 Ret = SUCCESS;
675 }
676
677 return Ret;
678}
679
680STATIC INTN ParseGptHeader(struct GptHeaderData *GptHeader, UINT8 *GptBuffer, UINTN DeviceDensity, UINT32 BlkSz)
681{
682 UINT32 CrcOrig;
683 UINT32 CrcVal;
684 UINT32 CurrentLba;
685 EFI_STATUS Status;
686
687 if (((UINT32 *) GptBuffer)[0] != GPT_SIGNATURE_2 || ((UINT32 *) GptBuffer)[1] != GPT_SIGNATURE_1)
688 {
689 DEBUG((EFI_D_ERROR, "Gpt signature is not correct\n"));
690 return FAILURE;
691 }
692
693 GptHeader->HeaderSz = GET_LWORD_FROM_BYTE(&GptBuffer[HEADER_SIZE_OFFSET]);
694 /* Validate the header size */
695 if (GptHeader->HeaderSz < GPT_HEADER_SIZE)
696 {
697 DEBUG((EFI_D_ERROR, "GPT Header size is too small: %u\n", GptHeader->HeaderSz));
698 return FAILURE;
699 }
700
701 if (GptHeader->HeaderSz > BlkSz)
702 {
703 DEBUG((EFI_D_ERROR, "GPT Header is too large: %u\n", GptHeader->HeaderSz));
704 return FAILURE;
705 }
706
707 CrcOrig = GET_LWORD_FROM_BYTE(&GptBuffer[HEADER_CRC_OFFSET]);
708 /* CRC value is computed by setting this field to 0, and computing the 32-bit CRC for HeaderSize bytes */
709 CrcVal = 0;
710 PUT_LONG(&GptBuffer[HEADER_CRC_OFFSET], CrcVal);
711
712 Status = gBS->CalculateCrc32(GptBuffer, GptHeader->HeaderSz, &CrcVal);
713 if (Status != EFI_SUCCESS)
714 {
715 DEBUG((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n", Status));
716 return FAILURE;
717 }
718
719 if (CrcVal != CrcOrig)
720 {
721 DEBUG((EFI_D_ERROR, "Header CRC mismatch CrcVal = %u and CrcOrig = %u\n", CrcVal, CrcOrig));
722 return FAILURE;
723 }
724 else
725 PUT_LONG(&GptBuffer[HEADER_CRC_OFFSET], CrcVal);
726
727 CurrentLba = GET_LLWORD_FROM_BYTE(&GptBuffer[PRIMARY_HEADER_OFFSET]);
728 GptHeader->FirstUsableLba = GET_LLWORD_FROM_BYTE(&GptBuffer[FIRST_USABLE_LBA_OFFSET]);
729 GptHeader->MaxPtCnt = GET_LWORD_FROM_BYTE(&GptBuffer[PARTITION_COUNT_OFFSET]);
730 GptHeader->PartEntrySz = GET_LWORD_FROM_BYTE(&GptBuffer[PENTRY_SIZE_OFFSET]);
731 GptHeader->LastUsableLba = GET_LLWORD_FROM_BYTE(&GptBuffer[LAST_USABLE_LBA_OFFSET]);
732 if (!ParseSecondaryGpt)
733 {
734 if (CurrentLba != GPT_LBA)
735 {
736 DEBUG((EFI_D_ERROR, "GPT first usable LBA mismatch\n"));
737 return FAILURE;
738 }
739 }
740
741 /* Check for first lba should be within valid range */
742 if (GptHeader->FirstUsableLba > (DeviceDensity / BlkSz))
743 {
744 DEBUG((EFI_D_ERROR, "FirstUsableLba: %u out of Device capacity\n", GptHeader->FirstUsableLba));
745 return FAILURE;
746 }
747
748 /* Check for Last lba should be within valid range */
749 if (GptHeader->LastUsableLba > (DeviceDensity / BlkSz))
750 {
751 DEBUG((EFI_D_ERROR, "LastUsableLba: %u out of device capacity\n", GptHeader->LastUsableLba));
752 return FAILURE;
753 }
754
755 if (GptHeader->PartEntrySz != GPT_PART_ENTRY_SIZE)
756 {
757 DEBUG((EFI_D_ERROR, "Invalid partition entry size: %u\n", GptHeader->PartEntrySz));
758 return FAILURE;
759 }
760
761 if (GptHeader->MaxPtCnt > (MIN_PARTITION_ARRAY_SIZE / (GptHeader->PartEntrySz)))
762 {
763 DEBUG((EFI_D_ERROR, "Invalid Max Partition Count: %u\n", GptHeader->MaxPtCnt));
764 return FAILURE;
765 }
766
767 /* Todo: Check CRC during reading partition table*/
768 if (!FlashingGpt)
769 {
770 }
771
772 return SUCCESS;
773}
774
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800775STATIC INTN PatchGpt (
776 UINT8 *Gpt, UINTN DeviceDensity, UINT32 PartEntryArrSz,
777 struct GptHeaderData *GptHeader, UINT32 BlkSz)
778{
779 UINT8 *PrimaryGptHeader;
780 UINT8 *SecondaryGptHeader;
781 UINTN NumSectors;
782 UINT32 Offset;
783 UINT32 TotalPart = 0;
784 UINT32 LastPartOffset;
785 UINT8 *PartitionEntryArrStart;
786 UINT32 CrcVal;
787 EFI_STATUS Status;
788
789 NumSectors = DeviceDensity / BlkSz;
790
791 /* Update the primary and backup GPT header offset with the sector location */
792 PrimaryGptHeader = (Gpt + BlkSz);
793 /* Patch primary GPT */
794 PUT_LONG_LONG(PrimaryGptHeader + BACKUP_HEADER_OFFSET, (UINTN) (NumSectors - 1));
795 PUT_LONG_LONG(PrimaryGptHeader + LAST_USABLE_LBA_OFFSET, (UINTN) (NumSectors - 34));
796
797 /* Patch Backup GPT */
798 Offset = (2 * PartEntryArrSz);
799 SecondaryGptHeader = Offset + BlkSz + PrimaryGptHeader;
800 PUT_LONG_LONG(SecondaryGptHeader + PRIMARY_HEADER_OFFSET, (UINTN)1);
801 PUT_LONG_LONG(SecondaryGptHeader + LAST_USABLE_LBA_OFFSET, (UINTN) (NumSectors - 34));
802 PUT_LONG_LONG(SecondaryGptHeader + PARTITION_ENTRIES_OFFSET, (UINTN) (NumSectors - 33));
803
804 /* Patch the last partition */
805 while (*(PrimaryGptHeader + BlkSz + TotalPart * PARTITION_ENTRY_SIZE) != 0)
806 TotalPart++;
807
808 LastPartOffset = (TotalPart - 1) * PARTITION_ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA;
809
810 PUT_LONG_LONG(PrimaryGptHeader + BlkSz + LastPartOffset, (UINTN) (NumSectors - 34));
811 PUT_LONG_LONG(PrimaryGptHeader + BlkSz + LastPartOffset + PartEntryArrSz, (UINTN) (NumSectors - 34));
812
813 /* Update CRC of the partition entry array for both headers */
814 PartitionEntryArrStart = PrimaryGptHeader + BlkSz;
815 Status = gBS->CalculateCrc32(PartitionEntryArrStart, (GptHeader->MaxPtCnt * GptHeader->PartEntrySz), &CrcVal);
816 if (EFI_ERROR(Status))
817 {
818 DEBUG((EFI_D_ERROR, "Error calculating CRC for primary partition entry\n"));
819 return FAILURE;
820 }
821 PUT_LONG(PrimaryGptHeader + PARTITION_CRC_OFFSET, CrcVal);
822
823 Status = gBS->CalculateCrc32(PartitionEntryArrStart + PartEntryArrSz, (GptHeader->MaxPtCnt * GptHeader->PartEntrySz), &CrcVal);
824 if (EFI_ERROR(Status))
825 {
826 DEBUG((EFI_D_ERROR, "Error calculating CRC for secondary partition entry\n"));
827 return FAILURE;
828 }
829 PUT_LONG(SecondaryGptHeader + PARTITION_CRC_OFFSET, CrcVal);
830
831 /* Clear Header CRC field values & recalculate */
832 PUT_LONG(PrimaryGptHeader + HEADER_CRC_OFFSET, 0);
833 Status = gBS->CalculateCrc32(PrimaryGptHeader, GPT_HEADER_SIZE, &CrcVal);
834 if (EFI_ERROR(Status))
835 {
836 DEBUG((EFI_D_ERROR, "Error calculating CRC for primary gpt header\n"));
837 return FAILURE;
838 }
839 PUT_LONG(PrimaryGptHeader + HEADER_CRC_OFFSET, CrcVal);
840 PUT_LONG(SecondaryGptHeader + HEADER_CRC_OFFSET, 0);
841 Status = gBS->CalculateCrc32(SecondaryGptHeader, GPT_HEADER_SIZE, &CrcVal);
842 if (EFI_ERROR(Status))
843 {
844 DEBUG((EFI_D_ERROR, "Error calculating CRC for secondary gpt header\n"));
845 return FAILURE;
846 }
847 PUT_LONG(SecondaryGptHeader + HEADER_CRC_OFFSET, CrcVal);
848
849 return SUCCESS;
850}
851
852STATIC INTN WriteGpt(INTN Lun, UINT32 Sz, UINT8 *Gpt)
853{
854 INTN Ret = 1;
855 struct GptHeaderData GptHeader;
856 UINTN BackupHeaderLba;
857 UINT32 MaxPtCnt = 0;
858 UINT8 *PartEntryArrSt;
859 UINT32 Offset;
860 UINT32 PartEntryArrSz;
861 UINTN DeviceDensity;
862 UINT32 BlkSz;
863 UINT8 *PrimaryGptHdr = NULL;
864 UINT8 *SecondaryGptHdr = NULL;
865 EFI_STATUS Status;
866 UINTN BackUpGptLba;
867 UINTN PartitionEntryLba;
868 EFI_ERASE_BLOCK_PROTOCOL *EraseProt = NULL;
869 UINTN TokenIndex;
870 EFI_ERASE_BLOCK_TOKEN EraseToken;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800871 EFI_BLOCK_IO_PROTOCOL *BlockIo = NULL;
872 HandleInfo BlockIoHandle[MAX_HANDLEINF_LST_SIZE];
873 UINTN MaxHandles = MAX_HANDLEINF_LST_SIZE;
874
875 Ret = GetStorageHandle(Lun, BlockIoHandle, &MaxHandles);
876 if (Ret || (MaxHandles != 1))
877 {
878 DEBUG((EFI_D_ERROR, "Failed to get the BlockIo for the device\n"));
879 return Ret;
880 }
881
882 BlockIo = BlockIoHandle[0].BlkIo;
883 DeviceDensity = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
884 BlkSz = BlockIo->Media->BlockSize;
885
886 /* Verity that passed block has valid GPT primary header */
887 PrimaryGptHdr = (Gpt + BlkSz);
888 Ret = ParseGptHeader(&GptHeader, PrimaryGptHdr, DeviceDensity, BlkSz);
889 if (Ret)
890 {
891 DEBUG((EFI_D_ERROR, "GPT: Error processing primary GPT header\n"));
892 return Ret;
893 }
894
895 /* Check if a valid back up GPT is present */
896 PartEntryArrSz = GptHeader.PartEntrySz * GptHeader.MaxPtCnt;
897 if (PartEntryArrSz < MIN_PARTITION_ARRAY_SIZE)
898 PartEntryArrSz = MIN_PARTITION_ARRAY_SIZE;
899
900 /* Back up partition is stored in the reverse order with back GPT, followed by
901 * part entries, find the offset to back up GPT */
902 Offset = (2 * PartEntryArrSz);
903 SecondaryGptHdr = Offset + BlkSz + PrimaryGptHdr;
904 ParseSecondaryGpt = TRUE;
905
906 Ret = ParseGptHeader(&GptHeader, SecondaryGptHdr, DeviceDensity, BlkSz);
907 if (Ret)
908 {
909 DEBUG((EFI_D_ERROR, "GPT: Error processing backup GPT header\n"));
910 return Ret;
911 }
912
913 Ret = PatchGpt(Gpt, DeviceDensity, PartEntryArrSz, &GptHeader, BlkSz);
914 if (Ret)
915 {
916 DEBUG((EFI_D_ERROR, "Failed to patch GPT\n"));
917 return Ret;
918 }
919 /* Erase the entire card */
920 Status = gBS->HandleProtocol(BlockIoHandle[0].Handle, &gEfiEraseBlockProtocolGuid, (VOID **) &EraseProt);
921 if (Status != EFI_SUCCESS)
922 {
923 DEBUG((EFI_D_ERROR, "Unable to locate Erase block protocol handle: %r\n", Status));
924 return Status;
925 }
926 Status = EraseProt->EraseBlocks(BlockIo, BlockIo->Media->MediaId, 0, &EraseToken, DeviceDensity);
927 if (Status != EFI_SUCCESS)
928 {
929 DEBUG((EFI_D_ERROR, "Unable to Erase Block: %r\n", Status));
930 return Status;
931 }
932 else
933 {
934 /* handle the event */
935 if (EraseToken.Event != NULL)
936 {
937 DEBUG((EFI_D_INFO, "Waiting for the Erase even to signal the completion\n"));
938 gBS->WaitForEvent(1, &EraseToken.Event, &TokenIndex);
939 }
940 }
941
942 /* write the protective MBR */
943 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, 0, BlkSz, (VOID *)Gpt);
944 if (EFI_ERROR(Status))
945 {
946 DEBUG((EFI_D_ERROR, "Error writing protective MBR: %x\n", Status));
947 return FAILURE;
948 }
949
950 /* Write the primary GPT header, which is at an offset of BlkSz */
951 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, 1, BlkSz, (VOID *)PrimaryGptHdr);
952 if (EFI_ERROR(Status))
953 {
954 DEBUG((EFI_D_ERROR, "Error writing primary GPT header: %r\n", Status));
955 return FAILURE;
956 }
957
958 /* Write the back up GPT header */
959 BackUpGptLba = GET_LLWORD_FROM_BYTE(&PrimaryGptHdr[BACKUP_HEADER_OFFSET]);
960 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, BackUpGptLba, BlkSz, (VOID *)SecondaryGptHdr);
961 if (EFI_ERROR(Status))
962 {
963 DEBUG((EFI_D_ERROR, "Error writing secondary GPT header: %x\n", Status));
964 return FAILURE;
965 }
966
967 /* write Partition Entries for primary partition table*/
968 PartEntryArrSt = PrimaryGptHdr + BlkSz;
969 PartitionEntryLba = GET_LLWORD_FROM_BYTE(&PrimaryGptHdr[PARTITION_ENTRIES_OFFSET]);
970 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, PartitionEntryLba, PartEntryArrSz, (VOID *)PartEntryArrSt);
971 if (EFI_ERROR(Status))
972 {
973 DEBUG((EFI_D_ERROR, "Error writing partition entries array for Primary Table: %x\n", Status));
974 return FAILURE;
975 }
976
977 /* write Partition Entries for secondary partition table*/
978 PartEntryArrSt = PrimaryGptHdr + BlkSz + PartEntryArrSz;
979 PartitionEntryLba = GET_LLWORD_FROM_BYTE(&SecondaryGptHdr[PARTITION_ENTRIES_OFFSET]);
980 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, PartitionEntryLba, PartEntryArrSz, (VOID *)PartEntryArrSt);
981 if (EFI_ERROR(Status))
982 {
983 DEBUG((EFI_D_ERROR, "Error writing partition entries array for Secondary Table: %x\n", Status));
984 return FAILURE;
985 }
986 FlashingGpt = 0;
Runmin Wang2a194612016-07-25 14:15:34 -0700987 SetMem((VOID *)PrimaryGptHdr, Sz, 0x0);
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800988
989 DEBUG((EFI_D_ERROR, "Updated Partition Table Successfully\n"));
990 return SUCCESS;
991}
992
993EFI_STATUS UpdatePartitionTable(UINT8 *GptImage, UINT32 Sz, INTN Lun, struct StoragePartInfo *Ptable)
Channagoud Kadabif8aa7632015-11-12 14:27:01 -0800994{
995 EFI_STATUS Status = EFI_SUCCESS;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800996 UINT32 Ptype;
997 INTN Ret;
Channagoud Kadabif8aa7632015-11-12 14:27:01 -0800998
999 /* Check if the partition type is GPT */
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -08001000 Ret = PartitionGetType(Sz, GptImage, &Ptype);
1001 if (Ret != 0)
1002 {
1003 DEBUG((EFI_D_ERROR, "Failed to get partition type from input gpt image\n"));
1004 return EFI_NOT_FOUND;
1005 }
1006
1007 switch (Ptype)
1008 {
1009 case PARTITION_TYPE_GPT:
1010 DEBUG((EFI_D_INFO, "Updating GPT partition\n"));
1011 FlashingGpt = TRUE;
1012 Ret = WriteGpt(Lun, Sz, GptImage);
1013 if (Ret != 0)
1014 {
1015 DEBUG((EFI_D_ERROR, "Failed to write Gpt partition: %x\n", Ret));
1016 return EFI_VOLUME_CORRUPTED;
1017 }
1018 break;
1019 default:
1020 DEBUG((EFI_D_ERROR, "Invalid Partition type: %x\n",Ptype));
1021 Status = EFI_UNSUPPORTED;
1022 break;
1023 }
1024
Channagoud Kadabif8aa7632015-11-12 14:27:01 -08001025 return Status;
1026}