1 // Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <string.h>
8 #include <unistd.h>
9 
10 #include "cgpt.h"
11 #include "cgpt_params.h"
12 #include "cgptlib_internal.h"
13 #include "vboot_host.h"
14 
CgptGetBootPartitionNumber(CgptBootParams * params)15 int CgptGetBootPartitionNumber(CgptBootParams *params) {
16   struct drive drive;
17   int gpt_retval= 0;
18   int retval;
19 
20   if (params == NULL)
21     return CGPT_FAILED;
22 
23   if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDONLY,
24                            params->drive_size))
25     return CGPT_FAILED;
26 
27   if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
28     Error("GptSanityCheck() returned %d: %s\n",
29           gpt_retval, GptError(gpt_retval));
30     retval = CGPT_FAILED;
31     goto done;
32   }
33 
34   if (CGPT_OK != ReadPMBR(&drive)) {
35     Error("Unable to read PMBR\n");
36     retval = CGPT_FAILED;
37     goto done;
38   }
39 
40   char buf[GUID_STRLEN];
41   GuidToStr(&drive.pmbr.boot_guid, buf, sizeof(buf));
42 
43   int numEntries = GetNumberOfEntries(&drive);
44   int i;
45   for(i = 0; i < numEntries; i++) {
46       GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, i);
47 
48       if (GuidEqual(&entry->unique, &drive.pmbr.boot_guid)) {
49         params->partition = i + 1;
50         retval = CGPT_OK;
51         goto done;
52       }
53   }
54 
55   Error("Didn't find any boot partition\n");
56   params->partition = 0;
57   retval = CGPT_FAILED;
58 
59 done:
60   (void) DriveClose(&drive, 1);
61   return retval;
62 }
63 
64 
CgptBoot(CgptBootParams * params)65 int CgptBoot(CgptBootParams *params) {
66   struct drive drive;
67   int retval = 1;
68   int gpt_retval= 0;
69   int mode = O_RDONLY;
70 
71   if (params == NULL)
72     return CGPT_FAILED;
73 
74   if (params->create_pmbr || params->partition || params->bootfile)
75     mode = O_RDWR;
76 
77   if (CGPT_OK != DriveOpen(params->drive_name, &drive, mode,
78                            params->drive_size)) {
79     return CGPT_FAILED;
80   }
81 
82   if (CGPT_OK != ReadPMBR(&drive)) {
83     Error("Unable to read PMBR\n");
84     goto done;
85   }
86 
87   if (params->create_pmbr) {
88     drive.pmbr.magic[0] = 0x1d;
89     drive.pmbr.magic[1] = 0x9a;
90     drive.pmbr.sig[0] = 0x55;
91     drive.pmbr.sig[1] = 0xaa;
92     memset(&drive.pmbr.part, 0, sizeof(drive.pmbr.part));
93     drive.pmbr.part[0].f_head = 0x00;
94     drive.pmbr.part[0].f_sect = 0x02;
95     drive.pmbr.part[0].f_cyl = 0x00;
96     drive.pmbr.part[0].type = 0xee;
97     drive.pmbr.part[0].l_head = 0xff;
98     drive.pmbr.part[0].l_sect = 0xff;
99     drive.pmbr.part[0].l_cyl = 0xff;
100     drive.pmbr.part[0].f_lba = htole32(1);
101     uint32_t max = 0xffffffff;
102     if (drive.gpt.streaming_drive_sectors < 0xffffffff)
103       max = drive.gpt.streaming_drive_sectors - 1;
104     drive.pmbr.part[0].num_sect = htole32(max);
105   }
106 
107   if (params->partition) {
108     if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
109       Error("GptSanityCheck() returned %d: %s\n",
110             gpt_retval, GptError(gpt_retval));
111       goto done;
112     }
113 
114     if (params->partition > GetNumberOfEntries(&drive)) {
115       Error("invalid partition number: %d\n", params->partition);
116       goto done;
117     }
118 
119     uint32_t index = params->partition - 1;
120     GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, index);
121     memcpy(&drive.pmbr.boot_guid, &entry->unique, sizeof(Guid));
122   }
123 
124   if (params->bootfile) {
125     int fd = open(params->bootfile, O_RDONLY);
126     if (fd < 0) {
127       Error("Can't read %s: %s\n", params->bootfile, strerror(errno));
128       goto done;
129     }
130 
131     int n = read(fd, drive.pmbr.bootcode, sizeof(drive.pmbr.bootcode));
132     if (n < 1) {
133       Error("problem reading %s: %s\n", params->bootfile, strerror(errno));
134       close(fd);
135       goto done;
136     }
137 
138     close(fd);
139   }
140 
141   char buf[GUID_STRLEN];
142   GuidToStr(&drive.pmbr.boot_guid, buf, sizeof(buf));
143   printf("%s\n", buf);
144 
145   // Write it all out, if needed.
146   if (mode == O_RDONLY || CGPT_OK == WritePMBR(&drive))
147     retval = 0;
148 
149 done:
150   (void) DriveClose(&drive, 1);
151   return retval;
152 }
153