UbixOS  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];
246  continue;
247  }
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