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