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