blob: 7fd20a4e1df4c97ae4abe1b44e84afbb9b0c3b9d [file] [log] [blame]
Channagoud Kadabif8aa7632015-11-12 14:27:01 -08001/*
Vijay Kumar Pendotia38f5742017-01-17 20:05:10 +05302 * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
Channagoud Kadabif8aa7632015-11-12 14:27:01 -08003 *
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 <Uefi.h>
30#include <Library/UefiLib.h>
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -080031#include <Uefi/UefiSpec.h>
Channagoud Kadabif8aa7632015-11-12 14:27:01 -080032#include "PartitionTableUpdate.h"
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053033#include <Library/LinuxLoaderLib.h>
lijuang2120d972016-11-02 18:28:21 +080034#include <Library/Board.h>
Shivaprasad Hongalc017e812017-04-26 16:15:27 -070035#include <VerifiedBoot.h>
Vijay Kumar Pendoti4229f7b2017-05-08 21:32:39 +053036#include <Library/BootLinux.h>
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -080037STATIC BOOLEAN FlashingGpt;
38STATIC BOOLEAN ParseSecondaryGpt;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053039struct StoragePartInfo Ptable[MAX_LUNS];
40struct PartitionEntry PtnEntries[MAX_NUM_PARTITIONS];
41STATIC UINT32 MaxLuns;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053042STATIC UINT32 PartitionCount;
Shivaprasad Hongal340f6872017-04-26 16:15:27 -070043STATIC BOOLEAN FirstBoot;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053044
Vijay Kumar Pendotia7e72a02016-11-11 15:36:56 +053045STATIC struct BootPartsLinkedList *HeadNode;
Shivaprasad Hongalc017e812017-04-26 16:15:27 -070046STATIC EFI_STATUS GetActiveSlot(Slot *ActiveSlot);
Vijay Kumar Pendotia7e72a02016-11-11 15:36:56 +053047
Shivaprasad Hongalc017e812017-04-26 16:15:27 -070048Slot GetCurrentSlotSuffix()
49{
50 Slot CurrentSlot = {{0}};
51 BOOLEAN IsMultiSlot = PartitionHasMultiSlot(L"boot");
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053052
Shivaprasad Hongalc017e812017-04-26 16:15:27 -070053 if (IsMultiSlot == FALSE) {
54 return CurrentSlot;
55 }
lijuanga4c1b082016-12-08 19:12:48 +080056
Shivaprasad Hongalc017e812017-04-26 16:15:27 -070057 GetActiveSlot(&CurrentSlot);
58 return CurrentSlot;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053059}
60
61UINT32 GetMaxLuns() {
62 return MaxLuns;
63}
64
lijuang94109952016-10-28 19:33:55 +080065UINT32 GetPartitionLunFromIndex(UINT32 Index)
Jeevan Shriramab436682016-09-23 07:08:06 -070066{
67 return PtnEntries[Index].lun;
68}
69
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053070VOID GetPartitionCount(UINT32 *Val) {
71 *Val = PartitionCount;
72 return;
73}
74
lijuang94109952016-10-28 19:33:55 +080075INT32 GetPartitionIdxInLun(CHAR16 *Pname, UINT32 Lun)
Jeevan Shriramab436682016-09-23 07:08:06 -070076{
lijuang94109952016-10-28 19:33:55 +080077 UINT32 n;
78 UINT32 RelativeIndex = 0;
Jeevan Shriramab436682016-09-23 07:08:06 -070079
80 for (n = 0; n < PartitionCount; n++) {
81 if (Lun == PtnEntries[n].lun) {
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +053082 if (!StrCmp(Pname, PtnEntries[n].PartEntry.PartitionName))
Jeevan Shriramab436682016-09-23 07:08:06 -070083 return RelativeIndex;
84 RelativeIndex++;
85 }
86 }
87 return INVALID_PTN;
88}
89
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053090VOID UpdatePartitionEntries()
91{
92 UINT32 i;
93 UINT32 j;
94 UINT32 Index = 0;
95 EFI_STATUS Status;
96 EFI_PARTITION_ENTRY *PartEntry;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053097
98 PartitionCount = 0;
99 /*Nullify the PtnEntries array before using it*/
100 SetMem((VOID*) PtnEntries, (sizeof(PtnEntries[0]) * MAX_NUM_PARTITIONS), 0);
101
102 for (i = 0; i < MaxLuns; i++) {
103 for (j = 0; (j < Ptable[i].MaxHandles) && (Index < MAX_NUM_PARTITIONS); j++, Index++) {
104 Status = gBS->HandleProtocol(Ptable[i].HandleInfoList[j].Handle, &gEfiPartitionRecordGuid, (VOID **)&PartEntry);
105 PartitionCount++;
106 if (EFI_ERROR(Status)) {
107 DEBUG((EFI_D_VERBOSE, "Selected Lun : %d, handle: %d does not have partition record, ignore\n", i,j));
Jeevan Shriram0da9d752016-09-28 15:04:27 -0700108 PtnEntries[Index].lun = i;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530109 continue;
110 }
Jeevan Shriram0da9d752016-09-28 15:04:27 -0700111
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530112 CopyMem((&PtnEntries[Index]), PartEntry, sizeof(PartEntry[0]));
113 PtnEntries[Index].lun = i;
114 }
115 }
116}
117
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530118INT32 GetPartitionIndex(CHAR16 *Pname)
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530119{
120 INT32 i;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530121
122 for (i = 0; i < PartitionCount; i++) {
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530123 if (!StrCmp(PtnEntries[i].PartEntry.PartitionName, Pname))
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530124 return i;
125 }
126
127 return INVALID_PTN;
128}
129
lijuang94109952016-10-28 19:33:55 +0800130STATIC EFI_STATUS GetStorageHandle(INT32 Lun, HandleInfo *BlockIoHandle, UINT32 *MaxHandles)
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530131{
132 EFI_STATUS Status = EFI_INVALID_PARAMETER;
133 UINT32 Attribs = 0;
134 PartiSelectFilter HandleFilter;
135 //UFS LUN GUIDs
136 EFI_GUID LunGuids[] = {
137 gEfiUfsLU0Guid,
138 gEfiUfsLU1Guid,
139 gEfiUfsLU2Guid,
140 gEfiUfsLU3Guid,
141 gEfiUfsLU4Guid,
142 gEfiUfsLU5Guid,
143 gEfiUfsLU6Guid,
144 gEfiUfsLU7Guid,
145 };
146
147 Attribs |= BLK_IO_SEL_SELECT_ROOT_DEVICE_ONLY;
148 HandleFilter.PartitionType = 0;
149 HandleFilter.VolumeName = 0;
150
151 if (Lun == NO_LUN) {
152 HandleFilter.RootDeviceType = &gEfiEmmcUserPartitionGuid;
153 Status = GetBlkIOHandles(Attribs, &HandleFilter, BlockIoHandle, MaxHandles);
154 if (EFI_ERROR (Status)) {
155 DEBUG((EFI_D_ERROR, "Error getting block IO handle for Emmc\n"));
156 return Status;
157 }
158 } else {
159 HandleFilter.RootDeviceType = &LunGuids[Lun];
160 Status = GetBlkIOHandles(Attribs, &HandleFilter, BlockIoHandle, MaxHandles);
161 if (EFI_ERROR (Status)) {
162 DEBUG((EFI_D_ERROR, "Error getting block IO handle for Lun:%x\n", Lun));
163 return Status;
164 }
165 }
166
167 return Status;
168}
169
lijuang2120d972016-11-02 18:28:21 +0800170VOID UpdatePartitionAttributes()
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530171{
172 UINT32 BlkSz;
173 UINT8 *GptHdr = NULL;
174 UINT8 *GptHdrPtr = NULL;
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530175 UINTN MaxGptPartEntrySzBytes;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530176 UINT32 Offset;
177 UINT32 MaxPtnCount = 0;
178 UINT32 PtnEntrySz = 0;
179 UINT32 i = 0;
180 UINT8 *PtnEntriesPtr;
181 UINT8 *Ptn_Entries;
182 UINT32 CrcVal = 0;
183 UINT32 Iter;
184 UINT32 HdrSz = GPT_HEADER_SIZE;
185 UINT64 DeviceDensity;
186 UINT64 CardSizeSec;
187 EFI_STATUS Status;
lijuang94109952016-10-28 19:33:55 +0800188 INT32 Lun;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530189 EFI_BLOCK_IO_PROTOCOL *BlockIo=NULL;
190 HandleInfo BlockIoHandle[MAX_HANDLEINF_LST_SIZE];
lijuang94109952016-10-28 19:33:55 +0800191 UINT32 MaxHandles = MAX_HANDLEINF_LST_SIZE;
Vijay Kumar Pendoti5fdbb162017-02-01 20:54:01 +0530192 CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX];
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530193 UINT32 PartEntriesblocks = 0;
Parth Dixit8b9c4bc2017-03-31 22:31:01 +0530194 BOOLEAN SkipUpdation;
195 UINT64 Attr;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530196
Vijay Kumar Pendoti5fdbb162017-02-01 20:54:01 +0530197 GetRootDeviceType(BootDeviceType, BOOT_DEV_NAME_SIZE_MAX);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530198 for( Lun = 0; Lun < MaxLuns; Lun++) {
199
Vijay Kumar Pendoti5fdbb162017-02-01 20:54:01 +0530200 if (!AsciiStrnCmp(BootDeviceType, "EMMC", AsciiStrLen("EMMC"))) {
201 Status = GetStorageHandle(NO_LUN, BlockIoHandle, &MaxHandles);
202 } else if (!AsciiStrnCmp(BootDeviceType, "UFS", AsciiStrLen("UFS"))) {
203 Status = GetStorageHandle(Lun, BlockIoHandle, &MaxHandles);
Vijay Kumar Pendoti25ac2e62017-02-27 18:52:52 +0530204 } else {
205 DEBUG((EFI_D_ERROR, "Unsupported boot device type\n"));
206 return;
Vijay Kumar Pendoti5fdbb162017-02-01 20:54:01 +0530207 }
Jeevan Shriram6a254302017-03-02 11:47:42 -0800208
Vijay Kumar Pendoti5547eab2017-03-16 16:21:23 +0530209 if (Status != EFI_SUCCESS) {
210 DEBUG((EFI_D_ERROR, "Failed to get BlkIo for device. MaxHandles:%d - %r\n", Status));
211 return;
212 }
213 if (MaxHandles != 1) {
Jeevan Shriram6a254302017-03-02 11:47:42 -0800214 DEBUG((EFI_D_VERBOSE, "Failed to get the BlockIo for device. MaxHandle:%d, %r\n",
215 MaxHandles, Status));
216 continue;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530217 }
Jeevan Shriram6a254302017-03-02 11:47:42 -0800218
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530219 BlockIo = BlockIoHandle[0].BlkIo;
220 DeviceDensity = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
221 BlkSz = BlockIo->Media->BlockSize;
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530222 PartEntriesblocks = MAX_PARTITION_ENTRIES_SZ/BlkSz;
223 MaxGptPartEntrySzBytes = (GPT_HDR_BLOCKS + PartEntriesblocks) * BlkSz;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530224 CardSizeSec = (DeviceDensity) / BlkSz;
225 Offset = PRIMARY_HDR_LBA;
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530226 GptHdr = AllocatePool(MaxGptPartEntrySzBytes);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530227 if (!GptHdr) {
228 DEBUG ((EFI_D_ERROR, "Unable to Allocate Memory for GptHdr \n"));
229 return;
230 }
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530231
232 SetMem((VOID *) GptHdr, MaxGptPartEntrySzBytes, 0);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530233 GptHdrPtr = GptHdr;
234
235 /* This loop iterates twice to update both primary and backup Gpt*/
Parth Dixit8b9c4bc2017-03-31 22:31:01 +0530236 for (Iter= 0; Iter < 2; Iter++, (Offset = CardSizeSec - MaxGptPartEntrySzBytes/BlkSz)) {
237 SkipUpdation = TRUE;
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530238 Status = BlockIo->ReadBlocks (BlockIo, BlockIo->Media->MediaId, Offset, MaxGptPartEntrySzBytes, GptHdr);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530239
240 if(EFI_ERROR(Status)) {
241 DEBUG ((EFI_D_ERROR, "Unable to read the media \n"));
242 return;
243 }
244 if(Iter == 0x1) {
245 /* This is the back up GPT */
lijuang2120d972016-11-02 18:28:21 +0800246 Ptn_Entries = GptHdr;
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530247 GptHdr = GptHdr + ((PartEntriesblocks) * BlkSz);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530248 } else
249 /* otherwise we are at the primary gpt */
lijuang2120d972016-11-02 18:28:21 +0800250 Ptn_Entries = GptHdr + BlkSz;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530251
252 PtnEntriesPtr = Ptn_Entries;
253
254 for (i = 0;i < PartitionCount;i++) {
Jeevan Shriram0da9d752016-09-28 15:04:27 -0700255 /*If GUID is not present, then it is BlkIo Handle of the Lun. Skip*/
256 if (!(PtnEntries[i].PartEntry.PartitionTypeGUID.Data1)) {
257 DEBUG((EFI_D_VERBOSE, " Skipping Lun:%d, i=%d\n", Lun, i));
258 continue;
259 }
260
Vijay Kumar Pendoti5fdbb162017-02-01 20:54:01 +0530261 if (!AsciiStrnCmp(BootDeviceType, "UFS", AsciiStrLen("UFS"))) {
262 /* Partition table is populated with entries from lun 0 to max lun.
263 * break out of the loop once we see the partition lun is > current lun */
264 if (PtnEntries[i].lun > Lun)
265 break;
266 /* Find the entry where the partition table for 'lun' starts and then update the attributes */
267 if (PtnEntries[i].lun != Lun)
268 continue;
269 }
Parth Dixit8b9c4bc2017-03-31 22:31:01 +0530270 Attr = GET_LLWORD_FROM_BYTE(&PtnEntriesPtr[ATTRIBUTE_FLAG_OFFSET]);
271 if(Attr != PtnEntries[i].PartEntry.Attributes) {
272 /* Update the partition attributes and partiton GUID values */
273 PUT_LONG_LONG(&PtnEntriesPtr[ATTRIBUTE_FLAG_OFFSET], PtnEntries[i].PartEntry.Attributes);
274 CopyMem((VOID *)PtnEntriesPtr, (VOID *)&PtnEntries[i].PartEntry.PartitionTypeGUID, GUID_SIZE);
275 SkipUpdation = FALSE;
276 }
277
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530278 /* point to the next partition entry */
279 PtnEntriesPtr += PARTITION_ENTRY_SIZE;
280 }
281
Parth Dixit8b9c4bc2017-03-31 22:31:01 +0530282 if(SkipUpdation)
283 continue;
284
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530285 MaxPtnCount = GET_LWORD_FROM_BYTE(&GptHdr[PARTITION_COUNT_OFFSET]);
286 PtnEntrySz = GET_LWORD_FROM_BYTE(&GptHdr[PENTRY_SIZE_OFFSET]);
287
288 Status = gBS->CalculateCrc32(Ptn_Entries, ((MaxPtnCount) * (PtnEntrySz)),&CrcVal);
289 if (Status != EFI_SUCCESS) {
290 DEBUG((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n", Status));
291 return;
292 }
293
294 PUT_LONG(&GptHdr[PARTITION_CRC_OFFSET], CrcVal);
295
296 /*Write CRC to 0 before we calculate the crc of the GPT header*/
297 CrcVal = 0;
298 PUT_LONG(&GptHdr[HEADER_CRC_OFFSET], CrcVal);
299
300 Status = gBS->CalculateCrc32(GptHdr, HdrSz, &CrcVal);
301 if (Status != EFI_SUCCESS) {
302 DEBUG((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n", Status));
303 return;
304 }
305
306 PUT_LONG(&GptHdr[HEADER_CRC_OFFSET], CrcVal);
307
308 if (Iter == 0x1)
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530309 /* Write the backup GPT header, which is at an offset of CardSizeSec - MaxGptPartEntrySzBytes/BlkSz in blocks*/
310 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, Offset, MaxGptPartEntrySzBytes, (VOID *)Ptn_Entries);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530311 else
312 /* Write the primary GPT header, which is at an offset of BlkSz */
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530313 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, Offset, MaxGptPartEntrySzBytes, (VOID *)GptHdr);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530314
315 if (EFI_ERROR(Status)) {
316 DEBUG((EFI_D_ERROR, "Error writing primary GPT header: %r\n", Status));
317 return;
318 }
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530319 }
320 FreePool(GptHdrPtr);
321 }
322}
323
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530324VOID MarkPtnActive(CHAR16 *ActiveSlot)
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530325{
326 UINT32 i;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530327 for (i = 0; i < PartitionCount; i++) {
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530328 /* Mark all the slots with current ActiveSlot as active */
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530329 if (StrStr(PtnEntries[i].PartEntry.PartitionName, ActiveSlot))
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530330 PtnEntries[i].PartEntry.Attributes |= PART_ATT_ACTIVE_VAL;
331 else
332 PtnEntries[i].PartEntry.Attributes &= ~PART_ATT_ACTIVE_VAL;
333 }
334
335 /* Update the partition table */
336 UpdatePartitionAttributes();
337}
338
339STATIC VOID SwapPtnGuid(EFI_PARTITION_ENTRY *p1, EFI_PARTITION_ENTRY *p2)
340{
Channagoud Kadabi0dbf8692016-09-30 16:17:11 -0700341 EFI_GUID Temp;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530342
343 if (p1 == NULL || p2 == NULL)
344 return;
Channagoud Kadabi0dbf8692016-09-30 16:17:11 -0700345 CopyMem((VOID *)&Temp, (VOID *)&p1->PartitionTypeGUID, sizeof(EFI_GUID));
346 CopyMem((VOID *)&p1->PartitionTypeGUID, (VOID *)&p2->PartitionTypeGUID, sizeof(EFI_GUID));
347 CopyMem((VOID *)&p2->PartitionTypeGUID, (VOID *)&Temp, sizeof(EFI_GUID));
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530348}
349
Vijay Kumar Pendotia7e72a02016-11-11 15:36:56 +0530350STATIC EFI_STATUS GetMultiSlotPartsList() {
351 UINT32 i = 0;
352 UINT32 j = 0;
353 UINT32 Len = 0;
354 CHAR16 *SearchString = NULL;
355 struct BootPartsLinkedList *TempNode = NULL;
356
357 for (i = 0; i < PartitionCount; i++) {
358 SearchString = PtnEntries[i].PartEntry.PartitionName;
359 if (!SearchString[0])
360 continue;
361
362 for (j = i+1; j < PartitionCount; j++) {
363 if (!PtnEntries[j].PartEntry.PartitionName[0])
364 continue;
365 Len = StrLen(SearchString);
366
367 /*Need to compare till "boot_"a hence skip last Char from StrLen value*/
368 if (!StrnCmp(PtnEntries[j].PartEntry.PartitionName, SearchString, Len-1) &&
369 (StrStr(SearchString, L"_a") || (StrStr(SearchString, L"_b")))) {
370 TempNode = AllocatePool(sizeof(struct BootPartsLinkedList));
371 if (TempNode) {
372 /*Skip _a/_b from partition name*/
373 StrnCpyS(TempNode->PartName, sizeof(TempNode->PartName), SearchString, Len-2);
374 TempNode->Next = HeadNode;
375 HeadNode = TempNode;
376 } else {
377 DEBUG ((EFI_D_ERROR, "Unable to Allocate Memory for MultiSlot Partition list\n"));
378 return EFI_OUT_OF_RESOURCES;
379 }
380 break;
381 }
382 }
383 }
384 return EFI_SUCCESS;
385}
386
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530387VOID SwitchPtnSlots(CONST CHAR16 *SetActive)
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530388{
Vijay Kumar Pendotia7e72a02016-11-11 15:36:56 +0530389 UINT32 i;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530390 struct PartitionEntry *PtnCurrent = NULL;
391 struct PartitionEntry *PtnNew = NULL;
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530392 CHAR16 CurSlot[BOOT_PART_SIZE];
393 CHAR16 NewSlot[BOOT_PART_SIZE];
394 CHAR16 SetInactive[MAX_SLOT_SUFFIX_SZ];
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530395 UINT32 UfsBootLun = 0;
396 BOOLEAN UfsGet = TRUE;
397 BOOLEAN UfsSet = FALSE;
Vijay Kumar Pendotia7e72a02016-11-11 15:36:56 +0530398 struct BootPartsLinkedList *TempNode = NULL;
399 EFI_STATUS Status;
Vijay Kumar Pendoti177eedc2017-01-20 18:57:03 +0530400 CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX];
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530401
402 /* Create the partition name string for active and non active slots*/
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530403 if (!StrnCmp(SetActive, L"_a", StrLen(L"_a")))
404 StrnCpyS(SetInactive, MAX_SLOT_SUFFIX_SZ, L"_b", StrLen(L"_b"));
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530405 else
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530406 StrnCpyS(SetInactive, MAX_SLOT_SUFFIX_SZ, L"_a", StrLen(L"_a"));
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530407
Vijay Kumar Pendotia7e72a02016-11-11 15:36:56 +0530408 if (!HeadNode) {
409 Status = GetMultiSlotPartsList();
410 if (Status != EFI_SUCCESS) {
411 DEBUG((EFI_D_INFO, "Unable to get GetMultiSlotPartsList\n"));
412 return;
413 }
414 }
415
416 for (TempNode = HeadNode; TempNode; TempNode = TempNode->Next) {
417 StrnCpyS(CurSlot, StrLen(TempNode->PartName) + 1, TempNode->PartName, StrLen(TempNode->PartName));
lijuanga4c1b082016-12-08 19:12:48 +0800418 StrnCatS(CurSlot, BOOT_PART_SIZE - 1, SetInactive, StrLen(SetInactive));
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530419
Vijay Kumar Pendotia7e72a02016-11-11 15:36:56 +0530420 StrnCpyS(NewSlot, StrLen(TempNode->PartName) + 1, TempNode->PartName, StrLen(TempNode->PartName));
lijuanga4c1b082016-12-08 19:12:48 +0800421 StrnCatS(NewSlot, BOOT_PART_SIZE - 1, SetActive, StrLen(SetActive));
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530422
423 /* Find the pointer to partition table entry for active and non-active slots*/
424 for (i = 0; i < PartitionCount; i++) {
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530425 if (!StrnCmp(PtnEntries[i].PartEntry.PartitionName, CurSlot, StrLen(CurSlot))) {
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530426 PtnCurrent = &PtnEntries[i];
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530427 } else if (!StrnCmp(PtnEntries[i].PartEntry.PartitionName, NewSlot, StrLen(NewSlot))) {
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530428 PtnNew = &PtnEntries[i];
429 }
430 }
431 /* Swap the guids for the slots */
432 SwapPtnGuid(&PtnCurrent->PartEntry, &PtnNew->PartEntry);
433 SetMem(CurSlot, BOOT_PART_SIZE, 0);
434 SetMem(NewSlot, BOOT_PART_SIZE, 0);
435 PtnCurrent = PtnNew = NULL;
436 }
Vijay Kumar Pendoti177eedc2017-01-20 18:57:03 +0530437
438 GetRootDeviceType(BootDeviceType, BOOT_DEV_NAME_SIZE_MAX);
439 if (!AsciiStrnCmp(BootDeviceType, "UFS", AsciiStrLen("UFS"))) {
440 UfsGetSetBootLun(&UfsBootLun, UfsGet);
441 // Special case for XBL is to change the bootlun instead of swapping the guid
442 if (UfsBootLun == 0x1 && !StrnCmp(SetActive, L"_b", StrLen(L"_b"))) {
443 DEBUG((EFI_D_INFO, "Switching the boot lun from 1 to 2\n"));
444 UfsBootLun = 0x2;
445 }
446 else if (UfsBootLun == 0x2 && !StrnCmp(SetActive, L"_a", StrLen(L"_a"))) {
447 DEBUG((EFI_D_INFO, "Switching the boot lun from 2 to 1\n"));
448 UfsBootLun = 0x1;
449 }
450 UfsGetSetBootLun(&UfsBootLun, UfsSet);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530451 }
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530452}
453
454EFI_STATUS
455EnumeratePartitions ()
456{
457 EFI_STATUS Status;
458 PartiSelectFilter HandleFilter;
459 UINT32 Attribs = 0;
460 UINT32 i;
461 INT32 Lun = NO_LUN;
462 //UFS LUN GUIDs
463 EFI_GUID LunGuids[] = {
464 gEfiUfsLU0Guid,
465 gEfiUfsLU1Guid,
466 gEfiUfsLU2Guid,
467 gEfiUfsLU3Guid,
468 gEfiUfsLU4Guid,
469 gEfiUfsLU5Guid,
470 gEfiUfsLU6Guid,
471 gEfiUfsLU7Guid,
472 };
473
474 SetMem((VOID*) Ptable, (sizeof(struct StoragePartInfo) * MAX_LUNS), 0);
475
476 /* By default look for emmc partitions if not found look for UFS */
477 Attribs |= BLK_IO_SEL_MATCH_ROOT_DEVICE;
478
479 Ptable[0].MaxHandles = ARRAY_SIZE(Ptable[0].HandleInfoList);
480 HandleFilter.PartitionType = 0;
481 HandleFilter.VolumeName = 0;
482 HandleFilter.RootDeviceType = &gEfiEmmcUserPartitionGuid;
483
484 Status = GetBlkIOHandles(Attribs, &HandleFilter, &Ptable[0].HandleInfoList[0], &Ptable[0].MaxHandles);
485 /* For Emmc devices the Lun concept does not exist, we will always one lun and the lun number is '0'
486 * to have the partition selection implementation same acros
487 */
488 if (Status == EFI_SUCCESS && Ptable[0].MaxHandles > 0) {
489 Lun = 0;
490 MaxLuns = 1;
491 }
492 /* If the media is not emmc then look for UFS */
493 else if (EFI_ERROR (Status) || Ptable[0].MaxHandles == 0) {
494 /* By default max 8 luns are supported but HW could be configured to use only few of them or all of them
495 * Based on the information read update the MaxLuns to reflect the max supported luns */
496 for (i = 0 ; i < MAX_LUNS; i++) {
497 Ptable[i].MaxHandles = ARRAY_SIZE(Ptable[i].HandleInfoList);
498 HandleFilter.PartitionType = 0;
499 HandleFilter.VolumeName = 0;
500 HandleFilter.RootDeviceType = &LunGuids[i];
501
502 Status = GetBlkIOHandles(Attribs, &HandleFilter, &Ptable[i].HandleInfoList[0], &Ptable[i].MaxHandles);
503 /* If we fail to get block for a lun that means the lun is not configured and unsed, ignore the error
504 * and continue with the next Lun */
505 if (EFI_ERROR (Status)) {
506 DEBUG((EFI_D_ERROR, "Error getting block IO handle for %d lun, Lun may be unused\n", i));
507 continue;
508 }
509 }
510 MaxLuns = i;
511 } else {
512 DEBUG((EFI_D_ERROR, "Error populating block IO handles\n"));
513 return EFI_NOT_FOUND;
514 }
515
516 return Status;
517}
518
519/*Function to provide has-slot info
520 *Pname: the partition name
521 *return: 1 or 0.
522 */
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530523BOOLEAN PartitionHasMultiSlot(CONST CHAR16 *Pname)
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530524{
525 UINT32 i;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530526 UINT32 SlotCount = 0;
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530527 UINT32 Len = StrLen(Pname);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530528
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530529 for (i = 0; i < PartitionCount; i++) {
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530530 if(!(StrnCmp(PtnEntries[i].PartEntry.PartitionName, Pname, Len))) {
531 if (PtnEntries[i].PartEntry.PartitionName[Len] == L'_' &&
532 (PtnEntries[i].PartEntry.PartitionName[Len+1] == L'a' ||
533 PtnEntries[i].PartEntry.PartitionName[Len+1] == L'b'))
Vijay Kumar Pendotia38f5742017-01-17 20:05:10 +0530534 if (++SlotCount > MIN_SLOTS) {
535 return TRUE;
536 }
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530537 }
538 }
Vijay Kumar Pendotia38f5742017-01-17 20:05:10 +0530539 return FALSE;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530540}
541
542VOID FindPtnActiveSlot()
543{
Shivaprasad Hongalc017e812017-04-26 16:15:27 -0700544 Slot ActiveSlot = {{0}};
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530545
Shivaprasad Hongalc017e812017-04-26 16:15:27 -0700546 GetActiveSlot(&ActiveSlot);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530547 return;
548}
549
lijuang94109952016-10-28 19:33:55 +0800550STATIC UINT32 PartitionVerifyMbrSignature(UINT32 Sz, UINT8 *Gpt)
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800551{
552 if ((MBR_SIGNATURE + 1) > Sz)
553 {
554 DEBUG((EFI_D_ERROR, "Gpt Image size is invalid\n"));
555 return FAILURE;
556 }
557
558 /* Check for the signature */
559 if ((Gpt[MBR_SIGNATURE] != MBR_SIGNATURE_BYTE_0) ||
560 (Gpt[MBR_SIGNATURE + 1] != MBR_SIGNATURE_BYTE_1))
561 {
562 DEBUG((EFI_D_ERROR, "MBR signature do not match\n"));
563 return FAILURE;
564 }
565 return SUCCESS;
566}
567
lijuang94109952016-10-28 19:33:55 +0800568STATIC UINT32 MbrGetPartitionType(UINT32 Sz, UINT8 *Gpt, UINT32 *Ptype)
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800569{
570 UINT32 PtypeOffset = MBR_PARTITION_RECORD + OS_TYPE;
571
572 if (Sz < (PtypeOffset + sizeof(*Ptype)))
573 {
574 DEBUG((EFI_D_ERROR, "Input gpt image does not have gpt partition record data\n"));
575 return FAILURE;
576 }
577
578 *Ptype = Gpt[PtypeOffset];
579
580 return SUCCESS;
581}
582
lijuang94109952016-10-28 19:33:55 +0800583STATIC UINT32 PartitionGetType(UINT32 Sz, UINT8 *Gpt, UINT32 *Ptype)
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800584{
lijuang94109952016-10-28 19:33:55 +0800585 UINT32 Ret;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800586
587 Ret = PartitionVerifyMbrSignature(Sz, Gpt);
588 if (!Ret)
589 {
590 /* MBR signature match, this coulb be MBR, MBR + EBR or GPT */
591 Ret = MbrGetPartitionType(Sz, Gpt, Ptype);
592 if (!Ret)
593 {
594 if (*Ptype == GPT_PROTECTIVE)
595 *Ptype = PARTITION_TYPE_GPT;
596 else
597 *Ptype = PARTITION_TYPE_MBR;
598 }
599 }
600 else
601 {
602 /* This could be GPT back up */
603 *Ptype = PARTITION_TYPE_GPT_BACKUP;
604 Ret = SUCCESS;
605 }
606
607 return Ret;
608}
609
lijuang94109952016-10-28 19:33:55 +0800610STATIC UINT32 ParseGptHeader(struct GptHeaderData *GptHeader, UINT8 *GptBuffer, UINT64 DeviceDensity, UINT32 BlkSz)
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800611{
612 UINT32 CrcOrig;
613 UINT32 CrcVal;
614 UINT32 CurrentLba;
615 EFI_STATUS Status;
616
617 if (((UINT32 *) GptBuffer)[0] != GPT_SIGNATURE_2 || ((UINT32 *) GptBuffer)[1] != GPT_SIGNATURE_1)
618 {
619 DEBUG((EFI_D_ERROR, "Gpt signature is not correct\n"));
620 return FAILURE;
621 }
622
623 GptHeader->HeaderSz = GET_LWORD_FROM_BYTE(&GptBuffer[HEADER_SIZE_OFFSET]);
624 /* Validate the header size */
625 if (GptHeader->HeaderSz < GPT_HEADER_SIZE)
626 {
627 DEBUG((EFI_D_ERROR, "GPT Header size is too small: %u\n", GptHeader->HeaderSz));
628 return FAILURE;
629 }
630
631 if (GptHeader->HeaderSz > BlkSz)
632 {
633 DEBUG((EFI_D_ERROR, "GPT Header is too large: %u\n", GptHeader->HeaderSz));
634 return FAILURE;
635 }
636
637 CrcOrig = GET_LWORD_FROM_BYTE(&GptBuffer[HEADER_CRC_OFFSET]);
638 /* CRC value is computed by setting this field to 0, and computing the 32-bit CRC for HeaderSize bytes */
639 CrcVal = 0;
640 PUT_LONG(&GptBuffer[HEADER_CRC_OFFSET], CrcVal);
641
642 Status = gBS->CalculateCrc32(GptBuffer, GptHeader->HeaderSz, &CrcVal);
643 if (Status != EFI_SUCCESS)
644 {
645 DEBUG((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n", Status));
646 return FAILURE;
647 }
648
649 if (CrcVal != CrcOrig)
650 {
651 DEBUG((EFI_D_ERROR, "Header CRC mismatch CrcVal = %u and CrcOrig = %u\n", CrcVal, CrcOrig));
652 return FAILURE;
653 }
654 else
655 PUT_LONG(&GptBuffer[HEADER_CRC_OFFSET], CrcVal);
656
657 CurrentLba = GET_LLWORD_FROM_BYTE(&GptBuffer[PRIMARY_HEADER_OFFSET]);
658 GptHeader->FirstUsableLba = GET_LLWORD_FROM_BYTE(&GptBuffer[FIRST_USABLE_LBA_OFFSET]);
659 GptHeader->MaxPtCnt = GET_LWORD_FROM_BYTE(&GptBuffer[PARTITION_COUNT_OFFSET]);
660 GptHeader->PartEntrySz = GET_LWORD_FROM_BYTE(&GptBuffer[PENTRY_SIZE_OFFSET]);
661 GptHeader->LastUsableLba = GET_LLWORD_FROM_BYTE(&GptBuffer[LAST_USABLE_LBA_OFFSET]);
662 if (!ParseSecondaryGpt)
663 {
664 if (CurrentLba != GPT_LBA)
665 {
666 DEBUG((EFI_D_ERROR, "GPT first usable LBA mismatch\n"));
667 return FAILURE;
668 }
669 }
670
671 /* Check for first lba should be within valid range */
672 if (GptHeader->FirstUsableLba > (DeviceDensity / BlkSz))
673 {
674 DEBUG((EFI_D_ERROR, "FirstUsableLba: %u out of Device capacity\n", GptHeader->FirstUsableLba));
675 return FAILURE;
676 }
677
678 /* Check for Last lba should be within valid range */
679 if (GptHeader->LastUsableLba > (DeviceDensity / BlkSz))
680 {
681 DEBUG((EFI_D_ERROR, "LastUsableLba: %u out of device capacity\n", GptHeader->LastUsableLba));
682 return FAILURE;
683 }
684
685 if (GptHeader->PartEntrySz != GPT_PART_ENTRY_SIZE)
686 {
687 DEBUG((EFI_D_ERROR, "Invalid partition entry size: %u\n", GptHeader->PartEntrySz));
688 return FAILURE;
689 }
690
691 if (GptHeader->MaxPtCnt > (MIN_PARTITION_ARRAY_SIZE / (GptHeader->PartEntrySz)))
692 {
693 DEBUG((EFI_D_ERROR, "Invalid Max Partition Count: %u\n", GptHeader->MaxPtCnt));
694 return FAILURE;
695 }
696
697 /* Todo: Check CRC during reading partition table*/
698 if (!FlashingGpt)
699 {
700 }
701
702 return SUCCESS;
703}
704
lijuang94109952016-10-28 19:33:55 +0800705STATIC UINT32 PatchGpt (
706 UINT8 *Gpt, UINT64 DeviceDensity, UINT32 PartEntryArrSz,
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800707 struct GptHeaderData *GptHeader, UINT32 BlkSz)
708{
709 UINT8 *PrimaryGptHeader;
710 UINT8 *SecondaryGptHeader;
lijuang94109952016-10-28 19:33:55 +0800711 UINT64 NumSectors;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800712 UINT32 Offset;
713 UINT32 TotalPart = 0;
714 UINT32 LastPartOffset;
715 UINT8 *PartitionEntryArrStart;
716 UINT32 CrcVal;
717 EFI_STATUS Status;
718
719 NumSectors = DeviceDensity / BlkSz;
720
721 /* Update the primary and backup GPT header offset with the sector location */
722 PrimaryGptHeader = (Gpt + BlkSz);
723 /* Patch primary GPT */
724 PUT_LONG_LONG(PrimaryGptHeader + BACKUP_HEADER_OFFSET, (UINTN) (NumSectors - 1));
725 PUT_LONG_LONG(PrimaryGptHeader + LAST_USABLE_LBA_OFFSET, (UINTN) (NumSectors - 34));
726
727 /* Patch Backup GPT */
728 Offset = (2 * PartEntryArrSz);
729 SecondaryGptHeader = Offset + BlkSz + PrimaryGptHeader;
730 PUT_LONG_LONG(SecondaryGptHeader + PRIMARY_HEADER_OFFSET, (UINTN)1);
731 PUT_LONG_LONG(SecondaryGptHeader + LAST_USABLE_LBA_OFFSET, (UINTN) (NumSectors - 34));
732 PUT_LONG_LONG(SecondaryGptHeader + PARTITION_ENTRIES_OFFSET, (UINTN) (NumSectors - 33));
733
734 /* Patch the last partition */
735 while (*(PrimaryGptHeader + BlkSz + TotalPart * PARTITION_ENTRY_SIZE) != 0)
736 TotalPart++;
737
738 LastPartOffset = (TotalPart - 1) * PARTITION_ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA;
739
740 PUT_LONG_LONG(PrimaryGptHeader + BlkSz + LastPartOffset, (UINTN) (NumSectors - 34));
741 PUT_LONG_LONG(PrimaryGptHeader + BlkSz + LastPartOffset + PartEntryArrSz, (UINTN) (NumSectors - 34));
742
743 /* Update CRC of the partition entry array for both headers */
744 PartitionEntryArrStart = PrimaryGptHeader + BlkSz;
745 Status = gBS->CalculateCrc32(PartitionEntryArrStart, (GptHeader->MaxPtCnt * GptHeader->PartEntrySz), &CrcVal);
746 if (EFI_ERROR(Status))
747 {
748 DEBUG((EFI_D_ERROR, "Error calculating CRC for primary partition entry\n"));
749 return FAILURE;
750 }
751 PUT_LONG(PrimaryGptHeader + PARTITION_CRC_OFFSET, CrcVal);
752
753 Status = gBS->CalculateCrc32(PartitionEntryArrStart + PartEntryArrSz, (GptHeader->MaxPtCnt * GptHeader->PartEntrySz), &CrcVal);
754 if (EFI_ERROR(Status))
755 {
756 DEBUG((EFI_D_ERROR, "Error calculating CRC for secondary partition entry\n"));
757 return FAILURE;
758 }
759 PUT_LONG(SecondaryGptHeader + PARTITION_CRC_OFFSET, CrcVal);
760
761 /* Clear Header CRC field values & recalculate */
762 PUT_LONG(PrimaryGptHeader + HEADER_CRC_OFFSET, 0);
763 Status = gBS->CalculateCrc32(PrimaryGptHeader, GPT_HEADER_SIZE, &CrcVal);
764 if (EFI_ERROR(Status))
765 {
766 DEBUG((EFI_D_ERROR, "Error calculating CRC for primary gpt header\n"));
767 return FAILURE;
768 }
769 PUT_LONG(PrimaryGptHeader + HEADER_CRC_OFFSET, CrcVal);
770 PUT_LONG(SecondaryGptHeader + HEADER_CRC_OFFSET, 0);
771 Status = gBS->CalculateCrc32(SecondaryGptHeader, GPT_HEADER_SIZE, &CrcVal);
772 if (EFI_ERROR(Status))
773 {
774 DEBUG((EFI_D_ERROR, "Error calculating CRC for secondary gpt header\n"));
775 return FAILURE;
776 }
777 PUT_LONG(SecondaryGptHeader + HEADER_CRC_OFFSET, CrcVal);
778
779 return SUCCESS;
780}
781
lijuang94109952016-10-28 19:33:55 +0800782STATIC UINT32 WriteGpt(INT32 Lun, UINT32 Sz, UINT8 *Gpt)
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800783{
lijuang94109952016-10-28 19:33:55 +0800784 UINT32 Ret = 1;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800785 struct GptHeaderData GptHeader;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800786 UINT8 *PartEntryArrSt;
787 UINT32 Offset;
788 UINT32 PartEntryArrSz;
lijuang94109952016-10-28 19:33:55 +0800789 UINT64 DeviceDensity;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800790 UINT32 BlkSz;
791 UINT8 *PrimaryGptHdr = NULL;
792 UINT8 *SecondaryGptHdr = NULL;
793 EFI_STATUS Status;
794 UINTN BackUpGptLba;
795 UINTN PartitionEntryLba;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800796 EFI_BLOCK_IO_PROTOCOL *BlockIo = NULL;
797 HandleInfo BlockIoHandle[MAX_HANDLEINF_LST_SIZE];
lijuang94109952016-10-28 19:33:55 +0800798 UINT32 MaxHandles = MAX_HANDLEINF_LST_SIZE;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800799
800 Ret = GetStorageHandle(Lun, BlockIoHandle, &MaxHandles);
801 if (Ret || (MaxHandles != 1))
802 {
803 DEBUG((EFI_D_ERROR, "Failed to get the BlockIo for the device\n"));
804 return Ret;
805 }
806
807 BlockIo = BlockIoHandle[0].BlkIo;
808 DeviceDensity = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
809 BlkSz = BlockIo->Media->BlockSize;
810
811 /* Verity that passed block has valid GPT primary header */
812 PrimaryGptHdr = (Gpt + BlkSz);
813 Ret = ParseGptHeader(&GptHeader, PrimaryGptHdr, DeviceDensity, BlkSz);
814 if (Ret)
815 {
816 DEBUG((EFI_D_ERROR, "GPT: Error processing primary GPT header\n"));
817 return Ret;
818 }
819
820 /* Check if a valid back up GPT is present */
821 PartEntryArrSz = GptHeader.PartEntrySz * GptHeader.MaxPtCnt;
822 if (PartEntryArrSz < MIN_PARTITION_ARRAY_SIZE)
823 PartEntryArrSz = MIN_PARTITION_ARRAY_SIZE;
824
825 /* Back up partition is stored in the reverse order with back GPT, followed by
826 * part entries, find the offset to back up GPT */
827 Offset = (2 * PartEntryArrSz);
828 SecondaryGptHdr = Offset + BlkSz + PrimaryGptHdr;
829 ParseSecondaryGpt = TRUE;
830
831 Ret = ParseGptHeader(&GptHeader, SecondaryGptHdr, DeviceDensity, BlkSz);
832 if (Ret)
833 {
834 DEBUG((EFI_D_ERROR, "GPT: Error processing backup GPT header\n"));
835 return Ret;
836 }
837
838 Ret = PatchGpt(Gpt, DeviceDensity, PartEntryArrSz, &GptHeader, BlkSz);
839 if (Ret)
840 {
841 DEBUG((EFI_D_ERROR, "Failed to patch GPT\n"));
842 return Ret;
843 }
844 /* Erase the entire card */
Channagoud Kadabid4c9c392016-10-17 23:42:16 -0700845 Status = ErasePartition(BlockIo, BlockIoHandle[0].Handle);
846 if (Status != EFI_SUCCESS) {
847 DEBUG((EFI_D_ERROR, "Error erasing the storage device: %r\n", Status));
848 return FAILURE;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800849 }
850
851 /* write the protective MBR */
852 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, 0, BlkSz, (VOID *)Gpt);
853 if (EFI_ERROR(Status))
854 {
855 DEBUG((EFI_D_ERROR, "Error writing protective MBR: %x\n", Status));
856 return FAILURE;
857 }
858
859 /* Write the primary GPT header, which is at an offset of BlkSz */
860 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, 1, BlkSz, (VOID *)PrimaryGptHdr);
861 if (EFI_ERROR(Status))
862 {
863 DEBUG((EFI_D_ERROR, "Error writing primary GPT header: %r\n", Status));
864 return FAILURE;
865 }
866
867 /* Write the back up GPT header */
868 BackUpGptLba = GET_LLWORD_FROM_BYTE(&PrimaryGptHdr[BACKUP_HEADER_OFFSET]);
869 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, BackUpGptLba, BlkSz, (VOID *)SecondaryGptHdr);
870 if (EFI_ERROR(Status))
871 {
872 DEBUG((EFI_D_ERROR, "Error writing secondary GPT header: %x\n", Status));
873 return FAILURE;
874 }
875
876 /* write Partition Entries for primary partition table*/
877 PartEntryArrSt = PrimaryGptHdr + BlkSz;
878 PartitionEntryLba = GET_LLWORD_FROM_BYTE(&PrimaryGptHdr[PARTITION_ENTRIES_OFFSET]);
879 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, PartitionEntryLba, PartEntryArrSz, (VOID *)PartEntryArrSt);
880 if (EFI_ERROR(Status))
881 {
882 DEBUG((EFI_D_ERROR, "Error writing partition entries array for Primary Table: %x\n", Status));
883 return FAILURE;
884 }
885
886 /* write Partition Entries for secondary partition table*/
887 PartEntryArrSt = PrimaryGptHdr + BlkSz + PartEntryArrSz;
888 PartitionEntryLba = GET_LLWORD_FROM_BYTE(&SecondaryGptHdr[PARTITION_ENTRIES_OFFSET]);
889 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, PartitionEntryLba, PartEntryArrSz, (VOID *)PartEntryArrSt);
890 if (EFI_ERROR(Status))
891 {
892 DEBUG((EFI_D_ERROR, "Error writing partition entries array for Secondary Table: %x\n", Status));
893 return FAILURE;
894 }
895 FlashingGpt = 0;
Runmin Wang2a194612016-07-25 14:15:34 -0700896 SetMem((VOID *)PrimaryGptHdr, Sz, 0x0);
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800897
898 DEBUG((EFI_D_ERROR, "Updated Partition Table Successfully\n"));
899 return SUCCESS;
900}
901
lijuang94109952016-10-28 19:33:55 +0800902EFI_STATUS UpdatePartitionTable(UINT8 *GptImage, UINT32 Sz, INT32 Lun, struct StoragePartInfo *Ptable)
Channagoud Kadabif8aa7632015-11-12 14:27:01 -0800903{
904 EFI_STATUS Status = EFI_SUCCESS;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800905 UINT32 Ptype;
lijuang94109952016-10-28 19:33:55 +0800906 UINT32 Ret;
Channagoud Kadabif8aa7632015-11-12 14:27:01 -0800907
908 /* Check if the partition type is GPT */
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800909 Ret = PartitionGetType(Sz, GptImage, &Ptype);
910 if (Ret != 0)
911 {
912 DEBUG((EFI_D_ERROR, "Failed to get partition type from input gpt image\n"));
913 return EFI_NOT_FOUND;
914 }
915
916 switch (Ptype)
917 {
918 case PARTITION_TYPE_GPT:
919 DEBUG((EFI_D_INFO, "Updating GPT partition\n"));
920 FlashingGpt = TRUE;
921 Ret = WriteGpt(Lun, Sz, GptImage);
922 if (Ret != 0)
923 {
924 DEBUG((EFI_D_ERROR, "Failed to write Gpt partition: %x\n", Ret));
925 return EFI_VOLUME_CORRUPTED;
926 }
927 break;
928 default:
929 DEBUG((EFI_D_ERROR, "Invalid Partition type: %x\n",Ptype));
930 Status = EFI_UNSUPPORTED;
931 break;
932 }
933
Channagoud Kadabif8aa7632015-11-12 14:27:01 -0800934 return Status;
935}
Shivaprasad Hongale3b53392017-04-27 17:32:47 -0700936
Shivaprasad Hongalc017e812017-04-26 16:15:27 -0700937STATIC CONST struct PartitionEntry *GetPartitionEntry(CHAR16 *Partition)
938{
939 INT32 Index = GetPartitionIndex(Partition);
940
941 if (Index == INVALID_PTN) {
942 DEBUG((EFI_D_ERROR, "GetPartitionEntry: No partition entry for "
943 "%s, invalid index\n",
944 Partition));
945 return NULL;
946 }
947 return &PtnEntries[Index];
Shivaprasad Hongale3b53392017-04-27 17:32:47 -0700948}
Shivaprasad Hongalc017e812017-04-26 16:15:27 -0700949
950STATIC struct PartitionEntry *GetBootPartitionEntry(Slot *BootSlot)
951{
952 INT32 Index = INVALID_PTN;
953
954 if (StrnCmp(L"_a", BootSlot->Suffix, StrLen(BootSlot->Suffix)) == 0) {
955 Index = GetPartitionIndex(L"boot_a");
956 } else if (StrnCmp(L"_b", BootSlot->Suffix, StrLen(BootSlot->Suffix)) == 0) {
957 Index = GetPartitionIndex(L"boot_b");
958 } else {
959 DEBUG((EFI_D_ERROR, "GetBootPartitionEntry: No boot partition "
960 "entry for slot %s\n",
961 BootSlot->Suffix));
962 return NULL;
963 }
964
965 if (Index == INVALID_PTN) {
966 DEBUG((EFI_D_ERROR,
967 "GetBootPartitionEntry: No boot partition entry "
968 "for slot %s, invalid index\n",
969 BootSlot->Suffix));
970 return NULL;
971 }
972 return &PtnEntries[Index];
973}
974
975BOOLEAN IsCurrentSlotBootable()
976{
977 Slot CurrentSlot = {{0}};
978 struct PartitionEntry *BootPartition = NULL;
979 EFI_STATUS Status = GetActiveSlot(&CurrentSlot);
980
981 if (Status != EFI_SUCCESS) {
982 DEBUG((EFI_D_ERROR,
983 "IsCurrentSlotBootable: no active slots found!\n"));
984 return FALSE;
985 }
986
987 BootPartition = GetBootPartitionEntry(&CurrentSlot);
988 if (BootPartition == NULL) {
989 DEBUG((EFI_D_ERROR, "IsCurrentSlotBootable: No boot partition "
990 "entry for slot %s\n",
991 CurrentSlot.Suffix));
992 return FALSE;
993 }
994 DEBUG((EFI_D_VERBOSE, "Slot suffix %s Part Attr 0x%lx\n",
995 CurrentSlot.Suffix, BootPartition->PartEntry.Attributes));
996
997 if (!(BootPartition->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) &&
998 BootPartition->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) {
999 DEBUG((EFI_D_VERBOSE, "Slot %s is bootable\n", CurrentSlot.Suffix));
1000 return TRUE;
1001 }
1002
1003 DEBUG((EFI_D_VERBOSE, "Slot %s is unbootable \n", CurrentSlot.Suffix));
1004 return FALSE;
1005}
1006
1007BOOLEAN IsSuffixEmpty(Slot *CheckSlot)
1008{
1009 if (CheckSlot == NULL) {
1010 return TRUE;
1011 }
1012
1013 if (StrLen(CheckSlot->Suffix) == 0) {
1014 return TRUE;
1015 }
1016 return FALSE;
1017}
1018
1019STATIC EFI_STATUS GetActiveSlot(Slot *ActiveSlot)
1020{
1021 EFI_STATUS Status = EFI_SUCCESS;
1022 Slot Slots[] = {{L"_a"}, {L"_b"}};
1023 UINT64 Priority = 0;
1024
1025 if (ActiveSlot == NULL) {
1026 DEBUG((EFI_D_ERROR, "GetActiveSlot: bad parameter\n"));
1027 return EFI_INVALID_PARAMETER;
1028 }
1029
1030 for (UINTN SlotIndex = 0; SlotIndex < ARRAY_SIZE(Slots); SlotIndex++) {
1031 struct PartitionEntry *BootPartition =
1032 GetBootPartitionEntry(&Slots[SlotIndex]);
1033 UINT64 BootPriority = 0;
1034 if (BootPartition == NULL) {
1035 DEBUG((EFI_D_ERROR, "GetActiveSlot: No boot partition "
1036 "entry for slot %s\n",
1037 Slots[SlotIndex].Suffix));
1038 return EFI_NOT_FOUND;
1039 }
1040
1041 BootPriority = (BootPartition->PartEntry.Attributes &
1042 PART_ATT_PRIORITY_VAL) >>
1043 PART_ATT_PRIORITY_BIT;
1044
1045 if ((BootPartition->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) &&
1046 (BootPriority > Priority)) {
1047 GUARD(StrnCpyS(ActiveSlot->Suffix, ARRAY_SIZE(ActiveSlot->Suffix),
1048 Slots[SlotIndex].Suffix,
1049 StrLen(Slots[SlotIndex].Suffix)));
1050 Priority = BootPriority;
1051 }
1052 }
1053
1054 DEBUG((EFI_D_VERBOSE, "GetActiveSlot: found active slot %s, priority %d\n",
1055 ActiveSlot->Suffix, Priority));
1056
1057 if (IsSuffixEmpty(ActiveSlot) == TRUE) {
1058 /* Check for first boot and set default slot */
1059 /* For First boot all A/B attributes for the slot would be 0 */
1060 UINT64 BootPriority = 0;
1061 UINT64 RetryCount = 0;
1062 struct PartitionEntry *SlotA = GetBootPartitionEntry(&Slots[0]);
1063 if (SlotA == NULL) {
1064 DEBUG((EFI_D_ERROR,
1065 "GetActiveSlot: First Boot: No boot partition "
1066 "entry for slot %s\n",
1067 Slots[0].Suffix));
1068 return EFI_NOT_FOUND;
1069 }
1070
1071 BootPriority =
1072 (SlotA->PartEntry.Attributes & PART_ATT_PRIORITY_VAL) >>
1073 PART_ATT_PRIORITY_BIT;
1074 RetryCount = (SlotA->PartEntry.Attributes &
1075 PART_ATT_MAX_RETRY_COUNT_VAL) >>
1076 PART_ATT_MAX_RETRY_CNT_BIT;
1077
1078 if ((SlotA->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) == 0 &&
1079 (SlotA->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) == 0 &&
1080 (SlotA->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) == 0 &&
1081 BootPriority == 0) {
1082
1083 DEBUG((EFI_D_INFO, "GetActiveSlot: First boot: set "
1084 "default slot _a\n"));
1085 SlotA->PartEntry.Attributes &=
1086 (~PART_ATT_SUCCESSFUL_VAL & ~PART_ATT_UNBOOTABLE_VAL);
1087 SlotA->PartEntry.Attributes |=
1088 (PART_ATT_PRIORITY_VAL | PART_ATT_ACTIVE_VAL |
1089 PART_ATT_MAX_RETRY_COUNT_VAL);
1090
1091 GUARD(StrnCpyS(ActiveSlot->Suffix, ARRAY_SIZE(ActiveSlot->Suffix),
1092 Slots[0].Suffix, StrLen(Slots[0].Suffix)));
1093 UpdatePartitionAttributes();
Shivaprasad Hongal340f6872017-04-26 16:15:27 -07001094 FirstBoot = TRUE;
Shivaprasad Hongalc017e812017-04-26 16:15:27 -07001095 return EFI_SUCCESS;
1096 }
1097
1098 DEBUG((EFI_D_ERROR, "GetActiveSlot: No active slot found\n"));
1099 DEBUG((EFI_D_ERROR,
1100 "GetActiveSlot: Slot attr: Priority %ld, Retry "
1101 "%ld, Active %ld, Success %ld, unboot %ld\n",
1102 BootPriority, RetryCount,
1103 (SlotA->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) >> PART_ATT_ACTIVE_BIT,
1104 (SlotA->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL),
1105 (SlotA->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL)));
1106
1107 return EFI_NOT_FOUND;
1108 }
1109
1110 return EFI_SUCCESS;
1111}
1112
1113EFI_STATUS SetActiveSlot(Slot *NewSlot)
1114{
1115 EFI_STATUS Status = EFI_SUCCESS;
1116 Slot CurrentSlot = {{0}};
1117 struct PartitionEntry *BootEntry = NULL;
1118
1119 if (NewSlot == NULL) {
1120 DEBUG((EFI_D_ERROR,
1121 "SetActiveSlot: input parameter invalid\n"));
1122 return EFI_INVALID_PARAMETER;
1123 }
1124
1125 GUARD(GetActiveSlot(&CurrentSlot));
1126
1127 if (StrnCmp(CurrentSlot.Suffix, NewSlot->Suffix,
1128 StrLen(CurrentSlot.Suffix)) == 0) {
1129 /* This Slot is already active do nothing */
1130 DEBUG((EFI_D_INFO, "SetActiveSlot: %s already active slot\n",
1131 NewSlot->Suffix));
1132 return EFI_SUCCESS;
1133 }
1134
1135 BootEntry = GetBootPartitionEntry(NewSlot);
1136 if (BootEntry == NULL) {
1137 DEBUG((EFI_D_ERROR,
1138 "SetActiveSlot: No boot partition entry for slot %s\n",
1139 NewSlot->Suffix));
1140 return EFI_NOT_FOUND;
1141 }
1142
1143 BootEntry->PartEntry.Attributes |= (PART_ATT_PRIORITY_VAL | PART_ATT_ACTIVE_VAL |
1144 PART_ATT_MAX_RETRY_COUNT_VAL);
1145 BootEntry->PartEntry.Attributes &=
1146 (~PART_ATT_SUCCESSFUL_VAL & ~PART_ATT_UNBOOTABLE_VAL);
1147
1148 /* Reduce the priority and clear the active flag for inactive slot*/
1149 BootEntry = GetBootPartitionEntry(&CurrentSlot);
1150 if (BootEntry == NULL) {
1151 DEBUG((EFI_D_ERROR,
1152 "SetActiveSlot: No boot partition entry for slot %s\n",
1153 CurrentSlot.Suffix));
1154 return EFI_NOT_FOUND;
1155 }
1156
1157 BootEntry->PartEntry.Attributes &=
1158 (~PART_ATT_PRIORITY_VAL & ~PART_ATT_ACTIVE_VAL);
1159 BootEntry->PartEntry.Attributes |=
1160 (((UINT64)MAX_PRIORITY - 1) << PART_ATT_PRIORITY_BIT);
1161
1162 DEBUG((EFI_D_INFO, "Current slot %s, New slot %s\n", CurrentSlot.Suffix,
1163 NewSlot->Suffix));
1164
1165 SwitchPtnSlots(NewSlot->Suffix);
1166 UpdatePartitionAttributes();
1167
1168 return EFI_SUCCESS;
1169}
1170
1171EFI_STATUS HandleActiveSlotUnbootable()
1172{
1173 EFI_STATUS Status = EFI_SUCCESS;
1174 struct PartitionEntry *BootEntry = NULL;
1175 Slot ActiveSlot = {{0}};
1176 Slot *AlternateSlot = NULL;
1177 Slot Slots[] = {{L"_a"}, {L"_b"}};
1178 UINT64 Unbootable = 0;
1179 UINT64 BootSuccess = 0;
1180
1181 /* Mark current Slot as unbootable */
1182 GUARD(GetActiveSlot(&ActiveSlot));
1183 BootEntry = GetBootPartitionEntry(&ActiveSlot);
1184 if (BootEntry == NULL) {
1185 DEBUG((EFI_D_ERROR, "HandleActiveSlotUnbootable: No boot "
1186 "partition entry for slot %s\n",
1187 ActiveSlot.Suffix));
1188 return EFI_NOT_FOUND;
1189 }
1190
Shivaprasad Hongal340f6872017-04-26 16:15:27 -07001191 if (FirstBoot && !TargetBuildVariantUser()) {
1192 DEBUG((EFI_D_VERBOSE, "FirstBoot, skipping slot Unbootable\n"));
1193 FirstBoot = FALSE;
1194 } else {
1195 BootEntry->PartEntry.Attributes |=
1196 (PART_ATT_UNBOOTABLE_VAL) & (~PART_ATT_SUCCESSFUL_VAL);
1197 UpdatePartitionAttributes();
1198 }
Shivaprasad Hongalc017e812017-04-26 16:15:27 -07001199
1200 if (StrnCmp(ActiveSlot.Suffix, Slots[0].Suffix, StrLen(Slots[0].Suffix)) == 0) {
1201 AlternateSlot = &Slots[1];
1202 } else {
1203 AlternateSlot = &Slots[0];
1204 }
1205
1206 /* Validate Aternate Slot is bootable */
1207 BootEntry = GetBootPartitionEntry(AlternateSlot);
1208 if (BootEntry == NULL) {
1209 DEBUG((EFI_D_ERROR, "HandleActiveSlotUnbootable: No boot "
1210 "partition entry for slot %s\n",
1211 AlternateSlot->Suffix));
1212 return EFI_NOT_FOUND;
1213 }
1214
1215 Unbootable = (BootEntry->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) >>
1216 PART_ATT_UNBOOTABLE_BIT;
1217 BootSuccess = (BootEntry->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) >>
1218 PART_ATT_SUCCESS_BIT;
1219
1220 if (Unbootable == 0 && BootSuccess == 1) {
1221 DEBUG((EFI_D_INFO, "Alternate Slot %s is bootable\n",
1222 AlternateSlot->Suffix));
1223 GUARD(SetActiveSlot(AlternateSlot));
1224
1225 DEBUG((EFI_D_INFO, "HandleActiveSlotUnbootable: Rebooting\n"));
1226 gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
1227
1228 // Shouldn't get here
1229 DEBUG((EFI_D_ERROR, "HandleActiveSlotUnbootable: "
1230 "gRT->Resetystem didn't work\n"));
1231 return EFI_LOAD_ERROR;
1232 }
1233
1234 return EFI_LOAD_ERROR;
1235}
1236
1237STATIC EFI_STATUS ValidateSlotGuids(Slot *BootableSlot)
1238{
1239 EFI_STATUS Status = EFI_SUCCESS;
1240 struct PartitionEntry *BootEntry = NULL;
1241 CHAR16 SystemPartitionName[] = L"system_x";
1242 CONST struct PartitionEntry *SystemEntry = NULL;
1243 CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX];
1244 UINT32 UfsBootLun = 0;
1245
1246 BootEntry = GetBootPartitionEntry(BootableSlot);
1247 if (BootEntry == NULL) {
1248 DEBUG((EFI_D_ERROR, "ValidateSlotGuids: No boot partition "
1249 "entry for slot %s\n",
1250 BootableSlot->Suffix));
1251 return EFI_NOT_FOUND;
1252 }
1253
1254 SystemPartitionName[StrLen(SystemPartitionName) - 1] =
1255 BootableSlot->Suffix[StrLen(BootableSlot->Suffix) - 1];
1256 SystemEntry = GetPartitionEntry(SystemPartitionName);
1257 if (SystemEntry == NULL) {
1258 DEBUG((EFI_D_ERROR,
1259 "ValidateSlotGuids: No partition entry for %s\n",
1260 SystemPartitionName));
1261 return EFI_NOT_FOUND;
1262 }
1263
1264 if (CompareMem(&BootEntry->PartEntry.PartitionTypeGUID,
1265 &SystemEntry->PartEntry.PartitionTypeGUID,
1266 sizeof(EFI_GUID)) == 0) {
1267 DEBUG((EFI_D_ERROR, "ValidateSlotGuids: BootableSlot %s does "
1268 "not have valid guids\n",
1269 BootableSlot->Suffix));
1270 DEBUG((EFI_D_INFO, "Boot GUID %g\n",
1271 &BootEntry->PartEntry.PartitionTypeGUID));
1272 DEBUG((EFI_D_INFO, "System GUID %g\n",
1273 &SystemEntry->PartEntry.PartitionTypeGUID));
1274 return EFI_DEVICE_ERROR;
1275 }
1276
1277 GetRootDeviceType(BootDeviceType, BOOT_DEV_NAME_SIZE_MAX);
1278 if (!AsciiStrnCmp(BootDeviceType, "UFS", AsciiStrLen("UFS"))) {
1279 GUARD(UfsGetSetBootLun(&UfsBootLun, TRUE));
1280 if (UfsBootLun == 0x1 && !StrCmp(BootableSlot->Suffix, L"_a")) {
1281 } else if (UfsBootLun == 0x2 && !StrCmp(BootableSlot->Suffix, L"_b")) {
1282 } else {
1283 DEBUG((EFI_D_ERROR, "Boot lun: %x and BootableSlot: %s "
1284 "do not match\n",
1285 UfsBootLun, BootableSlot->Suffix));
1286 return EFI_DEVICE_ERROR;
1287 }
1288 } else if (!AsciiStrnCmp(BootDeviceType, "EMMC", AsciiStrLen("EMMC"))) {
1289 } else {
1290 DEBUG((EFI_D_ERROR, "Unsupported Device Type\n"));
1291 return EFI_DEVICE_ERROR;
1292 }
1293
1294 DEBUG((EFI_D_INFO, "Booting from slot (%s)\n", BootableSlot->Suffix));
1295 return EFI_SUCCESS;
1296}
1297
1298EFI_STATUS FindBootableSlot(Slot *BootableSlot)
1299{
1300 EFI_STATUS Status = EFI_SUCCESS;
1301 struct PartitionEntry *BootEntry = NULL;
1302 UINT64 Unbootable = 0;
1303 UINT64 BootSuccess = 0;
1304 UINT64 RetryCount = 0;
1305
1306 if (BootableSlot == NULL) {
1307 DEBUG((EFI_D_ERROR,
1308 "FindBootableSlot: input parameter invalid\n"));
1309 return EFI_INVALID_PARAMETER;
1310 }
1311
1312 GUARD_OUT(GetActiveSlot(BootableSlot));
1313
1314 /* Validate Active Slot is bootable */
1315 BootEntry = GetBootPartitionEntry(BootableSlot);
1316 if (BootEntry == NULL) {
1317 DEBUG((EFI_D_ERROR, "FindBootableSlot: No boot partition entry "
1318 "for slot %s\n",
1319 BootableSlot->Suffix));
1320 return EFI_NOT_FOUND;
1321 }
1322
1323 Unbootable = (BootEntry->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) >>
1324 PART_ATT_UNBOOTABLE_BIT;
1325 BootSuccess = (BootEntry->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) >>
1326 PART_ATT_SUCCESS_BIT;
1327 RetryCount =
1328 (BootEntry->PartEntry.Attributes & PART_ATT_MAX_RETRY_COUNT_VAL) >>
1329 PART_ATT_MAX_RETRY_CNT_BIT;
1330
1331 if (Unbootable == 0 && BootSuccess == 1) {
1332 DEBUG((EFI_D_VERBOSE, "Active Slot %s is bootable\n",
1333 BootableSlot->Suffix));
1334 } else if (Unbootable == 0 && BootSuccess == 0 && RetryCount > 0) {
1335 RetryCount--;
1336 BootEntry->PartEntry.Attributes &= ~PART_ATT_MAX_RETRY_COUNT_VAL;
1337 BootEntry->PartEntry.Attributes |=
1338 RetryCount << PART_ATT_MAX_RETRY_CNT_BIT;
1339 UpdatePartitionAttributes();
1340 DEBUG((EFI_D_INFO,
1341 "Active Slot %s is bootable, retry count %ld\n",
1342 BootableSlot->Suffix, RetryCount));
1343 } else {
1344 DEBUG((EFI_D_INFO,
Shivaprasad Hongal7fd6a522017-05-10 13:56:28 -07001345 "Slot %s is unbootable, trying alternate slot\n",
Shivaprasad Hongalc017e812017-04-26 16:15:27 -07001346 BootableSlot->Suffix));
1347 GUARD_OUT(HandleActiveSlotUnbootable());
1348 }
1349
1350 /* Validate slot suffix and partition guids */
1351 if (Status == EFI_SUCCESS) {
1352 GUARD_OUT(ValidateSlotGuids(BootableSlot));
1353 }
1354 MarkPtnActive(BootableSlot->Suffix);
1355out:
1356 if (Status != EFI_SUCCESS) {
1357 /* clear bootable slot */
1358 BootableSlot->Suffix[0] = '\0';
1359 }
1360 return Status;
Vijay Kumar Pendoti644a20b2017-03-15 18:22:17 +05301361}
1362
1363/*Function to provide Dtbo Present info
1364 *return: TRUE or FALSE.
1365 */
Vijay Kumar Pendoti6fc41c42017-05-09 19:41:26 +05301366BOOLEAN LoadAndValidateDtboImg(BootInfo *Info, VOID** DtboImgBuffer)
Vijay Kumar Pendoti644a20b2017-03-15 18:22:17 +05301367{
Vijay Kumar Pendoti4229f7b2017-05-08 21:32:39 +05301368 UINTN DtboImgSize = 0;
Vijay Kumar Pendoti4229f7b2017-05-08 21:32:39 +05301369 EFI_STATUS Status = EFI_SUCCESS;
1370 struct DtboTableHdr* DtboTableHdr = NULL;
Vijay Kumar Pendoti644a20b2017-03-15 18:22:17 +05301371
Vijay Kumar Pendoti6fc41c42017-05-09 19:41:26 +05301372 Status = GetImage(Info, DtboImgBuffer, &DtboImgSize, "dtbo");
1373 if (Status != EFI_SUCCESS) {
1374 DEBUG((EFI_D_ERROR, "BootLinux: GetImage failed!"));
1375 return FALSE;
Vijay Kumar Pendoti644a20b2017-03-15 18:22:17 +05301376 }
Vijay Kumar Pendoti6fc41c42017-05-09 19:41:26 +05301377 if (!DtboImgBuffer) {
1378 DEBUG((EFI_D_ERROR, "DtboImgBuffer is NULL"));
1379 return FALSE;
1380 }
1381
1382 DtboTableHdr = *DtboImgBuffer;
1383 if (fdt32_to_cpu(DtboTableHdr->Magic) != DTBO_TABLE_MAGIC) {
1384 DEBUG((EFI_D_ERROR, "Dtbo hdr magic mismatch %x, with %x\n", DtboTableHdr->Magic, DTBO_TABLE_MAGIC));
1385 return FALSE;
1386 }
1387
1388 if (DtboImgSize > DTBO_MAX_SIZE_ALLOWED) {
1389 DEBUG((EFI_D_ERROR, "Dtbo Size too big %x, Allowed size %x\n", DtboImgSize,DTBO_MAX_SIZE_ALLOWED));
1390 return FALSE;
1391 }
1392
1393 /*Check for TotalSize of Dtbo image*/
1394 if ((fdt32_to_cpu(DtboTableHdr->TotalSize) > DTBO_MAX_SIZE_ALLOWED) || (fdt32_to_cpu(DtboTableHdr->TotalSize) == 0)) {
1395 DEBUG((EFI_D_ERROR, "Dtbo Table TotalSize got corrupted\n"));
1396 return FALSE;
1397 }
1398
1399 /*Check for HeaderSize of Dtbo image*/
1400 if (fdt32_to_cpu(DtboTableHdr->HeaderSize) != sizeof(struct DtboTableHdr)) {
1401 DEBUG((EFI_D_ERROR, "Dtbo Table HeaderSize got corrupted\n"));
1402 return FALSE;
1403 }
1404
1405 /*Check for DtEntrySize of Dtbo image*/
1406 if (fdt32_to_cpu(DtboTableHdr->DtEntrySize) != sizeof(struct DtboTableEntry)) {
1407 DEBUG((EFI_D_ERROR, "Dtbo Table DtEntrySize got corrupted\n"));
1408 return FALSE;
1409 }
1410
1411 /*Check for DtEntryOffset of Dtbo image*/
1412 if (fdt32_to_cpu(DtboTableHdr->DtEntryOffset) > DTBO_MAX_SIZE_ALLOWED) {
1413 DEBUG((EFI_D_ERROR, "Dtbo Table DtEntryOffset got corrupted\n"));
1414 return FALSE;
1415 }
1416
1417 return TRUE;
Vijay Kumar Pendoti644a20b2017-03-15 18:22:17 +05301418}