Home | History | Annotate | Download | only in GnuGenBootSector
      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.
    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
    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
    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
    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
    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
    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
    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