From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.71) id 1Z1Xle-0001xU-97 for mharc-grub-devel@gnu.org; Sun, 07 Jun 2015 06:25:26 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34653) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z1Xla-0001xM-VU for grub-devel@gnu.org; Sun, 07 Jun 2015 06:25:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Z1XlX-0000DE-NU for grub-devel@gnu.org; Sun, 07 Jun 2015 06:25:22 -0400 Received: from mail-wi0-x22a.google.com ([2a00:1450:400c:c05::22a]:35041) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z1XlX-0000Aa-E5 for grub-devel@gnu.org; Sun, 07 Jun 2015 06:25:19 -0400 Received: by wiga1 with SMTP id a1so58144491wig.0 for ; Sun, 07 Jun 2015 03:25:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=JH0jTx4Af1/9Xry0UN7k1MoFSNyn6ZPuBahVHTvpNs8=; b=XAed8zHR/K+S4UE7YqxR9YLMHEt5Y7Ll8PWs/sBuCYL/vULMmX9FnSzJPaf77ctTis 17ARA4nI2GD25yb1I4upcw1siSQjn+SwuDZQQPYLtgfQlOk1jHe5VYwKT8Vz4Gt2mZEY +3H9vBl5gX+G2XJpxFRvo4o+09CZhC5R+oMwU9xQLpwaFQs40vc5SX9Ymg8Eby7n3aR6 0wMj307CFTRFpA+B+vJBE+BzJLKeyWxF+JLkpIqke1t94hIBtSOnsGQ6H2x9sVmDUvh/ qH7LiCibV64H+LudFvZwel0cV8s/hM5BUnApexk2AOXkYAtQgXHNJSMke03pBsqrEu4v xJ0Q== X-Received: by 10.194.61.129 with SMTP id p1mr22516826wjr.92.1433672718494; Sun, 07 Jun 2015 03:25:18 -0700 (PDT) Received: from hobo (208.24.189.80.dyn.plus.net. [80.189.24.208]) by mx.google.com with ESMTPSA id q4sm18878499wju.14.2015.06.07.03.25.16 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 07 Jun 2015 03:25:17 -0700 (PDT) From: Ross Lagerwall To: grub-devel@gnu.org Subject: [PATCH] core/partmap: Add El Torito boot catalog parsing Date: Sun, 7 Jun 2015 11:24:46 +0100 Message-Id: <1433672686-774-1-git-send-email-rosslagerwall@gmail.com> X-Mailer: git-send-email 2.4.2 X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:400c:c05::22a Cc: Ross Lagerwall X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: The development of GNU GRUB List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 07 Jun 2015 10:25:24 -0000 Add a module, part_eltorito, to allow parsing of the El Torito boot catalog into partitions. This follows the El Torito Bootable CD-ROM Format Specification Version 1.0 and the UEFI Specification 2.5. In cases where the specification is unclear, the code follows the UEFI reference implementation. This is useful when booting CDs in UEFI mode. Before, GRUB would not be able to use the embedded ESP from which it was executed, so it would have a root and prefix set to the top level of the CD. This could result in subtle configuration bugs, because the same ISO booted from a USB disk (using isohybrid) would have its root and prefix set to the embedded ESP because it can find it through the MBR. With this change, GRUB is able to access the embedded ESP and set its root and prefix correctly when booting a CD in UEFI mode. It also allows GRUB to access embedded floppy and HDD images. Tested with OVMF and a couple of real machines. Signed-off-by: Ross Lagerwall --- grub-core/Makefile.core.def | 5 ++ grub-core/partmap/eltorito.c | 199 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 grub-core/partmap/eltorito.c diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index a6101de..f07572b 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1785,6 +1785,11 @@ module = { }; module = { + name = part_eltorito; + common = partmap/eltorito.c; +}; + +module = { name = part_msdos; common = partmap/msdos.c; }; diff --git a/grub-core/partmap/eltorito.c b/grub-core/partmap/eltorito.c new file mode 100644 index 0000000..dee6250 --- /dev/null +++ b/grub-core/partmap/eltorito.c @@ -0,0 +1,199 @@ +/* eltorito.c - Read GUID Partition Tables (GPT). */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2005,2006,2007,2008 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define ISO9660_LOG2_BLKSZ 2 +#define BOOT_RECORD_LBA (0x11 << ISO9660_LOG2_BLKSZ) +#define PRIMARY_VOLUME_LBA (0x10 << ISO9660_LOG2_BLKSZ) +#define VOLUME_SPACE_SIZE_OFFSET 0x50 +#define ELTORITO_MAGIC (grub_cpu_to_le16_compile_time (0xAA55)) +#define ELTORITO_BOOTABLE 0x88 +#define ELTORITO_NOT_BOOTABLE 0x00 +#define ELTORITO_MEDIA_TYPE_MASK 0x03 +#define ELTORITO_TYPE_NO_EMUL 0x00 +#define ELTORITO_TYPE_FLOPPY_1_2 0x01 +#define ELTORITO_TYPE_FLOPPY_1_4 0x02 +#define ELTORITO_TYPE_FLOPPY_2_8 0x03 +#define ELTORITO_TYPE_HDD 0x04 + +static const char *IDENT = "CD001"; +static const char SYSTEM_ID[32] = "EL TORITO SPECIFICATION"; + +struct boot_record { + grub_uint8_t indicator; + char identifier[5]; + grub_uint8_t version; + char system_id[32]; + grub_uint8_t pad[32]; + grub_uint32_t catalog_sector; +} GRUB_PACKED; + +union et_entry { + /* The validation entry. */ + struct { + grub_uint8_t header; + grub_uint8_t platform; + grub_uint16_t reserved; + char identifier[24]; + grub_uint16_t checksum; + grub_uint16_t magic; + } validation GRUB_PACKED; + + /* All other entries. */ + struct { + grub_uint8_t boot_indicator; + grub_uint8_t media_type; + grub_uint16_t load_segment; + grub_uint8_t system_type; + grub_uint8_t unused; + grub_uint16_t sector_count; + grub_uint32_t load_lba; + char pad[20]; + } e GRUB_PACKED; + + /* Used for calculating the checksum. */ + grub_uint16_t bin[16]; +}; + +static struct grub_partition_map grub_eltorito_partition_map; + +static grub_err_t +grub_eltorito_partition_map_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, + void *hook_data) +{ + struct grub_partition part; + struct boot_record br; + union et_entry entries[64]; + unsigned int i; + int found = 0; + grub_uint16_t checksum = 0, sector_count; + grub_uint32_t total_sectors; + + /* Find boot catalog. */ + if (grub_disk_read (disk, BOOT_RECORD_LBA, 0, sizeof br, &br)) + return grub_errno; + + if (br.indicator != 0 || br.version != 1 || + grub_memcmp (br.identifier, IDENT, sizeof br.identifier) != 0 || + grub_memcmp (br.system_id, SYSTEM_ID, sizeof SYSTEM_ID) != 0) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid boot descriptor"); + + part.offset = grub_le_to_cpu32 (br.catalog_sector) << ISO9660_LOG2_BLKSZ; + + /* Load boot catalog and verify the validation entry. */ + if (grub_disk_read (disk, part.offset, 0, sizeof entries, entries)) + return grub_errno; + + if (entries[0].validation.header != 1 || + entries[0].validation.reserved != 0 || + entries[0].validation.magic != ELTORITO_MAGIC) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid validation entry"); + + for (i = 0; i < ARRAY_SIZE (entries[0].bin); i++) + checksum += grub_le_to_cpu16 (entries[0].bin[i]); + if (checksum != 0) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid validation entry"); + + /* Calculate the number of sectors, in case the ISO9660 filesystem is smaller + than the disk. */ + if (grub_disk_read (disk, PRIMARY_VOLUME_LBA, VOLUME_SPACE_SIZE_OFFSET, + sizeof total_sectors, &total_sectors)) + return grub_errno; + total_sectors = grub_le_to_cpu32 (total_sectors) << ISO9660_LOG2_BLKSZ; + total_sectors = grub_min (total_sectors, + disk->total_sectors << (disk->log_sector_size - + GRUB_DISK_SECTOR_BITS)); + + part.partmap = &grub_eltorito_partition_map; + part.parent = disk->partition; + + /* Add a partition for each valid entry. */ + for (i = 1; i < ARRAY_SIZE (entries); i++) + { + if ((entries[i].e.boot_indicator == ELTORITO_BOOTABLE || + entries[i].e.boot_indicator == ELTORITO_NOT_BOOTABLE) && + entries[i].e.load_lba != 0) + { + part.number = found++; + part.index = i; + part.start = entries[i].e.load_lba << ISO9660_LOG2_BLKSZ; + sector_count = grub_le_to_cpu16 (entries[i].e.sector_count); + + /* Calculate the sector size as it's done in the UEFI reference + implementation so that partitions are matched correctly. */ + switch (entries[i].e.media_type & ELTORITO_MEDIA_TYPE_MASK) + { + case ELTORITO_TYPE_NO_EMUL: + default: + if (sector_count < 2) + part.len = total_sectors - part.start; + else + part.len = sector_count << ISO9660_LOG2_BLKSZ; + break; + case ELTORITO_TYPE_HDD: + if (sector_count < 2) + part.len = total_sectors - part.start; + else + part.len = sector_count; + break; + case ELTORITO_TYPE_FLOPPY_1_2: + part.len = 2400; + break; + case ELTORITO_TYPE_FLOPPY_1_4: + part.len = 2880; + break; + case ELTORITO_TYPE_FLOPPY_2_8: + part.len = 5760; + break; + } + + if (hook (disk, &part, hook_data)) + return grub_errno; + } + } + + return GRUB_ERR_NONE; +} + + +/* Partition map type. */ +static struct grub_partition_map grub_eltorito_partition_map = + { + .name = "eltorito", + .iterate = grub_eltorito_partition_map_iterate, + }; + +GRUB_MOD_INIT(part_eltorito) +{ + grub_partition_map_register (&grub_eltorito_partition_map); +} + +GRUB_MOD_FINI(part_eltorito) +{ + grub_partition_map_unregister (&grub_eltorito_partition_map); +} -- 2.4.2