• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 Reading/writing MBR/DBR.
3   NOTE:
4     If we write MBR to disk, we just update the MBR code and the partition table wouldn't be over written.
5     If we process DBR, we will patch MBR to set first partition active if no active partition exists.
6 
7 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution.  The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12 
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 
16 **/
17 
18 #include <windows.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <Common/UefiBaseTypes.h>
22 
23 #include "ParseInf.h"
24 #include "EfiUtilityMsgs.h"
25 #include "CommonLib.h"
26 
27 //
28 // Utility Name
29 //
30 #define UTILITY_NAME  "GenBootSector"
31 
32 //
33 // Utility version information
34 //
35 #define UTILITY_MAJOR_VERSION 0
36 #define UTILITY_MINOR_VERSION 2
37 
38 #define MAX_DRIVE                             26
39 #define PARTITION_TABLE_OFFSET                0x1BE
40 
41 #define SIZE_OF_PARTITION_ENTRY               0x10
42 
43 #define PARTITION_ENTRY_STARTLBA_OFFSET       8
44 
45 #define PARTITION_ENTRY_NUM                   4
46 
47 INT
48 GetDrvNumOffset (
49   IN VOID *BootSector
50   );
51 
52 typedef enum {
53   PatchTypeUnknown,
54   PatchTypeFloppy,
55   PatchTypeIde,
56   PatchTypeUsb,
57   PatchTypeFileImage   // input and output are all file image, patching action is same as PatchTypeFloppy
58 } PATCH_TYPE;
59 
60 typedef enum {
61   PathUnknown,
62   PathFile,
63   PathFloppy,
64   PathUsb,
65   PathIde
66 } PATH_TYPE;
67 
68 typedef enum {
69   ErrorSuccess,
70   ErrorFileCreate,
71   ErrorFileReadWrite,
72   ErrorNoMbr,
73   ErrorFatType,
74   ErrorPath,
75 } ERROR_STATUS;
76 
77 CHAR *ErrorStatusDesc[] = {
78   "Success",
79   "Failed to create files",
80   "Failed to read/write files",
81   "No MBR exists",
82   "Failed to detect Fat type",
83   "Inavlid path"
84 };
85 
86 typedef struct _DRIVE_TYPE_DESC {
87   UINT  Type;
88   CHAR  *Description;
89 } DRIVE_TYPE_DESC;
90 
91 #define DRIVE_TYPE_ITEM(x) {x, #x}
92 DRIVE_TYPE_DESC DriveTypeDesc[] = {
93   DRIVE_TYPE_ITEM (DRIVE_UNKNOWN),
94   DRIVE_TYPE_ITEM (DRIVE_NO_ROOT_DIR),
95   DRIVE_TYPE_ITEM (DRIVE_REMOVABLE),
96   DRIVE_TYPE_ITEM (DRIVE_FIXED),
97   DRIVE_TYPE_ITEM (DRIVE_REMOTE),
98   DRIVE_TYPE_ITEM (DRIVE_CDROM),
99   DRIVE_TYPE_ITEM (DRIVE_RAMDISK),
100   (UINT) -1, NULL
101 };
102 
103 typedef struct _DRIVE_INFO {
104   CHAR              VolumeLetter;
105   DRIVE_TYPE_DESC   *DriveType;
106   UINT              DiskNumber;
107 } DRIVE_INFO;
108 
109 typedef struct _PATH_INFO {
110   CHAR             *Path;
111   CHAR             PhysicalPath[260];
112   PATH_TYPE        Type;
113   BOOL             Input;
114 } PATH_INFO;
115 
116 #define BOOT_SECTOR_LBA_OFFSET 0x1FA
117 
118 #define IsLetter(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z'))
119 
120 BOOL
GetDriveInfo(CHAR VolumeLetter,DRIVE_INFO * DriveInfo)121 GetDriveInfo (
122   CHAR       VolumeLetter,
123   DRIVE_INFO *DriveInfo
124   )
125 /*++
126 Routine Description:
127   Get drive information including disk number and drive type,
128   where disknumber is useful for reading/writing disk raw data.
129   NOTE: Floppy disk doesn't have disk number but it doesn't matter because
130         we can reading/writing floppy disk without disk number.
131 
132 Arguments:
133   VolumeLetter : volume letter, e.g.: C for C:, A for A:
134   DriveInfo    : pointer to DRIVE_INFO structure receiving drive information.
135 
136 Return:
137   TRUE  : successful
138   FALSE : failed
139 --*/
140 {
141   HANDLE                  VolumeHandle;
142   STORAGE_DEVICE_NUMBER   StorageDeviceNumber;
143   DWORD                   BytesReturned;
144   BOOL                    Success;
145   UINT                    DriveType;
146   UINT                    Index;
147 
148   CHAR RootPath[]         = "X:\\";       // "X:\"  -> for GetDriveType
149   CHAR VolumeAccessPath[] = "\\\\.\\X:";  // "\\.\X:"  -> to open the volume
150 
151   RootPath[0] = VolumeAccessPath[4] = VolumeLetter;
152   DriveType = GetDriveType(RootPath);
153   if (DriveType != DRIVE_REMOVABLE && DriveType != DRIVE_FIXED) {
154     return FALSE;
155   }
156 
157   DriveInfo->VolumeLetter = VolumeLetter;
158   VolumeHandle = CreateFile (
159                    VolumeAccessPath,
160                    0,
161                    FILE_SHARE_READ | FILE_SHARE_WRITE,
162                    NULL,
163                    OPEN_EXISTING,
164                    0,
165                    NULL
166                    );
167   if (VolumeHandle == INVALID_HANDLE_VALUE) {
168     fprintf (
169       stderr,
170       "error E0005: CreateFile failed: Volume = %s, LastError = 0x%lx\n",
171       VolumeAccessPath,
172       GetLastError ()
173       );
174     return FALSE;
175   }
176 
177   //
178   // Get Disk Number. It should fail when operating on floppy. That's ok
179   //  because Disk Number is only needed when operating on Hard or USB disk.
180   //
181   // To direct write to disk:
182   //   for USB and HD: use path = \\.\PHYSICALDRIVEx, where x is Disk Number
183   //   for floppy:     use path = \\.\X:, where X can be A or B
184   //
185   Success = DeviceIoControl(
186               VolumeHandle,
187               IOCTL_STORAGE_GET_DEVICE_NUMBER,
188               NULL,
189               0,
190               &StorageDeviceNumber,
191               sizeof(StorageDeviceNumber),
192               &BytesReturned,
193               NULL
194               );
195   //
196   // DeviceIoControl should fail if Volume is floppy or network drive.
197   //
198   if (!Success) {
199     DriveInfo->DiskNumber = (UINT) -1;
200   } else if (StorageDeviceNumber.DeviceType != FILE_DEVICE_DISK) {
201     //
202     // Only care about the disk.
203     //
204     CloseHandle(VolumeHandle);
205     return FALSE;
206   } else{
207     DriveInfo->DiskNumber = StorageDeviceNumber.DeviceNumber;
208   }
209   CloseHandle(VolumeHandle);
210 
211   //
212   // Fill in the type string
213   //
214   DriveInfo->DriveType = NULL;
215   for (Index = 0; DriveTypeDesc[Index].Description != NULL; Index ++) {
216     if (DriveType == DriveTypeDesc[Index].Type) {
217       DriveInfo->DriveType = &DriveTypeDesc[Index];
218       break;
219     }
220   }
221 
222   if (DriveInfo->DriveType == NULL) {
223     //
224     // Should have a type.
225     //
226     fprintf (stderr, "error E3005: Fatal Error!!!\n");
227     return FALSE;
228   }
229   return TRUE;
230 }
231 
232 VOID
ListDrive(VOID)233 ListDrive (
234   VOID
235   )
236 /*++
237 Routine Description:
238   List every drive in current system and their information.
239 
240 --*/
241 {
242   UINT       Index;
243   DRIVE_INFO DriveInfo;
244 
245   UINT Mask =  GetLogicalDrives();
246 
247   for (Index = 0; Index < MAX_DRIVE; Index++) {
248     if (((Mask >> Index) & 0x1) == 1) {
249       if (GetDriveInfo ('A' + (CHAR) Index, &DriveInfo)) {
250         if (Index < 2) {
251           // Floppy will occupy 'A' and 'B'
252           fprintf (
253             stdout,
254             "%c: - Type: %s\n",
255             DriveInfo.VolumeLetter,
256             DriveInfo.DriveType->Description
257             );
258         } else {
259           fprintf (
260             stdout,
261             "%c: - DiskNum: %u, Type: %s\n",
262             DriveInfo.VolumeLetter,
263             (unsigned) DriveInfo.DiskNumber,
264             DriveInfo.DriveType->Description
265             );
266         }
267       }
268     }
269   }
270 
271 }
272 
273 INT
GetBootSectorOffset(HANDLE DiskHandle,PATH_INFO * PathInfo)274 GetBootSectorOffset (
275   HANDLE     DiskHandle,
276   PATH_INFO  *PathInfo
277   )
278 /*++
279 Description:
280   Get the offset of boot sector.
281   For non-MBR disk, offset is just 0
282   for disk with MBR, offset needs to be calculated by parsing MBR
283 
284   NOTE: if no one is active, we will patch MBR to select first partition as active.
285 
286 Arguments:
287   DiskHandle  : HANDLE of disk
288   PathInfo    : PATH_INFO structure.
289   WriteToDisk : TRUE indicates writing
290 
291 Return:
292   -1   : failed
293   o.w. : Offset to boot sector
294 --*/
295 {
296   BYTE    DiskPartition[0x200];
297   DWORD   BytesReturn;
298   DWORD   DbrOffset;
299   DWORD   Index;
300   BOOL    HasMbr;
301 
302   DbrOffset = 0;
303   HasMbr    = FALSE;
304 
305   SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN);
306   if (!ReadFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {
307     return -1;
308   }
309 
310   //
311   // Check Signature, Jmp, and Boot Indicator.
312   // if all pass, we assume MBR found.
313   //
314 
315   // Check Signature: 55AA
316   if ((DiskPartition[0x1FE] == 0x55) && (DiskPartition[0x1FF] == 0xAA)) {
317     // Check Jmp: (EB ?? 90) or (E9 ?? ??)
318     if (((DiskPartition[0] != 0xEB) || (DiskPartition[2] != 0x90)) &&
319         (DiskPartition[0] != 0xE9)) {
320       // Check Boot Indicator: 0x00 or 0x80
321       // Boot Indicator is the first byte of Partition Entry
322       HasMbr = TRUE;
323       for (Index = 0; Index < PARTITION_ENTRY_NUM; ++Index) {
324         if ((DiskPartition[PARTITION_TABLE_OFFSET + Index * SIZE_OF_PARTITION_ENTRY] & 0x7F) != 0) {
325           HasMbr = FALSE;
326           break;
327         }
328       }
329     }
330   }
331 
332   if (HasMbr) {
333     //
334     // Skip MBR
335     //
336     for (Index = 0; Index < PARTITION_ENTRY_NUM; Index++) {
337       //
338       // Found Boot Indicator.
339       //
340       if (DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY)] == 0x80) {
341         DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY) + PARTITION_ENTRY_STARTLBA_OFFSET];
342         break;
343       }
344     }
345     //
346     // If no boot indicator, we manually select 1st partition, and patch MBR.
347     //
348     if (Index == PARTITION_ENTRY_NUM) {
349       DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + PARTITION_ENTRY_STARTLBA_OFFSET];
350       if (!PathInfo->Input && (PathInfo->Type == PathUsb)) {
351         SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN);
352         DiskPartition[PARTITION_TABLE_OFFSET] = 0x80;
353         WriteFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL);
354       }
355     }
356   }
357 
358   return DbrOffset;
359 }
360 
361 /**
362  * Get window file handle for input/ouput disk/file.
363  *
364  * @param PathInfo
365  * @param ProcessMbr
366  * @param FileHandle
367  *
368  * @return ERROR_STATUS
369  */
370 ERROR_STATUS
GetFileHandle(PATH_INFO * PathInfo,BOOL ProcessMbr,HANDLE * FileHandle,DWORD * DbrOffset)371 GetFileHandle (
372   PATH_INFO  *PathInfo,
373   BOOL       ProcessMbr,
374   HANDLE     *FileHandle,
375   DWORD      *DbrOffset
376   )
377 {
378   DWORD  OpenFlag;
379 
380   OpenFlag = OPEN_ALWAYS;
381   if (PathInfo->Input || PathInfo->Type != PathFile) {
382     OpenFlag = OPEN_EXISTING;
383   }
384 
385   *FileHandle = CreateFile(
386                    PathInfo->PhysicalPath,
387                    GENERIC_READ | GENERIC_WRITE,
388                    FILE_SHARE_READ,
389                    NULL,
390                    OpenFlag,
391                    FILE_ATTRIBUTE_NORMAL,
392                    NULL
393                    );
394   if (*FileHandle == INVALID_HANDLE_VALUE) {
395     return ErrorFileCreate;
396   }
397 
398   if ((PathInfo->Type == PathIde) || (PathInfo->Type == PathUsb)){
399     *DbrOffset = GetBootSectorOffset (*FileHandle, PathInfo);
400     if (!ProcessMbr) {
401       //
402       // 1. Process boot sector, set file pointer to the beginning of boot sector
403       //
404       SetFilePointer (*FileHandle, *DbrOffset * 0x200, NULL, FILE_BEGIN);
405     } else if(*DbrOffset == 0) {
406       //
407       // If user want to process Mbr, but no Mbr exists, simply return FALSE
408       //
409       return ErrorNoMbr;
410     } else {
411       //
412       // 2. Process MBR, set file pointer to 0
413       //
414       SetFilePointer (*FileHandle, 0, NULL, FILE_BEGIN);
415     }
416   }
417 
418   return ErrorSuccess;
419 }
420 
421 /**
422   Writing or reading boot sector or MBR according to the argument.
423 
424   @param InputInfo PATH_INFO instance for input path
425   @param OutputInfo PATH_INFO instance for output path
426   @param ProcessMbr TRUE is to process MBR, otherwise, processing boot sector
427 
428   @return ERROR_STATUS
429  **/
430 ERROR_STATUS
ProcessBsOrMbr(PATH_INFO * InputInfo,PATH_INFO * OutputInfo,BOOL ProcessMbr)431 ProcessBsOrMbr (
432   PATH_INFO     *InputInfo,
433   PATH_INFO     *OutputInfo,
434   BOOL        	ProcessMbr
435   )
436 {
437   BYTE              DiskPartition[0x200] = {0};
438   BYTE              DiskPartitionBackup[0x200] = {0};
439   DWORD             BytesReturn;
440   INT               DrvNumOffset;
441   HANDLE            InputHandle = INVALID_HANDLE_VALUE;
442   HANDLE            OutputHandle = INVALID_HANDLE_VALUE;
443   ERROR_STATUS      Status;
444   DWORD             InputDbrOffset;
445   DWORD             OutputDbrOffset;
446 
447   //
448   // Create file Handle and move file Pointer is pointed to beginning of Mbr or Dbr
449   //
450   Status =  GetFileHandle(InputInfo, ProcessMbr, &InputHandle, &InputDbrOffset);
451   if (Status != ErrorSuccess) {
452     goto Done;
453   }
454 
455   //
456   // Create file Handle and move file Pointer is pointed to beginning of Mbr or Dbr
457   //
458   Status = GetFileHandle(OutputInfo, ProcessMbr, &OutputHandle, &OutputDbrOffset);
459   if (Status != ErrorSuccess) {
460     goto Done;
461   }
462 
463   //
464   // Read boot sector from source disk/file
465   //
466   if (!ReadFile (InputHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {
467     Status = ErrorFileReadWrite;
468     goto Done;
469   }
470 
471   if (InputInfo->Type == PathUsb) {
472       // Manually set BS_DrvNum to 0x80 as window's format.exe has a bug which will clear this field discarding USB disk's MBR.
473       // offset of BS_DrvNum is 0x24 for FAT12/16
474       //                        0x40 for FAT32
475       //
476       DrvNumOffset = GetDrvNumOffset (DiskPartition);
477       if (DrvNumOffset == -1) {
478         Status = ErrorFatType;
479         goto Done;
480       }
481       //
482       // Some legacy BIOS require 0x80 discarding MBR.
483       // Question left here: is it needed to check Mbr before set 0x80?
484       //
485       DiskPartition[DrvNumOffset] = ((InputDbrOffset > 0) ? 0x80 : 0);
486   }
487 
488   if (InputInfo->Type == PathIde) {
489       //
490       // Patch LBAOffsetForBootSector
491       //
492       *(DWORD *)&DiskPartition [BOOT_SECTOR_LBA_OFFSET] = InputDbrOffset;
493   }
494 
495   if (OutputInfo->Type != PathFile) {
496     if (ProcessMbr) {
497       //
498       // Use original partition table
499       //
500       if (!ReadFile (OutputHandle, DiskPartitionBackup, 0x200, &BytesReturn, NULL)) {
501         Status = ErrorFileReadWrite;
502         goto Done;
503       }
504       memcpy (DiskPartition + 0x1BE, DiskPartitionBackup + 0x1BE, 0x40);
505       SetFilePointer (OutputHandle, 0, NULL, FILE_BEGIN);
506 
507     }
508   }
509 
510   //
511   // Write boot sector to taget disk/file
512   //
513   if (!WriteFile (OutputHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {
514     Status = ErrorFileReadWrite;
515     goto Done;
516   }
517 
518 Done:
519   if (InputHandle != INVALID_HANDLE_VALUE) {
520     CloseHandle (InputHandle);
521   }
522   if (OutputHandle != INVALID_HANDLE_VALUE) {
523     CloseHandle (OutputHandle);
524   }
525 
526   return Status;
527 }
528 
529 void
Version(void)530 Version (
531   void
532   )
533 /*++
534 
535 Routine Description:
536 
537   Displays the standard utility information to SDTOUT
538 
539 Arguments:
540 
541   None
542 
543 Returns:
544 
545   None
546 
547 --*/
548 {
549   printf ("%s Version %d.%d %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
550 }
551 
552 VOID
PrintUsage(void)553 PrintUsage (
554   void
555   )
556 {
557   printf ("Usage: GenBootSector [options] --cfg-file CFG_FILE\n\n\
558 Copyright (c) 2009 - 2014, Intel Corporation.  All rights reserved.\n\n\
559   Utility to retrieve and update the boot sector or MBR.\n\n\
560 optional arguments:\n\
561   -h, --help            Show this help message and exit\n\
562   --version             Show program's version number and exit\n\
563   -d [DEBUG], --debug [DEBUG]\n\
564                         Output DEBUG statements, where DEBUG_LEVEL is 0 (min)\n\
565                         - 9 (max)\n\
566   -v, --verbose         Print informational statements\n\
567   -q, --quiet           Returns the exit code, error messages will be\n\
568                         displayed\n\
569   -s, --silent          Returns only the exit code; informational and error\n\
570                         messages are not displayed\n\
571   -l, --list            List disk drives\n\
572   -i INPUT_FILENAME, --input INPUT_FILENAME\n\
573                         Input file name\n\
574   -o OUTPUT_FILENAME, --output OUTPUT_FILENAME\n\
575                         Output file name\n\
576   -m, --mbr             Also process the MBR\n\
577   --sfo                 Reserved for future use\n");
578 
579 }
580 
581 /**
582   Get path information, including physical path for windows platform.
583 
584   @param PathInfo   Point to PATH_INFO structure.
585 
586   @return whether path is valid.
587 **/
588 ERROR_STATUS
GetPathInfo(PATH_INFO * PathInfo)589 GetPathInfo (
590   PATH_INFO   *PathInfo
591   )
592 {
593   DRIVE_INFO  DriveInfo;
594   CHAR        VolumeLetter;
595   CHAR        DiskPathTemplate[]   = "\\\\.\\PHYSICALDRIVE%u";
596   CHAR        FloppyPathTemplate[] = "\\\\.\\%c:";
597   FILE        *f;
598 
599   //
600   // If path is disk path
601   //
602   if (IsLetter(PathInfo->Path[0]) && (PathInfo->Path[1] == ':') && (PathInfo->Path[2] == '\0')) {
603     VolumeLetter = PathInfo->Path[0];
604     if ((VolumeLetter == 'A') || (VolumeLetter == 'a') ||
605         (VolumeLetter == 'B') || (VolumeLetter == 'b')) {
606       PathInfo->Type = PathFloppy;
607       sprintf (PathInfo->PhysicalPath, FloppyPathTemplate, VolumeLetter);
608       return ErrorSuccess;
609     }
610 
611     if (!GetDriveInfo(VolumeLetter, &DriveInfo)) {
612       fprintf (stderr, "ERROR: GetDriveInfo - 0x%lx\n", GetLastError ());
613       return ErrorPath;
614     }
615 
616     if (!PathInfo->Input && (DriveInfo.DriveType->Type == DRIVE_FIXED)) {
617       fprintf (stderr, "ERROR: Could patch own IDE disk!\n");
618       return ErrorPath;
619     }
620 
621     sprintf(PathInfo->PhysicalPath, DiskPathTemplate, DriveInfo.DiskNumber);
622     if (DriveInfo.DriveType->Type == DRIVE_REMOVABLE) {
623       PathInfo->Type = PathUsb;
624     } else if (DriveInfo.DriveType->Type == DRIVE_FIXED) {
625       PathInfo->Type = PathIde;
626     } else {
627       fprintf (stderr, "ERROR, Invalid disk path - %s", PathInfo->Path);
628       return ErrorPath;
629     }
630 
631 	return ErrorSuccess;
632   }
633 
634   PathInfo->Type = PathFile;
635   if (PathInfo->Input) {
636     //
637     // If path is file path, check whether file is valid.
638     //
639     f = fopen (LongFilePath (PathInfo->Path), "r");
640     if (f == NULL) {
641       fprintf (stderr, "error E2003: File was not provided!\n");
642       return ErrorPath;
643     }
644     fclose (f);
645   }
646   PathInfo->Type = PathFile;
647   strcpy(PathInfo->PhysicalPath, PathInfo->Path);
648 
649   return ErrorSuccess;
650 }
651 
652 INT
main(INT argc,CHAR * argv[])653 main (
654   INT  argc,
655   CHAR *argv[]
656   )
657 {
658   CHAR8         *AppName;
659   INTN          Index;
660   BOOLEAN       ProcessMbr;
661   ERROR_STATUS  Status;
662   EFI_STATUS    EfiStatus;
663   PATH_INFO     InputPathInfo = {0};
664   PATH_INFO     OutputPathInfo = {0};
665   UINT64        LogLevel;
666 
667   SetUtilityName (UTILITY_NAME);
668 
669   AppName = *argv;
670   argv ++;
671   argc --;
672 
673   ProcessMbr    = FALSE;
674 
675   if (argc == 0) {
676     PrintUsage();
677     return 0;
678   }
679 
680   //
681   // Parse command line
682   //
683   for (Index = 0; Index < argc; Index ++) {
684     if ((stricmp (argv[Index], "-l") == 0) || (stricmp (argv[Index], "--list") == 0)) {
685       ListDrive ();
686       return 0;
687     }
688 
689     if ((stricmp (argv[Index], "-m") == 0) || (stricmp (argv[Index], "--mbr") == 0)) {
690       ProcessMbr = TRUE;
691       continue;
692     }
693 
694     if ((stricmp (argv[Index], "-i") == 0) || (stricmp (argv[Index], "--input") == 0)) {
695       InputPathInfo.Path  = argv[Index + 1];
696       InputPathInfo.Input = TRUE;
697       if (InputPathInfo.Path == NULL) {
698         Error (NULL, 0, 1003, "Invalid option value", "Input file name can't be NULL");
699         return 1;
700       }
701       if (InputPathInfo.Path[0] == '-') {
702         Error (NULL, 0, 1003, "Invalid option value", "Input file is missing");
703         return 1;
704       }
705       ++Index;
706       continue;
707     }
708 
709     if ((stricmp (argv[Index], "-o") == 0) || (stricmp (argv[Index], "--output") == 0)) {
710       OutputPathInfo.Path  = argv[Index + 1];
711       OutputPathInfo.Input = FALSE;
712       if (OutputPathInfo.Path == NULL) {
713         Error (NULL, 0, 1003, "Invalid option value", "Output file name can't be NULL");
714         return 1;
715       }
716       if (OutputPathInfo.Path[0] == '-') {
717         Error (NULL, 0, 1003, "Invalid option value", "Output file is missing");
718         return 1;
719       }
720       ++Index;
721       continue;
722     }
723 
724     if ((stricmp (argv[Index], "-h") == 0) || (stricmp (argv[Index], "--help") == 0)) {
725       PrintUsage ();
726       return 0;
727     }
728 
729     if (stricmp (argv[Index], "--version") == 0) {
730       Version ();
731       return 0;
732     }
733 
734     if ((stricmp (argv[Index], "-v") == 0) || (stricmp (argv[Index], "--verbose") == 0)) {
735       continue;
736     }
737 
738     if ((stricmp (argv[Index], "-q") == 0) || (stricmp (argv[Index], "--quiet") == 0)) {
739       continue;
740     }
741 
742     if ((stricmp (argv[Index], "-d") == 0) || (stricmp (argv[Index], "--debug") == 0)) {
743       EfiStatus = AsciiStringToUint64 (argv[Index + 1], FALSE, &LogLevel);
744       if (EFI_ERROR (EfiStatus)) {
745         Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[Index], argv[Index + 1]);
746         return 1;
747       }
748       if (LogLevel > 9) {
749         Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) LogLevel);
750         return 1;
751       }
752       SetPrintLevel (LogLevel);
753       DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[Index + 1]);
754       ++Index;
755       continue;
756     }
757 
758     //
759     // Don't recognize the parameter.
760     //
761     Error (NULL, 0, 1000, "Unknown option", "%s", argv[Index]);
762     return 1;
763   }
764 
765   if (InputPathInfo.Path == NULL) {
766     Error (NULL, 0, 1001, "Missing options", "Input file is missing");
767     return 1;
768   }
769 
770   if (OutputPathInfo.Path == NULL) {
771     Error (NULL, 0, 1001, "Missing options", "Output file is missing");
772     return 1;
773   }
774 
775   if (GetPathInfo(&InputPathInfo) != ErrorSuccess) {
776     Error (NULL, 0, 1003, "Invalid option value", "Input file can't be found.");
777     return 1;
778   }
779 
780   if (GetPathInfo(&OutputPathInfo) != ErrorSuccess) {
781     Error (NULL, 0, 1003, "Invalid option value", "Output file can't be found.");
782     return 1;
783   }
784 
785   //
786   // Process DBR (Patch or Read)
787   //
788   Status = ProcessBsOrMbr (&InputPathInfo, &OutputPathInfo, ProcessMbr);
789 
790   if (Status == ErrorSuccess) {
791     fprintf (
792       stdout,
793       "%s %s: successful!\n",
794       (OutputPathInfo.Type != PathFile) ? "Write" : "Read",
795       ProcessMbr ? "MBR" : "DBR"
796       );
797     return 0;
798   } else {
799     fprintf (
800       stderr,
801       "%s: %s %s: failed - %s (LastError: 0x%lx)!\n",
802       (Status == ErrorNoMbr) ? "WARNING" : "ERROR",
803       (OutputPathInfo.Type != PathFile) ? "Write" : "Read",
804       ProcessMbr ? "MBR" : "DBR",
805       ErrorStatusDesc[Status],
806       GetLastError ()
807       );
808     return 1;
809   }
810 }
811