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