• 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 - 2014, 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 "CommonLib.h"
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <Common/UefiBaseTypes.h>
23 
24 #include "ParseInf.h"
25 #include "EfiUtilityMsgs.h"
26 
27 //
28 // Utility Name
29 //
30 #define UTILITY_NAME  "GnuGenBootSector"
31 
32 //
33 // Utility version information
34 //
35 #define UTILITY_MAJOR_VERSION 0
36 #define UTILITY_MINOR_VERSION 1
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 #define DRIVE_UNKNOWN     0
48 #define DRIVE_NO_ROOT_DIR 1
49 #define DRIVE_REMOVABLE   2
50 #define DRIVE_FIXED       3
51 #define DRIVE_REMOTE      4
52 #define DRIVE_CDROM       5
53 #define DRIVE_RAMDISK     6
54 
55 typedef struct _DRIVE_TYPE_DESC {
56   UINTN  Type;
57   CHAR8  *Description;
58 } DRIVE_TYPE_DESC;
59 
60 #define DRIVE_TYPE_ITEM(x) {x, #x}
61 
62 DRIVE_TYPE_DESC DriveTypeDesc[] = {
63   DRIVE_TYPE_ITEM (DRIVE_UNKNOWN),
64   DRIVE_TYPE_ITEM (DRIVE_NO_ROOT_DIR),
65   DRIVE_TYPE_ITEM (DRIVE_REMOVABLE),
66   DRIVE_TYPE_ITEM (DRIVE_FIXED),
67   DRIVE_TYPE_ITEM (DRIVE_REMOTE),
68   DRIVE_TYPE_ITEM (DRIVE_CDROM),
69   DRIVE_TYPE_ITEM (DRIVE_RAMDISK),
70   {(UINTN) -1, NULL}
71 };
72 
73 typedef struct _DRIVE_INFO {
74   CHAR8             VolumeLetter;
75   DRIVE_TYPE_DESC   *DriveType;
76   UINTN             DiskNumber;
77 } DRIVE_INFO;
78 
79 typedef enum {
80   PathUnknown,
81   PathFile,
82   PathFloppy,
83   PathUsb,
84   PathIde
85 } PATH_TYPE;
86 
87 typedef struct _PATH_INFO {
88   CHAR8            *Path;
89   CHAR8            PhysicalPath[260];
90   PATH_TYPE        Type;
91   BOOLEAN          Input;
92 } PATH_INFO;
93 
94 typedef enum {
95   ErrorSuccess,
96   ErrorFileCreate,
97   ErrorFileReadWrite,
98   ErrorNoMbr,
99   ErrorFatType,
100   ErrorPath,
101 } ERROR_STATUS;
102 
103 CHAR8 *ErrorStatusDesc[] = {
104   "Success",
105   "Failed to create files",
106   "Failed to read/write files",
107   "No MBR exists",
108   "Failed to detect Fat type",
109   "Inavlid path"
110 };
111 
112 
113 //UnSupported Windows API functions.
GetLogicalDrives(void)114 UINTN GetLogicalDrives(void) { return 1; }
115 
116 
117 
118 /**
119   Get path information, including physical path for Linux platform.
120 
121   @param PathInfo   Point to PATH_INFO structure.
122 
123   @return whether path is valid.
124 **/
125 ERROR_STATUS
GetPathInfo(PATH_INFO * PathInfo)126 GetPathInfo (
127   PATH_INFO   *PathInfo
128   )
129 {
130   FILE        *f;
131 
132   if (strncmp(PathInfo->Path, "/dev/", 5) == 0) {
133     //
134     // Process disk path here.
135     //
136 
137     // Process floppy disk
138     if (PathInfo->Path[5] == 'f' && PathInfo->Path[6] == 'd' && PathInfo->Path[8] == '\0') {
139       PathInfo->Type = PathFloppy;
140       strcpy (PathInfo->PhysicalPath, PathInfo->Path);
141 
142       return ErrorSuccess;
143     } else {
144     // Other disk types is not supported yet.
145     fprintf (stderr, "ERROR: It's not a floppy disk!\n");
146     return ErrorPath;
147     }
148 
149     // Try to open the device.
150     f = fopen (LongFilePath (PathInfo->Path),"r");
151     if (f == NULL) {
152       printf ("error :open device failed!\n");
153       return ErrorPath;
154     }
155     fclose (f);
156     return ErrorSuccess;
157   }
158 
159   // Process file path here.
160   PathInfo->Type = PathFile;
161   if (PathInfo->Input) {
162     // If path is file path, check whether file is valid.
163     printf("Path = %s\n",PathInfo->Path);
164     f = fopen (LongFilePath (PathInfo->Path), "r");
165     if (f == NULL) {
166       fprintf (stderr, "Test error E2003: File was not provided!\n");
167       return ErrorPath;
168     }
169     fclose (f);
170   }
171 
172   strcpy(PathInfo->PhysicalPath, PathInfo->Path);
173   return ErrorSuccess;
174 
175 }
176 
177 VOID
ListDrive(VOID)178 ListDrive (
179   VOID
180   )
181 {
182   printf("-l or -list not supported!\n");
183 }
184 
185 /**
186   Writing or reading boot sector or MBR according to the argument.
187 
188   @param InputInfo PATH_INFO instance for input path
189   @param OutputInfo PATH_INFO instance for output path
190   @param ProcessMbr TRUE is to process MBR, otherwise, processing boot sector
191 
192   @return ERROR_STATUS
193  **/
194 ERROR_STATUS
ProcessBsOrMbr(PATH_INFO * InputInfo,PATH_INFO * OutputInfo,BOOLEAN ProcessMbr)195 ProcessBsOrMbr (
196   PATH_INFO     *InputInfo,
197   PATH_INFO     *OutputInfo,
198   BOOLEAN       ProcessMbr
199   )
200 {
201   CHAR8 FirstSector[0x200] = {0};
202   CHAR8 FirstSectorBackup[0x200] = {0};
203 
204   FILE *InputFile;
205   FILE *OutputFile;
206 
207 
208   InputFile = fopen (LongFilePath (InputInfo->PhysicalPath), "r");
209   if (InputFile == NULL) {
210     return ErrorFileReadWrite;
211   }
212 
213   if (0x200 != fread(FirstSector, 1, 0x200, InputFile)) {
214     fclose(InputFile);
215     return ErrorFileReadWrite;
216   }
217 
218   fclose(InputFile);
219 
220   //Not support USB and IDE.
221   if (InputInfo->Type == PathUsb) {
222     printf("USB has not been supported yet!");
223     return ErrorSuccess;
224   }
225 
226   if (InputInfo->Type == PathIde) {
227     printf("IDE has not been supported yet!");
228     return ErrorSuccess;
229   }
230 
231   //Process Floppy Disk
232   OutputFile = fopen (LongFilePath (OutputInfo->PhysicalPath), "r+");
233   if (OutputFile == NULL) {
234     OutputFile = fopen (LongFilePath (OutputInfo->PhysicalPath), "w");
235     if (OutputFile == NULL) {
236       return ErrorFileReadWrite;
237     }
238   }
239 
240   if (OutputInfo->Type != PathFile) {
241     if (ProcessMbr) {
242       //
243       // Use original partition table
244       //
245       if (0x200 != fread (FirstSectorBackup, 1, 0x200, OutputFile)) {
246         fclose(OutputFile);
247         return ErrorFileReadWrite;
248         }
249       memcpy (FirstSector + 0x1BE, FirstSectorBackup + 0x1BE, 0x40);
250     }
251   }
252   if(0x200 != fwrite(FirstSector, 1, 0x200, OutputFile)) {
253     fclose(OutputFile);
254     return ErrorFileReadWrite;
255   }
256 
257   fclose(OutputFile);
258   return ErrorSuccess;
259 }
260 
261 
262 /**
263 
264   Displays the standard utility information to SDTOUT
265 
266 **/
267 VOID
Version(VOID)268 Version (
269   VOID
270   )
271 {
272   printf ("%s v%d.%d %s-Utility to retrieve and update the boot sector or MBR.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
273   printf ("Copyright (c) 2007-2014 Intel Corporation. All rights reserved.\n");
274 }
275 
276 
277 VOID
PrintUsage(VOID)278 PrintUsage (
279   VOID
280     )
281 {
282   Version();
283   printf ("\nUsage: \n\
284    GenBootSector\n\
285      [-l, --list list disks]\n\
286      [-i, --input Filename]\n\
287      [-o, --output Filename]\n\
288      [-m, --mbr process the MBR also]\n\
289      [-v, --verbose]\n\
290      [--version]\n\
291      [-q, --quiet disable all messages except fatal errors]\n\
292      [-d, --debug[#]\n\
293      [-h, --help]\n");
294 }
295 
296 int
main(int argc,char * argv[])297 main (
298   int  argc,
299   char *argv[]
300   )
301 {
302   INTN           Index;
303   BOOLEAN        ProcessMbr;
304   ERROR_STATUS   Status;
305   EFI_STATUS     EfiStatus;
306   PATH_INFO      InputPathInfo;
307   PATH_INFO      OutputPathInfo;
308   UINT64         LogLevel;
309 
310   SetUtilityName (UTILITY_NAME);
311 
312   ZeroMem(&InputPathInfo, sizeof(PATH_INFO));
313   ZeroMem(&OutputPathInfo, sizeof(PATH_INFO));
314 
315   argv ++;
316   argc --;
317 
318   ProcessMbr    = FALSE;
319 
320   if (argc == 0) {
321     PrintUsage();
322     return 0;
323   }
324 
325   //
326   // Parse command line
327   //
328   for (Index = 0; Index < argc; Index ++) {
329     if ((stricmp (argv[Index], "-l") == 0) || (stricmp (argv[Index], "--list") == 0)) {
330       ListDrive ();
331       return 0;
332     }
333 
334     if ((stricmp (argv[Index], "-m") == 0) || (stricmp (argv[Index], "--mbr") == 0)) {
335       ProcessMbr = TRUE;
336       continue;
337     }
338 
339     if ((stricmp (argv[Index], "-i") == 0) || (stricmp (argv[Index], "--input") == 0)) {
340       InputPathInfo.Path  = argv[Index + 1];
341       InputPathInfo.Input = TRUE;
342       if (InputPathInfo.Path == NULL) {
343         Error (NULL, 0, 1003, "Invalid option value", "Input file name can't be NULL");
344         return 1;
345       }
346       if (InputPathInfo.Path[0] == '-') {
347         Error (NULL, 0, 1003, "Invalid option value", "Input file is missing");
348         return 1;
349       }
350       ++Index;
351       continue;
352     }
353 
354     if ((stricmp (argv[Index], "-o") == 0) || (stricmp (argv[Index], "--output") == 0)) {
355       OutputPathInfo.Path  = argv[Index + 1];
356       OutputPathInfo.Input = FALSE;
357       if (OutputPathInfo.Path == NULL) {
358         Error (NULL, 0, 1003, "Invalid option value", "Output file name can't be NULL");
359         return 1;
360       }
361       if (OutputPathInfo.Path[0] == '-') {
362         Error (NULL, 0, 1003, "Invalid option value", "Output file is missing");
363         return 1;
364       }
365       ++Index;
366       continue;
367     }
368 
369     if ((stricmp (argv[Index], "-h") == 0) || (stricmp (argv[Index], "--help") == 0)) {
370       PrintUsage ();
371       return 0;
372     }
373 
374     if (stricmp (argv[Index], "--version") == 0) {
375       Version ();
376       return 0;
377     }
378 
379     if ((stricmp (argv[Index], "-v") == 0) || (stricmp (argv[Index], "--verbose") == 0)) {
380       continue;
381     }
382 
383     if ((stricmp (argv[Index], "-q") == 0) || (stricmp (argv[Index], "--quiet") == 0)) {
384       continue;
385     }
386 
387     if ((stricmp (argv[Index], "-d") == 0) || (stricmp (argv[Index], "--debug") == 0)) {
388       EfiStatus = AsciiStringToUint64 (argv[Index + 1], FALSE, &LogLevel);
389       if (EFI_ERROR (EfiStatus)) {
390         Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[Index], argv[Index + 1]);
391         return 1;
392       }
393       if (LogLevel > 9) {
394         Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) LogLevel);
395         return 1;
396       }
397       SetPrintLevel (LogLevel);
398       DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[Index + 1]);
399       ++Index;
400       continue;
401     }
402 
403     //
404     // Don't recognize the parameter.
405     //
406     Error (NULL, 0, 1000, "Unknown option", "%s", argv[Index]);
407     return 1;
408   }
409 
410   if (InputPathInfo.Path == NULL) {
411     Error (NULL, 0, 1001, "Missing options", "Input file is missing");
412     return 1;
413   }
414 
415   if (OutputPathInfo.Path == NULL) {
416     Error (NULL, 0, 1001, "Missing options", "Output file is missing");
417     return 1;
418   }
419 
420   if (GetPathInfo(&InputPathInfo) != ErrorSuccess) {
421     Error (NULL, 0, 1003, "Invalid option value", "Input file can't be found.");
422     return 1;
423   }
424 
425   if (GetPathInfo(&OutputPathInfo) != ErrorSuccess) {
426     Error (NULL, 0, 1003, "Invalid option value", "Output file can't be found.");
427     return 1;
428   }
429 
430   //
431   // Process DBR (Patch or Read)
432   //
433   Status = ProcessBsOrMbr (&InputPathInfo, &OutputPathInfo, ProcessMbr);
434 
435   if (Status == ErrorSuccess) {
436     fprintf (
437       stdout,
438       "%s %s: successful!\n",
439       (OutputPathInfo.Type != PathFile) ? "Write" : "Read",
440       ProcessMbr ? "MBR" : "DBR"
441       );
442     return 0;
443   } else {
444     fprintf (
445       stderr,
446       "%s: %s %s: failed - %s (LastError: 0x%x)!\n",
447       (Status == ErrorNoMbr) ? "WARNING" : "ERROR",
448       (OutputPathInfo.Type != PathFile) ? "Write" : "Read",
449       ProcessMbr ? "MBR" : "DBR",
450       ErrorStatusDesc[Status],
451       errno
452       );
453     return 1;
454   }
455 }
456