1 /** @file
2 
3 Copyright (c) 2007  - 2014, Intel Corporation. All rights reserved.<BR>
4 
5 
6   This program and the accompanying materials are licensed and made available under
7 
8   the terms and conditions of the BSD License that accompanies this distribution.
9 
10   The full text of the license may be found at
11 
12   http://opensource.org/licenses/bsd-license.php.
13 
14 
15 
16   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
17 
18   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 
20 
21 
22 
23 **/
24 
25 #include "FirmwareUpdate.h"
26 
27 EFI_HII_HANDLE  HiiHandle;
28 
29 //
30 // MinnowMax Flash Layout
31 //
32 //Start (hex)	End (hex)	Length (hex)	Area Name
33 //-----------	---------	------------	---------
34 //00000000	007FFFFF	00800000	Flash Image
35 //
36 //00000000	00000FFF	00001000	Descriptor Region
37 //00001000	004FFFFF	004FF000	TXE Region
38 //00500000	007FFFFF	00300000	BIOS Region
39 //
40 FV_REGION_INFO mRegionInfo[] = {
41   {FixedPcdGet32 (PcdFlashDescriptorBase), FixedPcdGet32 (PcdFlashDescriptorSize), TRUE},
42   {FixedPcdGet32 (PcdTxeRomBase), FixedPcdGet32 (PcdTxeRomSize), TRUE},
43   {FixedPcdGet32 (PcdBiosRomBase), FixedPcdGet32 (PcdBiosRomSize), TRUE}
GetRegionIndex(IN EFI_PHYSICAL_ADDRESS Address,OUT UINTN * RegionIndex)44 };
45 
46 UINTN mRegionInfoCount = sizeof (mRegionInfo) / sizeof (mRegionInfo[0]);
47 
48 FV_INPUT_DATA mInputData = {0};
49 
50 EFI_SPI_PROTOCOL  *mSpiProtocol;
51 
52 EFI_STATUS
53 GetRegionIndex (
54   IN  EFI_PHYSICAL_ADDRESS  Address,
55   OUT UINTN                 *RegionIndex
56   )
57 {
58   UINTN Index;
59 
60   for (Index = 0; Index < mRegionInfoCount; Index++) {
61     if (Address >= mRegionInfo[Index].Base &&
62         Address < (mRegionInfo[Index].Base + mRegionInfo[Index].Size)
63         ) {
64       break;
65     }
66   }
UpdateBlock(IN EFI_PHYSICAL_ADDRESS Address)67 
68   *RegionIndex = Index;
69   if (Index >= mRegionInfoCount) {
70     return EFI_NOT_FOUND;
71   }
72   return EFI_SUCCESS;
73 }
74 
75 BOOLEAN
76 UpdateBlock (
77   IN  EFI_PHYSICAL_ADDRESS  Address
78   )
79 {
80   EFI_STATUS  Status;
81   UINTN       Index;
82 
83   if (mInputData.FullFlashUpdate) {
84     return TRUE;
85   }
86 
MarkRegionState(IN EFI_PHYSICAL_ADDRESS Address,IN BOOLEAN Update)87   Status = GetRegionIndex (Address, &Index);
88   if ((!EFI_ERROR(Status)) && mRegionInfo[Index].Update) {
89     return TRUE;
90   }
91 
92   return FALSE;
93 }
94 
95 EFI_STATUS
96 MarkRegionState (
97   IN  EFI_PHYSICAL_ADDRESS  Address,
98   IN  BOOLEAN               Update
99   )
100 {
101   EFI_STATUS  Status;
102   UINTN       Index;
103 
InternalPrintToken(IN CONST CHAR16 * Format,IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * Console,IN VA_LIST Marker)104   Status = GetRegionIndex (Address, &Index);
105   if (!EFI_ERROR(Status)) {
106     mRegionInfo[Index].Update = Update;
107   }
108 
109   return Status;
110 }
111 
112 UINTN
113 InternalPrintToken (
114   IN  CONST CHAR16                     *Format,
115   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *Console,
116   IN  VA_LIST                          Marker
117   )
118 {
119   EFI_STATUS  Status;
120   UINTN       Return;
121   CHAR16      *Buffer;
122   UINTN       BufferSize;
123 
124   ASSERT (Format != NULL);
125   ASSERT (((UINTN) Format & BIT0) == 0);
126   ASSERT (Console != NULL);
127 
128   BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16);
129 
130   Buffer = (CHAR16 *) AllocatePool(BufferSize);
131   ASSERT (Buffer != NULL);
132 
133   Return = UnicodeVSPrint (Buffer, BufferSize, Format, Marker);
134 
135   if (Console != NULL && Return > 0) {
136     //
137     // To be extra safe make sure Console has been initialized.
138     //
139     Status = Console->OutputString (Console, Buffer);
140     if (EFI_ERROR (Status)) {
141       Return = 0;
142     }
PrintToken(IN UINT16 Token,IN EFI_HII_HANDLE Handle,...)143   }
144 
145   FreePool (Buffer);
146 
147   return Return;
148 }
149 
150 UINTN
151 EFIAPI
152 PrintToken (
153   IN UINT16             Token,
154   IN EFI_HII_HANDLE     Handle,
155   ...
156   )
157 {
158   VA_LIST Marker;
159   UINTN   Return;
160   CHAR16  *Format;
161 
162   VA_START (Marker, Handle);
163 
164   Format = HiiGetString (Handle, Token, NULL);
165   ASSERT (Format != NULL);
166 
167   Return = InternalPrintToken (Format, gST->ConOut, Marker);
ParseCommandLine(IN UINTN Argc,IN CHAR16 ** Argv)168 
169   FreePool (Format);
170 
171   VA_END (Marker);
172 
173   return Return;
174 }
175 
176 EFI_STATUS
177 ParseCommandLine (
178   IN  UINTN   Argc,
179   IN  CHAR16  **Argv
180   )
181 {
182   EFI_STATUS  Status;
183   UINTN       Index;
184 
185   //
186   // Check to make sure that the command line has enough arguments for minimal
187   // operation.  The minimum is just the file name.
188   //
189   if (Argc < 2 || Argc > 4) {
190     return EFI_INVALID_PARAMETER;
191   }
192 
193   //
194   // Loop through command line arguments.
195   //
196   for (Index = 1; Index < Argc; Index++) {
197     //
198     // Make sure the string is valid.
199     //
200     if (StrLen (Argv[Index]) == 0) {;
201       PrintToken (STRING_TOKEN (STR_FWUPDATE_ZEROLENGTH_ARG), HiiHandle);
202       return EFI_INVALID_PARAMETER;
203     }
204 
205     //
206     // Check to see if this is an option or the file name.
207     //
208     if ((Argv[Index])[0] == L'-' || (Argv[Index])[0] == L'/') {
209       //
210       // Parse the arguments.
211       //
212       if ((StrCmp (Argv[Index], L"-h") == 0) ||
213           (StrCmp (Argv[Index], L"--help") == 0) ||
214           (StrCmp (Argv[Index], L"/?") == 0) ||
215           (StrCmp (Argv[Index], L"/h") == 0)) {
216         //
217         // Print Help Information.
218         //
219         return EFI_INVALID_PARAMETER;
220       } else if (StrCmp (Argv[Index], L"-m") == 0) {
221         //
222         // Parse the MAC address here.
223         //
224         Status = ConvertMac(Argv[Index+1]);
225         if (EFI_ERROR(Status)) {
226           PrintToken (STRING_TOKEN (STR_FWUPDATE_INVAILD_MAC), HiiHandle);
227           return Status;
228         }
229 
230         //
231         // Save the MAC address to mInputData.MacValue.
232         //
233         mInputData.UpdateMac= TRUE;
234         Index++;
235         } else {
236         //
237         // Invalid option was provided.
238         //
239         return EFI_INVALID_PARAMETER;
240       }
241     }
242     if ((Index == Argc - 1) && (StrCmp (Argv[Index - 1], L"-m") != 0)) {
243       //
244       // The only parameter that is not an option is the firmware image.  Check
245       // to make sure that the file exists.
246       //
247       Status = ShellIsFile (Argv[Index]);
248       if (EFI_ERROR (Status)) {
249         PrintToken (STRING_TOKEN (STR_FWUPDATE_FILE_NOT_FOUND_ERROR), HiiHandle, Argv[Index]);
250         return EFI_INVALID_PARAMETER;
251       }
252       if (StrLen (Argv[Index]) > INPUT_STRING_LEN) {
253         PrintToken (STRING_TOKEN (STR_FWUPDATE_PATH_ERROR), HiiHandle, Argv[Index]);
254         return EFI_INVALID_PARAMETER;
255       }
256       StrCpy (mInputData.FileName, Argv[Index]);
ShellAppMain(IN UINTN Argc,IN CHAR16 ** Argv)257       mInputData.UpdateFromFile = TRUE;
258     }
259   }
260 
261   return EFI_SUCCESS;
262 }
263 
264 INTN
265 EFIAPI
266 ShellAppMain (
267   IN UINTN Argc,
268   IN CHAR16 **Argv
269   )
270 {
271   EFI_STATUS            Status;
272   UINTN                 Index;
273   UINT32                FileSize;
274   UINT32                BufferSize;
275   UINT8                 *FileBuffer;
276   UINT8                 *Buffer;
277   EFI_PHYSICAL_ADDRESS  Address;
278   UINTN                 CountOfBlocks;
279   EFI_TPL               OldTpl;
280   BOOLEAN               ResetRequired;
281   BOOLEAN               FlashError;
282 
283   Index             = 0;
284   FileSize          = 0;
285   BufferSize        = 0;
286   FileBuffer        = NULL;
287   Buffer            = NULL;
288   Address           = 0;
289   CountOfBlocks     = 0;
290   ResetRequired     = FALSE;
291   FlashError        = FALSE;
292 
293   Status = EFI_SUCCESS;
294 
295   mInputData.FullFlashUpdate = TRUE;
296 
297   //
298   // Publish our HII data.
299   //
300   HiiHandle = HiiAddPackages (
301                 &gEfiCallerIdGuid,
302                 NULL,
303                 FirmwareUpdateStrings,
304                 NULL
305                 );
306   if (HiiHandle == NULL) {
307     Status = EFI_OUT_OF_RESOURCES;
308     goto Done;
309   }
310 
311   //
312   // Locate the SPI protocol.
313   //
314   Status = gBS->LocateProtocol (
315                   &gEfiSpiProtocolGuid,
316                   NULL,
317                   (VOID **)&mSpiProtocol
318                   );
319   if (EFI_ERROR (Status)) {
320     PrintToken (STRING_TOKEN (STR_SPI_NOT_FOUND), HiiHandle);
321     return EFI_DEVICE_ERROR;
322   }
323 
324   //
325   // Parse the command line.
326   //
327   Status = ParseCommandLine (Argc, Argv);
328   if (EFI_ERROR (Status)) {
329     PrintHelpInfo ();
330     Status = EFI_SUCCESS;
331     goto Done;
332   }
333 
334   //
335   // Display sign-on information.
336   //
337   PrintToken (STRING_TOKEN (STR_FWUPDATE_FIRMWARE_VOL_UPDATE), HiiHandle);
338   PrintToken (STRING_TOKEN (STR_FWUPDATE_VERSION), HiiHandle);
339   PrintToken (STRING_TOKEN (STR_FWUPDATE_COPYRIGHT), HiiHandle);
340 
341   //
342   // Test to see if the firmware needs to be updated.
343   //
344   if (mInputData.UpdateFromFile) {
345     //
346     // Get the file to use in the update.
347     //
348     PrintToken (STRING_TOKEN (STR_FWUPDATE_READ_FILE), HiiHandle, mInputData.FileName);
349     Status = ReadFileData (mInputData.FileName, &FileBuffer, &FileSize);
350     if (EFI_ERROR (Status)) {
351       PrintToken (STRING_TOKEN (STR_FWUPDATE_READ_FILE_ERROR), HiiHandle, mInputData.FileName);
352       goto Done;
353     }
354 
355     //
356     // Check that the file and flash sizes match.
357     //
358     if (FileSize != PcdGet32 (PcdFlashChipSize)) {
359       PrintToken (STRING_TOKEN (STR_FWUPDATE_SIZE), HiiHandle);
360       Status = EFI_UNSUPPORTED;
361       goto Done;
362     }
363 
364     //
365     // Display flash update information.
366     //
367     PrintToken (STRING_TOKEN (STR_FWUPDATE_UPDATING_FIRMWARE), HiiHandle);
368 
369     //
370     // Update it.
371     //
372     Buffer        = FileBuffer;
373     BufferSize    = FileSize;
374     Address       = PcdGet32 (PcdFlashChipBase);
375     CountOfBlocks = (UINTN) (BufferSize / BLOCK_SIZE);
376 
377     //
378     // Raise TPL to TPL_NOTIFY to block any event handler,
379     // while still allowing RaiseTPL(TPL_NOTIFY) within
380     // output driver during Print().
381     //
382     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
383     for (Index = 0; Index < CountOfBlocks; Index++) {
384       //
385       // Handle block based on address and contents.
386       //
387       if (!UpdateBlock (Address)) {
388         DEBUG((EFI_D_INFO, "Skipping block at 0x%lx\n", Address));
389       } else if (!EFI_ERROR (InternalCompareBlock (Address, Buffer))) {
390         DEBUG((EFI_D_INFO, "Skipping block at 0x%lx (already programmed)\n", Address));
391       } else {
392         //
393         // Display a dot for each block being updated.
394         //
395         Print (L".");
396 
397         //
398         // Flag that the flash image will be changed and the system must be rebooted
399         // to use the change.
400         //
401         ResetRequired = TRUE;
402 
403         //
404         // Make updating process uninterruptable,
405         // so that the flash memory area is not accessed by other entities
406         // which may interfere with the updating process.
407         //
408         Status  = InternalEraseBlock (Address);
409         ASSERT_EFI_ERROR(Status);
410         if (EFI_ERROR (Status)) {
411           gBS->RestoreTPL (OldTpl);
412           FlashError = TRUE;
413           goto Done;
414         }
415         Status = InternalWriteBlock (
416                   Address,
417                   Buffer,
418                   (BufferSize > BLOCK_SIZE ? BLOCK_SIZE : BufferSize)
419                   );
420         if (EFI_ERROR (Status)) {
421           gBS->RestoreTPL (OldTpl);
422           FlashError = TRUE;
423           goto Done;
424         }
425       }
426 
427       //
428       // Move to next block to update.
429       //
430       Address += BLOCK_SIZE;
431       Buffer += BLOCK_SIZE;
432       if (BufferSize > BLOCK_SIZE) {
433         BufferSize -= BLOCK_SIZE;
434       } else {
435         BufferSize = 0;
436       }
437     }
438     gBS->RestoreTPL (OldTpl);
439 
440     //
441     // Print result of update.
442     //
443     if (!FlashError) {
444       if (ResetRequired) {
445         Print (L"\n");
446         PrintToken (STRING_TOKEN (STR_FWUPDATE_UPDATE_SUCCESS), HiiHandle);
447       } else {
448         PrintToken (STRING_TOKEN (STR_FWUPDATE_NO_RESET), HiiHandle);
449       }
450     } else {
451       goto Done;
452     }
453   }
454 
455   //
456   // All flash updates are done so see if the system needs to be reset.
457   //
458   if (ResetRequired && !FlashError) {
459     //
460     // Update successful.
461     //
462     for (Index = 5; Index > 0; Index--) {
463       PrintToken (STRING_TOKEN (STR_FWUPDATE_SHUTDOWN), HiiHandle, Index);
464       gBS->Stall (1000000);
465     }
466 
467     gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
468     PrintToken (STRING_TOKEN (STR_FWUPDATE_MANUAL_RESET), HiiHandle);
469     CpuDeadLoop ();
470   }
471 
472 Done:
473   //
474   // Print flash update failure message if error detected.
475   //
476   if (FlashError) {
477     PrintToken (STRING_TOKEN (STR_FWUPDATE_UPDATE_FAILED), HiiHandle, Index);
478   }
479 
480   //
481   // Do cleanup.
482   //
483   if (HiiHandle != NULL) {
484     HiiRemovePackages (HiiHandle);
485   }
InternalEraseBlock(IN EFI_PHYSICAL_ADDRESS BaseAddress)486   if (FileBuffer) {
487     gBS->FreePool (FileBuffer);
488   }
489 
490   return Status;
491 }
492 
493 STATIC
494 EFI_STATUS
495 InternalEraseBlock (
496   IN  EFI_PHYSICAL_ADDRESS BaseAddress
497   )
498 /*++
499 
500 Routine Description:
501 
502   Erase the whole block.
503 
504 Arguments:
505 
506   BaseAddress  - Base address of the block to be erased.
507 
508 Returns:
509 
510   EFI_SUCCESS - The command completed successfully.
511   Other       - Device error or wirte-locked, operation failed.
512 
513 --*/
514 {
515   EFI_STATUS                              Status;
516   UINTN                                   NumBytes;
517 
518   NumBytes = BLOCK_SIZE;
519 
520   Status = SpiFlashBlockErase ((UINTN) BaseAddress, &NumBytes);
521 
522   return Status;
523 }
524 
525 #if 0
526 STATIC
527 EFI_STATUS
528 InternalReadBlock (
529   IN  EFI_PHYSICAL_ADDRESS  BaseAddress,
530   OUT VOID                  *ReadBuffer
531   )
532 {
533   EFI_STATUS    Status;
534   UINT32        BlockSize;
535 
536   BlockSize = BLOCK_SIZE;
InternalCompareBlock(IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT8 * Buffer)537 
538   Status = SpiFlashRead ((UINTN) BaseAddress, &BlockSize, ReadBuffer);
539 
540   return Status;
541 }
542 #endif
543 
544 STATIC
545 EFI_STATUS
546 InternalCompareBlock (
547   IN  EFI_PHYSICAL_ADDRESS        BaseAddress,
548   IN  UINT8                       *Buffer
549   )
550 {
551   EFI_STATUS                              Status;
552   VOID                                    *CompareBuffer;
553   UINT32                                  NumBytes;
554   INTN                                    CompareResult;
555 
556   NumBytes = BLOCK_SIZE;
557   CompareBuffer = AllocatePool (NumBytes);
558   if (CompareBuffer == NULL) {
559     Status = EFI_OUT_OF_RESOURCES;
560     goto Done;
561   }
562 
563   Status = SpiFlashRead ((UINTN) BaseAddress, &NumBytes, CompareBuffer);
564   if (EFI_ERROR (Status)) {
565     goto Done;
566   }
567   CompareResult = CompareMem (CompareBuffer, Buffer, BLOCK_SIZE);
568   if (CompareResult != 0) {
569     Status = EFI_VOLUME_CORRUPTED;
570   }
571 
572 Done:
InternalWriteBlock(IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT8 * Buffer,IN UINT32 BufferSize)573   if (CompareBuffer != NULL) {
574     FreePool (CompareBuffer);
575   }
576 
577   return Status;
578 }
579 
580 STATIC
581 EFI_STATUS
582 InternalWriteBlock (
583   IN  EFI_PHYSICAL_ADDRESS        BaseAddress,
584   IN  UINT8                       *Buffer,
585   IN  UINT32                      BufferSize
586   )
587 /*++
588 
589 Routine Description:
590 
591   Write a block of data.
592 
593 Arguments:
594 
595   BaseAddress  - Base address of the block.
596   Buffer       - Data buffer.
597   BufferSize   - Size of the buffer.
598 
599 Returns:
600 
601   EFI_SUCCESS           - The command completed successfully.
602   EFI_INVALID_PARAMETER - Invalid parameter, can not proceed.
603   Other                 - Device error or wirte-locked, operation failed.
604 
605 --*/
606 {
607   EFI_STATUS                              Status;
608 
609   Status = SpiFlashWrite ((UINTN) BaseAddress, &BufferSize, Buffer);
610   ASSERT_EFI_ERROR(Status);
611   if (EFI_ERROR (Status)) {
612     DEBUG((EFI_D_ERROR, "\nFlash write error."));
613     return Status;
614   }
615 
616   WriteBackInvalidateDataCacheRange ((VOID *) (UINTN) BaseAddress, BLOCK_SIZE);
617 
618   Status = InternalCompareBlock (BaseAddress, Buffer);
619   if (EFI_ERROR (Status)) {
620     DEBUG((EFI_D_ERROR, "\nError when writing to BaseAddress %lx with different at offset %x.", BaseAddress, Status));
621   } else {
ReadFileData(IN CHAR16 * FileName,OUT UINT8 ** Buffer,OUT UINT32 * BufferSize)622     DEBUG((EFI_D_INFO, "\nVerified data written to Block at %lx is correct.", BaseAddress));
623   }
624 
625   return Status;
626 
627 }
628 
629 STATIC
630 EFI_STATUS
631 ReadFileData (
632   IN  CHAR16   *FileName,
633   OUT UINT8    **Buffer,
634   OUT UINT32   *BufferSize
635   )
636 {
637   EFI_STATUS             Status;
638   SHELL_FILE_HANDLE      FileHandle;
639   UINT64                 Size;
640   VOID                   *NewBuffer;
641   UINTN                  ReadSize;
642 
643   FileHandle = NULL;
644   NewBuffer = NULL;
645   Size = 0;
646 
647   Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ, 0);
648   if (EFI_ERROR (Status)) {
649     goto Done;
650   }
651 
652   Status = FileHandleIsDirectory (FileHandle);
653   if (!EFI_ERROR (Status)) {
654     Status = EFI_NOT_FOUND;
655     goto Done;
656   }
657 
658   Status = FileHandleGetSize (FileHandle, &Size);
659   if (EFI_ERROR (Status)) {
660     goto Done;
661   }
662 
663   NewBuffer = AllocatePool ((UINTN) Size);
664 
665   ReadSize = (UINTN) Size;
666   Status = FileHandleRead (FileHandle, &ReadSize, NewBuffer);
667   if (EFI_ERROR (Status)) {
668     goto Done;
669   } else if (ReadSize != (UINTN) Size) {
670     Status = EFI_INVALID_PARAMETER;
671     goto Done;
672   }
673 
674 Done:
675   if (FileHandle != NULL) {
676     ShellCloseFile (&FileHandle);
677   }
678 
679   if (EFI_ERROR (Status)) {
680     if (NewBuffer != NULL) {
681       FreePool (NewBuffer);
682     }
683   } else {
PrintHelpInfo(VOID)684     *Buffer = NewBuffer;
685     *BufferSize = (UINT32) Size;
686   }
687 
688   return Status;
689 }
690 
691 STATIC
692 VOID
693 PrintHelpInfo (
694   VOID
695   )
696 /*++
697 
698 Routine Description:
699 
700   Print out help information.
701 
702 Arguments:
703 
704   None.
705 
706 Returns:
707 
708   None.
709 
710 --*/
711 {
712   PrintToken (STRING_TOKEN (STR_FWUPDATE_FIRMWARE_VOL_UPDATE), HiiHandle);
713   PrintToken (STRING_TOKEN (STR_FWUPDATE_VERSION), HiiHandle);
714   PrintToken (STRING_TOKEN (STR_FWUPDATE_COPYRIGHT), HiiHandle);
715 
716   Print (L"\n");
717   PrintToken (STRING_TOKEN (STR_FWUPDATE_USAGE), HiiHandle);
718   PrintToken (STRING_TOKEN (STR_FWUPDATE_USAGE_1), HiiHandle);
719   PrintToken (STRING_TOKEN (STR_FWUPDATE_USAGE_2), HiiHandle);
720   PrintToken (STRING_TOKEN (STR_FWUPDATE_USAGE_3), HiiHandle);
721   PrintToken (STRING_TOKEN (STR_FWUPDATE_USAGE_4), HiiHandle);
722 
723   Print (L"\n");
724 }
725 
726 /**
727   Read NumBytes bytes of data from the address specified by
728   PAddress into Buffer.
729 
730   @param[in]      Address       The starting physical address of the read.
731   @param[in,out]  NumBytes      On input, the number of bytes to read. On output, the number
SpiFlashRead(IN UINTN Address,IN OUT UINT32 * NumBytes,OUT UINT8 * Buffer)732                                 of bytes actually read.
733   @param[out]     Buffer        The destination data buffer for the read.
734 
735   @retval         EFI_SUCCESS       Opertion is successful.
736   @retval         EFI_DEVICE_ERROR  If there is any device errors.
737 
738 **/
739 EFI_STATUS
740 EFIAPI
741 SpiFlashRead (
742   IN     UINTN     Address,
743   IN OUT UINT32    *NumBytes,
744      OUT UINT8     *Buffer
745   )
746 {
747   EFI_STATUS    Status = EFI_SUCCESS;
748   UINTN         Offset = 0;
749 
750   ASSERT ((NumBytes != NULL) && (Buffer != NULL));
751 
752     Offset = Address - (UINTN)PcdGet32 (PcdFlashChipBase);
753 
754     Status = mSpiProtocol->Execute (
755                              mSpiProtocol,
756                              1, //SPI_READ,
757                              0, //SPI_WREN,
758                              TRUE,
759                              TRUE,
760                              FALSE,
761                              Offset,
762                              BLOCK_SIZE,
763                              Buffer,
764                              EnumSpiRegionAll
765                              );
766     return Status;
767 
768 }
769 
770 /**
771   Write NumBytes bytes of data from Buffer to the address specified by
772   PAddresss.
773 
774   @param[in]      Address         The starting physical address of the write.
775   @param[in,out]  NumBytes        On input, the number of bytes to write. On output,
SpiFlashWrite(IN UINTN Address,IN OUT UINT32 * NumBytes,IN UINT8 * Buffer)776                                   the actual number of bytes written.
777   @param[in]      Buffer          The source data buffer for the write.
778 
779   @retval         EFI_SUCCESS       Opertion is successful.
780   @retval         EFI_DEVICE_ERROR  If there is any device errors.
781 
782 **/
783 EFI_STATUS
784 EFIAPI
785 SpiFlashWrite (
786   IN     UINTN     Address,
787   IN OUT UINT32    *NumBytes,
788   IN     UINT8     *Buffer
789   )
790 {
791   EFI_STATUS                Status;
792   UINTN                     Offset;
793   UINT32                    Length;
794   UINT32                    RemainingBytes;
795 
796   ASSERT ((NumBytes != NULL) && (Buffer != NULL));
797   ASSERT (Address >= (UINTN)PcdGet32 (PcdFlashChipBase));
798 
799   Offset    = Address - (UINTN)PcdGet32 (PcdFlashChipBase);
800 
801   ASSERT ((*NumBytes + Offset) <= (UINTN)PcdGet32 (PcdFlashChipSize));
802 
803   Status = EFI_SUCCESS;
804   RemainingBytes = *NumBytes;
805 
806   while (RemainingBytes > 0) {
807     if (RemainingBytes > SIZE_4KB) {
808       Length = SIZE_4KB;
809     } else {
810       Length = RemainingBytes;
811     }
812     Status = mSpiProtocol->Execute (
813                              mSpiProtocol,
814                              SPI_PROG,
815                              SPI_WREN,
816                              TRUE,
817                              TRUE,
818                              TRUE,
819                              (UINT32) Offset,
820                              Length,
821                              Buffer,
822                              EnumSpiRegionAll
823                              );
824     if (EFI_ERROR (Status)) {
825       break;
826     }
827     RemainingBytes -= Length;
828     Offset += Length;
829     Buffer += Length;
830   }
831 
832   //
833   // Actual number of bytes written.
834   //
835   *NumBytes -= RemainingBytes;
836 
837   return Status;
838 }
839 
840 /**
841   Erase the block starting at Address.
842 
843   @param[in]  Address         The starting physical address of the block to be erased.
844                               This library assume that caller garantee that the PAddress
845                               is at the starting address of this block.
SpiFlashBlockErase(IN UINTN Address,IN UINTN * NumBytes)846   @param[in]  NumBytes        On input, the number of bytes of the logical block to be erased.
847                               On output, the actual number of bytes erased.
848 
849   @retval     EFI_SUCCESS.      Opertion is successful.
850   @retval     EFI_DEVICE_ERROR  If there is any device errors.
851 
852 **/
853 EFI_STATUS
854 EFIAPI
855 SpiFlashBlockErase (
856   IN UINTN    Address,
857   IN UINTN    *NumBytes
858   )
859 {
860   EFI_STATUS          Status;
861   UINTN               Offset;
862   UINTN               RemainingBytes;
863 
864   ASSERT (NumBytes != NULL);
865   ASSERT (Address >= (UINTN)PcdGet32 (PcdFlashChipBase));
866 
867   Offset    = Address - (UINTN)PcdGet32 (PcdFlashChipBase);
868 
869   ASSERT ((*NumBytes % SIZE_4KB) == 0);
870   ASSERT ((*NumBytes + Offset) <= (UINTN)PcdGet32 (PcdFlashChipSize));
871 
872   Status = EFI_SUCCESS;
873   RemainingBytes = *NumBytes;
874 
875     while (RemainingBytes > 0) {
876       Status = mSpiProtocol->Execute (
877                                mSpiProtocol,
878                                SPI_SERASE,
879                                SPI_WREN,
880                                FALSE,
881                                TRUE,
882                                FALSE,
883                                (UINT32) Offset,
884                                0,
885                                NULL,
886                                EnumSpiRegionAll
887                                );
888       if (EFI_ERROR (Status)) {
889         break;
890       }
891       RemainingBytes -= SIZE_4KB;
892       Offset         += SIZE_4KB;
893     }
894 
895   //
896   // Actual number of bytes erased.
897   //
898   *NumBytes -= RemainingBytes;
899 
900   return Status;
901 }
902 
903 EFI_STATUS
904 EFIAPI
905 ConvertMac (
906   CHAR16 *Str
907   )
908 {
909   UINTN Index;
910   UINT8 Temp[MAC_ADD_STR_LEN];
911 
912   if (Str == NULL)
913     return EFI_INVALID_PARAMETER;
914 
915   if (StrLen(Str) != MAC_ADD_STR_LEN)
916     return EFI_INVALID_PARAMETER;
917 
918   for (Index = 0; Index < MAC_ADD_STR_LEN; Index++) {
919     if (Str[Index] >= 0x30 && Str[Index] <= 0x39) {
920       Temp[Index] = (UINT8)Str[Index] - 0x30;
921     } else if (Str[Index] >= 0x41 && Str[Index] <= 0x46) {
922       Temp[Index] = (UINT8)Str[Index] - 0x37;
923     } else if (Str[Index] >= 0x61 && Str[Index] <= 0x66) {
924       Temp[Index] = (UINT8)Str[Index] - 0x57;
925     } else {
926       return EFI_INVALID_PARAMETER;
927     }
928   }
929 
930   for (Index = 0; Index < MAC_ADD_BYTE_COUNT; Index++) {
931     mInputData.MacValue[Index] = (Temp[2 * Index] << 4) + Temp[2 * Index + 1];
932   }
933 
934   return EFI_SUCCESS;
935 }
936 
937