blob: 20cdc76e28c9a49d12d23f8e7d6ff33e19e8aeca [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>
lijuangf0bbcad2017-08-16 16:59:18 +080037#include "AutoGen.h"
38
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -080039STATIC BOOLEAN FlashingGpt;
40STATIC BOOLEAN ParseSecondaryGpt;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053041struct StoragePartInfo Ptable[MAX_LUNS];
42struct PartitionEntry PtnEntries[MAX_NUM_PARTITIONS];
43STATIC UINT32 MaxLuns;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053044STATIC UINT32 PartitionCount;
Shivaprasad Hongal340f6872017-04-26 16:15:27 -070045STATIC BOOLEAN FirstBoot;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053046
Vijay Kumar Pendotia7e72a02016-11-11 15:36:56 +053047STATIC struct BootPartsLinkedList *HeadNode;
Shivaprasad Hongalc017e812017-04-26 16:15:27 -070048STATIC EFI_STATUS GetActiveSlot(Slot *ActiveSlot);
Vijay Kumar Pendotia7e72a02016-11-11 15:36:56 +053049
lijuangf0bbcad2017-08-16 16:59:18 +080050Slot GetCurrentSlotSuffix(VOID)
Shivaprasad Hongalc017e812017-04-26 16:15:27 -070051{
52 Slot CurrentSlot = {{0}};
53 BOOLEAN IsMultiSlot = PartitionHasMultiSlot(L"boot");
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053054
Shivaprasad Hongalc017e812017-04-26 16:15:27 -070055 if (IsMultiSlot == FALSE) {
56 return CurrentSlot;
57 }
lijuanga4c1b082016-12-08 19:12:48 +080058
Shivaprasad Hongalc017e812017-04-26 16:15:27 -070059 GetActiveSlot(&CurrentSlot);
60 return CurrentSlot;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053061}
62
lijuangf0bbcad2017-08-16 16:59:18 +080063UINT32 GetMaxLuns(VOID) {
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053064 return MaxLuns;
65}
66
lijuang94109952016-10-28 19:33:55 +080067UINT32 GetPartitionLunFromIndex(UINT32 Index)
Jeevan Shriramab436682016-09-23 07:08:06 -070068{
69 return PtnEntries[Index].lun;
70}
71
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053072VOID GetPartitionCount(UINT32 *Val) {
73 *Val = PartitionCount;
74 return;
75}
76
lijuang94109952016-10-28 19:33:55 +080077INT32 GetPartitionIdxInLun(CHAR16 *Pname, UINT32 Lun)
Jeevan Shriramab436682016-09-23 07:08:06 -070078{
lijuang94109952016-10-28 19:33:55 +080079 UINT32 n;
80 UINT32 RelativeIndex = 0;
Jeevan Shriramab436682016-09-23 07:08:06 -070081
82 for (n = 0; n < PartitionCount; n++) {
83 if (Lun == PtnEntries[n].lun) {
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +053084 if (!StrCmp(Pname, PtnEntries[n].PartEntry.PartitionName))
Jeevan Shriramab436682016-09-23 07:08:06 -070085 return RelativeIndex;
86 RelativeIndex++;
87 }
88 }
89 return INVALID_PTN;
90}
91
lijuangf0bbcad2017-08-16 16:59:18 +080092VOID UpdatePartitionEntries(VOID)
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053093{
94 UINT32 i;
95 UINT32 j;
96 UINT32 Index = 0;
97 EFI_STATUS Status;
98 EFI_PARTITION_ENTRY *PartEntry;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +053099
100 PartitionCount = 0;
101 /*Nullify the PtnEntries array before using it*/
lijuang886b75a2017-05-12 19:26:14 +0800102 gBS->SetMem((VOID*) PtnEntries, (sizeof(PtnEntries[0]) * MAX_NUM_PARTITIONS), 0);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530103
104 for (i = 0; i < MaxLuns; i++) {
105 for (j = 0; (j < Ptable[i].MaxHandles) && (Index < MAX_NUM_PARTITIONS); j++, Index++) {
106 Status = gBS->HandleProtocol(Ptable[i].HandleInfoList[j].Handle, &gEfiPartitionRecordGuid, (VOID **)&PartEntry);
107 PartitionCount++;
108 if (EFI_ERROR(Status)) {
109 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 -0700110 PtnEntries[Index].lun = i;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530111 continue;
112 }
Jeevan Shriram0da9d752016-09-28 15:04:27 -0700113
lijuang886b75a2017-05-12 19:26:14 +0800114 gBS->CopyMem((&PtnEntries[Index]), PartEntry, sizeof(PartEntry[0]));
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530115 PtnEntries[Index].lun = i;
116 }
117 }
118}
119
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530120INT32 GetPartitionIndex(CHAR16 *Pname)
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530121{
122 INT32 i;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530123
124 for (i = 0; i < PartitionCount; i++) {
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530125 if (!StrCmp(PtnEntries[i].PartEntry.PartitionName, Pname))
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530126 return i;
127 }
128
129 return INVALID_PTN;
130}
131
lijuang94109952016-10-28 19:33:55 +0800132STATIC EFI_STATUS GetStorageHandle(INT32 Lun, HandleInfo *BlockIoHandle, UINT32 *MaxHandles)
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530133{
134 EFI_STATUS Status = EFI_INVALID_PARAMETER;
135 UINT32 Attribs = 0;
136 PartiSelectFilter HandleFilter;
137 //UFS LUN GUIDs
138 EFI_GUID LunGuids[] = {
139 gEfiUfsLU0Guid,
140 gEfiUfsLU1Guid,
141 gEfiUfsLU2Guid,
142 gEfiUfsLU3Guid,
143 gEfiUfsLU4Guid,
144 gEfiUfsLU5Guid,
145 gEfiUfsLU6Guid,
146 gEfiUfsLU7Guid,
147 };
148
149 Attribs |= BLK_IO_SEL_SELECT_ROOT_DEVICE_ONLY;
lijuangf0bbcad2017-08-16 16:59:18 +0800150 HandleFilter.PartitionType = NULL;
151 HandleFilter.VolumeName = NULL;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530152
153 if (Lun == NO_LUN) {
154 HandleFilter.RootDeviceType = &gEfiEmmcUserPartitionGuid;
155 Status = GetBlkIOHandles(Attribs, &HandleFilter, BlockIoHandle, MaxHandles);
156 if (EFI_ERROR (Status)) {
157 DEBUG((EFI_D_ERROR, "Error getting block IO handle for Emmc\n"));
158 return Status;
159 }
160 } else {
161 HandleFilter.RootDeviceType = &LunGuids[Lun];
162 Status = GetBlkIOHandles(Attribs, &HandleFilter, BlockIoHandle, MaxHandles);
163 if (EFI_ERROR (Status)) {
164 DEBUG((EFI_D_ERROR, "Error getting block IO handle for Lun:%x\n", Lun));
165 return Status;
166 }
167 }
168
169 return Status;
170}
171
lijuangf0bbcad2017-08-16 16:59:18 +0800172VOID UpdatePartitionAttributes(VOID)
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530173{
174 UINT32 BlkSz;
175 UINT8 *GptHdr = NULL;
176 UINT8 *GptHdrPtr = NULL;
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530177 UINTN MaxGptPartEntrySzBytes;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530178 UINT32 Offset;
179 UINT32 MaxPtnCount = 0;
180 UINT32 PtnEntrySz = 0;
181 UINT32 i = 0;
182 UINT8 *PtnEntriesPtr;
183 UINT8 *Ptn_Entries;
184 UINT32 CrcVal = 0;
185 UINT32 Iter;
186 UINT32 HdrSz = GPT_HEADER_SIZE;
187 UINT64 DeviceDensity;
188 UINT64 CardSizeSec;
189 EFI_STATUS Status;
lijuang94109952016-10-28 19:33:55 +0800190 INT32 Lun;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530191 EFI_BLOCK_IO_PROTOCOL *BlockIo=NULL;
192 HandleInfo BlockIoHandle[MAX_HANDLEINF_LST_SIZE];
lijuang94109952016-10-28 19:33:55 +0800193 UINT32 MaxHandles = MAX_HANDLEINF_LST_SIZE;
Vijay Kumar Pendoti5fdbb162017-02-01 20:54:01 +0530194 CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX];
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530195 UINT32 PartEntriesblocks = 0;
Parth Dixit8b9c4bc2017-03-31 22:31:01 +0530196 BOOLEAN SkipUpdation;
197 UINT64 Attr;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530198
Vijay Kumar Pendoti5fdbb162017-02-01 20:54:01 +0530199 GetRootDeviceType(BootDeviceType, BOOT_DEV_NAME_SIZE_MAX);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530200 for( Lun = 0; Lun < MaxLuns; Lun++) {
201
Vijay Kumar Pendoti5fdbb162017-02-01 20:54:01 +0530202 if (!AsciiStrnCmp(BootDeviceType, "EMMC", AsciiStrLen("EMMC"))) {
203 Status = GetStorageHandle(NO_LUN, BlockIoHandle, &MaxHandles);
204 } else if (!AsciiStrnCmp(BootDeviceType, "UFS", AsciiStrLen("UFS"))) {
205 Status = GetStorageHandle(Lun, BlockIoHandle, &MaxHandles);
Vijay Kumar Pendoti25ac2e62017-02-27 18:52:52 +0530206 } else {
207 DEBUG((EFI_D_ERROR, "Unsupported boot device type\n"));
208 return;
Vijay Kumar Pendoti5fdbb162017-02-01 20:54:01 +0530209 }
Jeevan Shriram6a254302017-03-02 11:47:42 -0800210
Vijay Kumar Pendoti5547eab2017-03-16 16:21:23 +0530211 if (Status != EFI_SUCCESS) {
212 DEBUG((EFI_D_ERROR, "Failed to get BlkIo for device. MaxHandles:%d - %r\n", Status));
213 return;
214 }
215 if (MaxHandles != 1) {
Jeevan Shriram6a254302017-03-02 11:47:42 -0800216 DEBUG((EFI_D_VERBOSE, "Failed to get the BlockIo for device. MaxHandle:%d, %r\n",
217 MaxHandles, Status));
218 continue;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530219 }
Jeevan Shriram6a254302017-03-02 11:47:42 -0800220
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530221 BlockIo = BlockIoHandle[0].BlkIo;
222 DeviceDensity = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
223 BlkSz = BlockIo->Media->BlockSize;
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530224 PartEntriesblocks = MAX_PARTITION_ENTRIES_SZ/BlkSz;
225 MaxGptPartEntrySzBytes = (GPT_HDR_BLOCKS + PartEntriesblocks) * BlkSz;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530226 CardSizeSec = (DeviceDensity) / BlkSz;
227 Offset = PRIMARY_HDR_LBA;
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530228 GptHdr = AllocatePool(MaxGptPartEntrySzBytes);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530229 if (!GptHdr) {
230 DEBUG ((EFI_D_ERROR, "Unable to Allocate Memory for GptHdr \n"));
231 return;
232 }
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530233
lijuang886b75a2017-05-12 19:26:14 +0800234 gBS->SetMem((VOID *) GptHdr, MaxGptPartEntrySzBytes, 0);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530235 GptHdrPtr = GptHdr;
236
237 /* This loop iterates twice to update both primary and backup Gpt*/
Parth Dixit8b9c4bc2017-03-31 22:31:01 +0530238 for (Iter= 0; Iter < 2; Iter++, (Offset = CardSizeSec - MaxGptPartEntrySzBytes/BlkSz)) {
239 SkipUpdation = TRUE;
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530240 Status = BlockIo->ReadBlocks (BlockIo, BlockIo->Media->MediaId, Offset, MaxGptPartEntrySzBytes, GptHdr);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530241
242 if(EFI_ERROR(Status)) {
243 DEBUG ((EFI_D_ERROR, "Unable to read the media \n"));
244 return;
245 }
246 if(Iter == 0x1) {
247 /* This is the back up GPT */
lijuang2120d972016-11-02 18:28:21 +0800248 Ptn_Entries = GptHdr;
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530249 GptHdr = GptHdr + ((PartEntriesblocks) * BlkSz);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530250 } else
251 /* otherwise we are at the primary gpt */
lijuang2120d972016-11-02 18:28:21 +0800252 Ptn_Entries = GptHdr + BlkSz;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530253
254 PtnEntriesPtr = Ptn_Entries;
255
256 for (i = 0;i < PartitionCount;i++) {
Jeevan Shriram0da9d752016-09-28 15:04:27 -0700257 /*If GUID is not present, then it is BlkIo Handle of the Lun. Skip*/
258 if (!(PtnEntries[i].PartEntry.PartitionTypeGUID.Data1)) {
259 DEBUG((EFI_D_VERBOSE, " Skipping Lun:%d, i=%d\n", Lun, i));
260 continue;
261 }
262
Vijay Kumar Pendoti5fdbb162017-02-01 20:54:01 +0530263 if (!AsciiStrnCmp(BootDeviceType, "UFS", AsciiStrLen("UFS"))) {
264 /* Partition table is populated with entries from lun 0 to max lun.
265 * break out of the loop once we see the partition lun is > current lun */
266 if (PtnEntries[i].lun > Lun)
267 break;
268 /* Find the entry where the partition table for 'lun' starts and then update the attributes */
269 if (PtnEntries[i].lun != Lun)
270 continue;
271 }
Parth Dixit8b9c4bc2017-03-31 22:31:01 +0530272 Attr = GET_LLWORD_FROM_BYTE(&PtnEntriesPtr[ATTRIBUTE_FLAG_OFFSET]);
273 if(Attr != PtnEntries[i].PartEntry.Attributes) {
274 /* Update the partition attributes and partiton GUID values */
275 PUT_LONG_LONG(&PtnEntriesPtr[ATTRIBUTE_FLAG_OFFSET], PtnEntries[i].PartEntry.Attributes);
lijuang886b75a2017-05-12 19:26:14 +0800276 gBS->CopyMem((VOID *)PtnEntriesPtr, (VOID *)&PtnEntries[i].PartEntry.PartitionTypeGUID, GUID_SIZE);
Parth Dixit8b9c4bc2017-03-31 22:31:01 +0530277 SkipUpdation = FALSE;
278 }
279
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530280 /* point to the next partition entry */
281 PtnEntriesPtr += PARTITION_ENTRY_SIZE;
282 }
283
Parth Dixit8b9c4bc2017-03-31 22:31:01 +0530284 if(SkipUpdation)
285 continue;
286
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530287 MaxPtnCount = GET_LWORD_FROM_BYTE(&GptHdr[PARTITION_COUNT_OFFSET]);
288 PtnEntrySz = GET_LWORD_FROM_BYTE(&GptHdr[PENTRY_SIZE_OFFSET]);
289
Vijay Kumar Pendotie2961262017-07-11 16:33:38 +0530290 if (((MaxPtnCount) * (PtnEntrySz)) > MAX_PARTITION_ENTRIES_SZ) {
291 DEBUG((EFI_D_ERROR, "Invalid GPT header fields MaxPtnCount = %x, PtnEntrySz = %x\n", MaxPtnCount, PtnEntrySz));
292 return;
293 }
294
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530295 Status = gBS->CalculateCrc32(Ptn_Entries, ((MaxPtnCount) * (PtnEntrySz)),&CrcVal);
296 if (Status != EFI_SUCCESS) {
297 DEBUG((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n", Status));
298 return;
299 }
300
301 PUT_LONG(&GptHdr[PARTITION_CRC_OFFSET], CrcVal);
302
303 /*Write CRC to 0 before we calculate the crc of the GPT header*/
304 CrcVal = 0;
305 PUT_LONG(&GptHdr[HEADER_CRC_OFFSET], CrcVal);
306
307 Status = gBS->CalculateCrc32(GptHdr, HdrSz, &CrcVal);
308 if (Status != EFI_SUCCESS) {
309 DEBUG((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n", Status));
310 return;
311 }
312
313 PUT_LONG(&GptHdr[HEADER_CRC_OFFSET], CrcVal);
314
315 if (Iter == 0x1)
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530316 /* Write the backup GPT header, which is at an offset of CardSizeSec - MaxGptPartEntrySzBytes/BlkSz in blocks*/
317 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, Offset, MaxGptPartEntrySzBytes, (VOID *)Ptn_Entries);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530318 else
319 /* Write the primary GPT header, which is at an offset of BlkSz */
Vijay Kumar Pendoti81ed7f82017-03-23 12:55:22 +0530320 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, Offset, MaxGptPartEntrySzBytes, (VOID *)GptHdr);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530321
322 if (EFI_ERROR(Status)) {
323 DEBUG((EFI_D_ERROR, "Error writing primary GPT header: %r\n", Status));
324 return;
325 }
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530326 }
327 FreePool(GptHdrPtr);
328 }
329}
330
lijuangf0bbcad2017-08-16 16:59:18 +0800331STATIC VOID MarkPtnActive(CHAR16 *ActiveSlot)
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530332{
333 UINT32 i;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530334 for (i = 0; i < PartitionCount; i++) {
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530335 /* Mark all the slots with current ActiveSlot as active */
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530336 if (StrStr(PtnEntries[i].PartEntry.PartitionName, ActiveSlot))
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530337 PtnEntries[i].PartEntry.Attributes |= PART_ATT_ACTIVE_VAL;
338 else
339 PtnEntries[i].PartEntry.Attributes &= ~PART_ATT_ACTIVE_VAL;
340 }
341
342 /* Update the partition table */
343 UpdatePartitionAttributes();
344}
345
346STATIC VOID SwapPtnGuid(EFI_PARTITION_ENTRY *p1, EFI_PARTITION_ENTRY *p2)
347{
Channagoud Kadabi0dbf8692016-09-30 16:17:11 -0700348 EFI_GUID Temp;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530349
350 if (p1 == NULL || p2 == NULL)
351 return;
lijuang886b75a2017-05-12 19:26:14 +0800352 gBS->CopyMem((VOID *)&Temp, (VOID *)&p1->PartitionTypeGUID, sizeof(EFI_GUID));
353 gBS->CopyMem((VOID *)&p1->PartitionTypeGUID, (VOID *)&p2->PartitionTypeGUID, sizeof(EFI_GUID));
354 gBS->CopyMem((VOID *)&p2->PartitionTypeGUID, (VOID *)&Temp, sizeof(EFI_GUID));
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530355}
356
lijuangf0bbcad2017-08-16 16:59:18 +0800357STATIC EFI_STATUS GetMultiSlotPartsList(VOID) {
Vijay Kumar Pendotia7e72a02016-11-11 15:36:56 +0530358 UINT32 i = 0;
359 UINT32 j = 0;
360 UINT32 Len = 0;
361 CHAR16 *SearchString = NULL;
362 struct BootPartsLinkedList *TempNode = NULL;
363
364 for (i = 0; i < PartitionCount; i++) {
365 SearchString = PtnEntries[i].PartEntry.PartitionName;
366 if (!SearchString[0])
367 continue;
368
369 for (j = i+1; j < PartitionCount; j++) {
370 if (!PtnEntries[j].PartEntry.PartitionName[0])
371 continue;
372 Len = StrLen(SearchString);
373
374 /*Need to compare till "boot_"a hence skip last Char from StrLen value*/
375 if (!StrnCmp(PtnEntries[j].PartEntry.PartitionName, SearchString, Len-1) &&
376 (StrStr(SearchString, L"_a") || (StrStr(SearchString, L"_b")))) {
377 TempNode = AllocatePool(sizeof(struct BootPartsLinkedList));
378 if (TempNode) {
379 /*Skip _a/_b from partition name*/
380 StrnCpyS(TempNode->PartName, sizeof(TempNode->PartName), SearchString, Len-2);
381 TempNode->Next = HeadNode;
382 HeadNode = TempNode;
383 } else {
384 DEBUG ((EFI_D_ERROR, "Unable to Allocate Memory for MultiSlot Partition list\n"));
385 return EFI_OUT_OF_RESOURCES;
386 }
387 break;
388 }
389 }
390 }
391 return EFI_SUCCESS;
392}
393
lijuangf0bbcad2017-08-16 16:59:18 +0800394STATIC VOID SwitchPtnSlots(CONST CHAR16 *SetActive)
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530395{
Vijay Kumar Pendotia7e72a02016-11-11 15:36:56 +0530396 UINT32 i;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530397 struct PartitionEntry *PtnCurrent = NULL;
398 struct PartitionEntry *PtnNew = NULL;
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530399 CHAR16 CurSlot[BOOT_PART_SIZE];
400 CHAR16 NewSlot[BOOT_PART_SIZE];
401 CHAR16 SetInactive[MAX_SLOT_SUFFIX_SZ];
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530402 UINT32 UfsBootLun = 0;
403 BOOLEAN UfsGet = TRUE;
404 BOOLEAN UfsSet = FALSE;
Vijay Kumar Pendotia7e72a02016-11-11 15:36:56 +0530405 struct BootPartsLinkedList *TempNode = NULL;
406 EFI_STATUS Status;
Vijay Kumar Pendoti177eedc2017-01-20 18:57:03 +0530407 CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX];
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530408
409 /* Create the partition name string for active and non active slots*/
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530410 if (!StrnCmp(SetActive, L"_a", StrLen(L"_a")))
411 StrnCpyS(SetInactive, MAX_SLOT_SUFFIX_SZ, L"_b", StrLen(L"_b"));
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530412 else
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530413 StrnCpyS(SetInactive, MAX_SLOT_SUFFIX_SZ, L"_a", StrLen(L"_a"));
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530414
Vijay Kumar Pendotia7e72a02016-11-11 15:36:56 +0530415 if (!HeadNode) {
416 Status = GetMultiSlotPartsList();
417 if (Status != EFI_SUCCESS) {
418 DEBUG((EFI_D_INFO, "Unable to get GetMultiSlotPartsList\n"));
419 return;
420 }
421 }
422
423 for (TempNode = HeadNode; TempNode; TempNode = TempNode->Next) {
424 StrnCpyS(CurSlot, StrLen(TempNode->PartName) + 1, TempNode->PartName, StrLen(TempNode->PartName));
lijuanga4c1b082016-12-08 19:12:48 +0800425 StrnCatS(CurSlot, BOOT_PART_SIZE - 1, SetInactive, StrLen(SetInactive));
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530426
Vijay Kumar Pendotia7e72a02016-11-11 15:36:56 +0530427 StrnCpyS(NewSlot, StrLen(TempNode->PartName) + 1, TempNode->PartName, StrLen(TempNode->PartName));
lijuanga4c1b082016-12-08 19:12:48 +0800428 StrnCatS(NewSlot, BOOT_PART_SIZE - 1, SetActive, StrLen(SetActive));
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530429
430 /* Find the pointer to partition table entry for active and non-active slots*/
431 for (i = 0; i < PartitionCount; i++) {
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530432 if (!StrnCmp(PtnEntries[i].PartEntry.PartitionName, CurSlot, StrLen(CurSlot))) {
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530433 PtnCurrent = &PtnEntries[i];
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530434 } else if (!StrnCmp(PtnEntries[i].PartEntry.PartitionName, NewSlot, StrLen(NewSlot))) {
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530435 PtnNew = &PtnEntries[i];
436 }
437 }
438 /* Swap the guids for the slots */
439 SwapPtnGuid(&PtnCurrent->PartEntry, &PtnNew->PartEntry);
lijuang886b75a2017-05-12 19:26:14 +0800440 gBS->SetMem(CurSlot, BOOT_PART_SIZE, 0);
441 gBS->SetMem(NewSlot, BOOT_PART_SIZE, 0);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530442 PtnCurrent = PtnNew = NULL;
443 }
Vijay Kumar Pendoti177eedc2017-01-20 18:57:03 +0530444
445 GetRootDeviceType(BootDeviceType, BOOT_DEV_NAME_SIZE_MAX);
446 if (!AsciiStrnCmp(BootDeviceType, "UFS", AsciiStrLen("UFS"))) {
447 UfsGetSetBootLun(&UfsBootLun, UfsGet);
448 // Special case for XBL is to change the bootlun instead of swapping the guid
449 if (UfsBootLun == 0x1 && !StrnCmp(SetActive, L"_b", StrLen(L"_b"))) {
450 DEBUG((EFI_D_INFO, "Switching the boot lun from 1 to 2\n"));
451 UfsBootLun = 0x2;
452 }
453 else if (UfsBootLun == 0x2 && !StrnCmp(SetActive, L"_a", StrLen(L"_a"))) {
454 DEBUG((EFI_D_INFO, "Switching the boot lun from 2 to 1\n"));
455 UfsBootLun = 0x1;
456 }
457 UfsGetSetBootLun(&UfsBootLun, UfsSet);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530458 }
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530459}
460
461EFI_STATUS
lijuangf0bbcad2017-08-16 16:59:18 +0800462EnumeratePartitions (VOID)
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530463{
464 EFI_STATUS Status;
465 PartiSelectFilter HandleFilter;
466 UINT32 Attribs = 0;
467 UINT32 i;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530468 //UFS LUN GUIDs
469 EFI_GUID LunGuids[] = {
470 gEfiUfsLU0Guid,
471 gEfiUfsLU1Guid,
472 gEfiUfsLU2Guid,
473 gEfiUfsLU3Guid,
474 gEfiUfsLU4Guid,
475 gEfiUfsLU5Guid,
476 gEfiUfsLU6Guid,
477 gEfiUfsLU7Guid,
478 };
479
lijuang886b75a2017-05-12 19:26:14 +0800480 gBS->SetMem((VOID*) Ptable, (sizeof(struct StoragePartInfo) * MAX_LUNS), 0);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530481
482 /* By default look for emmc partitions if not found look for UFS */
483 Attribs |= BLK_IO_SEL_MATCH_ROOT_DEVICE;
484
485 Ptable[0].MaxHandles = ARRAY_SIZE(Ptable[0].HandleInfoList);
lijuangf0bbcad2017-08-16 16:59:18 +0800486 HandleFilter.PartitionType = NULL;
487 HandleFilter.VolumeName = NULL;
Jeevan Shriram749ea922017-08-15 13:50:12 -0700488 HandleFilter.RootDeviceType = &gEfiNandUserPartitionGuid;
489
490 Status = GetBlkIOHandles(Attribs, &HandleFilter, &Ptable[0].HandleInfoList[0], &Ptable[0].MaxHandles);
491 /* For Emmc/NAND devices the Lun concept does not exist, we will always one lun and the lun number is '0'
492 * to have the partition selection implementation same acros
493 */
494 if (Status == EFI_SUCCESS && Ptable[0].MaxHandles > 0) {
495 MaxLuns = 1;
496 return Status;
497 }
498
499 Ptable[0].MaxHandles = ARRAY_SIZE(Ptable[0].HandleInfoList);
500 HandleFilter.PartitionType = NULL;
501 HandleFilter.VolumeName = NULL;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530502 HandleFilter.RootDeviceType = &gEfiEmmcUserPartitionGuid;
503
504 Status = GetBlkIOHandles(Attribs, &HandleFilter, &Ptable[0].HandleInfoList[0], &Ptable[0].MaxHandles);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530505 if (Status == EFI_SUCCESS && Ptable[0].MaxHandles > 0) {
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530506 MaxLuns = 1;
507 }
508 /* If the media is not emmc then look for UFS */
509 else if (EFI_ERROR (Status) || Ptable[0].MaxHandles == 0) {
510 /* By default max 8 luns are supported but HW could be configured to use only few of them or all of them
511 * Based on the information read update the MaxLuns to reflect the max supported luns */
512 for (i = 0 ; i < MAX_LUNS; i++) {
513 Ptable[i].MaxHandles = ARRAY_SIZE(Ptable[i].HandleInfoList);
lijuangf0bbcad2017-08-16 16:59:18 +0800514 HandleFilter.PartitionType = NULL;
515 HandleFilter.VolumeName = NULL;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530516 HandleFilter.RootDeviceType = &LunGuids[i];
517
518 Status = GetBlkIOHandles(Attribs, &HandleFilter, &Ptable[i].HandleInfoList[0], &Ptable[i].MaxHandles);
519 /* If we fail to get block for a lun that means the lun is not configured and unsed, ignore the error
520 * and continue with the next Lun */
521 if (EFI_ERROR (Status)) {
522 DEBUG((EFI_D_ERROR, "Error getting block IO handle for %d lun, Lun may be unused\n", i));
523 continue;
524 }
525 }
526 MaxLuns = i;
527 } else {
528 DEBUG((EFI_D_ERROR, "Error populating block IO handles\n"));
529 return EFI_NOT_FOUND;
530 }
531
532 return Status;
533}
534
535/*Function to provide has-slot info
536 *Pname: the partition name
537 *return: 1 or 0.
538 */
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530539BOOLEAN PartitionHasMultiSlot(CONST CHAR16 *Pname)
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530540{
541 UINT32 i;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530542 UINT32 SlotCount = 0;
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530543 UINT32 Len = StrLen(Pname);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530544
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530545 for (i = 0; i < PartitionCount; i++) {
Vijay Kumar Pendotieadfdf82016-10-17 19:37:54 +0530546 if(!(StrnCmp(PtnEntries[i].PartEntry.PartitionName, Pname, Len))) {
547 if (PtnEntries[i].PartEntry.PartitionName[Len] == L'_' &&
548 (PtnEntries[i].PartEntry.PartitionName[Len+1] == L'a' ||
549 PtnEntries[i].PartEntry.PartitionName[Len+1] == L'b'))
Vijay Kumar Pendotia38f5742017-01-17 20:05:10 +0530550 if (++SlotCount > MIN_SLOTS) {
551 return TRUE;
552 }
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530553 }
554 }
Vijay Kumar Pendotia38f5742017-01-17 20:05:10 +0530555 return FALSE;
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530556}
557
lijuangf0bbcad2017-08-16 16:59:18 +0800558VOID FindPtnActiveSlot(VOID)
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530559{
Shivaprasad Hongalc017e812017-04-26 16:15:27 -0700560 Slot ActiveSlot = {{0}};
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530561
Shivaprasad Hongalc017e812017-04-26 16:15:27 -0700562 GetActiveSlot(&ActiveSlot);
Vijay Kumar Pendotic3e0a4f2016-08-27 03:31:40 +0530563 return;
564}
565
lijuang94109952016-10-28 19:33:55 +0800566STATIC UINT32 PartitionVerifyMbrSignature(UINT32 Sz, UINT8 *Gpt)
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800567{
568 if ((MBR_SIGNATURE + 1) > Sz)
569 {
570 DEBUG((EFI_D_ERROR, "Gpt Image size is invalid\n"));
571 return FAILURE;
572 }
573
574 /* Check for the signature */
575 if ((Gpt[MBR_SIGNATURE] != MBR_SIGNATURE_BYTE_0) ||
576 (Gpt[MBR_SIGNATURE + 1] != MBR_SIGNATURE_BYTE_1))
577 {
578 DEBUG((EFI_D_ERROR, "MBR signature do not match\n"));
579 return FAILURE;
580 }
581 return SUCCESS;
582}
583
lijuang94109952016-10-28 19:33:55 +0800584STATIC UINT32 MbrGetPartitionType(UINT32 Sz, UINT8 *Gpt, UINT32 *Ptype)
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800585{
586 UINT32 PtypeOffset = MBR_PARTITION_RECORD + OS_TYPE;
587
588 if (Sz < (PtypeOffset + sizeof(*Ptype)))
589 {
590 DEBUG((EFI_D_ERROR, "Input gpt image does not have gpt partition record data\n"));
591 return FAILURE;
592 }
593
594 *Ptype = Gpt[PtypeOffset];
595
596 return SUCCESS;
597}
598
lijuang94109952016-10-28 19:33:55 +0800599STATIC UINT32 PartitionGetType(UINT32 Sz, UINT8 *Gpt, UINT32 *Ptype)
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800600{
lijuang94109952016-10-28 19:33:55 +0800601 UINT32 Ret;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800602
603 Ret = PartitionVerifyMbrSignature(Sz, Gpt);
604 if (!Ret)
605 {
606 /* MBR signature match, this coulb be MBR, MBR + EBR or GPT */
607 Ret = MbrGetPartitionType(Sz, Gpt, Ptype);
608 if (!Ret)
609 {
610 if (*Ptype == GPT_PROTECTIVE)
611 *Ptype = PARTITION_TYPE_GPT;
612 else
613 *Ptype = PARTITION_TYPE_MBR;
614 }
615 }
616 else
617 {
618 /* This could be GPT back up */
619 *Ptype = PARTITION_TYPE_GPT_BACKUP;
620 Ret = SUCCESS;
621 }
622
623 return Ret;
624}
625
lijuang94109952016-10-28 19:33:55 +0800626STATIC UINT32 ParseGptHeader(struct GptHeaderData *GptHeader, UINT8 *GptBuffer, UINT64 DeviceDensity, UINT32 BlkSz)
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800627{
628 UINT32 CrcOrig;
629 UINT32 CrcVal;
630 UINT32 CurrentLba;
631 EFI_STATUS Status;
632
633 if (((UINT32 *) GptBuffer)[0] != GPT_SIGNATURE_2 || ((UINT32 *) GptBuffer)[1] != GPT_SIGNATURE_1)
634 {
635 DEBUG((EFI_D_ERROR, "Gpt signature is not correct\n"));
636 return FAILURE;
637 }
638
639 GptHeader->HeaderSz = GET_LWORD_FROM_BYTE(&GptBuffer[HEADER_SIZE_OFFSET]);
640 /* Validate the header size */
641 if (GptHeader->HeaderSz < GPT_HEADER_SIZE)
642 {
643 DEBUG((EFI_D_ERROR, "GPT Header size is too small: %u\n", GptHeader->HeaderSz));
644 return FAILURE;
645 }
646
647 if (GptHeader->HeaderSz > BlkSz)
648 {
649 DEBUG((EFI_D_ERROR, "GPT Header is too large: %u\n", GptHeader->HeaderSz));
650 return FAILURE;
651 }
652
653 CrcOrig = GET_LWORD_FROM_BYTE(&GptBuffer[HEADER_CRC_OFFSET]);
654 /* CRC value is computed by setting this field to 0, and computing the 32-bit CRC for HeaderSize bytes */
655 CrcVal = 0;
656 PUT_LONG(&GptBuffer[HEADER_CRC_OFFSET], CrcVal);
657
658 Status = gBS->CalculateCrc32(GptBuffer, GptHeader->HeaderSz, &CrcVal);
659 if (Status != EFI_SUCCESS)
660 {
661 DEBUG((EFI_D_ERROR, "Error Calculating CRC32 on the Gpt header: %x\n", Status));
662 return FAILURE;
663 }
664
665 if (CrcVal != CrcOrig)
666 {
667 DEBUG((EFI_D_ERROR, "Header CRC mismatch CrcVal = %u and CrcOrig = %u\n", CrcVal, CrcOrig));
668 return FAILURE;
669 }
670 else
671 PUT_LONG(&GptBuffer[HEADER_CRC_OFFSET], CrcVal);
672
673 CurrentLba = GET_LLWORD_FROM_BYTE(&GptBuffer[PRIMARY_HEADER_OFFSET]);
674 GptHeader->FirstUsableLba = GET_LLWORD_FROM_BYTE(&GptBuffer[FIRST_USABLE_LBA_OFFSET]);
675 GptHeader->MaxPtCnt = GET_LWORD_FROM_BYTE(&GptBuffer[PARTITION_COUNT_OFFSET]);
676 GptHeader->PartEntrySz = GET_LWORD_FROM_BYTE(&GptBuffer[PENTRY_SIZE_OFFSET]);
677 GptHeader->LastUsableLba = GET_LLWORD_FROM_BYTE(&GptBuffer[LAST_USABLE_LBA_OFFSET]);
678 if (!ParseSecondaryGpt)
679 {
680 if (CurrentLba != GPT_LBA)
681 {
682 DEBUG((EFI_D_ERROR, "GPT first usable LBA mismatch\n"));
683 return FAILURE;
684 }
685 }
686
687 /* Check for first lba should be within valid range */
688 if (GptHeader->FirstUsableLba > (DeviceDensity / BlkSz))
689 {
690 DEBUG((EFI_D_ERROR, "FirstUsableLba: %u out of Device capacity\n", GptHeader->FirstUsableLba));
691 return FAILURE;
692 }
693
694 /* Check for Last lba should be within valid range */
695 if (GptHeader->LastUsableLba > (DeviceDensity / BlkSz))
696 {
697 DEBUG((EFI_D_ERROR, "LastUsableLba: %u out of device capacity\n", GptHeader->LastUsableLba));
698 return FAILURE;
699 }
700
701 if (GptHeader->PartEntrySz != GPT_PART_ENTRY_SIZE)
702 {
703 DEBUG((EFI_D_ERROR, "Invalid partition entry size: %u\n", GptHeader->PartEntrySz));
704 return FAILURE;
705 }
706
707 if (GptHeader->MaxPtCnt > (MIN_PARTITION_ARRAY_SIZE / (GptHeader->PartEntrySz)))
708 {
709 DEBUG((EFI_D_ERROR, "Invalid Max Partition Count: %u\n", GptHeader->MaxPtCnt));
710 return FAILURE;
711 }
712
713 /* Todo: Check CRC during reading partition table*/
714 if (!FlashingGpt)
715 {
716 }
717
718 return SUCCESS;
719}
720
lijuang94109952016-10-28 19:33:55 +0800721STATIC UINT32 PatchGpt (
722 UINT8 *Gpt, UINT64 DeviceDensity, UINT32 PartEntryArrSz,
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800723 struct GptHeaderData *GptHeader, UINT32 BlkSz)
724{
725 UINT8 *PrimaryGptHeader;
726 UINT8 *SecondaryGptHeader;
lijuang94109952016-10-28 19:33:55 +0800727 UINT64 NumSectors;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800728 UINT32 Offset;
729 UINT32 TotalPart = 0;
730 UINT32 LastPartOffset;
731 UINT8 *PartitionEntryArrStart;
732 UINT32 CrcVal;
733 EFI_STATUS Status;
734
735 NumSectors = DeviceDensity / BlkSz;
736
737 /* Update the primary and backup GPT header offset with the sector location */
738 PrimaryGptHeader = (Gpt + BlkSz);
739 /* Patch primary GPT */
Jeevan Shriram2d03b012017-05-22 09:01:41 -0700740 PUT_LONG_LONG(PrimaryGptHeader + BACKUP_HEADER_OFFSET, (UINT64) (NumSectors - 1));
741 PUT_LONG_LONG(PrimaryGptHeader + LAST_USABLE_LBA_OFFSET, (UINT64) (NumSectors - 34));
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800742
743 /* Patch Backup GPT */
744 Offset = (2 * PartEntryArrSz);
745 SecondaryGptHeader = Offset + BlkSz + PrimaryGptHeader;
Jeevan Shriram2d03b012017-05-22 09:01:41 -0700746 PUT_LONG_LONG(SecondaryGptHeader + PRIMARY_HEADER_OFFSET, (UINT64)1);
747 PUT_LONG_LONG(SecondaryGptHeader + LAST_USABLE_LBA_OFFSET, (UINT64) (NumSectors - 34));
748 PUT_LONG_LONG(SecondaryGptHeader + PARTITION_ENTRIES_OFFSET, (UINT64) (NumSectors - 33));
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800749
750 /* Patch the last partition */
751 while (*(PrimaryGptHeader + BlkSz + TotalPart * PARTITION_ENTRY_SIZE) != 0)
752 TotalPart++;
753
754 LastPartOffset = (TotalPart - 1) * PARTITION_ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA;
755
Jeevan Shriram2d03b012017-05-22 09:01:41 -0700756 PUT_LONG_LONG(PrimaryGptHeader + BlkSz + LastPartOffset, (UINT64) (NumSectors - 34));
757 PUT_LONG_LONG(PrimaryGptHeader + BlkSz + LastPartOffset + PartEntryArrSz, (UINT64) (NumSectors - 34));
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800758
759 /* Update CRC of the partition entry array for both headers */
760 PartitionEntryArrStart = PrimaryGptHeader + BlkSz;
761 Status = gBS->CalculateCrc32(PartitionEntryArrStart, (GptHeader->MaxPtCnt * GptHeader->PartEntrySz), &CrcVal);
762 if (EFI_ERROR(Status))
763 {
764 DEBUG((EFI_D_ERROR, "Error calculating CRC for primary partition entry\n"));
765 return FAILURE;
766 }
767 PUT_LONG(PrimaryGptHeader + PARTITION_CRC_OFFSET, CrcVal);
768
769 Status = gBS->CalculateCrc32(PartitionEntryArrStart + PartEntryArrSz, (GptHeader->MaxPtCnt * GptHeader->PartEntrySz), &CrcVal);
770 if (EFI_ERROR(Status))
771 {
772 DEBUG((EFI_D_ERROR, "Error calculating CRC for secondary partition entry\n"));
773 return FAILURE;
774 }
775 PUT_LONG(SecondaryGptHeader + PARTITION_CRC_OFFSET, CrcVal);
776
777 /* Clear Header CRC field values & recalculate */
778 PUT_LONG(PrimaryGptHeader + HEADER_CRC_OFFSET, 0);
779 Status = gBS->CalculateCrc32(PrimaryGptHeader, GPT_HEADER_SIZE, &CrcVal);
780 if (EFI_ERROR(Status))
781 {
782 DEBUG((EFI_D_ERROR, "Error calculating CRC for primary gpt header\n"));
783 return FAILURE;
784 }
785 PUT_LONG(PrimaryGptHeader + HEADER_CRC_OFFSET, CrcVal);
786 PUT_LONG(SecondaryGptHeader + HEADER_CRC_OFFSET, 0);
787 Status = gBS->CalculateCrc32(SecondaryGptHeader, GPT_HEADER_SIZE, &CrcVal);
788 if (EFI_ERROR(Status))
789 {
790 DEBUG((EFI_D_ERROR, "Error calculating CRC for secondary gpt header\n"));
791 return FAILURE;
792 }
793 PUT_LONG(SecondaryGptHeader + HEADER_CRC_OFFSET, CrcVal);
794
795 return SUCCESS;
796}
797
lijuang94109952016-10-28 19:33:55 +0800798STATIC UINT32 WriteGpt(INT32 Lun, UINT32 Sz, UINT8 *Gpt)
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800799{
lijuang94109952016-10-28 19:33:55 +0800800 UINT32 Ret = 1;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800801 struct GptHeaderData GptHeader;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800802 UINT8 *PartEntryArrSt;
803 UINT32 Offset;
804 UINT32 PartEntryArrSz;
lijuang94109952016-10-28 19:33:55 +0800805 UINT64 DeviceDensity;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800806 UINT32 BlkSz;
807 UINT8 *PrimaryGptHdr = NULL;
808 UINT8 *SecondaryGptHdr = NULL;
809 EFI_STATUS Status;
810 UINTN BackUpGptLba;
811 UINTN PartitionEntryLba;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800812 EFI_BLOCK_IO_PROTOCOL *BlockIo = NULL;
813 HandleInfo BlockIoHandle[MAX_HANDLEINF_LST_SIZE];
lijuang94109952016-10-28 19:33:55 +0800814 UINT32 MaxHandles = MAX_HANDLEINF_LST_SIZE;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800815
816 Ret = GetStorageHandle(Lun, BlockIoHandle, &MaxHandles);
817 if (Ret || (MaxHandles != 1))
818 {
819 DEBUG((EFI_D_ERROR, "Failed to get the BlockIo for the device\n"));
820 return Ret;
821 }
822
823 BlockIo = BlockIoHandle[0].BlkIo;
824 DeviceDensity = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
825 BlkSz = BlockIo->Media->BlockSize;
826
827 /* Verity that passed block has valid GPT primary header */
828 PrimaryGptHdr = (Gpt + BlkSz);
829 Ret = ParseGptHeader(&GptHeader, PrimaryGptHdr, DeviceDensity, BlkSz);
830 if (Ret)
831 {
832 DEBUG((EFI_D_ERROR, "GPT: Error processing primary GPT header\n"));
833 return Ret;
834 }
835
836 /* Check if a valid back up GPT is present */
837 PartEntryArrSz = GptHeader.PartEntrySz * GptHeader.MaxPtCnt;
838 if (PartEntryArrSz < MIN_PARTITION_ARRAY_SIZE)
839 PartEntryArrSz = MIN_PARTITION_ARRAY_SIZE;
840
841 /* Back up partition is stored in the reverse order with back GPT, followed by
842 * part entries, find the offset to back up GPT */
843 Offset = (2 * PartEntryArrSz);
844 SecondaryGptHdr = Offset + BlkSz + PrimaryGptHdr;
845 ParseSecondaryGpt = TRUE;
846
847 Ret = ParseGptHeader(&GptHeader, SecondaryGptHdr, DeviceDensity, BlkSz);
848 if (Ret)
849 {
850 DEBUG((EFI_D_ERROR, "GPT: Error processing backup GPT header\n"));
851 return Ret;
852 }
853
854 Ret = PatchGpt(Gpt, DeviceDensity, PartEntryArrSz, &GptHeader, BlkSz);
855 if (Ret)
856 {
857 DEBUG((EFI_D_ERROR, "Failed to patch GPT\n"));
858 return Ret;
859 }
860 /* Erase the entire card */
Channagoud Kadabid4c9c392016-10-17 23:42:16 -0700861 Status = ErasePartition(BlockIo, BlockIoHandle[0].Handle);
862 if (Status != EFI_SUCCESS) {
863 DEBUG((EFI_D_ERROR, "Error erasing the storage device: %r\n", Status));
864 return FAILURE;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800865 }
866
867 /* write the protective MBR */
868 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, 0, BlkSz, (VOID *)Gpt);
869 if (EFI_ERROR(Status))
870 {
871 DEBUG((EFI_D_ERROR, "Error writing protective MBR: %x\n", Status));
872 return FAILURE;
873 }
874
875 /* Write the primary GPT header, which is at an offset of BlkSz */
876 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, 1, BlkSz, (VOID *)PrimaryGptHdr);
877 if (EFI_ERROR(Status))
878 {
879 DEBUG((EFI_D_ERROR, "Error writing primary GPT header: %r\n", Status));
880 return FAILURE;
881 }
882
883 /* Write the back up GPT header */
884 BackUpGptLba = GET_LLWORD_FROM_BYTE(&PrimaryGptHdr[BACKUP_HEADER_OFFSET]);
885 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, BackUpGptLba, BlkSz, (VOID *)SecondaryGptHdr);
886 if (EFI_ERROR(Status))
887 {
888 DEBUG((EFI_D_ERROR, "Error writing secondary GPT header: %x\n", Status));
889 return FAILURE;
890 }
891
892 /* write Partition Entries for primary partition table*/
893 PartEntryArrSt = PrimaryGptHdr + BlkSz;
894 PartitionEntryLba = GET_LLWORD_FROM_BYTE(&PrimaryGptHdr[PARTITION_ENTRIES_OFFSET]);
895 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, PartitionEntryLba, PartEntryArrSz, (VOID *)PartEntryArrSt);
896 if (EFI_ERROR(Status))
897 {
898 DEBUG((EFI_D_ERROR, "Error writing partition entries array for Primary Table: %x\n", Status));
899 return FAILURE;
900 }
901
902 /* write Partition Entries for secondary partition table*/
903 PartEntryArrSt = PrimaryGptHdr + BlkSz + PartEntryArrSz;
904 PartitionEntryLba = GET_LLWORD_FROM_BYTE(&SecondaryGptHdr[PARTITION_ENTRIES_OFFSET]);
905 Status = BlockIo->WriteBlocks(BlockIo, BlockIo->Media->MediaId, PartitionEntryLba, PartEntryArrSz, (VOID *)PartEntryArrSt);
906 if (EFI_ERROR(Status))
907 {
908 DEBUG((EFI_D_ERROR, "Error writing partition entries array for Secondary Table: %x\n", Status));
909 return FAILURE;
910 }
911 FlashingGpt = 0;
lijuang886b75a2017-05-12 19:26:14 +0800912 gBS->SetMem((VOID *)PrimaryGptHdr, Sz, 0x0);
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800913
914 DEBUG((EFI_D_ERROR, "Updated Partition Table Successfully\n"));
915 return SUCCESS;
916}
917
lijuang94109952016-10-28 19:33:55 +0800918EFI_STATUS UpdatePartitionTable(UINT8 *GptImage, UINT32 Sz, INT32 Lun, struct StoragePartInfo *Ptable)
Channagoud Kadabif8aa7632015-11-12 14:27:01 -0800919{
920 EFI_STATUS Status = EFI_SUCCESS;
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800921 UINT32 Ptype;
lijuang94109952016-10-28 19:33:55 +0800922 UINT32 Ret;
Channagoud Kadabif8aa7632015-11-12 14:27:01 -0800923
924 /* Check if the partition type is GPT */
Channagoud Kadabi8ad76a72016-02-16 17:26:59 -0800925 Ret = PartitionGetType(Sz, GptImage, &Ptype);
926 if (Ret != 0)
927 {
928 DEBUG((EFI_D_ERROR, "Failed to get partition type from input gpt image\n"));
929 return EFI_NOT_FOUND;
930 }
931
932 switch (Ptype)
933 {
934 case PARTITION_TYPE_GPT:
935 DEBUG((EFI_D_INFO, "Updating GPT partition\n"));
936 FlashingGpt = TRUE;
937 Ret = WriteGpt(Lun, Sz, GptImage);
938 if (Ret != 0)
939 {
940 DEBUG((EFI_D_ERROR, "Failed to write Gpt partition: %x\n", Ret));
941 return EFI_VOLUME_CORRUPTED;
942 }
943 break;
944 default:
945 DEBUG((EFI_D_ERROR, "Invalid Partition type: %x\n",Ptype));
946 Status = EFI_UNSUPPORTED;
947 break;
948 }
949
Channagoud Kadabif8aa7632015-11-12 14:27:01 -0800950 return Status;
951}
Shivaprasad Hongale3b53392017-04-27 17:32:47 -0700952
Shivaprasad Hongalc017e812017-04-26 16:15:27 -0700953STATIC CONST struct PartitionEntry *GetPartitionEntry(CHAR16 *Partition)
954{
955 INT32 Index = GetPartitionIndex(Partition);
956
957 if (Index == INVALID_PTN) {
958 DEBUG((EFI_D_ERROR, "GetPartitionEntry: No partition entry for "
959 "%s, invalid index\n",
960 Partition));
961 return NULL;
962 }
963 return &PtnEntries[Index];
Shivaprasad Hongale3b53392017-04-27 17:32:47 -0700964}
Shivaprasad Hongalc017e812017-04-26 16:15:27 -0700965
966STATIC struct PartitionEntry *GetBootPartitionEntry(Slot *BootSlot)
967{
968 INT32 Index = INVALID_PTN;
969
970 if (StrnCmp(L"_a", BootSlot->Suffix, StrLen(BootSlot->Suffix)) == 0) {
971 Index = GetPartitionIndex(L"boot_a");
972 } else if (StrnCmp(L"_b", BootSlot->Suffix, StrLen(BootSlot->Suffix)) == 0) {
973 Index = GetPartitionIndex(L"boot_b");
974 } else {
975 DEBUG((EFI_D_ERROR, "GetBootPartitionEntry: No boot partition "
976 "entry for slot %s\n",
977 BootSlot->Suffix));
978 return NULL;
979 }
980
981 if (Index == INVALID_PTN) {
982 DEBUG((EFI_D_ERROR,
983 "GetBootPartitionEntry: No boot partition entry "
984 "for slot %s, invalid index\n",
985 BootSlot->Suffix));
986 return NULL;
987 }
988 return &PtnEntries[Index];
989}
990
lijuangf0bbcad2017-08-16 16:59:18 +0800991BOOLEAN IsCurrentSlotBootable(VOID)
Shivaprasad Hongalc017e812017-04-26 16:15:27 -0700992{
993 Slot CurrentSlot = {{0}};
994 struct PartitionEntry *BootPartition = NULL;
995 EFI_STATUS Status = GetActiveSlot(&CurrentSlot);
996
997 if (Status != EFI_SUCCESS) {
998 DEBUG((EFI_D_ERROR,
999 "IsCurrentSlotBootable: no active slots found!\n"));
1000 return FALSE;
1001 }
1002
1003 BootPartition = GetBootPartitionEntry(&CurrentSlot);
1004 if (BootPartition == NULL) {
1005 DEBUG((EFI_D_ERROR, "IsCurrentSlotBootable: No boot partition "
1006 "entry for slot %s\n",
1007 CurrentSlot.Suffix));
1008 return FALSE;
1009 }
1010 DEBUG((EFI_D_VERBOSE, "Slot suffix %s Part Attr 0x%lx\n",
1011 CurrentSlot.Suffix, BootPartition->PartEntry.Attributes));
1012
1013 if (!(BootPartition->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) &&
1014 BootPartition->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) {
1015 DEBUG((EFI_D_VERBOSE, "Slot %s is bootable\n", CurrentSlot.Suffix));
1016 return TRUE;
1017 }
1018
1019 DEBUG((EFI_D_VERBOSE, "Slot %s is unbootable \n", CurrentSlot.Suffix));
1020 return FALSE;
1021}
1022
1023BOOLEAN IsSuffixEmpty(Slot *CheckSlot)
1024{
1025 if (CheckSlot == NULL) {
1026 return TRUE;
1027 }
1028
1029 if (StrLen(CheckSlot->Suffix) == 0) {
1030 return TRUE;
1031 }
1032 return FALSE;
1033}
1034
1035STATIC EFI_STATUS GetActiveSlot(Slot *ActiveSlot)
1036{
1037 EFI_STATUS Status = EFI_SUCCESS;
1038 Slot Slots[] = {{L"_a"}, {L"_b"}};
1039 UINT64 Priority = 0;
1040
1041 if (ActiveSlot == NULL) {
1042 DEBUG((EFI_D_ERROR, "GetActiveSlot: bad parameter\n"));
1043 return EFI_INVALID_PARAMETER;
1044 }
1045
1046 for (UINTN SlotIndex = 0; SlotIndex < ARRAY_SIZE(Slots); SlotIndex++) {
1047 struct PartitionEntry *BootPartition =
1048 GetBootPartitionEntry(&Slots[SlotIndex]);
1049 UINT64 BootPriority = 0;
1050 if (BootPartition == NULL) {
1051 DEBUG((EFI_D_ERROR, "GetActiveSlot: No boot partition "
1052 "entry for slot %s\n",
1053 Slots[SlotIndex].Suffix));
1054 return EFI_NOT_FOUND;
1055 }
1056
1057 BootPriority = (BootPartition->PartEntry.Attributes &
1058 PART_ATT_PRIORITY_VAL) >>
1059 PART_ATT_PRIORITY_BIT;
1060
1061 if ((BootPartition->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) &&
1062 (BootPriority > Priority)) {
1063 GUARD(StrnCpyS(ActiveSlot->Suffix, ARRAY_SIZE(ActiveSlot->Suffix),
1064 Slots[SlotIndex].Suffix,
1065 StrLen(Slots[SlotIndex].Suffix)));
1066 Priority = BootPriority;
1067 }
1068 }
1069
1070 DEBUG((EFI_D_VERBOSE, "GetActiveSlot: found active slot %s, priority %d\n",
1071 ActiveSlot->Suffix, Priority));
1072
1073 if (IsSuffixEmpty(ActiveSlot) == TRUE) {
1074 /* Check for first boot and set default slot */
1075 /* For First boot all A/B attributes for the slot would be 0 */
1076 UINT64 BootPriority = 0;
1077 UINT64 RetryCount = 0;
1078 struct PartitionEntry *SlotA = GetBootPartitionEntry(&Slots[0]);
1079 if (SlotA == NULL) {
1080 DEBUG((EFI_D_ERROR,
1081 "GetActiveSlot: First Boot: No boot partition "
1082 "entry for slot %s\n",
1083 Slots[0].Suffix));
1084 return EFI_NOT_FOUND;
1085 }
1086
1087 BootPriority =
1088 (SlotA->PartEntry.Attributes & PART_ATT_PRIORITY_VAL) >>
1089 PART_ATT_PRIORITY_BIT;
1090 RetryCount = (SlotA->PartEntry.Attributes &
1091 PART_ATT_MAX_RETRY_COUNT_VAL) >>
1092 PART_ATT_MAX_RETRY_CNT_BIT;
1093
1094 if ((SlotA->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) == 0 &&
1095 (SlotA->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) == 0 &&
1096 (SlotA->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) == 0 &&
1097 BootPriority == 0) {
1098
1099 DEBUG((EFI_D_INFO, "GetActiveSlot: First boot: set "
1100 "default slot _a\n"));
1101 SlotA->PartEntry.Attributes &=
1102 (~PART_ATT_SUCCESSFUL_VAL & ~PART_ATT_UNBOOTABLE_VAL);
1103 SlotA->PartEntry.Attributes |=
1104 (PART_ATT_PRIORITY_VAL | PART_ATT_ACTIVE_VAL |
1105 PART_ATT_MAX_RETRY_COUNT_VAL);
1106
1107 GUARD(StrnCpyS(ActiveSlot->Suffix, ARRAY_SIZE(ActiveSlot->Suffix),
1108 Slots[0].Suffix, StrLen(Slots[0].Suffix)));
1109 UpdatePartitionAttributes();
Shivaprasad Hongal340f6872017-04-26 16:15:27 -07001110 FirstBoot = TRUE;
Shivaprasad Hongalc017e812017-04-26 16:15:27 -07001111 return EFI_SUCCESS;
1112 }
1113
1114 DEBUG((EFI_D_ERROR, "GetActiveSlot: No active slot found\n"));
1115 DEBUG((EFI_D_ERROR,
1116 "GetActiveSlot: Slot attr: Priority %ld, Retry "
1117 "%ld, Active %ld, Success %ld, unboot %ld\n",
1118 BootPriority, RetryCount,
1119 (SlotA->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) >> PART_ATT_ACTIVE_BIT,
1120 (SlotA->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL),
1121 (SlotA->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL)));
1122
1123 return EFI_NOT_FOUND;
1124 }
1125
1126 return EFI_SUCCESS;
1127}
1128
1129EFI_STATUS SetActiveSlot(Slot *NewSlot)
1130{
1131 EFI_STATUS Status = EFI_SUCCESS;
1132 Slot CurrentSlot = {{0}};
Jeevan Shrirame8bc92d2017-07-06 05:48:23 -07001133 Slot *AlternateSlot = NULL;
1134 Slot Slots[] = {{L"_a"}, {L"_b"}};
Shivaprasad Hongalc017e812017-04-26 16:15:27 -07001135 struct PartitionEntry *BootEntry = NULL;
1136
1137 if (NewSlot == NULL) {
1138 DEBUG((EFI_D_ERROR,
1139 "SetActiveSlot: input parameter invalid\n"));
1140 return EFI_INVALID_PARAMETER;
1141 }
1142
1143 GUARD(GetActiveSlot(&CurrentSlot));
1144
Jeevan Shrirame8bc92d2017-07-06 05:48:23 -07001145 if (StrnCmp(NewSlot->Suffix, Slots[0].Suffix, StrLen(Slots[0].Suffix)) == 0) {
1146 AlternateSlot = &Slots[1];
1147 } else {
1148 AlternateSlot = &Slots[0];
Shivaprasad Hongalc017e812017-04-26 16:15:27 -07001149 }
1150
1151 BootEntry = GetBootPartitionEntry(NewSlot);
1152 if (BootEntry == NULL) {
1153 DEBUG((EFI_D_ERROR,
1154 "SetActiveSlot: No boot partition entry for slot %s\n",
1155 NewSlot->Suffix));
1156 return EFI_NOT_FOUND;
1157 }
1158
1159 BootEntry->PartEntry.Attributes |= (PART_ATT_PRIORITY_VAL | PART_ATT_ACTIVE_VAL |
1160 PART_ATT_MAX_RETRY_COUNT_VAL);
1161 BootEntry->PartEntry.Attributes &=
1162 (~PART_ATT_SUCCESSFUL_VAL & ~PART_ATT_UNBOOTABLE_VAL);
1163
Jeevan Shrirame8bc92d2017-07-06 05:48:23 -07001164 /* Reduce the priority and clear the active flag for alternate slot*/
1165 BootEntry = GetBootPartitionEntry(AlternateSlot);
Shivaprasad Hongalc017e812017-04-26 16:15:27 -07001166 if (BootEntry == NULL) {
1167 DEBUG((EFI_D_ERROR,
1168 "SetActiveSlot: No boot partition entry for slot %s\n",
Jeevan Shrirame8bc92d2017-07-06 05:48:23 -07001169 AlternateSlot->Suffix));
Shivaprasad Hongalc017e812017-04-26 16:15:27 -07001170 return EFI_NOT_FOUND;
1171 }
1172
1173 BootEntry->PartEntry.Attributes &=
1174 (~PART_ATT_PRIORITY_VAL & ~PART_ATT_ACTIVE_VAL);
1175 BootEntry->PartEntry.Attributes |=
1176 (((UINT64)MAX_PRIORITY - 1) << PART_ATT_PRIORITY_BIT);
1177
Jeevan Shrirame8bc92d2017-07-06 05:48:23 -07001178 if (StrnCmp(CurrentSlot.Suffix, NewSlot->Suffix,
1179 StrLen(CurrentSlot.Suffix)) == 0) {
1180 /* This Slot is already active do nothing */
1181 DEBUG((EFI_D_INFO, "SetActiveSlot: %s already active slot\n",
1182 NewSlot->Suffix));
1183 } else {
1184 DEBUG((EFI_D_INFO, "Alternate slot %s, New slot %s\n", AlternateSlot->Suffix,
1185 NewSlot->Suffix));
1186 SwitchPtnSlots(NewSlot->Suffix);
1187 }
Shivaprasad Hongalc017e812017-04-26 16:15:27 -07001188
Shivaprasad Hongalc017e812017-04-26 16:15:27 -07001189 UpdatePartitionAttributes();
1190
1191 return EFI_SUCCESS;
1192}
1193
lijuangf0bbcad2017-08-16 16:59:18 +08001194EFI_STATUS HandleActiveSlotUnbootable(VOID)
Shivaprasad Hongalc017e812017-04-26 16:15:27 -07001195{
1196 EFI_STATUS Status = EFI_SUCCESS;
1197 struct PartitionEntry *BootEntry = NULL;
1198 Slot ActiveSlot = {{0}};
1199 Slot *AlternateSlot = NULL;
1200 Slot Slots[] = {{L"_a"}, {L"_b"}};
1201 UINT64 Unbootable = 0;
1202 UINT64 BootSuccess = 0;
1203
1204 /* Mark current Slot as unbootable */
1205 GUARD(GetActiveSlot(&ActiveSlot));
1206 BootEntry = GetBootPartitionEntry(&ActiveSlot);
1207 if (BootEntry == NULL) {
1208 DEBUG((EFI_D_ERROR, "HandleActiveSlotUnbootable: No boot "
1209 "partition entry for slot %s\n",
1210 ActiveSlot.Suffix));
1211 return EFI_NOT_FOUND;
1212 }
1213
Shivaprasad Hongal340f6872017-04-26 16:15:27 -07001214 if (FirstBoot && !TargetBuildVariantUser()) {
1215 DEBUG((EFI_D_VERBOSE, "FirstBoot, skipping slot Unbootable\n"));
1216 FirstBoot = FALSE;
1217 } else {
1218 BootEntry->PartEntry.Attributes |=
1219 (PART_ATT_UNBOOTABLE_VAL) & (~PART_ATT_SUCCESSFUL_VAL);
1220 UpdatePartitionAttributes();
1221 }
Shivaprasad Hongalc017e812017-04-26 16:15:27 -07001222
1223 if (StrnCmp(ActiveSlot.Suffix, Slots[0].Suffix, StrLen(Slots[0].Suffix)) == 0) {
1224 AlternateSlot = &Slots[1];
1225 } else {
1226 AlternateSlot = &Slots[0];
1227 }
1228
1229 /* Validate Aternate Slot is bootable */
1230 BootEntry = GetBootPartitionEntry(AlternateSlot);
1231 if (BootEntry == NULL) {
1232 DEBUG((EFI_D_ERROR, "HandleActiveSlotUnbootable: No boot "
1233 "partition entry for slot %s\n",
1234 AlternateSlot->Suffix));
1235 return EFI_NOT_FOUND;
1236 }
1237
1238 Unbootable = (BootEntry->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) >>
1239 PART_ATT_UNBOOTABLE_BIT;
1240 BootSuccess = (BootEntry->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) >>
1241 PART_ATT_SUCCESS_BIT;
1242
1243 if (Unbootable == 0 && BootSuccess == 1) {
1244 DEBUG((EFI_D_INFO, "Alternate Slot %s is bootable\n",
1245 AlternateSlot->Suffix));
1246 GUARD(SetActiveSlot(AlternateSlot));
1247
1248 DEBUG((EFI_D_INFO, "HandleActiveSlotUnbootable: Rebooting\n"));
1249 gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
1250
1251 // Shouldn't get here
1252 DEBUG((EFI_D_ERROR, "HandleActiveSlotUnbootable: "
1253 "gRT->Resetystem didn't work\n"));
1254 return EFI_LOAD_ERROR;
1255 }
1256
1257 return EFI_LOAD_ERROR;
1258}
1259
lijuangf0bbcad2017-08-16 16:59:18 +08001260EFI_STATUS ClearUnbootable(VOID)
Zhen Kong4c788f52017-07-19 16:51:58 -07001261{
1262 EFI_STATUS Status = EFI_SUCCESS;
1263 Slot ActiveSlot = {{0}};
1264 struct PartitionEntry *BootEntry = NULL;
1265
1266 Status = GetActiveSlot(&ActiveSlot);
1267 if(Status != EFI_SUCCESS) {
1268 DEBUG((EFI_D_ERROR, "ClearUnbootable: GetActiveSlot failed.\n"));
1269 return Status;
1270 }
1271 BootEntry = GetBootPartitionEntry(&ActiveSlot);
1272 if (BootEntry == NULL) {
1273 DEBUG((EFI_D_ERROR, "ClearUnbootable: No boot partition entry for slot %s\n", ActiveSlot.Suffix));
1274 return EFI_NOT_FOUND;
1275 }
1276 BootEntry->PartEntry.Attributes &= ~PART_ATT_UNBOOTABLE_VAL;
1277 UpdatePartitionAttributes();
1278 return EFI_SUCCESS;
1279}
1280
Shivaprasad Hongalc017e812017-04-26 16:15:27 -07001281STATIC EFI_STATUS ValidateSlotGuids(Slot *BootableSlot)
1282{
1283 EFI_STATUS Status = EFI_SUCCESS;
1284 struct PartitionEntry *BootEntry = NULL;
1285 CHAR16 SystemPartitionName[] = L"system_x";
1286 CONST struct PartitionEntry *SystemEntry = NULL;
1287 CHAR8 BootDeviceType[BOOT_DEV_NAME_SIZE_MAX];
1288 UINT32 UfsBootLun = 0;
1289
1290 BootEntry = GetBootPartitionEntry(BootableSlot);
1291 if (BootEntry == NULL) {
1292 DEBUG((EFI_D_ERROR, "ValidateSlotGuids: No boot partition "
1293 "entry for slot %s\n",
1294 BootableSlot->Suffix));
1295 return EFI_NOT_FOUND;
1296 }
1297
1298 SystemPartitionName[StrLen(SystemPartitionName) - 1] =
1299 BootableSlot->Suffix[StrLen(BootableSlot->Suffix) - 1];
1300 SystemEntry = GetPartitionEntry(SystemPartitionName);
1301 if (SystemEntry == NULL) {
1302 DEBUG((EFI_D_ERROR,
1303 "ValidateSlotGuids: No partition entry for %s\n",
1304 SystemPartitionName));
1305 return EFI_NOT_FOUND;
1306 }
1307
1308 if (CompareMem(&BootEntry->PartEntry.PartitionTypeGUID,
1309 &SystemEntry->PartEntry.PartitionTypeGUID,
1310 sizeof(EFI_GUID)) == 0) {
1311 DEBUG((EFI_D_ERROR, "ValidateSlotGuids: BootableSlot %s does "
1312 "not have valid guids\n",
1313 BootableSlot->Suffix));
1314 DEBUG((EFI_D_INFO, "Boot GUID %g\n",
1315 &BootEntry->PartEntry.PartitionTypeGUID));
1316 DEBUG((EFI_D_INFO, "System GUID %g\n",
1317 &SystemEntry->PartEntry.PartitionTypeGUID));
1318 return EFI_DEVICE_ERROR;
1319 }
1320
1321 GetRootDeviceType(BootDeviceType, BOOT_DEV_NAME_SIZE_MAX);
1322 if (!AsciiStrnCmp(BootDeviceType, "UFS", AsciiStrLen("UFS"))) {
1323 GUARD(UfsGetSetBootLun(&UfsBootLun, TRUE));
1324 if (UfsBootLun == 0x1 && !StrCmp(BootableSlot->Suffix, L"_a")) {
1325 } else if (UfsBootLun == 0x2 && !StrCmp(BootableSlot->Suffix, L"_b")) {
1326 } else {
1327 DEBUG((EFI_D_ERROR, "Boot lun: %x and BootableSlot: %s "
1328 "do not match\n",
1329 UfsBootLun, BootableSlot->Suffix));
1330 return EFI_DEVICE_ERROR;
1331 }
1332 } else if (!AsciiStrnCmp(BootDeviceType, "EMMC", AsciiStrLen("EMMC"))) {
1333 } else {
1334 DEBUG((EFI_D_ERROR, "Unsupported Device Type\n"));
1335 return EFI_DEVICE_ERROR;
1336 }
1337
1338 DEBUG((EFI_D_INFO, "Booting from slot (%s)\n", BootableSlot->Suffix));
1339 return EFI_SUCCESS;
1340}
1341
1342EFI_STATUS FindBootableSlot(Slot *BootableSlot)
1343{
1344 EFI_STATUS Status = EFI_SUCCESS;
1345 struct PartitionEntry *BootEntry = NULL;
1346 UINT64 Unbootable = 0;
1347 UINT64 BootSuccess = 0;
1348 UINT64 RetryCount = 0;
1349
1350 if (BootableSlot == NULL) {
1351 DEBUG((EFI_D_ERROR,
1352 "FindBootableSlot: input parameter invalid\n"));
1353 return EFI_INVALID_PARAMETER;
1354 }
1355
1356 GUARD_OUT(GetActiveSlot(BootableSlot));
1357
1358 /* Validate Active Slot is bootable */
1359 BootEntry = GetBootPartitionEntry(BootableSlot);
1360 if (BootEntry == NULL) {
1361 DEBUG((EFI_D_ERROR, "FindBootableSlot: No boot partition entry "
1362 "for slot %s\n",
1363 BootableSlot->Suffix));
1364 return EFI_NOT_FOUND;
1365 }
1366
1367 Unbootable = (BootEntry->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) >>
1368 PART_ATT_UNBOOTABLE_BIT;
1369 BootSuccess = (BootEntry->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) >>
1370 PART_ATT_SUCCESS_BIT;
1371 RetryCount =
1372 (BootEntry->PartEntry.Attributes & PART_ATT_MAX_RETRY_COUNT_VAL) >>
1373 PART_ATT_MAX_RETRY_CNT_BIT;
1374
1375 if (Unbootable == 0 && BootSuccess == 1) {
1376 DEBUG((EFI_D_VERBOSE, "Active Slot %s is bootable\n",
1377 BootableSlot->Suffix));
1378 } else if (Unbootable == 0 && BootSuccess == 0 && RetryCount > 0) {
Channagoud Kadabi6a54fe12017-06-02 17:00:56 -07001379 if (!IsBootDevImage()) {
1380 RetryCount--;
1381 BootEntry->PartEntry.Attributes &= ~PART_ATT_MAX_RETRY_COUNT_VAL;
1382 BootEntry->PartEntry.Attributes |=
1383 RetryCount << PART_ATT_MAX_RETRY_CNT_BIT;
1384 UpdatePartitionAttributes();
1385 DEBUG((EFI_D_INFO,
1386 "Active Slot %s is bootable, retry count %ld\n",
1387 BootableSlot->Suffix, RetryCount));
1388 }
Shivaprasad Hongalc017e812017-04-26 16:15:27 -07001389 } else {
1390 DEBUG((EFI_D_INFO,
Shivaprasad Hongal7fd6a522017-05-10 13:56:28 -07001391 "Slot %s is unbootable, trying alternate slot\n",
Shivaprasad Hongalc017e812017-04-26 16:15:27 -07001392 BootableSlot->Suffix));
1393 GUARD_OUT(HandleActiveSlotUnbootable());
1394 }
1395
1396 /* Validate slot suffix and partition guids */
1397 if (Status == EFI_SUCCESS) {
1398 GUARD_OUT(ValidateSlotGuids(BootableSlot));
1399 }
1400 MarkPtnActive(BootableSlot->Suffix);
1401out:
1402 if (Status != EFI_SUCCESS) {
1403 /* clear bootable slot */
1404 BootableSlot->Suffix[0] = '\0';
1405 }
1406 return Status;
Vijay Kumar Pendoti644a20b2017-03-15 18:22:17 +05301407}
1408
1409/*Function to provide Dtbo Present info
1410 *return: TRUE or FALSE.
1411 */
Vijay Kumar Pendoti6fc41c42017-05-09 19:41:26 +05301412BOOLEAN LoadAndValidateDtboImg(BootInfo *Info, VOID** DtboImgBuffer)
Vijay Kumar Pendoti644a20b2017-03-15 18:22:17 +05301413{
Vijay Kumar Pendoti4229f7b2017-05-08 21:32:39 +05301414 UINTN DtboImgSize = 0;
Vijay Kumar Pendoti4229f7b2017-05-08 21:32:39 +05301415 EFI_STATUS Status = EFI_SUCCESS;
1416 struct DtboTableHdr* DtboTableHdr = NULL;
Vijay Kumar Pendoti644a20b2017-03-15 18:22:17 +05301417
Vijay Kumar Pendoti6fc41c42017-05-09 19:41:26 +05301418 Status = GetImage(Info, DtboImgBuffer, &DtboImgSize, "dtbo");
1419 if (Status != EFI_SUCCESS) {
1420 DEBUG((EFI_D_ERROR, "BootLinux: GetImage failed!"));
1421 return FALSE;
Vijay Kumar Pendoti644a20b2017-03-15 18:22:17 +05301422 }
Vijay Kumar Pendoti6fc41c42017-05-09 19:41:26 +05301423 if (!DtboImgBuffer) {
1424 DEBUG((EFI_D_ERROR, "DtboImgBuffer is NULL"));
1425 return FALSE;
1426 }
1427
1428 DtboTableHdr = *DtboImgBuffer;
1429 if (fdt32_to_cpu(DtboTableHdr->Magic) != DTBO_TABLE_MAGIC) {
1430 DEBUG((EFI_D_ERROR, "Dtbo hdr magic mismatch %x, with %x\n", DtboTableHdr->Magic, DTBO_TABLE_MAGIC));
1431 return FALSE;
1432 }
1433
1434 if (DtboImgSize > DTBO_MAX_SIZE_ALLOWED) {
1435 DEBUG((EFI_D_ERROR, "Dtbo Size too big %x, Allowed size %x\n", DtboImgSize,DTBO_MAX_SIZE_ALLOWED));
1436 return FALSE;
1437 }
1438
1439 /*Check for TotalSize of Dtbo image*/
1440 if ((fdt32_to_cpu(DtboTableHdr->TotalSize) > DTBO_MAX_SIZE_ALLOWED) || (fdt32_to_cpu(DtboTableHdr->TotalSize) == 0)) {
1441 DEBUG((EFI_D_ERROR, "Dtbo Table TotalSize got corrupted\n"));
1442 return FALSE;
1443 }
1444
1445 /*Check for HeaderSize of Dtbo image*/
1446 if (fdt32_to_cpu(DtboTableHdr->HeaderSize) != sizeof(struct DtboTableHdr)) {
1447 DEBUG((EFI_D_ERROR, "Dtbo Table HeaderSize got corrupted\n"));
1448 return FALSE;
1449 }
1450
1451 /*Check for DtEntrySize of Dtbo image*/
1452 if (fdt32_to_cpu(DtboTableHdr->DtEntrySize) != sizeof(struct DtboTableEntry)) {
1453 DEBUG((EFI_D_ERROR, "Dtbo Table DtEntrySize got corrupted\n"));
1454 return FALSE;
1455 }
1456
1457 /*Check for DtEntryOffset of Dtbo image*/
1458 if (fdt32_to_cpu(DtboTableHdr->DtEntryOffset) > DTBO_MAX_SIZE_ALLOWED) {
1459 DEBUG((EFI_D_ERROR, "Dtbo Table DtEntryOffset got corrupted\n"));
1460 return FALSE;
1461 }
1462
1463 return TRUE;
Vijay Kumar Pendoti644a20b2017-03-15 18:22:17 +05301464}