one patch, on grub-2.04
This commit is contained in:
parent
2a2e10c1b3
commit
1b24dcf433
61 changed files with 4887 additions and 97 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -45,6 +45,7 @@ gensymlist.sh
|
|||
gentrigtables
|
||||
gentrigtables.exe
|
||||
gettext_strings_test
|
||||
gpt_unit_test
|
||||
/gnulib
|
||||
grub-bin2h
|
||||
/grub-bios-setup
|
||||
|
|
|
@ -1175,6 +1175,18 @@ script = {
|
|||
common = tests/grub_cmd_tr.in;
|
||||
};
|
||||
|
||||
script = {
|
||||
testcase;
|
||||
name = gptrepair_test;
|
||||
common = tests/gptrepair_test.in;
|
||||
};
|
||||
|
||||
script = {
|
||||
testcase;
|
||||
name = gptprio_test;
|
||||
common = tests/gptprio_test.in;
|
||||
};
|
||||
|
||||
script = {
|
||||
testcase;
|
||||
name = file_filter_test;
|
||||
|
@ -1270,6 +1282,25 @@ program = {
|
|||
ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
|
||||
program = {
|
||||
testcase;
|
||||
name = gpt_unit_test;
|
||||
common = tests/gpt_unit_test.c;
|
||||
common = tests/lib/unit_test.c;
|
||||
common = grub-core/commands/search_part_label.c;
|
||||
common = grub-core/commands/search_part_uuid.c;
|
||||
common = grub-core/commands/search_disk_uuid.c;
|
||||
common = grub-core/disk/host.c;
|
||||
common = grub-core/kern/emu/hostfs.c;
|
||||
common = grub-core/lib/gpt.c;
|
||||
common = grub-core/tests/lib/test.c;
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = grub-core/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
|
||||
program = {
|
||||
name = grub-menulst2cfg;
|
||||
mansection = 1;
|
||||
|
|
|
@ -3944,6 +3944,7 @@ you forget a command, you can run the command @command{help}
|
|||
* sha256sum:: Compute or check SHA256 hash
|
||||
* sha512sum:: Compute or check SHA512 hash
|
||||
* sleep:: Wait for a specified number of seconds
|
||||
* smbios:: Retrieve SMBIOS information
|
||||
* source:: Read a configuration file in same context
|
||||
* test:: Check file types and compare values
|
||||
* true:: Do nothing, successfully
|
||||
|
@ -5083,6 +5084,74 @@ if timeout was interrupted by @key{ESC}.
|
|||
@end deffn
|
||||
|
||||
|
||||
@node smbios
|
||||
@subsection smbios
|
||||
|
||||
@deffn Command smbios @
|
||||
[@option{--type} @var{type}] @
|
||||
[@option{--handle} @var{handle}] @
|
||||
[@option{--match} @var{match}] @
|
||||
(@option{--get-byte} | @option{--get-word} | @option{--get-dword} | @
|
||||
@option{--get-qword} | @option{--get-string} | @option{--get-uuid}) @
|
||||
@var{offset} @
|
||||
[@option{--set} @var{variable}]
|
||||
Retrieve SMBIOS information.
|
||||
|
||||
The @command{smbios} command returns the value of a field in an SMBIOS
|
||||
structure. The following options determine which structure to select.
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Specifying @option{--type} will select structures with a matching
|
||||
@var{type}. The type can be any integer from 0 to 255.
|
||||
@item
|
||||
Specifying @option{--handle} will select structures with a matching
|
||||
@var{handle}. The handle can be any integer from 0 to 65535.
|
||||
@item
|
||||
Specifying @option{--match} will select structure number @var{match} in the
|
||||
filtered list of structures; e.g. @code{smbios --type 4 --match 2} will select
|
||||
the second Process Information (Type 4) structure. The list is always ordered
|
||||
the same as the hardware's SMBIOS table. The match number must be a positive
|
||||
integer. If unspecified, the first matching structure will be selected.
|
||||
@end itemize
|
||||
|
||||
The remaining options determine which field in the selected SMBIOS structure to
|
||||
return. Only one of these options may be specified at a time.
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
When given @option{--get-byte}, return the value of the byte
|
||||
at @var{offset} bytes into the selected SMBIOS structure.
|
||||
@item
|
||||
When given @option{--get-word}, return the value of the word (two bytes)
|
||||
at @var{offset} bytes into the selected SMBIOS structure.
|
||||
@item
|
||||
When given @option{--get-dword}, return the value of the dword (four bytes)
|
||||
at @var{offset} bytes into the selected SMBIOS structure.
|
||||
@item
|
||||
When given @option{--get-qword}, return the value of the qword (eight bytes)
|
||||
at @var{offset} bytes into the selected SMBIOS structure.
|
||||
@item
|
||||
When given @option{--get-string}, return the string with its index found
|
||||
at @var{offset} bytes into the selected SMBIOS structure.
|
||||
@item
|
||||
When given @option{--get-uuid}, return the value of the UUID (sixteen bytes)
|
||||
at @var{offset} bytes into the selected SMBIOS structure.
|
||||
@end itemize
|
||||
|
||||
The default action is to print the value of the requested field to the console,
|
||||
but a variable name can be specified with @option{--set} to store the value
|
||||
instead of printing it.
|
||||
|
||||
For example, this will store and then display the system manufacturer's name.
|
||||
|
||||
@example
|
||||
smbios --type 1 --get-string 4 --set system_manufacturer
|
||||
echo $system_manufacturer
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
|
||||
@node source
|
||||
@subsection source
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h
|
|||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/net.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/tpm.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h
|
||||
|
||||
if COND_i386_pc
|
||||
|
|
|
@ -140,6 +140,7 @@ kernel = {
|
|||
common = kern/rescue_parser.c;
|
||||
common = kern/rescue_reader.c;
|
||||
common = kern/term.c;
|
||||
common = kern/tpm.c;
|
||||
|
||||
noemu = kern/compiler-rt.c;
|
||||
noemu = kern/mm.c;
|
||||
|
@ -203,6 +204,7 @@ kernel = {
|
|||
efi = term/efi/console.c;
|
||||
efi = kern/acpi.c;
|
||||
efi = kern/efi/acpi.c;
|
||||
efi = kern/efi/tpm.c;
|
||||
i386_coreboot = kern/i386/pc/acpi.c;
|
||||
i386_multiboot = kern/i386/pc/acpi.c;
|
||||
i386_coreboot = kern/acpi.c;
|
||||
|
@ -262,6 +264,7 @@ kernel = {
|
|||
|
||||
i386_pc = kern/i386/pc/init.c;
|
||||
i386_pc = kern/i386/pc/mmap.c;
|
||||
i386_pc = kern/i386/pc/tpm.c;
|
||||
i386_pc = term/i386/pc/console.c;
|
||||
|
||||
i386_qemu = bus/pci.c;
|
||||
|
@ -888,11 +891,32 @@ module = {
|
|||
enable = x86_64_efi;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = getenv;
|
||||
common = commands/efi/getenv.c;
|
||||
enable = efi;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = gptsync;
|
||||
common = commands/gptsync.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = gptrepair;
|
||||
common = commands/gptrepair.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = gptprio;
|
||||
common = commands/gptprio.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = gpt;
|
||||
common = lib/gpt.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = halt;
|
||||
nopc = commands/halt.c;
|
||||
|
@ -1080,6 +1104,21 @@ module = {
|
|||
common = commands/search_label.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = search_part_uuid;
|
||||
common = commands/search_part_uuid.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = search_part_label;
|
||||
common = commands/search_part_label.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = search_disk_uuid;
|
||||
common = commands/search_disk_uuid.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = setpci;
|
||||
common = commands/setpci.c;
|
||||
|
@ -1097,6 +1136,21 @@ module = {
|
|||
common = commands/sleep.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = smbios;
|
||||
|
||||
common = commands/smbios.c;
|
||||
efi = commands/efi/smbios.c;
|
||||
i386_pc = commands/i386/pc/smbios.c;
|
||||
i386_coreboot = commands/i386/pc/smbios.c;
|
||||
i386_multiboot = commands/i386/pc/smbios.c;
|
||||
|
||||
enable = efi;
|
||||
enable = i386_pc;
|
||||
enable = i386_coreboot;
|
||||
enable = i386_multiboot;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = suspend;
|
||||
ieee1275 = commands/ieee1275/suspend.c;
|
||||
|
@ -1849,6 +1903,14 @@ module = {
|
|||
enable = x86_64_efi;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = linuxefi;
|
||||
efi = loader/i386/efi/linux.c;
|
||||
efi = lib/cmdline.c;
|
||||
enable = i386_efi;
|
||||
enable = x86_64_efi;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = chain;
|
||||
efi = loader/efi/chainloader.c;
|
||||
|
@ -2503,3 +2565,8 @@ module = {
|
|||
common = commands/i386/wrmsr.c;
|
||||
enable = x86;
|
||||
};
|
||||
module = {
|
||||
name = fwconfig;
|
||||
common = commands/fwconfig.c;
|
||||
enable = x86;
|
||||
};
|
||||
|
|
|
@ -24,11 +24,14 @@
|
|||
* defines for the code go here
|
||||
*/
|
||||
|
||||
#define TPM 1
|
||||
|
||||
/* Print message string */
|
||||
#define MSG(x) movw $x, %si; call LOCAL(message)
|
||||
#define ERR(x) movw $x, %si; jmp LOCAL(error_message)
|
||||
|
||||
.macro floppy
|
||||
#ifndef TPM
|
||||
part_start:
|
||||
|
||||
LOCAL(probe_values):
|
||||
|
@ -85,6 +88,7 @@ fd_probe_error_string: .asciz "Floppy"
|
|||
movb MACRO_DOLLAR(79), %ch
|
||||
|
||||
jmp LOCAL(final_init)
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro scratch
|
||||
|
@ -255,6 +259,7 @@ real_start:
|
|||
/* set %si to the disk address packet */
|
||||
movw $disk_address_packet, %si
|
||||
|
||||
#ifndef TPM
|
||||
/* check if LBA is supported */
|
||||
movb $0x41, %ah
|
||||
movw $0x55aa, %bx
|
||||
|
@ -274,6 +279,7 @@ real_start:
|
|||
|
||||
andw $1, %cx
|
||||
jz LOCAL(chs_mode)
|
||||
#endif
|
||||
|
||||
LOCAL(lba_mode):
|
||||
xorw %ax, %ax
|
||||
|
@ -317,6 +323,9 @@ LOCAL(lba_mode):
|
|||
jmp LOCAL(copy_buffer)
|
||||
|
||||
LOCAL(chs_mode):
|
||||
#ifdef TPM
|
||||
jmp LOCAL(general_error)
|
||||
#else
|
||||
/*
|
||||
* Determine the hard disk geometry from the BIOS!
|
||||
* We do this first, so that LS-120 IDE floppies work correctly.
|
||||
|
@ -428,7 +437,7 @@ setup_sectors:
|
|||
jc LOCAL(read_error)
|
||||
|
||||
movw %es, %bx
|
||||
|
||||
#endif /* TPM */
|
||||
LOCAL(copy_buffer):
|
||||
/*
|
||||
* We need to save %cx and %si because the startup code in
|
||||
|
@ -451,6 +460,25 @@ LOCAL(copy_buffer):
|
|||
popw %ds
|
||||
popa
|
||||
|
||||
#ifdef TPM
|
||||
pusha
|
||||
|
||||
movw $0xBB00, %ax /* TCG_StatusCheck */
|
||||
int $0x1A
|
||||
test %eax, %eax
|
||||
jnz boot /* No TPM or TPM deactivated */
|
||||
|
||||
movw $0xBB07, %ax /* TCG_CompactHashLogExtendEvent */
|
||||
movw $GRUB_BOOT_MACHINE_KERNEL_ADDR, %di
|
||||
xorl %esi, %esi
|
||||
movl $0x41504354, %ebx /* TCPA */
|
||||
movl $0x200, %ecx /* Measure 512 bytes */
|
||||
movl $0x8, %edx /* PCR 8 */
|
||||
int $0x1A
|
||||
|
||||
boot:
|
||||
popa
|
||||
#endif
|
||||
/* boot kernel */
|
||||
jmp *(LOCAL(kernel_address))
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include <grub/symbol.h>
|
||||
#include <grub/machine/boot.h>
|
||||
|
||||
#define TPM 1
|
||||
|
||||
/*
|
||||
* defines for the code go here
|
||||
*/
|
||||
|
@ -58,6 +60,21 @@ _start:
|
|||
/* this sets up for the first run through "bootloop" */
|
||||
movw $LOCAL(firstlist), %di
|
||||
|
||||
#ifdef TPM
|
||||
/* clear EAX to remove potential garbage */
|
||||
xorl %eax, %eax
|
||||
/* 8(%di) = number of sectors to read */
|
||||
movw 8(%di), %ax
|
||||
|
||||
/* Multiply number of sectors to read with 512 bytes. EAX is 32bit
|
||||
* which is large enough to hold values of up to 4GB. I doubt there
|
||||
* will ever be a core.img larger than that. ;-) */
|
||||
shll $9, %eax
|
||||
|
||||
/* write result to bytes_to_measure var */
|
||||
movl %eax, bytes_to_measure
|
||||
#endif
|
||||
|
||||
/* save the sector number of the second sector in %ebp */
|
||||
movl (%di), %ebp
|
||||
|
||||
|
@ -295,6 +312,29 @@ LOCAL(copy_buffer):
|
|||
/* END OF MAIN LOOP */
|
||||
|
||||
LOCAL(bootit):
|
||||
#ifdef TPM
|
||||
pusha
|
||||
movw $0xBB07, %ax /* TCG_CompactHashLogExtendEvent */
|
||||
|
||||
movw $0x0, %bx
|
||||
movw %bx, %es
|
||||
|
||||
/* We've already measured the first 512 bytes, now measure the rest */
|
||||
xorl %edi, %edi
|
||||
movw $(GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200), %di
|
||||
|
||||
movl $0x41504354, %ebx /* EBX = "TCPA" */
|
||||
|
||||
/* %ecx = The length, in bytes, of the buffer to measure */
|
||||
movl $bytes_to_measure, %esi
|
||||
movl (%esi), %ecx
|
||||
xorl %esi, %esi
|
||||
movl $0x9, %edx /* PCR 9 */
|
||||
|
||||
int $0x1A
|
||||
|
||||
popa
|
||||
#endif
|
||||
/* print a newline */
|
||||
MSG(notification_done)
|
||||
popw %dx /* this makes sure %dl is our "boot" drive */
|
||||
|
@ -329,6 +369,10 @@ geometry_error_string: .asciz "Geom"
|
|||
read_error_string: .asciz "Read"
|
||||
general_error_string: .asciz " Error"
|
||||
|
||||
#ifdef TPM
|
||||
bytes_to_measure: .long 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* message: write the string pointed to by %si
|
||||
*
|
||||
|
|
153
grub-core/commands/efi/getenv.c
Normal file
153
grub-core/commands/efi/getenv.c
Normal file
|
@ -0,0 +1,153 @@
|
|||
/* getenv.c - retrieve EFI variables. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2014 CoreOS, 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static const struct grub_arg_option options_getenv[] = {
|
||||
{"var-name", 'e', 0,
|
||||
N_("Environment variable to query"),
|
||||
N_("VARNAME"), ARG_TYPE_STRING},
|
||||
{"var-guid", 'g', 0,
|
||||
N_("GUID of environment variable to query"),
|
||||
N_("GUID"), ARG_TYPE_STRING},
|
||||
{"binary", 'b', 0,
|
||||
N_("Read binary data and represent it as hex"),
|
||||
0, ARG_TYPE_NONE},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
enum options_getenv
|
||||
{
|
||||
GETENV_VAR_NAME,
|
||||
GETENV_VAR_GUID,
|
||||
GETENV_BINARY,
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_getenv (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
char *envvar = NULL, *guid = NULL, *bindata = NULL, *data = NULL;
|
||||
grub_size_t datasize;
|
||||
grub_efi_guid_t efi_var_guid;
|
||||
grub_efi_boolean_t binary = state[GETENV_BINARY].set;
|
||||
unsigned int i;
|
||||
|
||||
if (!state[GETENV_VAR_NAME].set || !state[GETENV_VAR_GUID].set)
|
||||
{
|
||||
grub_error (GRUB_ERR_INVALID_COMMAND, N_("-e and -g are required"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (argc != 1)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unexpected arguments"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
envvar = state[GETENV_VAR_NAME].arg;
|
||||
guid = state[GETENV_VAR_GUID].arg;
|
||||
|
||||
if (grub_strlen(guid) != 36 ||
|
||||
guid[8] != '-' ||
|
||||
guid[13] != '-' ||
|
||||
guid[18] != '-' ||
|
||||
guid[23] != '-')
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid GUID"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Forgive me father for I have sinned */
|
||||
guid[8] = 0;
|
||||
efi_var_guid.data1 = grub_strtoul(guid, NULL, 16);
|
||||
guid[13] = 0;
|
||||
efi_var_guid.data2 = grub_strtoul(guid + 9, NULL, 16);
|
||||
guid[18] = 0;
|
||||
efi_var_guid.data3 = grub_strtoul(guid + 14, NULL, 16);
|
||||
efi_var_guid.data4[7] = grub_strtoul(guid + 34, NULL, 16);
|
||||
guid[34] = 0;
|
||||
efi_var_guid.data4[6] = grub_strtoul(guid + 32, NULL, 16);
|
||||
guid[32] = 0;
|
||||
efi_var_guid.data4[5] = grub_strtoul(guid + 30, NULL, 16);
|
||||
guid[30] = 0;
|
||||
efi_var_guid.data4[4] = grub_strtoul(guid + 28, NULL, 16);
|
||||
guid[28] = 0;
|
||||
efi_var_guid.data4[3] = grub_strtoul(guid + 26, NULL, 16);
|
||||
guid[26] = 0;
|
||||
efi_var_guid.data4[2] = grub_strtoul(guid + 24, NULL, 16);
|
||||
guid[23] = 0;
|
||||
efi_var_guid.data4[1] = grub_strtoul(guid + 21, NULL, 16);
|
||||
guid[21] = 0;
|
||||
efi_var_guid.data4[0] = grub_strtoul(guid + 19, NULL, 16);
|
||||
|
||||
data = grub_efi_get_variable(envvar, &efi_var_guid, &datasize);
|
||||
|
||||
if (!data || !datasize)
|
||||
{
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("No such variable"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (binary)
|
||||
{
|
||||
bindata = grub_zalloc(datasize * 2 + 1);
|
||||
for (i=0; i<datasize; i++)
|
||||
grub_snprintf(bindata + i*2, 3, "%02x", data[i] & 0xff);
|
||||
|
||||
if (grub_env_set (args[0], bindata))
|
||||
goto done;
|
||||
}
|
||||
else if (grub_env_set (args[0], data))
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
done:
|
||||
grub_free(bindata);
|
||||
grub_free(data);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_extcmd_t cmd_getenv;
|
||||
|
||||
GRUB_MOD_INIT(getenv)
|
||||
{
|
||||
cmd_getenv = grub_register_extcmd ("getenv", grub_cmd_getenv, 0,
|
||||
N_("-e envvar -g guidenv setvar"),
|
||||
N_("Read a firmware environment variable"),
|
||||
options_getenv);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(getenv)
|
||||
{
|
||||
grub_unregister_extcmd (cmd_getenv);
|
||||
}
|
|
@ -30,6 +30,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
|
|||
static grub_efi_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID;
|
||||
static grub_efi_guid_t acpi2_guid = GRUB_EFI_ACPI_20_TABLE_GUID;
|
||||
static grub_efi_guid_t smbios_guid = GRUB_EFI_SMBIOS_TABLE_GUID;
|
||||
static grub_efi_guid_t smbios3_guid = GRUB_EFI_SMBIOS3_TABLE_GUID;
|
||||
|
||||
#define EBDA_SEG_ADDR 0x40e
|
||||
#define LOW_MEM_ADDR 0x413
|
||||
|
@ -93,7 +94,7 @@ static void
|
|||
fake_bios_data (int use_rom)
|
||||
{
|
||||
unsigned i;
|
||||
void *acpi, *smbios;
|
||||
void *acpi, *smbios, *smbios3;
|
||||
grub_uint16_t *ebda_seg_ptr, *low_mem_ptr;
|
||||
|
||||
ebda_seg_ptr = (grub_uint16_t *) EBDA_SEG_ADDR;
|
||||
|
@ -103,6 +104,7 @@ fake_bios_data (int use_rom)
|
|||
|
||||
acpi = 0;
|
||||
smbios = 0;
|
||||
smbios3 = 0;
|
||||
for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
|
||||
{
|
||||
grub_efi_packed_guid_t *guid =
|
||||
|
@ -127,6 +129,11 @@ fake_bios_data (int use_rom)
|
|||
smbios = grub_efi_system_table->configuration_table[i].vendor_table;
|
||||
grub_dprintf ("efi", "SMBIOS: %p\n", smbios);
|
||||
}
|
||||
else if (! grub_memcmp (guid, &smbios3_guid, sizeof (grub_efi_guid_t)))
|
||||
{
|
||||
smbios3 = grub_efi_system_table->configuration_table[i].vendor_table;
|
||||
grub_dprintf ("efi", "SMBIOS3: %p\n", smbios3);
|
||||
}
|
||||
}
|
||||
|
||||
*ebda_seg_ptr = FAKE_EBDA_SEG;
|
||||
|
@ -137,8 +144,13 @@ fake_bios_data (int use_rom)
|
|||
if (acpi)
|
||||
grub_memcpy ((char *) ((FAKE_EBDA_SEG << 4) + 16), acpi, 1024 - 16);
|
||||
|
||||
if ((use_rom) && (smbios))
|
||||
grub_memcpy ((char *) SBIOS_ADDR, (char *) smbios + 16, 16);
|
||||
if (use_rom)
|
||||
{
|
||||
if (smbios)
|
||||
grub_memcpy ((char *) SBIOS_ADDR, (char *) smbios, 31);
|
||||
if (smbios3)
|
||||
grub_memcpy ((char *) SBIOS_ADDR + 32, (char *) smbios3, 24);
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
|
|
|
@ -48,6 +48,7 @@ static const struct guid_mapping guid_mappings[] =
|
|||
{ GRUB_EFI_MPS_TABLE_GUID, "MPS"},
|
||||
{ GRUB_EFI_SAL_TABLE_GUID, "SAL"},
|
||||
{ GRUB_EFI_SMBIOS_TABLE_GUID, "SMBIOS"},
|
||||
{ GRUB_EFI_SMBIOS3_TABLE_GUID, "SMBIOS3"},
|
||||
{ GRUB_EFI_SYSTEM_RESOURCE_TABLE_GUID, "SYSTEM RESOURCE TABLE"},
|
||||
{ GRUB_EFI_TIANO_CUSTOM_DECOMPRESS_GUID, "TIANO CUSTOM DECOMPRESS"},
|
||||
{ GRUB_EFI_TSC_FREQUENCY_GUID, "TSC FREQUENCY"},
|
||||
|
|
59
grub-core/commands/efi/smbios.c
Normal file
59
grub-core/commands/efi/smbios.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
/* smbios.c - get smbios tables. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/smbios.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/efi/api.h>
|
||||
|
||||
struct grub_smbios_eps *
|
||||
grub_machine_smbios_get_eps (void)
|
||||
{
|
||||
unsigned i;
|
||||
static grub_efi_packed_guid_t smbios_guid = GRUB_EFI_SMBIOS_TABLE_GUID;
|
||||
|
||||
for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
|
||||
{
|
||||
grub_efi_packed_guid_t *guid =
|
||||
&grub_efi_system_table->configuration_table[i].vendor_guid;
|
||||
|
||||
if (! grub_memcmp (guid, &smbios_guid, sizeof (grub_efi_packed_guid_t)))
|
||||
return (struct grub_smbios_eps *)
|
||||
grub_efi_system_table->configuration_table[i].vendor_table;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct grub_smbios_eps3 *
|
||||
grub_machine_smbios_get_eps3 (void)
|
||||
{
|
||||
unsigned i;
|
||||
static grub_efi_packed_guid_t smbios3_guid = GRUB_EFI_SMBIOS3_TABLE_GUID;
|
||||
|
||||
for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
|
||||
{
|
||||
grub_efi_packed_guid_t *guid =
|
||||
&grub_efi_system_table->configuration_table[i].vendor_guid;
|
||||
|
||||
if (! grub_memcmp (guid, &smbios3_guid, sizeof (grub_efi_packed_guid_t)))
|
||||
return (struct grub_smbios_eps3 *)
|
||||
grub_efi_system_table->configuration_table[i].vendor_table;
|
||||
}
|
||||
return 0;
|
||||
}
|
122
grub-core/commands/fwconfig.c
Normal file
122
grub-core/commands/fwconfig.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
/* fwconfig.c - command to read config from qemu fwconfig */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2015 CoreOS, 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/cpu/io.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define SELECTOR 0x510
|
||||
#define DATA 0x511
|
||||
|
||||
#define SIGNATURE_INDEX 0x00
|
||||
#define DIRECTORY_INDEX 0x19
|
||||
|
||||
static grub_extcmd_t cmd_read_fwconfig;
|
||||
|
||||
struct grub_qemu_fwcfgfile {
|
||||
grub_uint32_t size;
|
||||
grub_uint16_t select;
|
||||
grub_uint16_t reserved;
|
||||
char name[56];
|
||||
};
|
||||
|
||||
static const struct grub_arg_option options[] =
|
||||
{
|
||||
{0, 'v', 0, N_("Save read value into variable VARNAME."),
|
||||
N_("VARNAME"), ARG_TYPE_STRING},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_fwconfig (grub_extcmd_context_t ctxt __attribute__ ((unused)),
|
||||
int argc, char **argv)
|
||||
{
|
||||
grub_uint32_t i, j, value = 0;
|
||||
struct grub_qemu_fwcfgfile file;
|
||||
char fwsig[4], signature[4] = { 'Q', 'E', 'M', 'U' };
|
||||
|
||||
if (argc != 2)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
|
||||
|
||||
/* Verify that we have meaningful hardware here */
|
||||
grub_outw(SIGNATURE_INDEX, SELECTOR);
|
||||
for (i=0; i<sizeof(fwsig); i++)
|
||||
fwsig[i] = grub_inb(DATA);
|
||||
|
||||
if (grub_memcmp(fwsig, signature, sizeof(signature)) != 0)
|
||||
return grub_error (GRUB_ERR_BAD_DEVICE, N_("invalid fwconfig hardware signature: got 0x%x%x%x%x"), fwsig[0], fwsig[1], fwsig[2], fwsig[3]);
|
||||
|
||||
/* Find out how many file entries we have */
|
||||
grub_outw(DIRECTORY_INDEX, SELECTOR);
|
||||
value = grub_inb(DATA) | grub_inb(DATA) << 8 | grub_inb(DATA) << 16 | grub_inb(DATA) << 24;
|
||||
value = grub_be_to_cpu32(value);
|
||||
/* Read the file description for each file */
|
||||
for (i=0; i<value; i++)
|
||||
{
|
||||
for (j=0; j<sizeof(file); j++)
|
||||
{
|
||||
((char *)&file)[j] = grub_inb(DATA);
|
||||
}
|
||||
/* Check whether it matches what we're looking for, and if so read the file */
|
||||
if (grub_strncmp(file.name, argv[0], sizeof(file.name)) == 0)
|
||||
{
|
||||
grub_uint32_t filesize = grub_be_to_cpu32(file.size);
|
||||
grub_uint16_t location = grub_be_to_cpu16(file.select);
|
||||
char *data = grub_malloc(filesize+1);
|
||||
|
||||
if (!data)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate buffer for data"));
|
||||
|
||||
grub_outw(location, SELECTOR);
|
||||
for (j=0; j<filesize; j++)
|
||||
{
|
||||
data[j] = grub_inb(DATA);
|
||||
}
|
||||
|
||||
data[filesize] = '\0';
|
||||
|
||||
grub_env_set (argv[1], data);
|
||||
|
||||
grub_free(data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("couldn't find entry %s"), argv[0]);
|
||||
}
|
||||
|
||||
GRUB_MOD_INIT(fwconfig)
|
||||
{
|
||||
cmd_read_fwconfig =
|
||||
grub_register_extcmd ("fwconfig", grub_cmd_fwconfig, 0,
|
||||
N_("PATH VAR"),
|
||||
N_("Set VAR to the contents of fwconfig PATH"),
|
||||
options);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(fwconfig)
|
||||
{
|
||||
grub_unregister_extcmd (cmd_read_fwconfig);
|
||||
}
|
223
grub-core/commands/gptprio.c
Normal file
223
grub-core/commands/gptprio.c
Normal file
|
@ -0,0 +1,223 @@
|
|||
/* gptprio.c - manage priority based partition selection. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2014 CoreOS, 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/device.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/gpt_partition.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/misc.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static const struct grub_arg_option options_next[] = {
|
||||
{"set-device", 'd', 0,
|
||||
N_("Set a variable to the name of selected partition."),
|
||||
N_("VARNAME"), ARG_TYPE_STRING},
|
||||
{"set-uuid", 'u', 0,
|
||||
N_("Set a variable to the GPT UUID of selected partition."),
|
||||
N_("VARNAME"), ARG_TYPE_STRING},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
enum options_next
|
||||
{
|
||||
NEXT_SET_DEVICE,
|
||||
NEXT_SET_UUID,
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
grub_gptprio_priority (struct grub_gpt_partentry *entry)
|
||||
{
|
||||
return (unsigned int) grub_gpt_entry_attribute
|
||||
(entry, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_PRIORITY, 4);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
grub_gptprio_tries_left (struct grub_gpt_partentry *entry)
|
||||
{
|
||||
return (unsigned int) grub_gpt_entry_attribute
|
||||
(entry, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_TRIES_LEFT, 4);
|
||||
}
|
||||
|
||||
static void
|
||||
grub_gptprio_set_tries_left (struct grub_gpt_partentry *entry,
|
||||
unsigned int tries_left)
|
||||
{
|
||||
grub_gpt_entry_set_attribute
|
||||
(entry, tries_left, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_TRIES_LEFT, 4);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
grub_gptprio_successful (struct grub_gpt_partentry *entry)
|
||||
{
|
||||
return (unsigned int) grub_gpt_entry_attribute
|
||||
(entry, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_SUCCESSFUL, 1);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_find_next (const char *disk_name,
|
||||
const grub_gpt_part_guid_t *part_type,
|
||||
char **part_name, char **part_guid)
|
||||
{
|
||||
struct grub_gpt_partentry *part, *part_found = NULL;
|
||||
grub_device_t dev = NULL;
|
||||
grub_gpt_t gpt = NULL;
|
||||
grub_uint32_t i, part_index;
|
||||
|
||||
dev = grub_device_open (disk_name);
|
||||
if (!dev)
|
||||
goto done;
|
||||
|
||||
gpt = grub_gpt_read (dev->disk);
|
||||
if (!gpt)
|
||||
goto done;
|
||||
|
||||
if (grub_gpt_repair (dev->disk, gpt))
|
||||
goto done;
|
||||
|
||||
for (i = 0; (part = grub_gpt_get_partentry (gpt, i)) != NULL; i++)
|
||||
{
|
||||
if (grub_memcmp (part_type, &part->type, sizeof (*part_type)) == 0)
|
||||
{
|
||||
unsigned int priority, tries_left, successful, old_priority = 0;
|
||||
|
||||
priority = grub_gptprio_priority (part);
|
||||
tries_left = grub_gptprio_tries_left (part);
|
||||
successful = grub_gptprio_successful (part);
|
||||
|
||||
if (part_found)
|
||||
old_priority = grub_gptprio_priority (part_found);
|
||||
|
||||
if ((tries_left || successful) && priority > old_priority)
|
||||
{
|
||||
part_index = i;
|
||||
part_found = part;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!part_found)
|
||||
{
|
||||
grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("no such partition"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (grub_gptprio_tries_left (part_found))
|
||||
{
|
||||
unsigned int tries_left = grub_gptprio_tries_left (part_found);
|
||||
|
||||
grub_gptprio_set_tries_left (part_found, tries_left - 1);
|
||||
|
||||
if (grub_gpt_update (gpt))
|
||||
goto done;
|
||||
|
||||
if (grub_gpt_write (dev->disk, gpt))
|
||||
goto done;
|
||||
}
|
||||
|
||||
*part_name = grub_xasprintf ("%s,gpt%u", disk_name, part_index + 1);
|
||||
if (!*part_name)
|
||||
goto done;
|
||||
|
||||
*part_guid = grub_gpt_guid_to_str (&part_found->guid);
|
||||
if (!*part_guid)
|
||||
goto done;
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
done:
|
||||
grub_gpt_free (gpt);
|
||||
|
||||
if (dev)
|
||||
grub_device_close (dev);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_next (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
char *p, *root = NULL, *part_name = NULL, *part_guid = NULL;
|
||||
|
||||
/* TODO: Add a uuid parser and a command line flag for providing type. */
|
||||
grub_gpt_part_guid_t part_type = GRUB_GPT_PARTITION_TYPE_USR_X86_64;
|
||||
|
||||
if (!state[NEXT_SET_DEVICE].set || !state[NEXT_SET_UUID].set)
|
||||
{
|
||||
grub_error (GRUB_ERR_INVALID_COMMAND, N_("-d and -u are required"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (argc == 0)
|
||||
root = grub_strdup (grub_env_get ("root"));
|
||||
else if (argc == 1)
|
||||
root = grub_strdup (args[0]);
|
||||
else
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unexpected arguments"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!root)
|
||||
goto done;
|
||||
|
||||
/* To make using $root practical strip off the partition name. */
|
||||
p = grub_strchr (root, ',');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
if (grub_find_next (root, &part_type, &part_name, &part_guid))
|
||||
goto done;
|
||||
|
||||
if (grub_env_set (state[NEXT_SET_DEVICE].arg, part_name))
|
||||
goto done;
|
||||
|
||||
if (grub_env_set (state[NEXT_SET_UUID].arg, part_guid))
|
||||
goto done;
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
done:
|
||||
grub_free (root);
|
||||
grub_free (part_name);
|
||||
grub_free (part_guid);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_extcmd_t cmd_next;
|
||||
|
||||
GRUB_MOD_INIT(gptprio)
|
||||
{
|
||||
cmd_next = grub_register_extcmd ("gptprio.next", grub_cmd_next, 0,
|
||||
N_("-d VARNAME -u VARNAME [DEVICE]"),
|
||||
N_("Select next partition to boot."),
|
||||
options_next);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(gptprio)
|
||||
{
|
||||
grub_unregister_extcmd (cmd_next);
|
||||
}
|
110
grub-core/commands/gptrepair.c
Normal file
110
grub-core/commands/gptrepair.c
Normal file
|
@ -0,0 +1,110 @@
|
|||
/* gptrepair.c - verify and restore GPT info from alternate location. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2014 CoreOS, 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/command.h>
|
||||
#include <grub/device.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/gpt_partition.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/misc.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static char *
|
||||
trim_dev_name (char *name)
|
||||
{
|
||||
grub_size_t len = grub_strlen (name);
|
||||
if (len && name[0] == '(' && name[len - 1] == ')')
|
||||
{
|
||||
name[len - 1] = '\0';
|
||||
name = name + 1;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_gptrepair (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
grub_device_t dev = NULL;
|
||||
grub_gpt_t gpt = NULL;
|
||||
char *dev_name;
|
||||
|
||||
if (argc != 1 || !grub_strlen(args[0]))
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
|
||||
|
||||
dev_name = trim_dev_name (args[0]);
|
||||
dev = grub_device_open (dev_name);
|
||||
if (!dev)
|
||||
goto done;
|
||||
|
||||
if (!dev->disk)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk");
|
||||
goto done;
|
||||
}
|
||||
|
||||
gpt = grub_gpt_read (dev->disk);
|
||||
if (!gpt)
|
||||
goto done;
|
||||
|
||||
if (grub_gpt_both_valid (gpt))
|
||||
{
|
||||
grub_printf_ (N_("GPT already valid, %s unmodified.\n"), dev_name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!grub_gpt_primary_valid (gpt))
|
||||
grub_printf_ (N_("Found invalid primary GPT on %s\n"), dev_name);
|
||||
|
||||
if (!grub_gpt_backup_valid (gpt))
|
||||
grub_printf_ (N_("Found invalid backup GPT on %s\n"), dev_name);
|
||||
|
||||
if (grub_gpt_repair (dev->disk, gpt))
|
||||
goto done;
|
||||
|
||||
if (grub_gpt_write (dev->disk, gpt))
|
||||
goto done;
|
||||
|
||||
grub_printf_ (N_("Repaired GPT on %s\n"), dev_name);
|
||||
|
||||
done:
|
||||
if (gpt)
|
||||
grub_gpt_free (gpt);
|
||||
|
||||
if (dev)
|
||||
grub_device_close (dev);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_command_t cmd;
|
||||
|
||||
GRUB_MOD_INIT(gptrepair)
|
||||
{
|
||||
cmd = grub_register_command ("gptrepair", grub_cmd_gptrepair,
|
||||
N_("DEVICE"),
|
||||
N_("Verify and repair GPT on drive DEVICE."));
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(gptrepair)
|
||||
{
|
||||
grub_unregister_command (cmd);
|
||||
}
|
50
grub-core/commands/i386/pc/smbios.c
Normal file
50
grub-core/commands/i386/pc/smbios.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
/* smbios.c - get smbios tables. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/acpi.h>
|
||||
#include <grub/smbios.h>
|
||||
#include <grub/misc.h>
|
||||
|
||||
struct grub_smbios_eps *
|
||||
grub_machine_smbios_get_eps (void)
|
||||
{
|
||||
grub_uint8_t *ptr;
|
||||
|
||||
grub_dprintf ("smbios", "Looking for SMBIOS EPS. Scanning BIOS\n");
|
||||
for (ptr = (grub_uint8_t *) 0xf0000; ptr < (grub_uint8_t *) 0x100000;
|
||||
ptr += 16)
|
||||
if (grub_memcmp (ptr, "_SM_", 4) == 0
|
||||
&& grub_byte_checksum (ptr, sizeof (struct grub_smbios_eps)) == 0)
|
||||
return (struct grub_smbios_eps *) ptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct grub_smbios_eps3 *
|
||||
grub_machine_smbios_get_eps3 (void)
|
||||
{
|
||||
grub_uint8_t *ptr;
|
||||
|
||||
grub_dprintf ("smbios", "Looking for SMBIOS3 EPS. Scanning BIOS\n");
|
||||
for (ptr = (grub_uint8_t *) 0xf0000; ptr < (grub_uint8_t *) 0x100000;
|
||||
ptr += 16)
|
||||
if (grub_memcmp (ptr, "_SM3_", 5) == 0
|
||||
&& grub_byte_checksum (ptr, sizeof (struct grub_smbios_eps3)) == 0)
|
||||
return (struct grub_smbios_eps3 *) ptr;
|
||||
return 0;
|
||||
}
|
|
@ -759,6 +759,78 @@ grub_cmd_trust (grub_extcmd_context_t ctxt,
|
|||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
|
||||
{
|
||||
grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Filesystem descriptor. */
|
||||
struct grub_fs pseudo_fs =
|
||||
{
|
||||
.name = "pseudo",
|
||||
.fs_read = pseudo_read
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_trust_var (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
struct grub_file pseudo_file;
|
||||
const char *var;
|
||||
char *data;
|
||||
struct grub_public_key *pk = NULL;
|
||||
unsigned int i, idx0, idx1;
|
||||
|
||||
if (argc < 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
|
||||
|
||||
var = grub_env_get (args[0]);
|
||||
if (!var)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unknown variable"));
|
||||
|
||||
data = grub_zalloc (grub_strlen (var) / 2);
|
||||
if (!data)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate memory for key"));
|
||||
|
||||
/* For the want of sscanf() */
|
||||
for (i = 0; i < grub_strlen (var); i += 2)
|
||||
{
|
||||
if (var[i] < 0x40)
|
||||
idx0 = var[i] - 0x30;
|
||||
else
|
||||
idx0 = var[i] - 0x57;
|
||||
|
||||
if (var[i+1] < 0x40)
|
||||
idx1 = var[i+1] - 0x30;
|
||||
else
|
||||
idx1 = var[i+1] - 0x57;
|
||||
|
||||
data[i/2] = ((idx0 << 4) & 0xf0) | (idx1 & 0x0f);
|
||||
}
|
||||
|
||||
grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
|
||||
|
||||
pseudo_file.fs = &pseudo_fs;
|
||||
pseudo_file.size = grub_strlen (var) / 2;
|
||||
pseudo_file.data = data;
|
||||
|
||||
pk = grub_load_public_key (&pseudo_file);
|
||||
if (!pk)
|
||||
{
|
||||
grub_free(data);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
pk->next = grub_pk_trusted;
|
||||
grub_pk_trusted = pk;
|
||||
|
||||
grub_free(data);
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_list (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc __attribute__ ((unused)),
|
||||
|
@ -922,21 +994,6 @@ grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)),
|
|||
return grub_strdup (sec ? "enforce" : "no");
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
|
||||
{
|
||||
grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/* Filesystem descriptor. */
|
||||
struct grub_fs pseudo_fs =
|
||||
{
|
||||
.name = "pseudo",
|
||||
.fs_read = pseudo_read
|
||||
};
|
||||
|
||||
struct grub_file_verifier grub_pubkey_verifier =
|
||||
{
|
||||
.name = "pgp",
|
||||
|
@ -947,7 +1004,7 @@ struct grub_file_verifier grub_pubkey_verifier =
|
|||
};
|
||||
|
||||
static grub_extcmd_t cmd, cmd_trust;
|
||||
static grub_command_t cmd_distrust, cmd_list;
|
||||
static grub_command_t cmd_trust_var, cmd_distrust, cmd_list;
|
||||
|
||||
GRUB_MOD_INIT(pgp)
|
||||
{
|
||||
|
@ -998,6 +1055,9 @@ GRUB_MOD_INIT(pgp)
|
|||
N_("[-s|--skip-sig] PUBKEY_FILE"),
|
||||
N_("Add PUBKEY_FILE to trusted keys."),
|
||||
options);
|
||||
cmd_trust_var = grub_register_command ("trust_var", grub_cmd_trust_var,
|
||||
N_("PUBKEY_VAR"),
|
||||
N_("Add the contents of PUBKEY_VAR to trusted keys."));
|
||||
cmd_list = grub_register_command ("list_trusted", grub_cmd_list,
|
||||
0,
|
||||
N_("Show the list of trusted keys."));
|
||||
|
@ -1013,6 +1073,7 @@ GRUB_MOD_FINI(pgp)
|
|||
grub_verifier_unregister (&grub_pubkey_verifier);
|
||||
grub_unregister_extcmd (cmd);
|
||||
grub_unregister_extcmd (cmd_trust);
|
||||
grub_unregister_command (cmd_trust_var);
|
||||
grub_unregister_command (cmd_list);
|
||||
grub_unregister_command (cmd_distrust);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
#include <grub/i18n.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/partition.h>
|
||||
#if defined(DO_SEARCH_PART_UUID) || defined(DO_SEARCH_PART_LABEL) || \
|
||||
defined(DO_SEARCH_DISK_UUID)
|
||||
#include <grub/gpt_partition.h>
|
||||
#endif
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
@ -66,7 +70,7 @@ iterate_device (const char *name, void *data)
|
|||
name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9')
|
||||
return 1;
|
||||
|
||||
#ifdef DO_SEARCH_FS_UUID
|
||||
#if defined(DO_SEARCH_FS_UUID) || defined(DO_SEARCH_DISK_UUID)
|
||||
#define compare_fn grub_strcasecmp
|
||||
#else
|
||||
#define compare_fn grub_strcmp
|
||||
|
@ -90,6 +94,63 @@ iterate_device (const char *name, void *data)
|
|||
}
|
||||
grub_free (buf);
|
||||
}
|
||||
#elif defined(DO_SEARCH_PART_UUID)
|
||||
{
|
||||
grub_device_t dev;
|
||||
char *quid;
|
||||
|
||||
dev = grub_device_open (name);
|
||||
if (dev)
|
||||
{
|
||||
if (grub_gpt_part_uuid (dev, &quid) == GRUB_ERR_NONE)
|
||||
{
|
||||
if (grub_strcasecmp (quid, ctx->key) == 0)
|
||||
found = 1;
|
||||
|
||||
grub_free (quid);
|
||||
}
|
||||
|
||||
grub_device_close (dev);
|
||||
}
|
||||
}
|
||||
#elif defined(DO_SEARCH_PART_LABEL)
|
||||
{
|
||||
grub_device_t dev;
|
||||
char *quid;
|
||||
|
||||
dev = grub_device_open (name);
|
||||
if (dev)
|
||||
{
|
||||
if (grub_gpt_part_label (dev, &quid) == GRUB_ERR_NONE)
|
||||
{
|
||||
if (grub_strcmp (quid, ctx->key) == 0)
|
||||
found = 1;
|
||||
|
||||
grub_free (quid);
|
||||
}
|
||||
|
||||
grub_device_close (dev);
|
||||
}
|
||||
}
|
||||
#elif defined(DO_SEARCH_DISK_UUID)
|
||||
{
|
||||
grub_device_t dev;
|
||||
char *quid;
|
||||
|
||||
dev = grub_device_open (name);
|
||||
if (dev)
|
||||
{
|
||||
if (grub_gpt_disk_uuid (dev, &quid) == GRUB_ERR_NONE)
|
||||
{
|
||||
if (grub_strcmp (quid, ctx->key) == 0)
|
||||
found = 1;
|
||||
|
||||
grub_free (quid);
|
||||
}
|
||||
|
||||
grub_device_close (dev);
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
/* SEARCH_FS_UUID or SEARCH_LABEL */
|
||||
|
@ -313,8 +374,14 @@ static grub_command_t cmd;
|
|||
|
||||
#ifdef DO_SEARCH_FILE
|
||||
GRUB_MOD_INIT(search_fs_file)
|
||||
#elif defined(DO_SEARCH_PART_UUID)
|
||||
GRUB_MOD_INIT(search_part_uuid)
|
||||
#elif defined(DO_SEARCH_PART_LABEL)
|
||||
GRUB_MOD_INIT(search_part_label)
|
||||
#elif defined (DO_SEARCH_FS_UUID)
|
||||
GRUB_MOD_INIT(search_fs_uuid)
|
||||
#elif defined (DO_SEARCH_DISK_UUID)
|
||||
GRUB_MOD_INIT(search_disk_uuid)
|
||||
#else
|
||||
GRUB_MOD_INIT(search_label)
|
||||
#endif
|
||||
|
@ -327,8 +394,14 @@ GRUB_MOD_INIT(search_label)
|
|||
|
||||
#ifdef DO_SEARCH_FILE
|
||||
GRUB_MOD_FINI(search_fs_file)
|
||||
#elif defined(DO_SEARCH_PART_UUID)
|
||||
GRUB_MOD_FINI(search_part_uuid)
|
||||
#elif defined(DO_SEARCH_PART_LABEL)
|
||||
GRUB_MOD_FINI(search_part_label)
|
||||
#elif defined (DO_SEARCH_FS_UUID)
|
||||
GRUB_MOD_FINI(search_fs_uuid)
|
||||
#elif defined (DO_SEARCH_DISK_UUID)
|
||||
GRUB_MOD_FINI(search_disk_uuid)
|
||||
#else
|
||||
GRUB_MOD_FINI(search_label)
|
||||
#endif
|
||||
|
|
5
grub-core/commands/search_disk_uuid.c
Normal file
5
grub-core/commands/search_disk_uuid.c
Normal file
|
@ -0,0 +1,5 @@
|
|||
#define DO_SEARCH_DISK_UUID 1
|
||||
#define FUNC_NAME grub_search_disk_uuid
|
||||
#define COMMAND_NAME "search.disk_uuid"
|
||||
#define HELP_MESSAGE N_("Search devices by disk UUID. If VARIABLE is specified, the first device found is set to a variable.")
|
||||
#include "search.c"
|
5
grub-core/commands/search_part_label.c
Normal file
5
grub-core/commands/search_part_label.c
Normal file
|
@ -0,0 +1,5 @@
|
|||
#define DO_SEARCH_PART_LABEL 1
|
||||
#define FUNC_NAME grub_search_part_label
|
||||
#define COMMAND_NAME "search.part_label"
|
||||
#define HELP_MESSAGE N_("Search devices by partition label. If VARIABLE is specified, the first device found is set to a variable.")
|
||||
#include "search.c"
|
5
grub-core/commands/search_part_uuid.c
Normal file
5
grub-core/commands/search_part_uuid.c
Normal file
|
@ -0,0 +1,5 @@
|
|||
#define DO_SEARCH_PART_UUID 1
|
||||
#define FUNC_NAME grub_search_part_uuid
|
||||
#define COMMAND_NAME "search.part_uuid"
|
||||
#define HELP_MESSAGE N_("Search devices by partition UUID. If VARIABLE is specified, the first device found is set to a variable.")
|
||||
#include "search.c"
|
|
@ -36,6 +36,12 @@ static const struct grub_arg_option options[] =
|
|||
0, 0},
|
||||
{"fs-uuid", 'u', 0, N_("Search devices by a filesystem UUID."),
|
||||
0, 0},
|
||||
{"part-label", 'L', 0, N_("Search devices by a partition label."),
|
||||
0, 0},
|
||||
{"part-uuid", 'U', 0, N_("Search devices by a partition UUID."),
|
||||
0, 0},
|
||||
{"disk-uuid", 'U', 0, N_("Search devices by a disk UUID."),
|
||||
0, 0},
|
||||
{"set", 's', GRUB_ARG_OPTION_OPTIONAL,
|
||||
N_("Set a variable to the first device found."), N_("VARNAME"),
|
||||
ARG_TYPE_STRING},
|
||||
|
@ -71,6 +77,9 @@ enum options
|
|||
SEARCH_FILE,
|
||||
SEARCH_LABEL,
|
||||
SEARCH_FS_UUID,
|
||||
SEARCH_PART_LABEL,
|
||||
SEARCH_PART_UUID,
|
||||
SEARCH_DISK_UUID,
|
||||
SEARCH_SET,
|
||||
SEARCH_NO_FLOPPY,
|
||||
SEARCH_HINT,
|
||||
|
@ -186,6 +195,15 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
|
|||
else if (state[SEARCH_FS_UUID].set)
|
||||
grub_search_fs_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
|
||||
hints, nhints);
|
||||
else if (state[SEARCH_PART_LABEL].set)
|
||||
grub_search_part_label (id, var, state[SEARCH_NO_FLOPPY].set,
|
||||
hints, nhints);
|
||||
else if (state[SEARCH_PART_UUID].set)
|
||||
grub_search_part_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
|
||||
hints, nhints);
|
||||
else if (state[SEARCH_DISK_UUID].set)
|
||||
grub_search_disk_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
|
||||
hints, nhints);
|
||||
else if (state[SEARCH_FILE].set)
|
||||
grub_search_fs_file (id, var, state[SEARCH_NO_FLOPPY].set,
|
||||
hints, nhints);
|
||||
|
|
372
grub-core/commands/smbios.c
Normal file
372
grub-core/commands/smbios.c
Normal file
|
@ -0,0 +1,372 @@
|
|||
/* smbios.c - retrieve smbios information. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2013,2014,2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/smbios.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
||||
/* Locate the SMBIOS entry point structure depending on the hardware. */
|
||||
struct grub_smbios_eps *
|
||||
grub_smbios_get_eps (void)
|
||||
{
|
||||
static struct grub_smbios_eps *eps = NULL;
|
||||
if (eps != NULL)
|
||||
return eps;
|
||||
eps = grub_machine_smbios_get_eps ();
|
||||
return eps;
|
||||
}
|
||||
|
||||
/* Locate the SMBIOS3 entry point structure depending on the hardware. */
|
||||
struct grub_smbios_eps3 *
|
||||
grub_smbios_get_eps3 (void)
|
||||
{
|
||||
static struct grub_smbios_eps3 *eps = NULL;
|
||||
if (eps != NULL)
|
||||
return eps;
|
||||
eps = grub_machine_smbios_get_eps3 ();
|
||||
return eps;
|
||||
}
|
||||
|
||||
/* Abstract useful values found in either the SMBIOS3 or SMBIOS EPS. */
|
||||
static struct {
|
||||
grub_addr_t start;
|
||||
grub_addr_t end;
|
||||
grub_uint16_t structures;
|
||||
} table_desc = {0, 0, 0};
|
||||
|
||||
|
||||
/*
|
||||
* These functions convert values from the various SMBIOS structure field types
|
||||
* into a string formatted to be returned to the user. They expect that the
|
||||
* structure and offset were already validated. The given buffer stores the
|
||||
* newly formatted string if needed. When the requested data is successfully
|
||||
* retrieved and formatted, the pointer to the string is returned; otherwise,
|
||||
* NULL is returned on failure.
|
||||
*/
|
||||
|
||||
static const char *
|
||||
grub_smbios_format_byte (char *buffer, grub_size_t size,
|
||||
const grub_uint8_t *structure, grub_uint8_t offset)
|
||||
{
|
||||
grub_snprintf (buffer, size, "%u", structure[offset]);
|
||||
return (const char *)buffer;
|
||||
}
|
||||
|
||||
static const char *
|
||||
grub_smbios_format_word (char *buffer, grub_size_t size,
|
||||
const grub_uint8_t *structure, grub_uint8_t offset)
|
||||
{
|
||||
grub_uint16_t value = grub_get_unaligned16 (structure + offset);
|
||||
grub_snprintf (buffer, size, "%u", value);
|
||||
return (const char *)buffer;
|
||||
}
|
||||
|
||||
static const char *
|
||||
grub_smbios_format_dword (char *buffer, grub_size_t size,
|
||||
const grub_uint8_t *structure, grub_uint8_t offset)
|
||||
{
|
||||
grub_uint32_t value = grub_get_unaligned32 (structure + offset);
|
||||
grub_snprintf (buffer, size, "%" PRIuGRUB_UINT32_T, value);
|
||||
return (const char *)buffer;
|
||||
}
|
||||
|
||||
static const char *
|
||||
grub_smbios_format_qword (char *buffer, grub_size_t size,
|
||||
const grub_uint8_t *structure, grub_uint8_t offset)
|
||||
{
|
||||
grub_uint64_t value = grub_get_unaligned64 (structure + offset);
|
||||
grub_snprintf (buffer, size, "%" PRIuGRUB_UINT64_T, value);
|
||||
return (const char *)buffer;
|
||||
}
|
||||
|
||||
/* The matching string pointer is returned directly to avoid extra copying. */
|
||||
static const char *
|
||||
grub_smbios_get_string (char *buffer __attribute__ ((unused)),
|
||||
grub_size_t size __attribute__ ((unused)),
|
||||
const grub_uint8_t *structure, grub_uint8_t offset)
|
||||
{
|
||||
const grub_uint8_t *ptr = structure + structure[1];
|
||||
const grub_uint8_t *table_end = (const grub_uint8_t *)table_desc.end;
|
||||
const grub_uint8_t referenced_string_number = structure[offset];
|
||||
grub_uint8_t i;
|
||||
|
||||
/* A string referenced with zero is interpreted as unset. */
|
||||
if (referenced_string_number == 0)
|
||||
return NULL;
|
||||
|
||||
/* Search the string set. */
|
||||
for (i = 1; *ptr != 0 && ptr < table_end; i++)
|
||||
if (i == referenced_string_number)
|
||||
{
|
||||
const char *str = (const char *)ptr;
|
||||
while (*ptr++ != 0)
|
||||
if (ptr >= table_end)
|
||||
return NULL; /* The string isn't terminated. */
|
||||
return str;
|
||||
}
|
||||
else
|
||||
while (*ptr++ != 0 && ptr < table_end);
|
||||
|
||||
/* The string number is greater than the number of strings in the set. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
grub_smbios_format_uuid (char *buffer, grub_size_t size,
|
||||
const grub_uint8_t *structure, grub_uint8_t offset)
|
||||
{
|
||||
const grub_uint8_t *f = structure + offset; /* little-endian fields */
|
||||
const grub_uint8_t *g = f + 8; /* byte-by-byte fields */
|
||||
grub_snprintf (buffer, size,
|
||||
"%02x%02x%02x%02x-%02x%02x-%02x%02x-"
|
||||
"%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
f[3], f[2], f[1], f[0], f[5], f[4], f[7], f[6],
|
||||
g[0], g[1], g[2], g[3], g[4], g[5], g[6], g[7]);
|
||||
return (const char *)buffer;
|
||||
}
|
||||
|
||||
|
||||
/* List the field formatting functions and the number of bytes they need. */
|
||||
#define MAXIMUM_FORMAT_LENGTH (sizeof ("ffffffff-ffff-ffff-ffff-ffffffffffff"))
|
||||
static const struct {
|
||||
const char *(*format) (char *buffer, grub_size_t size,
|
||||
const grub_uint8_t *structure, grub_uint8_t offset);
|
||||
grub_uint8_t field_length;
|
||||
} field_extractors[] = {
|
||||
{grub_smbios_format_byte, 1},
|
||||
{grub_smbios_format_word, 2},
|
||||
{grub_smbios_format_dword, 4},
|
||||
{grub_smbios_format_qword, 8},
|
||||
{grub_smbios_get_string, 1},
|
||||
{grub_smbios_format_uuid, 16}
|
||||
};
|
||||
|
||||
/* List command options, with structure field getters ordered as above. */
|
||||
#define FIRST_GETTER_OPT (3)
|
||||
#define SETTER_OPT (FIRST_GETTER_OPT + ARRAY_SIZE(field_extractors))
|
||||
static const struct grub_arg_option options[] = {
|
||||
{"type", 't', 0, N_("Match entries with the given type."),
|
||||
N_("type"), ARG_TYPE_INT},
|
||||
{"handle", 'h', 0, N_("Match entries with the given handle."),
|
||||
N_("handle"), ARG_TYPE_INT},
|
||||
{"match", 'm', 0, N_("Select a structure when several match."),
|
||||
N_("match"), ARG_TYPE_INT},
|
||||
{"get-byte", 'b', 0, N_("Get the byte's value at the given offset."),
|
||||
N_("offset"), ARG_TYPE_INT},
|
||||
{"get-word", 'w', 0, N_("Get two bytes' value at the given offset."),
|
||||
N_("offset"), ARG_TYPE_INT},
|
||||
{"get-dword", 'd', 0, N_("Get four bytes' value at the given offset."),
|
||||
N_("offset"), ARG_TYPE_INT},
|
||||
{"get-qword", 'q', 0, N_("Get eight bytes' value at the given offset."),
|
||||
N_("offset"), ARG_TYPE_INT},
|
||||
{"get-string", 's', 0, N_("Get the string specified at the given offset."),
|
||||
N_("offset"), ARG_TYPE_INT},
|
||||
{"get-uuid", 'u', 0, N_("Get the UUID's value at the given offset."),
|
||||
N_("offset"), ARG_TYPE_INT},
|
||||
{"set", '\0', 0, N_("Store the value in the given variable name."),
|
||||
N_("variable"), ARG_TYPE_STRING},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Return a matching SMBIOS structure.
|
||||
*
|
||||
* This method can use up to three criteria for selecting a structure:
|
||||
* - The "type" field (use -1 to ignore)
|
||||
* - The "handle" field (use -1 to ignore)
|
||||
* - Which to return if several match (use 0 to ignore)
|
||||
*
|
||||
* The return value is a pointer to the first matching structure. If no
|
||||
* structures match the given parameters, NULL is returned.
|
||||
*/
|
||||
static const grub_uint8_t *
|
||||
grub_smbios_match_structure (const grub_int16_t type,
|
||||
const grub_int32_t handle,
|
||||
const grub_uint16_t match)
|
||||
{
|
||||
const grub_uint8_t *ptr = (const grub_uint8_t *)table_desc.start;
|
||||
const grub_uint8_t *table_end = (const grub_uint8_t *)table_desc.end;
|
||||
grub_uint16_t structures = table_desc.structures;
|
||||
grub_uint16_t structure_count = 0;
|
||||
grub_uint16_t matches = 0;
|
||||
|
||||
while (ptr < table_end
|
||||
&& ptr[1] >= 4 /* Valid structures include the 4-byte header. */
|
||||
&& (structure_count++ < structures || structures == 0))
|
||||
{
|
||||
grub_uint16_t structure_handle = grub_get_unaligned16 (ptr + 2);
|
||||
grub_uint8_t structure_type = ptr[0];
|
||||
|
||||
if ((handle < 0 || handle == structure_handle)
|
||||
&& (type < 0 || type == structure_type)
|
||||
&& (match == 0 || match == ++matches))
|
||||
return ptr;
|
||||
|
||||
else
|
||||
{
|
||||
ptr += ptr[1];
|
||||
while ((*ptr++ != 0 || *ptr++ != 0) && ptr < table_end);
|
||||
}
|
||||
|
||||
if (structure_type == GRUB_SMBIOS_TYPE_END_OF_TABLE)
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_smbios (grub_extcmd_context_t ctxt,
|
||||
int argc __attribute__ ((unused)),
|
||||
char **argv __attribute__ ((unused)))
|
||||
{
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
|
||||
grub_int16_t type = -1;
|
||||
grub_int32_t handle = -1;
|
||||
grub_uint16_t match = 0;
|
||||
grub_uint8_t offset = 0;
|
||||
|
||||
const grub_uint8_t *structure;
|
||||
const char *value;
|
||||
char buffer[MAXIMUM_FORMAT_LENGTH];
|
||||
grub_int32_t option;
|
||||
grub_int8_t field_type = -1;
|
||||
grub_uint8_t i;
|
||||
|
||||
if (table_desc.start == 0)
|
||||
return grub_error (GRUB_ERR_IO,
|
||||
N_("the SMBIOS entry point structure was not found"));
|
||||
|
||||
/* Read the given filtering options. */
|
||||
if (state[0].set)
|
||||
{
|
||||
option = grub_strtol (state[0].arg, NULL, 0);
|
||||
if (option < 0 || option > 255)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
N_("the type must be between 0 and 255"));
|
||||
type = (grub_int16_t)option;
|
||||
}
|
||||
if (state[1].set)
|
||||
{
|
||||
option = grub_strtol (state[1].arg, NULL, 0);
|
||||
if (option < 0 || option > 65535)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
N_("the handle must be between 0 and 65535"));
|
||||
handle = (grub_int32_t)option;
|
||||
}
|
||||
if (state[2].set)
|
||||
{
|
||||
option = grub_strtol (state[2].arg, NULL, 0);
|
||||
if (option <= 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
N_("the match must be a positive integer"));
|
||||
match = (grub_uint16_t)option;
|
||||
}
|
||||
|
||||
/* Determine the data type of the structure field to retrieve. */
|
||||
for (i = 0; i < ARRAY_SIZE(field_extractors); i++)
|
||||
if (state[FIRST_GETTER_OPT + i].set)
|
||||
{
|
||||
if (field_type >= 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
N_("only one --get option is usable at a time"));
|
||||
field_type = i;
|
||||
}
|
||||
|
||||
/* Require a choice of a structure field to return. */
|
||||
if (field_type < 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
N_("one of the --get options is required"));
|
||||
|
||||
/* Locate a matching SMBIOS structure. */
|
||||
structure = grub_smbios_match_structure (type, handle, match);
|
||||
if (structure == NULL)
|
||||
return grub_error (GRUB_ERR_IO,
|
||||
N_("no structure matched the given options"));
|
||||
|
||||
/* Ensure the requested byte offset is inside the structure. */
|
||||
option = grub_strtol (state[FIRST_GETTER_OPT + field_type].arg, NULL, 0);
|
||||
if (option < 0 || option >= structure[1])
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
N_("the given offset is outside the structure"));
|
||||
|
||||
/* Ensure the requested data type at the offset is inside the structure. */
|
||||
offset = (grub_uint8_t)option;
|
||||
if (offset + field_extractors[field_type].field_length > structure[1])
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
N_("the field ends outside the structure"));
|
||||
|
||||
/* Format the requested structure field into a readable string. */
|
||||
value = field_extractors[field_type].format (buffer, sizeof (buffer),
|
||||
structure, offset);
|
||||
if (value == NULL)
|
||||
return grub_error (GRUB_ERR_IO,
|
||||
N_("failed to retrieve the structure field"));
|
||||
|
||||
/* Store or print the formatted value. */
|
||||
if (state[SETTER_OPT].set)
|
||||
grub_env_set (state[SETTER_OPT].arg, value);
|
||||
else
|
||||
grub_printf ("%s\n", value);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
static grub_extcmd_t cmd;
|
||||
|
||||
GRUB_MOD_INIT(smbios)
|
||||
{
|
||||
struct grub_smbios_eps3 *eps3;
|
||||
struct grub_smbios_eps *eps;
|
||||
|
||||
if ((eps3 = grub_smbios_get_eps3 ()))
|
||||
{
|
||||
table_desc.start = (grub_addr_t)eps3->table_address;
|
||||
table_desc.end = table_desc.start + eps3->maximum_table_length;
|
||||
table_desc.structures = 0; /* SMBIOS3 drops the structure count. */
|
||||
}
|
||||
else if ((eps = grub_smbios_get_eps ()))
|
||||
{
|
||||
table_desc.start = (grub_addr_t)eps->intermediate.table_address;
|
||||
table_desc.end = table_desc.start + eps->intermediate.table_length;
|
||||
table_desc.structures = eps->intermediate.structures;
|
||||
}
|
||||
|
||||
cmd = grub_register_extcmd ("smbios", grub_cmd_smbios, 0,
|
||||
N_("[-t type] [-h handle] [-m match] "
|
||||
"(-b|-w|-d|-q|-s|-u) offset "
|
||||
"[--set variable]"),
|
||||
N_("Retrieve SMBIOS information."), options);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(smbios)
|
||||
{
|
||||
grub_unregister_extcmd (cmd);
|
||||
}
|
|
@ -278,10 +278,14 @@ grub_biosdisk_call_hook (grub_disk_dev_iterate_hook_t hook, void *hook_data,
|
|||
char name[10];
|
||||
|
||||
if (cd_drive && drive == cd_drive)
|
||||
return hook ("cd", hook_data);
|
||||
{
|
||||
grub_dprintf ("biosdisk", "iterating cd\n");
|
||||
return hook ("cd", hook_data);
|
||||
}
|
||||
|
||||
grub_snprintf (name, sizeof (name),
|
||||
(drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80));
|
||||
grub_dprintf ("biosdisk", "iterating %s\n", name);
|
||||
return hook (name, hook_data);
|
||||
}
|
||||
|
||||
|
@ -301,7 +305,7 @@ grub_biosdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
|
|||
if (grub_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1,
|
||||
GRUB_MEMORY_MACHINE_SCRATCH_SEG) != 0)
|
||||
{
|
||||
grub_dprintf ("disk", "Read error when probing drive 0x%2x\n", drive);
|
||||
grub_dprintf ("biosdisk", "Read error when probing drive 0x%2x\n", drive);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -336,6 +340,8 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
|
|||
int drive;
|
||||
struct grub_biosdisk_data *data;
|
||||
|
||||
grub_dprintf ("biosdisk", "opening %s\n", name);
|
||||
|
||||
drive = grub_biosdisk_get_drive (name);
|
||||
if (drive < 0)
|
||||
return grub_errno;
|
||||
|
@ -393,6 +399,11 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
|
|||
(1 << disk->log_sector_size) < drp->bytes_per_sector;
|
||||
disk->log_sector_size++);
|
||||
}
|
||||
|
||||
grub_dprintf ("biosdisk",
|
||||
"LBA total = 0x%llx block size = 0x%lx\n",
|
||||
(unsigned long long) total_sectors,
|
||||
1L << disk->log_sector_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -428,6 +439,9 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
|
|||
if (! total_sectors)
|
||||
total_sectors = ((grub_uint64_t) data->cylinders)
|
||||
* data->heads * data->sectors;
|
||||
|
||||
grub_dprintf ("biosdisk", "C/H/S %lu/%lu/%lu\n",
|
||||
data->cylinders, data->heads, data->sectors);
|
||||
}
|
||||
|
||||
disk->total_sectors = total_sectors;
|
||||
|
@ -440,12 +454,15 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
|
|||
|
||||
disk->data = data;
|
||||
|
||||
grub_dprintf ("biosdisk", "opening %s succeeded\n", name);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_biosdisk_close (grub_disk_t disk)
|
||||
{
|
||||
grub_dprintf ("biosdisk", "closing %s\n", disk->name);
|
||||
grub_free (disk->data);
|
||||
}
|
||||
|
||||
|
@ -577,6 +594,9 @@ static grub_err_t
|
|||
grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
|
||||
grub_size_t size, char *buf)
|
||||
{
|
||||
grub_dprintf ("biosdisk", "reading 0x%lx sectors at 0x%llx from %s\n",
|
||||
(unsigned long) size, (unsigned long long) sector, disk->name);
|
||||
|
||||
while (size)
|
||||
{
|
||||
grub_size_t len;
|
||||
|
@ -607,6 +627,9 @@ grub_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
|
|||
{
|
||||
struct grub_biosdisk_data *data = disk->data;
|
||||
|
||||
grub_dprintf ("biosdisk", "writing 0x%lx sectors at 0x%llx to %s\n",
|
||||
(unsigned long) size, (unsigned long long) sector, disk->name);
|
||||
|
||||
if (data->flags & GRUB_BIOSDISK_FLAG_CDROM)
|
||||
return grub_error (GRUB_ERR_IO, N_("cannot write to CD-ROM"));
|
||||
|
||||
|
|
|
@ -22,18 +22,22 @@
|
|||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/acpi.h>
|
||||
#include <grub/smbios.h>
|
||||
|
||||
grub_err_t
|
||||
grub_machine_efiemu_init_tables (void)
|
||||
{
|
||||
grub_uint8_t *ptr;
|
||||
void *table;
|
||||
grub_err_t err;
|
||||
grub_efi_guid_t smbios = GRUB_EFI_SMBIOS_TABLE_GUID;
|
||||
grub_efi_guid_t smbios3 = GRUB_EFI_SMBIOS3_TABLE_GUID;
|
||||
grub_efi_guid_t acpi20 = GRUB_EFI_ACPI_20_TABLE_GUID;
|
||||
grub_efi_guid_t acpi = GRUB_EFI_ACPI_TABLE_GUID;
|
||||
|
||||
err = grub_efiemu_unregister_configuration_table (smbios);
|
||||
if (err)
|
||||
return err;
|
||||
err = grub_efiemu_unregister_configuration_table (smbios3);
|
||||
if (err)
|
||||
return err;
|
||||
err = grub_efiemu_unregister_configuration_table (acpi);
|
||||
|
@ -43,6 +47,20 @@ grub_machine_efiemu_init_tables (void)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
table = grub_smbios_get_eps ();
|
||||
if (table)
|
||||
{
|
||||
err = grub_efiemu_register_configuration_table (smbios, 0, 0, table);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
table = grub_smbios_get_eps3 ();
|
||||
if (table)
|
||||
{
|
||||
err = grub_efiemu_register_configuration_table (smbios3, 0, 0, table);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
table = grub_acpi_get_rsdpv1 ();
|
||||
if (table)
|
||||
{
|
||||
|
@ -58,19 +76,5 @@ grub_machine_efiemu_init_tables (void)
|
|||
return err;
|
||||
}
|
||||
|
||||
for (ptr = (grub_uint8_t *) 0xf0000; ptr < (grub_uint8_t *) 0x100000;
|
||||
ptr += 16)
|
||||
if (grub_memcmp (ptr, "_SM_", 4) == 0
|
||||
&& grub_byte_checksum (ptr, *(ptr + 5)) == 0)
|
||||
break;
|
||||
|
||||
if (ptr < (grub_uint8_t *) 0x100000)
|
||||
{
|
||||
grub_dprintf ("efiemu", "Registering SMBIOS\n");
|
||||
err = grub_efiemu_register_configuration_table (smbios, 0, 0, ptr);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
|
|
@ -32,12 +32,21 @@
|
|||
#include <grub/env.h>
|
||||
#include <grub/cache.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/tpm.h>
|
||||
|
||||
/* Platforms where modules are in a readonly area of memory. */
|
||||
#if defined(GRUB_MACHINE_QEMU)
|
||||
#define GRUB_MODULES_MACHINE_READONLY
|
||||
#endif
|
||||
|
||||
#ifdef GRUB_MACHINE_EMU
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#ifdef GRUB_MACHINE_EFI
|
||||
#include <grub/efi/efi.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
|
@ -686,6 +695,15 @@ grub_dl_load_file (const char *filename)
|
|||
void *core = 0;
|
||||
grub_dl_t mod = 0;
|
||||
|
||||
#ifdef GRUB_MACHINE_EFI
|
||||
if (grub_efi_secure_boot ())
|
||||
{
|
||||
grub_error (GRUB_ERR_ACCESS_DENIED,
|
||||
"Secure Boot forbids loading module from %s", filename);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
grub_boot_time ("Loading module %s", filename);
|
||||
|
||||
file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE);
|
||||
|
@ -712,6 +730,9 @@ grub_dl_load_file (const char *filename)
|
|||
opens of the same device. */
|
||||
grub_file_close (file);
|
||||
|
||||
grub_tpm_measure(core, size, GRUB_BINARY_PCR, filename);
|
||||
grub_print_error();
|
||||
|
||||
mod = grub_dl_load_core (core, size);
|
||||
grub_free (core);
|
||||
if (! mod)
|
||||
|
|
|
@ -273,6 +273,34 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
grub_efi_boolean_t
|
||||
grub_efi_secure_boot (void)
|
||||
{
|
||||
grub_efi_guid_t efi_var_guid = GRUB_EFI_GLOBAL_VARIABLE_GUID;
|
||||
grub_size_t datasize;
|
||||
char *secure_boot = NULL;
|
||||
char *setup_mode = NULL;
|
||||
grub_efi_boolean_t ret = 0;
|
||||
|
||||
secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize);
|
||||
|
||||
if (datasize != 1 || !secure_boot)
|
||||
goto out;
|
||||
|
||||
setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize);
|
||||
|
||||
if (datasize != 1 || !setup_mode)
|
||||
goto out;
|
||||
|
||||
if (*secure_boot && !*setup_mode)
|
||||
ret = 1;
|
||||
|
||||
out:
|
||||
grub_free (secure_boot);
|
||||
grub_free (setup_mode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
|
||||
/* Search the mods section from the PE32/PE32+ image. This code uses
|
||||
|
|
|
@ -49,6 +49,38 @@ static grub_efi_uintn_t finish_desc_size;
|
|||
static grub_efi_uint32_t finish_desc_version;
|
||||
int grub_efi_is_finished = 0;
|
||||
|
||||
/* Allocate pages below a specified address */
|
||||
void *
|
||||
grub_efi_allocate_pages_max (grub_efi_physical_address_t max,
|
||||
grub_efi_uintn_t pages)
|
||||
{
|
||||
grub_efi_status_t status;
|
||||
grub_efi_boot_services_t *b;
|
||||
grub_efi_physical_address_t address = max;
|
||||
|
||||
if (max > 0xffffffff)
|
||||
return 0;
|
||||
|
||||
b = grub_efi_system_table->boot_services;
|
||||
status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address);
|
||||
|
||||
if (status != GRUB_EFI_SUCCESS)
|
||||
return 0;
|
||||
|
||||
if (address == 0)
|
||||
{
|
||||
/* Uggh, the address 0 was allocated... This is too annoying,
|
||||
so reallocate another one. */
|
||||
address = max;
|
||||
status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address);
|
||||
grub_efi_free_pages (0, pages);
|
||||
if (status != GRUB_EFI_SUCCESS)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (void *) ((grub_addr_t) address);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to roll back EFI allocations on exit. Remember allocations that
|
||||
* we'll free on exit.
|
||||
|
|
273
grub-core/kern/efi/tpm.c
Normal file
273
grub-core/kern/efi/tpm.c
Normal file
|
@ -0,0 +1,273 @@
|
|||
#include <grub/err.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/efi/api.h>
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/efi/tpm.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/tpm.h>
|
||||
#include <grub/term.h>
|
||||
|
||||
static grub_efi_guid_t tpm_guid = EFI_TPM_GUID;
|
||||
static grub_efi_guid_t tpm2_guid = EFI_TPM2_GUID;
|
||||
|
||||
static grub_efi_boolean_t grub_tpm_present(grub_efi_tpm_protocol_t *tpm)
|
||||
{
|
||||
grub_efi_status_t status;
|
||||
TCG_EFI_BOOT_SERVICE_CAPABILITY caps;
|
||||
grub_uint32_t flags;
|
||||
grub_efi_physical_address_t eventlog, lastevent;
|
||||
|
||||
caps.Size = (grub_uint8_t)sizeof(caps);
|
||||
|
||||
status = efi_call_5(tpm->status_check, tpm, &caps, &flags, &eventlog,
|
||||
&lastevent);
|
||||
|
||||
if (status != GRUB_EFI_SUCCESS || caps.TPMDeactivatedFlag
|
||||
|| !caps.TPMPresentFlag)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static grub_efi_boolean_t grub_tpm2_present(grub_efi_tpm2_protocol_t *tpm)
|
||||
{
|
||||
grub_efi_status_t status;
|
||||
EFI_TCG2_BOOT_SERVICE_CAPABILITY caps;
|
||||
|
||||
caps.Size = (grub_uint8_t)sizeof(caps);
|
||||
|
||||
status = efi_call_2(tpm->get_capability, tpm, &caps);
|
||||
|
||||
if (status != GRUB_EFI_SUCCESS || !caps.TPMPresentFlag)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static grub_efi_boolean_t grub_tpm_handle_find(grub_efi_handle_t *tpm_handle,
|
||||
grub_efi_uint8_t *protocol_version)
|
||||
{
|
||||
grub_efi_handle_t *handles;
|
||||
grub_efi_uintn_t num_handles;
|
||||
|
||||
handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &tpm_guid, NULL,
|
||||
&num_handles);
|
||||
if (handles && num_handles > 0) {
|
||||
*tpm_handle = handles[0];
|
||||
*protocol_version = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &tpm2_guid, NULL,
|
||||
&num_handles);
|
||||
if (handles && num_handles > 0) {
|
||||
*tpm_handle = handles[0];
|
||||
*protocol_version = 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_tpm1_execute(grub_efi_handle_t tpm_handle,
|
||||
PassThroughToTPM_InputParamBlock *inbuf,
|
||||
PassThroughToTPM_OutputParamBlock *outbuf)
|
||||
{
|
||||
grub_efi_status_t status;
|
||||
grub_efi_tpm_protocol_t *tpm;
|
||||
grub_uint32_t inhdrsize = sizeof(*inbuf) - sizeof(inbuf->TPMOperandIn);
|
||||
grub_uint32_t outhdrsize = sizeof(*outbuf) - sizeof(outbuf->TPMOperandOut);
|
||||
|
||||
tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid,
|
||||
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
|
||||
if (!grub_tpm_present(tpm))
|
||||
return 0;
|
||||
|
||||
/* UEFI TPM protocol takes the raw operand block, no param block header */
|
||||
status = efi_call_5 (tpm->pass_through_to_tpm, tpm,
|
||||
inbuf->IPBLength - inhdrsize, inbuf->TPMOperandIn,
|
||||
outbuf->OPBLength - outhdrsize, outbuf->TPMOperandOut);
|
||||
|
||||
switch (status) {
|
||||
case GRUB_EFI_SUCCESS:
|
||||
return 0;
|
||||
case GRUB_EFI_DEVICE_ERROR:
|
||||
return grub_error (GRUB_ERR_IO, N_("Command failed"));
|
||||
case GRUB_EFI_INVALID_PARAMETER:
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter"));
|
||||
case GRUB_EFI_BUFFER_TOO_SMALL:
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small"));
|
||||
case GRUB_EFI_NOT_FOUND:
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable"));
|
||||
default:
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error"));
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_tpm2_execute(grub_efi_handle_t tpm_handle,
|
||||
PassThroughToTPM_InputParamBlock *inbuf,
|
||||
PassThroughToTPM_OutputParamBlock *outbuf)
|
||||
{
|
||||
grub_efi_status_t status;
|
||||
grub_efi_tpm2_protocol_t *tpm;
|
||||
grub_uint32_t inhdrsize = sizeof(*inbuf) - sizeof(inbuf->TPMOperandIn);
|
||||
grub_uint32_t outhdrsize = sizeof(*outbuf) - sizeof(outbuf->TPMOperandOut);
|
||||
|
||||
tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid,
|
||||
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
|
||||
if (!grub_tpm2_present(tpm))
|
||||
return 0;
|
||||
|
||||
/* UEFI TPM protocol takes the raw operand block, no param block header */
|
||||
status = efi_call_5 (tpm->submit_command, tpm,
|
||||
inbuf->IPBLength - inhdrsize, inbuf->TPMOperandIn,
|
||||
outbuf->OPBLength - outhdrsize, outbuf->TPMOperandOut);
|
||||
|
||||
switch (status) {
|
||||
case GRUB_EFI_SUCCESS:
|
||||
return 0;
|
||||
case GRUB_EFI_DEVICE_ERROR:
|
||||
return grub_error (GRUB_ERR_IO, N_("Command failed"));
|
||||
case GRUB_EFI_INVALID_PARAMETER:
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter"));
|
||||
case GRUB_EFI_BUFFER_TOO_SMALL:
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small"));
|
||||
case GRUB_EFI_NOT_FOUND:
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable"));
|
||||
default:
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error"));
|
||||
}
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
|
||||
PassThroughToTPM_OutputParamBlock *outbuf)
|
||||
{
|
||||
grub_efi_handle_t tpm_handle;
|
||||
grub_uint8_t protocol_version;
|
||||
|
||||
/* It's not a hard failure for there to be no TPM */
|
||||
if (!grub_tpm_handle_find(&tpm_handle, &protocol_version))
|
||||
return 0;
|
||||
|
||||
if (protocol_version == 1) {
|
||||
return grub_tpm1_execute(tpm_handle, inbuf, outbuf);
|
||||
} else {
|
||||
return grub_tpm2_execute(tpm_handle, inbuf, outbuf);
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_tpm1_log_event(grub_efi_handle_t tpm_handle, unsigned char *buf,
|
||||
grub_size_t size, grub_uint8_t pcr,
|
||||
const char *description)
|
||||
{
|
||||
TCG_PCR_EVENT *event;
|
||||
grub_efi_status_t status;
|
||||
grub_efi_tpm_protocol_t *tpm;
|
||||
grub_efi_physical_address_t lastevent;
|
||||
grub_uint32_t algorithm;
|
||||
grub_uint32_t eventnum = 0;
|
||||
|
||||
tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid,
|
||||
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
|
||||
if (!grub_tpm_present(tpm))
|
||||
return 0;
|
||||
|
||||
event = grub_zalloc(sizeof (TCG_PCR_EVENT) + grub_strlen(description) + 1);
|
||||
if (!event)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
N_("cannot allocate TPM event buffer"));
|
||||
|
||||
event->PCRIndex = pcr;
|
||||
event->EventType = EV_IPL;
|
||||
event->EventSize = grub_strlen(description) + 1;
|
||||
grub_memcpy(event->Event, description, event->EventSize);
|
||||
|
||||
algorithm = TCG_ALG_SHA;
|
||||
status = efi_call_7 (tpm->log_extend_event, tpm, (grub_efi_physical_address_t)buf, (grub_uint64_t) size,
|
||||
algorithm, event, &eventnum, &lastevent);
|
||||
|
||||
switch (status) {
|
||||
case GRUB_EFI_SUCCESS:
|
||||
return 0;
|
||||
case GRUB_EFI_DEVICE_ERROR:
|
||||
return grub_error (GRUB_ERR_IO, N_("Command failed"));
|
||||
case GRUB_EFI_INVALID_PARAMETER:
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter"));
|
||||
case GRUB_EFI_BUFFER_TOO_SMALL:
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small"));
|
||||
case GRUB_EFI_NOT_FOUND:
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable"));
|
||||
default:
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error"));
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_tpm2_log_event(grub_efi_handle_t tpm_handle, unsigned char *buf,
|
||||
grub_size_t size, grub_uint8_t pcr,
|
||||
const char *description)
|
||||
{
|
||||
EFI_TCG2_EVENT *event;
|
||||
grub_efi_status_t status;
|
||||
grub_efi_tpm2_protocol_t *tpm;
|
||||
|
||||
tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid,
|
||||
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
|
||||
if (!grub_tpm2_present(tpm))
|
||||
return 0;
|
||||
|
||||
event = grub_zalloc(sizeof (EFI_TCG2_EVENT) + grub_strlen(description) + 1);
|
||||
if (!event)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
N_("cannot allocate TPM event buffer"));
|
||||
|
||||
event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER);
|
||||
event->Header.HeaderVersion = 1;
|
||||
event->Header.PCRIndex = pcr;
|
||||
event->Header.EventType = EV_IPL;
|
||||
event->Size = sizeof(*event) - sizeof(event->Event) + grub_strlen(description) + 1;
|
||||
grub_memcpy(event->Event, description, grub_strlen(description) + 1);
|
||||
|
||||
status = efi_call_5 (tpm->hash_log_extend_event, tpm, 0, (grub_efi_physical_address_t)buf,
|
||||
(grub_uint64_t) size, event);
|
||||
|
||||
switch (status) {
|
||||
case GRUB_EFI_SUCCESS:
|
||||
return 0;
|
||||
case GRUB_EFI_DEVICE_ERROR:
|
||||
return grub_error (GRUB_ERR_IO, N_("Command failed"));
|
||||
case GRUB_EFI_INVALID_PARAMETER:
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter"));
|
||||
case GRUB_EFI_BUFFER_TOO_SMALL:
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small"));
|
||||
case GRUB_EFI_NOT_FOUND:
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable"));
|
||||
default:
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error"));
|
||||
}
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_tpm_log_event(unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
|
||||
const char *description)
|
||||
{
|
||||
grub_efi_handle_t tpm_handle;
|
||||
grub_efi_uint8_t protocol_version;
|
||||
|
||||
if (!grub_tpm_handle_find(&tpm_handle, &protocol_version))
|
||||
return 0;
|
||||
|
||||
if (protocol_version == 1) {
|
||||
return grub_tpm1_log_event(tpm_handle, buf, size, pcr, description);
|
||||
} else {
|
||||
return grub_tpm2_log_event(tpm_handle, buf, size, pcr, description);
|
||||
}
|
||||
}
|
145
grub-core/kern/i386/pc/tpm.c
Normal file
145
grub-core/kern/i386/pc/tpm.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
#include <grub/err.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/tpm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/i386/pc/int.h>
|
||||
|
||||
#define TCPA_MAGIC 0x41504354
|
||||
|
||||
static int tpm_presence = -1;
|
||||
|
||||
int tpm_present(void);
|
||||
|
||||
int tpm_present(void)
|
||||
{
|
||||
struct grub_bios_int_registers regs;
|
||||
|
||||
if (tpm_presence != -1)
|
||||
return tpm_presence;
|
||||
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
|
||||
regs.eax = 0xbb00;
|
||||
regs.ebx = TCPA_MAGIC;
|
||||
grub_bios_interrupt (0x1a, ®s);
|
||||
|
||||
if (regs.eax == 0)
|
||||
tpm_presence = 1;
|
||||
else
|
||||
tpm_presence = 0;
|
||||
|
||||
return tpm_presence;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
|
||||
PassThroughToTPM_OutputParamBlock *outbuf)
|
||||
{
|
||||
struct grub_bios_int_registers regs;
|
||||
grub_addr_t inaddr, outaddr;
|
||||
|
||||
if (!tpm_present())
|
||||
return 0;
|
||||
|
||||
inaddr = (grub_addr_t) inbuf;
|
||||
outaddr = (grub_addr_t) outbuf;
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
|
||||
regs.eax = 0xbb02;
|
||||
regs.ebx = TCPA_MAGIC;
|
||||
regs.ecx = 0;
|
||||
regs.edx = 0;
|
||||
regs.es = (inaddr & 0xffff0000) >> 4;
|
||||
regs.edi = inaddr & 0xffff;
|
||||
regs.ds = outaddr >> 4;
|
||||
regs.esi = outaddr & 0xf;
|
||||
|
||||
grub_bios_interrupt (0x1a, ®s);
|
||||
|
||||
if (regs.eax)
|
||||
{
|
||||
tpm_presence = 0;
|
||||
return grub_error (GRUB_ERR_IO, N_("TPM error %x, disabling TPM"), regs.eax);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
grub_uint32_t pcrindex;
|
||||
grub_uint32_t eventtype;
|
||||
grub_uint8_t digest[20];
|
||||
grub_uint32_t eventdatasize;
|
||||
grub_uint8_t event[0];
|
||||
} GRUB_PACKED Event;
|
||||
|
||||
typedef struct {
|
||||
grub_uint16_t ipblength;
|
||||
grub_uint16_t reserved;
|
||||
grub_uint32_t hashdataptr;
|
||||
grub_uint32_t hashdatalen;
|
||||
grub_uint32_t pcr;
|
||||
grub_uint32_t reserved2;
|
||||
grub_uint32_t logdataptr;
|
||||
grub_uint32_t logdatalen;
|
||||
} GRUB_PACKED EventIncoming;
|
||||
|
||||
typedef struct {
|
||||
grub_uint16_t opblength;
|
||||
grub_uint16_t reserved;
|
||||
grub_uint32_t eventnum;
|
||||
grub_uint8_t hashvalue[20];
|
||||
} GRUB_PACKED EventOutgoing;
|
||||
|
||||
grub_err_t
|
||||
grub_tpm_log_event(unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
|
||||
const char *description)
|
||||
{
|
||||
struct grub_bios_int_registers regs;
|
||||
EventIncoming incoming;
|
||||
EventOutgoing outgoing;
|
||||
Event *event;
|
||||
grub_uint32_t datalength;
|
||||
|
||||
if (!tpm_present())
|
||||
return 0;
|
||||
|
||||
datalength = grub_strlen(description);
|
||||
event = grub_zalloc(datalength + sizeof(Event));
|
||||
if (!event)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
N_("cannot allocate TPM event buffer"));
|
||||
|
||||
event->pcrindex = pcr;
|
||||
event->eventtype = 0x0d;
|
||||
event->eventdatasize = grub_strlen(description);
|
||||
grub_memcpy(event->event, description, datalength);
|
||||
|
||||
incoming.ipblength = sizeof(incoming);
|
||||
incoming.hashdataptr = (grub_uint32_t)buf;
|
||||
incoming.hashdatalen = size;
|
||||
incoming.pcr = pcr;
|
||||
incoming.logdataptr = (grub_uint32_t)event;
|
||||
incoming.logdatalen = datalength + sizeof(Event);
|
||||
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
|
||||
regs.eax = 0xbb01;
|
||||
regs.ebx = TCPA_MAGIC;
|
||||
regs.ecx = 0;
|
||||
regs.edx = 0;
|
||||
regs.es = (((grub_addr_t) &incoming) & 0xffff0000) >> 4;
|
||||
regs.edi = ((grub_addr_t) &incoming) & 0xffff;
|
||||
regs.ds = (((grub_addr_t) &outgoing) & 0xffff0000) >> 4;
|
||||
regs.esi = ((grub_addr_t) &outgoing) & 0xffff;
|
||||
|
||||
grub_bios_interrupt (0x1a, ®s);
|
||||
|
||||
grub_free(event);
|
||||
|
||||
if (regs.eax)
|
||||
{
|
||||
tpm_presence = 0;
|
||||
return grub_error (GRUB_ERR_IO, N_("TPM error %x, disabling TPM"), regs.eax);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -131,6 +131,9 @@ grub_set_prefix_and_root (void)
|
|||
{
|
||||
char *cmdpath;
|
||||
|
||||
grub_env_set ("cmddevice", fwdevice);
|
||||
grub_env_export ("cmddevice");
|
||||
|
||||
cmdpath = grub_xasprintf ("(%s)%s", fwdevice, fwpath ? : "");
|
||||
if (cmdpath)
|
||||
{
|
||||
|
|
14
grub-core/kern/tpm.c
Normal file
14
grub-core/kern/tpm.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include <grub/err.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/tpm.h>
|
||||
#include <grub/term.h>
|
||||
|
||||
grub_err_t
|
||||
grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
|
||||
const char *description)
|
||||
{
|
||||
return grub_tpm_log_event (buf, size, pcr, description);
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <grub/lib/cmdline.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/tpm.h>
|
||||
|
||||
static unsigned int check_arg (char *c, int *has_space)
|
||||
{
|
||||
|
|
777
grub-core/lib/gpt.c
Normal file
777
grub-core/lib/gpt.c
Normal file
|
@ -0,0 +1,777 @@
|
|||
/* gpt.c - Read/Verify/Write GUID Partition Tables (GPT). */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,2005,2006,2007,2008 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2014 CoreOS, 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/charset.h>
|
||||
#include <grub/crypto.h>
|
||||
#include <grub/device.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/msdos_partition.h>
|
||||
#include <grub/gpt_partition.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static grub_uint8_t grub_gpt_magic[] = GRUB_GPT_HEADER_MAGIC;
|
||||
|
||||
static grub_err_t
|
||||
grub_gpt_read_entries (grub_disk_t disk, grub_gpt_t gpt,
|
||||
struct grub_gpt_header *header,
|
||||
void **ret_entries,
|
||||
grub_size_t *ret_entries_size);
|
||||
|
||||
char *
|
||||
grub_gpt_guid_to_str (grub_gpt_part_guid_t *guid)
|
||||
{
|
||||
return grub_xasprintf ("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
grub_le_to_cpu32 (guid->data1),
|
||||
grub_le_to_cpu16 (guid->data2),
|
||||
grub_le_to_cpu16 (guid->data3),
|
||||
guid->data4[0], guid->data4[1],
|
||||
guid->data4[2], guid->data4[3],
|
||||
guid->data4[4], guid->data4[5],
|
||||
guid->data4[6], guid->data4[7]);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_gpt_device_partentry (grub_device_t device,
|
||||
struct grub_gpt_partentry *entry)
|
||||
{
|
||||
grub_disk_t disk = device->disk;
|
||||
grub_partition_t p;
|
||||
grub_err_t err;
|
||||
|
||||
if (!disk || !disk->partition)
|
||||
return grub_error (GRUB_ERR_BUG, "not a partition");
|
||||
|
||||
if (grub_strcmp (disk->partition->partmap->name, "gpt"))
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a GPT partition");
|
||||
|
||||
p = disk->partition;
|
||||
disk->partition = p->parent;
|
||||
err = grub_disk_read (disk, p->offset, p->index, sizeof (*entry), entry);
|
||||
disk->partition = p;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_gpt_part_label (grub_device_t device, char **label)
|
||||
{
|
||||
struct grub_gpt_partentry entry;
|
||||
const grub_size_t name_len = ARRAY_SIZE (entry.name);
|
||||
const grub_size_t label_len = name_len * GRUB_MAX_UTF8_PER_UTF16 + 1;
|
||||
grub_size_t i;
|
||||
grub_uint8_t *end;
|
||||
|
||||
if (grub_gpt_device_partentry (device, &entry))
|
||||
return grub_errno;
|
||||
|
||||
*label = grub_malloc (label_len);
|
||||
if (!*label)
|
||||
return grub_errno;
|
||||
|
||||
for (i = 0; i < name_len; i++)
|
||||
entry.name[i] = grub_le_to_cpu16 (entry.name[i]);
|
||||
|
||||
end = grub_utf16_to_utf8 ((grub_uint8_t *) *label, entry.name, name_len);
|
||||
*end = '\0';
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_gpt_part_uuid (grub_device_t device, char **uuid)
|
||||
{
|
||||
struct grub_gpt_partentry entry;
|
||||
|
||||
if (grub_gpt_device_partentry (device, &entry))
|
||||
return grub_errno;
|
||||
|
||||
*uuid = grub_gpt_guid_to_str (&entry.guid);
|
||||
if (!*uuid)
|
||||
return grub_errno;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static struct grub_gpt_header *
|
||||
grub_gpt_get_header (grub_gpt_t gpt)
|
||||
{
|
||||
if (gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID)
|
||||
return &gpt->primary;
|
||||
else if (gpt->status & GRUB_GPT_BACKUP_HEADER_VALID)
|
||||
return &gpt->backup;
|
||||
|
||||
grub_error (GRUB_ERR_BUG, "No valid GPT header");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_gpt_disk_uuid (grub_device_t device, char **uuid)
|
||||
{
|
||||
struct grub_gpt_header *header;
|
||||
|
||||
grub_gpt_t gpt = grub_gpt_read (device->disk);
|
||||
if (!gpt)
|
||||
goto done;
|
||||
|
||||
header = grub_gpt_get_header (gpt);
|
||||
if (!header)
|
||||
goto done;
|
||||
|
||||
*uuid = grub_gpt_guid_to_str (&header->guid);
|
||||
|
||||
done:
|
||||
grub_gpt_free (gpt);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_uint64_t
|
||||
grub_gpt_size_to_sectors (grub_gpt_t gpt, grub_size_t size)
|
||||
{
|
||||
unsigned int sector_size;
|
||||
grub_uint64_t sectors;
|
||||
|
||||
sector_size = 1U << gpt->log_sector_size;
|
||||
sectors = size / sector_size;
|
||||
if (size % sector_size)
|
||||
sectors++;
|
||||
|
||||
return sectors;
|
||||
}
|
||||
|
||||
/* Copied from grub-core/kern/disk_common.c grub_disk_adjust_range so we can
|
||||
* avoid attempting to use disk->total_sectors when GRUB won't let us.
|
||||
* TODO: Why is disk->total_sectors not set to GRUB_DISK_SIZE_UNKNOWN? */
|
||||
static int
|
||||
grub_gpt_disk_size_valid (grub_disk_t disk)
|
||||
{
|
||||
grub_disk_addr_t total_sectors;
|
||||
|
||||
/* Transform total_sectors to number of 512B blocks. */
|
||||
total_sectors = disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
|
||||
|
||||
/* Some drivers have problems with disks above reasonable.
|
||||
Treat unknown as 1EiB disk. While on it, clamp the size to 1EiB.
|
||||
Just one condition is enough since GRUB_DISK_UNKNOWN_SIZE << ls is always
|
||||
above 9EiB.
|
||||
*/
|
||||
if (total_sectors > (1ULL << 51))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_gpt_lecrc32 (grub_uint32_t *crc, const void *data, grub_size_t len)
|
||||
{
|
||||
grub_uint32_t crc32_val;
|
||||
|
||||
grub_crypto_hash (GRUB_MD_CRC32, &crc32_val, data, len);
|
||||
|
||||
/* GRUB_MD_CRC32 always uses big endian, gpt is always little. */
|
||||
*crc = grub_swap_bytes32 (crc32_val);
|
||||
}
|
||||
|
||||
static void
|
||||
grub_gpt_header_lecrc32 (grub_uint32_t *crc, struct grub_gpt_header *header)
|
||||
{
|
||||
grub_uint32_t old, new;
|
||||
|
||||
/* crc32 must be computed with the field cleared. */
|
||||
old = header->crc32;
|
||||
header->crc32 = 0;
|
||||
grub_gpt_lecrc32 (&new, header, sizeof (*header));
|
||||
header->crc32 = old;
|
||||
|
||||
*crc = new;
|
||||
}
|
||||
|
||||
/* Make sure the MBR is a protective MBR and not a normal MBR. */
|
||||
grub_err_t
|
||||
grub_gpt_pmbr_check (struct grub_msdos_partition_mbr *mbr)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (mbr->signature !=
|
||||
grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE))
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid MBR signature");
|
||||
|
||||
for (i = 0; i < sizeof (mbr->entries); i++)
|
||||
if (mbr->entries[i].type == GRUB_PC_PARTITION_TYPE_GPT_DISK)
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid protective MBR");
|
||||
}
|
||||
|
||||
static grub_uint64_t
|
||||
grub_gpt_entries_size (struct grub_gpt_header *gpt)
|
||||
{
|
||||
return (grub_uint64_t) grub_le_to_cpu32 (gpt->maxpart) *
|
||||
(grub_uint64_t) grub_le_to_cpu32 (gpt->partentry_size);
|
||||
}
|
||||
|
||||
static grub_uint64_t
|
||||
grub_gpt_entries_sectors (struct grub_gpt_header *gpt,
|
||||
unsigned int log_sector_size)
|
||||
{
|
||||
grub_uint64_t sector_bytes, entries_bytes;
|
||||
|
||||
sector_bytes = 1ULL << log_sector_size;
|
||||
entries_bytes = grub_gpt_entries_size (gpt);
|
||||
return grub_divmod64(entries_bytes + sector_bytes - 1, sector_bytes, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
is_pow2 (grub_uint32_t n)
|
||||
{
|
||||
return (n & (n - 1)) == 0;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_gpt_header_check (struct grub_gpt_header *gpt,
|
||||
unsigned int log_sector_size)
|
||||
{
|
||||
grub_uint32_t crc = 0, size;
|
||||
grub_uint64_t start, end;
|
||||
|
||||
if (grub_memcmp (gpt->magic, grub_gpt_magic, sizeof (grub_gpt_magic)) != 0)
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT signature");
|
||||
|
||||
if (gpt->version != GRUB_GPT_HEADER_VERSION)
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "unknown GPT version");
|
||||
|
||||
grub_gpt_header_lecrc32 (&crc, gpt);
|
||||
if (gpt->crc32 != crc)
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT header crc32");
|
||||
|
||||
/* The header size "must be greater than or equal to 92 and must be less
|
||||
* than or equal to the logical block size." */
|
||||
size = grub_le_to_cpu32 (gpt->headersize);
|
||||
if (size < 92U || size > (1U << log_sector_size))
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT header size");
|
||||
|
||||
/* The partition entry size must be "a value of 128*(2^n) where n is an
|
||||
* integer greater than or equal to zero (e.g., 128, 256, 512, etc.)." */
|
||||
size = grub_le_to_cpu32 (gpt->partentry_size);
|
||||
if (size < 128U || size % 128U || !is_pow2 (size / 128U))
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT entry size");
|
||||
|
||||
/* The minimum entries table size is specified in terms of bytes,
|
||||
* regardless of how large the individual entry size is. */
|
||||
if (grub_gpt_entries_size (gpt) < GRUB_GPT_DEFAULT_ENTRIES_SIZE)
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT entry table size");
|
||||
|
||||
/* And of course there better be some space for partitions! */
|
||||
start = grub_le_to_cpu64 (gpt->start);
|
||||
end = grub_le_to_cpu64 (gpt->end);
|
||||
if (start > end)
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid usable sectors");
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_gpt_headers_equal (grub_gpt_t gpt)
|
||||
{
|
||||
/* Assume headers passed grub_gpt_header_check so skip magic and version.
|
||||
* Individual fields must be checked instead of just using memcmp because
|
||||
* crc32, header, alternate, and partitions will all normally differ. */
|
||||
|
||||
if (gpt->primary.headersize != gpt->backup.headersize ||
|
||||
gpt->primary.header_lba != gpt->backup.alternate_lba ||
|
||||
gpt->primary.alternate_lba != gpt->backup.header_lba ||
|
||||
gpt->primary.start != gpt->backup.start ||
|
||||
gpt->primary.end != gpt->backup.end ||
|
||||
gpt->primary.maxpart != gpt->backup.maxpart ||
|
||||
gpt->primary.partentry_size != gpt->backup.partentry_size ||
|
||||
gpt->primary.partentry_crc32 != gpt->backup.partentry_crc32)
|
||||
return 0;
|
||||
|
||||
return grub_memcmp(&gpt->primary.guid, &gpt->backup.guid,
|
||||
sizeof(grub_gpt_part_guid_t)) == 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_gpt_check_primary (grub_gpt_t gpt)
|
||||
{
|
||||
grub_uint64_t backup, primary, entries, entries_len, start, end;
|
||||
|
||||
primary = grub_le_to_cpu64 (gpt->primary.header_lba);
|
||||
backup = grub_le_to_cpu64 (gpt->primary.alternate_lba);
|
||||
entries = grub_le_to_cpu64 (gpt->primary.partitions);
|
||||
entries_len = grub_gpt_entries_sectors(&gpt->primary, gpt->log_sector_size);
|
||||
start = grub_le_to_cpu64 (gpt->primary.start);
|
||||
end = grub_le_to_cpu64 (gpt->primary.end);
|
||||
|
||||
grub_dprintf ("gpt", "Primary GPT layout:\n"
|
||||
"primary header = 0x%llx backup header = 0x%llx\n"
|
||||
"entries location = 0x%llx length = 0x%llx\n"
|
||||
"first usable = 0x%llx last usable = 0x%llx\n",
|
||||
(unsigned long long) primary,
|
||||
(unsigned long long) backup,
|
||||
(unsigned long long) entries,
|
||||
(unsigned long long) entries_len,
|
||||
(unsigned long long) start,
|
||||
(unsigned long long) end);
|
||||
|
||||
if (grub_gpt_header_check (&gpt->primary, gpt->log_sector_size))
|
||||
return grub_errno;
|
||||
if (primary != 1)
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid primary GPT LBA");
|
||||
if (entries <= 1 || entries+entries_len > start)
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid entries location");
|
||||
if (backup <= end)
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA");
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_gpt_check_backup (grub_gpt_t gpt)
|
||||
{
|
||||
grub_uint64_t backup, primary, entries, entries_len, start, end;
|
||||
|
||||
backup = grub_le_to_cpu64 (gpt->backup.header_lba);
|
||||
primary = grub_le_to_cpu64 (gpt->backup.alternate_lba);
|
||||
entries = grub_le_to_cpu64 (gpt->backup.partitions);
|
||||
entries_len = grub_gpt_entries_sectors(&gpt->backup, gpt->log_sector_size);
|
||||
start = grub_le_to_cpu64 (gpt->backup.start);
|
||||
end = grub_le_to_cpu64 (gpt->backup.end);
|
||||
|
||||
grub_dprintf ("gpt", "Backup GPT layout:\n"
|
||||
"primary header = 0x%llx backup header = 0x%llx\n"
|
||||
"entries location = 0x%llx length = 0x%llx\n"
|
||||
"first usable = 0x%llx last usable = 0x%llx\n",
|
||||
(unsigned long long) primary,
|
||||
(unsigned long long) backup,
|
||||
(unsigned long long) entries,
|
||||
(unsigned long long) entries_len,
|
||||
(unsigned long long) start,
|
||||
(unsigned long long) end);
|
||||
|
||||
if (grub_gpt_header_check (&gpt->backup, gpt->log_sector_size))
|
||||
return grub_errno;
|
||||
if (primary != 1)
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid primary GPT LBA");
|
||||
if (entries <= end || entries+entries_len > backup)
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid entries location");
|
||||
if (backup <= end)
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA");
|
||||
|
||||
/* If both primary and backup are valid but differ prefer the primary. */
|
||||
if ((gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) &&
|
||||
!grub_gpt_headers_equal (gpt))
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "backup GPT out of sync");
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_gpt_read_primary (grub_disk_t disk, grub_gpt_t gpt)
|
||||
{
|
||||
grub_disk_addr_t addr;
|
||||
|
||||
/* TODO: The gpt partmap module searches for the primary header instead
|
||||
* of relying on the disk's sector size. For now trust the disk driver
|
||||
* but eventually this code should match the existing behavior. */
|
||||
gpt->log_sector_size = disk->log_sector_size;
|
||||
|
||||
grub_dprintf ("gpt", "reading primary GPT from sector 0x1\n");
|
||||
|
||||
addr = grub_gpt_sector_to_addr (gpt, 1);
|
||||
if (grub_disk_read (disk, addr, 0, sizeof (gpt->primary), &gpt->primary))
|
||||
return grub_errno;
|
||||
|
||||
if (grub_gpt_check_primary (gpt))
|
||||
return grub_errno;
|
||||
|
||||
gpt->status |= GRUB_GPT_PRIMARY_HEADER_VALID;
|
||||
|
||||
if (grub_gpt_read_entries (disk, gpt, &gpt->primary,
|
||||
&gpt->entries, &gpt->entries_size))
|
||||
return grub_errno;
|
||||
|
||||
gpt->status |= GRUB_GPT_PRIMARY_ENTRIES_VALID;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_gpt_read_backup (grub_disk_t disk, grub_gpt_t gpt)
|
||||
{
|
||||
void *entries = NULL;
|
||||
grub_size_t entries_size;
|
||||
grub_uint64_t sector;
|
||||
grub_disk_addr_t addr;
|
||||
|
||||
/* Assumes gpt->log_sector_size == disk->log_sector_size */
|
||||
if (gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID)
|
||||
{
|
||||
sector = grub_le_to_cpu64 (gpt->primary.alternate_lba);
|
||||
if (grub_gpt_disk_size_valid (disk) && sector >= disk->total_sectors)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
"backup GPT located at 0x%llx, "
|
||||
"beyond last disk sector at 0x%llx",
|
||||
(unsigned long long) sector,
|
||||
(unsigned long long) disk->total_sectors - 1);
|
||||
}
|
||||
else if (grub_gpt_disk_size_valid (disk))
|
||||
sector = disk->total_sectors - 1;
|
||||
else
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
"size of disk unknown, cannot locate backup GPT");
|
||||
|
||||
grub_dprintf ("gpt", "reading backup GPT from sector 0x%llx\n",
|
||||
(unsigned long long) sector);
|
||||
|
||||
addr = grub_gpt_sector_to_addr (gpt, sector);
|
||||
if (grub_disk_read (disk, addr, 0, sizeof (gpt->backup), &gpt->backup))
|
||||
return grub_errno;
|
||||
|
||||
if (grub_gpt_check_backup (gpt))
|
||||
return grub_errno;
|
||||
|
||||
/* Ensure the backup header thinks it is located where we found it. */
|
||||
if (grub_le_to_cpu64 (gpt->backup.header_lba) != sector)
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA");
|
||||
|
||||
gpt->status |= GRUB_GPT_BACKUP_HEADER_VALID;
|
||||
|
||||
if (grub_gpt_read_entries (disk, gpt, &gpt->backup,
|
||||
&entries, &entries_size))
|
||||
return grub_errno;
|
||||
|
||||
if (gpt->status & GRUB_GPT_PRIMARY_ENTRIES_VALID)
|
||||
{
|
||||
if (entries_size != gpt->entries_size ||
|
||||
grub_memcmp (entries, gpt->entries, entries_size) != 0)
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "backup GPT out of sync");
|
||||
|
||||
grub_free (entries);
|
||||
}
|
||||
else
|
||||
{
|
||||
gpt->entries = entries;
|
||||
gpt->entries_size = entries_size;
|
||||
}
|
||||
|
||||
gpt->status |= GRUB_GPT_BACKUP_ENTRIES_VALID;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_gpt_read_entries (grub_disk_t disk, grub_gpt_t gpt,
|
||||
struct grub_gpt_header *header,
|
||||
void **ret_entries,
|
||||
grub_size_t *ret_entries_size)
|
||||
{
|
||||
void *entries = NULL;
|
||||
grub_uint32_t count, size, crc;
|
||||
grub_uint64_t sector;
|
||||
grub_disk_addr_t addr;
|
||||
grub_size_t entries_size;
|
||||
|
||||
/* Grub doesn't include calloc, hence the manual overflow check. */
|
||||
count = grub_le_to_cpu32 (header->maxpart);
|
||||
size = grub_le_to_cpu32 (header->partentry_size);
|
||||
entries_size = count *size;
|
||||
if (size && entries_size / size != count)
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Double check that the header was validated properly. */
|
||||
if (entries_size < GRUB_GPT_DEFAULT_ENTRIES_SIZE)
|
||||
return grub_error (GRUB_ERR_BUG, "invalid GPT entries table size");
|
||||
|
||||
entries = grub_malloc (entries_size);
|
||||
if (!entries)
|
||||
goto fail;
|
||||
|
||||
sector = grub_le_to_cpu64 (header->partitions);
|
||||
grub_dprintf ("gpt", "reading GPT %lu entries from sector 0x%llx\n",
|
||||
(unsigned long) count,
|
||||
(unsigned long long) sector);
|
||||
|
||||
addr = grub_gpt_sector_to_addr (gpt, sector);
|
||||
if (grub_disk_read (disk, addr, 0, entries_size, entries))
|
||||
goto fail;
|
||||
|
||||
grub_gpt_lecrc32 (&crc, entries, entries_size);
|
||||
if (crc != header->partentry_crc32)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT entry crc32");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*ret_entries = entries;
|
||||
*ret_entries_size = entries_size;
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
fail:
|
||||
grub_free (entries);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
grub_gpt_t
|
||||
grub_gpt_read (grub_disk_t disk)
|
||||
{
|
||||
grub_gpt_t gpt;
|
||||
|
||||
grub_dprintf ("gpt", "reading GPT from %s\n", disk->name);
|
||||
|
||||
gpt = grub_zalloc (sizeof (*gpt));
|
||||
if (!gpt)
|
||||
goto fail;
|
||||
|
||||
if (grub_disk_read (disk, 0, 0, sizeof (gpt->mbr), &gpt->mbr))
|
||||
goto fail;
|
||||
|
||||
/* Check the MBR but errors aren't reported beyond the status bit. */
|
||||
if (grub_gpt_pmbr_check (&gpt->mbr))
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
else
|
||||
gpt->status |= GRUB_GPT_PROTECTIVE_MBR;
|
||||
|
||||
/* If both the primary and backup fail report the primary's error. */
|
||||
if (grub_gpt_read_primary (disk, gpt))
|
||||
{
|
||||
grub_error_push ();
|
||||
grub_gpt_read_backup (disk, gpt);
|
||||
grub_error_pop ();
|
||||
}
|
||||
else
|
||||
grub_gpt_read_backup (disk, gpt);
|
||||
|
||||
/* If either succeeded clear any possible error from the other. */
|
||||
if (grub_gpt_primary_valid (gpt) || grub_gpt_backup_valid (gpt))
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
else
|
||||
goto fail;
|
||||
|
||||
return gpt;
|
||||
|
||||
fail:
|
||||
grub_gpt_free (gpt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct grub_gpt_partentry *
|
||||
grub_gpt_get_partentry (grub_gpt_t gpt, grub_uint32_t n)
|
||||
{
|
||||
struct grub_gpt_header *header;
|
||||
grub_size_t offset;
|
||||
|
||||
header = grub_gpt_get_header (gpt);
|
||||
if (!header)
|
||||
return NULL;
|
||||
|
||||
if (n >= grub_le_to_cpu32 (header->maxpart))
|
||||
return NULL;
|
||||
|
||||
offset = (grub_size_t) grub_le_to_cpu32 (header->partentry_size) * n;
|
||||
return (struct grub_gpt_partentry *) ((char *) gpt->entries + offset);
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_gpt_repair (grub_disk_t disk, grub_gpt_t gpt)
|
||||
{
|
||||
/* Skip if there is nothing to do. */
|
||||
if (grub_gpt_both_valid (gpt))
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
grub_dprintf ("gpt", "repairing GPT for %s\n", disk->name);
|
||||
|
||||
if (disk->log_sector_size != gpt->log_sector_size)
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"GPT sector size must match disk sector size");
|
||||
|
||||
if (grub_gpt_primary_valid (gpt))
|
||||
{
|
||||
grub_uint64_t backup_header;
|
||||
|
||||
grub_dprintf ("gpt", "primary GPT is valid\n");
|
||||
|
||||
/* Relocate backup to end if disk if the disk has grown. */
|
||||
backup_header = grub_le_to_cpu64 (gpt->primary.alternate_lba);
|
||||
if (grub_gpt_disk_size_valid (disk) &&
|
||||
disk->total_sectors - 1 > backup_header)
|
||||
{
|
||||
backup_header = disk->total_sectors - 1;
|
||||
grub_dprintf ("gpt", "backup GPT header relocated to 0x%llx\n",
|
||||
(unsigned long long) backup_header);
|
||||
|
||||
gpt->primary.alternate_lba = grub_cpu_to_le64 (backup_header);
|
||||
}
|
||||
|
||||
grub_memcpy (&gpt->backup, &gpt->primary, sizeof (gpt->backup));
|
||||
gpt->backup.header_lba = gpt->primary.alternate_lba;
|
||||
gpt->backup.alternate_lba = gpt->primary.header_lba;
|
||||
gpt->backup.partitions = grub_cpu_to_le64 (backup_header -
|
||||
grub_gpt_size_to_sectors (gpt, gpt->entries_size));
|
||||
}
|
||||
else if (grub_gpt_backup_valid (gpt))
|
||||
{
|
||||
grub_dprintf ("gpt", "backup GPT is valid\n");
|
||||
|
||||
grub_memcpy (&gpt->primary, &gpt->backup, sizeof (gpt->primary));
|
||||
gpt->primary.header_lba = gpt->backup.alternate_lba;
|
||||
gpt->primary.alternate_lba = gpt->backup.header_lba;
|
||||
gpt->primary.partitions = grub_cpu_to_le64_compile_time (2);
|
||||
}
|
||||
else
|
||||
return grub_error (GRUB_ERR_BUG, "No valid GPT");
|
||||
|
||||
if (grub_gpt_update (gpt))
|
||||
return grub_errno;
|
||||
|
||||
grub_dprintf ("gpt", "repairing GPT for %s successful\n", disk->name);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_gpt_update (grub_gpt_t gpt)
|
||||
{
|
||||
grub_uint32_t crc;
|
||||
|
||||
/* Clear status bits, require revalidation of everything. */
|
||||
gpt->status &= ~(GRUB_GPT_PRIMARY_HEADER_VALID |
|
||||
GRUB_GPT_PRIMARY_ENTRIES_VALID |
|
||||
GRUB_GPT_BACKUP_HEADER_VALID |
|
||||
GRUB_GPT_BACKUP_ENTRIES_VALID);
|
||||
|
||||
/* Writing headers larger than our header structure are unsupported. */
|
||||
gpt->primary.headersize =
|
||||
grub_cpu_to_le32_compile_time (sizeof (gpt->primary));
|
||||
gpt->backup.headersize =
|
||||
grub_cpu_to_le32_compile_time (sizeof (gpt->backup));
|
||||
|
||||
grub_gpt_lecrc32 (&crc, gpt->entries, gpt->entries_size);
|
||||
gpt->primary.partentry_crc32 = crc;
|
||||
gpt->backup.partentry_crc32 = crc;
|
||||
|
||||
grub_gpt_header_lecrc32 (&gpt->primary.crc32, &gpt->primary);
|
||||
grub_gpt_header_lecrc32 (&gpt->backup.crc32, &gpt->backup);
|
||||
|
||||
if (grub_gpt_check_primary (gpt))
|
||||
{
|
||||
grub_error_push ();
|
||||
return grub_error (GRUB_ERR_BUG, "Generated invalid GPT primary header");
|
||||
}
|
||||
|
||||
gpt->status |= (GRUB_GPT_PRIMARY_HEADER_VALID |
|
||||
GRUB_GPT_PRIMARY_ENTRIES_VALID);
|
||||
|
||||
if (grub_gpt_check_backup (gpt))
|
||||
{
|
||||
grub_error_push ();
|
||||
return grub_error (GRUB_ERR_BUG, "Generated invalid GPT backup header");
|
||||
}
|
||||
|
||||
gpt->status |= (GRUB_GPT_BACKUP_HEADER_VALID |
|
||||
GRUB_GPT_BACKUP_ENTRIES_VALID);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_gpt_write_table (grub_disk_t disk, grub_gpt_t gpt,
|
||||
struct grub_gpt_header *header)
|
||||
{
|
||||
grub_disk_addr_t addr;
|
||||
|
||||
if (grub_le_to_cpu32 (header->headersize) != sizeof (*header))
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"Header size is %u, must be %u",
|
||||
grub_le_to_cpu32 (header->headersize),
|
||||
sizeof (*header));
|
||||
|
||||
addr = grub_gpt_sector_to_addr (gpt, grub_le_to_cpu64 (header->header_lba));
|
||||
if (addr == 0)
|
||||
return grub_error (GRUB_ERR_BUG,
|
||||
"Refusing to write GPT header to address 0x0");
|
||||
if (grub_disk_write (disk, addr, 0, sizeof (*header), header))
|
||||
return grub_errno;
|
||||
|
||||
addr = grub_gpt_sector_to_addr (gpt, grub_le_to_cpu64 (header->partitions));
|
||||
if (addr < 2)
|
||||
return grub_error (GRUB_ERR_BUG,
|
||||
"Refusing to write GPT entries to address 0x%llx",
|
||||
(unsigned long long) addr);
|
||||
if (grub_disk_write (disk, addr, 0, gpt->entries_size, gpt->entries))
|
||||
return grub_errno;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_gpt_write (grub_disk_t disk, grub_gpt_t gpt)
|
||||
{
|
||||
grub_uint64_t backup_header;
|
||||
|
||||
/* TODO: update/repair protective MBRs too. */
|
||||
|
||||
if (!grub_gpt_both_valid (gpt))
|
||||
return grub_error (GRUB_ERR_BAD_PART_TABLE, "Invalid GPT data");
|
||||
|
||||
/* Write the backup GPT first so if writing fails the update is aborted
|
||||
* and the primary is left intact. However if the backup location is
|
||||
* inaccessible we have to just skip and hope for the best, the backup
|
||||
* will need to be repaired in the OS. */
|
||||
backup_header = grub_le_to_cpu64 (gpt->backup.header_lba);
|
||||
if (grub_gpt_disk_size_valid (disk) &&
|
||||
backup_header >= disk->total_sectors)
|
||||
{
|
||||
grub_printf ("warning: backup GPT located at 0x%llx, "
|
||||
"beyond last disk sector at 0x%llx\n",
|
||||
(unsigned long long) backup_header,
|
||||
(unsigned long long) disk->total_sectors - 1);
|
||||
grub_printf ("warning: only writing primary GPT, "
|
||||
"the backup GPT must be repaired from the OS\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_dprintf ("gpt", "writing backup GPT to %s\n", disk->name);
|
||||
if (grub_gpt_write_table (disk, gpt, &gpt->backup))
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
grub_dprintf ("gpt", "writing primary GPT to %s\n", disk->name);
|
||||
if (grub_gpt_write_table (disk, gpt, &gpt->primary))
|
||||
return grub_errno;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
grub_gpt_free (grub_gpt_t gpt)
|
||||
{
|
||||
if (!gpt)
|
||||
return;
|
||||
|
||||
grub_free (gpt->entries);
|
||||
grub_free (gpt);
|
||||
}
|
|
@ -34,6 +34,8 @@
|
|||
#include <grub/lib/cmdline.h>
|
||||
#include <grub/verify.h>
|
||||
|
||||
#include <grub/verity-hash.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static grub_dl_t my_mod;
|
||||
|
@ -333,7 +335,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
|
||||
grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
|
||||
|
||||
cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE);
|
||||
cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE)
|
||||
+ VERITY_CMDLINE_LENGTH;
|
||||
linux_args = grub_malloc (cmdline_size);
|
||||
if (!linux_args)
|
||||
{
|
||||
|
@ -350,6 +353,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
{
|
||||
grub_pass_verity_hash (kernel_addr, linux_args, cmdline_size);
|
||||
grub_loader_set (grub_linux_boot, grub_linux_unload, 0);
|
||||
loaded = 1;
|
||||
}
|
||||
|
|
363
grub-core/loader/i386/efi/linux.c
Normal file
363
grub-core/loader/i386/efi/linux.c
Normal file
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2012 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/loader.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/cpu/linux.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/lib/cmdline.h>
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/tpm.h>
|
||||
|
||||
#include <grub/verity-hash.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static grub_dl_t my_mod;
|
||||
static int loaded;
|
||||
static void *kernel_mem;
|
||||
static grub_uint64_t kernel_size;
|
||||
static grub_uint8_t *initrd_mem;
|
||||
static grub_uint32_t handover_offset;
|
||||
struct linux_kernel_params *params;
|
||||
static char *linux_cmdline;
|
||||
|
||||
#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12)
|
||||
|
||||
#define SHIM_LOCK_GUID \
|
||||
{ 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
|
||||
|
||||
struct grub_efi_shim_lock
|
||||
{
|
||||
grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size);
|
||||
};
|
||||
typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
|
||||
|
||||
static grub_efi_boolean_t
|
||||
grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
|
||||
{
|
||||
grub_efi_guid_t guid = SHIM_LOCK_GUID;
|
||||
grub_efi_shim_lock_t *shim_lock;
|
||||
|
||||
shim_lock = grub_efi_locate_protocol(&guid, NULL);
|
||||
|
||||
if (!shim_lock) {
|
||||
if (grub_efi_secure_boot())
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef void(*handover_func)(void *, grub_efi_system_table_t *, struct linux_kernel_params *);
|
||||
|
||||
static grub_err_t
|
||||
grub_linuxefi_boot (void)
|
||||
{
|
||||
handover_func hf;
|
||||
int offset = 0;
|
||||
|
||||
#ifdef __x86_64__
|
||||
offset = 512;
|
||||
#endif
|
||||
|
||||
hf = (handover_func)((char *)kernel_mem + handover_offset + offset);
|
||||
|
||||
asm volatile ("cli");
|
||||
|
||||
hf (grub_efi_image_handle, grub_efi_system_table, params);
|
||||
|
||||
/* Not reached */
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_linuxefi_unload (void)
|
||||
{
|
||||
grub_dl_unref (my_mod);
|
||||
loaded = 0;
|
||||
if (initrd_mem)
|
||||
grub_efi_free_pages((grub_efi_physical_address_t)initrd_mem, BYTES_TO_PAGES(params->ramdisk_size));
|
||||
if (linux_cmdline)
|
||||
grub_efi_free_pages((grub_efi_physical_address_t)linux_cmdline, BYTES_TO_PAGES(params->cmdline_size + 1));
|
||||
if (kernel_mem)
|
||||
grub_efi_free_pages((grub_efi_physical_address_t)kernel_mem, BYTES_TO_PAGES(kernel_size));
|
||||
if (params)
|
||||
grub_efi_free_pages((grub_efi_physical_address_t)params, BYTES_TO_PAGES(16384));
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc, char *argv[])
|
||||
{
|
||||
grub_file_t *files = 0;
|
||||
int i, nfiles = 0;
|
||||
grub_size_t size = 0;
|
||||
grub_uint8_t *ptr;
|
||||
|
||||
if (argc == 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!loaded)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
files = grub_zalloc (argc * sizeof (files[0]));
|
||||
if (!files)
|
||||
goto fail;
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
grub_file_filter_disable_compression ();
|
||||
files[i] = grub_file_open (argv[i]);
|
||||
if (! files[i])
|
||||
goto fail;
|
||||
nfiles++;
|
||||
size += ALIGN_UP (grub_file_size (files[i]), 4);
|
||||
}
|
||||
|
||||
initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size));
|
||||
|
||||
if (!initrd_mem)
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
params->ramdisk_size = size;
|
||||
params->ramdisk_image = (grub_uint32_t)(grub_uint64_t) initrd_mem;
|
||||
|
||||
ptr = initrd_mem;
|
||||
|
||||
for (i = 0; i < nfiles; i++)
|
||||
{
|
||||
grub_ssize_t cursize = grub_file_size (files[i]);
|
||||
if (grub_file_read (files[i], ptr, cursize) != cursize)
|
||||
{
|
||||
if (!grub_errno)
|
||||
grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
|
||||
argv[i]);
|
||||
goto fail;
|
||||
}
|
||||
// TODO figure out the GRUB_VERIFY_ equivalent for this one
|
||||
//grub_tpm_measure (ptr, cursize, GRUB_BINARY_PCR, "Initrd");
|
||||
//grub_print_error();
|
||||
ptr += cursize;
|
||||
grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
|
||||
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
|
||||
}
|
||||
|
||||
params->ramdisk_size = size;
|
||||
|
||||
fail:
|
||||
for (i = 0; i < nfiles; i++)
|
||||
grub_file_close (files[i]);
|
||||
grub_free (files);
|
||||
|
||||
if (initrd_mem && grub_errno)
|
||||
grub_efi_free_pages((grub_efi_physical_address_t)initrd_mem, BYTES_TO_PAGES(size));
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc, char *argv[])
|
||||
{
|
||||
grub_file_t file = 0;
|
||||
struct linux_kernel_header lh;
|
||||
grub_ssize_t len, start, filelen;
|
||||
void *kernel = NULL;
|
||||
|
||||
grub_dl_ref (my_mod);
|
||||
|
||||
if (argc == 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
file = grub_file_open (argv[0]);
|
||||
if (! file)
|
||||
goto fail;
|
||||
|
||||
filelen = grub_file_size (file);
|
||||
|
||||
kernel = grub_malloc(filelen);
|
||||
|
||||
if (!kernel)
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (grub_file_read (file, kernel, filelen) != filelen)
|
||||
{
|
||||
grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// TODO figure out the GRUB_VERIFY_ equivalent for this one
|
||||
//grub_tpm_measure (kernel, filelen, GRUB_BINARY_PCR, "Kernel");
|
||||
//grub_print_error();
|
||||
|
||||
if (! grub_linuxefi_secure_validate (kernel, filelen))
|
||||
{
|
||||
grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
|
||||
grub_free (kernel);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384));
|
||||
|
||||
if (! params)
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
grub_memset (params, 0, 16384);
|
||||
|
||||
grub_memcpy (&lh, kernel, sizeof (lh));
|
||||
|
||||
if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (lh.version < grub_cpu_to_le16 (0x020b))
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_OS, N_("kernel too old"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!lh.handover_offset)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff,
|
||||
BYTES_TO_PAGES(lh.cmdline_size + 1));
|
||||
|
||||
if (!linux_cmdline)
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
|
||||
grub_create_loader_cmdline (argc, argv,
|
||||
linux_cmdline + sizeof (LINUX_IMAGE) - 1,
|
||||
lh.cmdline_size - (sizeof (LINUX_IMAGE) - 1));
|
||||
|
||||
grub_pass_verity_hash(&lh, linux_cmdline, lh.cmdline_size);
|
||||
lh.cmd_line_ptr = (grub_uint32_t)(grub_uint64_t)linux_cmdline;
|
||||
|
||||
handover_offset = lh.handover_offset;
|
||||
|
||||
start = (lh.setup_sects + 1) * 512;
|
||||
len = grub_file_size(file) - start;
|
||||
|
||||
kernel_mem = grub_efi_allocate_pages(lh.pref_address,
|
||||
BYTES_TO_PAGES(lh.init_size));
|
||||
|
||||
if (!kernel_mem)
|
||||
kernel_mem = grub_efi_allocate_pages_max(0x3fffffff,
|
||||
BYTES_TO_PAGES(lh.init_size));
|
||||
|
||||
if (!kernel_mem)
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
grub_memcpy (kernel_mem, (char *)kernel + start, len);
|
||||
grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
|
||||
loaded=1;
|
||||
|
||||
lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem;
|
||||
grub_memcpy (params, &lh, 2 * 512);
|
||||
|
||||
params->type_of_loader = 0x21;
|
||||
|
||||
fail:
|
||||
|
||||
if (file)
|
||||
grub_file_close (file);
|
||||
|
||||
grub_free (kernel);
|
||||
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_dl_unref (my_mod);
|
||||
loaded = 0;
|
||||
}
|
||||
|
||||
if (linux_cmdline && !loaded)
|
||||
grub_efi_free_pages((grub_efi_physical_address_t)linux_cmdline, BYTES_TO_PAGES(lh.cmdline_size + 1));
|
||||
|
||||
if (kernel_mem && !loaded)
|
||||
grub_efi_free_pages((grub_efi_physical_address_t)kernel_mem, BYTES_TO_PAGES(kernel_size));
|
||||
|
||||
if (params && !loaded)
|
||||
grub_efi_free_pages((grub_efi_physical_address_t)params, BYTES_TO_PAGES(16384));
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_command_t cmd_linux, cmd_initrd;
|
||||
|
||||
GRUB_MOD_INIT(linuxefi)
|
||||
{
|
||||
cmd_linux =
|
||||
grub_register_command ("linuxefi", grub_cmd_linux,
|
||||
0, N_("Load Linux."));
|
||||
cmd_initrd =
|
||||
grub_register_command ("initrdefi", grub_cmd_initrd,
|
||||
0, N_("Load initrd."));
|
||||
my_mod = mod;
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(linuxefi)
|
||||
{
|
||||
grub_unregister_command (cmd_linux);
|
||||
grub_unregister_command (cmd_initrd);
|
||||
}
|
|
@ -36,6 +36,9 @@
|
|||
#include <grub/lib/cmdline.h>
|
||||
#include <grub/linux.h>
|
||||
#include <grub/machine/kernel.h>
|
||||
#include <grub/tpm.h>
|
||||
|
||||
#include <grub/verity-hash.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
@ -642,12 +645,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
grub_file_t file = 0;
|
||||
struct linux_i386_kernel_header lh;
|
||||
grub_uint8_t setup_sects;
|
||||
grub_size_t real_size, prot_size, prot_file_size;
|
||||
grub_size_t real_size, prot_size, prot_file_size, kernel_offset;
|
||||
grub_ssize_t len;
|
||||
int i;
|
||||
grub_size_t align, min_align;
|
||||
int relocatable;
|
||||
grub_uint64_t preferred_address = GRUB_LINUX_BZIMAGE_ADDR;
|
||||
grub_uint8_t *kernel = NULL;
|
||||
|
||||
grub_dl_ref (my_mod);
|
||||
|
||||
|
@ -661,7 +665,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
if (! file)
|
||||
goto fail;
|
||||
|
||||
if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
|
||||
len = grub_file_size (file);
|
||||
kernel = grub_malloc (len);
|
||||
if (!kernel)
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (grub_file_read (file, kernel, len) != len)
|
||||
{
|
||||
if (!grub_errno)
|
||||
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
|
||||
|
@ -669,6 +681,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
goto fail;
|
||||
}
|
||||
|
||||
// TODO figure out the GRUB_VERIFY_ equivalent for this one
|
||||
//grub_tpm_measure (kernel, len, GRUB_BINARY_PCR, "Kernel");
|
||||
//grub_print_error();
|
||||
|
||||
grub_memcpy (&lh, kernel, sizeof (lh));
|
||||
|
||||
kernel_offset = sizeof (lh);
|
||||
|
||||
if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55))
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
|
||||
|
@ -789,6 +809,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
argv[0]);
|
||||
goto fail;
|
||||
}
|
||||
kernel_offset += len;
|
||||
|
||||
linux_params.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;
|
||||
|
||||
|
@ -847,7 +868,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
|
||||
/* The other parameters are filled when booting. */
|
||||
|
||||
grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
|
||||
kernel_offset = real_size + GRUB_DISK_SECTOR_SIZE;
|
||||
|
||||
grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n",
|
||||
(unsigned) real_size, (unsigned) prot_size);
|
||||
|
@ -1000,10 +1021,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
goto fail;
|
||||
}
|
||||
|
||||
grub_pass_verity_hash(&lh, linux_cmdline, maximal_cmdline_size);
|
||||
len = prot_file_size;
|
||||
if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno)
|
||||
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
|
||||
argv[0]);
|
||||
grub_memcpy (prot_mode_mem, kernel + kernel_offset, len);
|
||||
kernel_offset += len;
|
||||
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
{
|
||||
|
@ -1014,6 +1035,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
|
||||
fail:
|
||||
|
||||
grub_free (kernel);
|
||||
|
||||
if (file)
|
||||
grub_file_close (file);
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <grub/net.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/lib/cmdline.h>
|
||||
#include <grub/tpm.h>
|
||||
|
||||
#ifdef GRUB_MACHINE_EFI
|
||||
#include <grub/efi/efi.h>
|
||||
|
@ -173,6 +174,10 @@ grub_multiboot_load (grub_file_t file, const char *filename)
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
// TODO figure out the GRUB_VERIFY_ equivalent for this one
|
||||
//grub_tpm_measure((unsigned char*)buffer, len, GRUB_BINARY_PCR, filename);
|
||||
//grub_print_error();
|
||||
|
||||
header = find_header (buffer, len);
|
||||
|
||||
if (header == 0)
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <grub/i386/floppy.h>
|
||||
#include <grub/lib/cmdline.h>
|
||||
#include <grub/linux.h>
|
||||
#include <grub/tpm.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
@ -123,13 +124,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
grub_file_t file = 0;
|
||||
struct linux_i386_kernel_header lh;
|
||||
grub_uint8_t setup_sects;
|
||||
grub_size_t real_size;
|
||||
grub_size_t real_size, kernel_offset = 0;
|
||||
grub_ssize_t len;
|
||||
int i;
|
||||
char *grub_linux_prot_chunk;
|
||||
int grub_linux_is_bzimage;
|
||||
grub_addr_t grub_linux_prot_target;
|
||||
grub_err_t err;
|
||||
grub_uint8_t *kernel = NULL;
|
||||
|
||||
grub_dl_ref (my_mod);
|
||||
|
||||
|
@ -143,7 +145,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
if (! file)
|
||||
goto fail;
|
||||
|
||||
if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
|
||||
len = grub_file_size (file);
|
||||
kernel = grub_malloc (len);
|
||||
if (!kernel)
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (grub_file_read (file, kernel, len) != len)
|
||||
{
|
||||
if (!grub_errno)
|
||||
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
|
||||
|
@ -151,6 +161,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
goto fail;
|
||||
}
|
||||
|
||||
// TODO figure out the GRUB_VERIFY_ equivalent for this one
|
||||
//grub_tpm_measure (kernel, len, GRUB_BINARY_PCR, "Kernel");
|
||||
//grub_print_error();
|
||||
|
||||
grub_memcpy (&lh, kernel, sizeof (lh));
|
||||
kernel_offset = sizeof (lh);
|
||||
|
||||
if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55))
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
|
||||
|
@ -314,13 +331,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
grub_memmove (grub_linux_real_chunk, &lh, sizeof (lh));
|
||||
|
||||
len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh);
|
||||
if (grub_file_read (file, grub_linux_real_chunk + sizeof (lh), len) != len)
|
||||
{
|
||||
if (!grub_errno)
|
||||
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
|
||||
argv[0]);
|
||||
goto fail;
|
||||
}
|
||||
grub_memcpy (grub_linux_real_chunk + sizeof (lh), kernel + kernel_offset,
|
||||
len);
|
||||
kernel_offset += len;
|
||||
|
||||
if (lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE)
|
||||
|| grub_le_to_cpu16 (lh.version) < 0x0200)
|
||||
|
@ -370,6 +383,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
|
||||
fail:
|
||||
|
||||
grub_free (kernel);
|
||||
|
||||
if (file)
|
||||
grub_file_close (file);
|
||||
|
||||
|
|
|
@ -656,7 +656,9 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)),
|
|||
if (!file)
|
||||
return grub_errno;
|
||||
|
||||
elf = grub_xen_file (file);
|
||||
elf = grub_xen_file_and_cmdline (file,
|
||||
(char *) xen_state.next_start.cmd_line,
|
||||
sizeof (xen_state.next_start.cmd_line) - 1);
|
||||
if (!elf)
|
||||
goto fail;
|
||||
|
||||
|
|
|
@ -19,11 +19,20 @@
|
|||
#include <grub/xen_file.h>
|
||||
#include <grub/i386/linux.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/verity-hash.h>
|
||||
|
||||
#define XZ_MAGIC "\3757zXZ\0"
|
||||
|
||||
grub_elf_t
|
||||
grub_xen_file (grub_file_t file)
|
||||
{
|
||||
return grub_xen_file_and_cmdline (file, NULL, 0);
|
||||
}
|
||||
|
||||
grub_elf_t
|
||||
grub_xen_file_and_cmdline (grub_file_t file,
|
||||
char *cmdline,
|
||||
grub_size_t cmdline_max_len)
|
||||
{
|
||||
grub_elf_t elf;
|
||||
struct linux_i386_kernel_header lh;
|
||||
|
@ -64,6 +73,9 @@ grub_xen_file (grub_file_t file)
|
|||
(unsigned long long) payload_offset,
|
||||
(unsigned long long) lh.payload_length);
|
||||
|
||||
if (cmdline)
|
||||
grub_pass_verity_hash (&lh, cmdline, cmdline_max_len);
|
||||
|
||||
grub_file_seek (file, payload_offset);
|
||||
|
||||
if (grub_file_read (file, &magic, sizeof (magic)) != sizeof (magic))
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <grub/misc.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/tpm.h>
|
||||
|
||||
struct newc_head
|
||||
{
|
||||
|
@ -288,6 +289,10 @@ grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
|
|||
grub_initrd_close (initrd_ctx);
|
||||
return grub_errno;
|
||||
}
|
||||
// TODO figure out the GRUB_VERIFY_ equivalent for this one
|
||||
//grub_tpm_measure (ptr, cursize, GRUB_BINARY_PCR, "Initrd");
|
||||
//grub_print_error();
|
||||
|
||||
ptr += cursize;
|
||||
}
|
||||
if (newc)
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include <grub/video.h>
|
||||
#include <grub/memory.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/tpm.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
@ -437,6 +438,9 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
|
|||
}
|
||||
|
||||
grub_file_close (file);
|
||||
// TODO figure out the GRUB_VERIFY_ equivalent for this one
|
||||
//grub_tpm_measure (module, size, GRUB_BINARY_PCR, argv[0]);
|
||||
//grub_print_error();
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <grub/i18n.h>
|
||||
#include <grub/net.h>
|
||||
#include <grub/lib/cmdline.h>
|
||||
#include <grub/tpm.h>
|
||||
|
||||
#if defined (GRUB_MACHINE_EFI)
|
||||
#include <grub/efi/efi.h>
|
||||
|
@ -131,6 +132,10 @@ grub_multiboot2_load (grub_file_t file, const char *filename)
|
|||
|
||||
COMPILE_TIME_ASSERT (MULTIBOOT_HEADER_ALIGN % 4 == 0);
|
||||
|
||||
// TODO figure out the GRUB_VERIFY_ equivalent for this one
|
||||
//grub_tpm_measure ((unsigned char *)mld.buffer, len, GRUB_BINARY_PCR, filename);
|
||||
//grub_print_error();
|
||||
|
||||
header = find_header (mld.buffer, len);
|
||||
|
||||
if (header == 0)
|
||||
|
|
|
@ -25,6 +25,20 @@
|
|||
#include <grub/net/udp.h>
|
||||
#include <grub/datetime.h>
|
||||
|
||||
#if !defined(GRUB_MACHINE_EFI) && (defined(__i386__) || defined(__x86_64__))
|
||||
#define GRUB_NET_BOOTP_ARCH 0x0000
|
||||
#elif defined(GRUB_MACHINE_EFI) && defined(__x86_64__)
|
||||
#define GRUB_NET_BOOTP_ARCH 0x0007
|
||||
#elif defined(GRUB_MACHINE_EFI) && defined(__aarch64__)
|
||||
#define GRUB_NET_BOOTP_ARCH 0x000B
|
||||
#else
|
||||
#error "unknown bootp architecture"
|
||||
#endif
|
||||
|
||||
static grub_uint8_t grub_userclass[] = {0x4D, 0x06, 0x05, 'G', 'R', 'U', 'B', '2'};
|
||||
static grub_uint8_t grub_dhcpdiscover[] = {0x35, 0x01, 0x01};
|
||||
static grub_uint8_t grub_dhcptime[] = {0x33, 0x04, 0x00, 0x00, 0x0e, 0x10};
|
||||
|
||||
struct grub_dhcp_discover_options
|
||||
{
|
||||
grub_uint8_t magic[4];
|
||||
|
@ -90,11 +104,6 @@ enum
|
|||
/* Max timeout when waiting for BOOTP/DHCP reply */
|
||||
#define GRUB_DHCP_MAX_PACKET_TIMEOUT 32
|
||||
|
||||
#define GRUB_BOOTP_MAX_OPTIONS_SIZE 64
|
||||
|
||||
/* Max timeout when waiting for BOOTP/DHCP reply */
|
||||
#define GRUB_DHCP_MAX_PACKET_TIMEOUT 32
|
||||
|
||||
static const void *
|
||||
find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
|
||||
grub_uint8_t opt_code, grub_uint8_t *opt_len)
|
||||
|
@ -429,6 +438,7 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface)
|
|||
struct udphdr *udph;
|
||||
grub_net_network_level_address_t target;
|
||||
grub_net_link_level_address_t ll_target;
|
||||
grub_uint8_t *offset;
|
||||
|
||||
static struct grub_dhcp_discover_options discover_options =
|
||||
{
|
||||
|
@ -488,19 +498,31 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface)
|
|||
COMPILE_TIME_ASSERT (sizeof (discover_options) <= GRUB_BOOTP_MAX_OPTIONS_SIZE);
|
||||
COMPILE_TIME_ASSERT (sizeof (request_options) <= GRUB_BOOTP_MAX_OPTIONS_SIZE);
|
||||
|
||||
nb = grub_netbuff_alloc (sizeof (*pack) + GRUB_BOOTP_MAX_OPTIONS_SIZE + 128);
|
||||
nb = grub_netbuff_alloc (sizeof (*pack) + sizeof(grub_userclass)
|
||||
+ sizeof(grub_dhcpdiscover)
|
||||
+ sizeof(grub_dhcptime)
|
||||
+ GRUB_BOOTP_MAX_OPTIONS_SIZE + 128);
|
||||
if (!nb)
|
||||
return grub_errno;
|
||||
|
||||
err = grub_netbuff_reserve (nb, sizeof (*pack) + GRUB_BOOTP_MAX_OPTIONS_SIZE + 128);
|
||||
err = grub_netbuff_reserve (nb, sizeof (*pack) + sizeof(grub_userclass)
|
||||
+ sizeof(grub_dhcpdiscover)
|
||||
+ sizeof(grub_dhcptime)
|
||||
+ GRUB_BOOTP_MAX_OPTIONS_SIZE + 128);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = grub_netbuff_push (nb, GRUB_BOOTP_MAX_OPTIONS_SIZE);
|
||||
err = grub_netbuff_push (nb, sizeof(grub_userclass)
|
||||
+ sizeof(grub_dhcpdiscover)
|
||||
+ sizeof(grub_dhcptime)
|
||||
+ GRUB_BOOTP_MAX_OPTIONS_SIZE);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
grub_memset (nb->data, 0, GRUB_BOOTP_MAX_OPTIONS_SIZE);
|
||||
grub_memset (nb->data, 0, sizeof(grub_userclass)
|
||||
+ sizeof(grub_dhcpdiscover)
|
||||
+ sizeof(grub_dhcptime)
|
||||
+ GRUB_BOOTP_MAX_OPTIONS_SIZE);
|
||||
if (!iface->srv_id)
|
||||
{
|
||||
grub_memcpy (nb->data, &discover_options, sizeof (discover_options));
|
||||
|
@ -537,6 +559,22 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface)
|
|||
pack->ident = iface->xid;
|
||||
|
||||
grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, 6);
|
||||
offset = (grub_uint8_t *)&pack->vendor;
|
||||
grub_memcpy (offset, grub_dhcpdiscover, sizeof(grub_dhcpdiscover));
|
||||
offset += sizeof(grub_dhcpdiscover);
|
||||
grub_memcpy (offset, grub_userclass, sizeof(grub_userclass));
|
||||
offset += sizeof(grub_userclass);
|
||||
grub_memcpy (offset, grub_dhcptime, sizeof(grub_dhcptime));
|
||||
|
||||
/* insert Client System Architecture (option 93) */
|
||||
offset += sizeof(grub_dhcptime);
|
||||
offset[0] = 93;
|
||||
offset[1] = 2;
|
||||
offset[2] = (GRUB_NET_BOOTP_ARCH >> 8);
|
||||
offset[3] = (GRUB_NET_BOOTP_ARCH & 0xFF);
|
||||
|
||||
/* option terminator */
|
||||
offset[4] = 255;
|
||||
|
||||
grub_netbuff_push (nb, sizeof (*udph));
|
||||
|
||||
|
|
|
@ -285,8 +285,8 @@ recv_hook (grub_net_udp_socket_t sock __attribute__ ((unused)),
|
|||
ptr++;
|
||||
ptr += 4;
|
||||
}
|
||||
*data->addresses = grub_malloc (sizeof ((*data->addresses)[0])
|
||||
* grub_be_to_cpu16 (head->ancount));
|
||||
*data->addresses = grub_realloc (*data->addresses, sizeof ((*data->addresses)[0])
|
||||
* (grub_be_to_cpu16 (head->ancount) + *data->naddresses));
|
||||
if (!*data->addresses)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
|
|
@ -309,7 +309,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
|
|||
{
|
||||
http_data_t data = file->data;
|
||||
grub_uint8_t *ptr;
|
||||
int i;
|
||||
int i, port;
|
||||
struct grub_net_buff *nb;
|
||||
grub_err_t err;
|
||||
|
||||
|
@ -390,8 +390,12 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
|
|||
grub_netbuff_put (nb, 2);
|
||||
grub_memcpy (ptr, "\r\n", 2);
|
||||
|
||||
if (file->device->net->port)
|
||||
port = file->device->net->port;
|
||||
else
|
||||
port = HTTP_PORT;
|
||||
data->sock = grub_net_tcp_open (file->device->net->server,
|
||||
HTTP_PORT, http_receive,
|
||||
port, http_receive,
|
||||
http_err, http_err,
|
||||
file);
|
||||
if (!data->sock)
|
||||
|
|
|
@ -1261,7 +1261,7 @@ grub_net_open_real (const char *name)
|
|||
grub_net_app_level_t proto;
|
||||
const char *protname, *server;
|
||||
grub_size_t protnamelen;
|
||||
int try;
|
||||
int try, port = 0;
|
||||
|
||||
if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
|
||||
{
|
||||
|
@ -1278,7 +1278,18 @@ grub_net_open_real (const char *name)
|
|||
else
|
||||
{
|
||||
const char *comma;
|
||||
char *colon;
|
||||
comma = grub_strchr (name, ',');
|
||||
if (!comma)
|
||||
{
|
||||
comma = grub_strchr (name, ';');
|
||||
}
|
||||
colon = grub_strchr (name, ':');
|
||||
if (colon)
|
||||
{
|
||||
port = (int) grub_strtol(colon+1, NULL, 10);
|
||||
*colon = '\0';
|
||||
}
|
||||
if (comma)
|
||||
{
|
||||
protnamelen = comma - name;
|
||||
|
@ -1313,8 +1324,13 @@ grub_net_open_real (const char *name)
|
|||
ret->server = grub_strdup (server);
|
||||
if (!ret->server)
|
||||
{
|
||||
grub_free (ret);
|
||||
return NULL;
|
||||
ret->server = grub_strdup (server);
|
||||
ret->port = port;
|
||||
if (!ret->server)
|
||||
{
|
||||
grub_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
ret->fs = &grub_net_fs;
|
||||
return ret;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <grub/normal.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/tpm.h>
|
||||
#include <grub/verify.h>
|
||||
|
||||
/* Max digits for a char is 3 (0xFF is 255), similarly for an int it
|
||||
|
|
|
@ -314,6 +314,11 @@
|
|||
{ 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
|
||||
}
|
||||
|
||||
#define GRUB_EFI_SMBIOS3_TABLE_GUID \
|
||||
{ 0xf2fd1544, 0x9794, 0x4a2c, \
|
||||
{ 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94 } \
|
||||
}
|
||||
|
||||
#define GRUB_EFI_SAL_TABLE_GUID \
|
||||
{ 0xeb9d2d32, 0x2d88, 0x11d3, \
|
||||
{ 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
|
||||
|
|
|
@ -46,7 +46,8 @@ void *
|
|||
EXPORT_FUNC(grub_efi_allocate_fixed) (grub_efi_physical_address_t address,
|
||||
grub_efi_uintn_t pages);
|
||||
void *
|
||||
EXPORT_FUNC(grub_efi_allocate_any_pages) (grub_efi_uintn_t pages);
|
||||
EXPORT_FUNC(grub_efi_allocate_pages_max) (grub_efi_physical_address_t max,
|
||||
grub_efi_uintn_t pages);
|
||||
void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address,
|
||||
grub_efi_uintn_t pages);
|
||||
grub_efi_uintn_t EXPORT_FUNC(grub_efi_find_mmap_size) (void);
|
||||
|
@ -82,6 +83,7 @@ EXPORT_FUNC (grub_efi_set_variable) (const char *var,
|
|||
const grub_efi_guid_t *guid,
|
||||
void *data,
|
||||
grub_size_t datasize);
|
||||
grub_efi_boolean_t EXPORT_FUNC (grub_efi_secure_boot) (void);
|
||||
int
|
||||
EXPORT_FUNC (grub_efi_compare_device_paths) (const grub_efi_device_path_t *dp1,
|
||||
const grub_efi_device_path_t *dp2);
|
||||
|
|
|
@ -132,14 +132,12 @@ typedef struct tdEFI_TCG2_BOOT_SERVICE_CAPABILITY EFI_TCG2_BOOT_SERVICE_CAPABILI
|
|||
typedef grub_efi_uint32_t TCG_PCRINDEX;
|
||||
typedef grub_efi_uint32_t TCG_EVENTTYPE;
|
||||
|
||||
struct tdEFI_TCG2_EVENT_HEADER
|
||||
{
|
||||
typedef struct tdEFI_TCG2_EVENT_HEADER {
|
||||
grub_efi_uint32_t HeaderSize;
|
||||
grub_efi_uint16_t HeaderVersion;
|
||||
TCG_PCRINDEX PCRIndex;
|
||||
TCG_EVENTTYPE EventType;
|
||||
} GRUB_PACKED;
|
||||
typedef struct tdEFI_TCG2_EVENT_HEADER EFI_TCG2_EVENT_HEADER;
|
||||
TCG_PCRINDEX PCRIndex;
|
||||
TCG_EVENTTYPE EventType;
|
||||
} GRUB_PACKED EFI_TCG2_EVENT_HEADER;
|
||||
|
||||
struct tdEFI_TCG2_EVENT
|
||||
{
|
||||
|
@ -161,7 +159,7 @@ struct grub_efi_tpm2_protocol
|
|||
EventLogLocation,
|
||||
grub_efi_physical_address_t *
|
||||
EventLogLastEntry,
|
||||
grub_efi_boolean_t * EventLogTruncated);
|
||||
grub_efi_boolean_t *EventLogTruncated);
|
||||
grub_efi_status_t (*hash_log_extend_event) (struct grub_efi_tpm2_protocol *
|
||||
this, grub_efi_uint64_t Flags,
|
||||
grub_efi_physical_address_t
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <grub/types.h>
|
||||
#include <grub/partition.h>
|
||||
#include <grub/msdos_partition.h>
|
||||
|
||||
struct grub_gpt_part_guid
|
||||
{
|
||||
|
@ -31,24 +32,43 @@ struct grub_gpt_part_guid
|
|||
} GRUB_PACKED;
|
||||
typedef struct grub_gpt_part_guid grub_gpt_part_guid_t;
|
||||
|
||||
#define GRUB_GPT_PARTITION_TYPE_EMPTY \
|
||||
{ 0x0, 0x0, 0x0, \
|
||||
{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } \
|
||||
/* Format the raw little-endian GUID as a newly allocated string. */
|
||||
char * grub_gpt_guid_to_str (grub_gpt_part_guid_t *guid);
|
||||
|
||||
|
||||
#define GRUB_GPT_GUID_INIT(a, b, c, d1, d2, d3, d4, d5, d6, d7, d8) \
|
||||
{ \
|
||||
grub_cpu_to_le32_compile_time (a), \
|
||||
grub_cpu_to_le16_compile_time (b), \
|
||||
grub_cpu_to_le16_compile_time (c), \
|
||||
{ d1, d2, d3, d4, d5, d6, d7, d8 } \
|
||||
}
|
||||
|
||||
#define GRUB_GPT_PARTITION_TYPE_EMPTY \
|
||||
GRUB_GPT_GUID_INIT (0x0, 0x0, 0x0, \
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
|
||||
|
||||
#define GRUB_GPT_PARTITION_TYPE_EFI_SYSTEM \
|
||||
GRUB_GPT_GUID_INIT (0xc12a7328, 0xf81f, 0x11d2, \
|
||||
0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b)
|
||||
|
||||
#define GRUB_GPT_PARTITION_TYPE_BIOS_BOOT \
|
||||
{ grub_cpu_to_le32_compile_time (0x21686148), \
|
||||
grub_cpu_to_le16_compile_time (0x6449), \
|
||||
grub_cpu_to_le16_compile_time (0x6e6f), \
|
||||
{ 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } \
|
||||
}
|
||||
GRUB_GPT_GUID_INIT (0x21686148, 0x6449, 0x6e6f, \
|
||||
0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49)
|
||||
|
||||
#define GRUB_GPT_PARTITION_TYPE_LDM \
|
||||
{ grub_cpu_to_le32_compile_time (0x5808C8AAU),\
|
||||
grub_cpu_to_le16_compile_time (0x7E8F), \
|
||||
grub_cpu_to_le16_compile_time (0x42E0), \
|
||||
{ 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF, 0xB3 } \
|
||||
}
|
||||
GRUB_GPT_GUID_INIT (0x5808c8aa, 0x7e8f, 0x42e0, \
|
||||
0x85, 0xd2, 0xe1, 0xe9, 0x04, 0x34, 0xcf, 0xb3)
|
||||
|
||||
#define GRUB_GPT_PARTITION_TYPE_USR_X86_64 \
|
||||
GRUB_GPT_GUID_INIT (0x5dfbf5f4, 0x2848, 0x4bac, \
|
||||
0xaa, 0x5e, 0x0d, 0x9a, 0x20, 0xb7, 0x45, 0xa6)
|
||||
|
||||
#define GRUB_GPT_HEADER_MAGIC \
|
||||
{ 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54 }
|
||||
|
||||
#define GRUB_GPT_HEADER_VERSION \
|
||||
grub_cpu_to_le32_compile_time (0x00010000U)
|
||||
|
||||
struct grub_gpt_header
|
||||
{
|
||||
|
@ -57,11 +77,11 @@ struct grub_gpt_header
|
|||
grub_uint32_t headersize;
|
||||
grub_uint32_t crc32;
|
||||
grub_uint32_t unused1;
|
||||
grub_uint64_t primary;
|
||||
grub_uint64_t backup;
|
||||
grub_uint64_t header_lba;
|
||||
grub_uint64_t alternate_lba;
|
||||
grub_uint64_t start;
|
||||
grub_uint64_t end;
|
||||
grub_uint8_t guid[16];
|
||||
grub_gpt_part_guid_t guid;
|
||||
grub_uint64_t partitions;
|
||||
grub_uint32_t maxpart;
|
||||
grub_uint32_t partentry_size;
|
||||
|
@ -75,13 +95,172 @@ struct grub_gpt_partentry
|
|||
grub_uint64_t start;
|
||||
grub_uint64_t end;
|
||||
grub_uint64_t attrib;
|
||||
char name[72];
|
||||
grub_uint16_t name[36];
|
||||
} GRUB_PACKED;
|
||||
|
||||
enum grub_gpt_part_attr_offset
|
||||
{
|
||||
/* Standard partition attribute bits defined by UEFI. */
|
||||
GRUB_GPT_PART_ATTR_OFFSET_REQUIRED = 0,
|
||||
GRUB_GPT_PART_ATTR_OFFSET_NO_BLOCK_IO_PROTOCOL = 1,
|
||||
GRUB_GPT_PART_ATTR_OFFSET_LEGACY_BIOS_BOOTABLE = 2,
|
||||
|
||||
/* De facto standard attribute bits defined by Microsoft and reused by
|
||||
* http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec */
|
||||
GRUB_GPT_PART_ATTR_OFFSET_READ_ONLY = 60,
|
||||
GRUB_GPT_PART_ATTR_OFFSET_NO_AUTO = 63,
|
||||
|
||||
/* Partition attributes for priority based selection,
|
||||
* Currently only valid for PARTITION_TYPE_USR_X86_64.
|
||||
* TRIES_LEFT and PRIORITY are 4 bit wide fields. */
|
||||
GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_PRIORITY = 48,
|
||||
GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_TRIES_LEFT = 52,
|
||||
GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_SUCCESSFUL = 56,
|
||||
};
|
||||
|
||||
/* Helpers for reading/writing partition attributes. */
|
||||
static inline grub_uint64_t
|
||||
grub_gpt_entry_attribute (struct grub_gpt_partentry *entry,
|
||||
enum grub_gpt_part_attr_offset offset,
|
||||
unsigned int bits)
|
||||
{
|
||||
grub_uint64_t attrib = grub_le_to_cpu64 (entry->attrib);
|
||||
|
||||
return (attrib >> offset) & ((1ULL << bits) - 1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
grub_gpt_entry_set_attribute (struct grub_gpt_partentry *entry,
|
||||
grub_uint64_t value,
|
||||
enum grub_gpt_part_attr_offset offset,
|
||||
unsigned int bits)
|
||||
{
|
||||
grub_uint64_t attrib, mask;
|
||||
|
||||
mask = (((1ULL << bits) - 1) << offset);
|
||||
attrib = grub_le_to_cpu64 (entry->attrib) & ~mask;
|
||||
attrib |= ((value << offset) & mask);
|
||||
entry->attrib = grub_cpu_to_le64 (attrib);
|
||||
}
|
||||
|
||||
/* Basic GPT partmap module. */
|
||||
grub_err_t
|
||||
grub_gpt_partition_map_iterate (grub_disk_t disk,
|
||||
grub_partition_iterate_hook_t hook,
|
||||
void *hook_data);
|
||||
|
||||
/* Advanced GPT library. */
|
||||
|
||||
/* Status bits for the grub_gpt.status field. */
|
||||
#define GRUB_GPT_PROTECTIVE_MBR 0x01
|
||||
#define GRUB_GPT_HYBRID_MBR 0x02
|
||||
#define GRUB_GPT_PRIMARY_HEADER_VALID 0x04
|
||||
#define GRUB_GPT_PRIMARY_ENTRIES_VALID 0x08
|
||||
#define GRUB_GPT_BACKUP_HEADER_VALID 0x10
|
||||
#define GRUB_GPT_BACKUP_ENTRIES_VALID 0x20
|
||||
|
||||
/* UEFI requires the entries table to be at least 16384 bytes for a
|
||||
* total of 128 entries given the standard 128 byte entry size. */
|
||||
#define GRUB_GPT_DEFAULT_ENTRIES_SIZE 16384
|
||||
#define GRUB_GPT_DEFAULT_ENTRIES_LENGTH \
|
||||
(GRUB_GPT_DEFAULT_ENTRIES_SIZE / sizeof (struct grub_gpt_partentry))
|
||||
|
||||
struct grub_gpt
|
||||
{
|
||||
/* Bit field indicating which structures on disk are valid. */
|
||||
unsigned status;
|
||||
|
||||
/* Protective or hybrid MBR. */
|
||||
struct grub_msdos_partition_mbr mbr;
|
||||
|
||||
/* Each of the two GPT headers. */
|
||||
struct grub_gpt_header primary;
|
||||
struct grub_gpt_header backup;
|
||||
|
||||
/* Only need one entries table, on disk both copies are identical.
|
||||
* The on disk entry size may be larger than our partentry struct so
|
||||
* the table cannot be indexed directly. */
|
||||
void *entries;
|
||||
grub_size_t entries_size;
|
||||
|
||||
/* Logarithm of sector size, in case GPT and disk driver disagree. */
|
||||
unsigned int log_sector_size;
|
||||
};
|
||||
typedef struct grub_gpt *grub_gpt_t;
|
||||
|
||||
/* Helpers for checking the gpt status field. */
|
||||
static inline int
|
||||
grub_gpt_mbr_valid (grub_gpt_t gpt)
|
||||
{
|
||||
return ((gpt->status & GRUB_GPT_PROTECTIVE_MBR) ||
|
||||
(gpt->status & GRUB_GPT_HYBRID_MBR));
|
||||
}
|
||||
|
||||
static inline int
|
||||
grub_gpt_primary_valid (grub_gpt_t gpt)
|
||||
{
|
||||
return ((gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) &&
|
||||
(gpt->status & GRUB_GPT_PRIMARY_ENTRIES_VALID));
|
||||
}
|
||||
|
||||
static inline int
|
||||
grub_gpt_backup_valid (grub_gpt_t gpt)
|
||||
{
|
||||
return ((gpt->status & GRUB_GPT_BACKUP_HEADER_VALID) &&
|
||||
(gpt->status & GRUB_GPT_BACKUP_ENTRIES_VALID));
|
||||
}
|
||||
|
||||
static inline int
|
||||
grub_gpt_both_valid (grub_gpt_t gpt)
|
||||
{
|
||||
return grub_gpt_primary_valid (gpt) && grub_gpt_backup_valid (gpt);
|
||||
}
|
||||
|
||||
/* Translate GPT sectors to GRUB's 512 byte block addresses. */
|
||||
static inline grub_disk_addr_t
|
||||
grub_gpt_sector_to_addr (grub_gpt_t gpt, grub_uint64_t sector)
|
||||
{
|
||||
return (sector << (gpt->log_sector_size - GRUB_DISK_SECTOR_BITS));
|
||||
}
|
||||
|
||||
/* Allocates and fills new grub_gpt structure, free with grub_gpt_free. */
|
||||
grub_gpt_t grub_gpt_read (grub_disk_t disk);
|
||||
|
||||
/* Helper for indexing into the entries table.
|
||||
* Returns NULL when the end of the table has been reached. */
|
||||
struct grub_gpt_partentry * grub_gpt_get_partentry (grub_gpt_t gpt,
|
||||
grub_uint32_t n);
|
||||
|
||||
/* Sync and update primary and backup headers if either are invalid. */
|
||||
grub_err_t grub_gpt_repair (grub_disk_t disk, grub_gpt_t gpt);
|
||||
|
||||
/* Recompute checksums and revalidate everything, must be called after
|
||||
* modifying any GPT data. */
|
||||
grub_err_t grub_gpt_update (grub_gpt_t gpt);
|
||||
|
||||
/* Write headers and entry tables back to disk. */
|
||||
grub_err_t grub_gpt_write (grub_disk_t disk, grub_gpt_t gpt);
|
||||
|
||||
void grub_gpt_free (grub_gpt_t gpt);
|
||||
|
||||
grub_err_t grub_gpt_pmbr_check (struct grub_msdos_partition_mbr *mbr);
|
||||
grub_err_t grub_gpt_header_check (struct grub_gpt_header *gpt,
|
||||
unsigned int log_sector_size);
|
||||
|
||||
|
||||
/* Utilities for simple partition data lookups, usage is intended to
|
||||
* be similar to fs->label and fs->uuid functions. */
|
||||
|
||||
/* Return the partition label of the device DEVICE in LABEL.
|
||||
* The label is in a new buffer and should be freed by the caller. */
|
||||
grub_err_t grub_gpt_part_label (grub_device_t device, char **label);
|
||||
|
||||
/* Return the partition uuid of the device DEVICE in UUID.
|
||||
* The uuid is in a new buffer and should be freed by the caller. */
|
||||
grub_err_t grub_gpt_part_uuid (grub_device_t device, char **uuid);
|
||||
|
||||
/* Return the disk uuid of the device DEVICE in UUID.
|
||||
* The uuid is in a new buffer and should be freed by the caller. */
|
||||
grub_err_t grub_gpt_disk_uuid (grub_device_t device, char **uuid);
|
||||
|
||||
#endif /* ! GRUB_GPT_PARTITION_HEADER */
|
||||
|
|
|
@ -276,6 +276,7 @@ typedef struct grub_net
|
|||
grub_fs_t fs;
|
||||
int eof;
|
||||
int stall;
|
||||
int port;
|
||||
} *grub_net_t;
|
||||
|
||||
extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name);
|
||||
|
|
|
@ -25,5 +25,11 @@ void grub_search_fs_uuid (const char *key, const char *var, int no_floppy,
|
|||
char **hints, unsigned nhints);
|
||||
void grub_search_label (const char *key, const char *var, int no_floppy,
|
||||
char **hints, unsigned nhints);
|
||||
void grub_search_part_uuid (const char *key, const char *var, int no_floppy,
|
||||
char **hints, unsigned nhints);
|
||||
void grub_search_part_label (const char *key, const char *var, int no_floppy,
|
||||
char **hints, unsigned nhints);
|
||||
void grub_search_disk_uuid (const char *key, const char *var, int no_floppy,
|
||||
char **hints, unsigned nhints);
|
||||
|
||||
#endif
|
||||
|
|
68
include/grub/smbios.h
Normal file
68
include/grub/smbios.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRUB_SMBIOS_HEADER
|
||||
#define GRUB_SMBIOS_HEADER 1
|
||||
|
||||
#include <grub/types.h>
|
||||
|
||||
#define GRUB_SMBIOS_TYPE_END_OF_TABLE ((grub_uint8_t)127)
|
||||
|
||||
struct grub_smbios_ieps
|
||||
{
|
||||
grub_uint8_t anchor[5]; /* "_DMI_" */
|
||||
grub_uint8_t checksum;
|
||||
grub_uint16_t table_length;
|
||||
grub_uint32_t table_address;
|
||||
grub_uint16_t structures;
|
||||
grub_uint8_t revision;
|
||||
} GRUB_PACKED;
|
||||
|
||||
struct grub_smbios_eps
|
||||
{
|
||||
grub_uint8_t anchor[4]; /* "_SM_" */
|
||||
grub_uint8_t checksum;
|
||||
grub_uint8_t length; /* 0x1f */
|
||||
grub_uint8_t version_major;
|
||||
grub_uint8_t version_minor;
|
||||
grub_uint16_t maximum_structure_size;
|
||||
grub_uint8_t revision;
|
||||
grub_uint8_t formatted[5];
|
||||
struct grub_smbios_ieps intermediate;
|
||||
} GRUB_PACKED;
|
||||
|
||||
struct grub_smbios_eps3
|
||||
{
|
||||
grub_uint8_t anchor[5]; /* "_SM3_" */
|
||||
grub_uint8_t checksum;
|
||||
grub_uint8_t length; /* 0x18 */
|
||||
grub_uint8_t version_major;
|
||||
grub_uint8_t version_minor;
|
||||
grub_uint8_t docrev;
|
||||
grub_uint8_t revision;
|
||||
grub_uint8_t reserved;
|
||||
grub_uint32_t maximum_table_length;
|
||||
grub_uint64_t table_address;
|
||||
} GRUB_PACKED;
|
||||
|
||||
struct grub_smbios_eps *grub_smbios_get_eps (void);
|
||||
struct grub_smbios_eps3 *grub_smbios_get_eps3 (void);
|
||||
struct grub_smbios_eps *grub_machine_smbios_get_eps (void);
|
||||
struct grub_smbios_eps3 *grub_machine_smbios_get_eps3 (void);
|
||||
|
||||
#endif /* ! GRUB_SMBIOS_HEADER */
|
51
include/grub/verity-hash.h
Normal file
51
include/grub/verity-hash.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/* CoreOS verity hash */
|
||||
|
||||
#define VERITY_ARG " verity.usrhash="
|
||||
#define VERITY_ARG_LENGTH (sizeof (VERITY_ARG) - 1)
|
||||
#define VERITY_HASH_LENGTH 64
|
||||
#define VERITY_CMDLINE_LENGTH ((VERITY_ARG_LENGTH)+(VERITY_HASH_LENGTH))
|
||||
|
||||
#if defined(__aarch64__)
|
||||
# define VERITY_HASH_OFFSET 512
|
||||
#elif defined(__i386__) || defined(__amd64__)
|
||||
# define VERITY_HASH_OFFSET 0x40
|
||||
#else
|
||||
# error Unsupported arch
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* grub_pass_verity_hash - Reads the CoreOS verity hash value from a well known
|
||||
* kernel image offset and adds a kernel command line argument for it.
|
||||
*
|
||||
* @pImage: Kernel image buffer.
|
||||
* @cmdline: Kernel command line buffer.
|
||||
* @cmdline_max_len: Kernel command line buffer length.
|
||||
*/
|
||||
|
||||
static inline void grub_pass_verity_hash(const void *pImage,
|
||||
char *cmdline,
|
||||
grub_size_t cmdline_max_len)
|
||||
{
|
||||
const char *buf = pImage;
|
||||
grub_size_t cmdline_len;
|
||||
int i;
|
||||
|
||||
for (i=VERITY_HASH_OFFSET; i<VERITY_HASH_OFFSET + VERITY_HASH_LENGTH; i++)
|
||||
{
|
||||
if (buf[i] < '0' || buf[i] > '9') // Not a number
|
||||
if (buf[i] < 'a' || buf[i] > 'f') // Not a hex letter
|
||||
return;
|
||||
}
|
||||
|
||||
cmdline_len = grub_strlen(cmdline);
|
||||
if (cmdline_len + VERITY_CMDLINE_LENGTH > cmdline_max_len)
|
||||
return;
|
||||
|
||||
grub_memcpy (cmdline + cmdline_len, VERITY_ARG, VERITY_ARG_LENGTH);
|
||||
cmdline_len += VERITY_ARG_LENGTH;
|
||||
grub_memcpy (cmdline + cmdline_len, buf + VERITY_HASH_OFFSET,
|
||||
VERITY_HASH_LENGTH);
|
||||
cmdline_len += VERITY_HASH_LENGTH;
|
||||
cmdline[cmdline_len] = '\0';
|
||||
}
|
|
@ -24,6 +24,9 @@
|
|||
#include <grub/elfload.h>
|
||||
|
||||
grub_elf_t grub_xen_file (grub_file_t file);
|
||||
grub_elf_t grub_xen_file_and_cmdline (grub_file_t file,
|
||||
char *cmdline,
|
||||
grub_size_t cmdline_max_len);
|
||||
|
||||
struct grub_xen_file_info
|
||||
{
|
||||
|
|
840
tests/gpt_unit_test.c
Normal file
840
tests/gpt_unit_test.c
Normal file
|
@ -0,0 +1,840 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2014 CoreOS, 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/command.h>
|
||||
#include <grub/device.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/emu/hostdisk.h>
|
||||
#include <grub/emu/misc.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/gpt_partition.h>
|
||||
#include <grub/msdos_partition.h>
|
||||
#include <grub/lib/hexdump.h>
|
||||
#include <grub/search.h>
|
||||
#include <grub/test.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* from gnulib */
|
||||
#include <verify.h>
|
||||
|
||||
/* Confirm that the GPT structures conform to the sizes in the spec:
|
||||
* The header size "must be greater than or equal to 92 and must be less
|
||||
* than or equal to the logical block size."
|
||||
* The partition entry size must be "a value of 128*(2^n) where n is an
|
||||
* integer greater than or equal to zero (e.g., 128, 256, 512, etc.)." */
|
||||
verify (sizeof (struct grub_gpt_header) == 92);
|
||||
verify (sizeof (struct grub_gpt_partentry) == 128);
|
||||
|
||||
/* GPT section sizes. */
|
||||
#define HEADER_SIZE (sizeof (struct grub_gpt_header))
|
||||
#define HEADER_PAD (GRUB_DISK_SECTOR_SIZE - HEADER_SIZE)
|
||||
#define ENTRY_SIZE (sizeof (struct grub_gpt_partentry))
|
||||
#define TABLE_ENTRIES 0x80
|
||||
#define TABLE_SIZE (TABLE_ENTRIES * ENTRY_SIZE)
|
||||
#define TABLE_SECTORS (TABLE_SIZE / GRUB_DISK_SECTOR_SIZE)
|
||||
|
||||
/* Double check that the table size calculation was valid. */
|
||||
verify (TABLE_SECTORS * GRUB_DISK_SECTOR_SIZE == TABLE_SIZE);
|
||||
|
||||
/* GPT section locations for a 1MiB disk. */
|
||||
#define DISK_SECTORS 0x800
|
||||
#define DISK_SIZE (GRUB_DISK_SECTOR_SIZE * DISK_SECTORS)
|
||||
#define PRIMARY_HEADER_SECTOR 0x1
|
||||
#define PRIMARY_TABLE_SECTOR 0x2
|
||||
#define BACKUP_HEADER_SECTOR (DISK_SECTORS - 0x1)
|
||||
#define BACKUP_TABLE_SECTOR (BACKUP_HEADER_SECTOR - TABLE_SECTORS)
|
||||
|
||||
#define DATA_START_SECTOR (PRIMARY_TABLE_SECTOR + TABLE_SECTORS)
|
||||
#define DATA_END_SECTOR (BACKUP_TABLE_SECTOR - 0x1)
|
||||
#define DATA_SECTORS (BACKUP_TABLE_SECTOR - DATA_START_SECTOR)
|
||||
#define DATA_SIZE (GRUB_DISK_SECTOR_SIZE * DATA_SECTORS)
|
||||
|
||||
struct test_disk
|
||||
{
|
||||
struct grub_msdos_partition_mbr mbr;
|
||||
|
||||
struct grub_gpt_header primary_header;
|
||||
grub_uint8_t primary_header_pad[HEADER_PAD];
|
||||
struct grub_gpt_partentry primary_entries[TABLE_ENTRIES];
|
||||
|
||||
grub_uint8_t data[DATA_SIZE];
|
||||
|
||||
struct grub_gpt_partentry backup_entries[TABLE_ENTRIES];
|
||||
struct grub_gpt_header backup_header;
|
||||
grub_uint8_t backup_header_pad[HEADER_PAD];
|
||||
} GRUB_PACKED;
|
||||
|
||||
/* Sanity check that all the above ugly math was correct. */
|
||||
verify (sizeof (struct test_disk) == DISK_SIZE);
|
||||
|
||||
struct test_data
|
||||
{
|
||||
int fd;
|
||||
grub_device_t dev;
|
||||
struct test_disk *raw;
|
||||
};
|
||||
|
||||
|
||||
/* Sample primary GPT header for a 1MB disk. */
|
||||
static const struct grub_gpt_header example_primary = {
|
||||
.magic = GRUB_GPT_HEADER_MAGIC,
|
||||
.version = GRUB_GPT_HEADER_VERSION,
|
||||
.headersize = sizeof (struct grub_gpt_header),
|
||||
.crc32 = grub_cpu_to_le32_compile_time (0xb985abe0),
|
||||
.header_lba = grub_cpu_to_le64_compile_time (PRIMARY_HEADER_SECTOR),
|
||||
.alternate_lba = grub_cpu_to_le64_compile_time (BACKUP_HEADER_SECTOR),
|
||||
.start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR),
|
||||
.end = grub_cpu_to_le64_compile_time (DATA_END_SECTOR),
|
||||
.guid = GRUB_GPT_GUID_INIT(0x69c131ad, 0x67d6, 0x46c6,
|
||||
0x93, 0xc4, 0x12, 0x4c, 0x75, 0x52, 0x56, 0xac),
|
||||
.partitions = grub_cpu_to_le64_compile_time (PRIMARY_TABLE_SECTOR),
|
||||
.maxpart = grub_cpu_to_le32_compile_time (TABLE_ENTRIES),
|
||||
.partentry_size = grub_cpu_to_le32_compile_time (ENTRY_SIZE),
|
||||
.partentry_crc32 = grub_cpu_to_le32_compile_time (0x074e052c),
|
||||
};
|
||||
|
||||
static const struct grub_gpt_partentry example_entries[TABLE_ENTRIES] = {
|
||||
{
|
||||
.type = GRUB_GPT_PARTITION_TYPE_EFI_SYSTEM,
|
||||
.guid = GRUB_GPT_GUID_INIT (0xa0f1792e, 0xb4ce, 0x4136, 0xbc, 0xf2,
|
||||
0x1a, 0xfc, 0x13, 0x3c, 0x28, 0x28),
|
||||
.start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR),
|
||||
.end = grub_cpu_to_le64_compile_time (0x3f),
|
||||
.attrib = 0x0,
|
||||
.name = {
|
||||
grub_cpu_to_le16_compile_time ('E'),
|
||||
grub_cpu_to_le16_compile_time ('F'),
|
||||
grub_cpu_to_le16_compile_time ('I'),
|
||||
grub_cpu_to_le16_compile_time (' '),
|
||||
grub_cpu_to_le16_compile_time ('S'),
|
||||
grub_cpu_to_le16_compile_time ('Y'),
|
||||
grub_cpu_to_le16_compile_time ('S'),
|
||||
grub_cpu_to_le16_compile_time ('T'),
|
||||
grub_cpu_to_le16_compile_time ('E'),
|
||||
grub_cpu_to_le16_compile_time ('M'),
|
||||
0x0,
|
||||
}
|
||||
},
|
||||
{
|
||||
.type = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT,
|
||||
.guid = GRUB_GPT_GUID_INIT (0x876c898d, 0x1b40, 0x4727, 0xa1, 0x61,
|
||||
0xed, 0xf9, 0xb5, 0x48, 0x66, 0x74),
|
||||
.start = grub_cpu_to_le64_compile_time (0x40),
|
||||
.end = grub_cpu_to_le64_compile_time (0x7f),
|
||||
.attrib = grub_cpu_to_le64_compile_time (
|
||||
1ULL << GRUB_GPT_PART_ATTR_OFFSET_LEGACY_BIOS_BOOTABLE),
|
||||
.name = {
|
||||
grub_cpu_to_le16_compile_time ('B'),
|
||||
grub_cpu_to_le16_compile_time ('I'),
|
||||
grub_cpu_to_le16_compile_time ('O'),
|
||||
grub_cpu_to_le16_compile_time ('S'),
|
||||
grub_cpu_to_le16_compile_time (' '),
|
||||
grub_cpu_to_le16_compile_time ('B'),
|
||||
grub_cpu_to_le16_compile_time ('O'),
|
||||
grub_cpu_to_le16_compile_time ('O'),
|
||||
grub_cpu_to_le16_compile_time ('T'),
|
||||
0x0,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/* And the backup header. */
|
||||
static const struct grub_gpt_header example_backup = {
|
||||
.magic = GRUB_GPT_HEADER_MAGIC,
|
||||
.version = GRUB_GPT_HEADER_VERSION,
|
||||
.headersize = sizeof (struct grub_gpt_header),
|
||||
.crc32 = grub_cpu_to_le32_compile_time (0x0af785eb),
|
||||
.header_lba = grub_cpu_to_le64_compile_time (BACKUP_HEADER_SECTOR),
|
||||
.alternate_lba = grub_cpu_to_le64_compile_time (PRIMARY_HEADER_SECTOR),
|
||||
.start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR),
|
||||
.end = grub_cpu_to_le64_compile_time (DATA_END_SECTOR),
|
||||
.guid = GRUB_GPT_GUID_INIT(0x69c131ad, 0x67d6, 0x46c6,
|
||||
0x93, 0xc4, 0x12, 0x4c, 0x75, 0x52, 0x56, 0xac),
|
||||
.partitions = grub_cpu_to_le64_compile_time (BACKUP_TABLE_SECTOR),
|
||||
.maxpart = grub_cpu_to_le32_compile_time (TABLE_ENTRIES),
|
||||
.partentry_size = grub_cpu_to_le32_compile_time (ENTRY_SIZE),
|
||||
.partentry_crc32 = grub_cpu_to_le32_compile_time (0x074e052c),
|
||||
};
|
||||
|
||||
/* Sample protective MBR for the same 1MB disk. Note, this matches
|
||||
* parted and fdisk behavior. The UEFI spec uses different values. */
|
||||
static const struct grub_msdos_partition_mbr example_pmbr = {
|
||||
.entries = {{.flag = 0x00,
|
||||
.start_head = 0x00,
|
||||
.start_sector = 0x01,
|
||||
.start_cylinder = 0x00,
|
||||
.type = 0xee,
|
||||
.end_head = 0xfe,
|
||||
.end_sector = 0xff,
|
||||
.end_cylinder = 0xff,
|
||||
.start = grub_cpu_to_le32_compile_time (0x1),
|
||||
.length = grub_cpu_to_le32_compile_time (DISK_SECTORS - 0x1),
|
||||
}},
|
||||
.signature = grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE),
|
||||
};
|
||||
|
||||
/* If errors are left in grub's error stack things can get confused. */
|
||||
static void
|
||||
assert_error_stack_empty (void)
|
||||
{
|
||||
do
|
||||
{
|
||||
grub_test_assert (grub_errno == GRUB_ERR_NONE,
|
||||
"error on stack: %s", grub_errmsg);
|
||||
}
|
||||
while (grub_error_pop ());
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
execute_command2 (const char *name, const char *arg1, const char *arg2)
|
||||
{
|
||||
grub_command_t cmd;
|
||||
grub_err_t err;
|
||||
char *argv[2];
|
||||
|
||||
cmd = grub_command_find (name);
|
||||
if (!cmd)
|
||||
grub_fatal ("can't find command %s", name);
|
||||
|
||||
argv[0] = strdup (arg1);
|
||||
argv[1] = strdup (arg2);
|
||||
err = (cmd->func) (cmd, 2, argv);
|
||||
free (argv[0]);
|
||||
free (argv[1]);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
sync_disk (struct test_data *data)
|
||||
{
|
||||
if (msync (data->raw, DISK_SIZE, MS_SYNC | MS_INVALIDATE) < 0)
|
||||
grub_fatal ("Syncing disk failed: %s", strerror (errno));
|
||||
|
||||
grub_disk_cache_invalidate_all ();
|
||||
}
|
||||
|
||||
static void
|
||||
reset_disk (struct test_data *data)
|
||||
{
|
||||
memset (data->raw, 0, DISK_SIZE);
|
||||
|
||||
/* Initialize image with valid example tables. */
|
||||
memcpy (&data->raw->mbr, &example_pmbr, sizeof (data->raw->mbr));
|
||||
memcpy (&data->raw->primary_header, &example_primary,
|
||||
sizeof (data->raw->primary_header));
|
||||
memcpy (&data->raw->primary_entries, &example_entries,
|
||||
sizeof (data->raw->primary_entries));
|
||||
memcpy (&data->raw->backup_entries, &example_entries,
|
||||
sizeof (data->raw->backup_entries));
|
||||
memcpy (&data->raw->backup_header, &example_backup,
|
||||
sizeof (data->raw->backup_header));
|
||||
|
||||
sync_disk (data);
|
||||
}
|
||||
|
||||
static void
|
||||
open_disk (struct test_data *data)
|
||||
{
|
||||
const char *loop = "loop0";
|
||||
char template[] = "/tmp/grub_gpt_test.XXXXXX";
|
||||
char host[sizeof ("(host)") + sizeof (template)];
|
||||
|
||||
data->fd = mkstemp (template);
|
||||
if (data->fd < 0)
|
||||
grub_fatal ("Creating %s failed: %s", template, strerror (errno));
|
||||
|
||||
if (ftruncate (data->fd, DISK_SIZE) < 0)
|
||||
{
|
||||
int err = errno;
|
||||
unlink (template);
|
||||
grub_fatal ("Resizing %s failed: %s", template, strerror (err));
|
||||
}
|
||||
|
||||
data->raw = mmap (NULL, DISK_SIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, data->fd, 0);
|
||||
if (data->raw == MAP_FAILED)
|
||||
{
|
||||
int err = errno;
|
||||
unlink (template);
|
||||
grub_fatal ("Maping %s failed: %s", template, strerror (err));
|
||||
}
|
||||
|
||||
snprintf (host, sizeof (host), "(host)%s", template);
|
||||
if (execute_command2 ("loopback", loop, host) != GRUB_ERR_NONE)
|
||||
{
|
||||
unlink (template);
|
||||
grub_fatal ("loopback %s %s failed: %s", loop, host, grub_errmsg);
|
||||
}
|
||||
|
||||
if (unlink (template) < 0)
|
||||
grub_fatal ("Unlinking %s failed: %s", template, strerror (errno));
|
||||
|
||||
reset_disk (data);
|
||||
|
||||
data->dev = grub_device_open (loop);
|
||||
if (!data->dev)
|
||||
grub_fatal ("Opening %s failed: %s", loop, grub_errmsg);
|
||||
}
|
||||
|
||||
static void
|
||||
close_disk (struct test_data *data)
|
||||
{
|
||||
char *loop;
|
||||
|
||||
assert_error_stack_empty ();
|
||||
|
||||
if (munmap (data->raw, DISK_SIZE) || close (data->fd))
|
||||
grub_fatal ("Closing disk image failed: %s", strerror (errno));
|
||||
|
||||
loop = strdup (data->dev->disk->name);
|
||||
grub_test_assert (grub_device_close (data->dev) == GRUB_ERR_NONE,
|
||||
"Closing disk device failed: %s", grub_errmsg);
|
||||
|
||||
grub_test_assert (execute_command2 ("loopback", "-d", loop) ==
|
||||
GRUB_ERR_NONE, "loopback -d %s failed: %s", loop,
|
||||
grub_errmsg);
|
||||
|
||||
free (loop);
|
||||
}
|
||||
|
||||
static grub_gpt_t
|
||||
read_disk (struct test_data *data)
|
||||
{
|
||||
grub_gpt_t gpt;
|
||||
|
||||
gpt = grub_gpt_read (data->dev->disk);
|
||||
if (gpt == NULL)
|
||||
grub_fatal ("grub_gpt_read failed: %s", grub_errmsg);
|
||||
|
||||
return gpt;
|
||||
}
|
||||
|
||||
static void
|
||||
pmbr_test (void)
|
||||
{
|
||||
struct grub_msdos_partition_mbr mbr;
|
||||
|
||||
memset (&mbr, 0, sizeof (mbr));
|
||||
|
||||
/* Empty is invalid. */
|
||||
grub_gpt_pmbr_check (&mbr);
|
||||
grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE,
|
||||
"unexpected error: %s", grub_errmsg);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
/* A table without a protective partition is invalid. */
|
||||
mbr.signature = grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE);
|
||||
grub_gpt_pmbr_check (&mbr);
|
||||
grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE,
|
||||
"unexpected error: %s", grub_errmsg);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
/* A table with a protective type is ok. */
|
||||
memcpy (&mbr, &example_pmbr, sizeof (mbr));
|
||||
grub_gpt_pmbr_check (&mbr);
|
||||
grub_test_assert (grub_errno == GRUB_ERR_NONE,
|
||||
"unexpected error: %s", grub_errmsg);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
header_test (void)
|
||||
{
|
||||
struct grub_gpt_header primary, backup;
|
||||
|
||||
/* Example headers should be valid. */
|
||||
memcpy (&primary, &example_primary, sizeof (primary));
|
||||
grub_gpt_header_check (&primary, GRUB_DISK_SECTOR_BITS);
|
||||
grub_test_assert (grub_errno == GRUB_ERR_NONE,
|
||||
"unexpected error: %s", grub_errmsg);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
memcpy (&backup, &example_backup, sizeof (backup));
|
||||
grub_gpt_header_check (&backup, GRUB_DISK_SECTOR_BITS);
|
||||
grub_test_assert (grub_errno == GRUB_ERR_NONE,
|
||||
"unexpected error: %s", grub_errmsg);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
/* Twiddle the GUID to invalidate the CRC. */
|
||||
primary.guid.data1 = 0;
|
||||
grub_gpt_header_check (&primary, GRUB_DISK_SECTOR_BITS);
|
||||
grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE,
|
||||
"unexpected error: %s", grub_errmsg);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
backup.guid.data1 = 0;
|
||||
grub_gpt_header_check (&backup, GRUB_DISK_SECTOR_BITS);
|
||||
grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE,
|
||||
"unexpected error: %s", grub_errmsg);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
read_valid_test (void)
|
||||
{
|
||||
struct test_data data;
|
||||
grub_gpt_t gpt;
|
||||
|
||||
open_disk (&data);
|
||||
gpt = read_disk (&data);
|
||||
grub_test_assert (gpt->status == (GRUB_GPT_PROTECTIVE_MBR |
|
||||
GRUB_GPT_PRIMARY_HEADER_VALID |
|
||||
GRUB_GPT_PRIMARY_ENTRIES_VALID |
|
||||
GRUB_GPT_BACKUP_HEADER_VALID |
|
||||
GRUB_GPT_BACKUP_ENTRIES_VALID),
|
||||
"unexpected status: 0x%02x", gpt->status);
|
||||
grub_gpt_free (gpt);
|
||||
close_disk (&data);
|
||||
}
|
||||
|
||||
static void
|
||||
read_invalid_entries_test (void)
|
||||
{
|
||||
struct test_data data;
|
||||
grub_gpt_t gpt;
|
||||
|
||||
open_disk (&data);
|
||||
|
||||
/* Corrupt the first entry in both tables. */
|
||||
memset (&data.raw->primary_entries[0], 0x55,
|
||||
sizeof (data.raw->primary_entries[0]));
|
||||
memset (&data.raw->backup_entries[0], 0x55,
|
||||
sizeof (data.raw->backup_entries[0]));
|
||||
sync_disk (&data);
|
||||
|
||||
gpt = grub_gpt_read (data.dev->disk);
|
||||
grub_test_assert (gpt == NULL, "no error reported for corrupt entries");
|
||||
grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE,
|
||||
"unexpected error: %s", grub_errmsg);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
close_disk (&data);
|
||||
}
|
||||
|
||||
static void
|
||||
read_fallback_test (void)
|
||||
{
|
||||
struct test_data data;
|
||||
grub_gpt_t gpt;
|
||||
|
||||
open_disk (&data);
|
||||
|
||||
/* Corrupt the primary header. */
|
||||
memset (&data.raw->primary_header.guid, 0x55,
|
||||
sizeof (data.raw->primary_header.guid));
|
||||
sync_disk (&data);
|
||||
gpt = read_disk (&data);
|
||||
grub_test_assert ((gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) == 0,
|
||||
"unreported corrupt primary header");
|
||||
grub_gpt_free (gpt);
|
||||
reset_disk (&data);
|
||||
|
||||
/* Corrupt the backup header. */
|
||||
memset (&data.raw->backup_header.guid, 0x55,
|
||||
sizeof (data.raw->backup_header.guid));
|
||||
sync_disk (&data);
|
||||
gpt = read_disk (&data);
|
||||
grub_test_assert ((gpt->status & GRUB_GPT_BACKUP_HEADER_VALID) == 0,
|
||||
"unreported corrupt backup header");
|
||||
grub_gpt_free (gpt);
|
||||
reset_disk (&data);
|
||||
|
||||
/* Corrupt the primary entry table. */
|
||||
memset (&data.raw->primary_entries[0], 0x55,
|
||||
sizeof (data.raw->primary_entries[0]));
|
||||
sync_disk (&data);
|
||||
gpt = read_disk (&data);
|
||||
grub_test_assert ((gpt->status & GRUB_GPT_PRIMARY_ENTRIES_VALID) == 0,
|
||||
"unreported corrupt primary entries table");
|
||||
grub_gpt_free (gpt);
|
||||
reset_disk (&data);
|
||||
|
||||
/* Corrupt the backup entry table. */
|
||||
memset (&data.raw->backup_entries[0], 0x55,
|
||||
sizeof (data.raw->backup_entries[0]));
|
||||
sync_disk (&data);
|
||||
gpt = read_disk (&data);
|
||||
grub_test_assert ((gpt->status & GRUB_GPT_BACKUP_ENTRIES_VALID) == 0,
|
||||
"unreported corrupt backup entries table");
|
||||
grub_gpt_free (gpt);
|
||||
reset_disk (&data);
|
||||
|
||||
/* If primary is corrupt and disk size is unknown fallback fails. */
|
||||
memset (&data.raw->primary_header.guid, 0x55,
|
||||
sizeof (data.raw->primary_header.guid));
|
||||
sync_disk (&data);
|
||||
data.dev->disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN;
|
||||
gpt = grub_gpt_read (data.dev->disk);
|
||||
grub_test_assert (gpt == NULL, "no error reported");
|
||||
grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE,
|
||||
"unexpected error: %s", grub_errmsg);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
close_disk (&data);
|
||||
}
|
||||
|
||||
static void
|
||||
repair_test (void)
|
||||
{
|
||||
struct test_data data;
|
||||
grub_gpt_t gpt;
|
||||
|
||||
open_disk (&data);
|
||||
|
||||
/* Erase/Repair primary. */
|
||||
memset (&data.raw->primary_header, 0, sizeof (data.raw->primary_header));
|
||||
sync_disk (&data);
|
||||
gpt = read_disk (&data);
|
||||
grub_gpt_repair (data.dev->disk, gpt);
|
||||
grub_test_assert (grub_errno == GRUB_ERR_NONE,
|
||||
"repair failed: %s", grub_errmsg);
|
||||
if (memcmp (&gpt->primary, &example_primary, sizeof (gpt->primary)))
|
||||
{
|
||||
printf ("Invalid restored primary header:\n");
|
||||
hexdump (16, (char*)&gpt->primary, sizeof (gpt->primary));
|
||||
printf ("Expected primary header:\n");
|
||||
hexdump (16, (char*)&example_primary, sizeof (example_primary));
|
||||
grub_test_assert (0, "repair did not restore primary header");
|
||||
}
|
||||
grub_gpt_free (gpt);
|
||||
reset_disk (&data);
|
||||
|
||||
/* Erase/Repair backup. */
|
||||
memset (&data.raw->backup_header, 0, sizeof (data.raw->backup_header));
|
||||
sync_disk (&data);
|
||||
gpt = read_disk (&data);
|
||||
grub_gpt_repair (data.dev->disk, gpt);
|
||||
grub_test_assert (grub_errno == GRUB_ERR_NONE,
|
||||
"repair failed: %s", grub_errmsg);
|
||||
if (memcmp (&gpt->backup, &example_backup, sizeof (gpt->backup)))
|
||||
{
|
||||
printf ("Invalid restored backup header:\n");
|
||||
hexdump (16, (char*)&gpt->backup, sizeof (gpt->backup));
|
||||
printf ("Expected backup header:\n");
|
||||
hexdump (16, (char*)&example_backup, sizeof (example_backup));
|
||||
grub_test_assert (0, "repair did not restore backup header");
|
||||
}
|
||||
grub_gpt_free (gpt);
|
||||
reset_disk (&data);
|
||||
|
||||
close_disk (&data);
|
||||
}
|
||||
|
||||
/* Finding/reading/writing the backup GPT may be difficult if the OS and
|
||||
* BIOS report different sizes for the same disk. We need to gracefully
|
||||
* recognize this and avoid causing trouble for the OS. */
|
||||
static void
|
||||
weird_disk_size_test (void)
|
||||
{
|
||||
struct test_data data;
|
||||
grub_gpt_t gpt;
|
||||
|
||||
open_disk (&data);
|
||||
|
||||
/* Chop off 65536 bytes (128 512B sectors) which may happen when the
|
||||
* BIOS thinks you are using a software RAID system that reserves that
|
||||
* area for metadata when in fact you are not and using the bare disk. */
|
||||
grub_test_assert(data.dev->disk->total_sectors == DISK_SECTORS,
|
||||
"unexpected disk size: 0x%llx",
|
||||
(unsigned long long) data.dev->disk->total_sectors);
|
||||
data.dev->disk->total_sectors -= 128;
|
||||
|
||||
gpt = read_disk (&data);
|
||||
assert_error_stack_empty ();
|
||||
/* Reading the alternate_lba should have been blocked and reading
|
||||
* the (new) end of disk should have found no useful data. */
|
||||
grub_test_assert ((gpt->status & GRUB_GPT_BACKUP_HEADER_VALID) == 0,
|
||||
"unreported missing backup header");
|
||||
|
||||
/* We should be able to reconstruct the backup header and the location
|
||||
* of the backup should remain unchanged, trusting the GPT data over
|
||||
* what the BIOS is telling us. Further changes are left to the OS. */
|
||||
grub_gpt_repair (data.dev->disk, gpt);
|
||||
grub_test_assert (grub_errno == GRUB_ERR_NONE,
|
||||
"repair failed: %s", grub_errmsg);
|
||||
grub_test_assert (memcmp (&gpt->primary, &example_primary,
|
||||
sizeof (gpt->primary)) == 0,
|
||||
"repair corrupted primary header");
|
||||
|
||||
grub_gpt_free (gpt);
|
||||
close_disk (&data);
|
||||
}
|
||||
|
||||
static void
|
||||
iterate_partitions_test (void)
|
||||
{
|
||||
struct test_data data;
|
||||
struct grub_gpt_partentry *p;
|
||||
grub_gpt_t gpt;
|
||||
grub_uint32_t n;
|
||||
|
||||
open_disk (&data);
|
||||
gpt = read_disk (&data);
|
||||
|
||||
for (n = 0; (p = grub_gpt_get_partentry (gpt, n)) != NULL; n++)
|
||||
grub_test_assert (memcmp (p, &example_entries[n], sizeof (*p)) == 0,
|
||||
"unexpected partition %d data", n);
|
||||
|
||||
grub_test_assert (n == TABLE_ENTRIES, "unexpected partition limit: %d", n);
|
||||
|
||||
grub_gpt_free (gpt);
|
||||
close_disk (&data);
|
||||
}
|
||||
|
||||
static void
|
||||
large_partitions_test (void)
|
||||
{
|
||||
struct test_data data;
|
||||
struct grub_gpt_partentry *p;
|
||||
grub_gpt_t gpt;
|
||||
grub_uint32_t n;
|
||||
|
||||
open_disk (&data);
|
||||
|
||||
/* Double the entry size, cut the number of entries in half. */
|
||||
data.raw->primary_header.maxpart =
|
||||
data.raw->backup_header.maxpart =
|
||||
grub_cpu_to_le32_compile_time (TABLE_ENTRIES/2);
|
||||
data.raw->primary_header.partentry_size =
|
||||
data.raw->backup_header.partentry_size =
|
||||
grub_cpu_to_le32_compile_time (ENTRY_SIZE*2);
|
||||
data.raw->primary_header.partentry_crc32 =
|
||||
data.raw->backup_header.partentry_crc32 =
|
||||
grub_cpu_to_le32_compile_time (0xf2c45af8);
|
||||
data.raw->primary_header.crc32 = grub_cpu_to_le32_compile_time (0xde00cc8f);
|
||||
data.raw->backup_header.crc32 = grub_cpu_to_le32_compile_time (0x6d72e284);
|
||||
|
||||
memset (&data.raw->primary_entries, 0,
|
||||
sizeof (data.raw->primary_entries));
|
||||
for (n = 0; n < TABLE_ENTRIES/2; n++)
|
||||
memcpy (&data.raw->primary_entries[n*2], &example_entries[n],
|
||||
sizeof (data.raw->primary_entries[0]));
|
||||
memcpy (&data.raw->backup_entries, &data.raw->primary_entries,
|
||||
sizeof (data.raw->backup_entries));
|
||||
|
||||
sync_disk(&data);
|
||||
gpt = read_disk (&data);
|
||||
|
||||
for (n = 0; (p = grub_gpt_get_partentry (gpt, n)) != NULL; n++)
|
||||
grub_test_assert (memcmp (p, &example_entries[n], sizeof (*p)) == 0,
|
||||
"unexpected partition %d data", n);
|
||||
|
||||
grub_test_assert (n == TABLE_ENTRIES/2, "unexpected partition limit: %d", n);
|
||||
|
||||
grub_gpt_free (gpt);
|
||||
|
||||
/* Editing memory beyond the entry structure should still change the crc. */
|
||||
data.raw->primary_entries[1].attrib = 0xff;
|
||||
|
||||
sync_disk(&data);
|
||||
gpt = read_disk (&data);
|
||||
grub_test_assert (gpt->status == (GRUB_GPT_PROTECTIVE_MBR |
|
||||
GRUB_GPT_PRIMARY_HEADER_VALID |
|
||||
GRUB_GPT_BACKUP_HEADER_VALID |
|
||||
GRUB_GPT_BACKUP_ENTRIES_VALID),
|
||||
"unexpected status: 0x%02x", gpt->status);
|
||||
grub_gpt_free (gpt);
|
||||
|
||||
close_disk (&data);
|
||||
}
|
||||
|
||||
static void
|
||||
invalid_partsize_test (void)
|
||||
{
|
||||
struct grub_gpt_header header = {
|
||||
.magic = GRUB_GPT_HEADER_MAGIC,
|
||||
.version = GRUB_GPT_HEADER_VERSION,
|
||||
.headersize = sizeof (struct grub_gpt_header),
|
||||
.crc32 = grub_cpu_to_le32_compile_time (0x1ff2a054),
|
||||
.header_lba = grub_cpu_to_le64_compile_time (PRIMARY_HEADER_SECTOR),
|
||||
.alternate_lba = grub_cpu_to_le64_compile_time (BACKUP_HEADER_SECTOR),
|
||||
.start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR),
|
||||
.end = grub_cpu_to_le64_compile_time (DATA_END_SECTOR),
|
||||
.guid = GRUB_GPT_GUID_INIT(0x69c131ad, 0x67d6, 0x46c6,
|
||||
0x93, 0xc4, 0x12, 0x4c, 0x75, 0x52, 0x56, 0xac),
|
||||
.partitions = grub_cpu_to_le64_compile_time (PRIMARY_TABLE_SECTOR),
|
||||
.maxpart = grub_cpu_to_le32_compile_time (TABLE_ENTRIES),
|
||||
/* Triple the entry size, which is not valid. */
|
||||
.partentry_size = grub_cpu_to_le32_compile_time (ENTRY_SIZE*3),
|
||||
.partentry_crc32 = grub_cpu_to_le32_compile_time (0x074e052c),
|
||||
};
|
||||
|
||||
grub_gpt_header_check(&header, GRUB_DISK_SECTOR_BITS);
|
||||
grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE,
|
||||
"unexpected error: %s", grub_errmsg);
|
||||
grub_test_assert (strcmp(grub_errmsg, "invalid GPT entry size") == 0,
|
||||
"unexpected error: %s", grub_errmsg);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
search_part_label_test (void)
|
||||
{
|
||||
struct test_data data;
|
||||
const char *test_result;
|
||||
char *expected_result;
|
||||
|
||||
open_disk (&data);
|
||||
|
||||
expected_result = grub_xasprintf ("%s,gpt1", data.dev->disk->name);
|
||||
grub_env_unset ("test_result");
|
||||
grub_search_part_label ("EFI SYSTEM", "test_result", 0, NULL, 0);
|
||||
test_result = grub_env_get ("test_result");
|
||||
grub_test_assert (test_result && strcmp (test_result, expected_result) == 0,
|
||||
"wrong device: %s (%s)", test_result, expected_result);
|
||||
grub_free (expected_result);
|
||||
|
||||
expected_result = grub_xasprintf ("%s,gpt2", data.dev->disk->name);
|
||||
grub_env_unset ("test_result");
|
||||
grub_search_part_label ("BIOS BOOT", "test_result", 0, NULL, 0);
|
||||
test_result = grub_env_get ("test_result");
|
||||
grub_test_assert (test_result && strcmp (test_result, expected_result) == 0,
|
||||
"wrong device: %s (%s)", test_result, expected_result);
|
||||
grub_free (expected_result);
|
||||
|
||||
grub_env_unset ("test_result");
|
||||
grub_search_part_label ("bogus name", "test_result", 0, NULL, 0);
|
||||
test_result = grub_env_get ("test_result");
|
||||
grub_test_assert (test_result == NULL,
|
||||
"unexpected device: %s", test_result);
|
||||
grub_test_assert (grub_errno == GRUB_ERR_FILE_NOT_FOUND,
|
||||
"unexpected error: %s", grub_errmsg);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
close_disk (&data);
|
||||
}
|
||||
|
||||
static void
|
||||
search_part_uuid_test (void)
|
||||
{
|
||||
struct test_data data;
|
||||
const char gpt1_uuid[] = "A0F1792E-B4CE-4136-BCF2-1AFC133C2828";
|
||||
const char gpt2_uuid[] = "876c898d-1b40-4727-a161-edf9b5486674";
|
||||
const char bogus_uuid[] = "1534c928-c50e-4866-9daf-6a9fd7918a76";
|
||||
const char *test_result;
|
||||
char *expected_result;
|
||||
|
||||
open_disk (&data);
|
||||
|
||||
expected_result = grub_xasprintf ("%s,gpt1", data.dev->disk->name);
|
||||
grub_env_unset ("test_result");
|
||||
grub_search_part_uuid (gpt1_uuid, "test_result", 0, NULL, 0);
|
||||
test_result = grub_env_get ("test_result");
|
||||
grub_test_assert (test_result && strcmp (test_result, expected_result) == 0,
|
||||
"wrong device: %s (%s)", test_result, expected_result);
|
||||
grub_free (expected_result);
|
||||
|
||||
expected_result = grub_xasprintf ("%s,gpt2", data.dev->disk->name);
|
||||
grub_env_unset ("test_result");
|
||||
grub_search_part_uuid (gpt2_uuid, "test_result", 0, NULL, 0);
|
||||
test_result = grub_env_get ("test_result");
|
||||
grub_test_assert (test_result && strcmp (test_result, expected_result) == 0,
|
||||
"wrong device: %s (%s)", test_result, expected_result);
|
||||
grub_free (expected_result);
|
||||
|
||||
grub_env_unset ("test_result");
|
||||
grub_search_part_uuid (bogus_uuid, "test_result", 0, NULL, 0);
|
||||
test_result = grub_env_get ("test_result");
|
||||
grub_test_assert (test_result == NULL,
|
||||
"unexpected device: %s", test_result);
|
||||
grub_test_assert (grub_errno == GRUB_ERR_FILE_NOT_FOUND,
|
||||
"unexpected error: %s", grub_errmsg);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
close_disk (&data);
|
||||
}
|
||||
|
||||
static void
|
||||
search_disk_uuid_test (void)
|
||||
{
|
||||
struct test_data data;
|
||||
const char disk_uuid[] = "69c131ad-67d6-46c6-93c4-124c755256ac";
|
||||
const char bogus_uuid[] = "1534c928-c50e-4866-9daf-6a9fd7918a76";
|
||||
const char *test_result;
|
||||
char *expected_result;
|
||||
|
||||
open_disk (&data);
|
||||
|
||||
expected_result = grub_xasprintf ("%s", data.dev->disk->name);
|
||||
grub_env_unset ("test_result");
|
||||
grub_search_disk_uuid (disk_uuid, "test_result", 0, NULL, 0);
|
||||
test_result = grub_env_get ("test_result");
|
||||
grub_test_assert (test_result && strcmp (test_result, expected_result) == 0,
|
||||
"wrong device: %s (%s)", test_result, expected_result);
|
||||
grub_free (expected_result);
|
||||
|
||||
grub_env_unset ("test_result");
|
||||
grub_search_disk_uuid (bogus_uuid, "test_result", 0, NULL, 0);
|
||||
test_result = grub_env_get ("test_result");
|
||||
grub_test_assert (test_result == NULL,
|
||||
"unexpected device: %s", test_result);
|
||||
grub_test_assert (grub_errno == GRUB_ERR_FILE_NOT_FOUND,
|
||||
"unexpected error: %s", grub_errmsg);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
close_disk (&data);
|
||||
}
|
||||
|
||||
void
|
||||
grub_unit_test_init (void)
|
||||
{
|
||||
grub_init_all ();
|
||||
grub_hostfs_init ();
|
||||
grub_host_init ();
|
||||
grub_test_register ("gpt_pmbr_test", pmbr_test);
|
||||
grub_test_register ("gpt_header_test", header_test);
|
||||
grub_test_register ("gpt_read_valid_test", read_valid_test);
|
||||
grub_test_register ("gpt_read_invalid_test", read_invalid_entries_test);
|
||||
grub_test_register ("gpt_read_fallback_test", read_fallback_test);
|
||||
grub_test_register ("gpt_repair_test", repair_test);
|
||||
grub_test_register ("gpt_iterate_partitions_test", iterate_partitions_test);
|
||||
grub_test_register ("gpt_large_partitions_test", large_partitions_test);
|
||||
grub_test_register ("gpt_invalid_partsize_test", invalid_partsize_test);
|
||||
grub_test_register ("gpt_weird_disk_size_test", weird_disk_size_test);
|
||||
grub_test_register ("gpt_search_part_label_test", search_part_label_test);
|
||||
grub_test_register ("gpt_search_uuid_test", search_part_uuid_test);
|
||||
grub_test_register ("gpt_search_disk_uuid_test", search_disk_uuid_test);
|
||||
}
|
||||
|
||||
void
|
||||
grub_unit_test_fini (void)
|
||||
{
|
||||
grub_test_unregister ("gpt_pmbr_test");
|
||||
grub_test_unregister ("gpt_header_test");
|
||||
grub_test_unregister ("gpt_read_valid_test");
|
||||
grub_test_unregister ("gpt_read_invalid_test");
|
||||
grub_test_unregister ("gpt_read_fallback_test");
|
||||
grub_test_unregister ("gpt_repair_test");
|
||||
grub_test_unregister ("gpt_iterate_partitions_test");
|
||||
grub_test_unregister ("gpt_large_partitions_test");
|
||||
grub_test_unregister ("gpt_invalid_partsize_test");
|
||||
grub_test_unregister ("gpt_weird_disk_size_test");
|
||||
grub_test_unregister ("gpt_search_part_label_test");
|
||||
grub_test_unregister ("gpt_search_part_uuid_test");
|
||||
grub_test_unregister ("gpt_search_disk_uuid_test");
|
||||
grub_fini_all ();
|
||||
}
|
207
tests/gptprio_test.in
Normal file
207
tests/gptprio_test.in
Normal file
|
@ -0,0 +1,207 @@
|
|||
#! /bin/bash
|
||||
set -e
|
||||
|
||||
# Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2014 CoreOS, 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
sgdisk=sgdisk
|
||||
grubshell=@builddir@/grub-shell
|
||||
|
||||
if ! which "${sgdisk}" >/dev/null 2>&1; then
|
||||
echo "sgdisk not installed; cannot test gptprio."
|
||||
exit 77
|
||||
fi
|
||||
|
||||
. "@builddir@/grub-core/modinfo.sh"
|
||||
|
||||
case "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" in
|
||||
mips-qemu_mips | mipsel-qemu_mips | i386-qemu | i386-multiboot | i386-coreboot | mipsel-loongson)
|
||||
disk=ata0
|
||||
;;
|
||||
powerpc-ieee1275)
|
||||
disk=ieee1275//pci@80000000/mac-io@4/ata-3@20000/disk@0
|
||||
# FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label.
|
||||
exit 0
|
||||
;;
|
||||
sparc64-ieee1275)
|
||||
disk=ieee1275//pci@1fe\,0/pci-ata@5/ide0@500/disk@0
|
||||
# FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label.
|
||||
exit 0
|
||||
;;
|
||||
i386-ieee1275)
|
||||
disk=ieee1275/d
|
||||
# FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label.
|
||||
exit 0
|
||||
;;
|
||||
mips-arc)
|
||||
# FIXME: ARC firmware has bugs which prevent it from accessing hard disk w/o dvh disklabel.
|
||||
exit 0 ;;
|
||||
mipsel-arc)
|
||||
disk=arc/scsi0/disk0/rdisk0
|
||||
;;
|
||||
*)
|
||||
disk=hd0
|
||||
;;
|
||||
esac
|
||||
img1="`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"`" || exit 1
|
||||
trap "rm -f '${img1}'" EXIT
|
||||
|
||||
prio_type="5dfbf5f4-2848-4bac-aa5e-0d9a20b745a6"
|
||||
declare -a prio_uuid
|
||||
prio_uuid[2]="9b003904-d006-4ab3-97f1-73f547b7af1a"
|
||||
prio_uuid[3]="1aa5a658-5b02-414d-9b71-f7e6c151f0cd"
|
||||
prio_uuid[4]="8aa0240d-98af-42b0-b32a-ccbe0572d62b"
|
||||
|
||||
create_disk_image () {
|
||||
size=$1
|
||||
rm -f "${img1}"
|
||||
dd if=/dev/zero of="${img1}" bs=512 count=1 seek=$((size - 1)) status=none
|
||||
${sgdisk} \
|
||||
-n 1:0:+1 -c 1:ESP -t 1:ef00 \
|
||||
-n 2:0:+1 -c 2:A -t 2:"${prio_type}" -u 2:"${prio_uuid[2]}" \
|
||||
-n 3:0:+1 -c 3:B -t 3:"${prio_type}" -u 3:"${prio_uuid[3]}" \
|
||||
-n 4:0:+1 -c 4:C -t 4:"${prio_type}" -u 4:"${prio_uuid[4]}" \
|
||||
"${img1}" >/dev/null
|
||||
}
|
||||
|
||||
wipe_disk_area () {
|
||||
sector=$1
|
||||
size=$2
|
||||
dd if=/dev/zero of="${img1}" bs=512 count=${size} seek=${sector} conv=notrunc status=none
|
||||
}
|
||||
|
||||
is_zero () {
|
||||
sector=$1
|
||||
size=$2
|
||||
cmp -s -i $((sector * 512)) -n $((size * 512)) /dev/zero "${img1}"
|
||||
}
|
||||
|
||||
check_is_zero () {
|
||||
sector=$1
|
||||
size=$2
|
||||
if ! is_zero "$@"; then
|
||||
echo "$size sector(s) starting at $sector should be all zero"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_not_zero () {
|
||||
sector=$1
|
||||
size=$2
|
||||
if is_zero "$@"; then
|
||||
echo "$size sector(s) starting at $sector should not be all zero"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
fmt_prio () {
|
||||
priority=$(( ( $1 & 15 ) << 48 ))
|
||||
tries=$(( ( $2 & 15 ) << 52 ))
|
||||
success=$(( ( $3 & 1 ) << 56 ))
|
||||
printf %016x $(( priority | tries | success ))
|
||||
}
|
||||
|
||||
set_prio () {
|
||||
part="$1"
|
||||
attr=$(fmt_prio $2 $3 $4)
|
||||
${sgdisk} -A "${part}:=:${attr}" "${img1}" >/dev/null
|
||||
}
|
||||
|
||||
check_prio () {
|
||||
part="$1"
|
||||
expect=$(fmt_prio $2 $3 $4)
|
||||
result=$(LANG=C ${sgdisk} -i "${part}" "${img1}" 2>&1 \
|
||||
| awk '/^Attribute flags: / {print $3}')
|
||||
if [[ "${expect}" != "${result}" ]]; then
|
||||
echo "Partition ${part} has attributes ${result:-??}, not ${expect}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_next() {
|
||||
"${grubshell}" --disk="${img1}" --modules=gptprio <<EOF
|
||||
gptprio.next -d next_dev -u next_uuid "${disk}"
|
||||
echo next_dev=\$next_dev
|
||||
echo next_uuid=\$next_uuid
|
||||
EOF
|
||||
}
|
||||
|
||||
check_next () {
|
||||
part="$1"
|
||||
output=$(run_next)
|
||||
if grep ^error <<<"${output}"; then
|
||||
exit 1
|
||||
fi
|
||||
if ! grep -q "^next_dev=${disk},gpt${part}$" <<<"${output}"; then
|
||||
echo "Unexpected next_dev: (expected ${disk},gpt${part})"
|
||||
echo "${output}"
|
||||
exit 1
|
||||
fi
|
||||
if ! grep -q "^next_uuid=${prio_uuid[$part]}$" <<<"${output}"; then
|
||||
echo "Unexpected next_uuid: (expected ${prio_uuid[$part]})"
|
||||
echo "${output}"
|
||||
exit 1
|
||||
fi
|
||||
check_prio "$@"
|
||||
}
|
||||
|
||||
# Basic sanity check
|
||||
create_disk_image 100
|
||||
set_prio 2 3 2 1
|
||||
check_prio 2 3 2 1
|
||||
|
||||
# Check gptprio works without modifying the disk when no update is required.
|
||||
# Leaves any existing corruption as is, repairing in the OS is better.
|
||||
create_disk_image 100
|
||||
set_prio 2 1 0 1
|
||||
wipe_disk_area 99 1
|
||||
check_next 2 1 0 1
|
||||
check_is_zero 99 1
|
||||
|
||||
create_disk_image 100
|
||||
set_prio 2 1 0 1
|
||||
wipe_disk_area 1 1
|
||||
check_next 2 1 0 1
|
||||
check_is_zero 1 1
|
||||
|
||||
# When writes do need to be made go ahead and perform the repair.
|
||||
create_disk_image 100
|
||||
set_prio 2 1 1 0
|
||||
wipe_disk_area 99 1
|
||||
check_next 2 1 0 0
|
||||
check_not_zero 99 1
|
||||
|
||||
create_disk_image 100
|
||||
set_prio 2 1 1 0
|
||||
wipe_disk_area 1 1
|
||||
check_next 2 1 0 0
|
||||
check_not_zero 1 1
|
||||
|
||||
# Try two partitions before falling before falling back to a third
|
||||
create_disk_image 100
|
||||
set_prio 2 3 3 0
|
||||
set_prio 3 2 2 0
|
||||
set_prio 4 1 0 1
|
||||
check_next 2 3 2 0
|
||||
check_next 2 3 1 0
|
||||
check_next 2 3 0 0
|
||||
check_next 3 2 1 0
|
||||
check_next 3 2 0 0
|
||||
check_next 4 1 0 1
|
||||
check_next 4 1 0 1
|
||||
check_next 4 1 0 1
|
||||
check_prio 2 3 0 0
|
||||
check_prio 3 2 0 0
|
102
tests/gptrepair_test.in
Normal file
102
tests/gptrepair_test.in
Normal file
|
@ -0,0 +1,102 @@
|
|||
#! /bin/sh
|
||||
set -e
|
||||
|
||||
# Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2014 CoreOS, 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
parted=parted
|
||||
grubshell=@builddir@/grub-shell
|
||||
|
||||
. "@builddir@/grub-core/modinfo.sh"
|
||||
|
||||
case "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" in
|
||||
mips-qemu_mips | mipsel-qemu_mips | i386-qemu | i386-multiboot | i386-coreboot | mipsel-loongson)
|
||||
disk=ata0
|
||||
;;
|
||||
powerpc-ieee1275)
|
||||
disk=ieee1275//pci@80000000/mac-io@4/ata-3@20000/disk@0
|
||||
# FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label.
|
||||
exit 0
|
||||
;;
|
||||
sparc64-ieee1275)
|
||||
disk=ieee1275//pci@1fe\,0/pci-ata@5/ide0@500/disk@0
|
||||
# FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label.
|
||||
exit 0
|
||||
;;
|
||||
i386-ieee1275)
|
||||
disk=ieee1275/d
|
||||
# FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label.
|
||||
exit 0
|
||||
;;
|
||||
mips-arc)
|
||||
# FIXME: ARC firmware has bugs which prevent it from accessing hard disk w/o dvh disklabel.
|
||||
exit 0 ;;
|
||||
mipsel-arc)
|
||||
disk=arc/scsi0/disk0/rdisk0
|
||||
;;
|
||||
*)
|
||||
disk=hd0
|
||||
;;
|
||||
esac
|
||||
img1="`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"`" || exit 1
|
||||
img2="`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"`" || exit 1
|
||||
trap "rm -f '${img1}' '${img2}'" EXIT
|
||||
|
||||
create_disk_image () {
|
||||
size=$1
|
||||
rm -f "${img1}"
|
||||
dd if=/dev/zero of="${img1}" bs=512 count=1 seek=$((size - 1)) status=none
|
||||
${parted} -a none -s "${img1}" mklabel gpt
|
||||
cp "${img1}" "${img2}"
|
||||
}
|
||||
|
||||
wipe_disk_area () {
|
||||
sector=$1
|
||||
size=$2
|
||||
dd if=/dev/zero of="${img2}" bs=512 count=${size} seek=${sector} conv=notrunc status=none
|
||||
}
|
||||
|
||||
do_repair () {
|
||||
output="`echo "gptrepair ($disk)" | "${grubshell}" --disk="${img2}"`"
|
||||
if echo "${output}" | grep ^error; then
|
||||
return 1
|
||||
fi
|
||||
if echo "${output}" | grep -v GPT; then
|
||||
echo "Unexpected output ${output}"
|
||||
return 1
|
||||
fi
|
||||
echo "${output}"
|
||||
}
|
||||
|
||||
echo "Nothing to repair:"
|
||||
create_disk_image 100
|
||||
do_repair
|
||||
cmp "${img1}" "${img2}"
|
||||
echo
|
||||
|
||||
echo "Repair primary (MBR left intact)"
|
||||
create_disk_image 100
|
||||
wipe_disk_area 1 1
|
||||
do_repair
|
||||
cmp "${img1}" "${img2}"
|
||||
echo
|
||||
|
||||
echo "Repair backup"
|
||||
create_disk_image 100
|
||||
wipe_disk_area 99 1
|
||||
do_repair
|
||||
cmp "${img1}" "${img2}"
|
||||
echo
|
|
@ -600,7 +600,7 @@ for LOGSECSIZE in $(range "$MINLOGSECSIZE" "$MAXLOGSECSIZE" 1); do
|
|||
GENERATED=n
|
||||
LODEVICES=
|
||||
MOUNTDEVICE=
|
||||
|
||||
|
||||
case x"$fs" in
|
||||
x"tarfs" | x"cpio_"*| x"ziso9660" | x"romfs" | x"squash4_"*\
|
||||
| x"iso9660" | xjoliet | xrockridge | xrockridge_joliet \
|
||||
|
|
Loading…
Reference in a new issue