Add Linux version of GenBootSector for DuetPkg to generate Boot image.Now only floppy...
[efi/basetools/.git] / Source / C / GnuGenBootSector / GnuGenBootSector.c
1 /** @file\r
2 \r
3 Copyright 2006 - 2009, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14   GnuGenBootSector.c\r
15   \r
16 Abstract:\r
17   Reading/writing MBR/DBR.\r
18   NOTE:\r
19     If we write MBR to disk, we just update the MBR code and the partition table wouldn't be over written.\r
20     If we process DBR, we will patch MBR to set first partition active if no active partition exists.\r
21 \r
22 **/\r
23 \r
24 #include "CommonLib.h"\r
25 #include <errno.h>\r
26 #include <stdlib.h>\r
27 #include <string.h>\r
28 \r
29 //\r
30 // Utility Name\r
31 //\r
32 #define UTILITY_NAME  "GnuGenBootSector"\r
33 \r
34 //\r
35 // Utility version information\r
36 //\r
37 #define UTILITY_MAJOR_VERSION 0\r
38 #define UTILITY_MINOR_VERSION 1\r
39 \r
40 #define MAX_DRIVE                             26\r
41 #define PARTITION_TABLE_OFFSET                0x1BE\r
42 \r
43 #define SIZE_OF_PARTITION_ENTRY               0x10\r
44 \r
45 #define PARTITION_ENTRY_STARTLBA_OFFSET       8\r
46 \r
47 #define PARTITION_ENTRY_NUM                   4\r
48 \r
49 #define DRIVE_UNKNOWN     0\r
50 #define DRIVE_NO_ROOT_DIR 1\r
51 #define DRIVE_REMOVABLE   2\r
52 #define DRIVE_FIXED       3\r
53 #define DRIVE_REMOTE      4\r
54 #define DRIVE_CDROM       5\r
55 #define DRIVE_RAMDISK     6\r
56 \r
57 typedef struct _DRIVE_TYPE_DESC {\r
58   UINTN  Type;\r
59   CHAR8  *Description;\r
60 } DRIVE_TYPE_DESC;\r
61 \r
62 #define DRIVE_TYPE_ITEM(x) {x, #x}\r
63 \r
64 DRIVE_TYPE_DESC DriveTypeDesc[] = {\r
65   DRIVE_TYPE_ITEM (DRIVE_UNKNOWN),\r
66   DRIVE_TYPE_ITEM (DRIVE_NO_ROOT_DIR),\r
67   DRIVE_TYPE_ITEM (DRIVE_REMOVABLE),\r
68   DRIVE_TYPE_ITEM (DRIVE_FIXED),\r
69   DRIVE_TYPE_ITEM (DRIVE_REMOTE),\r
70   DRIVE_TYPE_ITEM (DRIVE_CDROM),\r
71   DRIVE_TYPE_ITEM (DRIVE_RAMDISK),\r
72   {(UINTN) -1, NULL}\r
73 };\r
74 \r
75 typedef struct _DRIVE_INFO {\r
76   CHAR8             VolumeLetter;\r
77   DRIVE_TYPE_DESC   *DriveType;\r
78   UINTN             DiskNumber;\r
79 } DRIVE_INFO;\r
80 \r
81 typedef enum {\r
82   PathUnknown,\r
83   PathFile,\r
84   PathFloppy,\r
85   PathUsb,\r
86   PathIde\r
87 } PATH_TYPE;\r
88 \r
89 typedef struct _PATH_INFO {\r
90   CHAR8            *Path;\r
91   CHAR8            PhysicalPath[260];\r
92   PATH_TYPE        Type;\r
93   BOOLEAN          Input;\r
94 } PATH_INFO;\r
95 \r
96 typedef enum {\r
97   ErrorSuccess,\r
98   ErrorFileCreate,\r
99   ErrorFileReadWrite,\r
100   ErrorNoMbr,\r
101   ErrorFatType,\r
102   ErrorPath,\r
103 } ERROR_STATUS;\r
104 \r
105 CHAR8 *ErrorStatusDesc[] = {\r
106   "Success",\r
107   "Failed to create files",\r
108   "Failed to read/write files",\r
109   "No MBR exists",\r
110   "Failed to detect Fat type",\r
111   "Inavlid path"\r
112 };\r
113 \r
114 \r
115 //UnSupported Windows API functions.\r
116 UINTN GetLogicalDrives(void) { return 1; }\r
117 \r
118 \r
119 \r
120 /**\r
121   Get path information, including physical path for Linux platform.\r
122 \r
123   @param PathInfo   Point to PATH_INFO structure.\r
124 \r
125   @return whether path is valid.\r
126 **/\r
127 ERROR_STATUS\r
128 GetPathInfo (\r
129   PATH_INFO   *PathInfo\r
130   )\r
131 {\r
132   FILE        *f;\r
133 \r
134   if (strncmp(PathInfo->Path, "/dev/", 5) == 0) {\r
135     //\r
136     // Process disk path here.\r
137     // \r
138     \r
139     // Process floppy disk\r
140     if (PathInfo->Path[5] == 'f' && PathInfo->Path[6] == 'd' && PathInfo->Path[8] == '\0') {\r
141       PathInfo->Type = PathFloppy;\r
142       strcpy (PathInfo->PhysicalPath, PathInfo->Path);\r
143       \r
144       return ErrorSuccess;\r
145     } else {\r
146     // Other disk types is not supported yet.\r
147     fprintf (stderr, "ERROR: It's not a floppy disk!\n");\r
148     return ErrorPath;\r
149     }  \r
150      \r
151     // Try to open the device.   \r
152     f = fopen(PathInfo->Path,"r");\r
153     if (f == NULL) {\r
154       printf ("error :open device failed!\n");\r
155       return ErrorPath;\r
156     }\r
157     fclose (f);\r
158     return ErrorSuccess;\r
159   }\r
160  \r
161   // Process file path here.\r
162   PathInfo->Type = PathFile;\r
163   if (PathInfo->Input) {\r
164     // If path is file path, check whether file is valid.\r
165     printf("Path = %s\n",PathInfo->Path);\r
166     f = fopen (PathInfo->Path, "r");\r
167     if (f == NULL) {\r
168       fprintf (stderr, "Test error E2003: File was not provided!\n");\r
169       return ErrorPath;\r
170     }\r
171     fclose (f);\r
172   }\r
173 \r
174   strcpy(PathInfo->PhysicalPath, PathInfo->Path);\r
175   return ErrorSuccess;\r
176 \r
177 }\r
178 \r
179 VOID\r
180 ListDrive (\r
181   VOID\r
182   )\r
183 {\r
184   printf("-l or -list not supported!\n");\r
185 }\r
186 \r
187 /**\r
188   Writing or reading boot sector or MBR according to the argument. \r
189    \r
190   @param InputInfo PATH_INFO instance for input path\r
191   @param OutputInfo PATH_INFO instance for output path\r
192   @param ProcessMbr TRUE is to process MBR, otherwise, processing boot sector\r
193   \r
194   @return ERROR_STATUS\r
195  **/\r
196 ERROR_STATUS\r
197 ProcessBsOrMbr (\r
198   PATH_INFO     *InputInfo,\r
199   PATH_INFO     *OutputInfo,\r
200   BOOLEAN       ProcessMbr\r
201   )\r
202 {\r
203   CHAR8 FirstSector[0x200] = {0};\r
204   CHAR8 FirstSectorBackup[0x200] = {0};\r
205   \r
206   FILE *InputFile;\r
207   FILE *OutputFile;\r
208   \r
209   \r
210   InputFile = fopen(InputInfo->PhysicalPath, "r");\r
211   if (InputFile == NULL) {\r
212     return ErrorFileReadWrite;\r
213   }\r
214    \r
215   if (0x200 != fread(FirstSector, 1, 0x200, InputFile)) {\r
216     fclose(InputFile);\r
217     return ErrorFileReadWrite;\r
218   }\r
219   \r
220   fclose(InputFile);\r
221   \r
222   //Not support USB and IDE.\r
223   if (InputInfo->Type == PathUsb) {\r
224     printf("USB has not been supported yet!");\r
225     return ErrorSuccess;\r
226   }\r
227   \r
228   if (InputInfo->Type == PathIde) {\r
229     printf("IDE has not been supported yet!");\r
230     return ErrorSuccess;\r
231   } \r
232   \r
233   //Process Floppy Disk\r
234   OutputFile = fopen(OutputInfo->PhysicalPath, "w");\r
235   if (OutputFile == NULL) {\r
236     return ErrorFileReadWrite;\r
237   }  \r
238   \r
239   if (OutputInfo->Type != PathFile) {\r
240     if (ProcessMbr) {\r
241       //\r
242       // Use original partition table\r
243       //\r
244       if (0x200 != fread (FirstSectorBackup, 1, 0x200, OutputFile)) {\r
245         fclose(OutputFile);\r
246         return ErrorFileReadWrite; \r
247         }\r
248       memcpy (FirstSector + 0x1BE, FirstSectorBackup + 0x1BE, 0x40);  \r
249     }\r
250   }\r
251   if(0x200 != fwrite(FirstSector, 1, 0x200, OutputFile)) {\r
252     fclose(OutputFile);\r
253     return ErrorFileReadWrite;\r
254   }\r
255   \r
256   fclose(OutputFile);\r
257   return ErrorSuccess;\r
258 }\r
259 \r
260 \r
261 /**\r
262 \r
263   Displays the standard utility information to SDTOUT\r
264 \r
265 **/\r
266 VOID\r
267 Version (\r
268   VOID\r
269   )\r
270 {\r
271   printf ("%s v%d.%d -Utility to retrieve and update the boot sector or MBR.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
272   printf ("Copyright (c) 1999-2007 Intel Corporation. All rights reserved.\n");\r
273 }\r
274 \r
275 \r
276 VOID\r
277 PrintUsage (\r
278   VOID\r
279     )\r
280 {\r
281   Version();\r
282   printf ("\nUsage: \n\\r
283    GenBootSector\n\\r
284      [-l, --list list disks]\n\\r
285      [-i, --input Filename]\n\\r
286      [-o, --output Filename]\n\\r
287      [-m, --mbr process the MBR also]\n\\r
288      [-v, --verbose]\n\\r
289      [--version]\n\\r
290      [-q, --quiet disable all messages except fatal errors]\n\\r
291      [-d, --debug[#]\n\\r
292      [-h, --help]\n");\r
293 }\r
294 \r
295 INTN\r
296 main (\r
297   INTN  argc,\r
298   CHAR8 *argv[]\r
299   )\r
300 {\r
301   CHAR8          *AppName;\r
302   INTN           Index;\r
303   BOOLEAN        ProcessMbr;\r
304   ERROR_STATUS   Status;\r
305   PATH_INFO      InputPathInfo;\r
306   PATH_INFO      OutputPathInfo;\r
307   \r
308   ZeroMem(&InputPathInfo, sizeof(PATH_INFO));\r
309   ZeroMem(&OutputPathInfo, sizeof(PATH_INFO));\r
310   \r
311   AppName = *argv;\r
312   argv ++;\r
313   argc --;\r
314   \r
315   ProcessMbr    = FALSE;\r
316 \r
317   if (argc == 0) {\r
318     PrintUsage();\r
319     return 0;\r
320   }\r
321    \r
322   //\r
323   // Parse command line\r
324   //\r
325   for (Index = 0; Index < argc; Index ++) {\r
326     if ((stricmp (argv[Index], "-l") == 0) || (stricmp (argv[0], "--list") == 0)) {\r
327       ListDrive ();\r
328       return 0;\r
329     }\r
330     else if ((stricmp (argv[Index], "-m") == 0) || (stricmp (argv[Index], "--mbr") == 0)) {\r
331       ProcessMbr = TRUE;\r
332     }\r
333     else if ((stricmp (argv[Index], "-i") == 0) || (stricmp (argv[Index], "--input") == 0)) {\r
334       InputPathInfo.Path  = argv[Index + 1];\r
335       InputPathInfo.Input = TRUE;\r
336       ++Index;\r
337     }\r
338     else if ((stricmp (argv[Index], "-o") == 0) || (stricmp (argv[Index], "--output") == 0)) {\r
339       OutputPathInfo.Path  = argv[Index + 1];\r
340       OutputPathInfo.Input = FALSE;\r
341       ++Index;\r
342     }\r
343     else {\r
344       PrintUsage ();\r
345       return 1;\r
346     }\r
347   }\r
348 \r
349 \r
350   if ((GetPathInfo(&InputPathInfo)  != ErrorSuccess) ||\r
351       (GetPathInfo(&OutputPathInfo) != ErrorSuccess)) {\r
352     return 1;\r
353   }\r
354   \r
355   //\r
356   // Process DBR (Patch or Read)\r
357   //\r
358   Status = ProcessBsOrMbr (&InputPathInfo, &OutputPathInfo, ProcessMbr);\r
359 \r
360   if (Status == ErrorSuccess) {\r
361     fprintf (\r
362       stdout, \r
363       "%s %s: successful!\n", \r
364       (OutputPathInfo.Type != PathFile) ? "Write" : "Read", \r
365       ProcessMbr ? "MBR" : "DBR"\r
366       );\r
367     return 0;\r
368   } else {\r
369     fprintf (\r
370       stderr, \r
371       "%s: %s %s: failed - %s (LastError: 0x%x)!\n",\r
372       (Status == ErrorNoMbr) ? "WARNING" : "ERROR",\r
373       (OutputPathInfo.Type != PathFile) ? "Write" : "Read", \r
374       ProcessMbr ? "MBR" : "DBR", \r
375       ErrorStatusDesc[Status],\r
376       errno \r
377       );\r
378     return 1;\r
379   }\r
380 }\r