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