1 /** @file
2 *
3 *  Copyright (c) 2015, Linaro Ltd. All rights reserved.
4 *  Copyright (c) 2015, Hisilicon Ltd. All rights reserved.
5 *
6 *  This program and the accompanying materials
7 *  are licensed and made available under the terms and conditions of the BSD License
8 *  which accompanies this distribution.  The full text of the license may be found at
9 *  http://opensource.org/licenses/bsd-license.php
10 *
11 *  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 *
14 **/
15 
16 #include <Library/BaseMemoryLib.h>
17 #include <Library/BdsLib.h>
18 #include <Library/CacheMaintenanceLib.h>
19 #include <Library/DevicePathLib.h>
20 #include <Library/DxeServicesLib.h>
21 #include <Library/IoLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/PrintLib.h>
24 #include <Library/UefiBootServicesTableLib.h>
25 #include <Library/UefiLib.h>
26 #include <Library/UefiRuntimeServicesTableLib.h>
27 
28 #include <Protocol/BlockIo.h>
29 #include <Protocol/DevicePathFromText.h>
30 #include <Protocol/DevicePathToText.h>
31 #include <Protocol/DwUsb.h>
32 #include <Protocol/EmbeddedGpio.h>
33 #include <Protocol/SimpleFileSystem.h>
34 
35 #include <Guid/Fdt.h>
36 #include <Guid/FileInfo.h>
37 #include <Guid/EventGroup.h>
38 #include <Guid/GlobalVariable.h>
39 #include <Guid/HiKeyVariable.h>
40 #include <Guid/VariableFormat.h>
41 
42 #include "HiKeyDxeInternal.h"
43 
44 typedef enum {
45   HIKEY_DTB_ANDROID = 0,	/* DTB is attached at the end of boot.img */
46   HIKEY_DTB_LINUX = 1,		/* DTB is in partition */
47   HIKEY_DTB_SD = 2,		/* DTB is already in SD Card */
48 } HiKeyDtbType;
49 
50 #define HIKEY_IO_BLOCK_SIZE      512
51 
52 #define MAX_BOOT_ENTRIES         16
53 // Jumper on pin5-6 of J15 determines whether boot to fastboot
54 #define DETECT_J15_FASTBOOT      24    // GPIO 3_0
55 
56 #define USER_LED1                32    // GPIO 4_0
57 #define USER_LED2                33    // GPIO 4_1
58 #define USER_LED3                34    // GPIO 4_2
59 #define USER_LED4                35    // GPIO 4_3
60 
61 struct HiKeyBootEntry {
62   CHAR16    *Path;
63   CHAR16    *Args;
64   CHAR16    *Description;
65   UINT16     LoadType;
66 };
67 
68 STATIC CONST BOOLEAN mIsEndOfDxeEvent = TRUE;
69 STATIC UINT16 *mBootOrder = NULL;
70 STATIC UINT16 mBootCount = 0;
71 STATIC UINT16 mBootIndex = 0;
72 
73 #define HIKEY_BOOT_ENTRY_FASTBOOT          0
74 #define HIKEY_BOOT_ENTRY_BOOT_EMMC         1    /* boot from eMMC */
75 #define HIKEY_BOOT_ENTRY_BOOT_SD           2    /* boot from SD card */
76 
77 STATIC struct HiKeyBootEntry LinuxEntries[] = {
78   [HIKEY_BOOT_ENTRY_FASTBOOT] = {
79     L"FvFile(9588502a-5370-11e3-8631-d7c5951364c8)",
80     //L"VenHw(B549F005-4BD4-4020-A0CB-06F42BDA68C3)/HD(6,GPT,5C0F213C-17E1-4149-88C8-8B50FB4EC70E,0x7000,0x20000)/\\EFI\\BOOT\\FASTBOOT.EFI",
81     NULL,
82     L"fastboot",
83     LOAD_OPTION_CATEGORY_APP
84   },
85   [HIKEY_BOOT_ENTRY_BOOT_EMMC] = {
86     L"VenHw(B549F005-4BD4-4020-A0CB-06F42BDA68C3)/HD(6,GPT,5C0F213C-17E1-4149-88C8-8B50FB4EC70E,0x7000,0x20000)/\\EFI\\BOOT\\GRUBAA64.EFI",
87     NULL,
88     L"boot from eMMC",
89     LOAD_OPTION_CATEGORY_APP
90   },
91   [HIKEY_BOOT_ENTRY_BOOT_SD] = {
92     L"VenHw(594BFE73-5E18-4F12-8119-19DB8C5FC849)/HD(1,MBR,0x00000000,0x3F,0x21FC0)/\\EFI\\BOOT\\BOOTAA64.EFI",
93     NULL,
94     L"boot from SD card",
95     LOAD_OPTION_CATEGORY_BOOT
96   }
97 };
98 
99 STATIC struct HiKeyBootEntry AndroidEntries[] = {
100   [HIKEY_BOOT_ENTRY_FASTBOOT] = {
101     L"FvFile(9588502a-5370-11e3-8631-d7c5951364c8)",
102     //L"VenHw(B549F005-4BD4-4020-A0CB-06F42BDA68C3)/HD(6,GPT,5C0F213C-17E1-4149-88C8-8B50FB4EC70E,0x7000,0x20000)/\\EFI\\BOOT\\FASTBOOT.EFI",
103     NULL,
104     L"fastboot",
105     LOAD_OPTION_CATEGORY_APP
106   },
107   [HIKEY_BOOT_ENTRY_BOOT_EMMC] = {
108     L"VenHw(B549F005-4BD4-4020-A0CB-06F42BDA68C3)/HD(6,GPT,5C0F213C-17E1-4149-88C8-8B50FB4EC70E,0x7000,0x20000)/Offset(0x0000,0x20000)",
109     L"console=ttyAMA3,115200 earlycon=pl011,0xf7113000 root=/dev/mmcblk0p9 rw rootwait efi=noruntime",
110     L"boot from eMMC",
111     LOAD_OPTION_CATEGORY_BOOT
112   },
113   [HIKEY_BOOT_ENTRY_BOOT_SD] = {
114     L"VenHw(594BFE73-5E18-4F12-8119-19DB8C5FC849)/HD(1,MBR,0x00000000,0x3F,0x21FC0)/Image",
115     L"dtb=hi6220-hikey.dtb console=ttyAMA3,115200 earlycon=pl011,0xf7113000 root=/dev/mmcblk1p2 rw rootwait initrd=initrd.img efi=noruntime",
116     L"boot from SD card",
117     LOAD_OPTION_CATEGORY_BOOT
118   }
119 };
120 
121 
122 STATIC
123 BOOLEAN
124 EFIAPI
HiKeyVerifyBootEntry(IN CHAR16 * BootVariableName,IN CHAR16 * BootDevicePathText,IN CHAR16 * BootArgs,IN CHAR16 * BootDescription,IN UINT16 LoadOptionAttr)125 HiKeyVerifyBootEntry (
126   IN CHAR16          *BootVariableName,
127   IN CHAR16          *BootDevicePathText,
128   IN CHAR16          *BootArgs,
129   IN CHAR16          *BootDescription,
130   IN UINT16           LoadOptionAttr
131   )
132 {
133   EFI_DEVICE_PATH_TO_TEXT_PROTOCOL   *DevicePathToTextProtocol;
134   CHAR16                             *DevicePathText;
135   UINTN                               EfiLoadOptionSize;
136   EFI_LOAD_OPTION                    *EfiLoadOption;
137   BDS_LOAD_OPTION                    *LoadOption;
138   EFI_STATUS                          Status;
139   UINTN                               DescriptionLength;
140 
141   Status = GetGlobalEnvironmentVariable (BootVariableName, NULL, &EfiLoadOptionSize, (VOID**)&EfiLoadOption);
142   if (EFI_ERROR (Status)) {
143     return FALSE;
144   }
145   if (EfiLoadOption == NULL) {
146     return FALSE;
147   }
148   if (EfiLoadOptionSize < sizeof(UINT32) + sizeof(UINT16) + sizeof(CHAR16) + sizeof(EFI_DEVICE_PATH_PROTOCOL)) {
149     return FALSE;
150   }
151   LoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
152   if (LoadOption == NULL) {
153     return FALSE;
154   }
155 
156   LoadOption->LoadOption         = EfiLoadOption;
157   LoadOption->Attributes         = *(UINT32*)EfiLoadOption;
158   LoadOption->FilePathListLength = *(UINT16*)(EfiLoadOption + sizeof(UINT32));
159   LoadOption->Description        = (CHAR16*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16));
160   DescriptionLength              = StrSize (LoadOption->Description);
161   LoadOption->FilePathList       = (EFI_DEVICE_PATH_PROTOCOL*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16) + DescriptionLength);
162   if ((UINTN)((UINTN)LoadOption->FilePathList + LoadOption->FilePathListLength - (UINTN)EfiLoadOption) == EfiLoadOptionSize) {
163     LoadOption->OptionalData     = NULL;
164     LoadOption->OptionalDataSize = 0;
165   } else {
166     LoadOption->OptionalData     = (VOID*)((UINTN)(LoadOption->FilePathList) + LoadOption->FilePathListLength);
167     LoadOption->OptionalDataSize = EfiLoadOptionSize - ((UINTN)LoadOption->OptionalData - (UINTN)EfiLoadOption);
168   }
169 
170   if (((BootArgs == NULL) && (LoadOption->OptionalDataSize)) ||
171       (BootArgs && (LoadOption->OptionalDataSize == 0))) {
172     return FALSE;
173   } else if (BootArgs && LoadOption->OptionalDataSize) {
174     if (StrCmp (BootArgs, LoadOption->OptionalData) != 0)
175       return FALSE;
176   }
177   if ((LoadOption->Description == NULL) || (BootDescription == NULL)) {
178     return FALSE;
179   }
180   if (StrCmp (BootDescription, LoadOption->Description) != 0) {
181     return FALSE;
182   }
183   if ((LoadOption->Attributes & LOAD_OPTION_CATEGORY) != (LoadOptionAttr & LOAD_OPTION_CATEGORY)) {
184     return FALSE;
185   }
186 
187   Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
188   ASSERT_EFI_ERROR(Status);
189   DevicePathText = DevicePathToTextProtocol->ConvertDevicePathToText(LoadOption->FilePathList, TRUE, TRUE);
190   if (StrCmp (DevicePathText, BootDevicePathText) != 0) {
191     return FALSE;
192   }
193 
194   FreePool (LoadOption);
195   return TRUE;
196 }
197 
198 STATIC
199 EFI_STATUS
200 EFIAPI
HiKeyCreateBootEntry(IN CHAR16 * DevicePathText,IN CHAR16 * BootArgs,IN CHAR16 * BootDescription,IN UINT16 LoadOption)201 HiKeyCreateBootEntry (
202   IN CHAR16          *DevicePathText,
203   IN CHAR16          *BootArgs,
204   IN CHAR16          *BootDescription,
205   IN UINT16           LoadOption
206   )
207 {
208   BDS_LOAD_OPTION                    *BdsLoadOption;
209   EFI_STATUS                          Status;
210   UINTN                               DescriptionSize;
211   UINTN                               BootOrderSize;
212   CHAR16                              BootVariableName[9];
213   UINT8                              *EfiLoadOptionPtr;
214   EFI_DEVICE_PATH_PROTOCOL           *DevicePathNode;
215   UINTN                               NodeLength;
216   EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *DevicePathFromTextProtocol;
217 
218   if ((DevicePathText == NULL) || (BootDescription == NULL)) {
219     DEBUG ((EFI_D_ERROR, "%a: Invalid Parameters\n", __func__));
220     return EFI_INVALID_PARAMETER;
221   }
222 
223   UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", mBootCount);
224   if (HiKeyVerifyBootEntry (BootVariableName, DevicePathText, BootArgs, BootDescription, LoadOption) == TRUE) {
225     // The boot entry is already created.
226     Status = EFI_SUCCESS;
227     goto done;
228   }
229 
230   BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
231   ASSERT (BdsLoadOption != NULL);
232 
233   Status = gBS->LocateProtocol (
234                   &gEfiDevicePathFromTextProtocolGuid,
235                   NULL,
236                   (VOID**)&DevicePathFromTextProtocol
237                   );
238   ASSERT_EFI_ERROR(Status);
239 
240   BdsLoadOption->FilePathList = DevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathText);
241   ASSERT (BdsLoadOption->FilePathList != NULL);
242   BdsLoadOption->FilePathListLength = GetDevicePathSize (BdsLoadOption->FilePathList);
243   BdsLoadOption->Attributes = LOAD_OPTION_ACTIVE | (LoadOption & LOAD_OPTION_CATEGORY);
244 
245   if (BootArgs) {
246     /* Always force the BootArgs to save 512 characters. */
247     ASSERT (StrSize(BootArgs) <= 512);
248     BdsLoadOption->OptionalDataSize = 512;
249     BdsLoadOption->OptionalData = (CHAR16*)AllocateZeroPool (BdsLoadOption->OptionalDataSize);
250     ASSERT (BdsLoadOption->OptionalData != NULL);
251     StrCpy (BdsLoadOption->OptionalData, BootArgs);
252   }
253 
254   BdsLoadOption->LoadOptionIndex = mBootCount;
255   DescriptionSize = StrSize (BootDescription);
256   BdsLoadOption->Description = (VOID*)AllocateZeroPool (DescriptionSize);
257   StrCpy (BdsLoadOption->Description, BootDescription);
258 
259   BdsLoadOption->LoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + DescriptionSize + BdsLoadOption->FilePathListLength + BdsLoadOption->OptionalDataSize;
260   BdsLoadOption->LoadOption = (EFI_LOAD_OPTION*)AllocateZeroPool (BdsLoadOption->LoadOptionSize);
261   ASSERT (BdsLoadOption->LoadOption != NULL);
262 
263   EfiLoadOptionPtr = (VOID*)BdsLoadOption->LoadOption;
264 
265   //
266   // Populate the EFI Load Option and BDS Boot Option structures
267   //
268 
269   // Attributes fields
270   *(UINT32*)EfiLoadOptionPtr = BdsLoadOption->Attributes;
271   EfiLoadOptionPtr += sizeof(UINT32);
272 
273   // FilePath List fields
274   *(UINT16*)EfiLoadOptionPtr = BdsLoadOption->FilePathListLength;
275   EfiLoadOptionPtr += sizeof(UINT16);
276 
277   // Boot description fields
278   CopyMem (EfiLoadOptionPtr, BdsLoadOption->Description, DescriptionSize);
279   EfiLoadOptionPtr += DescriptionSize;
280 
281   // File path fields
282   DevicePathNode = BdsLoadOption->FilePathList;
283   while (!IsDevicePathEndType (DevicePathNode)) {
284     NodeLength = DevicePathNodeLength(DevicePathNode);
285     CopyMem (EfiLoadOptionPtr, DevicePathNode, NodeLength);
286     EfiLoadOptionPtr += NodeLength;
287     DevicePathNode = NextDevicePathNode (DevicePathNode);
288   }
289 
290   // Set the End Device Path Type
291   SetDevicePathEndNode (EfiLoadOptionPtr);
292   EfiLoadOptionPtr += sizeof(EFI_DEVICE_PATH);
293 
294   // Fill the Optional Data
295   if (BdsLoadOption->OptionalDataSize > 0) {
296     CopyMem (EfiLoadOptionPtr, BdsLoadOption->OptionalData, BdsLoadOption->OptionalDataSize);
297   }
298 
299   Status = gRT->SetVariable (
300                   BootVariableName,
301                   &gEfiGlobalVariableGuid,
302                   EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
303                   BdsLoadOption->LoadOptionSize,
304                   BdsLoadOption->LoadOption
305                   );
306   if (EFI_ERROR (Status)) {
307     DEBUG ((EFI_D_ERROR, "%a: failed to set BootVariable\n", __func__));
308     return Status;
309   }
310 
311 done:
312   BootOrderSize = mBootCount * sizeof (UINT16);
313   mBootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof (UINT16), mBootOrder);
314   mBootOrder[mBootCount] = mBootCount;
315   mBootCount++;
316   return Status;
317 }
318 
319 STATIC
320 EFI_STATUS
321 EFIAPI
HiKeyCreateBootOrder(IN VOID)322 HiKeyCreateBootOrder (
323   IN    VOID
324   )
325 {
326   UINT16             *BootOrder;
327   UINTN               BootOrderSize;
328   UINTN               Index;
329   EFI_STATUS          Status;
330 
331   Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
332   if (EFI_ERROR(Status) == 0) {
333     if (BootOrderSize == mBootCount) {
334       for (Index = 0; Index < mBootCount; Index++) {
335         if (BootOrder[Index] != mBootOrder[Index]) {
336           break;
337         }
338       }
339       if (Index == mBootCount) {
340         // Found BootOrder variable with expected value.
341         return EFI_SUCCESS;
342       }
343     }
344   }
345 
346   Status = gRT->SetVariable (
347                   (CHAR16*)L"BootOrder",
348                   &gEfiGlobalVariableGuid,
349                   EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
350                   mBootCount * sizeof(UINT16),
351                   mBootOrder
352                   );
353   return Status;
354 }
355 
356 STATIC
357 EFI_STATUS
358 EFIAPI
HiKeyCreateBootNext(IN VOID)359 HiKeyCreateBootNext (
360   IN     VOID
361   )
362 {
363   EFI_STATUS          Status;
364   UINT16             *BootNext;
365   UINTN               BootNextSize;
366 
367   BootNextSize = sizeof(UINT16);
368   Status = GetGlobalEnvironmentVariable (L"BootNext", NULL, &BootNextSize, (VOID**)&BootNext);
369   if (EFI_ERROR(Status) == 0) {
370     if (BootNextSize == sizeof (UINT16)) {
371       if (*BootNext == mBootOrder[mBootIndex]) {
372         // Found the BootNext variable with expected value.
373         return EFI_SUCCESS;
374       }
375     }
376   }
377   BootNext = &mBootOrder[mBootIndex];
378   Status = gRT->SetVariable (
379                   (CHAR16*)L"BootNext",
380                   &gEfiGlobalVariableGuid,
381                   EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
382                   sizeof (UINT16),
383                   BootNext
384                   );
385   return Status;
386 }
387 
388 STATIC
389 VOID
390 EFIAPI
HiKeyTestLed(IN EMBEDDED_GPIO * Gpio)391 HiKeyTestLed (
392   IN     EMBEDDED_GPIO   *Gpio
393   )
394 {
395   EFI_STATUS             Status;
396 
397   Status = Gpio->Set (Gpio, USER_LED1, GPIO_MODE_OUTPUT_0);
398   if (EFI_ERROR (Status)) {
399     DEBUG ((EFI_D_ERROR, "%a: failed to set LED1\n", __func__));
400     return;
401   }
402   Status = Gpio->Set (Gpio, USER_LED2, GPIO_MODE_OUTPUT_1);
403   if (EFI_ERROR (Status)) {
404     DEBUG ((EFI_D_ERROR, "%a: failed to set LED2\n", __func__));
405     return;
406   }
407   Status = Gpio->Set (Gpio, USER_LED3, GPIO_MODE_OUTPUT_0);
408   if (EFI_ERROR (Status)) {
409     DEBUG ((EFI_D_ERROR, "%a: failed to set LED3\n", __func__));
410     return;
411   }
412   Status = Gpio->Set (Gpio, USER_LED4, GPIO_MODE_OUTPUT_1);
413   if (EFI_ERROR (Status)) {
414     DEBUG ((EFI_D_ERROR, "%a: failed to set LED4\n", __func__));
415     return;
416   }
417 }
418 
419 
420 #define REBOOT_REASON_ADDR		0x05F01000
421 #define REBOOT_REASON_BOOTLOADER	0x77665500
422 #define REBOOT_REASON_NONE		0x77665501
423 STATIC
424 BOOLEAN
425 EFIAPI
HiKeyDetectRebootReason(IN VOID)426 HiKeyDetectRebootReason (
427   IN     VOID
428   )
429 {
430    UINT32 *addr = (UINT32*)REBOOT_REASON_ADDR;
431    UINT32  val;
432 
433    val = *addr;
434    /* Write NONE to the reason address to clear the state */
435    *addr = REBOOT_REASON_NONE;
436    /* Check to see if "reboot booloader" was specified */
437    if (val == REBOOT_REASON_BOOTLOADER)
438      return TRUE;
439 
440    return FALSE;
441 }
442 
443 STATIC
444 BOOLEAN
445 EFIAPI
HiKeyIsJumperConnected(IN VOID)446 HiKeyIsJumperConnected (
447   IN     VOID
448   )
449 {
450   EMBEDDED_GPIO         *Gpio;
451   EFI_STATUS             Status;
452   UINTN                  Value;
453 
454   Status = gBS->LocateProtocol (&gEmbeddedGpioProtocolGuid, NULL, (VOID **)&Gpio);
455   ASSERT_EFI_ERROR (Status);
456 
457   Status = Gpio->Set (Gpio, DETECT_J15_FASTBOOT, GPIO_MODE_INPUT);
458   if (EFI_ERROR (Status)) {
459     DEBUG ((EFI_D_ERROR, "%a: failed to set jumper as gpio input\n", __func__));
460     return FALSE;
461   }
462   Status = Gpio->Get (Gpio, DETECT_J15_FASTBOOT, &Value);
463   if (EFI_ERROR (Status)) {
464     DEBUG ((EFI_D_ERROR, "%a: failed to get value from jumper\n", __func__));
465     return FALSE;
466   }
467 
468   HiKeyTestLed (Gpio);
469   if (Value != 0)
470     return FALSE;
471   return TRUE;
472 }
473 
474 STATIC
475 BOOLEAN
476 EFIAPI
HiKeySDCardIsPresent(IN VOID)477 HiKeySDCardIsPresent (
478   IN      VOID
479   )
480 {
481   UINT32    Value;
482 
483   /*
484    * FIXME
485    * At first, reading GPIO pin shouldn't exist in SD driver. We need to
486    * add some callbacks to handle settings for hardware platform.
487    * In the second, reading GPIO pin should be based on GPIO driver. Now
488    * GPIO driver could only be used for one PL061 gpio controller. And it's
489    * used to detect jumper setting. As a workaround, we have to read the gpio
490    * register instead at here.
491    *
492    */
493   Value = MmioRead32 (0xf8012000 + (1 << 2));
494   if (Value)
495     return FALSE;
496   return TRUE;
497 }
498 
499 #define BOOT_MAGIC        "ANDROID!"
500 #define BOOT_MAGIC_LENGTH sizeof (BOOT_MAGIC) - 1
501 
502 /*
503  * Check which boot type is valid for eMMC.
504  */
505 STATIC
506 EFI_STATUS
507 EFIAPI
HiKeyCheckEmmcDtbType(OUT UINTN * DtbType)508 HiKeyCheckEmmcDtbType (
509   OUT UINTN       *DtbType
510   )
511 {
512   EFI_DEVICE_PATH_PROTOCOL        *BlockDevicePath;
513   EFI_BLOCK_IO_PROTOCOL           *BlockIoProtocol;
514   EFI_HANDLE                      Handle;
515   EFI_STATUS                      Status;
516   VOID                            *DataPtr, *AlignedPtr;
517 
518   /* Check boot image */
519   BlockDevicePath = ConvertTextToDevicePath ((CHAR16*)FixedPcdGetPtr (PcdBootImagePath));
520   Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &BlockDevicePath, &Handle);
521   ASSERT_EFI_ERROR (Status);
522 
523   Status = gBS->OpenProtocol (
524                       Handle,
525                       &gEfiBlockIoProtocolGuid,
526                       (VOID **) &BlockIoProtocol,
527                       gImageHandle,
528                       NULL,
529                       EFI_OPEN_PROTOCOL_GET_PROTOCOL
530                       );
531   ASSERT_EFI_ERROR (Status);
532 
533   /* Read the header of boot image. */
534   DataPtr = AllocateZeroPool (HIKEY_IO_BLOCK_SIZE * 2);
535   ASSERT (DataPtr != 0);
536   AlignedPtr = (VOID *)(((UINTN)DataPtr + HIKEY_IO_BLOCK_SIZE - 1) & ~(HIKEY_IO_BLOCK_SIZE - 1));
537   InvalidateDataCacheRange (AlignedPtr, HIKEY_IO_BLOCK_SIZE);
538   /* TODO: Update 0x7000 by LBA what is fetched from partition. */
539   Status = BlockIoProtocol->ReadBlocks (BlockIoProtocol, BlockIoProtocol->Media->MediaId,
540                                         0x7000, HIKEY_IO_BLOCK_SIZE, AlignedPtr);
541   ASSERT_EFI_ERROR (Status);
542   if (AsciiStrnCmp ((CHAR8 *)AlignedPtr, BOOT_MAGIC, BOOT_MAGIC_LENGTH) != 0) {
543     /* It's debian boot image. */
544     *DtbType = HIKEY_DTB_LINUX;
545   } else {
546     /* It's android boot image. */
547     *DtbType = HIKEY_DTB_ANDROID;
548   }
549   FreePool (DataPtr);
550   return Status;
551 }
552 
553 STATIC
554 BOOLEAN
555 EFIAPI
HiKeyIsSdBoot(IN struct HiKeyBootEntry * Entry)556 HiKeyIsSdBoot (
557   IN struct HiKeyBootEntry    *Entry
558   )
559 {
560   CHAR16                           *Path;
561   EFI_DEVICE_PATH                  *DevicePath, *NextDevicePath;
562   EFI_STATUS                        Status;
563   EFI_HANDLE                        Handle;
564   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *FsProtocol;
565   EFI_FILE_PROTOCOL                *Fs;
566   EFI_FILE_INFO                    *FileInfo;
567   EFI_FILE_PROTOCOL                *File;
568   FILEPATH_DEVICE_PATH             *FilePathDevicePath;
569   UINTN                             Index, Size;
570   UINTN                             HandleCount;
571   EFI_HANDLE                       *HandleBuffer;
572   EFI_DEVICE_PATH_PROTOCOL         *DevicePathProtocol;
573   BOOLEAN                           Found = FALSE, Result = FALSE;
574 
575   if (HiKeySDCardIsPresent () == FALSE)
576     return FALSE;
577   Path = Entry[HIKEY_BOOT_ENTRY_BOOT_SD].Path;
578   ASSERT (Path != NULL);
579 
580   DevicePath = ConvertTextToDevicePath (Path);
581   if (DevicePath == NULL) {
582     DEBUG ((EFI_D_ERROR, "Warning: Couldn't get device path\n"));
583     return FALSE;
584   }
585 
586   /* Connect handles to drivers. Since simple filesystem driver is loaded later by default. */
587   do {
588     // Locate all the driver handles
589     Status = gBS->LocateHandleBuffer (
590                 AllHandles,
591                 NULL,
592                 NULL,
593                 &HandleCount,
594                 &HandleBuffer
595                 );
596     if (EFI_ERROR (Status)) {
597       break;
598     }
599 
600     // Connect every handles
601     for (Index = 0; Index < HandleCount; Index++) {
602       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
603     }
604 
605     if (HandleBuffer != NULL) {
606       FreePool (HandleBuffer);
607     }
608 
609     // Check if new handles have been created after the start of the previous handles
610     Status = gDS->Dispatch ();
611   } while (!EFI_ERROR(Status));
612 
613   // List all the Simple File System Protocols
614   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &HandleBuffer);
615   if (EFI_ERROR (Status)) {
616     DEBUG ((EFI_D_ERROR, "Warning: Failed to list all the simple filesystem protocols (status:%r)\n", Status));
617     return FALSE;
618   }
619   for (Index = 0; Index < HandleCount; Index++) {
620     Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
621     if (EFI_ERROR(Status))
622       continue;
623     NextDevicePath = NextDevicePathNode (DevicePath);
624     Size = (UINTN)NextDevicePath - (UINTN)DevicePath;
625     if (Size <= GetDevicePathSize (DevicePath)) {
626       if ((CompareMem (DevicePath, DevicePathProtocol, Size)) == 0) {
627 	Found = TRUE;
628         break;
629       }
630     }
631   }
632   if (!Found) {
633     DEBUG ((EFI_D_ERROR, "Warning: Failed to find valid device path\n"));
634     return FALSE;
635   }
636 
637   Handle = HandleBuffer[Index];
638   Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &DevicePath, &Handle);
639   if (EFI_ERROR (Status)) {
640     DEBUG ((EFI_D_ERROR, "Warning: Couldn't locate device (status: %r)\n", Status));
641     return FALSE;
642   }
643   FilePathDevicePath = (FILEPATH_DEVICE_PATH*)DevicePath;
644 
645   Status = gBS->OpenProtocol (
646                   Handle,
647                   &gEfiSimpleFileSystemProtocolGuid,
648                   (VOID**)&FsProtocol,
649                   gImageHandle,
650                   Handle,
651                   EFI_OPEN_PROTOCOL_BY_DRIVER
652                   );
653   if (EFI_ERROR (Status)) {
654     DEBUG ((EFI_D_ERROR, "Warning: Failedn't to mount as Simple Filrsystem (status: %r)\n", Status));
655     return FALSE;
656   }
657   Status = FsProtocol->OpenVolume (FsProtocol, &Fs);
658   if (EFI_ERROR (Status)) {
659     goto CLOSE_PROTOCOL;
660   }
661 
662   Status = Fs->Open (Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0);
663   if (EFI_ERROR (Status)) {
664     goto CLOSE_PROTOCOL;
665   }
666 
667   Size = 0;
668   File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL);
669   FileInfo = AllocatePool (Size);
670   Status = File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo);
671   if (EFI_ERROR (Status)) {
672     goto CLOSE_FILE;
673   }
674 
675   // Get the file size
676   Size = FileInfo->FileSize;
677   FreePool (FileInfo);
678   if (Size != 0) {
679     Result = TRUE;
680   }
681 
682 CLOSE_FILE:
683   File->Close (File);
684 CLOSE_PROTOCOL:
685   gBS->CloseProtocol (
686          Handle,
687          &gEfiSimpleFileSystemProtocolGuid,
688          gImageHandle,
689          Handle);
690   return Result;
691 }
692 
693 STATIC
694 EFI_STATUS
695 EFIAPI
HiKeyInstallFdt(VOID)696 HiKeyInstallFdt (
697   VOID
698   )
699 {
700   EFI_STATUS              Status;
701   VOID                   *Image;
702   UINTN                   ImageSize, NumPages;
703   EFI_GUID               *Guid;
704   EFI_PHYSICAL_ADDRESS    FdtConfigurationTableBase;
705 
706   Guid = &gHiKeyTokenSpaceGuid;
707   Status = GetSectionFromAnyFv (Guid, EFI_SECTION_RAW, 0, &Image, &ImageSize);
708   if (EFI_ERROR (Status))
709     return Status;
710   NumPages = EFI_SIZE_TO_PAGES (ImageSize);
711   Status = gBS->AllocatePages (
712 		  AllocateAnyPages, EfiRuntimeServicesData,
713 		  NumPages, &FdtConfigurationTableBase
714 		  );
715   if (EFI_ERROR (Status))
716     return Status;
717   CopyMem ((VOID *)(UINTN)FdtConfigurationTableBase, Image, ImageSize);
718   Status = gBS->InstallConfigurationTable (
719 		  &gFdtTableGuid,
720 		  (VOID *)(UINTN)FdtConfigurationTableBase
721 		  );
722   if (EFI_ERROR (Status)) {
723     gBS->FreePages (FdtConfigurationTableBase, NumPages);
724   }
725   return Status;
726 }
727 
728 STATIC
729 VOID
730 EFIAPI
HiKeyOnEndOfDxe(EFI_EVENT Event,VOID * Context)731 HiKeyOnEndOfDxe (
732   EFI_EVENT                               Event,
733   VOID                                    *Context
734   )
735 {
736   EFI_STATUS          Status;
737   UINTN               VariableSize;
738   UINT16              AutoBoot, Count, Index;
739   UINTN               DtbType;
740   struct HiKeyBootEntry *Entry;
741 
742   VariableSize = sizeof (UINT16);
743   Status = gRT->GetVariable (
744                   (CHAR16 *)L"HiKeyAutoBoot",
745                   &gHiKeyVariableGuid,
746                   NULL,
747                   &VariableSize,
748                   (VOID*)&AutoBoot
749                   );
750   if (Status == EFI_NOT_FOUND) {
751     AutoBoot = 1;
752     Status = gRT->SetVariable (
753                     (CHAR16*)L"HiKeyAutoBoot",
754                     &gHiKeyVariableGuid,
755                     EFI_VARIABLE_NON_VOLATILE       |
756                     EFI_VARIABLE_BOOTSERVICE_ACCESS |
757                     EFI_VARIABLE_RUNTIME_ACCESS,
758                     sizeof (UINT16),
759                     &AutoBoot
760                     );
761     ASSERT_EFI_ERROR (Status);
762   } else if (EFI_ERROR (Status) == 0) {
763     if (AutoBoot == 0) {
764       // Select boot entry by manual.
765       // Delete the BootNext environment variable
766       gRT->SetVariable (L"BootNext",
767              &gEfiGlobalVariableGuid,
768              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
769              0,
770              NULL);
771       return;
772     }
773   }
774 
775   Status = HiKeyCheckEmmcDtbType (&DtbType);
776   ASSERT_EFI_ERROR (Status);
777 
778   mBootCount = 0;
779   mBootOrder = NULL;
780 
781   if (DtbType == HIKEY_DTB_LINUX) {
782     Count = sizeof (LinuxEntries) / sizeof (struct HiKeyBootEntry);
783     Entry = LinuxEntries;
784   } else if (DtbType == HIKEY_DTB_ANDROID) {
785     Count = sizeof (AndroidEntries) / sizeof (struct HiKeyBootEntry);
786     Entry = AndroidEntries;
787   } else {
788     ASSERT (0);
789   }
790   ASSERT (HIKEY_DTB_SD < Count);
791   if (HiKeyIsSdBoot (Entry) == TRUE)
792     DtbType = HIKEY_DTB_SD;
793 
794   for (Index = 0; Index < Count; Index++) {
795     Status = HiKeyCreateBootEntry (
796                Entry->Path,
797                Entry->Args,
798                Entry->Description,
799                Entry->LoadType
800                );
801     ASSERT_EFI_ERROR (Status);
802     Entry++;
803   }
804 
805   if ((mBootCount == 0) || (mBootCount >= MAX_BOOT_ENTRIES)) {
806     DEBUG ((EFI_D_ERROR, "%a: can't create boot entries\n", __func__));
807     return;
808   }
809 
810   Status = HiKeyCreateBootOrder ();
811   if (EFI_ERROR (Status)) {
812     DEBUG ((EFI_D_ERROR, "%a: failed to set BootOrder variable\n", __func__));
813     return;
814   }
815 
816   if (DtbType == HIKEY_DTB_SD) {
817     mBootIndex = HIKEY_BOOT_ENTRY_BOOT_SD;
818   } else {
819     mBootIndex = HIKEY_BOOT_ENTRY_BOOT_EMMC;
820   }
821 
822   if (HiKeyGetUsbMode () == USB_DEVICE_MODE) {
823     if (HiKeyIsJumperConnected () == TRUE)
824       mBootIndex = HIKEY_BOOT_ENTRY_FASTBOOT;
825     /* Set mBootIndex as HIKEY_BOOT_ENTRY_FASTBOOT if adb reboot-bootloader is specified */
826     if (HiKeyDetectRebootReason () == TRUE)
827       mBootIndex = HIKEY_BOOT_ENTRY_FASTBOOT;
828   }
829 
830   Status = HiKeyCreateBootNext ();
831   if (EFI_ERROR (Status)) {
832     DEBUG ((EFI_D_ERROR, "%a: failed to set BootNext variable\n", __func__));
833     return;
834   }
835 
836   /*
837    * Priority of Loading DTB file:
838    *   1. Load configured DTB file in grub.cfg.
839    *   2. Load DTB file in UEFI Fv.
840    */
841   /* Load DTB file in UEFI Fv. */
842   Status = HiKeyInstallFdt ();
843   if (EFI_ERROR (Status)) {
844     DEBUG ((EFI_D_ERROR, "%a: failed to install Fdt file\n", __func__));
845     return;
846   }
847 }
848 
849 EFI_STATUS
HiKeyBootMenuInstall(IN VOID)850 HiKeyBootMenuInstall (
851   IN VOID
852   )
853 {
854   EFI_STATUS          Status;
855   EFI_EVENT           EndOfDxeEvent;
856 
857   Status = gBS->CreateEventEx (
858                   EVT_NOTIFY_SIGNAL,
859                   TPL_CALLBACK,
860                   HiKeyOnEndOfDxe,
861                   &mIsEndOfDxeEvent,
862                   &gEfiEndOfDxeEventGroupGuid,
863                   &EndOfDxeEvent
864                   );
865   ASSERT_EFI_ERROR (Status);
866   return Status;
867 }
868 
869