]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/ArmVExpressPkg/ArmVExpressFastBootDxe/ArmVExpressFastBoot.c
ARM Packages: Replace tabs by spaces for indentation
[mirror_edk2.git] / ArmPlatformPkg / ArmVExpressPkg / ArmVExpressFastBootDxe / ArmVExpressFastBoot.c
CommitLineData
81f29156
OM
1/** @file\r
2\r
3 Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>\r
4\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15/*\r
16 Implementation of the Android Fastboot Platform protocol, to be used by the\r
17 Fastboot UEFI application, for ARM Versatile Express platforms.\r
18*/\r
19\r
20#include <Protocol/AndroidFastbootPlatform.h>\r
21#include <Protocol/BlockIo.h>\r
22#include <Protocol/DiskIo.h>\r
23\r
24#include <Library/BaseLib.h>\r
25#include <Library/BaseMemoryLib.h>\r
26#include <Library/DebugLib.h>\r
27#include <Library/DevicePathLib.h>\r
28#include <Library/MemoryAllocationLib.h>\r
29#include <Library/UefiBootServicesTableLib.h>\r
30\r
31#define FLASH_DEVICE_PATH_SIZE(DevPath) ( GetDevicePathSize (DevPath) - \\r
32 sizeof (EFI_DEVICE_PATH_PROTOCOL))\r
33\r
34#define PARTITION_NAME_MAX_LENGTH 72/2\r
35\r
36#define IS_ALPHA(Char) (((Char) <= L'z' && (Char) >= L'a') || \\r
37 ((Char) <= L'Z' && (Char) >= L'Z'))\r
38\r
39typedef struct _FASTBOOT_PARTITION_LIST {\r
40 LIST_ENTRY Link;\r
41 CHAR16 PartitionName[PARTITION_NAME_MAX_LENGTH];\r
42 EFI_HANDLE PartitionHandle;\r
43} FASTBOOT_PARTITION_LIST;\r
44\r
45STATIC LIST_ENTRY mPartitionListHead;\r
46\r
47/*\r
48 Helper to free the partition list\r
49*/\r
50STATIC\r
51VOID\r
52FreePartitionList (\r
53 VOID\r
54 )\r
55{\r
56 FASTBOOT_PARTITION_LIST *Entry;\r
57 FASTBOOT_PARTITION_LIST *NextEntry;\r
58\r
59 Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&mPartitionListHead);\r
60 while (!IsNull (&mPartitionListHead, &Entry->Link)) {\r
61 NextEntry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &Entry->Link);\r
62\r
63 RemoveEntryList (&Entry->Link);\r
64 FreePool (Entry);\r
65\r
66 Entry = NextEntry;\r
67 }\r
68}\r
69/*\r
70 Read the PartitionName fields from the GPT partition entries, putting them\r
71 into an allocated array that should later be freed.\r
72*/\r
73STATIC\r
74EFI_STATUS\r
75ReadPartitionEntries (\r
76 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
77 OUT EFI_PARTITION_ENTRY **PartitionEntries\r
78 )\r
79{\r
80 UINTN EntrySize;\r
81 UINTN NumEntries;\r
82 UINTN BufferSize;\r
83 UINT32 MediaId;\r
84 EFI_PARTITION_TABLE_HEADER *GptHeader;\r
85 EFI_STATUS Status;\r
86\r
87 MediaId = BlockIo->Media->MediaId;\r
88\r
89 //\r
90 // Read size of Partition entry and number of entries from GPT header\r
91 //\r
92\r
93 GptHeader = AllocatePool (BlockIo->Media->BlockSize);\r
94 if (GptHeader == NULL) {\r
95 return EFI_OUT_OF_RESOURCES;\r
96 }\r
97\r
98 Status = BlockIo->ReadBlocks (BlockIo, MediaId, 1, BlockIo->Media->BlockSize, (VOID *) GptHeader);\r
99 if (EFI_ERROR (Status)) {\r
100 return Status;\r
101 }\r
102\r
103 // Check there is a GPT on the media\r
104 if (GptHeader->Header.Signature != EFI_PTAB_HEADER_ID ||\r
105 GptHeader->MyLBA != 1) {\r
106 DEBUG ((EFI_D_ERROR,\r
107 "Fastboot platform: No GPT on flash. "\r
108 "Fastboot on Versatile Express does not support MBR.\n"\r
109 ));\r
110 return EFI_DEVICE_ERROR;\r
111 }\r
112\r
113 EntrySize = GptHeader->SizeOfPartitionEntry;\r
114 NumEntries = GptHeader->NumberOfPartitionEntries;\r
115\r
116 FreePool (GptHeader);\r
117\r
118 ASSERT (EntrySize != 0);\r
119 ASSERT (NumEntries != 0);\r
120\r
121 BufferSize = ALIGN_VALUE (EntrySize * NumEntries, BlockIo->Media->BlockSize);\r
122 *PartitionEntries = AllocatePool (BufferSize);\r
123 if (PartitionEntries == NULL) {\r
124 return EFI_OUT_OF_RESOURCES;\r
125 }\r
126\r
127 Status = BlockIo->ReadBlocks (BlockIo, MediaId, 2, BufferSize, (VOID *) *PartitionEntries);\r
128 if (EFI_ERROR (Status)) {\r
129 FreePool (PartitionEntries);\r
130 return Status;\r
131 }\r
132\r
133 return Status;\r
134}\r
135\r
136\r
137/*\r
138 Initialise: Open the Android NVM device and find the partitions on it. Save them in\r
139 a list along with the "PartitionName" fields for their GPT entries.\r
140 We will use these partition names as the key in\r
141 ArmFastbootPlatformFlashPartition.\r
142*/\r
143EFI_STATUS\r
144ArmFastbootPlatformInit (\r
145 VOID\r
146 )\r
147{\r
148 EFI_STATUS Status;\r
149 EFI_DEVICE_PATH_PROTOCOL *FlashDevicePath;\r
150 EFI_DEVICE_PATH_PROTOCOL *FlashDevicePathDup;\r
151 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
152 EFI_DEVICE_PATH_PROTOCOL *NextNode;\r
153 HARDDRIVE_DEVICE_PATH *PartitionNode;\r
154 UINTN NumHandles;\r
155 EFI_HANDLE *AllHandles;\r
156 UINTN LoopIndex;\r
157 EFI_HANDLE FlashHandle;\r
158 EFI_BLOCK_IO_PROTOCOL *FlashBlockIo;\r
159 EFI_PARTITION_ENTRY *PartitionEntries;\r
160 FASTBOOT_PARTITION_LIST *Entry;\r
161\r
162 InitializeListHead (&mPartitionListHead);\r
163\r
164 //\r
165 // Get EFI_HANDLES for all the partitions on the block devices pointed to by\r
166 // PcdFastbootFlashDevicePath, also saving their GPT partition labels.\r
167 // There's no way to find all of a device's children, so we get every handle\r
168 // in the system supporting EFI_BLOCK_IO_PROTOCOL and then filter out ones\r
169 // that don't represent partitions on the flash device.\r
170 //\r
171\r
172 FlashDevicePath = ConvertTextToDevicePath ((CHAR16*)FixedPcdGetPtr (PcdAndroidFastbootNvmDevicePath));\r
173\r
174 //\r
175 // Open the Disk IO protocol on the flash device - this will be used to read\r
176 // partition names out of the GPT entries\r
177 //\r
178 // Create another device path pointer because LocateDevicePath will modify it.\r
179 FlashDevicePathDup = FlashDevicePath;\r
180 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &FlashDevicePathDup, &FlashHandle);\r
181 if (EFI_ERROR (Status)) {\r
182 DEBUG ((EFI_D_ERROR, "Warning: Couldn't locate Android NVM device (status: %r)\n", Status));\r
183 // Failing to locate partitions should not prevent to do other Android FastBoot actions\r
184 return EFI_SUCCESS;\r
185 }\r
186\r
187 Status = gBS->OpenProtocol (\r
188 FlashHandle,\r
189 &gEfiBlockIoProtocolGuid,\r
190 (VOID **) &FlashBlockIo,\r
191 gImageHandle,\r
192 NULL,\r
193 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
194 );\r
195 if (EFI_ERROR (Status)) {\r
196 DEBUG ((EFI_D_ERROR, "Fastboot platform: Couldn't open Android NVM device (status: %r)\n", Status));\r
197 return EFI_DEVICE_ERROR;\r
198 }\r
199\r
200 // Read the GPT partition entry array into memory so we can get the partition names\r
201 Status = ReadPartitionEntries (FlashBlockIo, &PartitionEntries);\r
202 if (EFI_ERROR (Status)) {\r
91c38d4e
RC
203 DEBUG ((EFI_D_ERROR, "Warning: Failed to read partitions from Android NVM device (status: %r)\n", Status));\r
204 // Failing to locate partitions should not prevent to do other Android FastBoot actions\r
205 return EFI_SUCCESS;\r
81f29156
OM
206 }\r
207\r
208 // Get every Block IO protocol instance installed in the system\r
209 Status = gBS->LocateHandleBuffer (\r
210 ByProtocol,\r
211 &gEfiBlockIoProtocolGuid,\r
212 NULL,\r
213 &NumHandles,\r
214 &AllHandles\r
215 );\r
216 ASSERT_EFI_ERROR (Status);\r
217\r
218 // Filter out handles that aren't children of the flash device\r
219 for (LoopIndex = 0; LoopIndex < NumHandles; LoopIndex++) {\r
220 // Get the device path for the handle\r
221 Status = gBS->OpenProtocol (\r
222 AllHandles[LoopIndex],\r
223 &gEfiDevicePathProtocolGuid,\r
224 (VOID **) &DevicePath,\r
225 gImageHandle,\r
226 NULL,\r
227 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
228 );\r
229 ASSERT_EFI_ERROR (Status);\r
230\r
231 // Check if it is a sub-device of the flash device\r
232 if (!CompareMem (DevicePath, FlashDevicePath, FLASH_DEVICE_PATH_SIZE (FlashDevicePath))) {\r
233 // Device path starts with path of flash device. Check it isn't the flash\r
234 // device itself.\r
235 NextNode = NextDevicePathNode (DevicePath);\r
236 if (IsDevicePathEndType (NextNode)) {\r
237 continue;\r
238 }\r
239\r
240 // Assert that this device path node represents a partition.\r
241 ASSERT (NextNode->Type == MEDIA_DEVICE_PATH &&\r
242 NextNode->SubType == MEDIA_HARDDRIVE_DP);\r
243\r
244 PartitionNode = (HARDDRIVE_DEVICE_PATH *) NextNode;\r
245\r
246 // Assert that the partition type is GPT. ReadPartitionEntries checks for\r
247 // presence of a GPT, so we should never find MBR partitions.\r
248 // ("MBRType" is a misnomer - this field is actually called "Partition\r
249 // Format")\r
250 ASSERT (PartitionNode->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER);\r
251\r
252 // The firmware may install a handle for "partition 0", representing the\r
253 // whole device. Ignore it.\r
254 if (PartitionNode->PartitionNumber == 0) {\r
255 continue;\r
256 }\r
257\r
258 //\r
259 // Add the partition handle to the list\r
260 //\r
261\r
262 // Create entry\r
263 Entry = AllocatePool (sizeof (FASTBOOT_PARTITION_LIST));\r
264 if (Entry == NULL) {\r
265 Status = EFI_OUT_OF_RESOURCES;\r
266 FreePartitionList ();\r
267 goto Exit;\r
268 }\r
269\r
270 // Copy handle and partition name\r
271 Entry->PartitionHandle = AllHandles[LoopIndex];\r
272 StrnCpy (\r
273 Entry->PartitionName,\r
274 PartitionEntries[PartitionNode->PartitionNumber - 1].PartitionName, // Partition numbers start from 1.\r
275 PARTITION_NAME_MAX_LENGTH\r
276 );\r
277 InsertTailList (&mPartitionListHead, &Entry->Link);\r
278\r
279 // Print a debug message if the partition label is empty or looks like\r
280 // garbage.\r
281 if (!IS_ALPHA (Entry->PartitionName[0])) {\r
282 DEBUG ((EFI_D_ERROR,\r
283 "Warning: Partition %d doesn't seem to have a GPT partition label. "\r
284 "You won't be able to flash it with Fastboot.\n",\r
285 PartitionNode->PartitionNumber\r
286 ));\r
287 }\r
288 }\r
289 }\r
290\r
291Exit:\r
292 FreePool (PartitionEntries);\r
293 FreePool (FlashDevicePath);\r
294 FreePool (AllHandles);\r
295 return Status;\r
296\r
297}\r
298\r
299VOID\r
300ArmFastbootPlatformUnInit (\r
301 VOID\r
302 )\r
303{\r
304 FreePartitionList ();\r
305}\r
306\r
307EFI_STATUS\r
308ArmFastbootPlatformFlashPartition (\r
309 IN CHAR8 *PartitionName,\r
310 IN UINTN Size,\r
311 IN VOID *Image\r
312 )\r
313{\r
314 EFI_STATUS Status;\r
315 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
316 EFI_DISK_IO_PROTOCOL *DiskIo;\r
317 UINT32 MediaId;\r
318 UINTN PartitionSize;\r
319 FASTBOOT_PARTITION_LIST *Entry;\r
320 CHAR16 PartitionNameUnicode[60];\r
321 BOOLEAN PartitionFound;\r
322\r
323 AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode);\r
324\r
325 PartitionFound = FALSE;\r
326 Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));\r
327 while (!IsNull (&mPartitionListHead, &Entry->Link)) {\r
328 // Search the partition list for the partition named by PartitionName\r
329 if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {\r
330 PartitionFound = TRUE;\r
331 break;\r
332 }\r
333\r
334 Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link);\r
335 }\r
336 if (!PartitionFound) {\r
337 return EFI_NOT_FOUND;\r
338 }\r
339\r
340 Status = gBS->OpenProtocol (\r
341 Entry->PartitionHandle,\r
342 &gEfiBlockIoProtocolGuid,\r
343 (VOID **) &BlockIo,\r
344 gImageHandle,\r
345 NULL,\r
346 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
347 );\r
348 if (EFI_ERROR (Status)) {\r
349 DEBUG ((EFI_D_ERROR, "Fastboot platform: couldn't open Block IO for flash: %r\n", Status));\r
350 return EFI_NOT_FOUND;\r
351 }\r
352\r
353 // Check image will fit on device\r
354 PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;\r
355 if (PartitionSize < Size) {\r
356 DEBUG ((EFI_D_ERROR, "Partition not big enough.\n"));\r
357 DEBUG ((EFI_D_ERROR, "Partition Size:\t%d\nImage Size:\t%d\n", PartitionSize, Size));\r
358\r
359 return EFI_VOLUME_FULL;\r
360 }\r
361\r
362 MediaId = BlockIo->Media->MediaId;\r
363\r
364 Status = gBS->OpenProtocol (\r
365 Entry->PartitionHandle,\r
366 &gEfiDiskIoProtocolGuid,\r
367 (VOID **) &DiskIo,\r
368 gImageHandle,\r
369 NULL,\r
370 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
371 );\r
372 ASSERT_EFI_ERROR (Status);\r
373\r
374 Status = DiskIo->WriteDisk (DiskIo, MediaId, 0, Size, Image);\r
375 if (EFI_ERROR (Status)) {\r
376 return Status;\r
377 }\r
378\r
379 BlockIo->FlushBlocks(BlockIo);\r
380\r
381 return Status;\r
382}\r
383\r
384EFI_STATUS\r
385ArmFastbootPlatformErasePartition (\r
386 IN CHAR8 *Partition\r
387 )\r
388{\r
389 return EFI_SUCCESS;\r
390}\r
391\r
392EFI_STATUS\r
393ArmFastbootPlatformGetVar (\r
394 IN CHAR8 *Name,\r
395 OUT CHAR8 *Value\r
396 )\r
397{\r
398 if (AsciiStrCmp (Name, "product")) {\r
399 AsciiStrCpy (Value, FixedPcdGetPtr (PcdFirmwareVendor));\r
400 } else {\r
401 *Value = '\0';\r
402 }\r
403 return EFI_SUCCESS;\r
404}\r
405\r
406EFI_STATUS\r
407ArmFastbootPlatformOemCommand (\r
408 IN CHAR8 *Command\r
409 )\r
410{\r
411 CHAR16 CommandUnicode[65];\r
412\r
413 AsciiStrToUnicodeStr (Command, CommandUnicode);\r
414\r
415 if (AsciiStrCmp (Command, "Demonstrate") == 0) {\r
416 DEBUG ((EFI_D_ERROR, "ARM OEM Fastboot command 'Demonstrate' received.\n"));\r
417 return EFI_SUCCESS;\r
418 } else {\r
419 DEBUG ((EFI_D_ERROR,\r
420 "VExpress: Unrecognised Fastboot OEM command: %s\n",\r
421 CommandUnicode\r
422 ));\r
423 return EFI_NOT_FOUND;\r
424 }\r
425}\r
426\r
427FASTBOOT_PLATFORM_PROTOCOL mPlatformProtocol = {\r
428 ArmFastbootPlatformInit,\r
429 ArmFastbootPlatformUnInit,\r
430 ArmFastbootPlatformFlashPartition,\r
431 ArmFastbootPlatformErasePartition,\r
432 ArmFastbootPlatformGetVar,\r
433 ArmFastbootPlatformOemCommand\r
434};\r
435\r
436EFI_STATUS\r
437EFIAPI\r
438ArmAndroidFastbootPlatformEntryPoint (\r
439 IN EFI_HANDLE ImageHandle,\r
440 IN EFI_SYSTEM_TABLE *SystemTable\r
441 )\r
442{\r
81f29156
OM
443 return gBS->InstallProtocolInterface (\r
444 &ImageHandle,\r
445 &gAndroidFastbootPlatformProtocolGuid,\r
446 EFI_NATIVE_INTERFACE,\r
447 &mPlatformProtocol\r
448 );\r
449}\r