From 44bc9120699af80bb18366ca474cb2c618608ca9 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Sat, 10 Jan 2015 21:19:51 +0100 Subject: [PATCH] 5560 grub should support EFI/GPT partitioning Reviewed by: Hans Rosenfeld Reviewed by: Jean McCormack Reviewed by: Josef 'Jeff' Sipek Approved by: Dan McDonald --- exception_lists/copyright | 5 ++ exception_lists/cstyle | 5 ++ exception_lists/hdrchk | 1 + usr/src/grub/grub-0.97/stage2/builtins.c | 20 +++++-- usr/src/grub/grub-0.97/stage2/disk_io.c | 99 ++++++++++++++++++++++++++++++-- usr/src/grub/grub-0.97/stage2/gpt.h | 68 ++++++++++++++++++++++ usr/src/grub/grub-0.97/stage2/pc_slice.h | 1 + usr/src/grub/grub-0.97/stage2/shared.h | 4 +- 8 files changed, 191 insertions(+), 12 deletions(-) create mode 100644 usr/src/grub/grub-0.97/stage2/gpt.h diff --git a/exception_lists/copyright b/exception_lists/copyright index 37c48c548f..4f3c232f39 100644 --- a/exception_lists/copyright +++ b/exception_lists/copyright @@ -68,6 +68,11 @@ usr/src/common/bzip2/huffman.c usr/src/common/openssl/crypto/krb5/krb5_asn.c usr/src/common/openssl/crypto/krb5/krb5_asn.h usr/src/grub/grub-0.97/stage2/Makefile.am +usr/src/grub/grub-0.97/stage2/builtins.c +usr/src/grub/grub-0.97/stage2/disk_io.c +usr/src/grub/grub-0.97/stage2/pc_slice.h +usr/src/grub/grub-0.97/stage2/gpt.h +usr/src/grub/grub-0.97/stage2/shared.h usr/src/lib/gss_mechs/mech_krb5/crypto/cksumtype_to_string.c usr/src/lib/gss_mechs/mech_krb5/crypto/coll_proof_cksum.c usr/src/lib/gss_mechs/mech_krb5/crypto/enctype_compare.c diff --git a/exception_lists/cstyle b/exception_lists/cstyle index cc7c15183c..fc3764db2c 100644 --- a/exception_lists/cstyle +++ b/exception_lists/cstyle @@ -125,6 +125,11 @@ usr/src/common/bzip2/bzlib_private.h usr/src/common/bzip2/huffman.c usr/src/common/openssl/crypto/krb5/krb5_asn.c usr/src/common/openssl/crypto/krb5/krb5_asn.h +usr/src/grub/grub-0.97/stage2/builtins.c +usr/src/grub/grub-0.97/stage2/disk_io.c +usr/src/grub/grub-0.97/stage2/pc_slice.h +usr/src/grub/grub-0.97/stage2/gpt.h +usr/src/grub/grub-0.97/stage2/shared.h usr/src/lib/gss_mechs/mech_krb5/crypto/aes/aes_s2k.c usr/src/lib/gss_mechs/mech_krb5/crypto/cksumtype_to_string.c usr/src/lib/gss_mechs/mech_krb5/crypto/coll_proof_cksum.c diff --git a/exception_lists/hdrchk b/exception_lists/hdrchk index 57805d0dfc..304af86790 100644 --- a/exception_lists/hdrchk +++ b/exception_lists/hdrchk @@ -30,6 +30,7 @@ usr/src/cmd/mandoc/mdoc.h usr/src/cmd/mandoc/out.h usr/src/cmd/mandoc/term.h usr/src/common/openssl/crypto/krb5/krb5_asn.h +usr/src/grub/grub-0.97/stage2/shared.h usr/src/lib/gss_mechs/mech_krb5/et/error_table.h usr/src/lib/gss_mechs/mech_krb5/et/internal.h usr/src/lib/gss_mechs/mech_krb5/et/mit-sipb-copyright.h diff --git a/usr/src/grub/grub-0.97/stage2/builtins.c b/usr/src/grub/grub-0.97/stage2/builtins.c index 17eb542a1e..ecc92bc819 100644 --- a/usr/src/grub/grub-0.97/stage2/builtins.c +++ b/usr/src/grub/grub-0.97/stage2/builtins.c @@ -1654,8 +1654,8 @@ harddisk: for (drive = 0x80; drive < 0x88; drive++) { unsigned long part = 0xFFFFFF; - unsigned long start, len, offset, ext_offset; - int type, entry; + unsigned long start, len, offset, ext_offset, gpt_offset; + int type, entry, gpt_count, gpt_size; char buf[SECTOR_SIZE]; if (for_root && tmp_argpart) { @@ -1685,7 +1685,8 @@ harddisk: current_drive = drive; while (next_partition (drive, 0xFFFFFF, &part, &type, &start, &len, &offset, &entry, - &ext_offset, buf)) + &ext_offset, &gpt_offset, + &gpt_count, &gpt_size, buf)) { if (type != PC_SLICE_TYPE_NONE && ! IS_PC_SLICE_TYPE_BSD (type) @@ -3378,8 +3379,8 @@ parttype_func (char *arg, int flags) { int new_type; unsigned long part = 0xFFFFFF; - unsigned long start, len, offset, ext_offset; - int entry, type; + unsigned long start, len, offset, ext_offset, gpt_offset; + int entry, type, gpt_count, gpt_size; char mbr[512]; /* Get the drive and the partition. */ @@ -3416,8 +3417,15 @@ parttype_func (char *arg, int flags) /* Look for the partition. */ while (next_partition (current_drive, 0xFFFFFF, &part, &type, &start, &len, &offset, &entry, - &ext_offset, mbr)) + &ext_offset, &gpt_offset, &gpt_count, &gpt_size, mbr)) { + /* The partition may not be a GPT partition. */ + if (gpt_offset != 0) + { + errnum = ERR_BAD_ARGUMENT; + return 1; + } + if (part == current_partition) { /* Found. */ diff --git a/usr/src/grub/grub-0.97/stage2/disk_io.c b/usr/src/grub/grub-0.97/stage2/disk_io.c index 5e767dc747..6f21277dae 100644 --- a/usr/src/grub/grub-0.97/stage2/disk_io.c +++ b/usr/src/grub/grub-0.97/stage2/disk_io.c @@ -21,6 +21,7 @@ #include #include +#include #ifdef SUPPORT_NETBOOT # include @@ -514,8 +515,8 @@ int set_partition_hidden_flag (int hidden) { unsigned long part = 0xFFFFFF; - unsigned long start, len, offset, ext_offset; - int entry, type; + unsigned long start, len, offset, ext_offset, gpt_offset; + int entry, type, gpt_count, gpt_size; char mbr[512]; /* The drive must be a hard disk. */ @@ -536,8 +537,15 @@ set_partition_hidden_flag (int hidden) /* Look for the partition. */ while (next_partition (current_drive, 0xFFFFFF, &part, &type, &start, &len, &offset, &entry, - &ext_offset, mbr)) + &ext_offset, &gpt_offset, &gpt_count, &gpt_size, mbr)) { + /* The partition may not be a GPT partition. */ + if (gpt_offset != 0) + { + errnum = ERR_BAD_ARGUMENT; + return 1; + } + if (part == current_partition) { /* Found. */ @@ -589,12 +597,15 @@ next_partition (unsigned long drive, unsigned long dest, unsigned long *partition, int *type, unsigned long *start, unsigned long *len, unsigned long *offset, int *entry, - unsigned long *ext_offset, char *buf) + unsigned long *ext_offset, + unsigned long *gpt_offset, int *gpt_count, + int *gpt_size, char *buf) { /* Forward declarations. */ auto int next_bsd_partition (void); auto int next_solaris_partition(void); auto int next_pc_slice (void); + auto int next_gpt_slice(void); /* Get next BSD partition in current PC slice. */ int next_bsd_partition (void) @@ -729,6 +740,40 @@ next_partition (unsigned long drive, unsigned long dest, return 0; } + /* If this is a GPT partition table, read it as such. */ + if (*entry == -1 && *offset == 0 && PC_SLICE_TYPE (buf, 0) == PC_SLICE_TYPE_GPT) + { + struct grub_gpt_header *hdr = (struct grub_gpt_header *) buf; + + /* Read in the GPT Partition table header. */ + if (! rawread (drive, 1, 0, SECTOR_SIZE, buf)) + return 0; + + if (hdr->magic == GPT_HEADER_MAGIC && hdr->version == 0x10000) + { + /* Let gpt_offset point to the first entry in the GPT + partition table. This can also be used by callers of + next_partition to determine if a entry comes from a + GPT partition table or not. */ + *gpt_offset = hdr->partitions; + *gpt_count = hdr->maxpart; + *gpt_size = hdr->partentry_size; + + return next_gpt_slice(); + } + else + { + /* This is not a valid header for a GPT partition table. + Re-read the MBR or the boot sector of the extended + partition. */ + if (! rawread (drive, *offset, 0, SECTOR_SIZE, buf)) + return 0; + } + } + + /* Not a GPT partition. */ + *gpt_offset = 0; + /* Increase the entry number. */ (*entry)++; @@ -773,6 +818,43 @@ next_partition (unsigned long drive, unsigned long dest, return 1; } + /* Get the next GPT slice. */ + int next_gpt_slice (void) + { + struct grub_gpt_partentry *gptentry = (struct grub_gpt_partentry *) buf; + /* Make GPT partitions show up as PC slices. */ + int pc_slice_no = (*partition & 0xFF0000) >> 16; + + /* If this is the first time... */ + if (pc_slice_no == 0xFF) + { + pc_slice_no = -1; + *entry = -1; + } + + do { + (*entry)++; + + if (*entry >= *gpt_count) + { + errnum = ERR_NO_PART; + return 0; + } + /* Read in the GPT Partition table entry. */ + if (! rawread (drive, (*gpt_offset) + GPT_ENTRY_SECTOR (*gpt_size, *entry), GPT_ENTRY_INDEX (*gpt_size, *entry), *gpt_size, buf)) + return 0; + } while (! (gptentry->type1 && gptentry->type2)); + + pc_slice_no++; + *start = gptentry->start; + *len = gptentry->end - gptentry->start + 1; + *type = PC_SLICE_TYPE_EXT2FS; + *entry = pc_slice_no; + *partition = (*entry << 16) | 0xFFFF; + + return 1; + } + /* Start the body of this function. */ #ifndef STAGE1_5 @@ -788,6 +870,9 @@ next_partition (unsigned long drive, unsigned long dest, errnum = ERR_NONE; } + if (*partition != 0xFFFFFF && *gpt_offset != 0) + return next_gpt_slice (); + /* If previous partition is a BSD partition or a PC slice which contains BSD partitions... */ if ((*partition != 0xFFFFFF && IS_PC_SLICE_TYPE_BSD (*type & 0xff)) @@ -826,6 +911,9 @@ real_open_partition (int flags) unsigned long dest_partition = current_partition; unsigned long part_offset; unsigned long ext_offset; + unsigned long gpt_offset; + int gpt_count; + int gpt_size; int entry; char buf[SECTOR_SIZE]; int unix_part, pc_slice; @@ -837,7 +925,8 @@ real_open_partition (int flags) int ret = next_partition (current_drive, dest_partition, ¤t_partition, ¤t_slice, &part_start, &part_length, - &part_offset, &entry, &ext_offset, buf); + &part_offset, &entry, &ext_offset, + &gpt_offset, &gpt_count, &gpt_size, buf); unix_part = (current_partition >> 8) & 0xFF; pc_slice = current_partition >> 16; return ret; diff --git a/usr/src/grub/grub-0.97/stage2/gpt.h b/usr/src/grub/grub-0.97/stage2/gpt.h new file mode 100644 index 0000000000..71ed0b843b --- /dev/null +++ b/usr/src/grub/grub-0.97/stage2/gpt.h @@ -0,0 +1,68 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2005,2006 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _GPT_H +#define _GPT_H + +typedef signed char grub_int8_t; +typedef signed short grub_int16_t; +typedef signed int grub_int32_t; +typedef signed long long int grub_int64_t; +typedef unsigned char grub_uint8_t; +typedef unsigned short grub_uint16_t; +typedef unsigned int grub_uint32_t; +typedef unsigned long long int grub_uint64_t; + +struct grub_gpt_header +{ + grub_uint64_t magic; + grub_uint32_t version; + grub_uint32_t headersize; + grub_uint32_t crc32; + grub_uint32_t unused1; + grub_uint64_t primary; + grub_uint64_t backup; + grub_uint64_t start; + grub_uint64_t end; + grub_uint8_t guid[16]; + grub_uint64_t partitions; + grub_uint32_t maxpart; + grub_uint32_t partentry_size; + grub_uint32_t partentry_crc32; +} __attribute__ ((packed)); + +struct grub_gpt_partentry +{ + grub_uint64_t type1; + grub_uint64_t type2; + grub_uint8_t guid[16]; + grub_uint64_t start; + grub_uint64_t end; + grub_uint8_t attrib; + char name[72]; +} __attribute__ ((packed)); + +#define GPT_HEADER_MAGIC 0x5452415020494645ULL + +#define GPT_ENTRY_SECTOR(size,entry) \ + ((((entry) * (size) + 1) & ~(SECTOR_SIZE - 1)) >> SECTOR_BITS) +#define GPT_ENTRY_INDEX(size,entry) \ + ((((entry) * (size) + 1) & (SECTOR_SIZE - 1)) - 1) + +#endif /* _GPT_H */ diff --git a/usr/src/grub/grub-0.97/stage2/pc_slice.h b/usr/src/grub/grub-0.97/stage2/pc_slice.h index a237f88a26..7e7171d5c4 100644 --- a/usr/src/grub/grub-0.97/stage2/pc_slice.h +++ b/usr/src/grub/grub-0.97/stage2/pc_slice.h @@ -118,6 +118,7 @@ #define PC_SLICE_TYPE_SOLARIS_BOOT 0xbe /* Solaris boot (fat) */ #define PC_SLICE_TYPE_SOLARIS2 0xbf /* new Solaris type */ #define PC_SLICE_TYPE_DELL_UTIL 0xde +#define PC_SLICE_TYPE_GPT 0xee #define PC_SLICE_TYPE_LINUX_RAID 0xfd diff --git a/usr/src/grub/grub-0.97/stage2/shared.h b/usr/src/grub/grub-0.97/stage2/shared.h index cb41978ce3..9cf436e346 100644 --- a/usr/src/grub/grub-0.97/stage2/shared.h +++ b/usr/src/grub/grub-0.97/stage2/shared.h @@ -1021,7 +1021,9 @@ int next_partition (unsigned long drive, unsigned long dest, unsigned long *partition, int *type, unsigned long *start, unsigned long *len, unsigned long *offset, int *entry, - unsigned long *ext_offset, char *buf); + unsigned long *ext_offset, + unsigned long *gpt_offset, int *gpt_count, + int *gpt_size, char *buf); /* Sets device to the one represented by the SAVED_* parameters. */ int make_saved_active (void); -- 2.11.4.GIT