UbixOS V2 2.0

gpt.c
Go to the documentation of this file.
1 /*-
2 * Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 //#include <sys/cdefs.h>
28 //#include <sys/param.h>
29 #include <fs/common/gpt.h>
30 #include <fs/common/crc32.h>
31 #include <sys/device.h>
32 #include <lib/kprintf.h>
33 #include <pci/hd.h>
34
35
36 /*
37 #ifndef LITTLE_ENDIAN
38 #error gpt.c works only for little endian architectures
39 #endif
40 */
41
42 /*
43 #include "crc32.h"
44 #include "drv.h"
45 #include "util.h"
46 #include "gpt.h"
47 */
48
49 #define MAXTBLENTS 128
50
51 #ifndef BOOTPROG
52 #define BOOTPROG "Unknown"
53 #endif
54
55 static struct gpt_hdr hdr_primary, hdr_backup, *gpthdr;
56 static u_int64_t hdr_primary_lba, hdr_backup_lba;
57 static struct gpt_ent table_primary[MAXTBLENTS], table_backup[MAXTBLENTS];
58 static struct gpt_ent *gpttable;
59 static int curent, bootonce;
60
61 /*
62 * Buffer below 64kB passed on gptread(), which can hold at least
63 * one sector of data (512 bytes).
64 */
65 static char *secbuf;
66
67 static void gptupdate( const char *which, struct device_interface *devInfo, struct gpt_hdr *hdr, struct gpt_ent *table ) {
68 int entries_per_sec, firstent;
69 daddr_t slba;
70
71 /*
72 * We need to update the following for both primary and backup GPT:
73 * 1. Sector on disk that contains current partition.
74 * 2. Partition table checksum.
75 * 3. Header checksum.
76 * 4. Header on disk.
77 */
78
79 entries_per_sec = DEV_BSIZE / hdr->hdr_entsz;
80 slba = curent / entries_per_sec;
81 firstent = slba * entries_per_sec;
82 bcopy( &table[firstent], secbuf, DEV_BSIZE );
83 slba += hdr->hdr_lba_table;
84 if ( devInfo->write( devInfo->info, secbuf, slba, 1 ) ) {
85 kprintf( "%s: unable to update %s GPT partition table\n", BOOTPROG, which );
86 return;
87 }
88 hdr->hdr_crc_table = crc32( table, hdr->hdr_entries * hdr->hdr_entsz );
89 hdr->hdr_crc_self = 0;
90 hdr->hdr_crc_self = crc32( hdr, hdr->hdr_size );
91 bzero( secbuf, DEV_BSIZE );
92 bcopy( hdr, secbuf, hdr->hdr_size );
93 if ( devInfo->write( devInfo->info, secbuf, hdr->hdr_lba_self, 1 ) ) {
94 kprintf( "%s: unable to update %s GPT header\n", BOOTPROG, which );
95 return;
96 }
97 }
98
99 int gptfind( const uuid_t *uuid, struct device_interface *devInfo, int part ) {
100 struct gpt_ent *ent;
101 struct driveInfo *drvInfo = devInfo->info;
102 int firsttry;
103
104 if ( part >= 0 ) {
105 if ( part == 0 || part > gpthdr->hdr_entries ) {
106 kprintf( "%s: invalid partition index\n", BOOTPROG );
107 return (-1);
108 }
109 ent = &gpttable[part - 1];
110 if ( bcmp( &ent->ent_type, uuid, sizeof(uuid_t) ) != 0 ) {
111 kprintf( "%s: specified partition is not UFS\n", BOOTPROG );
112 return (-1);
113 }
114 curent = part - 1;
115 goto found;
116 }
117
118 firsttry = (curent == -1);
119 curent++;
120 if ( curent >= gpthdr->hdr_entries ) {
121 curent = gpthdr->hdr_entries;
122 return (-1);
123 }
124 if ( bootonce ) {
125 /*
126 * First look for partition with both GPT_ENT_ATTR_BOOTME and
127 * GPT_ENT_ATTR_BOOTONCE flags.
128 */
129 for (; curent < gpthdr->hdr_entries; curent++ ) {
130 ent = &gpttable[curent];
131 if ( bcmp( &ent->ent_type, uuid, sizeof(uuid_t) ) != 0 )
132 continue;
133 if ( !(ent->ent_attr & GPT_ENT_ATTR_BOOTME) )
134 continue;
135 if ( !(ent->ent_attr & GPT_ENT_ATTR_BOOTONCE) )
136 continue;
137 /* Ok, found one. */
138 goto found;
139 }
140 bootonce = 0;
141 curent = 0;
142 }
143 for (; curent < gpthdr->hdr_entries; curent++ ) {
144 ent = &gpttable[curent];
145 if ( bcmp( &ent->ent_type, uuid, sizeof(uuid_t) ) != 0 )
146 continue;
147 if ( !(ent->ent_attr & GPT_ENT_ATTR_BOOTME) )
148 continue;
149 if ( ent->ent_attr & GPT_ENT_ATTR_BOOTONCE )
150 continue;
151 /* Ok, found one. */
152 goto found;
153 }
154 if ( firsttry ) {
155 /*
156 * No partition with BOOTME flag was found, try to boot from
157 * first UFS partition.
158 */
159 for ( curent = 0; curent < gpthdr->hdr_entries; curent++ ) {
160 ent = &gpttable[curent];
161 if ( bcmp( &ent->ent_type, uuid, sizeof(uuid_t) ) != 0 )
162 continue;
163 /* Ok, found one. */
164 goto found;
165 }
166 }
167 return (-1);
168 found: drvInfo->part = curent + 1;
169 ent = &gpttable[curent];
170 drvInfo->parOffset = ent->ent_lba_start * drvInfo->sector_size;
171 drvInfo->lba_start = ent->ent_lba_start;
172 drvInfo->lba_end = ent->ent_lba_end;
173 if ( ent->ent_attr & GPT_ENT_ATTR_BOOTONCE ) {
174 /*
175 * Clear BOOTME, but leave BOOTONCE set before trying to
176 * boot from this partition.
177 */
178 if ( hdr_primary_lba > 0 ) {
179 table_primary[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTME;
180 gptupdate( "primary", devInfo, &hdr_primary, table_primary );
181 }
182 if ( hdr_backup_lba > 0 ) {
183 table_backup[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTME;
184 gptupdate( "backup", devInfo, &hdr_backup, table_backup );
185 }
186 }
187 return (0);
188 }
189
190 static int gptread_hdr( const char *which, struct device_interface *devInfo, struct gpt_hdr *hdr, u_int64_t hdrlba ) {
191 uint32_t crc;
192
193 if ( devInfo->read( devInfo->info, secbuf, hdrlba, 1 ) ) {
194 kprintf( "%s: unable to read %s GPT header\n", BOOTPROG, which );
195 return (-1);
196 }
197
198 bcopy( secbuf, hdr, sizeof(*hdr) );
199
200 if ( bcmp( hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig) ) != 0 || hdr->hdr_lba_self != hdrlba || hdr->hdr_revision < 0x00010000 || hdr->hdr_entsz < sizeof(struct gpt_ent) || hdr->hdr_entries > MAXTBLENTS || DEV_BSIZE % hdr->hdr_entsz != 0 ) {
201 kprintf( "%s: invalid %s GPT header\n", BOOTPROG, which );
202 return (-1);
203 }
204
205 crc = hdr->hdr_crc_self;
206 hdr->hdr_crc_self = 0;
207
208 if ( crc32( hdr, hdr->hdr_size ) != crc ) {
209 kprintf( "%s: %s GPT header checksum mismatch\n", BOOTPROG, which );
210 return (-1);
211 }
212 hdr->hdr_crc_self = crc;
213 return (0);
214 }
215
216 void gptbootfailed( struct device_interface *devInfo ) {
217
218 if ( !(gpttable[curent].ent_attr & GPT_ENT_ATTR_BOOTONCE) )
219 return;
220
221 if ( hdr_primary_lba > 0 ) {
222 table_primary[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTONCE;
223 table_primary[curent].ent_attr |= GPT_ENT_ATTR_BOOTFAILED;
224 gptupdate( "primary", devInfo, &hdr_primary, table_primary );
225 }
226 if ( hdr_backup_lba > 0 ) {
227 table_backup[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTONCE;
228 table_backup[curent].ent_attr |= GPT_ENT_ATTR_BOOTFAILED;
229 gptupdate( "backup", devInfo, &hdr_backup, table_backup );
230 }
231 }
232
233 static void gptbootconv( const char *which, struct device_interface *devInfo, struct gpt_hdr *hdr, struct gpt_ent *table ) {
234 struct gpt_ent *ent;
235 daddr_t slba;
236 int table_updated, sector_updated;
237 int entries_per_sec, nent, part;
238
239 table_updated = 0;
240 entries_per_sec = DEV_BSIZE / hdr->hdr_entsz;
241 for ( nent = 0, slba = hdr->hdr_lba_table; slba < hdr->hdr_lba_table + hdr->hdr_entries / entries_per_sec; slba++, nent += entries_per_sec ) {
242 sector_updated = 0;
243 for ( part = 0; part < entries_per_sec; part++ ) {
244 ent = &table[nent + part];
245 if ( (ent->ent_attr & (GPT_ENT_ATTR_BOOTME | GPT_ENT_ATTR_BOOTONCE | GPT_ENT_ATTR_BOOTFAILED)) != GPT_ENT_ATTR_BOOTONCE ) {
246 continue;
247 }
248 ent->ent_attr &= ~GPT_ENT_ATTR_BOOTONCE;
249 ent->ent_attr |= GPT_ENT_ATTR_BOOTFAILED;
250 table_updated = 1;
251 sector_updated = 1;
252 }
253 if ( !sector_updated )
254 continue;
255 bcopy( &table[nent], secbuf, DEV_BSIZE );
256 if ( devInfo->write( devInfo->info, secbuf, slba, 1 ) ) {
257 kprintf( "%s: unable to update %s GPT partition table\n", BOOTPROG, which );
258 }
259 }
260 if ( !table_updated )
261 return;
262 hdr->hdr_crc_table = crc32( table, hdr->hdr_entries * hdr->hdr_entsz );
263 hdr->hdr_crc_self = 0;
264 hdr->hdr_crc_self = crc32( hdr, hdr->hdr_size );
265 bzero( secbuf, DEV_BSIZE );
266 bcopy( hdr, secbuf, hdr->hdr_size );
267 if ( devInfo->write( devInfo->info, secbuf, hdr->hdr_lba_self, 1 ) )
268 kprintf( "%s: unable to update %s GPT header\n", BOOTPROG, which );
269 }
270
271 static int gptread_table( const char *which, const uuid_t *uuid, struct device_interface *devInfo, struct gpt_hdr *hdr, struct gpt_ent *table ) {
272 struct gpt_ent *ent;
273 int entries_per_sec;
274 int part, nent;
275 daddr_t slba;
276
277 if ( hdr->hdr_entries == 0 )
278 return (0);
279
280 entries_per_sec = DEV_BSIZE / hdr->hdr_entsz;
281 slba = hdr->hdr_lba_table;
282 nent = 0;
283 for (;; ) {
284 if ( devInfo->read(devInfo->info, secbuf, slba, 1 ) ) {
285 kprintf( "%s: unable to read %s GPT partition table\n", BOOTPROG, which );
286 return (-1);
287 }
288 ent = (struct gpt_ent *) secbuf;
289 for ( part = 0; part < entries_per_sec; part++, ent++ ) {
290 bcopy( ent, &table[nent], sizeof(table[nent]) );
291 if ( ++nent >= hdr->hdr_entries )
292 break;
293 }
294 if ( nent >= hdr->hdr_entries )
295 break;
296 slba++;
297 }
298 if ( crc32( table, nent * hdr->hdr_entsz ) != hdr->hdr_crc_table ) {
299 kprintf( "%s: %s GPT table checksum mismatch\n", BOOTPROG, which );
300 return (-1);
301 }
302 return (0);
303 }
304
305 int gptread( const uuid_t *uuid, struct device_interface *devInfo, char *buf ) {
306 u_int64_t altlba;
307
308 /*
309 * Read and verify both GPT headers: primary and backup.
310 */
311
312 secbuf = buf;
313 hdr_primary_lba = hdr_backup_lba = 0;
314 curent = -1;
315 bootonce = 1;
316
317 /* MrOlsen (2016-01-11) NOTE: What Was This For?
318 dskp->start = 0;
319 */
320
321 if ( gptread_hdr( "primary", devInfo, &hdr_primary, 1 ) == 0 && gptread_table( "primary", uuid, devInfo, &hdr_primary, table_primary ) == 0 ) {
322 hdr_primary_lba = hdr_primary.hdr_lba_self;
323 gpthdr = &hdr_primary;
324 gpttable = table_primary;
325 }
326
327 if ( hdr_primary_lba > 0 ) {
328 /*
329 * If primary header is valid, we can get backup
330 * header location from there.
331 */
332 altlba = hdr_primary.hdr_lba_alt;
333 }
334 else {
335 //MrOlsen (2016-01-11) FIX: What Is This???
336 kprintf("FIX!\n");
337 //altlba = drvsize( dskp );
338 if ( altlba > 0 )
339 altlba--;
340 }
341 if ( altlba == 0 )
342 kprintf( "%s: unable to locate backup GPT header\n", BOOTPROG );
343 else if ( gptread_hdr( "backup", devInfo, &hdr_backup, altlba ) == 0 && gptread_table( "backup", uuid, devInfo, &hdr_backup, table_backup ) == 0 ) {
344 hdr_backup_lba = hdr_backup.hdr_lba_self;
345 if ( hdr_primary_lba == 0 ) {
346 gpthdr = &hdr_backup;
347 gpttable = table_backup;
348 kprintf( "%s: using backup GPT\n", BOOTPROG );
349 }
350 }
351
352 /*
353 * Convert all BOOTONCE without BOOTME flags into BOOTFAILED.
354 * BOOTONCE without BOOTME means that we tried to boot from it,
355 * but failed after leaving gptboot and machine was rebooted.
356 * We don't want to leave partitions marked as BOOTONCE only,
357 * because when we boot successfully start-up scripts should
358 * find at most one partition with only BOOTONCE flag and this
359 * will mean that we booted from that partition.
360 */
361 if ( hdr_primary_lba != 0 )
362 gptbootconv( "primary", devInfo, &hdr_primary, table_primary );
363 if ( hdr_backup_lba != 0 )
364 gptbootconv( "backup", devInfo, &hdr_backup, table_backup );
365
366 if ( hdr_primary_lba == 0 && hdr_backup_lba == 0 )
367 return (-1);
368 return (0);
369 }
GPT_ENT_ATTR_BOOTFAILED
#define GPT_ENT_ATTR_BOOTFAILED
Definition: gpt.h:80
device_interface
Definition: device.h:47
gptfind
int gptfind(const uuid_t *uuid, struct device_interface *devInfo, int part)
Definition: gpt.c:99
gpt_hdr::hdr_entsz
uint32_t hdr_entsz
Definition: gpt.h:59
bcmp
#define bcmp(b1, b2, len)
Definition: gpt.h:38
gpt_hdr::hdr_crc_table
uint32_t hdr_crc_table
Definition: gpt.h:60
driveInfo
Definition: hd.h:164
u_int64_t
__uint64_t u_int64_t
Definition: types.h:54
bcopy
#define bcopy(src, dst, len)
Definition: gpt.h:36
gpt_hdr::hdr_size
uint32_t hdr_size
Definition: gpt.h:49
bzero
#define bzero(buf, size)
Definition: gpt.h:37
gpt.h
gpt_ent
Definition: gpt.h:71
BOOTPROG
#define BOOTPROG
Definition: gpt.c:52
gpt_ent::ent_lba_start
u_int64_t ent_lba_start
Definition: gpt.h:74
MAXTBLENTS
#define MAXTBLENTS
Definition: gpt.c:49
gptread
int gptread(const uuid_t *uuid, struct device_interface *devInfo, char *buf)
Definition: gpt.c:305
driveInfo::part
int part
Definition: hd.h:180
kprintf.h
crc32.h
buf
Definition: buf.h:35
gpt_hdr::hdr_entries
uint32_t hdr_entries
Definition: gpt.h:58
uint32_t
__uint32_t uint32_t
Definition: types.h:46
gpt_hdr::hdr_crc_self
uint32_t hdr_crc_self
Definition: gpt.h:50
gpt_hdr::hdr_lba_table
u_int64_t hdr_lba_table
Definition: gpt.h:57
device_interface::write
int(* write)(void *, void *, uInt32, uInt32)
Definition: device.h:53
driveInfo::lba_start
long lba_start
Definition: hd.h:181
gpt_hdr::hdr_revision
uint32_t hdr_revision
Definition: gpt.h:47
hd.h
gptbootfailed
void gptbootfailed(struct device_interface *devInfo)
Definition: gpt.c:216
crc32
uint32_t crc32(const void *buf, size_t size)
Definition: crc32.c:97
driveInfo::sector_size
uint32_t sector_size
Definition: hd.h:169
device_interface::read
int(* read)(void *, void *, uInt32, uInt32)
Definition: device.h:52
GPT_HDR_SIG
#define GPT_HDR_SIG
Definition: gpt.h:46
driveInfo::parOffset
long parOffset
Definition: hd.h:179
device.h
driveInfo::lba_end
long lba_end
Definition: hd.h:182
gpt_hdr
Definition: gpt.h:44
device_interface::info
void * info
Definition: device.h:51
gpt_ent::ent_lba_end
u_int64_t ent_lba_end
Definition: gpt.h:75
GPT_ENT_ATTR_BOOTONCE
#define GPT_ENT_ATTR_BOOTONCE
Definition: gpt.h:79
uuid
Definition: uuid.h:45
GPT_ENT_ATTR_BOOTME
#define GPT_ENT_ATTR_BOOTME
Definition: gpt.h:78
kprintf
int kprintf(const char *,...)
Definition: kprintf.c:259
gpt_ent::ent_type
struct uuid ent_type
Definition: gpt.h:72
gpt_hdr::hdr_lba_self
u_int64_t hdr_lba_self
Definition: gpt.h:52
gpt_ent::ent_attr
u_int64_t ent_attr
Definition: gpt.h:76
DEV_BSIZE
#define DEV_BSIZE
Definition: gpt.h:42
daddr_t
__int64_t daddr_t
Definition: types.h:59
gpt_hdr::hdr_sig
char hdr_sig[8]
Definition: gpt.h:45