summaryrefslogtreecommitdiffstats
path: root/grub-core/commands
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 10:54:16 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 10:54:16 +0000
commit485f6ecd453d8a2fd8b9b9fadea03159d8b50797 (patch)
tree32451fa3cdd9321fb2591fada9891b2cb70a9cd1 /grub-core/commands
parentInitial commit. (diff)
downloadgrub2-upstream.tar.xz
grub2-upstream.zip
Adding upstream version 2.06.upstream/2.06upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--grub-core/commands/acpi.c791
-rw-r--r--grub-core/commands/acpihalt.c454
-rw-r--r--grub-core/commands/arc/lsdev.c57
-rw-r--r--grub-core/commands/blocklist.c160
-rw-r--r--grub-core/commands/boot.c195
-rw-r--r--grub-core/commands/boottime.c65
-rw-r--r--grub-core/commands/cacheinfo.c62
-rw-r--r--grub-core/commands/cat.c170
-rw-r--r--grub-core/commands/cmp.c119
-rw-r--r--grub-core/commands/configfile.c98
-rw-r--r--grub-core/commands/date.c149
-rw-r--r--grub-core/commands/echo.c141
-rw-r--r--grub-core/commands/efi/efifwsetup.c90
-rw-r--r--grub-core/commands/efi/fixvideo.c114
-rw-r--r--grub-core/commands/efi/loadbios.c222
-rw-r--r--grub-core/commands/efi/lsefi.c155
-rw-r--r--grub-core/commands/efi/lsefimmap.c160
-rw-r--r--grub-core/commands/efi/lsefisystab.c125
-rw-r--r--grub-core/commands/efi/lssal.c169
-rw-r--r--grub-core/commands/efi/smbios.c61
-rw-r--r--grub-core/commands/efi/tpm.c241
-rw-r--r--grub-core/commands/eval.c71
-rw-r--r--grub-core/commands/extcmd.c141
-rw-r--r--grub-core/commands/file.c694
-rw-r--r--grub-core/commands/file32.c5
-rw-r--r--grub-core/commands/file64.c5
-rw-r--r--grub-core/commands/fileXX.c74
-rw-r--r--grub-core/commands/gptsync.c266
-rw-r--r--grub-core/commands/halt.c47
-rw-r--r--grub-core/commands/hashsum.c334
-rw-r--r--grub-core/commands/hdparm.c447
-rw-r--r--grub-core/commands/help.c153
-rw-r--r--grub-core/commands/hexdump.c133
-rw-r--r--grub-core/commands/i386/cmosdump.c64
-rw-r--r--grub-core/commands/i386/cmostest.c124
-rw-r--r--grub-core/commands/i386/coreboot/cb_timestamps.c126
-rw-r--r--grub-core/commands/i386/coreboot/cbls.c143
-rw-r--r--grub-core/commands/i386/cpuid.c125
-rw-r--r--grub-core/commands/i386/pc/drivemap.c428
-rw-r--r--grub-core/commands/i386/pc/drivemap_int13h.S124
-rw-r--r--grub-core/commands/i386/pc/halt.c126
-rw-r--r--grub-core/commands/i386/pc/lsapm.c115
-rw-r--r--grub-core/commands/i386/pc/play.c197
-rw-r--r--grub-core/commands/i386/pc/sendkey.c387
-rw-r--r--grub-core/commands/i386/pc/smbios.c52
-rw-r--r--grub-core/commands/i386/rdmsr.c102
-rw-r--r--grub-core/commands/i386/wrmsr.c94
-rw-r--r--grub-core/commands/ieee1275/suspend.c51
-rw-r--r--grub-core/commands/iorw.c156
-rw-r--r--grub-core/commands/keylayouts.c307
-rw-r--r--grub-core/commands/keystatus.c95
-rw-r--r--grub-core/commands/legacycfg.c912
-rw-r--r--grub-core/commands/loadenv.c470
-rw-r--r--grub-core/commands/ls.c302
-rw-r--r--grub-core/commands/lsacpi.c314
-rw-r--r--grub-core/commands/lsmmap.c85
-rw-r--r--grub-core/commands/lspci.c238
-rw-r--r--grub-core/commands/macbless.c235
-rw-r--r--grub-core/commands/memrw.c158
-rw-r--r--grub-core/commands/menuentry.c337
-rw-r--r--grub-core/commands/minicmd.c227
-rw-r--r--grub-core/commands/mips/loongson/lsspd.c103
-rw-r--r--grub-core/commands/nativedisk.c332
-rw-r--r--grub-core/commands/parttool.c357
-rw-r--r--grub-core/commands/password.c93
-rw-r--r--grub-core/commands/password_pbkdf2.c209
-rw-r--r--grub-core/commands/pcidump.c174
-rw-r--r--grub-core/commands/pgp.c1018
-rw-r--r--grub-core/commands/probe.c225
-rw-r--r--grub-core/commands/read.c92
-rw-r--r--grub-core/commands/reboot.c46
-rw-r--r--grub-core/commands/regexp.c168
-rw-r--r--grub-core/commands/search.c337
-rw-r--r--grub-core/commands/search_file.c5
-rw-r--r--grub-core/commands/search_label.c5
-rw-r--r--grub-core/commands/search_uuid.c5
-rw-r--r--grub-core/commands/search_wrap.c220
-rw-r--r--grub-core/commands/setpci.c340
-rw-r--r--grub-core/commands/sleep.c117
-rw-r--r--grub-core/commands/smbios.c398
-rw-r--r--grub-core/commands/syslinuxcfg.c217
-rw-r--r--grub-core/commands/terminal.c285
-rw-r--r--grub-core/commands/test.c455
-rw-r--r--grub-core/commands/testload.c170
-rw-r--r--grub-core/commands/testspeed.c115
-rw-r--r--grub-core/commands/time.c68
-rw-r--r--grub-core/commands/tpm.c95
-rw-r--r--grub-core/commands/tr.c126
-rw-r--r--grub-core/commands/true.c61
-rw-r--r--grub-core/commands/usbtest.c227
-rw-r--r--grub-core/commands/videoinfo.c262
-rw-r--r--grub-core/commands/videotest.c241
-rw-r--r--grub-core/commands/wildcard.c652
-rw-r--r--grub-core/commands/xen/lsxen.c90
-rw-r--r--grub-core/commands/xnu_uuid.c119
95 files changed, 19689 insertions, 0 deletions
diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c
new file mode 100644
index 0000000..1215f2a
--- /dev/null
+++ b/grub-core/commands/acpi.c
@@ -0,0 +1,791 @@
+/* acpi.c - modify acpi tables. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/extcmd.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/term.h>
+#include <grub/misc.h>
+#include <grub/acpi.h>
+#include <grub/mm.h>
+#include <grub/memory.h>
+#include <grub/i18n.h>
+#include <grub/lockdown.h>
+
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/efi.h>
+#include <grub/efi/api.h>
+#endif
+
+#pragma GCC diagnostic ignored "-Wcast-align"
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] = {
+ {"exclude", 'x', 0,
+ N_("Don't load host tables specified by comma-separated list."),
+ 0, ARG_TYPE_STRING},
+ {"load-only", 'n', 0,
+ N_("Load only tables specified by comma-separated list."), 0, ARG_TYPE_STRING},
+ {"v1", '1', 0, N_("Export version 1 tables to the OS."), 0, ARG_TYPE_NONE},
+ {"v2", '2', 0, N_("Export version 2 and version 3 tables to the OS."), 0, ARG_TYPE_NONE},
+ {"oemid", 'o', 0, N_("Set OEMID of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING},
+ {"oemtable", 't', 0,
+ N_("Set OEMTABLE ID of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING},
+ {"oemtablerev", 'r', 0,
+ N_("Set OEMTABLE revision of RSDP, XSDT and RSDT."), 0, ARG_TYPE_INT},
+ {"oemtablecreator", 'c', 0,
+ N_("Set creator field of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING},
+ {"oemtablecreatorrev", 'd', 0,
+ N_("Set creator revision of RSDP, XSDT and RSDT."), 0, ARG_TYPE_INT},
+ /* TRANSLATORS: "hangs" here is a noun, not a verb. */
+ {"no-ebda", 'e', 0, N_("Don't update EBDA. May fix failures or hangs on some "
+ "BIOSes but makes it ineffective with OS not receiving RSDP from GRUB."),
+ 0, ARG_TYPE_NONE},
+ {0, 0, 0, 0, 0, 0}
+};
+
+/* rev1 is 1 if ACPIv1 is to be generated, 0 otherwise.
+ rev2 contains the revision of ACPIv2+ to generate or 0 if none. */
+static int rev1, rev2;
+/* OEMID of RSDP, RSDT and XSDT. */
+static char root_oemid[6];
+/* OEMTABLE of the same tables. */
+static char root_oemtable[8];
+/* OEMREVISION of the same tables. */
+static grub_uint32_t root_oemrev;
+/* CreatorID of the same tables. */
+static char root_creator_id[4];
+/* CreatorRevision of the same tables. */
+static grub_uint32_t root_creator_rev;
+static struct grub_acpi_rsdp_v10 *rsdpv1_new = 0;
+static struct grub_acpi_rsdp_v20 *rsdpv2_new = 0;
+static char *playground = 0, *playground_ptr = 0;
+static int playground_size = 0;
+
+/* Linked list of ACPI tables. */
+struct efiemu_acpi_table
+{
+ void *addr;
+ grub_size_t size;
+ struct efiemu_acpi_table *next;
+};
+static struct efiemu_acpi_table *acpi_tables = 0;
+
+/* DSDT isn't in RSDT. So treat it specially. */
+static void *table_dsdt = 0;
+/* Pointer to recreated RSDT. */
+static void *rsdt_addr = 0;
+
+/* Allocation handles for different tables. */
+static grub_size_t dsdt_size = 0;
+
+/* Address of original FACS. */
+static grub_uint32_t facs_addr = 0;
+
+struct grub_acpi_rsdp_v20 *
+grub_acpi_get_rsdpv2 (void)
+{
+ if (rsdpv2_new)
+ return rsdpv2_new;
+ if (rsdpv1_new)
+ return 0;
+ return grub_machine_acpi_get_rsdpv2 ();
+}
+
+struct grub_acpi_rsdp_v10 *
+grub_acpi_get_rsdpv1 (void)
+{
+ if (rsdpv1_new)
+ return rsdpv1_new;
+ if (rsdpv2_new)
+ return 0;
+ return grub_machine_acpi_get_rsdpv1 ();
+}
+
+#if defined (__i386__) || defined (__x86_64__)
+
+static inline int
+iszero (grub_uint8_t *reg, int size)
+{
+ int i;
+ for (i = 0; i < size; i++)
+ if (reg[i])
+ return 0;
+ return 1;
+}
+
+/* Context for grub_acpi_create_ebda. */
+struct grub_acpi_create_ebda_ctx {
+ int ebda_len;
+ grub_uint64_t highestlow;
+};
+
+/* Helper for grub_acpi_create_ebda. */
+static int
+find_hook (grub_uint64_t start, grub_uint64_t size, grub_memory_type_t type,
+ void *data)
+{
+ struct grub_acpi_create_ebda_ctx *ctx = data;
+ grub_uint64_t end = start + size;
+ if (type != GRUB_MEMORY_AVAILABLE)
+ return 0;
+ if (end > 0x100000)
+ end = 0x100000;
+ if (end > start + ctx->ebda_len
+ && ctx->highestlow < ((end - ctx->ebda_len) & (~0xf)) )
+ ctx->highestlow = (end - ctx->ebda_len) & (~0xf);
+ return 0;
+}
+
+grub_err_t
+grub_acpi_create_ebda (void)
+{
+ struct grub_acpi_create_ebda_ctx ctx = {
+ .highestlow = 0
+ };
+ int ebda_kb_len = 0;
+ int mmapregion = 0;
+ grub_uint8_t *ebda, *v1inebda = 0, *v2inebda = 0;
+ grub_uint8_t *targetebda, *target;
+ struct grub_acpi_rsdp_v10 *v1;
+ struct grub_acpi_rsdp_v20 *v2;
+
+ ebda = (grub_uint8_t *) (grub_addr_t) ((*((grub_uint16_t *)0x40e)) << 4);
+ grub_dprintf ("acpi", "EBDA @%p\n", ebda);
+ if (ebda)
+ ebda_kb_len = *(grub_uint16_t *) ebda;
+ grub_dprintf ("acpi", "EBDA length 0x%x\n", ebda_kb_len);
+ if (ebda_kb_len > 16)
+ ebda_kb_len = 0;
+ ctx.ebda_len = (ebda_kb_len + 1) << 10;
+
+ /* FIXME: use low-memory mm allocation once it's available. */
+ grub_mmap_iterate (find_hook, &ctx);
+ targetebda = (grub_uint8_t *) (grub_addr_t) ctx.highestlow;
+ grub_dprintf ("acpi", "creating ebda @%llx\n",
+ (unsigned long long) ctx.highestlow);
+ if (! ctx.highestlow)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't find space for the new EBDA");
+
+ mmapregion = grub_mmap_register ((grub_addr_t) targetebda, ctx.ebda_len,
+ GRUB_MEMORY_RESERVED);
+ if (! mmapregion)
+ return grub_errno;
+
+ /* XXX: EBDA is unstandardized, so this implementation is heuristical. */
+ if (ebda_kb_len)
+ grub_memcpy (targetebda, ebda, 0x400);
+ else
+ grub_memset (targetebda, 0, 0x400);
+ *((grub_uint16_t *) targetebda) = ebda_kb_len + 1;
+ target = targetebda;
+
+ v1 = grub_acpi_get_rsdpv1 ();
+ v2 = grub_acpi_get_rsdpv2 ();
+ if (v2 && v2->length > 40)
+ v2 = 0;
+
+ /* First try to replace already existing rsdp. */
+ if (v2)
+ {
+ grub_dprintf ("acpi", "Scanning EBDA for old rsdpv2\n");
+ for (; target < targetebda + 0x400 - v2->length; target += 0x10)
+ if (grub_memcmp (target, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
+ && grub_byte_checksum (target,
+ sizeof (struct grub_acpi_rsdp_v10)) == 0
+ && ((struct grub_acpi_rsdp_v10 *) target)->revision != 0
+ && ((struct grub_acpi_rsdp_v20 *) target)->length <= v2->length)
+ {
+ grub_memcpy (target, v2, v2->length);
+ grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target);
+ v2inebda = target;
+ target += v2->length;
+ target = (grub_uint8_t *) ALIGN_UP((grub_addr_t) target, 16);
+ v2 = 0;
+ break;
+ }
+ }
+
+ if (v1)
+ {
+ grub_dprintf ("acpi", "Scanning EBDA for old rsdpv1\n");
+ for (; target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10);
+ target += 0x10)
+ if (grub_memcmp (target, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
+ && grub_byte_checksum (target,
+ sizeof (struct grub_acpi_rsdp_v10)) == 0)
+ {
+ grub_memcpy (target, v1, sizeof (struct grub_acpi_rsdp_v10));
+ grub_dprintf ("acpi", "Copying rsdpv1 to %p\n", target);
+ v1inebda = target;
+ target += sizeof (struct grub_acpi_rsdp_v10);
+ target = (grub_uint8_t *) ALIGN_UP((grub_addr_t) target, 16);
+ v1 = 0;
+ break;
+ }
+ }
+
+ target = targetebda + 0x100;
+
+ /* Try contiguous zeros. */
+ if (v2)
+ {
+ grub_dprintf ("acpi", "Scanning EBDA for block of zeros\n");
+ for (; target < targetebda + 0x400 - v2->length; target += 0x10)
+ if (iszero (target, v2->length))
+ {
+ grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target);
+ grub_memcpy (target, v2, v2->length);
+ v2inebda = target;
+ target += v2->length;
+ target = (grub_uint8_t *) ALIGN_UP((grub_addr_t) target, 16);
+ v2 = 0;
+ break;
+ }
+ }
+
+ if (v1)
+ {
+ grub_dprintf ("acpi", "Scanning EBDA for block of zeros\n");
+ for (; target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10);
+ target += 0x10)
+ if (iszero (target, sizeof (struct grub_acpi_rsdp_v10)))
+ {
+ grub_dprintf ("acpi", "Copying rsdpv1 to %p\n", target);
+ grub_memcpy (target, v1, sizeof (struct grub_acpi_rsdp_v10));
+ v1inebda = target;
+ target += sizeof (struct grub_acpi_rsdp_v10);
+ target = (grub_uint8_t *) ALIGN_UP((grub_addr_t) target, 16);
+ v1 = 0;
+ break;
+ }
+ }
+
+ if (v1 || v2)
+ {
+ grub_mmap_unregister (mmapregion);
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't find suitable spot in EBDA");
+ }
+
+ /* Remove any other RSDT. */
+ for (target = targetebda;
+ target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10);
+ target += 0x10)
+ if (grub_memcmp (target, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
+ && grub_byte_checksum (target,
+ sizeof (struct grub_acpi_rsdp_v10)) == 0
+ && target != v1inebda && target != v2inebda)
+ *target = 0;
+
+ grub_dprintf ("acpi", "Switching EBDA\n");
+ (*((grub_uint16_t *) 0x40e)) = ((grub_addr_t) targetebda) >> 4;
+ grub_dprintf ("acpi", "EBDA switched\n");
+
+ return GRUB_ERR_NONE;
+}
+#endif
+
+/* Create tables common to ACPIv1 and ACPIv2+ */
+static void
+setup_common_tables (void)
+{
+ struct efiemu_acpi_table *cur;
+ struct grub_acpi_table_header *rsdt;
+ grub_uint32_t *rsdt_entry;
+ int numoftables;
+
+ /* Treat DSDT. */
+ grub_memcpy (playground_ptr, table_dsdt, dsdt_size);
+ grub_free (table_dsdt);
+ table_dsdt = playground_ptr;
+ playground_ptr += dsdt_size;
+
+ /* Treat other tables. */
+ for (cur = acpi_tables; cur; cur = cur->next)
+ {
+ struct grub_acpi_fadt *fadt;
+
+ grub_memcpy (playground_ptr, cur->addr, cur->size);
+ grub_free (cur->addr);
+ cur->addr = playground_ptr;
+ playground_ptr += cur->size;
+
+ /* If it's FADT correct DSDT and FACS addresses. */
+ fadt = (struct grub_acpi_fadt *) cur->addr;
+ if (grub_memcmp (fadt->hdr.signature, GRUB_ACPI_FADT_SIGNATURE,
+ sizeof (fadt->hdr.signature)) == 0)
+ {
+ fadt->dsdt_addr = (grub_addr_t) table_dsdt;
+ fadt->facs_addr = facs_addr;
+
+ /* Does a revision 2 exist at all? */
+ if (fadt->hdr.revision >= 3)
+ {
+ fadt->dsdt_xaddr = (grub_addr_t) table_dsdt;
+ fadt->facs_xaddr = facs_addr;
+ }
+
+ /* Recompute checksum. */
+ fadt->hdr.checksum = 0;
+ fadt->hdr.checksum = 1 + ~grub_byte_checksum (fadt, fadt->hdr.length);
+ }
+ }
+
+ /* Fill RSDT entries. */
+ numoftables = 0;
+ for (cur = acpi_tables; cur; cur = cur->next)
+ numoftables++;
+
+ rsdt_addr = rsdt = (struct grub_acpi_table_header *) playground_ptr;
+ playground_ptr += sizeof (struct grub_acpi_table_header) + sizeof (grub_uint32_t) * numoftables;
+
+ rsdt_entry = (grub_uint32_t *) (rsdt + 1);
+
+ /* Fill RSDT header. */
+ grub_memcpy (&(rsdt->signature), "RSDT", 4);
+ rsdt->length = sizeof (struct grub_acpi_table_header) + sizeof (grub_uint32_t) * numoftables;
+ rsdt->revision = 1;
+ grub_memcpy (&(rsdt->oemid), root_oemid, sizeof (rsdt->oemid));
+ grub_memcpy (&(rsdt->oemtable), root_oemtable, sizeof (rsdt->oemtable));
+ rsdt->oemrev = root_oemrev;
+ grub_memcpy (&(rsdt->creator_id), root_creator_id, sizeof (rsdt->creator_id));
+ rsdt->creator_rev = root_creator_rev;
+
+ for (cur = acpi_tables; cur; cur = cur->next)
+ *(rsdt_entry++) = (grub_addr_t) cur->addr;
+
+ /* Recompute checksum. */
+ rsdt->checksum = 0;
+ rsdt->checksum = 1 + ~grub_byte_checksum (rsdt, rsdt->length);
+}
+
+/* Regenerate ACPIv1 RSDP */
+static void
+setv1table (void)
+{
+ /* Create RSDP. */
+ rsdpv1_new = (struct grub_acpi_rsdp_v10 *) playground_ptr;
+ playground_ptr += sizeof (struct grub_acpi_rsdp_v10);
+ grub_memcpy (&(rsdpv1_new->signature), GRUB_RSDP_SIGNATURE,
+ sizeof (rsdpv1_new->signature));
+ grub_memcpy (&(rsdpv1_new->oemid), root_oemid, sizeof (rsdpv1_new->oemid));
+ rsdpv1_new->revision = 0;
+ rsdpv1_new->rsdt_addr = (grub_addr_t) rsdt_addr;
+ rsdpv1_new->checksum = 0;
+ rsdpv1_new->checksum = 1 + ~grub_byte_checksum (rsdpv1_new,
+ sizeof (*rsdpv1_new));
+ grub_dprintf ("acpi", "Generated ACPIv1 tables\n");
+}
+
+static void
+setv2table (void)
+{
+ struct grub_acpi_table_header *xsdt;
+ struct efiemu_acpi_table *cur;
+ grub_uint64_t *xsdt_entry;
+ int numoftables;
+
+ numoftables = 0;
+ for (cur = acpi_tables; cur; cur = cur->next)
+ numoftables++;
+
+ /* Create XSDT. */
+ xsdt = (struct grub_acpi_table_header *) playground_ptr;
+ playground_ptr += sizeof (struct grub_acpi_table_header) + sizeof (grub_uint64_t) * numoftables;
+
+ xsdt_entry = (grub_uint64_t *)(xsdt + 1);
+ for (cur = acpi_tables; cur; cur = cur->next)
+ *(xsdt_entry++) = (grub_addr_t) cur->addr;
+ grub_memcpy (&(xsdt->signature), "XSDT", 4);
+ xsdt->length = sizeof (struct grub_acpi_table_header) + sizeof (grub_uint64_t) * numoftables;
+ xsdt->revision = 1;
+ grub_memcpy (&(xsdt->oemid), root_oemid, sizeof (xsdt->oemid));
+ grub_memcpy (&(xsdt->oemtable), root_oemtable, sizeof (xsdt->oemtable));
+ xsdt->oemrev = root_oemrev;
+ grub_memcpy (&(xsdt->creator_id), root_creator_id, sizeof (xsdt->creator_id));
+ xsdt->creator_rev = root_creator_rev;
+ xsdt->checksum = 0;
+ xsdt->checksum = 1 + ~grub_byte_checksum (xsdt, xsdt->length);
+
+ /* Create RSDPv2. */
+ rsdpv2_new = (struct grub_acpi_rsdp_v20 *) playground_ptr;
+ playground_ptr += sizeof (struct grub_acpi_rsdp_v20);
+ grub_memcpy (&(rsdpv2_new->rsdpv1.signature), GRUB_RSDP_SIGNATURE,
+ sizeof (rsdpv2_new->rsdpv1.signature));
+ grub_memcpy (&(rsdpv2_new->rsdpv1.oemid), root_oemid,
+ sizeof (rsdpv2_new->rsdpv1.oemid));
+ rsdpv2_new->rsdpv1.revision = rev2;
+ rsdpv2_new->rsdpv1.rsdt_addr = (grub_addr_t) rsdt_addr;
+ rsdpv2_new->rsdpv1.checksum = 0;
+ rsdpv2_new->rsdpv1.checksum = 1 + ~grub_byte_checksum
+ (&(rsdpv2_new->rsdpv1), sizeof (rsdpv2_new->rsdpv1));
+ rsdpv2_new->length = sizeof (*rsdpv2_new);
+ rsdpv2_new->xsdt_addr = (grub_addr_t) xsdt;
+ rsdpv2_new->checksum = 0;
+ rsdpv2_new->checksum = 1 + ~grub_byte_checksum (rsdpv2_new,
+ rsdpv2_new->length);
+ grub_dprintf ("acpi", "Generated ACPIv2 tables\n");
+}
+
+static void
+free_tables (void)
+{
+ struct efiemu_acpi_table *cur, *t;
+ if (table_dsdt)
+ grub_free (table_dsdt);
+ for (cur = acpi_tables; cur;)
+ {
+ t = cur;
+ grub_free (cur->addr);
+ cur = cur->next;
+ grub_free (t);
+ }
+ acpi_tables = 0;
+ table_dsdt = 0;
+}
+
+static grub_err_t
+grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ struct grub_acpi_rsdp_v10 *rsdp;
+ struct efiemu_acpi_table *cur, *t;
+ int i, mmapregion;
+ int numoftables;
+
+ /* Default values if no RSDP is found. */
+ rev1 = 1;
+ rev2 = 3;
+
+ facs_addr = 0;
+ playground = playground_ptr = 0;
+ playground_size = 0;
+
+ rsdp = (struct grub_acpi_rsdp_v10 *) grub_machine_acpi_get_rsdpv2 ();
+
+ if (! rsdp)
+ rsdp = grub_machine_acpi_get_rsdpv1 ();
+
+ grub_dprintf ("acpi", "RSDP @%p\n", rsdp);
+
+ if (rsdp)
+ {
+ grub_uint32_t *entry_ptr;
+ char *exclude = 0;
+ char *load_only = 0;
+ char *ptr;
+ /* RSDT consists of header and an array of 32-bit pointers. */
+ struct grub_acpi_table_header *rsdt;
+
+ exclude = state[0].set ? grub_strdup (state[0].arg) : 0;
+ if (exclude)
+ {
+ for (ptr = exclude; *ptr; ptr++)
+ *ptr = grub_tolower (*ptr);
+ }
+
+ load_only = state[1].set ? grub_strdup (state[1].arg) : 0;
+ if (load_only)
+ {
+ for (ptr = load_only; *ptr; ptr++)
+ *ptr = grub_tolower (*ptr);
+ }
+
+ /* Set revision variables to replicate the same version as host. */
+ rev1 = ! rsdp->revision;
+ rev2 = rsdp->revision;
+ rsdt = (struct grub_acpi_table_header *) (grub_addr_t) rsdp->rsdt_addr;
+ /* Load host tables. */
+ for (entry_ptr = (grub_uint32_t *) (rsdt + 1);
+ entry_ptr < (grub_uint32_t *) (((grub_uint8_t *) rsdt)
+ + rsdt->length);
+ entry_ptr++)
+ {
+ char signature[5];
+ struct efiemu_acpi_table *table;
+ struct grub_acpi_table_header *curtable
+ = (struct grub_acpi_table_header *) (grub_addr_t) *entry_ptr;
+ signature[4] = 0;
+ for (i = 0; i < 4;i++)
+ signature[i] = grub_tolower (curtable->signature[i]);
+
+ /* If it's FADT it contains addresses of DSDT and FACS. */
+ if (grub_strcmp (signature, "facp") == 0)
+ {
+ struct grub_acpi_table_header *dsdt;
+ struct grub_acpi_fadt *fadt = (struct grub_acpi_fadt *) curtable;
+
+ /* Set root header variables to the same values
+ as FADT by default. */
+ grub_memcpy (&root_oemid, &(fadt->hdr.oemid),
+ sizeof (root_oemid));
+ grub_memcpy (&root_oemtable, &(fadt->hdr.oemtable),
+ sizeof (root_oemtable));
+ root_oemrev = fadt->hdr.oemrev;
+ grub_memcpy (&root_creator_id, &(fadt->hdr.creator_id),
+ sizeof (root_creator_id));
+ root_creator_rev = fadt->hdr.creator_rev;
+
+ /* Load DSDT if not excluded. */
+ dsdt = (struct grub_acpi_table_header *)
+ (grub_addr_t) fadt->dsdt_addr;
+ if (dsdt && (! exclude || ! grub_strword (exclude, "dsdt"))
+ && (! load_only || grub_strword (load_only, "dsdt"))
+ && dsdt->length >= sizeof (*dsdt))
+ {
+ dsdt_size = dsdt->length;
+ table_dsdt = grub_malloc (dsdt->length);
+ if (! table_dsdt)
+ {
+ free_tables ();
+ grub_free (exclude);
+ grub_free (load_only);
+ return grub_errno;
+ }
+ grub_memcpy (table_dsdt, dsdt, dsdt->length);
+ }
+
+ /* Save FACS address. FACS shouldn't be overridden. */
+ facs_addr = fadt->facs_addr;
+ }
+
+ /* Skip excluded tables. */
+ if (exclude && grub_strword (exclude, signature))
+ continue;
+ if (load_only && ! grub_strword (load_only, signature))
+ continue;
+
+ /* Sanity check. */
+ if (curtable->length < sizeof (*curtable))
+ continue;
+
+ table = (struct efiemu_acpi_table *) grub_malloc
+ (sizeof (struct efiemu_acpi_table));
+ if (! table)
+ {
+ free_tables ();
+ grub_free (exclude);
+ grub_free (load_only);
+ return grub_errno;
+ }
+ table->size = curtable->length;
+ table->addr = grub_malloc (table->size);
+ playground_size += table->size;
+ if (! table->addr)
+ {
+ free_tables ();
+ grub_free (exclude);
+ grub_free (load_only);
+ grub_free (table);
+ return grub_errno;
+ }
+ table->next = acpi_tables;
+ acpi_tables = table;
+ grub_memcpy (table->addr, curtable, table->size);
+ }
+ grub_free (exclude);
+ grub_free (load_only);
+ }
+
+ /* Does user specify versions to generate? */
+ if (state[2].set || state[3].set)
+ {
+ rev1 = state[2].set;
+ if (state[3].set)
+ rev2 = rev2 ? : 2;
+ else
+ rev2 = 0;
+ }
+
+ /* Does user override root header information? */
+ if (state[4].set)
+ grub_strncpy (root_oemid, state[4].arg, sizeof (root_oemid));
+ if (state[5].set)
+ grub_strncpy (root_oemtable, state[5].arg, sizeof (root_oemtable));
+ if (state[6].set)
+ root_oemrev = grub_strtoul (state[6].arg, 0, 0);
+ if (state[7].set)
+ grub_strncpy (root_creator_id, state[7].arg, sizeof (root_creator_id));
+ if (state[8].set)
+ root_creator_rev = grub_strtoul (state[8].arg, 0, 0);
+
+ /* Load user tables */
+ for (i = 0; i < argc; i++)
+ {
+ grub_file_t file;
+ grub_size_t size;
+ char *buf;
+
+ file = grub_file_open (args[i], GRUB_FILE_TYPE_ACPI_TABLE);
+ if (! file)
+ {
+ free_tables ();
+ return grub_errno;
+ }
+
+ size = grub_file_size (file);
+ if (size < sizeof (struct grub_acpi_table_header))
+ {
+ grub_file_close (file);
+ free_tables ();
+ return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+ args[i]);
+ }
+
+ buf = (char *) grub_malloc (size);
+ if (! buf)
+ {
+ grub_file_close (file);
+ free_tables ();
+ return grub_errno;
+ }
+
+ if (grub_file_read (file, buf, size) != (int) size)
+ {
+ grub_file_close (file);
+ free_tables ();
+ if (!grub_errno)
+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+ args[i]);
+ return grub_errno;
+ }
+ grub_file_close (file);
+
+ if (grub_memcmp (((struct grub_acpi_table_header *) buf)->signature,
+ "DSDT", 4) == 0)
+ {
+ grub_free (table_dsdt);
+ table_dsdt = buf;
+ dsdt_size = size;
+ }
+ else
+ {
+ struct efiemu_acpi_table *table;
+ table = (struct efiemu_acpi_table *) grub_malloc
+ (sizeof (struct efiemu_acpi_table));
+ if (! table)
+ {
+ free_tables ();
+ return grub_errno;
+ }
+
+ table->size = size;
+ table->addr = buf;
+ playground_size += table->size;
+
+ table->next = acpi_tables;
+ acpi_tables = table;
+ }
+ }
+
+ numoftables = 0;
+ for (cur = acpi_tables; cur; cur = cur->next)
+ numoftables++;
+
+ /* DSDT. */
+ playground_size += dsdt_size;
+ /* RSDT. */
+ playground_size += sizeof (struct grub_acpi_table_header) + sizeof (grub_uint32_t) * numoftables;
+ /* RSDPv1. */
+ playground_size += sizeof (struct grub_acpi_rsdp_v10);
+ /* XSDT. */
+ playground_size += sizeof (struct grub_acpi_table_header) + sizeof (grub_uint64_t) * numoftables;
+ /* RSDPv2. */
+ playground_size += sizeof (struct grub_acpi_rsdp_v20);
+
+ playground = playground_ptr
+ = grub_mmap_malign_and_register (1, playground_size, &mmapregion,
+ GRUB_MEMORY_ACPI, 0);
+
+ if (! playground)
+ {
+ free_tables ();
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't allocate space for ACPI tables");
+ }
+
+ setup_common_tables ();
+
+ /* Request space for RSDPv1. */
+ if (rev1)
+ setv1table ();
+
+ /* Request space for RSDPv2+ and XSDT. */
+ if (rev2)
+ setv2table ();
+
+ for (cur = acpi_tables; cur;)
+ {
+ t = cur;
+ cur = cur->next;
+ grub_free (t);
+ }
+ acpi_tables = 0;
+
+#if defined (__i386__) || defined (__x86_64__)
+ if (! state[9].set)
+ {
+ grub_err_t err;
+ err = grub_acpi_create_ebda ();
+ if (err)
+ {
+ rsdpv1_new = 0;
+ rsdpv2_new = 0;
+ grub_mmap_free_and_unregister (mmapregion);
+ return err;
+ }
+ }
+#endif
+
+#ifdef GRUB_MACHINE_EFI
+ {
+ struct grub_efi_guid acpi = GRUB_EFI_ACPI_TABLE_GUID;
+ struct grub_efi_guid acpi20 = GRUB_EFI_ACPI_20_TABLE_GUID;
+
+ efi_call_2 (grub_efi_system_table->boot_services->install_configuration_table,
+ &acpi20, grub_acpi_get_rsdpv2 ());
+ efi_call_2 (grub_efi_system_table->boot_services->install_configuration_table,
+ &acpi, grub_acpi_get_rsdpv1 ());
+ }
+#endif
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(acpi)
+{
+ cmd = grub_register_extcmd_lockdown ("acpi", grub_cmd_acpi, 0,
+ N_("[-1|-2] [--exclude=TABLE1,TABLE2|"
+ "--load-only=TABLE1,TABLE2] FILE1"
+ " [FILE2] [...]"),
+ N_("Load host ACPI tables and tables "
+ "specified by arguments."),
+ options);
+}
+
+GRUB_MOD_FINI(acpi)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/acpihalt.c b/grub-core/commands/acpihalt.c
new file mode 100644
index 0000000..9cc7f18
--- /dev/null
+++ b/grub-core/commands/acpihalt.c
@@ -0,0 +1,454 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010 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/>.
+ */
+
+#ifdef GRUB_DSDT_TEST
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#define grub_dprintf(cond, args...) printf ( args )
+#define grub_printf printf
+#define grub_util_fopen fopen
+#define grub_memcmp memcmp
+typedef uint64_t grub_uint64_t;
+typedef uint32_t grub_uint32_t;
+typedef uint16_t grub_uint16_t;
+typedef uint8_t grub_uint8_t;
+
+#endif
+
+#include <grub/acpi.h>
+#ifndef GRUB_DSDT_TEST
+#include <grub/i18n.h>
+#else
+#define _(x) x
+#define N_(x) x
+#endif
+
+#ifndef GRUB_DSDT_TEST
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/time.h>
+#include <grub/cpu/io.h>
+#endif
+
+static inline grub_uint32_t
+decode_length (const grub_uint8_t *ptr, int *numlen)
+{
+ int num_bytes, i;
+ grub_uint32_t ret;
+ if (*ptr < 64)
+ {
+ if (numlen)
+ *numlen = 1;
+ return *ptr;
+ }
+ num_bytes = *ptr >> 6;
+ if (numlen)
+ *numlen = num_bytes + 1;
+ ret = *ptr & 0xf;
+ ptr++;
+ for (i = 0; i < num_bytes; i++)
+ {
+ ret |= *ptr << (8 * i + 4);
+ ptr++;
+ }
+ return ret;
+}
+
+static inline grub_uint32_t
+skip_name_string (const grub_uint8_t *ptr, const grub_uint8_t *end)
+{
+ const grub_uint8_t *ptr0 = ptr;
+
+ while (ptr < end && (*ptr == '^' || *ptr == '\\'))
+ ptr++;
+ switch (*ptr)
+ {
+ case '.':
+ ptr++;
+ ptr += 8;
+ break;
+ case '/':
+ ptr++;
+ ptr += 1 + (*ptr) * 4;
+ break;
+ case 0:
+ ptr++;
+ break;
+ default:
+ ptr += 4;
+ break;
+ }
+ return ptr - ptr0;
+}
+
+static inline grub_uint32_t
+skip_data_ref_object (const grub_uint8_t *ptr, const grub_uint8_t *end)
+{
+ grub_dprintf ("acpi", "data type = 0x%x\n", *ptr);
+ switch (*ptr)
+ {
+ case GRUB_ACPI_OPCODE_PACKAGE:
+ case GRUB_ACPI_OPCODE_BUFFER:
+ return 1 + decode_length (ptr + 1, 0);
+ case GRUB_ACPI_OPCODE_ZERO:
+ case GRUB_ACPI_OPCODE_ONES:
+ case GRUB_ACPI_OPCODE_ONE:
+ return 1;
+ case GRUB_ACPI_OPCODE_BYTE_CONST:
+ return 2;
+ case GRUB_ACPI_OPCODE_WORD_CONST:
+ return 3;
+ case GRUB_ACPI_OPCODE_DWORD_CONST:
+ return 5;
+ case GRUB_ACPI_OPCODE_STRING_CONST:
+ {
+ const grub_uint8_t *ptr0 = ptr;
+ for (ptr++; ptr < end && *ptr; ptr++);
+ if (ptr == end)
+ return 0;
+ return ptr - ptr0 + 1;
+ }
+ default:
+ if (*ptr == '^' || *ptr == '\\' || *ptr == '_'
+ || (*ptr >= 'A' && *ptr <= 'Z'))
+ return skip_name_string (ptr, end);
+ grub_printf ("Unknown opcode 0x%x\n", *ptr);
+ return 0;
+ }
+}
+
+static inline grub_uint32_t
+skip_term (const grub_uint8_t *ptr, const grub_uint8_t *end)
+{
+ grub_uint32_t add;
+ const grub_uint8_t *ptr0 = ptr;
+
+ switch(*ptr)
+ {
+ case GRUB_ACPI_OPCODE_ADD:
+ case GRUB_ACPI_OPCODE_AND:
+ case GRUB_ACPI_OPCODE_CONCAT:
+ case GRUB_ACPI_OPCODE_CONCATRES:
+ case GRUB_ACPI_OPCODE_DIVIDE:
+ case GRUB_ACPI_OPCODE_INDEX:
+ case GRUB_ACPI_OPCODE_LSHIFT:
+ case GRUB_ACPI_OPCODE_MOD:
+ case GRUB_ACPI_OPCODE_MULTIPLY:
+ case GRUB_ACPI_OPCODE_NAND:
+ case GRUB_ACPI_OPCODE_NOR:
+ case GRUB_ACPI_OPCODE_OR:
+ case GRUB_ACPI_OPCODE_RSHIFT:
+ case GRUB_ACPI_OPCODE_SUBTRACT:
+ case GRUB_ACPI_OPCODE_TOSTRING:
+ case GRUB_ACPI_OPCODE_XOR:
+ /*
+ * Parameters for these opcodes: TermArg, TermArg Target, see ACPI
+ * spec r5.0, page 828f.
+ */
+ ptr++;
+ ptr += add = skip_term (ptr, end);
+ if (!add)
+ return 0;
+ ptr += add = skip_term (ptr, end);
+ if (!add)
+ return 0;
+ ptr += skip_name_string (ptr, end);
+ break;
+ default:
+ return skip_data_ref_object (ptr, end);
+ }
+ return ptr - ptr0;
+}
+
+static inline grub_uint32_t
+skip_ext_op (const grub_uint8_t *ptr, const grub_uint8_t *end)
+{
+ const grub_uint8_t *ptr0 = ptr;
+ int add;
+ grub_dprintf ("acpi", "Extended opcode: 0x%x\n", *ptr);
+ switch (*ptr)
+ {
+ case GRUB_ACPI_EXTOPCODE_MUTEX:
+ ptr++;
+ ptr += skip_name_string (ptr, end);
+ ptr++;
+ break;
+ case GRUB_ACPI_EXTOPCODE_EVENT_OP:
+ ptr++;
+ ptr += skip_name_string (ptr, end);
+ break;
+ case GRUB_ACPI_EXTOPCODE_OPERATION_REGION:
+ ptr++;
+ ptr += skip_name_string (ptr, end);
+ ptr++;
+ ptr += add = skip_term (ptr, end);
+ if (!add)
+ return 0;
+ ptr += add = skip_term (ptr, end);
+ if (!add)
+ return 0;
+ break;
+ case GRUB_ACPI_EXTOPCODE_FIELD_OP:
+ case GRUB_ACPI_EXTOPCODE_DEVICE_OP:
+ case GRUB_ACPI_EXTOPCODE_PROCESSOR_OP:
+ case GRUB_ACPI_EXTOPCODE_POWER_RES_OP:
+ case GRUB_ACPI_EXTOPCODE_THERMAL_ZONE_OP:
+ case GRUB_ACPI_EXTOPCODE_INDEX_FIELD_OP:
+ case GRUB_ACPI_EXTOPCODE_BANK_FIELD_OP:
+ ptr++;
+ ptr += decode_length (ptr, 0);
+ break;
+ default:
+ grub_printf ("Unexpected extended opcode: 0x%x\n", *ptr);
+ return 0;
+ }
+ return ptr - ptr0;
+}
+
+
+static int
+get_sleep_type (grub_uint8_t *table, grub_uint8_t *ptr, grub_uint8_t *end,
+ grub_uint8_t *scope, int scope_len)
+{
+ grub_uint8_t *prev = table;
+
+ if (!ptr)
+ ptr = table + sizeof (struct grub_acpi_table_header);
+ while (ptr < end && prev < ptr)
+ {
+ int add;
+ prev = ptr;
+ grub_dprintf ("acpi", "Opcode 0x%x\n", *ptr);
+ grub_dprintf ("acpi", "Tell %x\n", (unsigned) (ptr - table));
+ switch (*ptr)
+ {
+ case GRUB_ACPI_OPCODE_EXTOP:
+ ptr++;
+ ptr += add = skip_ext_op (ptr, end);
+ if (!add)
+ return -1;
+ break;
+ case GRUB_ACPI_OPCODE_CREATE_DWORD_FIELD:
+ case GRUB_ACPI_OPCODE_CREATE_WORD_FIELD:
+ case GRUB_ACPI_OPCODE_CREATE_BYTE_FIELD:
+ {
+ ptr += 5;
+ ptr += add = skip_data_ref_object (ptr, end);
+ if (!add)
+ return -1;
+ ptr += 4;
+ break;
+ }
+ case GRUB_ACPI_OPCODE_NAME:
+ ptr++;
+ if ((!scope || grub_memcmp (scope, "\\", scope_len) == 0) &&
+ (grub_memcmp (ptr, "_S5_", 4) == 0 || grub_memcmp (ptr, "\\_S5_", 4) == 0))
+ {
+ int ll;
+ grub_uint8_t *ptr2 = ptr;
+ grub_dprintf ("acpi", "S5 found\n");
+ ptr2 += skip_name_string (ptr, end);
+ if (*ptr2 != 0x12)
+ {
+ grub_printf ("Unknown opcode in _S5: 0x%x\n", *ptr2);
+ return -1;
+ }
+ ptr2++;
+ decode_length (ptr2, &ll);
+ ptr2 += ll;
+ ptr2++;
+ switch (*ptr2)
+ {
+ case GRUB_ACPI_OPCODE_ZERO:
+ return 0;
+ case GRUB_ACPI_OPCODE_ONE:
+ return 1;
+ case GRUB_ACPI_OPCODE_BYTE_CONST:
+ return ptr2[1];
+ default:
+ grub_printf ("Unknown data type in _S5: 0x%x\n", *ptr2);
+ return -1;
+ }
+ }
+ ptr += add = skip_name_string (ptr, end);
+ if (!add)
+ return -1;
+ ptr += add = skip_data_ref_object (ptr, end);
+ if (!add)
+ return -1;
+ break;
+ case GRUB_ACPI_OPCODE_ALIAS:
+ ptr++;
+ /* We need to skip two name strings */
+ ptr += add = skip_name_string (ptr, end);
+ if (!add)
+ return -1;
+ ptr += add = skip_name_string (ptr, end);
+ if (!add)
+ return -1;
+ break;
+
+ case GRUB_ACPI_OPCODE_SCOPE:
+ {
+ int scope_sleep_type;
+ int ll;
+ grub_uint8_t *name;
+ int name_len;
+
+ ptr++;
+ add = decode_length (ptr, &ll);
+ name = ptr + ll;
+ name_len = skip_name_string (name, ptr + add);
+ if (!name_len)
+ return -1;
+ scope_sleep_type = get_sleep_type (table, name + name_len,
+ ptr + add, name, name_len);
+ if (scope_sleep_type != -2)
+ return scope_sleep_type;
+ ptr += add;
+ break;
+ }
+ case GRUB_ACPI_OPCODE_IF:
+ case GRUB_ACPI_OPCODE_METHOD:
+ {
+ ptr++;
+ ptr += decode_length (ptr, 0);
+ break;
+ }
+ default:
+ grub_printf ("Unknown opcode 0x%x\n", *ptr);
+ return -1;
+ }
+ }
+
+ return -2;
+}
+
+#ifdef GRUB_DSDT_TEST
+int
+main (int argc, char **argv)
+{
+ FILE *f;
+ size_t len;
+ unsigned char *buf;
+ if (argc < 2)
+ printf ("Usage: %s FILE\n", argv[0]);
+ f = grub_util_fopen (argv[1], "rb");
+ if (!f)
+ {
+ printf ("Couldn't open file\n");
+ return 1;
+ }
+ fseek (f, 0, SEEK_END);
+ len = ftell (f);
+ fseek (f, 0, SEEK_SET);
+ buf = malloc (len);
+ if (!buf)
+ {
+ printf (_("error: %s.\n"), _("out of memory"));
+ fclose (f);
+ return 2;
+ }
+ if (fread (buf, 1, len, f) != len)
+ {
+ printf (_("cannot read `%s': %s"), argv[1], strerror (errno));
+ free (buf);
+ fclose (f);
+ return 2;
+ }
+
+ printf ("Sleep type = %d\n", get_sleep_type (buf, NULL, buf + len, NULL, 0));
+ free (buf);
+ fclose (f);
+ return 0;
+}
+
+#else
+
+void
+grub_acpi_halt (void)
+{
+ struct grub_acpi_rsdp_v20 *rsdp2;
+ struct grub_acpi_rsdp_v10 *rsdp1;
+ struct grub_acpi_table_header *rsdt;
+ grub_uint32_t *entry_ptr;
+ grub_uint32_t port = 0;
+ int sleep_type = -1;
+
+ rsdp2 = grub_acpi_get_rsdpv2 ();
+ if (rsdp2)
+ rsdp1 = &(rsdp2->rsdpv1);
+ else
+ rsdp1 = grub_acpi_get_rsdpv1 ();
+ grub_dprintf ("acpi", "rsdp1=%p\n", rsdp1);
+ if (!rsdp1)
+ return;
+
+ rsdt = (struct grub_acpi_table_header *) (grub_addr_t) rsdp1->rsdt_addr;
+ for (entry_ptr = (grub_uint32_t *) (rsdt + 1);
+ entry_ptr < (grub_uint32_t *) (((grub_uint8_t *) rsdt)
+ + rsdt->length);
+ entry_ptr++)
+ {
+ if (grub_memcmp ((void *) (grub_addr_t) *entry_ptr, "FACP", 4) == 0)
+ {
+ struct grub_acpi_fadt *fadt
+ = ((struct grub_acpi_fadt *) (grub_addr_t) *entry_ptr);
+ struct grub_acpi_table_header *dsdt
+ = (struct grub_acpi_table_header *) (grub_addr_t) fadt->dsdt_addr;
+ grub_uint8_t *buf = (grub_uint8_t *) dsdt;
+
+ port = fadt->pm1a;
+
+ grub_dprintf ("acpi", "PM1a port=%x\n", port);
+
+ if (grub_memcmp (dsdt->signature, "DSDT",
+ sizeof (dsdt->signature)) == 0
+ && sleep_type < 0)
+ sleep_type = get_sleep_type (buf, NULL, buf + dsdt->length,
+ NULL, 0);
+ }
+ else if (grub_memcmp ((void *) (grub_addr_t) *entry_ptr, "SSDT", 4) == 0
+ && sleep_type < 0)
+ {
+ struct grub_acpi_table_header *ssdt
+ = (struct grub_acpi_table_header *) (grub_addr_t) *entry_ptr;
+ grub_uint8_t *buf = (grub_uint8_t *) ssdt;
+
+ grub_dprintf ("acpi", "SSDT = %p\n", ssdt);
+
+ sleep_type = get_sleep_type (buf, NULL, buf + ssdt->length, NULL, 0);
+ }
+ }
+
+ grub_dprintf ("acpi", "SLP_TYP = %d, port = 0x%x\n", sleep_type, port);
+ if (port && sleep_type >= 0 && sleep_type < 8)
+ grub_outw (GRUB_ACPI_SLP_EN | (sleep_type << GRUB_ACPI_SLP_TYP_OFFSET),
+ port & 0xffff);
+
+ grub_millisleep (1500);
+
+ /* TRANSLATORS: It's computer shutdown using ACPI, not disabling ACPI. */
+ grub_puts_ (N_("ACPI shutdown failed"));
+}
+#endif
diff --git a/grub-core/commands/arc/lsdev.c b/grub-core/commands/arc/lsdev.c
new file mode 100644
index 0000000..27ed0a2
--- /dev/null
+++ b/grub-core/commands/arc/lsdev.c
@@ -0,0 +1,57 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2011 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/misc.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/arc/arc.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* Helper for grub_cmd_lsdev. */
+static int
+grub_cmd_lsdev_iter (const char *name,
+ const struct grub_arc_component *comp __attribute__ ((unused)),
+ void *data __attribute__ ((unused)))
+{
+ grub_printf ("%s\n", name);
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_lsdev (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ grub_arc_iterate_devs (grub_cmd_lsdev_iter, 0, 0);
+ return 0;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(lsdev)
+{
+ cmd = grub_register_command ("lsdev", grub_cmd_lsdev, "",
+ N_("List devices."));
+}
+
+GRUB_MOD_FINI(lsdev)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/blocklist.c b/grub-core/commands/blocklist.c
new file mode 100644
index 0000000..944449b
--- /dev/null
+++ b/grub-core/commands/blocklist.c
@@ -0,0 +1,160 @@
+/* blocklist.c - print the block list of a file */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007 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/misc.h>
+#include <grub/file.h>
+#include <grub/mm.h>
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* Context for grub_cmd_blocklist. */
+struct blocklist_ctx
+{
+ unsigned long start_sector;
+ unsigned num_sectors;
+ int num_entries;
+ grub_disk_addr_t part_start;
+};
+
+/* Helper for grub_cmd_blocklist. */
+static void
+print_blocklist (grub_disk_addr_t sector, unsigned num,
+ unsigned offset, unsigned length, struct blocklist_ctx *ctx)
+{
+ if (ctx->num_entries++)
+ grub_printf (",");
+
+ grub_printf ("%llu", (unsigned long long) (sector - ctx->part_start));
+ if (num > 0)
+ grub_printf ("+%u", num);
+ if (offset != 0 || length != 0)
+ grub_printf ("[%u-%u]", offset, offset + length);
+}
+
+/* Helper for grub_cmd_blocklist. */
+static void
+read_blocklist (grub_disk_addr_t sector, unsigned offset, unsigned length,
+ void *data)
+{
+ struct blocklist_ctx *ctx = data;
+
+ if (ctx->num_sectors > 0)
+ {
+ if (ctx->start_sector + ctx->num_sectors == sector
+ && offset == 0 && length >= GRUB_DISK_SECTOR_SIZE)
+ {
+ ctx->num_sectors += length >> GRUB_DISK_SECTOR_BITS;
+ sector += length >> GRUB_DISK_SECTOR_BITS;
+ length &= (GRUB_DISK_SECTOR_SIZE - 1);
+ }
+
+ if (!length)
+ return;
+ print_blocklist (ctx->start_sector, ctx->num_sectors, 0, 0, ctx);
+ ctx->num_sectors = 0;
+ }
+
+ if (offset)
+ {
+ unsigned l = length + offset;
+ l &= (GRUB_DISK_SECTOR_SIZE - 1);
+ l -= offset;
+ print_blocklist (sector, 0, offset, l, ctx);
+ length -= l;
+ sector++;
+ offset = 0;
+ }
+
+ if (!length)
+ return;
+
+ if (length & (GRUB_DISK_SECTOR_SIZE - 1))
+ {
+ if (length >> GRUB_DISK_SECTOR_BITS)
+ {
+ print_blocklist (sector, length >> GRUB_DISK_SECTOR_BITS, 0, 0, ctx);
+ sector += length >> GRUB_DISK_SECTOR_BITS;
+ }
+ print_blocklist (sector, 0, 0, length & (GRUB_DISK_SECTOR_SIZE - 1), ctx);
+ }
+ else
+ {
+ ctx->start_sector = sector;
+ ctx->num_sectors = length >> GRUB_DISK_SECTOR_BITS;
+ }
+}
+
+static grub_err_t
+grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ grub_file_t file;
+ char buf[GRUB_DISK_SECTOR_SIZE];
+ struct blocklist_ctx ctx = {
+ .start_sector = 0,
+ .num_sectors = 0,
+ .num_entries = 0,
+ .part_start = 0
+ };
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ file = grub_file_open (args[0], GRUB_FILE_TYPE_PRINT_BLOCKLIST
+ | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (! file)
+ return grub_errno;
+
+ if (! file->device->disk)
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ "this command is available only for disk devices");
+
+ ctx.part_start = grub_partition_get_start (file->device->disk->partition);
+
+ file->read_hook = read_blocklist;
+ file->read_hook_data = &ctx;
+
+ while (grub_file_read (file, buf, sizeof (buf)) > 0)
+ ;
+
+ if (ctx.num_sectors > 0)
+ print_blocklist (ctx.start_sector, ctx.num_sectors, 0, 0, &ctx);
+
+ grub_file_close (file);
+
+ return grub_errno;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(blocklist)
+{
+ cmd = grub_register_command ("blocklist", grub_cmd_blocklist,
+ N_("FILE"), N_("Print a block list."));
+}
+
+GRUB_MOD_FINI(blocklist)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c
new file mode 100644
index 0000000..bbca81e
--- /dev/null
+++ b/grub-core/commands/boot.c
@@ -0,0 +1,195 @@
+/* boot.c - command to boot an operating system */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2004,2005,2007,2009 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/normal.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/loader.h>
+#include <grub/kernel.h>
+#include <grub/mm.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t (*grub_loader_boot_func) (void);
+static grub_err_t (*grub_loader_unload_func) (void);
+static int grub_loader_flags;
+
+struct grub_preboot
+{
+ grub_err_t (*preboot_func) (int);
+ grub_err_t (*preboot_rest_func) (void);
+ grub_loader_preboot_hook_prio_t prio;
+ struct grub_preboot *next;
+ struct grub_preboot *prev;
+};
+
+static int grub_loader_loaded;
+static struct grub_preboot *preboots_head = 0,
+ *preboots_tail = 0;
+
+int
+grub_loader_is_loaded (void)
+{
+ return grub_loader_loaded;
+}
+
+/* Register a preboot hook. */
+struct grub_preboot *
+grub_loader_register_preboot_hook (grub_err_t (*preboot_func) (int flags),
+ grub_err_t (*preboot_rest_func) (void),
+ grub_loader_preboot_hook_prio_t prio)
+{
+ struct grub_preboot *cur, *new_preboot;
+
+ if (! preboot_func && ! preboot_rest_func)
+ return 0;
+
+ new_preboot = (struct grub_preboot *)
+ grub_malloc (sizeof (struct grub_preboot));
+ if (! new_preboot)
+ return 0;
+
+ new_preboot->preboot_func = preboot_func;
+ new_preboot->preboot_rest_func = preboot_rest_func;
+ new_preboot->prio = prio;
+
+ for (cur = preboots_head; cur && cur->prio > prio; cur = cur->next);
+
+ if (cur)
+ {
+ new_preboot->next = cur;
+ new_preboot->prev = cur->prev;
+ cur->prev = new_preboot;
+ }
+ else
+ {
+ new_preboot->next = 0;
+ new_preboot->prev = preboots_tail;
+ preboots_tail = new_preboot;
+ }
+ if (new_preboot->prev)
+ new_preboot->prev->next = new_preboot;
+ else
+ preboots_head = new_preboot;
+
+ return new_preboot;
+}
+
+void
+grub_loader_unregister_preboot_hook (struct grub_preboot *hnd)
+{
+ struct grub_preboot *preb = hnd;
+
+ if (preb->next)
+ preb->next->prev = preb->prev;
+ else
+ preboots_tail = preb->prev;
+ if (preb->prev)
+ preb->prev->next = preb->next;
+ else
+ preboots_head = preb->next;
+
+ grub_free (preb);
+}
+
+void
+grub_loader_set (grub_err_t (*boot) (void),
+ grub_err_t (*unload) (void),
+ int flags)
+{
+ if (grub_loader_loaded && grub_loader_unload_func)
+ grub_loader_unload_func ();
+
+ grub_loader_boot_func = boot;
+ grub_loader_unload_func = unload;
+ grub_loader_flags = flags;
+
+ grub_loader_loaded = 1;
+}
+
+void
+grub_loader_unset(void)
+{
+ if (grub_loader_loaded && grub_loader_unload_func)
+ grub_loader_unload_func ();
+
+ grub_loader_boot_func = 0;
+ grub_loader_unload_func = 0;
+
+ grub_loader_loaded = 0;
+}
+
+grub_err_t
+grub_loader_boot (void)
+{
+ grub_err_t err = GRUB_ERR_NONE;
+ struct grub_preboot *cur;
+
+ if (! grub_loader_loaded)
+ return grub_error (GRUB_ERR_NO_KERNEL,
+ N_("you need to load the kernel first"));
+
+ grub_machine_fini (grub_loader_flags);
+
+ for (cur = preboots_head; cur; cur = cur->next)
+ {
+ err = cur->preboot_func (grub_loader_flags);
+ if (err)
+ {
+ for (cur = cur->prev; cur; cur = cur->prev)
+ cur->preboot_rest_func ();
+ return err;
+ }
+ }
+ err = (grub_loader_boot_func) ();
+
+ for (cur = preboots_tail; cur; cur = cur->prev)
+ if (! err)
+ err = cur->preboot_rest_func ();
+ else
+ cur->preboot_rest_func ();
+
+ return err;
+}
+
+/* boot */
+static grub_err_t
+grub_cmd_boot (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ return grub_loader_boot ();
+}
+
+
+
+static grub_command_t cmd_boot;
+
+GRUB_MOD_INIT(boot)
+{
+ cmd_boot =
+ grub_register_command ("boot", grub_cmd_boot,
+ 0, N_("Boot an operating system."));
+}
+
+GRUB_MOD_FINI(boot)
+{
+ grub_unregister_command (cmd_boot);
+}
diff --git a/grub-core/commands/boottime.c b/grub-core/commands/boottime.c
new file mode 100644
index 0000000..dcc078c
--- /dev/null
+++ b/grub-core/commands/boottime.c
@@ -0,0 +1,65 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/misc.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+
+static grub_err_t
+grub_cmd_boottime (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ struct grub_boot_time *cur;
+ grub_uint64_t last_time = 0, start_time = 0;
+ if (!grub_boot_time_head)
+ {
+ grub_puts_ (N_("No boot time statistics is available\n"));
+ return 0;
+ }
+ start_time = last_time = grub_boot_time_head->tp;
+ for (cur = grub_boot_time_head; cur; cur = cur->next)
+ {
+ grub_uint32_t tmabs = cur->tp - start_time;
+ grub_uint32_t tmrel = cur->tp - last_time;
+ last_time = cur->tp;
+
+ grub_printf ("%3d.%03ds %2d.%03ds %s:%d %s\n",
+ tmabs / 1000, tmabs % 1000, tmrel / 1000, tmrel % 1000, cur->file, cur->line,
+ cur->msg);
+ }
+ return 0;
+}
+
+static grub_command_t cmd_boottime;
+
+GRUB_MOD_INIT(boottime)
+{
+ cmd_boottime =
+ grub_register_command ("boottime", grub_cmd_boottime,
+ 0, N_("Show boot time statistics."));
+}
+
+GRUB_MOD_FINI(boottime)
+{
+ grub_unregister_command (cmd_boottime);
+}
diff --git a/grub-core/commands/cacheinfo.c b/grub-core/commands/cacheinfo.c
new file mode 100644
index 0000000..d34a346
--- /dev/null
+++ b/grub-core/commands/cacheinfo.c
@@ -0,0 +1,62 @@
+/* cacheinfo.c - disk cache statistics */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008,2010 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/misc.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/disk.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+grub_rescue_cmd_info (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ unsigned long hits, misses;
+
+ grub_disk_cache_get_performance (&hits, &misses);
+ if (hits + misses)
+ {
+ unsigned long ratio = hits * 10000 / (hits + misses);
+ grub_printf ("(%lu.%lu%%)\n", ratio / 100, ratio % 100);
+ grub_printf_ (N_("Disk cache statistics: hits = %lu (%lu.%02lu%%),"
+ " misses = %lu\n"), ratio / 100, ratio % 100,
+ hits, misses);
+ }
+ else
+ grub_printf ("%s\n", _("No disk cache statistics available\n"));
+
+ return 0;
+}
+
+static grub_command_t cmd_cacheinfo;
+
+GRUB_MOD_INIT(cacheinfo)
+{
+ cmd_cacheinfo =
+ grub_register_command ("cacheinfo", grub_rescue_cmd_info,
+ 0, N_("Get disk cache info."));
+}
+
+GRUB_MOD_FINI(cacheinfo)
+{
+ grub_unregister_command (cmd_cacheinfo);
+}
diff --git a/grub-core/commands/cat.c b/grub-core/commands/cat.c
new file mode 100644
index 0000000..ba5f006
--- /dev/null
+++ b/grub-core/commands/cat.c
@@ -0,0 +1,170 @@
+/* cat.c - command to show the contents of a file */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2005,2007,2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/term.h>
+#include <grub/misc.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+#include <grub/charset.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =
+ {
+ {"dos", -1, 0, N_("Accept DOS-style CR/NL line endings."), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static grub_err_t
+grub_cmd_cat (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ int dos = 0;
+ grub_file_t file;
+ unsigned char buf[GRUB_DISK_SECTOR_SIZE];
+ grub_ssize_t size;
+ int key = GRUB_TERM_NO_KEY;
+ grub_uint32_t code = 0;
+ int count = 0;
+ unsigned char utbuf[GRUB_MAX_UTF8_PER_CODEPOINT + 1];
+ int utcount = 0;
+ int is_0d = 0;
+ int j;
+
+ if (state[0].set)
+ dos = 1;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ file = grub_file_open (args[0], GRUB_FILE_TYPE_CAT);
+ if (! file)
+ return grub_errno;
+
+ while ((size = grub_file_read (file, buf, sizeof (buf))) > 0
+ && key != GRUB_TERM_ESC)
+ {
+ int i;
+
+ for (i = 0; i < size; i++)
+ {
+ utbuf[utcount++] = buf[i];
+
+ if (is_0d && buf[i] != '\n')
+ {
+ grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
+ grub_printf ("<%x>", (int) '\r');
+ grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
+ }
+
+ is_0d = 0;
+
+ if (!grub_utf8_process (buf[i], &code, &count))
+ {
+ grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
+ for (j = 0; j < utcount - 1; j++)
+ grub_printf ("<%x>", (unsigned int) utbuf[j]);
+ code = 0;
+ count = 0;
+ if (utcount == 1 || !grub_utf8_process (buf[i], &code, &count))
+ {
+ grub_printf ("<%x>", (unsigned int) buf[i]);
+ code = 0;
+ count = 0;
+ utcount = 0;
+ grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
+ continue;
+ }
+ grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
+ utcount = 1;
+ }
+ if (count)
+ continue;
+
+ if ((code >= 0xa1 || grub_isprint (code)
+ || grub_isspace (code)) && code != '\r')
+ {
+ grub_printf ("%C", code);
+ count = 0;
+ code = 0;
+ utcount = 0;
+ continue;
+ }
+
+ if (dos && code == '\r')
+ {
+ is_0d = 1;
+ count = 0;
+ code = 0;
+ utcount = 0;
+ continue;
+ }
+
+ grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
+ for (j = 0; j < utcount; j++)
+ grub_printf ("<%x>", (unsigned int) utbuf[j]);
+ grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
+ count = 0;
+ code = 0;
+ utcount = 0;
+ }
+
+ do
+ key = grub_getkey_noblock ();
+ while (key != GRUB_TERM_ESC && key != GRUB_TERM_NO_KEY);
+ }
+
+ if (is_0d)
+ {
+ grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
+ grub_printf ("<%x>", (unsigned int) '\r');
+ grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
+ }
+
+ if (utcount)
+ {
+ grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
+ for (j = 0; j < utcount; j++)
+ grub_printf ("<%x>", (unsigned int) utbuf[j]);
+ grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
+ }
+
+ grub_xputs ("\n");
+ grub_refresh ();
+ grub_file_close (file);
+
+ return 0;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(cat)
+{
+ cmd = grub_register_extcmd ("cat", grub_cmd_cat, 0,
+ N_("FILE"), N_("Show the contents of a file."),
+ options);
+}
+
+GRUB_MOD_FINI(cat)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/cmp.c b/grub-core/commands/cmp.c
new file mode 100644
index 0000000..e9c3b25
--- /dev/null
+++ b/grub-core/commands/cmp.c
@@ -0,0 +1,119 @@
+/* cmd.c - command to cmp an operating system */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2005,2006,2007,2009 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/misc.h>
+#include <grub/file.h>
+#include <grub/mm.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define BUFFER_SIZE 512
+
+static grub_err_t
+grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ grub_ssize_t rd1, rd2;
+ grub_off_t pos;
+ grub_file_t file1 = 0;
+ grub_file_t file2 = 0;
+ char *buf1 = 0;
+ char *buf2 = 0;
+
+ if (argc != 2)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
+
+ grub_printf_ (N_("Compare file `%s' with `%s':\n"), args[0],
+ args[1]);
+
+ file1 = grub_file_open (args[0], GRUB_FILE_TYPE_CMP);
+ file2 = grub_file_open (args[1], GRUB_FILE_TYPE_CMP);
+ if (! file1 || ! file2)
+ goto cleanup;
+
+ if (grub_file_size (file1) != grub_file_size (file2))
+ grub_printf_ (N_("Files differ in size: %llu [%s], %llu [%s]\n"),
+ (unsigned long long) grub_file_size (file1), args[0],
+ (unsigned long long) grub_file_size (file2), args[1]);
+ else
+ {
+ pos = 0;
+
+ buf1 = grub_malloc (BUFFER_SIZE);
+ buf2 = grub_malloc (BUFFER_SIZE);
+
+ if (! buf1 || ! buf2)
+ goto cleanup;
+
+ do
+ {
+ int i;
+
+ rd1 = grub_file_read (file1, buf1, BUFFER_SIZE);
+ rd2 = grub_file_read (file2, buf2, BUFFER_SIZE);
+
+ if (rd1 != rd2)
+ goto cleanup;
+
+ for (i = 0; i < rd2; i++)
+ {
+ if (buf1[i] != buf2[i])
+ {
+ grub_printf_ (N_("Files differ at the offset %llu: 0x%x [%s], 0x%x [%s]\n"),
+ (unsigned long long) (i + pos), buf1[i],
+ args[0], buf2[i], args[1]);
+ goto cleanup;
+ }
+ }
+ pos += BUFFER_SIZE;
+
+ }
+ while (rd2);
+
+ /* TRANSLATORS: it's always exactly 2 files. */
+ grub_printf_ (N_("The files are identical.\n"));
+ }
+
+cleanup:
+
+ grub_free (buf1);
+ grub_free (buf2);
+ if (file1)
+ grub_file_close (file1);
+ if (file2)
+ grub_file_close (file2);
+
+ return grub_errno;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(cmp)
+{
+ cmd = grub_register_command ("cmp", grub_cmd_cmp,
+ N_("FILE1 FILE2"), N_("Compare two files."));
+}
+
+GRUB_MOD_FINI(cmp)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/configfile.c b/grub-core/commands/configfile.c
new file mode 100644
index 0000000..f2d2abb
--- /dev/null
+++ b/grub-core/commands/configfile.c
@@ -0,0 +1,98 @@
+/* configfile.c - command to manually load config file */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2006,2007,2009 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/term.h>
+#include <grub/env.h>
+#include <grub/normal.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+grub_cmd_source (grub_command_t cmd, int argc, char **args)
+{
+ int new_env, extractor;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ extractor = (cmd->name[0] == 'e');
+ new_env = (cmd->name[extractor ? sizeof ("extract_entries_") - 1 : 0] == 'c');
+
+ if (new_env)
+ grub_cls ();
+
+ if (new_env && !extractor)
+ grub_env_context_open ();
+ if (extractor)
+ grub_env_extractor_open (!new_env);
+
+ grub_normal_execute (args[0], 1, ! new_env);
+
+ if (new_env && !extractor)
+ grub_env_context_close ();
+ if (extractor)
+ grub_env_extractor_close (!new_env);
+
+ return 0;
+}
+
+static grub_command_t cmd_configfile, cmd_source, cmd_dot;
+static grub_command_t cmd_extractor_source, cmd_extractor_configfile;
+
+GRUB_MOD_INIT(configfile)
+{
+ cmd_configfile =
+ grub_register_command ("configfile", grub_cmd_source,
+ N_("FILE"), N_("Load another config file."));
+ cmd_source =
+ grub_register_command ("source", grub_cmd_source,
+ N_("FILE"),
+ N_("Load another config file without changing context.")
+ );
+
+ cmd_extractor_source =
+ grub_register_command ("extract_entries_source", grub_cmd_source,
+ N_("FILE"),
+ N_("Load another config file without changing context but take only menu entries.")
+ );
+
+ cmd_extractor_configfile =
+ grub_register_command ("extract_entries_configfile", grub_cmd_source,
+ N_("FILE"),
+ N_("Load another config file but take only menu entries.")
+ );
+
+ cmd_dot =
+ grub_register_command (".", grub_cmd_source,
+ N_("FILE"),
+ N_("Load another config file without changing context.")
+ );
+}
+
+GRUB_MOD_FINI(configfile)
+{
+ grub_unregister_command (cmd_configfile);
+ grub_unregister_command (cmd_source);
+ grub_unregister_command (cmd_extractor_configfile);
+ grub_unregister_command (cmd_extractor_source);
+ grub_unregister_command (cmd_dot);
+}
diff --git a/grub-core/commands/date.c b/grub-core/commands/date.c
new file mode 100644
index 0000000..5cb4faf
--- /dev/null
+++ b/grub-core/commands/date.c
@@ -0,0 +1,149 @@
+/* date.c - command to display/set current datetime. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/datetime.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define GRUB_DATETIME_SET_YEAR 1
+#define GRUB_DATETIME_SET_MONTH 2
+#define GRUB_DATETIME_SET_DAY 4
+#define GRUB_DATETIME_SET_HOUR 8
+#define GRUB_DATETIME_SET_MINUTE 16
+#define GRUB_DATETIME_SET_SECOND 32
+
+static grub_err_t
+grub_cmd_date (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ struct grub_datetime datetime;
+ int limit[6][2] = {{1980, 2079}, {1, 12}, {1, 31}, {0, 23}, {0, 59}, {0, 59}};
+ int value[6], mask;
+
+ if (argc == 0)
+ {
+ if (grub_get_datetime (&datetime))
+ return grub_errno;
+
+ grub_printf ("%d-%02d-%02d %02d:%02d:%02d %s\n",
+ datetime.year, datetime.month, datetime.day,
+ datetime.hour, datetime.minute, datetime.second,
+ grub_get_weekday_name (&datetime));
+
+ return 0;
+ }
+
+ grub_memset (&value, 0, sizeof (value));
+ mask = 0;
+
+ for (; argc; argc--, args++)
+ {
+ const char *p;
+ char c;
+ int m1, ofs, n, cur_mask;
+
+ p = args[0];
+ m1 = grub_strtoul (p, &p, 10);
+
+ c = *p;
+ if (c == '-')
+ ofs = 0;
+ else if (c == ':')
+ ofs = 3;
+ else
+ goto fail;
+
+ value[ofs] = m1;
+ cur_mask = (1 << ofs);
+ mask &= ~(cur_mask * (1 + 2 + 4));
+
+ for (n = 1; (n < 3) && (*p); n++)
+ {
+ if (*p != c)
+ goto fail;
+
+ value[ofs + n] = grub_strtoul (p + 1, &p, 10);
+ cur_mask |= (1 << (ofs + n));
+ }
+
+ if (*p)
+ goto fail;
+
+ if ((ofs == 0) && (n == 2))
+ {
+ value[ofs + 2] = value[ofs + 1];
+ value[ofs + 1] = value[ofs];
+ ofs++;
+ cur_mask <<= 1;
+ }
+
+ for (; n; n--, ofs++)
+ if ((value [ofs] < limit[ofs][0]) ||
+ (value [ofs] > limit[ofs][1]))
+ goto fail;
+
+ mask |= cur_mask;
+ }
+
+ if (grub_get_datetime (&datetime))
+ return grub_errno;
+
+ if (mask & GRUB_DATETIME_SET_YEAR)
+ datetime.year = value[0];
+
+ if (mask & GRUB_DATETIME_SET_MONTH)
+ datetime.month = value[1];
+
+ if (mask & GRUB_DATETIME_SET_DAY)
+ datetime.day = value[2];
+
+ if (mask & GRUB_DATETIME_SET_HOUR)
+ datetime.hour = value[3];
+
+ if (mask & GRUB_DATETIME_SET_MINUTE)
+ datetime.minute = value[4];
+
+ if (mask & GRUB_DATETIME_SET_SECOND)
+ datetime.second = value[5];
+
+ return grub_set_datetime (&datetime);
+
+fail:
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid datetime");
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(date)
+{
+ cmd =
+ grub_register_command ("date", grub_cmd_date,
+ N_("[[year-]month-day] [hour:minute[:second]]"),
+ N_("Display/set current datetime."));
+}
+
+GRUB_MOD_FINI(date)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/echo.c b/grub-core/commands/echo.c
new file mode 100644
index 0000000..81ba50d
--- /dev/null
+++ b/grub-core/commands/echo.c
@@ -0,0 +1,141 @@
+/* echo.c - Command to display a line of text */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007,2010 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/misc.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+#include <grub/term.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =
+ {
+ {0, 'n', 0, N_("Do not output the trailing newline."), 0, 0},
+ {0, 'e', 0, N_("Enable interpretation of backslash escapes."), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static grub_err_t
+grub_cmd_echo (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ int newline = 1;
+ int i;
+
+ /* Check if `-n' was used. */
+ if (state[0].set)
+ newline = 0;
+
+ for (i = 0; i < argc; i++)
+ {
+ char *arg = *args;
+ /* Unescaping results in a string no longer than the original. */
+ char *unescaped = grub_malloc (grub_strlen (arg) + 1);
+ char *p = unescaped;
+ args++;
+
+ if (!unescaped)
+ return grub_errno;
+
+ while (*arg)
+ {
+ /* In case `-e' is used, parse backslashes. */
+ if (*arg == '\\' && state[1].set)
+ {
+ arg++;
+ if (*arg == '\0')
+ break;
+
+ switch (*arg)
+ {
+ case '\\':
+ *p++ = '\\';
+ break;
+
+ case 'a':
+ *p++ = '\a';
+ break;
+
+ case 'c':
+ newline = 0;
+ break;
+
+ case 'f':
+ *p++ = '\f';
+ break;
+
+ case 'n':
+ *p++ = '\n';
+ break;
+
+ case 'r':
+ *p++ = '\r';
+ break;
+
+ case 't':
+ *p++ = '\t';
+ break;
+
+ case 'v':
+ *p++ = '\v';
+ break;
+ }
+ arg++;
+ continue;
+ }
+
+ /* This was not an escaped character, or escaping is not
+ enabled. */
+ *p++ = *arg;
+ arg++;
+ }
+
+ *p = '\0';
+ grub_xputs (unescaped);
+ grub_free (unescaped);
+
+ /* If another argument follows, insert a space. */
+ if (i != argc - 1)
+ grub_printf (" " );
+ }
+
+ if (newline)
+ grub_printf ("\n");
+
+ grub_refresh ();
+
+ return 0;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(echo)
+{
+ cmd = grub_register_extcmd ("echo", grub_cmd_echo,
+ GRUB_COMMAND_ACCEPT_DASH
+ | GRUB_COMMAND_OPTIONS_AT_START,
+ N_("[-e|-n] STRING"), N_("Display a line of text."),
+ options);
+}
+
+GRUB_MOD_FINI(echo)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/efi/efifwsetup.c b/grub-core/commands/efi/efifwsetup.c
new file mode 100644
index 0000000..eaca032
--- /dev/null
+++ b/grub-core/commands/efi/efifwsetup.c
@@ -0,0 +1,90 @@
+/* fwsetup.c - Reboot into firmware setup menu. */
+/*
+ * 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/types.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ grub_efi_uint64_t *old_os_indications;
+ grub_efi_uint64_t os_indications = GRUB_EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
+ grub_err_t status;
+ grub_size_t oi_size;
+ grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
+
+ grub_efi_get_variable ("OsIndications", &global, &oi_size,
+ (void **) &old_os_indications);
+
+ if (old_os_indications != NULL && oi_size == sizeof (os_indications))
+ os_indications |= *old_os_indications;
+
+ status = grub_efi_set_variable ("OsIndications", &global, &os_indications,
+ sizeof (os_indications));
+ if (status != GRUB_ERR_NONE)
+ return status;
+
+ grub_reboot ();
+
+ return GRUB_ERR_BUG;
+}
+
+static grub_command_t cmd = NULL;
+
+static grub_efi_boolean_t
+efifwsetup_is_supported (void)
+{
+ grub_efi_uint64_t *os_indications_supported = NULL;
+ grub_size_t oi_size = 0;
+ grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
+
+ grub_efi_get_variable ("OsIndicationsSupported", &global, &oi_size,
+ (void **) &os_indications_supported);
+
+ if (!os_indications_supported)
+ return 0;
+
+ if (*os_indications_supported & GRUB_EFI_OS_INDICATIONS_BOOT_TO_FW_UI)
+ return 1;
+
+ return 0;
+}
+
+GRUB_MOD_INIT (efifwsetup)
+{
+ if (efifwsetup_is_supported ())
+ cmd = grub_register_command ("fwsetup", grub_cmd_fwsetup, NULL,
+ N_("Reboot into firmware setup menu."));
+
+}
+
+GRUB_MOD_FINI (efifwsetup)
+{
+ if (cmd)
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/efi/fixvideo.c b/grub-core/commands/efi/fixvideo.c
new file mode 100644
index 0000000..d9d54a2
--- /dev/null
+++ b/grub-core/commands/efi/fixvideo.c
@@ -0,0 +1,114 @@
+/* fixvideo.c - fix video problem in efi */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/misc.h>
+#include <grub/file.h>
+#include <grub/pci.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/mm.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static struct grub_video_patch
+{
+ const char *name;
+ grub_uint32_t pci_id;
+ grub_uint32_t mmio_bar;
+ grub_uint32_t mmio_reg;
+ grub_uint32_t mmio_old;
+} video_patches[] =
+ {
+ {"Intel 945GM", 0x27a28086, 0, 0x71184, 0x1000000}, /* DSPBBASE */
+ {"Intel 965GM", 0x2a028086, 0, 0x7119C, 0x1000000}, /* DSPBSURF */
+ {0, 0, 0, 0, 0}
+ };
+
+static int
+scan_card (grub_pci_device_t dev, grub_pci_id_t pciid,
+ void *data __attribute__ ((unused)))
+{
+ grub_pci_address_t addr;
+
+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
+ if (grub_pci_read_byte (addr + 3) == 0x3)
+ {
+ struct grub_video_patch *p = video_patches;
+
+ while (p->name)
+ {
+ if (p->pci_id == pciid)
+ {
+ grub_addr_t base;
+
+ grub_dprintf ("fixvideo", "Found graphic card: %s\n", p->name);
+ addr += 8 + p->mmio_bar * 4;
+ base = grub_pci_read (addr);
+ if ((! base) || (base & GRUB_PCI_ADDR_SPACE_IO) ||
+ (base & GRUB_PCI_ADDR_MEM_PREFETCH))
+ grub_dprintf ("fixvideo", "Invalid MMIO bar %d\n", p->mmio_bar);
+ else
+ {
+ base &= GRUB_PCI_ADDR_MEM_MASK;
+ base += p->mmio_reg;
+
+ if (*((volatile grub_uint32_t *) base) != p->mmio_old)
+ grub_dprintf ("fixvideo", "Old value doesn't match\n");
+ else
+ {
+ *((volatile grub_uint32_t *) base) = 0;
+ if (*((volatile grub_uint32_t *) base))
+ grub_dprintf ("fixvideo", "Setting MMIO fails\n");
+ }
+ }
+
+ return 1;
+ }
+ p++;
+ }
+
+ grub_dprintf ("fixvideo", "Unknown graphic card: %x\n", pciid);
+ }
+
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_fixvideo (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ grub_pci_iterate (scan_card, NULL);
+ return 0;
+}
+
+static grub_command_t cmd_fixvideo;
+
+GRUB_MOD_INIT(fixvideo)
+{
+ cmd_fixvideo = grub_register_command ("fix_video", grub_cmd_fixvideo,
+ 0, N_("Fix video problem."));
+
+}
+
+GRUB_MOD_FINI(fixvideo)
+{
+ grub_unregister_command (cmd_fixvideo);
+}
diff --git a/grub-core/commands/efi/loadbios.c b/grub-core/commands/efi/loadbios.c
new file mode 100644
index 0000000..5c7725f
--- /dev/null
+++ b/grub-core/commands/efi/loadbios.c
@@ -0,0 +1,222 @@
+/* loadbios.c - command to load a bios dump */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/misc.h>
+#include <grub/file.h>
+#include <grub/efi/efi.h>
+#include <grub/pci.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+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;
+
+#define EBDA_SEG_ADDR 0x40e
+#define LOW_MEM_ADDR 0x413
+#define FAKE_EBDA_SEG 0x9fc0
+
+#define BLANK_MEM 0xffffffff
+#define VBIOS_ADDR 0xc0000
+#define SBIOS_ADDR 0xf0000
+
+static int
+enable_rom_area (void)
+{
+ grub_pci_address_t addr;
+ grub_uint32_t *rom_ptr;
+ grub_pci_device_t dev = { .bus = 0, .device = 0, .function = 0};
+
+ rom_ptr = (grub_uint32_t *) VBIOS_ADDR;
+ if (*rom_ptr != BLANK_MEM)
+ {
+ grub_puts_ (N_("ROM image is present."));
+ return 0;
+ }
+
+ /* FIXME: should be macroified. */
+ addr = grub_pci_make_address (dev, 144);
+ grub_pci_write_byte (addr++, 0x30);
+ grub_pci_write_byte (addr++, 0x33);
+ grub_pci_write_byte (addr++, 0x33);
+ grub_pci_write_byte (addr++, 0x33);
+ grub_pci_write_byte (addr++, 0x33);
+ grub_pci_write_byte (addr++, 0x33);
+ grub_pci_write_byte (addr++, 0x33);
+ grub_pci_write_byte (addr, 0);
+
+ *rom_ptr = 0;
+ if (*rom_ptr != 0)
+ {
+ grub_puts_ (N_("Can\'t enable ROM area."));
+ return 0;
+ }
+
+ return 1;
+}
+
+static void
+lock_rom_area (void)
+{
+ grub_pci_address_t addr;
+ grub_pci_device_t dev = { .bus = 0, .device = 0, .function = 0};
+
+ /* FIXME: should be macroified. */
+ addr = grub_pci_make_address (dev, 144);
+ grub_pci_write_byte (addr++, 0x10);
+ grub_pci_write_byte (addr++, 0x11);
+ grub_pci_write_byte (addr++, 0x11);
+ grub_pci_write_byte (addr++, 0x11);
+ grub_pci_write_byte (addr, 0x11);
+}
+
+static void
+fake_bios_data (int use_rom)
+{
+ unsigned i;
+ void *acpi, *smbios;
+ grub_uint16_t *ebda_seg_ptr, *low_mem_ptr;
+
+ ebda_seg_ptr = (grub_uint16_t *) EBDA_SEG_ADDR;
+ low_mem_ptr = (grub_uint16_t *) LOW_MEM_ADDR;
+ if ((*ebda_seg_ptr) || (*low_mem_ptr))
+ return;
+
+ acpi = 0;
+ smbios = 0;
+ 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, &acpi2_guid, sizeof (grub_efi_guid_t)))
+ {
+ acpi = grub_efi_system_table->configuration_table[i].vendor_table;
+ grub_dprintf ("efi", "ACPI2: %p\n", acpi);
+ }
+ else if (! grub_memcmp (guid, &acpi_guid, sizeof (grub_efi_guid_t)))
+ {
+ void *t;
+
+ t = grub_efi_system_table->configuration_table[i].vendor_table;
+ if (! acpi)
+ acpi = t;
+ grub_dprintf ("efi", "ACPI: %p\n", t);
+ }
+ else if (! grub_memcmp (guid, &smbios_guid, sizeof (grub_efi_guid_t)))
+ {
+ smbios = grub_efi_system_table->configuration_table[i].vendor_table;
+ grub_dprintf ("efi", "SMBIOS: %p\n", smbios);
+ }
+ }
+
+ *ebda_seg_ptr = FAKE_EBDA_SEG;
+ *low_mem_ptr = (FAKE_EBDA_SEG >> 6);
+
+ *((grub_uint16_t *) (FAKE_EBDA_SEG << 4)) = 640 - *low_mem_ptr;
+
+ 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);
+}
+
+static grub_err_t
+grub_cmd_fakebios (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ if (enable_rom_area ())
+ {
+ fake_bios_data (1);
+ lock_rom_area ();
+ }
+ else
+ fake_bios_data (0);
+
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_loadbios (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ grub_file_t file;
+ int size;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ if (argc > 1)
+ {
+ file = grub_file_open (argv[1], GRUB_FILE_TYPE_VBE_DUMP);
+ if (! file)
+ return grub_errno;
+
+ if (file->size != 4)
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid int10 dump size");
+ else
+ grub_file_read (file, (void *) 0x40, 4);
+
+ grub_file_close (file);
+ if (grub_errno)
+ return grub_errno;
+ }
+
+ file = grub_file_open (argv[0], GRUB_FILE_TYPE_VBE_DUMP);
+ if (! file)
+ return grub_errno;
+
+ size = file->size;
+ if ((size < 0x10000) || (size > 0x40000))
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid bios dump size");
+ else if (enable_rom_area ())
+ {
+ grub_file_read (file, (void *) VBIOS_ADDR, size);
+ fake_bios_data (size <= 0x40000);
+ lock_rom_area ();
+ }
+
+ grub_file_close (file);
+ return grub_errno;
+}
+
+static grub_command_t cmd_fakebios, cmd_loadbios;
+
+GRUB_MOD_INIT(loadbios)
+{
+ cmd_fakebios = grub_register_command_lockdown ("fakebios", grub_cmd_fakebios,
+ 0, N_("Create BIOS-like structures for"
+ " backward compatibility with"
+ " existing OS."));
+
+ cmd_loadbios = grub_register_command_lockdown ("loadbios", grub_cmd_loadbios,
+ N_("BIOS_DUMP [INT10_DUMP]"),
+ N_("Load BIOS dump."));
+}
+
+GRUB_MOD_FINI(loadbios)
+{
+ grub_unregister_command (cmd_fakebios);
+ grub_unregister_command (cmd_loadbios);
+}
diff --git a/grub-core/commands/efi/lsefi.c b/grub-core/commands/efi/lsefi.c
new file mode 100644
index 0000000..d1ce99a
--- /dev/null
+++ b/grub-core/commands/efi/lsefi.c
@@ -0,0 +1,155 @@
+/*
+ * 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/types.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/efi/api.h>
+#include <grub/efi/edid.h>
+#include <grub/efi/pci.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/uga_draw.h>
+#include <grub/efi/graphics_output.h>
+#include <grub/efi/console_control.h>
+#include <grub/command.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+struct known_protocol
+{
+ grub_efi_guid_t guid;
+ const char *name;
+} known_protocols[] =
+ {
+ { GRUB_EFI_DISK_IO_GUID, "disk" },
+ { GRUB_EFI_BLOCK_IO_GUID, "block" },
+ { GRUB_EFI_SERIAL_IO_GUID, "serial" },
+ { GRUB_EFI_SIMPLE_NETWORK_GUID, "network" },
+ { GRUB_EFI_PXE_GUID, "pxe" },
+ { GRUB_EFI_DEVICE_PATH_GUID, "device path" },
+ { GRUB_EFI_PCI_IO_GUID, "PCI" },
+ { GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root" },
+ { GRUB_EFI_EDID_ACTIVE_GUID, "active EDID" },
+ { GRUB_EFI_EDID_DISCOVERED_GUID, "discovered EDID" },
+ { GRUB_EFI_EDID_OVERRIDE_GUID, "override EDID" },
+ { GRUB_EFI_GOP_GUID, "GOP" },
+ { GRUB_EFI_UGA_DRAW_GUID, "UGA draw" },
+ { GRUB_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID, "simple text output" },
+ { GRUB_EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID, "simple text input" },
+ { GRUB_EFI_SIMPLE_POINTER_PROTOCOL_GUID, "simple pointer" },
+ { GRUB_EFI_CONSOLE_CONTROL_GUID, "console control" },
+ { GRUB_EFI_ABSOLUTE_POINTER_PROTOCOL_GUID, "absolute pointer" },
+ { GRUB_EFI_DRIVER_BINDING_PROTOCOL_GUID, "EFI driver binding" },
+ { GRUB_EFI_LOAD_FILE_PROTOCOL_GUID, "load file" },
+ { GRUB_EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, "simple FS" },
+ { GRUB_EFI_TAPE_IO_PROTOCOL_GUID, "tape I/O" },
+ { GRUB_EFI_UNICODE_COLLATION_PROTOCOL_GUID, "unicode collation" },
+ { GRUB_EFI_SCSI_IO_PROTOCOL_GUID, "SCSI I/O" },
+ { GRUB_EFI_USB2_HC_PROTOCOL_GUID, "USB host" },
+ { GRUB_EFI_DEBUG_SUPPORT_PROTOCOL_GUID, "debug support" },
+ { GRUB_EFI_DEBUGPORT_PROTOCOL_GUID, "debug port" },
+ { GRUB_EFI_DECOMPRESS_PROTOCOL_GUID, "decompress" },
+ { GRUB_EFI_LOADED_IMAGE_PROTOCOL_GUID, "loaded image" },
+ { GRUB_EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID, "device path to text" },
+ { GRUB_EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID, "device path utilities" },
+ { GRUB_EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID, "device path from text" },
+ { GRUB_EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID, "HII config routing" },
+ { GRUB_EFI_HII_DATABASE_PROTOCOL_GUID, "HII database" },
+ { GRUB_EFI_HII_STRING_PROTOCOL_GUID, "HII string" },
+ { GRUB_EFI_HII_IMAGE_PROTOCOL_GUID, "HII image" },
+ { GRUB_EFI_HII_FONT_PROTOCOL_GUID, "HII font" },
+ { GRUB_EFI_COMPONENT_NAME2_PROTOCOL_GUID, "component name 2" },
+ { GRUB_EFI_HII_CONFIGURATION_ACCESS_PROTOCOL_GUID,
+ "HII configuration access" },
+ { GRUB_EFI_USB_IO_PROTOCOL_GUID, "USB I/O" },
+ };
+
+static grub_err_t
+grub_cmd_lsefi (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ grub_efi_handle_t *handles;
+ grub_efi_uintn_t num_handles;
+ unsigned i, j, k;
+
+ handles = grub_efi_locate_handle (GRUB_EFI_ALL_HANDLES,
+ NULL, NULL, &num_handles);
+
+ for (i = 0; i < num_handles; i++)
+ {
+ grub_efi_handle_t handle = handles[i];
+ grub_efi_status_t status;
+ grub_efi_uintn_t num_protocols;
+ grub_efi_packed_guid_t **protocols;
+ grub_efi_device_path_t *dp;
+
+ grub_printf ("Handle %p\n", handle);
+
+ dp = grub_efi_get_device_path (handle);
+ if (dp)
+ {
+ grub_printf (" ");
+ grub_efi_print_device_path (dp);
+ }
+
+ status = efi_call_3 (grub_efi_system_table->boot_services->protocols_per_handle,
+ handle, &protocols, &num_protocols);
+ if (status != GRUB_EFI_SUCCESS) {
+ grub_printf ("Unable to retrieve protocols\n");
+ continue;
+ }
+ for (j = 0; j < num_protocols; j++)
+ {
+ for (k = 0; k < ARRAY_SIZE (known_protocols); k++)
+ if (grub_memcmp (protocols[j], &known_protocols[k].guid,
+ sizeof (known_protocols[k].guid)) == 0)
+ break;
+ if (k < ARRAY_SIZE (known_protocols))
+ grub_printf (" %s\n", known_protocols[k].name);
+ else
+ grub_printf (" %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
+ protocols[j]->data1,
+ protocols[j]->data2,
+ protocols[j]->data3,
+ (unsigned) protocols[j]->data4[0],
+ (unsigned) protocols[j]->data4[1],
+ (unsigned) protocols[j]->data4[2],
+ (unsigned) protocols[j]->data4[3],
+ (unsigned) protocols[j]->data4[4],
+ (unsigned) protocols[j]->data4[5],
+ (unsigned) protocols[j]->data4[6],
+ (unsigned) protocols[j]->data4[7]);
+ }
+
+ }
+
+ return 0;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(lsefi)
+{
+ cmd = grub_register_command ("lsefi", grub_cmd_lsefi,
+ NULL, "Display EFI handles.");
+}
+
+GRUB_MOD_FINI(lsefi)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/efi/lsefimmap.c b/grub-core/commands/efi/lsefimmap.c
new file mode 100644
index 0000000..c85ff7f
--- /dev/null
+++ b/grub-core/commands/efi/lsefimmap.c
@@ -0,0 +1,160 @@
+/* lsefimemmap.c - Display memory map. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/command.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define ADD_MEMORY_DESCRIPTOR(desc, size) \
+ ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
+
+static grub_err_t
+grub_cmd_lsefimmap (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ grub_efi_uintn_t map_size;
+ grub_efi_memory_descriptor_t *memory_map;
+ grub_efi_memory_descriptor_t *memory_map_end;
+ grub_efi_memory_descriptor_t *desc;
+ grub_efi_uintn_t desc_size;
+
+ map_size = 0;
+ if (grub_efi_get_memory_map (&map_size, NULL, NULL, &desc_size, 0) < 0)
+ return 0;
+
+ memory_map = grub_malloc (map_size);
+ if (memory_map == NULL)
+ return grub_errno;
+ if (grub_efi_get_memory_map (&map_size, memory_map, NULL, &desc_size, 0) <= 0)
+ goto fail;
+
+ grub_printf
+ ("Type Physical start - end #Pages "
+ " Size Attributes\n");
+ memory_map_end = ADD_MEMORY_DESCRIPTOR (memory_map, map_size);
+ for (desc = memory_map;
+ desc < memory_map_end;
+ desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size))
+ {
+ grub_efi_uint64_t size;
+ grub_efi_uint64_t attr;
+ static const char types_str[][9] =
+ {
+ "reserved",
+ "ldr-code",
+ "ldr-data",
+ "BS-code ",
+ "BS-data ",
+ "RT-code ",
+ "RT-data ",
+ "conv-mem",
+ "unusable",
+ "ACPI-rec",
+ "ACPI-nvs",
+ "MMIO ",
+ "IO-ports",
+ "PAL-code",
+ "persist ",
+ };
+ if (desc->type < ARRAY_SIZE (types_str))
+ grub_printf ("%s ", types_str[desc->type]);
+ else
+ grub_printf ("Unk %02x ", desc->type);
+
+ grub_printf (" %016" PRIxGRUB_UINT64_T "-%016" PRIxGRUB_UINT64_T
+ " %08" PRIxGRUB_UINT64_T,
+ desc->physical_start,
+ desc->physical_start + (desc->num_pages << 12) - 1,
+ desc->num_pages);
+
+ size = desc->num_pages << 12; /* 4 KiB page size */
+ /*
+ * Since size is a multiple of 4 KiB, no need to handle units
+ * of just Bytes (which would use a mask of 0x3ff).
+ *
+ * 14 characters would support the largest possible number of 4 KiB
+ * pages that are not a multiple of larger units (e.g., MiB):
+ * 17592186044415 (0xffffff_fffff000), but that uses a lot of
+ * whitespace for a rare case. 6 characters usually suffices;
+ * columns will be off if not, but this is preferable to rounding.
+ */
+ if (size & 0xfffff)
+ grub_printf (" %6" PRIuGRUB_UINT64_T "KiB", size >> 10);
+ else if (size & 0x3fffffff)
+ grub_printf (" %6" PRIuGRUB_UINT64_T "MiB", size >> 20);
+ else if (size & 0xffffffffff)
+ grub_printf (" %6" PRIuGRUB_UINT64_T "GiB", size >> 30);
+ else if (size & 0x3ffffffffffff)
+ grub_printf (" %6" PRIuGRUB_UINT64_T "TiB", size >> 40);
+ else if (size & 0xfffffffffffffff)
+ grub_printf (" %6" PRIuGRUB_UINT64_T "PiB", size >> 50);
+ else
+ grub_printf (" %6" PRIuGRUB_UINT64_T "EiB", size >> 60);
+
+ attr = desc->attribute;
+ if (attr & GRUB_EFI_MEMORY_RUNTIME)
+ grub_printf (" RT");
+ if (attr & GRUB_EFI_MEMORY_UC)
+ grub_printf (" UC");
+ if (attr & GRUB_EFI_MEMORY_WC)
+ grub_printf (" WC");
+ if (attr & GRUB_EFI_MEMORY_WT)
+ grub_printf (" WT");
+ if (attr & GRUB_EFI_MEMORY_WB)
+ grub_printf (" WB");
+ if (attr & GRUB_EFI_MEMORY_UCE)
+ grub_printf (" UCE");
+ if (attr & GRUB_EFI_MEMORY_WP)
+ grub_printf (" WP");
+ if (attr & GRUB_EFI_MEMORY_RP)
+ grub_printf (" RP");
+ if (attr & GRUB_EFI_MEMORY_XP)
+ grub_printf (" XP");
+ if (attr & GRUB_EFI_MEMORY_NV)
+ grub_printf (" NV");
+ if (attr & GRUB_EFI_MEMORY_MORE_RELIABLE)
+ grub_printf (" MR");
+ if (attr & GRUB_EFI_MEMORY_RO)
+ grub_printf (" RO");
+
+ grub_printf ("\n");
+ }
+
+ fail:
+ grub_free (memory_map);
+ return 0;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(lsefimmap)
+{
+ cmd = grub_register_command ("lsefimmap", grub_cmd_lsefimmap,
+ "", "Display EFI memory map.");
+}
+
+GRUB_MOD_FINI(lsefimmap)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/efi/lsefisystab.c b/grub-core/commands/efi/lsefisystab.c
new file mode 100644
index 0000000..456198e
--- /dev/null
+++ b/grub-core/commands/efi/lsefisystab.c
@@ -0,0 +1,125 @@
+/* lsefisystab.c - Display EFI systab. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/normal.h>
+#include <grub/charset.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+struct guid_mapping
+{
+ grub_efi_guid_t guid;
+ const char *name;
+};
+
+static const struct guid_mapping guid_mappings[] =
+ {
+ { GRUB_EFI_ACPI_20_TABLE_GUID, "ACPI-2.0"},
+ { GRUB_EFI_ACPI_TABLE_GUID, "ACPI-1.0"},
+ { GRUB_EFI_CRC32_GUIDED_SECTION_EXTRACTION_GUID,
+ "CRC32 GUIDED SECTION EXTRACTION"},
+ { GRUB_EFI_DEBUG_IMAGE_INFO_TABLE_GUID, "DEBUG IMAGE INFO"},
+ { GRUB_EFI_DEVICE_TREE_GUID, "DEVICE TREE"},
+ { GRUB_EFI_DXE_SERVICES_TABLE_GUID, "DXE SERVICES"},
+ { GRUB_EFI_HCDP_TABLE_GUID, "HCDP"},
+ { GRUB_EFI_HOB_LIST_GUID, "HOB LIST"},
+ { GRUB_EFI_LZMA_CUSTOM_DECOMPRESS_GUID, "LZMA CUSTOM DECOMPRESS"},
+ { GRUB_EFI_MEMORY_TYPE_INFORMATION_GUID, "MEMORY TYPE INFO"},
+ { GRUB_EFI_MPS_TABLE_GUID, "MPS"},
+ { GRUB_EFI_RT_PROPERTIES_TABLE_GUID, "RT PROPERTIES"},
+ { 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"},
+ };
+
+static grub_err_t
+grub_cmd_lsefisystab (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ const grub_efi_system_table_t *st = grub_efi_system_table;
+ grub_efi_configuration_table_t *t;
+ unsigned int i;
+
+ grub_printf ("Address: %p\n", st);
+ grub_printf ("Signature: %016" PRIxGRUB_UINT64_T " revision: %08x\n",
+ st->hdr.signature, st->hdr.revision);
+ {
+ char *vendor;
+ grub_uint16_t *vendor_utf16;
+ grub_printf ("Vendor: ");
+
+ for (vendor_utf16 = st->firmware_vendor; *vendor_utf16; vendor_utf16++);
+ /* Allocate extra 3 bytes to simplify math. */
+ vendor = grub_calloc (4, vendor_utf16 - st->firmware_vendor + 1);
+ if (!vendor)
+ return grub_errno;
+ *grub_utf16_to_utf8 ((grub_uint8_t *) vendor, st->firmware_vendor,
+ vendor_utf16 - st->firmware_vendor) = 0;
+ grub_printf ("%s", vendor);
+ grub_free (vendor);
+ }
+
+ grub_printf (", Version=%x\n", st->firmware_revision);
+
+ grub_printf ("%lld tables:\n", (long long) st->num_table_entries);
+ t = st->configuration_table;
+ for (i = 0; i < st->num_table_entries; i++)
+ {
+ unsigned int j;
+
+ grub_printf ("%p ", t->vendor_table);
+
+ grub_printf ("%08x-%04x-%04x-",
+ t->vendor_guid.data1, t->vendor_guid.data2,
+ t->vendor_guid.data3);
+ for (j = 0; j < 8; j++)
+ grub_printf ("%02x", t->vendor_guid.data4[j]);
+
+ for (j = 0; j < ARRAY_SIZE (guid_mappings); j++)
+ if (grub_memcmp (&guid_mappings[j].guid, &t->vendor_guid,
+ sizeof (grub_efi_guid_t)) == 0)
+ grub_printf (" %s", guid_mappings[j].name);
+
+ grub_printf ("\n");
+ t++;
+ }
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(lsefisystab)
+{
+ cmd = grub_register_command ("lsefisystab", grub_cmd_lsefisystab,
+ "", "Display EFI system tables.");
+}
+
+GRUB_MOD_FINI(lsefisystab)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/efi/lssal.c b/grub-core/commands/efi/lssal.c
new file mode 100644
index 0000000..5084ddd
--- /dev/null
+++ b/grub-core/commands/efi/lssal.c
@@ -0,0 +1,169 @@
+/* lssal.c - Display EFI SAL systab. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/normal.h>
+#include <grub/charset.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/dl.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static void
+disp_sal (void *table)
+{
+ struct grub_efi_sal_system_table *t = table;
+ void *desc;
+ grub_uint32_t len, l, i;
+
+ grub_printf ("SAL rev: %02x, signature: %x, len:%x\n",
+ t->sal_rev, t->signature, t->total_table_len);
+ grub_printf ("nbr entry: %d, chksum: %02x, SAL version A: %02x B: %02x\n",
+ t->entry_count, t->checksum,
+ t->sal_a_version, t->sal_b_version);
+ grub_printf ("OEM-ID: %-32s\n", t->oem_id);
+ grub_printf ("Product-ID: %-32s\n", t->product_id);
+
+ desc = t->entries;
+ len = t->total_table_len - sizeof (struct grub_efi_sal_system_table);
+ if (t->total_table_len <= sizeof (struct grub_efi_sal_system_table))
+ return;
+ for (i = 0; i < t->entry_count; i++)
+ {
+ switch (*(grub_uint8_t *) desc)
+ {
+ case GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_ENTRYPOINT_DESCRIPTOR:
+ {
+ struct grub_efi_sal_system_table_entrypoint_descriptor *c = desc;
+ l = sizeof (*c);
+ grub_printf (" Entry point: PAL=%016" PRIxGRUB_UINT64_T
+ " SAL=%016" PRIxGRUB_UINT64_T " GP=%016"
+ PRIxGRUB_UINT64_T "\n",
+ c->pal_proc_addr, c->sal_proc_addr,
+ c->global_data_ptr);
+ }
+ break;
+ case GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_MEMORY_DESCRIPTOR:
+ {
+ struct grub_efi_sal_system_table_memory_descriptor *c = desc;
+ l = sizeof (*c);
+ grub_printf (" Memory descriptor entry addr=%016" PRIxGRUB_UINT64_T
+ " len=%" PRIuGRUB_UINT64_T "KB\n",
+ c->addr, c->len * 4);
+ grub_printf (" sal_used=%d attr=%x AR=%x attr_mask=%x "
+ "type=%x usage=%x\n",
+ c->sal_used, c->attr, c->ar, c->attr_mask, c->mem_type,
+ c->usage);
+ }
+ break;
+ case GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_PLATFORM_FEATURES:
+ {
+ struct grub_efi_sal_system_table_platform_features *c = desc;
+ l = sizeof (*c);
+ grub_printf (" Platform features: %02x", c->flags);
+ if (c->flags & GRUB_EFI_SAL_SYSTEM_TABLE_PLATFORM_FEATURE_BUSLOCK)
+ grub_printf (" BusLock");
+ if (c->flags & GRUB_EFI_SAL_SYSTEM_TABLE_PLATFORM_FEATURE_IRQREDIRECT)
+ grub_printf (" IrqRedirect");
+ if (c->flags & GRUB_EFI_SAL_SYSTEM_TABLE_PLATFORM_FEATURE_IPIREDIRECT)
+
+ grub_printf (" IPIRedirect");
+ if (c->flags & GRUB_EFI_SAL_SYSTEM_TABLE_PLATFORM_FEATURE_ITCDRIFT)
+
+ grub_printf (" ITCDrift");
+ grub_printf ("\n");
+ }
+ break;
+ case GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_TRANSLATION_REGISTER_DESCRIPTOR:
+ {
+ struct grub_efi_sal_system_table_translation_register_descriptor *c
+ = desc;
+ l = sizeof (*c);
+ grub_printf (" TR type=%d num=%d va=%016" PRIxGRUB_UINT64_T
+ " pte=%016" PRIxGRUB_UINT64_T "\n",
+ c->register_type, c->register_number,
+ c->addr, c->page_size);
+ }
+ break;
+ case GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_PURGE_TRANSLATION_COHERENCE:
+ {
+ struct grub_efi_sal_system_table_purge_translation_coherence *c
+ = desc;
+ l = sizeof (*c);
+ grub_printf (" PTC coherence nbr=%d addr=%016" PRIxGRUB_UINT64_T "\n",
+ c->ndomains, c->coherence);
+ }
+ break;
+ case GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_AP_WAKEUP:
+ {
+ struct grub_efi_sal_system_table_ap_wakeup *c = desc;
+ l = sizeof (*c);
+ grub_printf (" AP wake-up: mec=%d vect=%" PRIxGRUB_UINT64_T "\n",
+ c->mechanism, c->vector);
+ }
+ break;
+ default:
+ grub_printf (" unknown entry 0x%x\n", *(grub_uint8_t *)desc);
+ return;
+ }
+ desc = (grub_uint8_t *)desc + l;
+ if (len <= l)
+ return;
+ len -= l;
+ }
+}
+
+static grub_err_t
+grub_cmd_lssal (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ const grub_efi_system_table_t *st = grub_efi_system_table;
+ grub_efi_configuration_table_t *t = st->configuration_table;
+ unsigned int i;
+ grub_efi_packed_guid_t guid = GRUB_EFI_SAL_TABLE_GUID;
+
+ for (i = 0; i < st->num_table_entries; i++)
+ {
+ if (grub_memcmp (&guid, &t->vendor_guid,
+ sizeof (grub_efi_packed_guid_t)) == 0)
+ {
+ disp_sal (t->vendor_table);
+ return GRUB_ERR_NONE;
+ }
+ t++;
+ }
+ grub_printf ("SAL not found\n");
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(lssal)
+{
+ cmd = grub_register_command ("lssal", grub_cmd_lssal, "",
+ "Display SAL system table.");
+}
+
+GRUB_MOD_FINI(lssal)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/efi/smbios.c b/grub-core/commands/efi/smbios.c
new file mode 100644
index 0000000..75202d5
--- /dev/null
+++ b/grub-core/commands/efi/smbios.c
@@ -0,0 +1,61 @@
+/* smbios.c - get smbios tables. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2019 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;
+}
diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c
new file mode 100644
index 0000000..a97d853
--- /dev/null
+++ b/grub-core/commands/efi/tpm.c
@@ -0,0 +1,241 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2018 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/>.
+ *
+ * EFI TPM support code.
+ */
+
+#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>
+
+typedef TCG_PCR_EVENT grub_tpm_event_t;
+
+static grub_efi_guid_t tpm_guid = EFI_TPM_GUID;
+static grub_efi_guid_t tpm2_guid = EFI_TPM2_GUID;
+
+static grub_efi_handle_t *grub_tpm_handle;
+static grub_uint8_t grub_tpm_version;
+
+static grub_int8_t tpm1_present = -1;
+static grub_int8_t tpm2_present = -1;
+
+static grub_efi_boolean_t
+grub_tpm1_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;
+
+ if (tpm1_present != -1)
+ return (grub_efi_boolean_t) tpm1_present;
+
+ 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)
+ tpm1_present = 0;
+ else
+ tpm1_present = 1;
+
+ grub_dprintf ("tpm", "tpm1%s present\n", tpm1_present ? "" : " NOT");
+
+ return (grub_efi_boolean_t) tpm1_present;
+}
+
+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);
+
+ if (tpm2_present != -1)
+ return (grub_efi_boolean_t) tpm2_present;
+
+ status = efi_call_2 (tpm->get_capability, tpm, &caps);
+
+ if (status != GRUB_EFI_SUCCESS || !caps.TPMPresentFlag)
+ tpm2_present = 0;
+ else
+ tpm2_present = 1;
+
+ grub_dprintf ("tpm", "tpm2%s present\n", tpm2_present ? "" : " NOT");
+
+ return (grub_efi_boolean_t) tpm2_present;
+}
+
+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;
+
+ if (grub_tpm_handle != NULL)
+ {
+ *tpm_handle = grub_tpm_handle;
+ *protocol_version = grub_tpm_version;
+ return 1;
+ }
+
+ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &tpm_guid, NULL,
+ &num_handles);
+ if (handles && num_handles > 0)
+ {
+ grub_tpm_handle = handles[0];
+ *tpm_handle = handles[0];
+ grub_tpm_version = 1;
+ *protocol_version = 1;
+ grub_dprintf ("tpm", "TPM handle Found, version: 1\n");
+ return 1;
+ }
+
+ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &tpm2_guid, NULL,
+ &num_handles);
+ if (handles && num_handles > 0)
+ {
+ grub_tpm_handle = handles[0];
+ *tpm_handle = handles[0];
+ grub_tpm_version = 2;
+ *protocol_version = 2;
+ grub_dprintf ("tpm", "TPM handle Found, version: 2\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static grub_err_t
+grub_efi_log_event_status (grub_efi_status_t status)
+{
+ 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_tpm1_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf,
+ grub_size_t size, grub_uint8_t pcr,
+ const char *description)
+{
+ grub_tpm_event_t *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_tpm1_present (tpm))
+ return 0;
+
+ event = grub_zalloc (sizeof (*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_addr_t) buf, (grub_uint64_t) size,
+ algorithm, event, &eventnum, &lastevent);
+ grub_free (event);
+
+ return grub_efi_log_event_status (status);
+}
+
+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_addr_t) buf,
+ (grub_uint64_t) size, event);
+ grub_free (event);
+
+ return grub_efi_log_event_status (status);
+}
+
+grub_err_t
+grub_tpm_measure (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;
+
+ grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n",
+ pcr, size, description);
+
+ 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);
+}
diff --git a/grub-core/commands/eval.c b/grub-core/commands/eval.c
new file mode 100644
index 0000000..f826a4f
--- /dev/null
+++ b/grub-core/commands/eval.c
@@ -0,0 +1,71 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/misc.h>
+#include <grub/script_sh.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/term.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+grub_cmd_eval (grub_command_t cmd __attribute__((__unused__)),
+ int argc, char *argv[])
+{
+ int i;
+ grub_size_t size = argc; /* +1 for final zero */
+ char *str, *p;
+ grub_err_t ret;
+
+ if (argc == 0)
+ return GRUB_ERR_NONE;
+
+ for (i = 0; i < argc; i++)
+ size += grub_strlen (argv[i]);
+
+ str = p = grub_malloc (size);
+ if (!str)
+ return grub_errno;
+
+ for (i = 0; i < argc; i++)
+ {
+ p = grub_stpcpy (p, argv[i]);
+ *p++ = ' ';
+ }
+ *--p = '\0';
+
+ ret = grub_script_execute_sourcecode (str);
+ grub_free (str);
+ return ret;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(eval)
+{
+ cmd = grub_register_command ("eval", grub_cmd_eval, N_("STRING ..."),
+ N_("Evaluate arguments as GRUB commands"));
+}
+
+GRUB_MOD_FINI(eval)
+{
+ grub_unregister_command (cmd);
+}
+
diff --git a/grub-core/commands/extcmd.c b/grub-core/commands/extcmd.c
new file mode 100644
index 0000000..90a5ca2
--- /dev/null
+++ b/grub-core/commands/extcmd.c
@@ -0,0 +1,141 @@
+/* extcmd.c - support extended command */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/mm.h>
+#include <grub/list.h>
+#include <grub/lockdown.h>
+#include <grub/misc.h>
+#include <grub/extcmd.h>
+#include <grub/script_sh.h>
+#include <grub/dl.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+grub_err_t
+grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args,
+ struct grub_script *script)
+{
+ int new_argc;
+ char **new_args;
+ struct grub_arg_list *state;
+ struct grub_extcmd_context context;
+ grub_err_t ret;
+ grub_extcmd_t ext = cmd->data;
+
+ context.state = 0;
+ context.extcmd = ext;
+ context.script = script;
+
+ if (! ext->options)
+ {
+ ret = (ext->func) (&context, argc, args);
+ return ret;
+ }
+
+ state = grub_arg_list_alloc (ext, argc, args);
+ if (grub_arg_parse (ext, argc, args, state, &new_args, &new_argc))
+ {
+ context.state = state;
+ ret = (ext->func) (&context, new_argc, new_args);
+ grub_free (new_args);
+ grub_free (state);
+ return ret;
+ }
+
+ grub_free (state);
+ return grub_errno;
+}
+
+static grub_err_t
+grub_extcmd_dispatch (struct grub_command *cmd, int argc, char **args)
+{
+ return grub_extcmd_dispatcher (cmd, argc, args, 0);
+}
+
+grub_extcmd_t
+grub_register_extcmd_prio (const char *name, grub_extcmd_func_t func,
+ grub_command_flags_t flags, const char *summary,
+ const char *description,
+ const struct grub_arg_option *parser,
+ int prio)
+{
+ grub_extcmd_t ext;
+ grub_command_t cmd;
+
+ ext = (grub_extcmd_t) grub_malloc (sizeof (*ext));
+ if (! ext)
+ return 0;
+
+ cmd = grub_register_command_prio (name, grub_extcmd_dispatch,
+ summary, description, prio);
+ if (! cmd)
+ {
+ grub_free (ext);
+ return 0;
+ }
+
+ cmd->flags = (flags | GRUB_COMMAND_FLAG_EXTCMD);
+ cmd->data = ext;
+
+ ext->cmd = cmd;
+ ext->func = func;
+ ext->options = parser;
+ ext->data = 0;
+
+ return ext;
+}
+
+grub_extcmd_t
+grub_register_extcmd (const char *name, grub_extcmd_func_t func,
+ grub_command_flags_t flags, const char *summary,
+ const char *description,
+ const struct grub_arg_option *parser)
+{
+ return grub_register_extcmd_prio (name, func, flags,
+ summary, description, parser, 1);
+}
+
+static grub_err_t
+grub_extcmd_lockdown (grub_extcmd_context_t ctxt __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **argv __attribute__ ((unused)))
+{
+ return grub_error (GRUB_ERR_ACCESS_DENIED,
+ N_("%s: the command is not allowed when lockdown is enforced"),
+ ctxt->extcmd->cmd->name);
+}
+
+grub_extcmd_t
+grub_register_extcmd_lockdown (const char *name, grub_extcmd_func_t func,
+ grub_command_flags_t flags, const char *summary,
+ const char *description,
+ const struct grub_arg_option *parser)
+{
+ if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED)
+ func = grub_extcmd_lockdown;
+
+ return grub_register_extcmd (name, func, flags, summary, description, parser);
+}
+
+void
+grub_unregister_extcmd (grub_extcmd_t ext)
+{
+ grub_unregister_command (ext->cmd);
+ grub_free (ext);
+}
diff --git a/grub-core/commands/file.c b/grub-core/commands/file.c
new file mode 100644
index 0000000..9de0006
--- /dev/null
+++ b/grub-core/commands/file.c
@@ -0,0 +1,694 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/misc.h>
+#include <grub/mm.h>
+#include <grub/env.h>
+#include <grub/command.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+#include <grub/file.h>
+#include <grub/elf.h>
+#include <grub/xen_file.h>
+#include <grub/efi/pe32.h>
+#include <grub/arm/linux.h>
+#include <grub/arm64/linux.h>
+#include <grub/i386/linux.h>
+#include <grub/xnu.h>
+#include <grub/machoload.h>
+#include <grub/fileid.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] = {
+ {"is-i386-xen-pae-domu", 0, 0,
+ N_("Check if FILE can be booted as i386 PAE Xen unprivileged guest kernel"),
+ 0, 0},
+ {"is-x86_64-xen-domu", 0, 0,
+ N_("Check if FILE can be booted as x86_64 Xen unprivileged guest kernel"), 0, 0},
+ {"is-x86-xen-dom0", 0, 0,
+ N_("Check if FILE can be used as Xen x86 privileged guest kernel"), 0, 0},
+ {"is-x86-multiboot", 0, 0,
+ N_("Check if FILE can be used as x86 multiboot kernel"), 0, 0},
+ {"is-x86-multiboot2", 0, 0,
+ N_("Check if FILE can be used as x86 multiboot2 kernel"), 0, 0},
+ {"is-arm-linux", 0, 0,
+ N_("Check if FILE is ARM Linux"), 0, 0},
+ {"is-arm64-linux", 0, 0,
+ N_("Check if FILE is ARM64 Linux"), 0, 0},
+ {"is-ia64-linux", 0, 0,
+ N_("Check if FILE is IA64 Linux"), 0, 0},
+ {"is-mips-linux", 0, 0,
+ N_("Check if FILE is MIPS Linux"), 0, 0},
+ {"is-mipsel-linux", 0, 0,
+ N_("Check if FILE is MIPSEL Linux"), 0, 0},
+ {"is-sparc64-linux", 0, 0,
+ N_("Check if FILE is SPARC64 Linux"), 0, 0},
+ {"is-powerpc-linux", 0, 0,
+ N_("Check if FILE is POWERPC Linux"), 0, 0},
+ {"is-x86-linux", 0, 0,
+ N_("Check if FILE is x86 Linux"), 0, 0},
+ {"is-x86-linux32", 0, 0,
+ N_("Check if FILE is x86 Linux supporting 32-bit protocol"), 0, 0},
+ {"is-x86-kfreebsd", 0, 0,
+ N_("Check if FILE is x86 kFreeBSD"), 0, 0},
+ {"is-i386-kfreebsd", 0, 0,
+ N_("Check if FILE is i386 kFreeBSD"), 0, 0},
+ {"is-x86_64-kfreebsd", 0, 0,
+ N_("Check if FILE is x86_64 kFreeBSD"), 0, 0},
+
+ {"is-x86-knetbsd", 0, 0,
+ N_("Check if FILE is x86 kNetBSD"), 0, 0},
+ {"is-i386-knetbsd", 0, 0,
+ N_("Check if FILE is i386 kNetBSD"), 0, 0},
+ {"is-x86_64-knetbsd", 0, 0,
+ N_("Check if FILE is x86_64 kNetBSD"), 0, 0},
+
+ {"is-i386-efi", 0, 0,
+ N_("Check if FILE is i386 EFI file"), 0, 0},
+ {"is-x86_64-efi", 0, 0,
+ N_("Check if FILE is x86_64 EFI file"), 0, 0},
+ {"is-ia64-efi", 0, 0,
+ N_("Check if FILE is IA64 EFI file"), 0, 0},
+ {"is-arm64-efi", 0, 0,
+ N_("Check if FILE is ARM64 EFI file"), 0, 0},
+ {"is-arm-efi", 0, 0,
+ N_("Check if FILE is ARM EFI file"), 0, 0},
+ {"is-riscv32-efi", 0, 0,
+ N_("Check if FILE is RISC-V 32bit EFI file"), 0, 0},
+ {"is-riscv64-efi", 0, 0,
+ N_("Check if FILE is RISC-V 64bit EFI file"), 0, 0},
+ {"is-hibernated-hiberfil", 0, 0,
+ N_("Check if FILE is hiberfil.sys in hibernated state"), 0, 0},
+ {"is-x86_64-xnu", 0, 0,
+ N_("Check if FILE is x86_64 XNU (Mac OS X kernel)"), 0, 0},
+ {"is-i386-xnu", 0, 0,
+ N_("Check if FILE is i386 XNU (Mac OS X kernel)"), 0, 0},
+ {"is-xnu-hibr", 0, 0,
+ N_("Check if FILE is XNU (Mac OS X kernel) hibernated image"), 0, 0},
+ {"is-x86-bios-bootsector", 0, 0,
+ N_("Check if FILE is BIOS bootsector"), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+};
+
+enum
+{
+ IS_PAE_DOMU,
+ IS_64_DOMU,
+ IS_DOM0,
+ IS_MULTIBOOT,
+ IS_MULTIBOOT2,
+ IS_ARM_LINUX,
+ IS_ARM64_LINUX,
+ IS_IA64_LINUX,
+ IS_MIPS_LINUX,
+ IS_MIPSEL_LINUX,
+ IS_SPARC64_LINUX,
+ IS_POWERPC_LINUX,
+ IS_X86_LINUX,
+ IS_X86_LINUX32,
+ IS_X86_KFREEBSD,
+ IS_X86_KFREEBSD32,
+ IS_X86_KFREEBSD64,
+ IS_X86_KNETBSD,
+ IS_X86_KNETBSD32,
+ IS_X86_KNETBSD64,
+ IS_32_EFI,
+ IS_64_EFI,
+ IS_IA_EFI,
+ IS_ARM64_EFI,
+ IS_ARM_EFI,
+ IS_RISCV32_EFI,
+ IS_RISCV64_EFI,
+ IS_HIBERNATED,
+ IS_XNU64,
+ IS_XNU32,
+ IS_XNU_HIBR,
+ IS_BIOS_BOOTSECTOR,
+ OPT_TYPE_MIN = IS_PAE_DOMU,
+ OPT_TYPE_MAX = IS_BIOS_BOOTSECTOR
+};
+
+
+static grub_err_t
+grub_cmd_file (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ grub_file_t file = 0;
+ grub_elf_t elf = 0;
+ grub_err_t err;
+ int type = -1, i;
+ int ret = 0;
+ grub_macho_t macho = 0;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ for (i = OPT_TYPE_MIN; i <= OPT_TYPE_MAX; i++)
+ if (ctxt->state[i].set)
+ {
+ if (type == -1)
+ {
+ type = i;
+ continue;
+ }
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple types specified");
+ }
+ if (type == -1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no type specified");
+
+ file = grub_file_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL);
+ if (!file)
+ return grub_errno;
+ switch (type)
+ {
+ case IS_BIOS_BOOTSECTOR:
+ {
+ grub_uint16_t sig;
+ if (grub_file_size (file) != 512)
+ break;
+ if (grub_file_seek (file, 510) == (grub_size_t) -1)
+ break;
+ if (grub_file_read (file, &sig, 2) != 2)
+ break;
+ if (sig != grub_cpu_to_le16_compile_time (0xaa55))
+ break;
+ ret = 1;
+ break;
+ }
+ case IS_IA64_LINUX:
+ {
+ Elf64_Ehdr ehdr;
+
+ if (grub_file_read (file, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
+ break;
+
+ if (ehdr.e_ident[EI_MAG0] != ELFMAG0
+ || ehdr.e_ident[EI_MAG1] != ELFMAG1
+ || ehdr.e_ident[EI_MAG2] != ELFMAG2
+ || ehdr.e_ident[EI_MAG3] != ELFMAG3
+ || ehdr.e_ident[EI_VERSION] != EV_CURRENT
+ || ehdr.e_version != EV_CURRENT)
+ break;
+
+ if (ehdr.e_ident[EI_CLASS] != ELFCLASS64
+ || ehdr.e_ident[EI_DATA] != ELFDATA2LSB
+ || ehdr.e_machine != grub_cpu_to_le16_compile_time (EM_IA_64))
+ break;
+
+ ret = 1;
+
+ break;
+ }
+
+ case IS_SPARC64_LINUX:
+ {
+ Elf64_Ehdr ehdr;
+
+ if (grub_file_read (file, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
+ break;
+
+ if (ehdr.e_ident[EI_MAG0] != ELFMAG0
+ || ehdr.e_ident[EI_MAG1] != ELFMAG1
+ || ehdr.e_ident[EI_MAG2] != ELFMAG2
+ || ehdr.e_ident[EI_MAG3] != ELFMAG3
+ || ehdr.e_ident[EI_VERSION] != EV_CURRENT
+ || ehdr.e_version != EV_CURRENT)
+ break;
+
+ if (ehdr.e_ident[EI_CLASS] != ELFCLASS64
+ || ehdr.e_ident[EI_DATA] != ELFDATA2MSB)
+ break;
+
+ if (ehdr.e_machine != grub_cpu_to_le16_compile_time (EM_SPARCV9)
+ || ehdr.e_type != grub_cpu_to_be16_compile_time (ET_EXEC))
+ break;
+
+ ret = 1;
+
+ break;
+ }
+
+ case IS_POWERPC_LINUX:
+ {
+ Elf32_Ehdr ehdr;
+
+ if (grub_file_read (file, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
+ break;
+
+ if (ehdr.e_ident[EI_MAG0] != ELFMAG0
+ || ehdr.e_ident[EI_MAG1] != ELFMAG1
+ || ehdr.e_ident[EI_MAG2] != ELFMAG2
+ || ehdr.e_ident[EI_MAG3] != ELFMAG3
+ || ehdr.e_ident[EI_VERSION] != EV_CURRENT
+ || ehdr.e_version != EV_CURRENT)
+ break;
+
+ if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB
+ || (ehdr.e_machine != grub_cpu_to_le16_compile_time (EM_PPC)
+ && ehdr.e_machine !=
+ grub_cpu_to_le16_compile_time (EM_PPC64)))
+ break;
+
+ if (ehdr.e_type != grub_cpu_to_be16_compile_time (ET_EXEC)
+ && ehdr.e_type != grub_cpu_to_be16_compile_time (ET_DYN))
+ break;
+
+ ret = 1;
+
+ break;
+ }
+
+ case IS_MIPS_LINUX:
+ {
+ Elf32_Ehdr ehdr;
+
+ if (grub_file_read (file, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
+ break;
+
+ if (ehdr.e_ident[EI_MAG0] != ELFMAG0
+ || ehdr.e_ident[EI_MAG1] != ELFMAG1
+ || ehdr.e_ident[EI_MAG2] != ELFMAG2
+ || ehdr.e_ident[EI_MAG3] != ELFMAG3
+ || ehdr.e_ident[EI_VERSION] != EV_CURRENT
+ || ehdr.e_version != EV_CURRENT)
+ break;
+
+ if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB
+ || ehdr.e_machine != grub_cpu_to_be16_compile_time (EM_MIPS)
+ || ehdr.e_type != grub_cpu_to_be16_compile_time (ET_EXEC))
+ break;
+
+ ret = 1;
+
+ break;
+ }
+
+ case IS_X86_KNETBSD:
+ case IS_X86_KNETBSD32:
+ case IS_X86_KNETBSD64:
+ {
+ int is32, is64;
+
+ elf = grub_elf_file (file, file->name);
+
+ if (elf->ehdr.ehdr32.e_type != grub_cpu_to_le16_compile_time (ET_EXEC)
+ || elf->ehdr.ehdr32.e_ident[EI_DATA] != ELFDATA2LSB)
+ break;
+
+ is32 = grub_elf_is_elf32 (elf);
+ is64 = grub_elf_is_elf64 (elf);
+ if (!is32 && !is64)
+ break;
+ if (!is32 && type == IS_X86_KNETBSD32)
+ break;
+ if (!is64 && type == IS_X86_KNETBSD64)
+ break;
+ if (is64)
+ ret = grub_file_check_netbsd64 (elf);
+ if (is32)
+ ret = grub_file_check_netbsd32 (elf);
+ break;
+ }
+
+ case IS_X86_KFREEBSD:
+ case IS_X86_KFREEBSD32:
+ case IS_X86_KFREEBSD64:
+ {
+ Elf32_Ehdr ehdr;
+ int is32, is64;
+
+ if (grub_file_read (file, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
+ break;
+
+ if (ehdr.e_ident[EI_MAG0] != ELFMAG0
+ || ehdr.e_ident[EI_MAG1] != ELFMAG1
+ || ehdr.e_ident[EI_MAG2] != ELFMAG2
+ || ehdr.e_ident[EI_MAG3] != ELFMAG3
+ || ehdr.e_ident[EI_VERSION] != EV_CURRENT
+ || ehdr.e_version != EV_CURRENT)
+ break;
+
+ if (ehdr.e_type != grub_cpu_to_le16_compile_time (ET_EXEC)
+ || ehdr.e_ident[EI_DATA] != ELFDATA2LSB)
+ break;
+
+ if (ehdr.e_ident[EI_OSABI] != ELFOSABI_FREEBSD)
+ break;
+
+ is32 = (ehdr.e_machine == grub_cpu_to_le16_compile_time (EM_386)
+ && ehdr.e_ident[EI_CLASS] == ELFCLASS32);
+ is64 = (ehdr.e_machine == grub_cpu_to_le16_compile_time (EM_X86_64)
+ && ehdr.e_ident[EI_CLASS] == ELFCLASS64);
+ if (!is32 && !is64)
+ break;
+ if (!is32 && (type == IS_X86_KFREEBSD32 || type == IS_X86_KNETBSD32))
+ break;
+ if (!is64 && (type == IS_X86_KFREEBSD64 || type == IS_X86_KNETBSD64))
+ break;
+ ret = 1;
+
+ break;
+ }
+
+
+ case IS_MIPSEL_LINUX:
+ {
+ Elf32_Ehdr ehdr;
+
+ if (grub_file_read (file, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
+ break;
+
+ if (ehdr.e_ident[EI_MAG0] != ELFMAG0
+ || ehdr.e_ident[EI_MAG1] != ELFMAG1
+ || ehdr.e_ident[EI_MAG2] != ELFMAG2
+ || ehdr.e_ident[EI_MAG3] != ELFMAG3
+ || ehdr.e_ident[EI_VERSION] != EV_CURRENT
+ || ehdr.e_version != EV_CURRENT)
+ break;
+
+ if (ehdr.e_machine != grub_cpu_to_le16_compile_time (EM_MIPS)
+ || ehdr.e_type != grub_cpu_to_le16_compile_time (ET_EXEC))
+ break;
+
+ ret = 1;
+
+ break;
+ }
+ case IS_ARM_LINUX:
+ {
+ struct linux_arm_kernel_header lh;
+
+ if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
+ break;
+ /* Short forward branch in A32 state (for Raspberry pi kernels). */
+ if (lh.code0 == grub_cpu_to_le32_compile_time (0xea000006))
+ {
+ ret = 1;
+ break;
+ }
+
+ if (lh.magic ==
+ grub_cpu_to_le32_compile_time (GRUB_LINUX_ARM_MAGIC_SIGNATURE))
+ {
+ ret = 1;
+ break;
+ }
+ break;
+ }
+ case IS_ARM64_LINUX:
+ {
+ struct linux_arm64_kernel_header lh;
+
+ if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
+ break;
+
+ if (lh.magic ==
+ grub_cpu_to_le32_compile_time (GRUB_LINUX_ARM64_MAGIC_SIGNATURE))
+ {
+ ret = 1;
+ break;
+ }
+ break;
+ }
+ case IS_PAE_DOMU ... IS_DOM0:
+ {
+ struct grub_xen_file_info xen_inf;
+ elf = grub_xen_file (file);
+ if (!elf)
+ break;
+ err = grub_xen_get_info (elf, &xen_inf);
+ if (err)
+ break;
+ /* Unfortuntely no way to check if kernel supports dom0. */
+ if (type == IS_DOM0)
+ ret = 1;
+ if (type == IS_PAE_DOMU)
+ ret = (xen_inf.arch == GRUB_XEN_FILE_I386_PAE
+ || xen_inf.arch == GRUB_XEN_FILE_I386_PAE_BIMODE);
+ if (type == IS_64_DOMU)
+ ret = (xen_inf.arch == GRUB_XEN_FILE_X86_64);
+ break;
+ }
+ case IS_MULTIBOOT:
+ case IS_MULTIBOOT2:
+ {
+ grub_uint32_t *buffer;
+ grub_ssize_t len;
+ grub_size_t search_size;
+ grub_uint32_t *header;
+ grub_uint32_t magic;
+ grub_size_t step;
+
+ if (type == IS_MULTIBOOT2)
+ {
+ search_size = 32768;
+ magic = grub_cpu_to_le32_compile_time (0xe85250d6);
+ step = 2;
+ }
+ else
+ {
+ search_size = 8192;
+ magic = grub_cpu_to_le32_compile_time (0x1BADB002);
+ step = 1;
+ }
+
+ buffer = grub_malloc (search_size);
+ if (!buffer)
+ break;
+
+ len = grub_file_read (file, buffer, search_size);
+ if (len < 32)
+ {
+ grub_free (buffer);
+ break;
+ }
+
+ /* Look for the multiboot header in the buffer. The header should
+ be at least 12 bytes and aligned on a 4-byte boundary. */
+ for (header = buffer;
+ ((char *) header <=
+ (char *) buffer + len - (type == IS_MULTIBOOT2 ? 16 : 12));
+ header += step)
+ {
+ if (header[0] == magic
+ && !(grub_le_to_cpu32 (header[0])
+ + grub_le_to_cpu32 (header[1])
+ + grub_le_to_cpu32 (header[2])
+ + (type == IS_MULTIBOOT2
+ ? grub_le_to_cpu32 (header[3]) : 0)))
+ {
+ ret = 1;
+ break;
+ }
+ }
+
+ grub_free (buffer);
+ break;
+ }
+ case IS_X86_LINUX32:
+ case IS_X86_LINUX:
+ {
+ struct linux_i386_kernel_header lh;
+ if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
+ break;
+ if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55))
+ break;
+
+ if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
+ break;
+
+ /* FIXME: some really old kernels (< 1.3.73) will fail this. */
+ if (lh.header !=
+ grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE)
+ || grub_le_to_cpu16 (lh.version) < 0x0200)
+ break;
+
+ if (type == IS_X86_LINUX)
+ {
+ ret = 1;
+ break;
+ }
+
+ /* FIXME: 2.03 is not always good enough (Linux 2.4 can be 2.03 and
+ still not support 32-bit boot. */
+ if (lh.header !=
+ grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE)
+ || grub_le_to_cpu16 (lh.version) < 0x0203)
+ break;
+
+ if (!(lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL))
+ break;
+ ret = 1;
+ break;
+ }
+ case IS_HIBERNATED:
+ {
+ grub_uint8_t hibr_file_magic[4];
+ if (grub_file_read (file, &hibr_file_magic, sizeof (hibr_file_magic))
+ != sizeof (hibr_file_magic))
+ break;
+ if (grub_memcmp ("hibr", hibr_file_magic, sizeof (hibr_file_magic)) ==
+ 0
+ || grub_memcmp ("HIBR", hibr_file_magic,
+ sizeof (hibr_file_magic)) == 0)
+ ret = 1;
+ break;
+ }
+ case IS_XNU64:
+ case IS_XNU32:
+ {
+ macho = grub_macho_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL,
+ (type == IS_XNU64));
+ if (!macho)
+ break;
+ /* FIXME: more checks? */
+ ret = 1;
+ break;
+ }
+ case IS_XNU_HIBR:
+ {
+ struct grub_xnu_hibernate_header hibhead;
+ if (grub_file_read (file, &hibhead, sizeof (hibhead))
+ != sizeof (hibhead))
+ break;
+ if (hibhead.magic !=
+ grub_cpu_to_le32_compile_time (GRUB_XNU_HIBERNATE_MAGIC))
+ break;
+ ret = 1;
+ break;
+ }
+ case IS_32_EFI:
+ case IS_64_EFI:
+ case IS_IA_EFI:
+ case IS_ARM64_EFI:
+ case IS_ARM_EFI:
+ case IS_RISCV32_EFI:
+ case IS_RISCV64_EFI:
+ {
+ char signature[4];
+ grub_uint32_t pe_offset;
+ struct grub_pe32_coff_header coff_head;
+
+ if (grub_file_read (file, signature, 2) != 2)
+ break;
+ if (signature[0] != 'M' || signature[1] != 'Z')
+ break;
+ if ((grub_ssize_t) grub_file_seek (file, 0x3c) == -1)
+ break;
+ if (grub_file_read (file, &pe_offset, 4) != 4)
+ break;
+ if ((grub_ssize_t) grub_file_seek (file, grub_le_to_cpu32 (pe_offset))
+ == -1)
+ break;
+ if (grub_file_read (file, signature, 4) != 4)
+ break;
+ if (signature[0] != 'P' || signature[1] != 'E'
+ || signature[2] != '\0' || signature[3] != '\0')
+ break;
+
+ if (grub_file_read (file, &coff_head, sizeof (coff_head))
+ != sizeof (coff_head))
+ break;
+ if (type == IS_32_EFI
+ && coff_head.machine !=
+ grub_cpu_to_le16_compile_time (GRUB_PE32_MACHINE_I386))
+ break;
+ if (type == IS_64_EFI
+ && coff_head.machine !=
+ grub_cpu_to_le16_compile_time (GRUB_PE32_MACHINE_X86_64))
+ break;
+ if (type == IS_IA_EFI
+ && coff_head.machine !=
+ grub_cpu_to_le16_compile_time (GRUB_PE32_MACHINE_IA64))
+ break;
+ if (type == IS_ARM64_EFI
+ && coff_head.machine !=
+ grub_cpu_to_le16_compile_time (GRUB_PE32_MACHINE_ARM64))
+ break;
+ if (type == IS_ARM_EFI
+ && coff_head.machine !=
+ grub_cpu_to_le16_compile_time (GRUB_PE32_MACHINE_ARMTHUMB_MIXED))
+ break;
+ if ((type == IS_RISCV32_EFI || type == IS_RISCV64_EFI)
+ && coff_head.machine !=
+ grub_cpu_to_le16_compile_time (GRUB_PE32_MACHINE_RISCV64))
+ /* TODO: Determine bitness dynamically */
+ break;
+ if (type == IS_IA_EFI || type == IS_64_EFI || type == IS_ARM64_EFI ||
+ type == IS_RISCV32_EFI || type == IS_RISCV64_EFI)
+ {
+ struct grub_pe64_optional_header o64;
+ if (grub_file_read (file, &o64, sizeof (o64)) != sizeof (o64))
+ break;
+ if (o64.magic !=
+ grub_cpu_to_le16_compile_time (GRUB_PE32_PE64_MAGIC))
+ break;
+ if (o64.subsystem !=
+ grub_cpu_to_le16_compile_time
+ (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION))
+ break;
+ ret = 1;
+ break;
+ }
+ if (type == IS_32_EFI || type == IS_ARM_EFI)
+ {
+ struct grub_pe32_optional_header o32;
+ if (grub_file_read (file, &o32, sizeof (o32)) != sizeof (o32))
+ break;
+ if (o32.magic !=
+ grub_cpu_to_le16_compile_time (GRUB_PE32_PE32_MAGIC))
+ break;
+ if (o32.subsystem !=
+ grub_cpu_to_le16_compile_time
+ (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION))
+ break;
+ ret = 1;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (elf)
+ grub_elf_close (elf);
+ else if (macho)
+ grub_macho_close (macho);
+ else if (file)
+ grub_file_close (file);
+
+ if (!ret && (grub_errno == GRUB_ERR_BAD_OS || grub_errno == GRUB_ERR_NONE))
+ /* TRANSLATORS: it's a standalone boolean value,
+ opposite of "true". */
+ grub_error (GRUB_ERR_TEST_FAILURE, N_("false"));
+ return grub_errno;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(file)
+{
+ cmd = grub_register_extcmd ("file", grub_cmd_file, 0,
+ N_("OPTIONS FILE"),
+ N_("Check if FILE is of specified type."),
+ options);
+}
+
+GRUB_MOD_FINI(file)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/file32.c b/grub-core/commands/file32.c
new file mode 100644
index 0000000..0861c45
--- /dev/null
+++ b/grub-core/commands/file32.c
@@ -0,0 +1,5 @@
+#define GRUB_TARGET_WORDSIZE 32
+#define XX 32
+#define ehdrXX ehdr32
+#define grub_file_check_netbsdXX grub_file_check_netbsd32
+#include "fileXX.c"
diff --git a/grub-core/commands/file64.c b/grub-core/commands/file64.c
new file mode 100644
index 0000000..90890d4
--- /dev/null
+++ b/grub-core/commands/file64.c
@@ -0,0 +1,5 @@
+#define GRUB_TARGET_WORDSIZE 64
+#define XX 64
+#define ehdrXX ehdr64
+#define grub_file_check_netbsdXX grub_file_check_netbsd64
+#include "fileXX.c"
diff --git a/grub-core/commands/fileXX.c b/grub-core/commands/fileXX.c
new file mode 100644
index 0000000..c17d26c
--- /dev/null
+++ b/grub-core/commands/fileXX.c
@@ -0,0 +1,74 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/fileid.h>
+#include <grub/elfload.h>
+#include <grub/misc.h>
+
+#pragma GCC diagnostic ignored "-Wcast-align"
+
+int
+grub_file_check_netbsdXX (grub_elf_t elf)
+{
+ Elf_Shdr *s, *s0;
+
+ grub_size_t shnum = elf->ehdr.ehdrXX.e_shnum;
+ grub_size_t shentsize = elf->ehdr.ehdrXX.e_shentsize;
+ grub_size_t shsize = shnum * shentsize;
+ grub_off_t stroff;
+
+ if (!shnum || !shentsize)
+ return 0;
+
+ s0 = grub_malloc (shsize);
+ if (!s0)
+ return 0;
+
+ if (grub_file_seek (elf->file, elf->ehdr.ehdrXX.e_shoff) == (grub_off_t) -1)
+ goto fail;
+
+ if (grub_file_read (elf->file, s0, shsize) != (grub_ssize_t) shsize)
+ goto fail;
+
+ s = (Elf_Shdr *) ((char *) s0 + elf->ehdr.ehdrXX.e_shstrndx * shentsize);
+ stroff = s->sh_offset;
+
+ for (s = s0; s < (Elf_Shdr *) ((char *) s0 + shnum * shentsize);
+ s = (Elf_Shdr *) ((char *) s + shentsize))
+ {
+ char name[sizeof(".note.netbsd.ident")];
+ grub_memset (name, 0, sizeof (name));
+ if (grub_file_seek (elf->file, stroff + s->sh_name) == (grub_off_t) -1)
+ goto fail;
+
+ if (grub_file_read (elf->file, name, sizeof (name)) != (grub_ssize_t) sizeof (name))
+ {
+ if (grub_errno)
+ goto fail;
+ continue;
+ }
+ if (grub_memcmp (name, ".note.netbsd.ident",
+ sizeof(".note.netbsd.ident")) != 0)
+ continue;
+ grub_free (s0);
+ return 1;
+ }
+ fail:
+ grub_free (s0);
+ return 0;
+}
diff --git a/grub-core/commands/gptsync.c b/grub-core/commands/gptsync.c
new file mode 100644
index 0000000..444e248
--- /dev/null
+++ b/grub-core/commands/gptsync.c
@@ -0,0 +1,266 @@
+/* gptsync.c - fill the mbr based on gpt entries */
+/* XXX: I don't know what to do if sector size isn't 512 bytes */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/command.h>
+#include <grub/dl.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+#include <grub/msdos_partition.h>
+#include <grub/partition.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/fs.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* Convert a LBA address to a CHS address in the INT 13 format. */
+/* Taken from grub1. */
+/* XXX: use hardcoded geometry of C = 1024, H = 255, S = 63.
+ Is it a problem?
+*/
+static void
+lba_to_chs (grub_uint32_t lba, grub_uint8_t *cl, grub_uint8_t *ch,
+ grub_uint8_t *dh)
+{
+ grub_uint32_t cylinder, head, sector;
+ grub_uint32_t sectors = 63, heads = 255, cylinders = 1024;
+
+ sector = lba % sectors + 1;
+ head = (lba / sectors) % heads;
+ cylinder = lba / (sectors * heads);
+
+ if (cylinder >= cylinders)
+ {
+ *cl = *ch = *dh = 0xff;
+ return;
+ }
+
+ *cl = sector | ((cylinder & 0x300) >> 2);
+ *ch = cylinder & 0xFF;
+ *dh = head;
+}
+
+static grub_err_t
+grub_cmd_gptsync (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ grub_device_t dev;
+ struct grub_msdos_partition_mbr mbr;
+ struct grub_partition *partition;
+ grub_disk_addr_t first_sector;
+ int numactive = 0;
+ int i;
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
+ if (argc > 4)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "only 3 partitions can be "
+ "in hybrid MBR");
+
+ if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')')
+ {
+ args[0][grub_strlen (args[0]) - 1] = 0;
+ dev = grub_device_open (args[0] + 1);
+ args[0][grub_strlen (args[0])] = ')';
+ }
+ else
+ dev = grub_device_open (args[0]);
+
+ if (! dev)
+ return grub_errno;
+
+ if (! dev->disk)
+ {
+ grub_device_close (dev);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk");
+ }
+
+ /* Read the protective MBR. */
+ if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr))
+ {
+ grub_device_close (dev);
+ return grub_errno;
+ }
+
+ /* Check if it is valid. */
+ if (mbr.signature != grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE))
+ {
+ grub_device_close (dev);
+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
+ }
+
+ /* Make sure the MBR is a protective MBR and not a normal MBR. */
+ for (i = 0; i < 4; i++)
+ if (mbr.entries[i].type == GRUB_PC_PARTITION_TYPE_GPT_DISK)
+ break;
+ if (i == 4)
+ {
+ grub_device_close (dev);
+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
+ }
+
+ first_sector = dev->disk->total_sectors;
+ for (i = 1; i < argc; i++)
+ {
+ char *separator, csep = 0;
+ grub_uint8_t type;
+ separator = grub_strchr (args[i], '+');
+ if (! separator)
+ separator = grub_strchr (args[i], '-');
+ if (separator)
+ {
+ csep = *separator;
+ *separator = 0;
+ }
+ partition = grub_partition_probe (dev->disk, args[i]);
+ if (separator)
+ *separator = csep;
+ if (! partition)
+ {
+ grub_device_close (dev);
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+ N_("no such partition"));
+ }
+
+ if (partition->start + partition->len > 0xffffffff)
+ {
+ grub_device_close (dev);
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ "only partitions residing in the first 2TB "
+ "can be present in hybrid MBR");
+ }
+
+
+ if (first_sector > partition->start)
+ first_sector = partition->start;
+
+ if (separator && *(separator + 1))
+ type = grub_strtoul (separator + 1, 0, 0);
+ else
+ {
+ grub_fs_t fs = 0;
+ dev->disk->partition = partition;
+ fs = grub_fs_probe (dev);
+
+ /* Unknown filesystem isn't fatal. */
+ if (grub_errno == GRUB_ERR_UNKNOWN_FS)
+ {
+ fs = 0;
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ if (fs && grub_strcmp (fs->name, "ntfs") == 0)
+ type = GRUB_PC_PARTITION_TYPE_NTFS;
+ else if (fs && grub_strcmp (fs->name, "fat") == 0)
+ /* FIXME: detect FAT16. */
+ type = GRUB_PC_PARTITION_TYPE_FAT32_LBA;
+ else if (fs && (grub_strcmp (fs->name, "hfsplus") == 0
+ || grub_strcmp (fs->name, "hfs") == 0))
+ type = GRUB_PC_PARTITION_TYPE_HFS;
+ else
+ /* FIXME: detect more types. */
+ type = GRUB_PC_PARTITION_TYPE_EXT2FS;
+
+ dev->disk->partition = 0;
+ }
+
+ mbr.entries[i].flag = (csep == '+') ? 0x80 : 0;
+ if (csep == '+')
+ {
+ numactive++;
+ if (numactive == 2)
+ {
+ grub_device_close (dev);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "only one partition can be active");
+ }
+ }
+ mbr.entries[i].type = type;
+ mbr.entries[i].start = grub_cpu_to_le32 (partition->start);
+ lba_to_chs (partition->start,
+ &(mbr.entries[i].start_sector),
+ &(mbr.entries[i].start_cylinder),
+ &(mbr.entries[i].start_head));
+ lba_to_chs (partition->start + partition->len - 1,
+ &(mbr.entries[i].end_sector),
+ &(mbr.entries[i].end_cylinder),
+ &(mbr.entries[i].end_head));
+ mbr.entries[i].length = grub_cpu_to_le32 (partition->len);
+ grub_free (partition);
+ }
+ for (; i < 4; i++)
+ grub_memset (&(mbr.entries[i]), 0, sizeof (mbr.entries[i]));
+
+ /* The protective partition. */
+ if (first_sector > 0xffffffff)
+ first_sector = 0xffffffff;
+ else
+ first_sector--;
+ mbr.entries[0].flag = 0;
+ mbr.entries[0].type = GRUB_PC_PARTITION_TYPE_GPT_DISK;
+ mbr.entries[0].start = grub_cpu_to_le32_compile_time (1);
+ lba_to_chs (1,
+ &(mbr.entries[0].start_sector),
+ &(mbr.entries[0].start_cylinder),
+ &(mbr.entries[0].start_head));
+ lba_to_chs (first_sector,
+ &(mbr.entries[0].end_sector),
+ &(mbr.entries[0].end_cylinder),
+ &(mbr.entries[0].end_head));
+ mbr.entries[0].length = grub_cpu_to_le32 (first_sector);
+
+ mbr.signature = grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE);
+
+ if (grub_disk_write (dev->disk, 0, 0, sizeof (mbr), &mbr))
+ {
+ grub_device_close (dev);
+ return grub_errno;
+ }
+
+ grub_device_close (dev);
+
+ grub_printf_ (N_("New MBR is written to `%s'\n"), args[0]);
+
+ return GRUB_ERR_NONE;
+}
+
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(gptsync)
+{
+ (void) mod; /* To stop warning. */
+ cmd = grub_register_command ("gptsync", grub_cmd_gptsync,
+ N_("DEVICE [PARTITION[+/-[TYPE]]] ..."),
+ /* TRANSLATORS: MBR type is one-byte partition
+ type id. */
+ N_("Fill hybrid MBR of GPT drive DEVICE. "
+ "Specified partitions will be a part "
+ "of hybrid MBR. Up to 3 partitions are "
+ "allowed. TYPE is an MBR type. "
+ "+ means that partition is active. "
+ "Only one partition can be active."));
+}
+
+GRUB_MOD_FINI(gptsync)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/halt.c b/grub-core/commands/halt.c
new file mode 100644
index 0000000..f8596ec
--- /dev/null
+++ b/grub-core/commands/halt.c
@@ -0,0 +1,47 @@
+/* halt.c - command to halt the computer. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2007,2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/command.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t __attribute__ ((noreturn))
+grub_cmd_halt (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ grub_halt ();
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(halt)
+{
+ cmd = grub_register_command ("halt", grub_cmd_halt,
+ 0, N_("Halts the computer. This command does"
+ " not work on all firmware implementations."));
+}
+
+GRUB_MOD_FINI(halt)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/hashsum.c b/grub-core/commands/hashsum.c
new file mode 100644
index 0000000..b8a22b0
--- /dev/null
+++ b/grub-core/commands/hashsum.c
@@ -0,0 +1,334 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/extcmd.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/crypto.h>
+#include <grub/normal.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] = {
+ {"hash", 'h', 0, N_("Specify hash to use."), N_("HASH"), ARG_TYPE_STRING},
+ {"check", 'c', 0, N_("Check hashes of files with hash list FILE."),
+ N_("FILE"), ARG_TYPE_STRING},
+ {"prefix", 'p', 0, N_("Base directory for hash list."), N_("DIR"),
+ ARG_TYPE_STRING},
+ {"keep-going", 'k', 0, N_("Don't stop after first error."), 0, 0},
+ {"uncompress", 'u', 0, N_("Uncompress file before checksumming."), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+};
+
+static struct { const char *name; const char *hashname; } aliases[] =
+ {
+ {"sha256sum", "sha256"},
+ {"sha512sum", "sha512"},
+ {"sha1sum", "sha1"},
+ {"md5sum", "md5"},
+ {"crc", "crc32"},
+ };
+
+static inline int
+hextoval (char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+static grub_err_t
+hash_file (grub_file_t file, const gcry_md_spec_t *hash, void *result)
+{
+ void *context;
+ grub_uint8_t *readbuf;
+#define BUF_SIZE 4096
+ readbuf = grub_malloc (BUF_SIZE);
+ if (!readbuf)
+ return grub_errno;
+ context = grub_zalloc (hash->contextsize);
+ if (!readbuf || !context)
+ goto fail;
+
+ hash->init (context);
+ while (1)
+ {
+ grub_ssize_t r;
+ r = grub_file_read (file, readbuf, BUF_SIZE);
+ if (r < 0)
+ goto fail;
+ if (r == 0)
+ break;
+ hash->write (context, readbuf, r);
+ }
+ hash->final (context);
+ grub_memcpy (result, hash->read (context), hash->mdlen);
+
+ grub_free (readbuf);
+ grub_free (context);
+
+ return GRUB_ERR_NONE;
+
+ fail:
+ grub_free (readbuf);
+ grub_free (context);
+ return grub_errno;
+}
+
+static grub_err_t
+check_list (const gcry_md_spec_t *hash, const char *hashfilename,
+ const char *prefix, int keep, int uncompress)
+{
+ grub_file_t hashlist, file;
+ char *buf = NULL;
+ grub_uint8_t expected[GRUB_CRYPTO_MAX_MDLEN];
+ grub_uint8_t actual[GRUB_CRYPTO_MAX_MDLEN];
+ grub_err_t err;
+ unsigned i;
+ unsigned unread = 0, mismatch = 0;
+
+ if (hash->mdlen > GRUB_CRYPTO_MAX_MDLEN)
+ return grub_error (GRUB_ERR_BUG, "mdlen is too long");
+
+ hashlist = grub_file_open (hashfilename, GRUB_FILE_TYPE_HASHLIST);
+ if (!hashlist)
+ return grub_errno;
+
+ while (grub_free (buf), (buf = grub_file_getline (hashlist)))
+ {
+ const char *p = buf;
+ while (grub_isspace (p[0]))
+ p++;
+ for (i = 0; i < hash->mdlen; i++)
+ {
+ int high, low;
+ high = hextoval (*p++);
+ low = hextoval (*p++);
+ if (high < 0 || low < 0)
+ {
+ grub_free (buf);
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list");
+ }
+ expected[i] = (high << 4) | low;
+ }
+ if ((p[0] != ' ' && p[0] != '\t') || (p[1] != ' ' && p[1] != '\t'))
+ {
+ grub_free (buf);
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list");
+ }
+ p += 2;
+ if (prefix)
+ {
+ char *filename;
+
+ filename = grub_xasprintf ("%s/%s", prefix, p);
+ if (!filename)
+ {
+ grub_free (buf);
+ return grub_errno;
+ }
+ file = grub_file_open (filename, GRUB_FILE_TYPE_TO_HASH
+ | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS
+ : GRUB_FILE_TYPE_NONE));
+ grub_free (filename);
+ }
+ else
+ file = grub_file_open (p, GRUB_FILE_TYPE_TO_HASH
+ | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS
+ : GRUB_FILE_TYPE_NONE));
+ if (!file)
+ {
+ grub_file_close (hashlist);
+ grub_free (buf);
+ return grub_errno;
+ }
+ err = hash_file (file, hash, actual);
+ grub_file_close (file);
+ if (err)
+ {
+ grub_printf_ (N_("%s: READ ERROR\n"), p);
+ if (!keep)
+ {
+ grub_file_close (hashlist);
+ grub_free (buf);
+ return err;
+ }
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+ unread++;
+ continue;
+ }
+ if (grub_crypto_memcmp (expected, actual, hash->mdlen) != 0)
+ {
+ grub_printf_ (N_("%s: HASH MISMATCH\n"), p);
+ if (!keep)
+ {
+ grub_file_close (hashlist);
+ grub_free (buf);
+ return grub_error (GRUB_ERR_TEST_FAILURE,
+ "hash of '%s' mismatches", p);
+ }
+ mismatch++;
+ continue;
+ }
+ grub_printf_ (N_("%s: OK\n"), p);
+ }
+ if (mismatch || unread)
+ return grub_error (GRUB_ERR_TEST_FAILURE,
+ "%d files couldn't be read and hash "
+ "of %d files mismatches", unread, mismatch);
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_hashsum (struct grub_extcmd_context *ctxt,
+ int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ const char *hashname = NULL;
+ const char *prefix = NULL;
+ const gcry_md_spec_t *hash;
+ unsigned i;
+ int keep = state[3].set;
+ int uncompress = state[4].set;
+ unsigned unread = 0;
+
+ for (i = 0; i < ARRAY_SIZE (aliases); i++)
+ if (grub_strcmp (ctxt->extcmd->cmd->name, aliases[i].name) == 0)
+ hashname = aliases[i].hashname;
+ if (state[0].set)
+ hashname = state[0].arg;
+
+ if (!hashname)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no hash specified");
+
+ hash = grub_crypto_lookup_md_by_name (hashname);
+ if (!hash)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown hash");
+
+ if (hash->mdlen > GRUB_CRYPTO_MAX_MDLEN)
+ return grub_error (GRUB_ERR_BUG, "mdlen is too long");
+
+ if (state[2].set)
+ prefix = state[2].arg;
+
+ if (state[1].set)
+ {
+ if (argc != 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "--check is incompatible with file list");
+ return check_list (hash, state[1].arg, prefix, keep, uncompress);
+ }
+
+ for (i = 0; i < (unsigned) argc; i++)
+ {
+ GRUB_PROPERLY_ALIGNED_ARRAY (result, GRUB_CRYPTO_MAX_MDLEN);
+ grub_file_t file;
+ grub_err_t err;
+ unsigned j;
+ file = grub_file_open (args[i], GRUB_FILE_TYPE_TO_HASH
+ | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS
+ : GRUB_FILE_TYPE_NONE));
+ if (!file)
+ {
+ if (!keep)
+ return grub_errno;
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+ unread++;
+ continue;
+ }
+ err = hash_file (file, hash, result);
+ grub_file_close (file);
+ if (err)
+ {
+ if (!keep)
+ return err;
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+ unread++;
+ continue;
+ }
+ for (j = 0; j < hash->mdlen; j++)
+ grub_printf ("%02x", ((grub_uint8_t *) result)[j]);
+ grub_printf (" %s\n", args[i]);
+ }
+
+ if (unread)
+ return grub_error (GRUB_ERR_TEST_FAILURE, "%d files couldn't be read",
+ unread);
+ return GRUB_ERR_NONE;
+}
+
+static grub_extcmd_t cmd, cmd_md5, cmd_sha1, cmd_sha256, cmd_sha512, cmd_crc;
+
+GRUB_MOD_INIT(hashsum)
+{
+ cmd = grub_register_extcmd ("hashsum", grub_cmd_hashsum, 0,
+ N_("-h HASH [-c FILE [-p PREFIX]] "
+ "[FILE1 [FILE2 ...]]"),
+ /* TRANSLATORS: "hash checksum" is just to
+ be a bit more precise, you can treat it as
+ just "hash". */
+ N_("Compute or check hash checksum."),
+ options);
+ cmd_md5 = grub_register_extcmd ("md5sum", grub_cmd_hashsum, 0,
+ N_("[-c FILE [-p PREFIX]] "
+ "[FILE1 [FILE2 ...]]"),
+ N_("Compute or check hash checksum."),
+ options);
+ cmd_sha1 = grub_register_extcmd ("sha1sum", grub_cmd_hashsum, 0,
+ N_("[-c FILE [-p PREFIX]] "
+ "[FILE1 [FILE2 ...]]"),
+ N_("Compute or check hash checksum."),
+ options);
+ cmd_sha256 = grub_register_extcmd ("sha256sum", grub_cmd_hashsum, 0,
+ N_("[-c FILE [-p PREFIX]] "
+ "[FILE1 [FILE2 ...]]"),
+ N_("Compute or check hash checksum."),
+ options);
+ cmd_sha512 = grub_register_extcmd ("sha512sum", grub_cmd_hashsum, 0,
+ N_("[-c FILE [-p PREFIX]] "
+ "[FILE1 [FILE2 ...]]"),
+ N_("Compute or check hash checksum."),
+ options);
+
+ cmd_crc = grub_register_extcmd ("crc", grub_cmd_hashsum, 0,
+ N_("[-c FILE [-p PREFIX]] "
+ "[FILE1 [FILE2 ...]]"),
+ N_("Compute or check hash checksum."),
+ options);
+}
+
+GRUB_MOD_FINI(hashsum)
+{
+ grub_unregister_extcmd (cmd);
+ grub_unregister_extcmd (cmd_md5);
+ grub_unregister_extcmd (cmd_sha1);
+ grub_unregister_extcmd (cmd_sha256);
+ grub_unregister_extcmd (cmd_sha512);
+ grub_unregister_extcmd (cmd_crc);
+}
diff --git a/grub-core/commands/hdparm.c b/grub-core/commands/hdparm.c
new file mode 100644
index 0000000..2e2319e
--- /dev/null
+++ b/grub-core/commands/hdparm.c
@@ -0,0 +1,447 @@
+/* hdparm.c - command to get/set ATA disk parameters. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/ata.h>
+#include <grub/scsi.h>
+#include <grub/disk.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/lib/hexdump.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] = {
+ {"apm", 'B', 0, N_("Set Advanced Power Management\n"
+ "(1=low, ..., 254=high, 255=off)."),
+ 0, ARG_TYPE_INT},
+ {"power", 'C', 0, N_("Display power mode."), 0, ARG_TYPE_NONE},
+ {"security-freeze", 'F', 0, N_("Freeze ATA security settings until reset."),
+ 0, ARG_TYPE_NONE},
+ {"health", 'H', 0, N_("Display SMART health status."), 0, ARG_TYPE_NONE},
+ {"aam", 'M', 0, N_("Set Automatic Acoustic Management\n"
+ "(0=off, 128=quiet, ..., 254=fast)."),
+ 0, ARG_TYPE_INT},
+ {"standby-timeout", 'S', 0, N_("Set standby timeout\n"
+ "(0=off, 1=5s, 2=10s, ..., 240=20m, 241=30m, ...)."),
+ 0, ARG_TYPE_INT},
+ {"standby", 'y', 0, N_("Set drive to standby mode."), 0, ARG_TYPE_NONE},
+ {"sleep", 'Y', 0, N_("Set drive to sleep mode."), 0, ARG_TYPE_NONE},
+ {"identify", 'i', 0, N_("Print drive identity and settings."),
+ 0, ARG_TYPE_NONE},
+ {"dumpid", 'I', 0, N_("Show raw contents of ATA IDENTIFY sector."),
+ 0, ARG_TYPE_NONE},
+ {"smart", -1, 0, N_("Disable/enable SMART (0/1)."), 0, ARG_TYPE_INT},
+ {"quiet", 'q', 0, N_("Do not print messages."), 0, ARG_TYPE_NONE},
+ {0, 0, 0, 0, 0, 0}
+};
+
+enum grub_ata_smart_commands
+ {
+ GRUB_ATA_FEAT_SMART_ENABLE = 0xd8,
+ GRUB_ATA_FEAT_SMART_DISABLE = 0xd9,
+ GRUB_ATA_FEAT_SMART_STATUS = 0xda,
+ };
+
+static int quiet = 0;
+
+static grub_err_t
+grub_hdparm_do_ata_cmd (grub_ata_t ata, grub_uint8_t cmd,
+ grub_uint8_t features, grub_uint8_t sectors,
+ void * buffer, int size)
+{
+ struct grub_disk_ata_pass_through_parms apt;
+ grub_memset (&apt, 0, sizeof (apt));
+
+ apt.taskfile.cmd = cmd;
+ apt.taskfile.features = features;
+ apt.taskfile.sectors = sectors;
+ apt.taskfile.disk = 0xE0;
+
+ apt.buffer = buffer;
+ apt.size = size;
+
+ if (ata->dev->readwrite (ata, &apt, 0))
+ return grub_errno;
+
+ return GRUB_ERR_NONE;
+}
+
+static int
+grub_hdparm_do_check_powermode_cmd (grub_ata_t ata)
+{
+ struct grub_disk_ata_pass_through_parms apt;
+ grub_memset (&apt, 0, sizeof (apt));
+
+ apt.taskfile.cmd = GRUB_ATA_CMD_CHECK_POWER_MODE;
+ apt.taskfile.disk = 0xE0;
+
+ if (ata->dev->readwrite (ata, &apt, 0))
+ return -1;
+
+ return apt.taskfile.sectors;
+}
+
+static int
+grub_hdparm_do_smart_cmd (grub_ata_t ata, grub_uint8_t features)
+{
+ struct grub_disk_ata_pass_through_parms apt;
+ grub_memset (&apt, 0, sizeof (apt));
+
+ apt.taskfile.cmd = GRUB_ATA_CMD_SMART;
+ apt.taskfile.features = features;
+ apt.taskfile.lba_mid = 0x4f;
+ apt.taskfile.lba_high = 0xc2;
+ apt.taskfile.disk = 0xE0;
+
+ if (ata->dev->readwrite (ata, &apt, 0))
+ return -1;
+
+ if (features == GRUB_ATA_FEAT_SMART_STATUS)
+ {
+ if ( apt.taskfile.lba_mid == 0x4f
+ && apt.taskfile.lba_high == 0xc2)
+ return 0; /* Good SMART status. */
+ else if ( apt.taskfile.lba_mid == 0xf4
+ && apt.taskfile.lba_high == 0x2c)
+ return 1; /* Bad SMART status. */
+ else
+ return -1;
+ }
+ return 0;
+}
+
+static grub_err_t
+grub_hdparm_simple_cmd (const char * msg,
+ grub_ata_t ata, grub_uint8_t cmd)
+{
+ if (! quiet && msg)
+ grub_printf ("%s", msg);
+
+ grub_err_t err = grub_hdparm_do_ata_cmd (ata, cmd, 0, 0, NULL, 0);
+
+ if (! quiet && msg)
+ grub_printf ("%s\n", ! err ? "" : ": not supported");
+ return err;
+}
+
+static grub_err_t
+grub_hdparm_set_val_cmd (const char * msg, int val,
+ grub_ata_t ata, grub_uint8_t cmd,
+ grub_uint8_t features, grub_uint8_t sectors)
+{
+ if (! quiet && msg && *msg)
+ {
+ if (val >= 0)
+ grub_printf ("Set %s to %d", msg, val);
+ else
+ grub_printf ("Disable %s", msg);
+ }
+
+ grub_err_t err = grub_hdparm_do_ata_cmd (ata, cmd, features, sectors,
+ NULL, 0);
+
+ if (! quiet && msg)
+ grub_printf ("%s\n", ! err ? "" : ": not supported");
+ return err;
+}
+
+static const char *
+le16_to_char (grub_uint16_t *dest, const grub_uint16_t * src16, unsigned bytes)
+{
+ unsigned i;
+ for (i = 0; i < bytes / 2; i++)
+ dest[i] = grub_swap_bytes16 (src16[i]);
+ dest[i] = 0;
+ return (char *) dest;
+}
+
+static void
+grub_hdparm_print_identify (const grub_uint16_t * idw)
+{
+ /* Print identity strings. */
+ grub_uint16_t tmp[21];
+ grub_printf ("Model: \"%.40s\"\n", le16_to_char (tmp, &idw[27], 40));
+ grub_printf ("Firmware: \"%.8s\"\n", le16_to_char (tmp, &idw[23], 8));
+ grub_printf ("Serial: \"%.20s\"\n", le16_to_char (tmp, &idw[10], 20));
+
+ /* Print AAM, APM and SMART settings. */
+ grub_uint16_t features1 = grub_le_to_cpu16 (idw[82]);
+ grub_uint16_t features2 = grub_le_to_cpu16 (idw[83]);
+ grub_uint16_t enabled1 = grub_le_to_cpu16 (idw[85]);
+ grub_uint16_t enabled2 = grub_le_to_cpu16 (idw[86]);
+
+ grub_printf ("Automatic Acoustic Management: ");
+ if (features2 & 0x0200)
+ {
+ if (enabled2 & 0x0200)
+ {
+ grub_uint16_t aam = grub_le_to_cpu16 (idw[94]);
+ grub_printf ("%u (128=quiet, ..., 254=fast, recommended=%u)\n",
+ aam & 0xff, (aam >> 8) & 0xff);
+ }
+ else
+ grub_printf ("disabled\n");
+ }
+ else
+ grub_printf ("not supported\n");
+
+ grub_printf ("Advanced Power Management: ");
+ if (features2 & 0x0008)
+ {
+ if (enabled2 & 0x0008)
+ grub_printf ("%u (1=low, ..., 254=high)\n",
+ grub_le_to_cpu16 (idw[91]) & 0xff);
+ else
+ grub_printf ("disabled\n");
+ }
+ else
+ grub_printf ("not supported\n");
+
+ grub_printf ("SMART Feature Set: ");
+ if (features1 & 0x0001)
+ grub_printf ("%sabled\n", (enabled1 & 0x0001 ? "en" : "dis"));
+ else
+ grub_printf ("not supported\n");
+
+ /* Print security settings. */
+ grub_uint16_t security = grub_le_to_cpu16 (idw[128]);
+
+ grub_printf ("ATA Security: ");
+ if (security & 0x0001)
+ grub_printf ("%s, %s, %s, %s\n",
+ (security & 0x0002 ? "ENABLED" : "disabled"),
+ (security & 0x0004 ? "**LOCKED**" : "not locked"),
+ (security & 0x0008 ? "frozen" : "NOT FROZEN"),
+ (security & 0x0010 ? "COUNT EXPIRED" : "count not expired"));
+ else
+ grub_printf ("not supported\n");
+}
+
+static void
+grub_hdparm_print_standby_tout (int timeout)
+{
+ if (timeout == 0)
+ grub_printf ("off");
+ else if (timeout <= 252 || timeout == 255)
+ {
+ int h = 0, m = 0 , s = 0;
+ if (timeout == 255)
+ {
+ m = 21;
+ s = 15;
+ }
+ else if (timeout == 252)
+ m = 21;
+ else if (timeout <= 240)
+ {
+ s = timeout * 5;
+ m = s / 60;
+ s %= 60;
+ }
+ else
+ {
+ m = (timeout - 240) * 30;
+ h = m / 60;
+ m %= 60;
+ }
+ grub_printf ("%02d:%02d:%02d", h, m, s);
+ }
+ else
+ grub_printf ("invalid or vendor-specific");
+}
+
+static int get_int_arg (const struct grub_arg_list *state)
+{
+ return (state->set ? (int)grub_strtoul (state->arg, 0, 0) : -1);
+}
+
+static grub_err_t
+grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ struct grub_ata *ata;
+ const char *diskname;
+
+ /* Check command line. */
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+
+ if (args[0][0] == '(')
+ {
+ grub_size_t len = grub_strlen (args[0]);
+ if (args[0][len - 1] == ')')
+ args[0][len - 1] = 0;
+ diskname = &args[0][1];
+ }
+ else
+ diskname = &args[0][0];
+
+ int i = 0;
+ int apm = get_int_arg (&state[i++]);
+ int power = state[i++].set;
+ int sec_freeze = state[i++].set;
+ int health = state[i++].set;
+ int aam = get_int_arg (&state[i++]);
+ int standby_tout = get_int_arg (&state[i++]);
+ int standby_now = state[i++].set;
+ int sleep_now = state[i++].set;
+ int ident = state[i++].set;
+ int dumpid = state[i++].set;
+ int enable_smart = get_int_arg (&state[i++]);
+ quiet = state[i++].set;
+
+ /* Open disk. */
+ grub_disk_t disk = grub_disk_open (diskname);
+ if (! disk)
+ return grub_errno;
+
+ switch (disk->dev->id)
+ {
+ case GRUB_DISK_DEVICE_ATA_ID:
+ ata = disk->data;
+ break;
+ case GRUB_DISK_DEVICE_SCSI_ID:
+ if (((disk->id >> GRUB_SCSI_ID_SUBSYSTEM_SHIFT) & 0xFF)
+ == GRUB_SCSI_SUBSYSTEM_PATA
+ || (((disk->id >> GRUB_SCSI_ID_SUBSYSTEM_SHIFT) & 0xFF)
+ == GRUB_SCSI_SUBSYSTEM_AHCI))
+ {
+ ata = ((struct grub_scsi *) disk->data)->data;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ grub_disk_close (disk);
+ return grub_error (GRUB_ERR_IO, "not an ATA device");
+ }
+
+
+ /* Change settings. */
+ if (aam >= 0)
+ grub_hdparm_set_val_cmd ("Automatic Acoustic Management", (aam ? aam : -1),
+ ata, GRUB_ATA_CMD_SET_FEATURES,
+ (aam ? 0x42 : 0xc2), aam);
+
+ if (apm >= 0)
+ grub_hdparm_set_val_cmd ("Advanced Power Management",
+ (apm != 255 ? apm : -1), ata,
+ GRUB_ATA_CMD_SET_FEATURES,
+ (apm != 255 ? 0x05 : 0x85),
+ (apm != 255 ? apm : 0));
+
+ if (standby_tout >= 0)
+ {
+ if (! quiet)
+ {
+ grub_printf ("Set standby timeout to %d (", standby_tout);
+ grub_hdparm_print_standby_tout (standby_tout);
+ grub_printf (")");
+ }
+ /* The IDLE cmd sets disk to idle mode and configures standby timer. */
+ grub_hdparm_set_val_cmd ("", -1, ata, GRUB_ATA_CMD_IDLE, 0, standby_tout);
+ }
+
+ if (enable_smart >= 0)
+ {
+ if (! quiet)
+ grub_printf ("%sable SMART operations", (enable_smart ? "En" : "Dis"));
+ int err = grub_hdparm_do_smart_cmd (ata, (enable_smart ?
+ GRUB_ATA_FEAT_SMART_ENABLE : GRUB_ATA_FEAT_SMART_DISABLE));
+ if (! quiet)
+ grub_printf ("%s\n", err ? ": not supported" : "");
+ }
+
+ if (sec_freeze)
+ grub_hdparm_simple_cmd ("Freeze security settings", ata,
+ GRUB_ATA_CMD_SECURITY_FREEZE_LOCK);
+
+ /* Print/dump IDENTIFY. */
+ if (ident || dumpid)
+ {
+ grub_uint16_t buf[GRUB_DISK_SECTOR_SIZE / 2];
+ if (grub_hdparm_do_ata_cmd (ata, GRUB_ATA_CMD_IDENTIFY_DEVICE,
+ 0, 0, buf, sizeof (buf)))
+ grub_printf ("Cannot read ATA IDENTIFY data\n");
+ else
+ {
+ if (ident)
+ grub_hdparm_print_identify (buf);
+ if (dumpid)
+ hexdump (0, (char *) buf, sizeof (buf));
+ }
+ }
+
+ /* Check power mode. */
+ if (power)
+ {
+ grub_printf ("Disk power mode is: ");
+ int mode = grub_hdparm_do_check_powermode_cmd (ata);
+ if (mode < 0)
+ grub_printf ("unknown\n");
+ else
+ grub_printf ("%s (0x%02x)\n",
+ (mode == 0xff ? "active/idle" :
+ mode == 0x80 ? "idle" :
+ mode == 0x00 ? "standby" : "unknown"), mode);
+ }
+
+ /* Check health. */
+ int status = 0;
+ if (health)
+ {
+ if (! quiet)
+ grub_printf ("SMART status is: ");
+ int err = grub_hdparm_do_smart_cmd (ata, GRUB_ATA_FEAT_SMART_STATUS);
+ if (! quiet)
+ grub_printf ("%s\n", (err < 0 ? "unknown" :
+ err == 0 ? "OK" : "*BAD*"));
+ status = (err > 0);
+ }
+
+ /* Change power mode. */
+ if (standby_now)
+ grub_hdparm_simple_cmd ("Set disk to standby mode", ata,
+ GRUB_ATA_CMD_STANDBY_IMMEDIATE);
+
+ if (sleep_now)
+ grub_hdparm_simple_cmd ("Set disk to sleep mode", ata,
+ GRUB_ATA_CMD_SLEEP);
+
+ grub_disk_close (disk);
+
+ grub_errno = GRUB_ERR_NONE;
+ return status;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(hdparm)
+{
+ cmd = grub_register_extcmd_lockdown ("hdparm", grub_cmd_hdparm, 0,
+ N_("[OPTIONS] DISK"),
+ N_("Get/set ATA disk parameters."), options);
+}
+
+GRUB_MOD_FINI(hdparm)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/help.c b/grub-core/commands/help.c
new file mode 100644
index 0000000..f0be89b
--- /dev/null
+++ b/grub-core/commands/help.c
@@ -0,0 +1,153 @@
+/* help.c - command to show a help text. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2007,2008,2009 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/misc.h>
+#include <grub/term.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+#include <grub/mm.h>
+#include <grub/normal.h>
+#include <grub/charset.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+grub_cmd_help (grub_extcmd_context_t ctxt __attribute__ ((unused)), int argc,
+ char **args)
+{
+ int cnt = 0;
+ char *currarg;
+
+ if (argc == 0)
+ {
+ grub_command_t cmd;
+ FOR_COMMANDS(cmd)
+ {
+ if ((cmd->prio & GRUB_COMMAND_FLAG_ACTIVE))
+ {
+ struct grub_term_output *term;
+ const char *summary_translated = _(cmd->summary);
+ char *command_help;
+ grub_uint32_t *unicode_command_help;
+ grub_uint32_t *unicode_last_position;
+
+ command_help = grub_xasprintf ("%s %s", cmd->name, summary_translated);
+ if (!command_help)
+ break;
+
+ grub_utf8_to_ucs4_alloc (command_help, &unicode_command_help,
+ &unicode_last_position);
+
+ FOR_ACTIVE_TERM_OUTPUTS(term)
+ {
+ unsigned stringwidth;
+ grub_uint32_t *unicode_last_screen_position;
+
+ unicode_last_screen_position = unicode_command_help;
+
+ stringwidth = 0;
+
+ while (unicode_last_screen_position < unicode_last_position &&
+ stringwidth < ((grub_term_width (term) / 2) - 2))
+ {
+ struct grub_unicode_glyph glyph;
+ unicode_last_screen_position
+ += grub_unicode_aglomerate_comb (unicode_last_screen_position,
+ unicode_last_position
+ - unicode_last_screen_position,
+ &glyph);
+
+ stringwidth
+ += grub_term_getcharwidth (term, &glyph);
+ }
+
+ grub_print_ucs4 (unicode_command_help,
+ unicode_last_screen_position, 0, 0, term);
+ if (!(cnt % 2))
+ grub_print_spaces (term, grub_term_width (term) / 2
+ - stringwidth);
+ }
+
+ if (cnt % 2)
+ grub_printf ("\n");
+ cnt++;
+
+ grub_free (command_help);
+ grub_free (unicode_command_help);
+ }
+ }
+ if (!(cnt % 2))
+ grub_printf ("\n");
+ }
+ else
+ {
+ int i;
+ grub_command_t cmd_iter, cmd, cmd_next;
+
+ for (i = 0; i < argc; i++)
+ {
+ currarg = args[i];
+
+ FOR_COMMANDS_SAFE (cmd_iter, cmd_next)
+ {
+ if (!(cmd_iter->prio & GRUB_COMMAND_FLAG_ACTIVE))
+ continue;
+
+ if (grub_strncmp (cmd_iter->name, currarg,
+ grub_strlen (currarg)) != 0)
+ continue;
+ if (cmd_iter->flags & GRUB_COMMAND_FLAG_DYNCMD)
+ cmd = grub_dyncmd_get_cmd (cmd_iter);
+ else
+ cmd = cmd_iter;
+ if (!cmd)
+ {
+ grub_print_error ();
+ continue;
+ }
+ if (cnt++ > 0)
+ grub_printf ("\n\n");
+
+ if ((cmd->flags & GRUB_COMMAND_FLAG_EXTCMD) &&
+ ! (cmd->flags & GRUB_COMMAND_FLAG_DYNCMD))
+ grub_arg_show_help ((grub_extcmd_t) cmd->data);
+ else
+ grub_printf ("%s %s %s\n%s\n", _("Usage:"), cmd->name,
+ _(cmd->summary), _(cmd->description));
+ }
+ }
+ }
+
+ return 0;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(help)
+{
+ cmd = grub_register_extcmd ("help", grub_cmd_help, 0,
+ N_("[PATTERN ...]"),
+ N_("Show a help message."), 0);
+}
+
+GRUB_MOD_FINI(help)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/hexdump.c b/grub-core/commands/hexdump.c
new file mode 100644
index 0000000..eaa1246
--- /dev/null
+++ b/grub-core/commands/hexdump.c
@@ -0,0 +1,133 @@
+/* hexdump.c - command to dump the contents of a file or memory */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2007,2008,2009 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/file.h>
+#include <grub/disk.h>
+#include <grub/misc.h>
+#include <grub/lib/hexdump.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] = {
+ {"skip", 's', 0, N_("Skip offset bytes from the beginning of file."), 0,
+ ARG_TYPE_INT},
+ {"length", 'n', 0, N_("Read only LENGTH bytes."), 0, ARG_TYPE_INT},
+ {0, 0, 0, 0, 0, 0}
+};
+
+static grub_err_t
+grub_cmd_hexdump (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ char buf[GRUB_DISK_SECTOR_SIZE * 4];
+ grub_ssize_t size, length;
+ grub_disk_addr_t skip;
+ int namelen;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ namelen = grub_strlen (args[0]);
+ skip = (state[0].set) ? grub_strtoull (state[0].arg, 0, 0) : 0;
+ length = (state[1].set) ? grub_strtoul (state[1].arg, 0, 0) : 256;
+
+ if (!grub_strcmp (args[0], "(mem)"))
+ hexdump (skip, (char *) (grub_addr_t) skip, length);
+ else if ((args[0][0] == '(') && (args[0][namelen - 1] == ')'))
+ {
+ grub_disk_t disk;
+ grub_disk_addr_t sector;
+ grub_size_t ofs;
+
+ args[0][namelen - 1] = 0;
+ disk = grub_disk_open (&args[0][1]);
+ if (! disk)
+ return 0;
+
+ sector = (skip >> (GRUB_DISK_SECTOR_BITS + 2)) * 4;
+ ofs = skip & (GRUB_DISK_SECTOR_SIZE * 4 - 1);
+ while (length)
+ {
+ grub_size_t len;
+
+ len = length;
+ if (len > sizeof (buf))
+ len = sizeof (buf);
+
+ if (grub_disk_read (disk, sector, ofs, len, buf))
+ break;
+
+ hexdump (skip, buf, len);
+
+ ofs = 0;
+ skip += len;
+ length -= len;
+ sector += 4;
+ }
+
+ grub_disk_close (disk);
+ }
+ else
+ {
+ grub_file_t file;
+
+ file = grub_file_open (args[0], GRUB_FILE_TYPE_HEXCAT);
+ if (! file)
+ return 0;
+
+ file->offset = skip;
+
+ while ((size = grub_file_read (file, buf, sizeof (buf))) > 0)
+ {
+ unsigned long len;
+
+ len = ((length) && (size > length)) ? length : size;
+ hexdump (skip, buf, len);
+ skip += len;
+ if (length)
+ {
+ length -= len;
+ if (!length)
+ break;
+ }
+ }
+
+ grub_file_close (file);
+ }
+
+ return 0;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT (hexdump)
+{
+ cmd = grub_register_extcmd ("hexdump", grub_cmd_hexdump, 0,
+ N_("[OPTIONS] FILE_OR_DEVICE"),
+ N_("Show raw contents of a file or memory."),
+ options);
+}
+
+GRUB_MOD_FINI (hexdump)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/i386/cmosdump.c b/grub-core/commands/i386/cmosdump.c
new file mode 100644
index 0000000..626485c
--- /dev/null
+++ b/grub-core/commands/i386/cmosdump.c
@@ -0,0 +1,64 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009,2013 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/command.h>
+#include <grub/misc.h>
+#include <grub/cmos.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+grub_cmd_cmosdump (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)), char *argv[] __attribute__ ((unused)))
+{
+ int i;
+
+ for (i = 0; i < 256; i++)
+ {
+ grub_err_t err;
+ grub_uint8_t value;
+ if ((i & 0xf) == 0)
+ grub_printf ("%02x: ", i);
+
+ err = grub_cmos_read (i, &value);
+ if (err)
+ return err;
+
+ grub_printf ("%02x ", value);
+ if ((i & 0xf) == 0xf)
+ grub_printf ("\n");
+ }
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd;
+
+
+GRUB_MOD_INIT(cmosdump)
+{
+ cmd = grub_register_command ("cmosdump", grub_cmd_cmosdump,
+ 0,
+ N_("Show raw dump of the CMOS contents."));
+}
+
+GRUB_MOD_FINI(cmosdump)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/i386/cmostest.c b/grub-core/commands/i386/cmostest.c
new file mode 100644
index 0000000..9f6b56a
--- /dev/null
+++ b/grub-core/commands/i386/cmostest.c
@@ -0,0 +1,124 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/command.h>
+#include <grub/misc.h>
+#include <grub/cmos.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+parse_args (int argc, char *argv[], int *byte, int *bit)
+{
+ const char *rest;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "address required");
+
+ *byte = grub_strtoul (argv[0], &rest, 0);
+ if (*rest != ':')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "address required");
+
+ *bit = grub_strtoul (rest + 1, 0, 0);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_cmostest (struct grub_command *cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ int byte = 0, bit = 0;
+ grub_err_t err;
+ grub_uint8_t value;
+
+ err = parse_args (argc, argv, &byte, &bit);
+ if (err)
+ return err;
+
+ err = grub_cmos_read (byte, &value);
+ if (err)
+ return err;
+
+ if (value & (1 << bit))
+ return GRUB_ERR_NONE;
+
+ return grub_error (GRUB_ERR_TEST_FAILURE, N_("false"));
+}
+
+static grub_err_t
+grub_cmd_cmosclean (struct grub_command *cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ int byte = 0, bit = 0;
+ grub_err_t err;
+ grub_uint8_t value;
+
+ err = parse_args (argc, argv, &byte, &bit);
+ if (err)
+ return err;
+ err = grub_cmos_read (byte, &value);
+ if (err)
+ return err;
+
+ return grub_cmos_write (byte, value & (~(1 << bit)));
+}
+
+static grub_err_t
+grub_cmd_cmosset (struct grub_command *cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ int byte = 0, bit = 0;
+ grub_err_t err;
+ grub_uint8_t value;
+
+ err = parse_args (argc, argv, &byte, &bit);
+ if (err)
+ return err;
+ err = grub_cmos_read (byte, &value);
+ if (err)
+ return err;
+
+ return grub_cmos_write (byte, value | (1 << bit));
+}
+
+static grub_command_t cmd, cmd_clean, cmd_set;
+
+
+GRUB_MOD_INIT(cmostest)
+{
+ cmd = grub_register_command ("cmostest", grub_cmd_cmostest,
+ N_("BYTE:BIT"),
+ N_("Test bit at BYTE:BIT in CMOS."));
+ cmd_clean = grub_register_command ("cmosclean", grub_cmd_cmosclean,
+ N_("BYTE:BIT"),
+ N_("Clear bit at BYTE:BIT in CMOS."));
+ cmd_set = grub_register_command ("cmosset", grub_cmd_cmosset,
+ N_("BYTE:BIT"),
+ /* TRANSLATORS: A bit may be either set (1) or clear (0). */
+ N_("Set bit at BYTE:BIT in CMOS."));
+}
+
+GRUB_MOD_FINI(cmostest)
+{
+ grub_unregister_command (cmd);
+ grub_unregister_command (cmd_clean);
+ grub_unregister_command (cmd_set);
+}
diff --git a/grub-core/commands/i386/coreboot/cb_timestamps.c b/grub-core/commands/i386/coreboot/cb_timestamps.c
new file mode 100644
index 0000000..e97ea6b
--- /dev/null
+++ b/grub-core/commands/i386/coreboot/cb_timestamps.c
@@ -0,0 +1,126 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/misc.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/coreboot/lbio.h>
+#include <grub/i386/tsc.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_uint32_t
+tsc2ms (grub_uint64_t tsc)
+{
+ grub_uint64_t ah = tsc >> 32;
+ grub_uint64_t al = tsc & 0xffffffff;
+
+ return ((al * grub_tsc_rate) >> 32) + ah * grub_tsc_rate;
+}
+
+static const char *descs[] = {
+ [1] = "romstage",
+ [2] = "before RAM init",
+ [3] = "after RAM init",
+ [4] = "end of romstage",
+ [5] = "start of verified boot",
+ [6] = "end of verified boot",
+ [8] = "start of RAM copy",
+ [9] = "end of RAM copy",
+ [10] = "start of ramstage",
+ [11] = "start of bootblock",
+ [12] = "end of bootblock",
+ [13] = "starting to load romstage",
+ [14] = "finished loading romstage",
+ [15] = "starting LZMA decompress (ignore for x86)",
+ [16] = "finished LZMA decompress (ignore for x86)",
+ [30] = "device enumerate",
+ [40] = "device configure",
+ [50] = "device enable",
+ [60] = "device initialize",
+ [70] = "device done",
+ [75] = "CBMEM POST",
+ [80] = "writing tables",
+ [90] = "loading payload",
+ [98] = "wake jump",
+ [99] = "selfboot jump",
+};
+
+static int
+iterate_linuxbios_table (grub_linuxbios_table_item_t table_item,
+ void *data)
+{
+ int *available = data;
+ grub_uint64_t last_tsc = 0;
+ struct grub_linuxbios_timestamp_table *ts_table;
+ unsigned i;
+
+ if (table_item->tag != GRUB_LINUXBIOS_MEMBER_TIMESTAMPS)
+ return 0;
+
+ *available = 1;
+ ts_table = (struct grub_linuxbios_timestamp_table *) (grub_addr_t)
+ *(grub_uint64_t *) (table_item + 1);
+
+ for (i = 0; i < ts_table->used; i++)
+ {
+ grub_uint32_t tmabs = tsc2ms (ts_table->entries[i].tsc);
+ grub_uint32_t tmrel = tsc2ms (ts_table->entries[i].tsc - last_tsc);
+ last_tsc = ts_table->entries[i].tsc;
+
+ grub_printf ("%3d.%03ds %2d.%03ds %02d %s\n",
+ tmabs / 1000, tmabs % 1000, tmrel / 1000, tmrel % 1000,
+ ts_table->entries[i].id,
+ (ts_table->entries[i].id < ARRAY_SIZE (descs)
+ && descs[ts_table->entries[i].id])
+ ? descs[ts_table->entries[i].id] : "");
+ }
+ return 1;
+}
+
+
+static grub_err_t
+grub_cmd_coreboot_boottime (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ int available = 0;
+
+ grub_linuxbios_table_iterate (iterate_linuxbios_table, &available);
+ if (!available)
+ {
+ grub_puts_ (N_("No boot time statistics is available\n"));
+ return 0;
+ }
+ return 0;
+}
+
+static grub_command_t cmd_boottime;
+
+GRUB_MOD_INIT(cbtime)
+{
+ cmd_boottime =
+ grub_register_command ("coreboot_boottime", grub_cmd_coreboot_boottime,
+ 0, N_("Show coreboot boot time statistics."));
+}
+
+GRUB_MOD_FINI(cbtime)
+{
+ grub_unregister_command (cmd_boottime);
+}
diff --git a/grub-core/commands/i386/coreboot/cbls.c b/grub-core/commands/i386/coreboot/cbls.c
new file mode 100644
index 0000000..102291f
--- /dev/null
+++ b/grub-core/commands/i386/coreboot/cbls.c
@@ -0,0 +1,143 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/misc.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/coreboot/lbio.h>
+#include <grub/i386/tsc.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const char *console_descs[] = {
+ "8250 UART",
+ "VGA",
+ "BTEXT",
+ "log buffer console",
+ "SROM",
+ "EHCI debug",
+ "memory-mapped 8250 UART"
+};
+
+static const char *descs[] = {
+ [GRUB_LINUXBIOS_MEMBER_MEMORY] = "memory map (`lsmmap' to list)",
+ [GRUB_LINUXBIOS_MEMBER_MAINBOARD] = "mainboard",
+ [4] = "version",
+ [5] = "extra version",
+ [6] = "build",
+ [7] = "compile time",
+ [8] = "compile by",
+ [9] = "compile host",
+ [0xa] = "compile domain",
+ [0xb] = "compiler",
+ [0xc] = "linker",
+ [0xd] = "assembler",
+ [0xf] = "serial",
+ [GRUB_LINUXBIOS_MEMBER_CONSOLE] = "console",
+ [GRUB_LINUXBIOS_MEMBER_FRAMEBUFFER] = "framebuffer",
+ [0x13] = "GPIO",
+ [0x15] = "VDAT",
+ [GRUB_LINUXBIOS_MEMBER_TIMESTAMPS] = "timestamps (`coreboot_boottime' to list)",
+ [GRUB_LINUXBIOS_MEMBER_CBMEMC] = "CBMEM console (`cbmemc' to list)",
+ [0x18] = "MRC cache",
+ [0x19] = "VBNV",
+ [0xc8] = "CMOS option table",
+ [0xc9] = "CMOS option",
+ [0xca] = "CMOS option enum",
+ [0xcb] = "CMOS option defaults",
+ [0xcc] = "CMOS checksum",
+};
+
+static int
+iterate_linuxbios_table (grub_linuxbios_table_item_t table_item,
+ void *data __attribute__ ((unused)))
+{
+ if (table_item->tag < ARRAY_SIZE (descs) && descs[table_item->tag])
+ grub_printf ("tag=%02x size=%02x %s",
+ table_item->tag, table_item->size, descs[table_item->tag]);
+ else
+ grub_printf ("tag=%02x size=%02x",
+ table_item->tag, table_item->size);
+
+ switch (table_item->tag)
+ {
+ case GRUB_LINUXBIOS_MEMBER_FRAMEBUFFER:
+ {
+ struct grub_linuxbios_table_framebuffer *fb;
+ fb = (struct grub_linuxbios_table_framebuffer *) (table_item + 1);
+
+ grub_printf (": %dx%dx%d pitch=%d lfb=0x%llx %d/%d/%d/%d %d/%d/%d/%d",
+ fb->width, fb->height,
+ fb->bpp, fb->pitch,
+ (unsigned long long) fb->lfb,
+ fb->red_mask_size, fb->green_mask_size,
+ fb->blue_mask_size, fb->reserved_mask_size,
+ fb->red_field_pos, fb->green_field_pos,
+ fb->blue_field_pos, fb->reserved_field_pos);
+ break;
+ }
+ case GRUB_LINUXBIOS_MEMBER_MAINBOARD:
+ {
+ struct grub_linuxbios_mainboard *mb;
+ mb = (struct grub_linuxbios_mainboard *) (table_item + 1);
+ grub_printf (": vendor=`%s' part_number=`%s'",
+ mb->strings + mb->vendor,
+ mb->strings + mb->part_number);
+ break;
+ }
+ case 0x04 ... 0x0d:
+ grub_printf (": `%s'", (char *) (table_item + 1));
+ break;
+ case GRUB_LINUXBIOS_MEMBER_CONSOLE:
+ {
+ grub_uint16_t *val = (grub_uint16_t *) (table_item + 1);
+ grub_printf (": id=%d", *val);
+ if (*val < ARRAY_SIZE (console_descs)
+ && console_descs[*val])
+ grub_printf (" %s", console_descs[*val]);
+ }
+ }
+ grub_printf ("\n");
+
+ return 0;
+}
+
+
+static grub_err_t
+grub_cmd_lscoreboot (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ grub_linuxbios_table_iterate (iterate_linuxbios_table, 0);
+ return 0;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(cbls)
+{
+ cmd =
+ grub_register_command ("lscoreboot", grub_cmd_lscoreboot,
+ 0, N_("List coreboot tables."));
+}
+
+GRUB_MOD_FINI(cbls)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/i386/cpuid.c b/grub-core/commands/i386/cpuid.c
new file mode 100644
index 0000000..42b9841
--- /dev/null
+++ b/grub-core/commands/i386/cpuid.c
@@ -0,0 +1,125 @@
+/* cpuid.c - test for CPU features */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006, 2007, 2009 Free Software Foundation, Inc.
+ * Based on gcc/gcc/config/i386/driver-i386.c
+ *
+ * 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/mm.h>
+#include <grub/env.h>
+#include <grub/command.h>
+#include <grub/extcmd.h>
+#include <grub/i386/cpuid.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =
+ {
+ /* TRANSLATORS: "(default)" at the end means that this option is used if
+ no argument is specified. */
+ {"long-mode", 'l', 0, N_("Check if CPU supports 64-bit (long) mode (default)."), 0, 0},
+ {"pae", 'p', 0, N_("Check if CPU supports Physical Address Extension."), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+enum
+ {
+ MODE_LM = 0,
+ MODE_PAE = 1
+ };
+
+enum
+ {
+ bit_PAE = (1 << 6),
+ };
+enum
+ {
+ bit_LM = (1 << 29)
+ };
+
+unsigned char grub_cpuid_has_longmode = 0, grub_cpuid_has_pae = 0;
+
+static grub_err_t
+grub_cmd_cpuid (grub_extcmd_context_t ctxt,
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ int val = 0;
+ if (ctxt->state[MODE_PAE].set)
+ val = grub_cpuid_has_pae;
+ else
+ val = grub_cpuid_has_longmode;
+ return val ? GRUB_ERR_NONE
+ /* TRANSLATORS: it's a standalone boolean value,
+ opposite of "true". */
+ : grub_error (GRUB_ERR_TEST_FAILURE, N_("false"));
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(cpuid)
+{
+#ifdef __x86_64__
+ /* grub-emu */
+ grub_cpuid_has_longmode = 1;
+ grub_cpuid_has_pae = 1;
+#else
+ unsigned int eax, ebx, ecx, edx;
+ unsigned int max_level;
+ unsigned int ext_level;
+
+ /* See if we can use cpuid. */
+ asm volatile ("pushfl; pushfl; popl %0; movl %0,%1; xorl %2,%0;"
+ "pushl %0; popfl; pushfl; popl %0; popfl"
+ : "=&r" (eax), "=&r" (ebx)
+ : "i" (0x00200000));
+ if (((eax ^ ebx) & 0x00200000) == 0)
+ goto done;
+
+ /* Check the highest input value for eax. */
+ grub_cpuid (0, eax, ebx, ecx, edx);
+ /* We only look at the first four characters. */
+ max_level = eax;
+ if (max_level == 0)
+ goto done;
+
+ if (max_level >= 1)
+ {
+ grub_cpuid (1, eax, ebx, ecx, edx);
+ grub_cpuid_has_pae = !!(edx & bit_PAE);
+ }
+
+ grub_cpuid (0x80000000, eax, ebx, ecx, edx);
+ ext_level = eax;
+ if (ext_level < 0x80000000)
+ goto done;
+
+ grub_cpuid (0x80000001, eax, ebx, ecx, edx);
+ grub_cpuid_has_longmode = !!(edx & bit_LM);
+done:
+#endif
+
+ cmd = grub_register_extcmd ("cpuid", grub_cmd_cpuid, 0,
+ "[-l]", N_("Check for CPU features."), options);
+}
+
+GRUB_MOD_FINI(cpuid)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/i386/pc/drivemap.c b/grub-core/commands/i386/pc/drivemap.c
new file mode 100644
index 0000000..7f7f2d4
--- /dev/null
+++ b/grub-core/commands/i386/pc/drivemap.c
@@ -0,0 +1,428 @@
+/* drivemap.c - command to manage the BIOS drive mappings. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008, 2009 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/extcmd.h>
+#include <grub/dl.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/disk.h>
+#include <grub/loader.h>
+#include <grub/env.h>
+#include <grub/machine/biosnum.h>
+#include <grub/i18n.h>
+#include <grub/memory.h>
+#include <grub/machine/memory.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* Real mode IVT slot (seg:off far pointer) for interrupt 0x13. */
+static grub_uint32_t *const int13slot = (grub_uint32_t *) (4 * 0x13);
+
+/* Remember to update enum opt_idxs accordingly. */
+static const struct grub_arg_option options[] = {
+ /* TRANSLATORS: In this file "mapping" refers to a change GRUB makes so if
+ your language doesn't have an equivalent of "mapping" you can
+ use the word like "rerouting".
+ */
+ {"list", 'l', 0, N_("Show the current mappings."), 0, 0},
+ {"reset", 'r', 0, N_("Reset all mappings to the default values."), 0, 0},
+ {"swap", 's', 0, N_("Perform both direct and reverse mappings."), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+};
+
+/* Remember to update options[] accordingly. */
+enum opt_idxs
+{
+ OPTIDX_LIST = 0,
+ OPTIDX_RESET,
+ OPTIDX_SWAP,
+};
+
+/* Realmode far ptr (2 * 16b) to the previous INT13h handler. */
+extern grub_uint32_t grub_drivemap_oldhandler;
+
+/* The type "void" is used for imported assembly labels, takes no storage and
+ serves just to take the address with &label. */
+
+/* The assembly function to replace the old INT13h handler. It does not follow
+ any C callspecs and returns with IRET. */
+extern const void grub_drivemap_handler;
+
+/* Start of the drive mappings area (space reserved at runtime). */
+extern const void grub_drivemap_mapstart;
+
+typedef struct drivemap_node
+{
+ struct drivemap_node *next;
+ grub_uint8_t newdrive;
+ grub_uint8_t redirto;
+} drivemap_node_t;
+
+typedef struct GRUB_PACKED int13map_node
+{
+ grub_uint8_t disknum;
+ grub_uint8_t mapto;
+} int13map_node_t;
+
+#define INT13H_OFFSET(x) \
+ (((grub_uint8_t *)(x)) - ((grub_uint8_t *)&grub_drivemap_handler))
+
+static drivemap_node_t *map_head;
+static void *drivemap_hook;
+static int drivemap_mmap;
+
+/* Puts the specified mapping into the table, replacing an existing mapping
+ for newdrive or adding a new one if required. */
+static grub_err_t
+drivemap_set (grub_uint8_t newdrive, grub_uint8_t redirto)
+{
+ drivemap_node_t *mapping = 0;
+ drivemap_node_t *search = map_head;
+ while (search)
+ {
+ if (search->newdrive == newdrive)
+ {
+ mapping = search;
+ break;
+ }
+ search = search->next;
+ }
+
+ /* Check for pre-existing mappings to modify before creating a new one. */
+ if (mapping)
+ mapping->redirto = redirto;
+ else
+ {
+ mapping = grub_malloc (sizeof (drivemap_node_t));
+ if (! mapping)
+ return grub_errno;
+ mapping->newdrive = newdrive;
+ mapping->redirto = redirto;
+ mapping->next = map_head;
+ map_head = mapping;
+ }
+ return GRUB_ERR_NONE;
+}
+
+/* Removes the mapping for newdrive from the table. If there is no mapping,
+ then this function behaves like a no-op on the map. */
+static void
+drivemap_remove (grub_uint8_t newdrive)
+{
+ drivemap_node_t *mapping = 0;
+ drivemap_node_t *search = map_head;
+ drivemap_node_t *previous = 0;
+
+ while (search)
+ {
+ if (search->newdrive == newdrive)
+ {
+ mapping = search;
+ break;
+ }
+ previous = search;
+ search = search->next;
+ }
+
+ if (mapping)
+ {
+ if (previous)
+ previous->next = mapping->next;
+ else
+ map_head = mapping->next;
+ grub_free (mapping);
+ }
+}
+
+/* Given a GRUB-like device name and a convenient location, stores the
+ related BIOS disk number. Accepts devices like \((f|h)dN\), with
+ 0 <= N < 128. */
+static grub_err_t
+tryparse_diskstring (const char *str, grub_uint8_t *output)
+{
+ /* Skip opening paren in order to allow both (hd0) and hd0. */
+ if (*str == '(')
+ str++;
+ if ((str[0] == 'f' || str[0] == 'h') && str[1] == 'd')
+ {
+ grub_uint8_t bios_num = (str[0] == 'h') ? 0x80 : 0x00;
+ unsigned long drivenum = grub_strtoul (str + 2, 0, 0);
+ if (grub_errno == GRUB_ERR_NONE && drivenum < 128)
+ {
+ bios_num |= drivenum;
+ if (output)
+ *output = bios_num;
+ return GRUB_ERR_NONE;
+ }
+ }
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device format \"%s\" "
+ "invalid: must be (f|h)dN, with 0 <= N < 128", str);
+}
+
+static grub_err_t
+list_mappings (void)
+{
+ /* Show: list mappings. */
+ if (! map_head)
+ {
+ grub_puts_ (N_("No drives have been remapped"));
+ return GRUB_ERR_NONE;
+ }
+
+ /* TRANSLATORS: This is the header of mapping list.
+ On the left is how OS will see the disks and
+ on the right current GRUB vision. */
+ grub_puts_ (N_("OS disk #num ------> GRUB/BIOS device"));
+ drivemap_node_t *curnode = map_head;
+ while (curnode)
+ {
+ grub_printf ("%cD #%-3u (0x%02x) %cd%d\n",
+ (curnode->newdrive & 0x80) ? 'H' : 'F',
+ curnode->newdrive & 0x7F, curnode->newdrive,
+ (curnode->redirto & 0x80) ? 'h' : 'f',
+ curnode->redirto & 0x7F
+ );
+ curnode = curnode->next;
+ }
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_drivemap (struct grub_extcmd_context *ctxt, int argc, char **args)
+{
+ if (ctxt->state[OPTIDX_LIST].set)
+ {
+ return list_mappings ();
+ }
+ else if (ctxt->state[OPTIDX_RESET].set)
+ {
+ /* Reset: just delete all mappings, freeing their memory. */
+ drivemap_node_t *curnode = map_head;
+ drivemap_node_t *prevnode = 0;
+ while (curnode)
+ {
+ prevnode = curnode;
+ curnode = curnode->next;
+ grub_free (prevnode);
+ }
+ map_head = 0;
+ return GRUB_ERR_NONE;
+ }
+ else if (!ctxt->state[OPTIDX_SWAP].set && argc == 0)
+ {
+ /* No arguments */
+ return list_mappings ();
+ }
+
+ /* Neither flag: put mapping. */
+ grub_uint8_t mapfrom = 0;
+ grub_uint8_t mapto = 0xFF;
+ grub_err_t err;
+
+ if (argc != 2)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
+
+ err = tryparse_diskstring (args[0], &mapfrom);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ err = tryparse_diskstring (args[1], &mapto);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ if (mapto == mapfrom)
+ {
+ /* Reset to default. */
+ grub_dprintf ("drivemap", "Removing mapping for %s (%02x)\n",
+ args[0], mapfrom);
+ drivemap_remove (mapfrom);
+ return GRUB_ERR_NONE;
+ }
+ /* Set the mapping for the disk (overwrites any existing mapping). */
+ grub_dprintf ("drivemap", "%s %s (%02x) = %s (%02x)\n",
+ ctxt->state[OPTIDX_SWAP].set ? "Swapping" : "Mapping",
+ args[1], mapto, args[0], mapfrom);
+ err = drivemap_set (mapto, mapfrom);
+ /* If -s, perform the reverse mapping too (only if the first was OK). */
+ if (ctxt->state[OPTIDX_SWAP].set && err == GRUB_ERR_NONE)
+ err = drivemap_set (mapfrom, mapto);
+ return err;
+}
+
+/* Int13h handler installer - reserves conventional memory for the handler,
+ copies it over and sets the IVT entry for int13h.
+ This code rests on the assumption that GRUB does not activate any kind
+ of memory mapping apart from identity paging, since it accesses
+ realmode structures by their absolute addresses, like the IVT at 0;
+ and transforms a pmode pointer into a rmode seg:off far ptr. */
+static grub_err_t
+install_int13_handler (int noret __attribute__ ((unused)))
+{
+ /* Size of the full int13 handler "bundle", including code and map. */
+ grub_uint32_t total_size;
+ /* Base address of the space reserved for the handler bundle. */
+ grub_uint8_t *handler_base = 0;
+ /* Address of the map within the deployed bundle. */
+ int13map_node_t *handler_map;
+
+ int i;
+ int entries = 0;
+ drivemap_node_t *curentry = map_head;
+
+ /* Count entries to prepare a contiguous map block. */
+ while (curentry)
+ {
+ entries++;
+ curentry = curentry->next;
+ }
+ if (entries == 0)
+ {
+ /* No need to install the int13h handler. */
+ grub_dprintf ("drivemap", "No drives marked as remapped, not installing "
+ "our int13h handler.\n");
+ return GRUB_ERR_NONE;
+ }
+
+ grub_dprintf ("drivemap", "Installing our int13h handler\n");
+
+ /* Save the pointer to the old handler. */
+ grub_drivemap_oldhandler = *int13slot;
+ grub_dprintf ("drivemap", "Original int13 handler: %04x:%04x\n",
+ (grub_drivemap_oldhandler >> 16) & 0x0ffff,
+ grub_drivemap_oldhandler & 0x0ffff);
+
+ /* Find a rmode-segment-aligned zone in conventional memory big
+ enough to hold the handler and its data. */
+ total_size = INT13H_OFFSET (&grub_drivemap_mapstart)
+ + (entries + 1) * sizeof (int13map_node_t);
+ grub_dprintf ("drivemap", "Payload is %u bytes long\n", total_size);
+ handler_base = grub_mmap_malign_and_register (16, ALIGN_UP (total_size, 16),
+ &drivemap_mmap,
+ GRUB_MEMORY_RESERVED,
+ GRUB_MMAP_MALLOC_LOW);
+ if (! handler_base)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't reserve "
+ "memory for the int13h handler");
+
+ /* Copy int13h handler bundle to reserved area. */
+ grub_dprintf ("drivemap", "Reserved memory at %p, copying handler\n",
+ handler_base);
+ grub_memcpy (handler_base, &grub_drivemap_handler,
+ INT13H_OFFSET (&grub_drivemap_mapstart));
+
+ /* Copy the mappings to the reserved area. */
+ curentry = map_head;
+ handler_map = (int13map_node_t *) (handler_base +
+ INT13H_OFFSET (&grub_drivemap_mapstart));
+ grub_dprintf ("drivemap", "Target map at %p, copying mappings\n", handler_map);
+ for (i = 0; i < entries; ++i, curentry = curentry->next)
+ {
+ handler_map[i].disknum = curentry->newdrive;
+ handler_map[i].mapto = curentry->redirto;
+ grub_dprintf ("drivemap", "\t#%d: 0x%02x <- 0x%02x\n", i,
+ handler_map[i].disknum, handler_map[i].mapto);
+ }
+ /* Signal end-of-map. */
+ handler_map[i].disknum = 0;
+ handler_map[i].mapto = 0;
+ grub_dprintf ("drivemap", "\t#%d: 0x00 <- 0x00 (end)\n", i);
+
+ /* Install our function as the int13h handler in the IVT. */
+ *int13slot = ((grub_uint32_t) handler_base) << 12; /* Segment address. */
+ grub_dprintf ("drivemap", "New int13 handler: %04x:%04x\n",
+ (*int13slot >> 16) & 0x0ffff, *int13slot & 0x0ffff);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+uninstall_int13_handler (void)
+{
+ if (! grub_drivemap_oldhandler)
+ return GRUB_ERR_NONE;
+
+ *int13slot = grub_drivemap_oldhandler;
+ grub_mmap_free_and_unregister (drivemap_mmap);
+ grub_drivemap_oldhandler = 0;
+ grub_dprintf ("drivemap", "Restored int13 handler: %04x:%04x\n",
+ (*int13slot >> 16) & 0x0ffff, *int13slot & 0x0ffff);
+
+ return GRUB_ERR_NONE;
+}
+
+static int
+grub_get_root_biosnumber_drivemap (void)
+{
+ const char *biosnum;
+ int ret = -1;
+ grub_device_t dev;
+
+ biosnum = grub_env_get ("biosnum");
+
+ if (biosnum)
+ return grub_strtoul (biosnum, 0, 0);
+
+ dev = grub_device_open (0);
+ if (dev && dev->disk && dev->disk->dev
+ && dev->disk->dev->id == GRUB_DISK_DEVICE_BIOSDISK_ID)
+ {
+ drivemap_node_t *curnode = map_head;
+ ret = (int) dev->disk->id;
+ while (curnode)
+ {
+ if (curnode->redirto == ret)
+ {
+ ret = curnode->newdrive;
+ break;
+ }
+ curnode = curnode->next;
+ }
+
+ }
+
+ if (dev)
+ grub_device_close (dev);
+
+ return ret;
+}
+
+static grub_extcmd_t cmd;
+static int (*grub_get_root_biosnumber_saved) (void);
+
+GRUB_MOD_INIT (drivemap)
+{
+ grub_get_root_biosnumber_saved = grub_get_root_biosnumber;
+ grub_get_root_biosnumber = grub_get_root_biosnumber_drivemap;
+ cmd = grub_register_extcmd ("drivemap", grub_cmd_drivemap, 0,
+ N_("-l | -r | [-s] grubdev osdisk."),
+ N_("Manage the BIOS drive mappings."),
+ options);
+ drivemap_hook =
+ grub_loader_register_preboot_hook (&install_int13_handler,
+ &uninstall_int13_handler,
+ GRUB_LOADER_PREBOOT_HOOK_PRIO_NORMAL);
+}
+
+GRUB_MOD_FINI (drivemap)
+{
+ grub_get_root_biosnumber = grub_get_root_biosnumber_saved;
+ grub_loader_unregister_preboot_hook (drivemap_hook);
+ drivemap_hook = 0;
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/i386/pc/drivemap_int13h.S b/grub-core/commands/i386/pc/drivemap_int13h.S
new file mode 100644
index 0000000..3c87521
--- /dev/null
+++ b/grub-core/commands/i386/pc/drivemap_int13h.S
@@ -0,0 +1,124 @@
+/* drivemap_int13h.S - interrupt handler for the BIOS drive remapper */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008, 2009 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/symbol.h>
+
+#define INT13H_OFFSET(x) ((x) - LOCAL (base))
+
+.code16
+
+/* Copy starts here. When deployed, this code must be segment-aligned. */
+
+/* The replacement int13 handler. Preserve all registers. */
+FUNCTION(grub_drivemap_handler)
+LOCAL (base):
+ /* Save %dx for future restore. */
+ push %dx
+ /* Push flags. Used to simulate interrupt with original flags. */
+ pushf
+
+ /* Map the drive number (always in DL). */
+ push %ax
+ push %bx
+#ifdef __APPLE__
+ LOCAL(mapstart_offset) = INT13H_OFFSET(LOCAL (mapstart))
+ movw $LOCAL(mapstart_offset), %bx
+#else
+ movw $INT13H_OFFSET(LOCAL (mapstart)), %bx
+#endif
+
+more_remaining:
+ movw %cs:(%bx), %ax
+ cmpb %ah, %al
+ jz not_found /* DRV=DST => map end - drive not remapped, keep DL. */
+ inc %bx
+ inc %bx
+ cmpb %dl, %al
+ jnz more_remaining /* Not found, but more remaining, loop. */
+ movb %ah, %dl /* Found - drive remapped, modify DL. */
+
+not_found:
+ pop %bx
+ pop %ax
+
+ /* If the call isn't ah=0x8 or ah=0x15 we must restore %dx. */
+ cmpb $0x8, %ah
+ jz norestore
+ cmpb $0x15, %ah
+ jz norestore
+
+ /* Restore flags. */
+ popf
+ pushf
+
+#ifdef __APPLE__
+ LOCAL(oldhandler_offset) = INT13H_OFFSET (LOCAL (oldhandler))
+ lcall *%cs:LOCAL(oldhandler_offset)
+#else
+ lcall *%cs:INT13H_OFFSET (LOCAL (oldhandler))
+#endif
+
+ push %bp
+ mov %sp, %bp
+
+tail:
+ /* Save new flags below %esp so the caller will recieve new flags. */
+ pushf
+ pop %dx
+ mov %dx, 8(%bp)
+
+ pop %bp
+
+ /* Restore %dx. */
+ pop %dx
+ iret
+
+norestore:
+
+ /* Restore flags. */
+ popf
+ pushf
+
+#ifdef __APPLE__
+ lcall *%cs:LOCAL(oldhandler_offset)
+#else
+ lcall *%cs:INT13H_OFFSET (LOCAL (oldhandler))
+#endif
+
+ push %bp
+ mov %sp, %bp
+
+ /* Save %dx. So it won't be restored to original value. */
+ mov %dx, 2(%bp)
+
+ jmp tail
+
+/* Far pointer to the old handler. Stored as a CS:IP in the style of real-mode
+ IVT entries (thus PI:SC in mem). */
+VARIABLE(grub_drivemap_oldhandler)
+LOCAL (oldhandler):
+ .word 0x0, 0x0
+
+/* This label MUST be at the end of the copied block, since the installer code
+ reserves additional space for mappings at runtime and copies them over it. */
+ .align 2
+
+VARIABLE(grub_drivemap_mapstart)
+LOCAL (mapstart):
+ .byte 0
diff --git a/grub-core/commands/i386/pc/halt.c b/grub-core/commands/i386/pc/halt.c
new file mode 100644
index 0000000..1e7c2c9
--- /dev/null
+++ b/grub-core/commands/i386/pc/halt.c
@@ -0,0 +1,126 @@
+/* halt.c - command to halt the computer. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2007,2009 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/misc.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+#include <grub/machine/int.h>
+#include <grub/acpi.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =
+ {
+ {"no-apm", 'n', 0, N_("Do not use APM to halt the computer."), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static inline void __attribute__ ((noreturn))
+stop (void)
+{
+ while (1)
+ {
+ asm volatile ("hlt");
+ }
+}
+/*
+ * Halt the system, using APM if possible. If NO_APM is true, don't use
+ * APM even if it is available.
+ */
+void __attribute__ ((noreturn))
+grub_halt (int no_apm)
+{
+ struct grub_bios_int_registers regs;
+
+ grub_acpi_halt ();
+
+ if (no_apm)
+ stop ();
+
+ /* detect APM */
+ regs.eax = 0x5300;
+ regs.ebx = 0;
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+ grub_bios_interrupt (0x15, &regs);
+
+ if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY)
+ stop ();
+
+ /* disconnect APM first */
+ regs.eax = 0x5304;
+ regs.ebx = 0;
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+ grub_bios_interrupt (0x15, &regs);
+
+ /* connect APM */
+ regs.eax = 0x5301;
+ regs.ebx = 0;
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+ grub_bios_interrupt (0x15, &regs);
+ if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY)
+ stop ();
+
+ /* set APM protocol level - 1.1 or bust. (this covers APM 1.2 also) */
+ regs.eax = 0x530E;
+ regs.ebx = 0;
+ regs.ecx = 0x0101;
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+ grub_bios_interrupt (0x15, &regs);
+ if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY)
+ stop ();
+
+ /* set the power state to off */
+ regs.eax = 0x5307;
+ regs.ebx = 1;
+ regs.ecx = 3;
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+ grub_bios_interrupt (0x15, &regs);
+
+ /* shouldn't reach here */
+ stop ();
+}
+
+static grub_err_t __attribute__ ((noreturn))
+grub_cmd_halt (grub_extcmd_context_t ctxt,
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+
+{
+ struct grub_arg_list *state = ctxt->state;
+ int no_apm = 0;
+
+ if (state[0].set)
+ no_apm = 1;
+ grub_halt (no_apm);
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(halt)
+{
+ cmd = grub_register_extcmd ("halt", grub_cmd_halt, 0, "[-n]",
+ N_("Halt the system, if possible using APM."),
+ options);
+}
+
+GRUB_MOD_FINI(halt)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/i386/pc/lsapm.c b/grub-core/commands/i386/pc/lsapm.c
new file mode 100644
index 0000000..c82476d
--- /dev/null
+++ b/grub-core/commands/i386/pc/lsapm.c
@@ -0,0 +1,115 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010 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/machine/int.h>
+#include <grub/machine/apm.h>
+#include <grub/dl.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+int
+grub_apm_get_info (struct grub_apm_info *info)
+{
+ struct grub_bios_int_registers regs;
+
+ /* detect APM */
+ regs.eax = 0x5300;
+ regs.ebx = 0;
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+ grub_bios_interrupt (0x15, &regs);
+
+ if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY)
+ return 0;
+ info->version = regs.eax & 0xffff;
+ info->flags = regs.ecx & 0xffff;
+
+ /* disconnect APM first */
+ regs.eax = 0x5304;
+ regs.ebx = 0;
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+ grub_bios_interrupt (0x15, &regs);
+
+ /* connect APM */
+ regs.eax = 0x5303;
+ regs.ebx = 0;
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+ grub_bios_interrupt (0x15, &regs);
+
+ if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY)
+ return 0;
+
+ info->cseg = regs.eax & 0xffff;
+ info->offset = regs.ebx;
+ info->cseg_16 = regs.ecx & 0xffff;
+ info->dseg = regs.edx & 0xffff;
+ info->cseg_len = regs.esi >> 16;
+ info->cseg_16_len = regs.esi & 0xffff;
+ info->dseg_len = regs.edi;
+
+ return 1;
+}
+
+static grub_err_t
+grub_cmd_lsapm (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)), char **args __attribute__ ((unused)))
+{
+ struct grub_apm_info info;
+ if (!grub_apm_get_info (&info))
+ return grub_error (GRUB_ERR_IO, N_("no APM found"));
+
+ grub_printf_ (N_("Version %u.%u\n"
+ "32-bit CS = 0x%x, len = 0x%x, offset = 0x%x\n"
+ "16-bit CS = 0x%x, len = 0x%x\n"
+ "DS = 0x%x, len = 0x%x\n"),
+ info.version >> 8, info.version & 0xff,
+ info.cseg, info.cseg_len, info.offset,
+ info.cseg_16, info.cseg_16_len,
+ info.dseg, info.dseg_len);
+ grub_xputs (info.flags & GRUB_APM_FLAGS_16BITPROTECTED_SUPPORTED
+ ? _("16-bit protected interface supported\n")
+ : _("16-bit protected interface unsupported\n"));
+ grub_xputs (info.flags & GRUB_APM_FLAGS_32BITPROTECTED_SUPPORTED
+ ? _("32-bit protected interface supported\n")
+ : _("32-bit protected interface unsupported\n"));
+ grub_xputs (info.flags & GRUB_APM_FLAGS_CPUIDLE_SLOWS_DOWN
+ ? _("CPU Idle slows down processor\n")
+ : _("CPU Idle doesn't slow down processor\n"));
+ grub_xputs (info.flags & GRUB_APM_FLAGS_DISABLED
+ ? _("APM disabled\n") : _("APM enabled\n"));
+ grub_xputs (info.flags & GRUB_APM_FLAGS_DISENGAGED
+ ? _("APM disengaged\n") : _("APM engaged\n"));
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(lsapm)
+{
+ cmd = grub_register_command ("lsapm", grub_cmd_lsapm, 0,
+ N_("Show APM information."));
+}
+
+GRUB_MOD_FINI(lsapm)
+{
+ grub_unregister_command (cmd);
+}
+
+
diff --git a/grub-core/commands/i386/pc/play.c b/grub-core/commands/i386/pc/play.c
new file mode 100644
index 0000000..a980e46
--- /dev/null
+++ b/grub-core/commands/i386/pc/play.c
@@ -0,0 +1,197 @@
+/* play.c - command to play a tune */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2007,2009 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/>.
+ */
+
+/* Lots of this file is borrowed from GNU/Hurd generic-speaker driver. */
+
+#include <grub/dl.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/term.h>
+#include <grub/misc.h>
+#include <grub/cpu/io.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/time.h>
+#include <grub/speaker.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define BASE_TEMPO (60 * 1000)
+
+
+#define T_REST ((grub_uint16_t) 0)
+#define T_FINE ((grub_uint16_t) -1)
+
+struct note
+{
+ grub_uint16_t pitch;
+ grub_uint16_t duration;
+};
+
+/* Returns whether playing should continue. */
+static int
+play (unsigned tempo, struct note *note)
+{
+ grub_uint64_t to;
+
+ if (note->pitch == T_FINE || grub_getkey_noblock () != GRUB_TERM_NO_KEY)
+ return 1;
+
+ grub_dprintf ("play", "pitch = %d, duration = %d\n", note->pitch,
+ note->duration);
+
+ switch (note->pitch)
+ {
+ case T_REST:
+ grub_speaker_beep_off ();
+ break;
+
+ default:
+ grub_speaker_beep_on (note->pitch);
+ break;
+ }
+
+ to = grub_get_time_ms () + BASE_TEMPO * note->duration / tempo;
+ while ((grub_get_time_ms () <= to)
+ && (grub_getkey_noblock () == GRUB_TERM_NO_KEY));
+
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_play (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ /* TRANSLATORS: It's musical notes, not the notes
+ you take. Play command expects arguments which can
+ be either a filename or tempo+notes.
+ This error happens if none is specified. */
+ N_("filename or tempo and notes expected"));
+
+ if (argc == 1)
+ {
+ struct note buf;
+ grub_uint32_t tempo;
+ grub_file_t file;
+
+ file = grub_file_open (args[0], GRUB_FILE_TYPE_AUDIO);
+
+ if (! file)
+ return grub_errno;
+
+ if (grub_file_read (file, &tempo, sizeof (tempo)) != sizeof (tempo))
+ {
+ grub_file_close (file);
+ if (!grub_errno)
+ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
+ args[0]);
+ return grub_errno;
+ }
+
+ if (!tempo)
+ {
+ grub_file_close (file);
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid tempo in %s"),
+ args[0]);
+ return grub_errno;
+ }
+
+ tempo = grub_le_to_cpu32 (tempo);
+ grub_dprintf ("play","tempo = %d\n", tempo);
+
+ while (grub_file_read (file, &buf,
+ sizeof (struct note)) == sizeof (struct note))
+ {
+ buf.pitch = grub_le_to_cpu16 (buf.pitch);
+ buf.duration = grub_le_to_cpu16 (buf.duration);
+
+ if (play (tempo, &buf))
+ break;
+ }
+
+ grub_file_close (file);
+ }
+ else
+ {
+ const char *end;
+ unsigned tempo;
+ struct note note;
+ int i;
+
+ tempo = grub_strtoul (args[0], &end, 0);
+
+ if (!tempo)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid tempo in %s"),
+ args[0]);
+ return grub_errno;
+ }
+
+ if (*end)
+ /* Was not a number either, assume it was supposed to be a file name. */
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), args[0]);
+
+ grub_dprintf ("play","tempo = %d\n", tempo);
+
+ for (i = 1; i + 1 < argc; i += 2)
+ {
+ note.pitch = grub_strtoul (args[i], &end, 0);
+ if (grub_errno)
+ break;
+ if (*end)
+ {
+ grub_error (GRUB_ERR_BAD_NUMBER, N_("unrecognized number"));
+ break;
+ }
+
+ note.duration = grub_strtoul (args[i + 1], &end, 0);
+ if (grub_errno)
+ break;
+ if (*end)
+ {
+ grub_error (GRUB_ERR_BAD_NUMBER, N_("unrecognized number"));
+ break;
+ }
+
+ if (play (tempo, &note))
+ break;
+ }
+ }
+
+ grub_speaker_beep_off ();
+
+ return 0;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(play)
+{
+ cmd = grub_register_command ("play", grub_cmd_play,
+ N_("FILE | TEMPO [PITCH1 DURATION1] [PITCH2 DURATION2] ... "),
+ N_("Play a tune."));
+}
+
+GRUB_MOD_FINI(play)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/i386/pc/sendkey.c b/grub-core/commands/i386/pc/sendkey.c
new file mode 100644
index 0000000..26d9acd
--- /dev/null
+++ b/grub-core/commands/i386/pc/sendkey.c
@@ -0,0 +1,387 @@
+/* sendkey.c - fake keystroke. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/extcmd.h>
+#include <grub/cpu/io.h>
+#include <grub/loader.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv2+");
+
+static char sendkey[0x20];
+/* Length of sendkey. */
+static int keylen = 0;
+static int noled = 0;
+static const struct grub_arg_option options[] =
+ {
+ {"num", 'n', 0, N_("set numlock mode"), "[on|off]", ARG_TYPE_STRING},
+ {"caps", 'c', 0, N_("set capslock mode"), "[on|off]", ARG_TYPE_STRING},
+ {"scroll", 's', 0, N_("set scrolllock mode"), "[on|off]", ARG_TYPE_STRING},
+ {"insert", 0, 0, N_("set insert mode"), "[on|off]", ARG_TYPE_STRING},
+ {"pause", 0, 0, N_("set pause mode"), "[on|off]", ARG_TYPE_STRING},
+ {"left-shift", 0, 0, N_("press left shift"), "[on|off]", ARG_TYPE_STRING},
+ {"right-shift", 0, 0, N_("press right shift"), "[on|off]", ARG_TYPE_STRING},
+ {"sysrq", 0, 0, N_("press SysRq"), "[on|off]", ARG_TYPE_STRING},
+ {"numkey", 0, 0, N_("press NumLock key"), "[on|off]", ARG_TYPE_STRING},
+ {"capskey", 0, 0, N_("press CapsLock key"), "[on|off]", ARG_TYPE_STRING},
+ {"scrollkey", 0, 0, N_("press ScrollLock key"), "[on|off]", ARG_TYPE_STRING},
+ {"insertkey", 0, 0, N_("press Insert key"), "[on|off]", ARG_TYPE_STRING},
+ {"left-alt", 0, 0, N_("press left alt"), "[on|off]", ARG_TYPE_STRING},
+ {"right-alt", 0, 0, N_("press right alt"), "[on|off]", ARG_TYPE_STRING},
+ {"left-ctrl", 0, 0, N_("press left ctrl"), "[on|off]", ARG_TYPE_STRING},
+ {"right-ctrl", 0, 0, N_("press right ctrl"), "[on|off]", ARG_TYPE_STRING},
+ {"no-led", 0, 0, N_("don't update LED state"), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+static int simple_flag_offsets[]
+= {5, 6, 4, 7, 11, 1, 0, 10, 13, 14, 12, 15, 9, 3, 8, 2};
+
+static grub_uint32_t andmask = 0xffffffff, ormask = 0;
+
+struct
+keysym
+{
+ const char *unshifted_name; /* the name in unshifted state */
+ const char *shifted_name; /* the name in shifted state */
+ unsigned char unshifted_ascii; /* the ascii code in unshifted state */
+ unsigned char shifted_ascii; /* the ascii code in shifted state */
+ unsigned char keycode; /* keyboard scancode */
+};
+
+/* The table for key symbols. If the "shifted" member of an entry is
+ NULL, the entry does not have shifted state. Copied from GRUB Legacy setkey fuction */
+static struct keysym keysym_table[] =
+{
+ {"escape", 0, 0x1b, 0, 0x01},
+ {"1", "exclam", '1', '!', 0x02},
+ {"2", "at", '2', '@', 0x03},
+ {"3", "numbersign", '3', '#', 0x04},
+ {"4", "dollar", '4', '$', 0x05},
+ {"5", "percent", '5', '%', 0x06},
+ {"6", "caret", '6', '^', 0x07},
+ {"7", "ampersand", '7', '&', 0x08},
+ {"8", "asterisk", '8', '*', 0x09},
+ {"9", "parenleft", '9', '(', 0x0a},
+ {"0", "parenright", '0', ')', 0x0b},
+ {"minus", "underscore", '-', '_', 0x0c},
+ {"equal", "plus", '=', '+', 0x0d},
+ {"backspace", 0, '\b', 0, 0x0e},
+ {"tab", 0, '\t', 0, 0x0f},
+ {"q", "Q", 'q', 'Q', 0x10},
+ {"w", "W", 'w', 'W', 0x11},
+ {"e", "E", 'e', 'E', 0x12},
+ {"r", "R", 'r', 'R', 0x13},
+ {"t", "T", 't', 'T', 0x14},
+ {"y", "Y", 'y', 'Y', 0x15},
+ {"u", "U", 'u', 'U', 0x16},
+ {"i", "I", 'i', 'I', 0x17},
+ {"o", "O", 'o', 'O', 0x18},
+ {"p", "P", 'p', 'P', 0x19},
+ {"bracketleft", "braceleft", '[', '{', 0x1a},
+ {"bracketright", "braceright", ']', '}', 0x1b},
+ {"enter", 0, '\r', 0, 0x1c},
+ {"control", 0, 0, 0, 0x1d},
+ {"a", "A", 'a', 'A', 0x1e},
+ {"s", "S", 's', 'S', 0x1f},
+ {"d", "D", 'd', 'D', 0x20},
+ {"f", "F", 'f', 'F', 0x21},
+ {"g", "G", 'g', 'G', 0x22},
+ {"h", "H", 'h', 'H', 0x23},
+ {"j", "J", 'j', 'J', 0x24},
+ {"k", "K", 'k', 'K', 0x25},
+ {"l", "L", 'l', 'L', 0x26},
+ {"semicolon", "colon", ';', ':', 0x27},
+ {"quote", "doublequote", '\'', '"', 0x28},
+ {"backquote", "tilde", '`', '~', 0x29},
+ {"shift", 0, 0, 0, 0x2a},
+ {"backslash", "bar", '\\', '|', 0x2b},
+ {"z", "Z", 'z', 'Z', 0x2c},
+ {"x", "X", 'x', 'X', 0x2d},
+ {"c", "C", 'c', 'C', 0x2e},
+ {"v", "V", 'v', 'V', 0x2f},
+ {"b", "B", 'b', 'B', 0x30},
+ {"n", "N", 'n', 'N', 0x31},
+ {"m", "M", 'm', 'M', 0x32},
+ {"comma", "less", ',', '<', 0x33},
+ {"period", "greater", '.', '>', 0x34},
+ {"slash", "question", '/', '?', 0x35},
+ {"rshift", 0, 0, 0, 0x36},
+ {"numasterisk", 0, '*', 0, 0x37},
+ {"alt", 0, 0, 0, 0x38},
+ {"space", 0, ' ', 0, 0x39},
+ {"capslock", 0, 0, 0, 0x3a},
+ {"F1", 0, 0, 0, 0x3b},
+ {"F2", 0, 0, 0, 0x3c},
+ {"F3", 0, 0, 0, 0x3d},
+ {"F4", 0, 0, 0, 0x3e},
+ {"F5", 0, 0, 0, 0x3f},
+ {"F6", 0, 0, 0, 0x40},
+ {"F7", 0, 0, 0, 0x41},
+ {"F8", 0, 0, 0, 0x42},
+ {"F9", 0, 0, 0, 0x43},
+ {"F10", 0, 0, 0, 0x44},
+ {"num7", "numhome", '7', 0, 0x47},
+ {"num8", "numup", '8', 0, 0x48},
+ {"num9", "numpgup", '9', 0, 0x49},
+ {"numminus", 0, '-', 0, 0x4a},
+ {"num4", "numleft", '4', 0, 0x4b},
+ {"num5", "numcenter", '5', 0, 0x4c},
+ {"num6", "numright", '6', 0, 0x4d},
+ {"numplus", 0, '-', 0, 0x4e},
+ {"num1", "numend", '1', 0, 0x4f},
+ {"num2", "numdown", '2', 0, 0x50},
+ {"num3", "numpgdown", '3', 0, 0x51},
+ {"num0", "numinsert", '0', 0, 0x52},
+ {"numperiod", "numdelete", 0, 0x7f, 0x53},
+ {"F11", 0, 0, 0, 0x57},
+ {"F12", 0, 0, 0, 0x58},
+ {"numenter", 0, '\r', 0, 0xe0},
+ {"numslash", 0, '/', 0, 0xe0},
+ {"delete", 0, 0x7f, 0, 0xe0},
+ {"insert", 0, 0xe0, 0, 0x52},
+ {"home", 0, 0xe0, 0, 0x47},
+ {"end", 0, 0xe0, 0, 0x4f},
+ {"pgdown", 0, 0xe0, 0, 0x51},
+ {"pgup", 0, 0xe0, 0, 0x49},
+ {"down", 0, 0xe0, 0, 0x50},
+ {"up", 0, 0xe0, 0, 0x48},
+ {"left", 0, 0xe0, 0, 0x4b},
+ {"right", 0, 0xe0, 0, 0x4d}
+};
+
+/* Set a simple flag in flags variable
+ OUTOFFSET - offset of flag in FLAGS,
+ OP - action id
+*/
+static void
+grub_sendkey_set_simple_flag (int outoffset, int op)
+{
+ if (op == 2)
+ {
+ andmask |= (1 << outoffset);
+ ormask &= ~(1 << outoffset);
+ }
+ else
+ {
+ andmask &= (~(1 << outoffset));
+ if (op == 1)
+ ormask |= (1 << outoffset);
+ else
+ ormask &= ~(1 << outoffset);
+ }
+}
+
+static int
+grub_sendkey_parse_op (struct grub_arg_list state)
+{
+ if (! state.set)
+ return 2;
+
+ if (grub_strcmp (state.arg, "off") == 0 || grub_strcmp (state.arg, "0") == 0
+ || grub_strcmp (state.arg, "unpress") == 0)
+ return 0;
+
+ if (grub_strcmp (state.arg, "on") == 0 || grub_strcmp (state.arg, "1") == 0
+ || grub_strcmp (state.arg, "press") == 0)
+ return 1;
+
+ return 2;
+}
+
+static grub_uint32_t oldflags;
+
+static grub_err_t
+grub_sendkey_postboot (void)
+{
+ /* For convention: pointer to flags. */
+ grub_uint32_t *flags = (grub_uint32_t *) 0x417;
+
+ *flags = oldflags;
+
+ *((char *) 0x41a) = 0x1e;
+ *((char *) 0x41c) = 0x1e;
+
+ return GRUB_ERR_NONE;
+}
+
+/* Set keyboard buffer to our sendkey */
+static grub_err_t
+grub_sendkey_preboot (int noret __attribute__ ((unused)))
+{
+ /* For convention: pointer to flags. */
+ grub_uint32_t *flags = (grub_uint32_t *) 0x417;
+
+ oldflags = *flags;
+
+ /* Set the sendkey. */
+ *((char *) 0x41a) = 0x1e;
+ *((char *) 0x41c) = keylen + 0x1e;
+ grub_memcpy ((char *) 0x41e, sendkey, 0x20);
+
+ /* Transform "any ctrl" to "right ctrl" flag. */
+ if (*flags & (1 << 8))
+ *flags &= ~(1 << 2);
+
+ /* Transform "any alt" to "right alt" flag. */
+ if (*flags & (1 << 9))
+ *flags &= ~(1 << 3);
+
+ *flags = (*flags & andmask) | ormask;
+
+ /* Transform "right ctrl" to "any ctrl" flag. */
+ if (*flags & (1 << 8))
+ *flags |= (1 << 2);
+
+ /* Transform "right alt" to "any alt" flag. */
+ if (*flags & (1 << 9))
+ *flags |= (1 << 3);
+
+ /* Write new LED state */
+ if (!noled)
+ {
+ int value = 0;
+ int failed;
+ /* Try 5 times */
+ for (failed = 0; failed < 5; failed++)
+ {
+ value = 0;
+ /* Send command change LEDs */
+ grub_outb (0xed, 0x60);
+
+ /* Wait */
+ do
+ value = grub_inb (0x60);
+ while ((value != 0xfa) && (value != 0xfe));
+
+ if (value == 0xfa)
+ {
+ /* Set new LEDs*/
+ grub_outb ((*flags >> 4) & 7, 0x60);
+ break;
+ }
+ }
+ }
+ return GRUB_ERR_NONE;
+}
+
+/* Helper for grub_cmd_sendkey. */
+static int
+find_key_code (char *key)
+{
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(keysym_table); i++)
+ {
+ if (keysym_table[i].unshifted_name
+ && grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
+ return keysym_table[i].keycode;
+ else if (keysym_table[i].shifted_name
+ && grub_strcmp (key, keysym_table[i].shifted_name) == 0)
+ return keysym_table[i].keycode;
+ }
+
+ return 0;
+}
+
+/* Helper for grub_cmd_sendkey. */
+static int
+find_ascii_code (char *key)
+{
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(keysym_table); i++)
+ {
+ if (keysym_table[i].unshifted_name
+ && grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
+ return keysym_table[i].unshifted_ascii;
+ else if (keysym_table[i].shifted_name
+ && grub_strcmp (key, keysym_table[i].shifted_name) == 0)
+ return keysym_table[i].shifted_ascii;
+ }
+
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_sendkey (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+
+ andmask = 0xffffffff;
+ ormask = 0;
+
+ {
+ int i;
+
+ keylen = 0;
+
+ for (i = 0; i < argc && keylen < 0x20; i++)
+ {
+ int key_code;
+
+ key_code = find_key_code (args[i]);
+ if (key_code)
+ {
+ sendkey[keylen++] = find_ascii_code (args[i]);
+ sendkey[keylen++] = key_code;
+ }
+ }
+ }
+
+ {
+ unsigned i;
+ for (i = 0; i < ARRAY_SIZE(simple_flag_offsets); i++)
+ grub_sendkey_set_simple_flag (simple_flag_offsets[i],
+ grub_sendkey_parse_op(state[i]));
+ }
+
+ /* Set noled. */
+ noled = (state[ARRAY_SIZE(simple_flag_offsets)].set);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_extcmd_t cmd;
+static struct grub_preboot *preboot_hook;
+
+GRUB_MOD_INIT (sendkey)
+{
+ cmd = grub_register_extcmd ("sendkey", grub_cmd_sendkey, 0,
+ N_("[KEYSTROKE1] [KEYSTROKE2] ..."),
+ /* TRANSLATORS: It can emulate multiple
+ keypresses. */
+ N_("Emulate a keystroke sequence"), options);
+
+ preboot_hook
+ = grub_loader_register_preboot_hook (grub_sendkey_preboot,
+ grub_sendkey_postboot,
+ GRUB_LOADER_PREBOOT_HOOK_PRIO_CONSOLE);
+}
+
+GRUB_MOD_FINI (sendkey)
+{
+ grub_unregister_extcmd (cmd);
+ grub_loader_unregister_preboot_hook (preboot_hook);
+}
diff --git a/grub-core/commands/i386/pc/smbios.c b/grub-core/commands/i386/pc/smbios.c
new file mode 100644
index 0000000..069d663
--- /dev/null
+++ b/grub-core/commands/i386/pc/smbios.c
@@ -0,0 +1,52 @@
+/* smbios.c - get smbios tables. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2019 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;
+}
diff --git a/grub-core/commands/i386/rdmsr.c b/grub-core/commands/i386/rdmsr.c
new file mode 100644
index 0000000..46c4346
--- /dev/null
+++ b/grub-core/commands/i386/rdmsr.c
@@ -0,0 +1,102 @@
+/* rdmsr.c - Read CPU model-specific registers. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2019 Free Software Foundation, Inc.
+ * Based on gcc/gcc/config/i386/driver-i386.c
+ *
+ * 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/mm.h>
+#include <grub/env.h>
+#include <grub/command.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+#include <grub/i386/cpuid.h>
+#include <grub/i386/rdmsr.h>
+
+GRUB_MOD_LICENSE("GPLv3+");
+
+static grub_extcmd_t cmd_read;
+
+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_msr_read (grub_extcmd_context_t ctxt, int argc, char **argv)
+{
+ grub_uint32_t manufacturer[3], max_cpuid, a, b, c, features, addr;
+ grub_uint64_t value;
+ const char *ptr;
+ char buf[sizeof("1122334455667788")];
+
+ /*
+ * The CPUID instruction should be used to determine whether MSRs
+ * are supported. (CPUID.01H:EDX[5] = 1)
+ */
+ if (! grub_cpu_is_cpuid_supported ())
+ return grub_error (GRUB_ERR_BUG, N_("unsupported instruction"));
+
+ grub_cpuid (0, max_cpuid, manufacturer[0], manufacturer[2], manufacturer[1]);
+
+ if (max_cpuid < 1)
+ return grub_error (GRUB_ERR_BUG, N_("unsupported instruction"));
+
+ grub_cpuid (1, a, b, c, features);
+
+ if (!(features & (1 << 5)))
+ return grub_error (GRUB_ERR_BUG, N_("unsupported instruction"));
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+
+ grub_errno = GRUB_ERR_NONE;
+ ptr = argv[0];
+ addr = grub_strtoul (ptr, &ptr, 0);
+
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
+ if (*ptr != '\0')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid argument"));
+
+ value = grub_msr_read (addr);
+
+ if (ctxt->state[0].set)
+ {
+ grub_snprintf (buf, sizeof(buf), "%llx", (unsigned long long) value);
+ grub_env_set (ctxt->state[0].arg, buf);
+ }
+ else
+ grub_printf ("0x%llx\n", (unsigned long long) value);
+
+ return GRUB_ERR_NONE;
+}
+
+GRUB_MOD_INIT(rdmsr)
+{
+ cmd_read = grub_register_extcmd ("rdmsr", grub_cmd_msr_read, 0, N_("ADDR"),
+ N_("Read a CPU model specific register."),
+ options);
+}
+
+GRUB_MOD_FINI(rdmsr)
+{
+ grub_unregister_extcmd (cmd_read);
+}
diff --git a/grub-core/commands/i386/wrmsr.c b/grub-core/commands/i386/wrmsr.c
new file mode 100644
index 0000000..1b143b8
--- /dev/null
+++ b/grub-core/commands/i386/wrmsr.c
@@ -0,0 +1,94 @@
+/* wrmsr.c - Write CPU model-specific registers. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2019 Free Software Foundation, Inc.
+ * Based on gcc/gcc/config/i386/driver-i386.c
+ *
+ * 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/mm.h>
+#include <grub/env.h>
+#include <grub/command.h>
+#include <grub/extcmd.h>
+#include <grub/lockdown.h>
+#include <grub/i18n.h>
+#include <grub/i386/cpuid.h>
+#include <grub/i386/wrmsr.h>
+
+GRUB_MOD_LICENSE("GPLv3+");
+
+static grub_command_t cmd_write;
+
+static grub_err_t
+grub_cmd_msr_write (grub_command_t cmd __attribute__ ((unused)), int argc, char **argv)
+{
+ grub_uint32_t manufacturer[3], max_cpuid, a, b, c, features, addr;
+ grub_uint64_t value;
+ const char *ptr;
+
+ /*
+ * The CPUID instruction should be used to determine whether MSRs
+ * are supported. (CPUID.01H:EDX[5] = 1)
+ */
+ if (!grub_cpu_is_cpuid_supported ())
+ return grub_error (GRUB_ERR_BUG, N_("unsupported instruction"));
+
+ grub_cpuid (0, max_cpuid, manufacturer[0], manufacturer[2], manufacturer[1]);
+
+ if (max_cpuid < 1)
+ return grub_error (GRUB_ERR_BUG, N_("unsupported instruction"));
+
+ grub_cpuid (1, a, b, c, features);
+
+ if (!(features & (1 << 5)))
+ return grub_error (GRUB_ERR_BUG, N_("unsupported instruction"));
+
+ if (argc != 2)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
+
+ grub_errno = GRUB_ERR_NONE;
+ ptr = argv[0];
+ addr = grub_strtoul (ptr, &ptr, 0);
+
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
+ if (*ptr != '\0')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid argument"));
+
+ ptr = argv[1];
+ value = grub_strtoull (ptr, &ptr, 0);
+
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
+ if (*ptr != '\0')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid argument"));
+
+ grub_msr_write (addr, value);
+
+ return GRUB_ERR_NONE;
+}
+
+GRUB_MOD_INIT(wrmsr)
+{
+ cmd_write = grub_register_command_lockdown ("wrmsr", grub_cmd_msr_write, N_("ADDR VALUE"),
+ N_("Write a value to a CPU model specific register."));
+}
+
+GRUB_MOD_FINI(wrmsr)
+{
+ grub_unregister_command (cmd_write);
+}
diff --git a/grub-core/commands/ieee1275/suspend.c b/grub-core/commands/ieee1275/suspend.c
new file mode 100644
index 0000000..b505485
--- /dev/null
+++ b/grub-core/commands/ieee1275/suspend.c
@@ -0,0 +1,51 @@
+/* suspend.c - command to suspend GRUB and return to Open Firmware */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2007 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/misc.h>
+#include <grub/term.h>
+#include <grub/ieee1275/ieee1275.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+grub_cmd_suspend (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ grub_puts_ (N_("Run `go' to resume GRUB."));
+ grub_ieee1275_enter ();
+ grub_cls ();
+ return 0;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(ieee1275_suspend)
+{
+ cmd = grub_register_command ("suspend", grub_cmd_suspend,
+ 0, N_("Return to IEEE1275 prompt."));
+}
+
+GRUB_MOD_FINI(ieee1275_suspend)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/iorw.c b/grub-core/commands/iorw.c
new file mode 100644
index 0000000..584baec
--- /dev/null
+++ b/grub-core/commands/iorw.c
@@ -0,0 +1,156 @@
+/* memrw.c - command to read / write physical memory */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/misc.h>
+#include <grub/extcmd.h>
+#include <grub/env.h>
+#include <grub/cpu/io.h>
+#include <grub/i18n.h>
+#include <grub/lockdown.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_extcmd_t cmd_read_byte, cmd_read_word, cmd_read_dword;
+static grub_command_t cmd_write_byte, cmd_write_word, cmd_write_dword;
+
+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_read (grub_extcmd_context_t ctxt, int argc, char **argv)
+{
+ grub_port_t addr;
+ grub_uint32_t value = 0;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+
+ addr = grub_strtoul (argv[0], 0, 0);
+ switch (ctxt->extcmd->cmd->name[sizeof ("in") - 1])
+ {
+ case 'l':
+ value = grub_inl (addr);
+ break;
+
+ case 'w':
+ value = grub_inw (addr);
+ break;
+
+ case 'b':
+ value = grub_inb (addr);
+ break;
+ }
+
+ if (ctxt->state[0].set)
+ {
+ char buf[sizeof ("XXXXXXXX")];
+ grub_snprintf (buf, sizeof (buf), "%x", value);
+ grub_env_set (ctxt->state[0].arg, buf);
+ }
+ else
+ grub_printf ("0x%x\n", value);
+
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_write (grub_command_t cmd, int argc, char **argv)
+{
+ grub_port_t addr;
+ grub_uint32_t value;
+ grub_uint32_t mask = 0xffffffff;
+
+ if (argc != 2 && argc != 3)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
+
+ addr = grub_strtoul (argv[0], 0, 0);
+ value = grub_strtoul (argv[1], 0, 0);
+ if (argc == 3)
+ mask = grub_strtoul (argv[2], 0, 0);
+ value &= mask;
+ switch (cmd->name[sizeof ("out") - 1])
+ {
+ case 'l':
+ if (mask != 0xffffffff)
+ grub_outl ((grub_inl (addr) & ~mask) | value, addr);
+ else
+ grub_outl (value, addr);
+ break;
+
+ case 'w':
+ if ((mask & 0xffff) != 0xffff)
+ grub_outw ((grub_inw (addr) & ~mask) | value, addr);
+ else
+ grub_outw (value, addr);
+ break;
+
+ case 'b':
+ if ((mask & 0xff) != 0xff)
+ grub_outb ((grub_inb (addr) & ~mask) | value, addr);
+ else
+ grub_outb (value, addr);
+ break;
+ }
+
+ return 0;
+}
+
+GRUB_MOD_INIT(memrw)
+{
+ cmd_read_byte =
+ grub_register_extcmd ("inb", grub_cmd_read, 0,
+ N_("PORT"), N_("Read 8-bit value from PORT."),
+ options);
+ cmd_read_word =
+ grub_register_extcmd ("inw", grub_cmd_read, 0,
+ N_("PORT"), N_("Read 16-bit value from PORT."),
+ options);
+ cmd_read_dword =
+ grub_register_extcmd ("inl", grub_cmd_read, 0,
+ N_("PORT"), N_("Read 32-bit value from PORT."),
+ options);
+ cmd_write_byte =
+ grub_register_command_lockdown ("outb", grub_cmd_write,
+ N_("PORT VALUE [MASK]"),
+ N_("Write 8-bit VALUE to PORT."));
+ cmd_write_word =
+ grub_register_command_lockdown ("outw", grub_cmd_write,
+ N_("PORT VALUE [MASK]"),
+ N_("Write 16-bit VALUE to PORT."));
+ cmd_write_dword =
+ grub_register_command_lockdown ("outl", grub_cmd_write,
+ N_("ADDR VALUE [MASK]"),
+ N_("Write 32-bit VALUE to PORT."));
+}
+
+GRUB_MOD_FINI(memrw)
+{
+ grub_unregister_extcmd (cmd_read_byte);
+ grub_unregister_extcmd (cmd_read_word);
+ grub_unregister_extcmd (cmd_read_dword);
+ grub_unregister_command (cmd_write_byte);
+ grub_unregister_command (cmd_write_word);
+ grub_unregister_command (cmd_write_dword);
+}
diff --git a/grub-core/commands/keylayouts.c b/grub-core/commands/keylayouts.c
new file mode 100644
index 0000000..c05d612
--- /dev/null
+++ b/grub-core/commands/keylayouts.c
@@ -0,0 +1,307 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2005,2007,2008,2009 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/term.h>
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/env.h>
+#include <grub/time.h>
+#include <grub/dl.h>
+#include <grub/keyboard_layouts.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/file.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static struct grub_keyboard_layout layout_us = {
+ .keyboard_map = {
+ /* Keyboard errors. Handled by driver. */
+ /* 0x00 */ 0, 0, 0, 0,
+
+ /* 0x04 */ 'a', 'b', 'c', 'd',
+ /* 0x08 */ 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
+ /* 0x10 */ 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+ /* 0x18 */ 'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
+ /* 0x20 */ '3', '4', '5', '6', '7', '8', '9', '0',
+ /* 0x28 */ '\n', GRUB_TERM_ESC, GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, ' ', '-', '=', '[',
+ /* According to usage table 0x31 should be mapped to '/'
+ but testing with real keyboard shows that 0x32 is remapped to '/'.
+ Map 0x31 to 0.
+ */
+ /* 0x30 */ ']', 0, '\\', ';', '\'', '`', ',', '.',
+ /* 0x39 is CapsLock. Handled by driver. */
+ /* 0x38 */ '/', 0, GRUB_TERM_KEY_F1, GRUB_TERM_KEY_F2,
+ /* 0x3c */ GRUB_TERM_KEY_F3, GRUB_TERM_KEY_F4,
+ /* 0x3e */ GRUB_TERM_KEY_F5, GRUB_TERM_KEY_F6,
+ /* 0x40 */ GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8,
+ /* 0x42 */ GRUB_TERM_KEY_F9, GRUB_TERM_KEY_F10,
+ /* 0x44 */ GRUB_TERM_KEY_F11, GRUB_TERM_KEY_F12,
+ /* PrtScr and ScrollLock. Not handled yet. */
+ /* 0x46 */ 0, 0,
+ /* 0x48 is Pause. Not handled yet. */
+ /* 0x48 */ 0, GRUB_TERM_KEY_INSERT,
+ /* 0x4a */ GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_PPAGE,
+ /* 0x4c */ GRUB_TERM_KEY_DC, GRUB_TERM_KEY_END,
+ /* 0x4e */ GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_RIGHT,
+ /* 0x50 */ GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_DOWN,
+ /* 0x53 is NumLock. Handled by driver. */
+ /* 0x52 */ GRUB_TERM_KEY_UP, 0,
+ /* 0x54 */ '/', '*',
+ /* 0x56 */ '-', '+',
+ /* 0x58 */ '\n', GRUB_TERM_KEY_END,
+ /* 0x5a */ GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_NPAGE,
+ /* 0x5c */ GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_CENTER,
+ /* 0x5e */ GRUB_TERM_KEY_RIGHT, GRUB_TERM_KEY_HOME,
+ /* 0x60 */ GRUB_TERM_KEY_UP, GRUB_TERM_KEY_PPAGE,
+ /* 0x62 */ GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_DC,
+ /* 0x64 */ '\\'
+ },
+ .keyboard_map_shift = {
+ /* Keyboard errors. Handled by driver. */
+ /* 0x00 */ 0, 0, 0, 0,
+
+ /* 0x04 */ 'A', 'B', 'C', 'D',
+ /* 0x08 */ 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
+ /* 0x10 */ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ /* 0x18 */ 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@',
+ /* 0x20 */ '#', '$', '%', '^', '&', '*', '(', ')',
+ /* 0x28 */ '\n' | GRUB_TERM_SHIFT, GRUB_TERM_ESC | GRUB_TERM_SHIFT,
+ /* 0x2a */ GRUB_TERM_BACKSPACE | GRUB_TERM_SHIFT, GRUB_TERM_TAB | GRUB_TERM_SHIFT,
+ /* 0x2c */ ' ' | GRUB_TERM_SHIFT, '_', '+', '{',
+ /* According to usage table 0x31 should be mapped to '/'
+ but testing with real keyboard shows that 0x32 is remapped to '/'.
+ Map 0x31 to 0.
+ */
+ /* 0x30 */ '}', 0, '|', ':', '"', '~', '<', '>',
+ /* 0x39 is CapsLock. Handled by driver. */
+ /* 0x38 */ '?', 0,
+ /* 0x3a */ GRUB_TERM_KEY_F1 | GRUB_TERM_SHIFT,
+ /* 0x3b */ GRUB_TERM_KEY_F2 | GRUB_TERM_SHIFT,
+ /* 0x3c */ GRUB_TERM_KEY_F3 | GRUB_TERM_SHIFT,
+ /* 0x3d */ GRUB_TERM_KEY_F4 | GRUB_TERM_SHIFT,
+ /* 0x3e */ GRUB_TERM_KEY_F5 | GRUB_TERM_SHIFT,
+ /* 0x3f */ GRUB_TERM_KEY_F6 | GRUB_TERM_SHIFT,
+ /* 0x40 */ GRUB_TERM_KEY_F7 | GRUB_TERM_SHIFT,
+ /* 0x41 */ GRUB_TERM_KEY_F8 | GRUB_TERM_SHIFT,
+ /* 0x42 */ GRUB_TERM_KEY_F9 | GRUB_TERM_SHIFT,
+ /* 0x43 */ GRUB_TERM_KEY_F10 | GRUB_TERM_SHIFT,
+ /* 0x44 */ GRUB_TERM_KEY_F11 | GRUB_TERM_SHIFT,
+ /* 0x45 */ GRUB_TERM_KEY_F12 | GRUB_TERM_SHIFT,
+ /* PrtScr and ScrollLock. Not handled yet. */
+ /* 0x46 */ 0, 0,
+ /* 0x48 is Pause. Not handled yet. */
+ /* 0x48 */ 0, GRUB_TERM_KEY_INSERT | GRUB_TERM_SHIFT,
+ /* 0x4a */ GRUB_TERM_KEY_HOME | GRUB_TERM_SHIFT,
+ /* 0x4b */ GRUB_TERM_KEY_PPAGE | GRUB_TERM_SHIFT,
+ /* 0x4c */ GRUB_TERM_KEY_DC | GRUB_TERM_SHIFT,
+ /* 0x4d */ GRUB_TERM_KEY_END | GRUB_TERM_SHIFT,
+ /* 0x4e */ GRUB_TERM_KEY_NPAGE | GRUB_TERM_SHIFT,
+ /* 0x4f */ GRUB_TERM_KEY_RIGHT | GRUB_TERM_SHIFT,
+ /* 0x50 */ GRUB_TERM_KEY_LEFT | GRUB_TERM_SHIFT,
+ /* 0x51 */ GRUB_TERM_KEY_DOWN | GRUB_TERM_SHIFT,
+ /* 0x53 is NumLock. Handled by driver. */
+ /* 0x52 */ GRUB_TERM_KEY_UP | GRUB_TERM_SHIFT, 0,
+ /* 0x54 */ '/', '*',
+ /* 0x56 */ '-', '+',
+ /* 0x58 */ '\n' | GRUB_TERM_SHIFT, '1', '2', '3', '4', '5','6', '7',
+ /* 0x60 */ '8', '9', '0', '.', '|'
+ }
+};
+
+static struct grub_keyboard_layout *grub_current_layout = &layout_us;
+
+static int
+map_key_core (int code, int status, int *alt_gr_consumed)
+{
+ *alt_gr_consumed = 0;
+
+ if (code >= GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE)
+ return 0;
+
+ if (status & GRUB_TERM_STATUS_RALT)
+ {
+ if (status & (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT))
+ {
+ if (grub_current_layout->keyboard_map_shift_l3[code])
+ {
+ *alt_gr_consumed = 1;
+ return grub_current_layout->keyboard_map_shift_l3[code];
+ }
+ }
+ else if (grub_current_layout->keyboard_map_l3[code])
+ {
+ *alt_gr_consumed = 1;
+ return grub_current_layout->keyboard_map_l3[code];
+ }
+ }
+ if (status & (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT))
+ return grub_current_layout->keyboard_map_shift[code];
+ else
+ return grub_current_layout->keyboard_map[code];
+}
+
+unsigned
+grub_term_map_key (grub_keyboard_key_t code, int status)
+{
+ int alt_gr_consumed = 0;
+ int key;
+
+ if (code >= 0x59 && code <= 0x63 && (status & GRUB_TERM_STATUS_NUM))
+ {
+ if (status & (GRUB_TERM_STATUS_RSHIFT | GRUB_TERM_STATUS_LSHIFT))
+ status &= ~(GRUB_TERM_STATUS_RSHIFT | GRUB_TERM_STATUS_LSHIFT);
+ else
+ status |= GRUB_TERM_STATUS_RSHIFT;
+ }
+
+ key = map_key_core (code, status, &alt_gr_consumed);
+
+ if (key == 0 || key == GRUB_TERM_SHIFT) {
+ grub_printf ("Unknown key 0x%x detected\n", code);
+ return GRUB_TERM_NO_KEY;
+ }
+
+ if (status & GRUB_TERM_STATUS_CAPS)
+ {
+ if ((key >= 'a') && (key <= 'z'))
+ key += 'A' - 'a';
+ else if ((key >= 'A') && (key <= 'Z'))
+ key += 'a' - 'A';
+ }
+
+ if ((status & GRUB_TERM_STATUS_LALT) ||
+ ((status & GRUB_TERM_STATUS_RALT) && !alt_gr_consumed))
+ key |= GRUB_TERM_ALT;
+ if (status & (GRUB_TERM_STATUS_LCTRL | GRUB_TERM_STATUS_RCTRL))
+ key |= GRUB_TERM_CTRL;
+
+ return key;
+}
+
+static grub_err_t
+grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ char *filename;
+ grub_file_t file;
+ grub_uint32_t version;
+ grub_uint8_t magic[GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE];
+ struct grub_keyboard_layout *newmap = NULL;
+ unsigned i;
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "file or layout name required");
+ if (argv[0][0] != '(' && argv[0][0] != '/' && argv[0][0] != '+')
+ {
+ const char *prefix = grub_env_get ("prefix");
+ if (!prefix)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("variable `%s' isn't set"), "prefix");
+ filename = grub_xasprintf ("%s/layouts/%s.gkb", prefix, argv[0]);
+ if (!filename)
+ return grub_errno;
+ }
+ else
+ filename = argv[0];
+
+ file = grub_file_open (filename, GRUB_FILE_TYPE_KEYBOARD_LAYOUT);
+ if (! file)
+ goto fail;
+
+ if (grub_file_read (file, magic, sizeof (magic)) != sizeof (magic))
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("premature end of file %s"),
+ filename);
+ goto fail;
+ }
+
+ if (grub_memcmp (magic, GRUB_KEYBOARD_LAYOUTS_FILEMAGIC,
+ GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE) != 0)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid magic");
+ goto fail;
+ }
+
+ if (grub_file_read (file, &version, sizeof (version)) != sizeof (version))
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("premature end of file %s"),
+ filename);
+ goto fail;
+ }
+
+ if (version != grub_cpu_to_le32_compile_time (GRUB_KEYBOARD_LAYOUTS_VERSION))
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid version");
+ goto fail;
+ }
+
+ newmap = grub_malloc (sizeof (*newmap));
+ if (!newmap)
+ goto fail;
+
+ if (grub_file_read (file, newmap, sizeof (*newmap)) != sizeof (*newmap))
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("premature end of file %s"),
+ filename);
+ goto fail;
+ }
+
+ for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map); i++)
+ newmap->keyboard_map[i] = grub_le_to_cpu32(newmap->keyboard_map[i]);
+
+ for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map_shift); i++)
+ newmap->keyboard_map_shift[i]
+ = grub_le_to_cpu32(newmap->keyboard_map_shift[i]);
+
+ for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map_l3); i++)
+ newmap->keyboard_map_l3[i]
+ = grub_le_to_cpu32(newmap->keyboard_map_l3[i]);
+
+ for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map_shift_l3); i++)
+ newmap->keyboard_map_shift_l3[i]
+ = grub_le_to_cpu32(newmap->keyboard_map_shift_l3[i]);
+
+ grub_current_layout = newmap;
+
+ return GRUB_ERR_NONE;
+
+ fail:
+ if (filename != argv[0])
+ grub_free (filename);
+ grub_free (newmap);
+ if (file)
+ grub_file_close (file);
+ return grub_errno;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(keylayouts)
+{
+ cmd = grub_register_command ("keymap", grub_cmd_keymap,
+ 0, N_("Load a keyboard layout."));
+}
+
+GRUB_MOD_FINI(keylayouts)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/keystatus.c b/grub-core/commands/keystatus.c
new file mode 100644
index 0000000..ff3f587
--- /dev/null
+++ b/grub-core/commands/keystatus.c
@@ -0,0 +1,95 @@
+/* keystatus.c - Command to check key modifier status. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/misc.h>
+#include <grub/extcmd.h>
+#include <grub/term.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =
+ {
+ /* TRANSLATORS: "Check" in a sense that if this key is pressed then
+ "true" is returned, otherwise "false". */
+ {"shift", 's', 0, N_("Check Shift key."), 0, 0},
+ {"ctrl", 'c', 0, N_("Check Control key."), 0, 0},
+ {"alt", 'a', 0, N_("Check Alt key."), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static grub_err_t
+grub_cmd_keystatus (grub_extcmd_context_t ctxt,
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ struct grub_arg_list *state = ctxt->state;
+ int expect_mods = 0;
+ int mods;
+
+ if (state[0].set)
+ expect_mods |= (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT);
+ if (state[1].set)
+ expect_mods |= (GRUB_TERM_STATUS_LCTRL | GRUB_TERM_STATUS_RCTRL);
+ if (state[2].set)
+ expect_mods |= (GRUB_TERM_STATUS_LALT | GRUB_TERM_STATUS_RALT);
+
+ grub_dprintf ("keystatus", "expect_mods: %d\n", expect_mods);
+
+ /* Without arguments, just check whether getkeystatus is supported at
+ all. */
+ if (expect_mods == 0)
+ {
+ grub_term_input_t term;
+ int nterms = 0;
+
+ FOR_ACTIVE_TERM_INPUTS (term)
+ if (!term->getkeystatus)
+ return grub_error (GRUB_ERR_TEST_FAILURE, N_("false"));
+ else
+ nterms++;
+ if (!nterms)
+ return grub_error (GRUB_ERR_TEST_FAILURE, N_("false"));
+ return 0;
+ }
+
+ mods = grub_getkeystatus ();
+ grub_dprintf ("keystatus", "mods: %d\n", mods);
+ if (mods >= 0 && (mods & expect_mods) != 0)
+ return 0;
+ else
+ return grub_error (GRUB_ERR_TEST_FAILURE, N_("false"));
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(keystatus)
+{
+ cmd = grub_register_extcmd ("keystatus", grub_cmd_keystatus, 0,
+ "[--shift] [--ctrl] [--alt]",
+ /* TRANSLATORS: there are 3 modifiers. */
+ N_("Check key modifier status."),
+ options);
+}
+
+GRUB_MOD_FINI(keystatus)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/legacycfg.c b/grub-core/commands/legacycfg.c
new file mode 100644
index 0000000..cc5971f
--- /dev/null
+++ b/grub-core/commands/legacycfg.c
@@ -0,0 +1,912 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000, 2001, 2010 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/types.h>
+#include <grub/misc.h>
+#include <grub/command.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/file.h>
+#include <grub/normal.h>
+#include <grub/script_sh.h>
+#include <grub/i18n.h>
+#include <grub/term.h>
+#include <grub/legacy_parse.h>
+#include <grub/crypto.h>
+#include <grub/auth.h>
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/safemath.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* Helper for legacy_file. */
+static grub_err_t
+legacy_file_getline (char **line, int cont __attribute__ ((unused)),
+ void *data __attribute__ ((unused)))
+{
+ *line = 0;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+legacy_file (const char *filename)
+{
+ grub_file_t file;
+ char *entryname = NULL, *entrysrc = NULL;
+ grub_menu_t menu;
+ char *suffix = grub_strdup ("");
+
+ if (!suffix)
+ return grub_errno;
+
+ file = grub_file_open (filename, GRUB_FILE_TYPE_CONFIG);
+ if (! file)
+ {
+ grub_free (suffix);
+ return grub_errno;
+ }
+
+ menu = grub_env_get_menu ();
+ if (! menu)
+ {
+ menu = grub_zalloc (sizeof (*menu));
+ if (! menu)
+ {
+ grub_free (suffix);
+ return grub_errno;
+ }
+
+ grub_env_set_menu (menu);
+ }
+
+ while (1)
+ {
+ char *buf = grub_file_getline (file);
+ char *parsed = NULL;
+
+ if (!buf && grub_errno)
+ {
+ grub_file_close (file);
+ grub_free (suffix);
+ return grub_errno;
+ }
+
+ if (!buf)
+ break;
+
+ {
+ char *oldname = NULL;
+ char *newsuffix;
+ char *ptr;
+
+ for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++);
+
+ oldname = entryname;
+ parsed = grub_legacy_parse (ptr, &entryname, &newsuffix);
+ grub_free (buf);
+ buf = NULL;
+ if (newsuffix)
+ {
+ char *t;
+ grub_size_t sz;
+
+ if (grub_add (grub_strlen (suffix), grub_strlen (newsuffix), &sz) ||
+ grub_add (sz, 1, &sz))
+ {
+ grub_errno = GRUB_ERR_OUT_OF_RANGE;
+ goto fail_0;
+ }
+
+ t = suffix;
+ suffix = grub_realloc (suffix, sz);
+ if (!suffix)
+ {
+ grub_free (t);
+
+ fail_0:
+ grub_free (entrysrc);
+ grub_free (parsed);
+ grub_free (newsuffix);
+ grub_free (suffix);
+ return grub_errno;
+ }
+ grub_memcpy (suffix + grub_strlen (suffix), newsuffix,
+ grub_strlen (newsuffix) + 1);
+ grub_free (newsuffix);
+ newsuffix = NULL;
+ }
+ if (oldname != entryname && oldname)
+ {
+ const char **args = grub_malloc (sizeof (args[0]));
+ if (!args)
+ {
+ grub_file_close (file);
+ return grub_errno;
+ }
+ args[0] = oldname;
+ grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy",
+ NULL, NULL,
+ entrysrc, 0);
+ grub_free (args);
+ entrysrc[0] = 0;
+ grub_free (oldname);
+ }
+ }
+
+ if (parsed && !entryname)
+ {
+ grub_normal_parse_line (parsed, legacy_file_getline, NULL);
+ grub_print_error ();
+ grub_free (parsed);
+ parsed = NULL;
+ }
+ else if (parsed)
+ {
+ if (!entrysrc)
+ entrysrc = parsed;
+ else
+ {
+ char *t;
+ grub_size_t sz;
+
+ if (grub_add (grub_strlen (entrysrc), grub_strlen (parsed), &sz) ||
+ grub_add (sz, 1, &sz))
+ {
+ grub_errno = GRUB_ERR_OUT_OF_RANGE;
+ goto fail_1;
+ }
+
+ t = entrysrc;
+ entrysrc = grub_realloc (entrysrc, sz);
+ if (!entrysrc)
+ {
+ grub_free (t);
+
+ fail_1:
+ grub_free (parsed);
+ grub_free (suffix);
+ return grub_errno;
+ }
+ grub_memcpy (entrysrc + grub_strlen (entrysrc), parsed,
+ grub_strlen (parsed) + 1);
+ grub_free (parsed);
+ parsed = NULL;
+ }
+ }
+ }
+ grub_file_close (file);
+
+ if (entryname)
+ {
+ const char **args = grub_malloc (sizeof (args[0]));
+ if (!args)
+ {
+ grub_file_close (file);
+ grub_free (suffix);
+ grub_free (entrysrc);
+ return grub_errno;
+ }
+ args[0] = entryname;
+ grub_normal_add_menu_entry (1, args, NULL, NULL, NULL,
+ NULL, NULL, entrysrc, 0);
+ grub_free (args);
+ }
+
+ grub_normal_parse_line (suffix, legacy_file_getline, NULL);
+ grub_print_error ();
+ grub_free (suffix);
+ grub_free (entrysrc);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_legacy_source (struct grub_command *cmd,
+ int argc, char **args)
+{
+ int new_env, extractor;
+ grub_err_t ret;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ extractor = (cmd->name[0] == 'e');
+ new_env = (cmd->name[extractor ? (sizeof ("extract_legacy_entries_") - 1)
+ : (sizeof ("legacy_") - 1)] == 'c');
+
+ if (new_env)
+ grub_cls ();
+
+ if (new_env && !extractor)
+ grub_env_context_open ();
+ if (extractor)
+ grub_env_extractor_open (!new_env);
+
+ ret = legacy_file (args[0]);
+
+ if (new_env)
+ {
+ grub_menu_t menu;
+ menu = grub_env_get_menu ();
+ if (menu && menu->size)
+ grub_show_menu (menu, 1, 0);
+ if (!extractor)
+ grub_env_context_close ();
+ }
+ if (extractor)
+ grub_env_extractor_close (!new_env);
+
+ return ret;
+}
+
+static enum
+ {
+ GUESS_IT, LINUX, MULTIBOOT, KFREEBSD, KNETBSD, KOPENBSD
+ } kernel_type;
+
+static grub_err_t
+grub_cmd_legacy_kernel (struct grub_command *mycmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ int i;
+#ifdef TODO
+ int no_mem_option = 0;
+#endif
+ struct grub_command *cmd;
+ char **cutargs;
+ int cutargc;
+ grub_err_t err = GRUB_ERR_NONE;
+
+ for (i = 0; i < 2; i++)
+ {
+ /* FIXME: really support this. */
+ if (argc >= 1 && grub_strcmp (args[0], "--no-mem-option") == 0)
+ {
+#ifdef TODO
+ no_mem_option = 1;
+#endif
+ argc--;
+ args++;
+ continue;
+ }
+
+ /* linux16 handles both zImages and bzImages. */
+ if (argc >= 1 && (grub_strcmp (args[0], "--type=linux") == 0
+ || grub_strcmp (args[0], "--type=biglinux") == 0))
+ {
+ kernel_type = LINUX;
+ argc--;
+ args++;
+ continue;
+ }
+
+ if (argc >= 1 && grub_strcmp (args[0], "--type=multiboot") == 0)
+ {
+ kernel_type = MULTIBOOT;
+ argc--;
+ args++;
+ continue;
+ }
+
+ if (argc >= 1 && grub_strcmp (args[0], "--type=freebsd") == 0)
+ {
+ kernel_type = KFREEBSD;
+ argc--;
+ args++;
+ continue;
+ }
+
+ if (argc >= 1 && grub_strcmp (args[0], "--type=openbsd") == 0)
+ {
+ kernel_type = KOPENBSD;
+ argc--;
+ args++;
+ continue;
+ }
+
+ if (argc >= 1 && grub_strcmp (args[0], "--type=netbsd") == 0)
+ {
+ kernel_type = KNETBSD;
+ argc--;
+ args++;
+ continue;
+ }
+ }
+
+ if (argc < 2)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ cutargs = grub_calloc (argc - 1, sizeof (cutargs[0]));
+ if (!cutargs)
+ return grub_errno;
+ cutargc = argc - 1;
+ grub_memcpy (cutargs + 1, args + 2, sizeof (cutargs[0]) * (argc - 2));
+ cutargs[0] = args[0];
+
+ do
+ {
+ /* First try Linux. */
+ if (kernel_type == GUESS_IT || kernel_type == LINUX)
+ {
+#ifdef GRUB_MACHINE_PCBIOS
+ cmd = grub_command_find ("linux16");
+#else
+ cmd = grub_command_find ("linux");
+#endif
+ if (cmd)
+ {
+ if (!(cmd->func) (cmd, cutargc, cutargs))
+ {
+ kernel_type = LINUX;
+ goto out;
+ }
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ /* Then multiboot. */
+ if (kernel_type == GUESS_IT || kernel_type == MULTIBOOT)
+ {
+ cmd = grub_command_find ("multiboot");
+ if (cmd)
+ {
+ if (!(cmd->func) (cmd, argc, args))
+ {
+ kernel_type = MULTIBOOT;
+ goto out;
+ }
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ {
+ int bsd_device = -1;
+ int bsd_slice = -1;
+ int bsd_part = -1;
+ {
+ grub_device_t dev;
+ const char *hdbiasstr;
+ int hdbias = 0;
+ hdbiasstr = grub_env_get ("legacy_hdbias");
+ if (hdbiasstr)
+ {
+ hdbias = grub_strtoul (hdbiasstr, 0, 0);
+ grub_errno = GRUB_ERR_NONE;
+ }
+ dev = grub_device_open (0);
+ if (dev && dev->disk
+ && dev->disk->dev->id == GRUB_DISK_DEVICE_BIOSDISK_ID
+ && dev->disk->id >= 0x80 && dev->disk->id <= 0x90)
+ {
+ struct grub_partition *part = dev->disk->partition;
+ bsd_device = dev->disk->id - 0x80 - hdbias;
+ if (part && (grub_strcmp (part->partmap->name, "netbsd") == 0
+ || grub_strcmp (part->partmap->name, "openbsd") == 0
+ || grub_strcmp (part->partmap->name, "bsd") == 0))
+ {
+ bsd_part = part->number;
+ part = part->parent;
+ }
+ if (part && grub_strcmp (part->partmap->name, "msdos") == 0)
+ bsd_slice = part->number;
+ }
+ if (dev)
+ grub_device_close (dev);
+ }
+
+ /* k*BSD didn't really work well with grub-legacy. */
+ if (kernel_type == GUESS_IT || kernel_type == KFREEBSD)
+ {
+ char buf[sizeof("adXXXXXXXXXXXXsXXXXXXXXXXXXYYY")];
+ if (bsd_device != -1)
+ {
+ if (bsd_slice != -1 && bsd_part != -1)
+ grub_snprintf(buf, sizeof(buf), "ad%ds%d%c", bsd_device,
+ bsd_slice, 'a' + bsd_part);
+ else if (bsd_slice != -1)
+ grub_snprintf(buf, sizeof(buf), "ad%ds%d", bsd_device,
+ bsd_slice);
+ else
+ grub_snprintf(buf, sizeof(buf), "ad%d", bsd_device);
+ grub_env_set ("kFreeBSD.vfs.root.mountfrom", buf);
+ }
+ else
+ grub_env_unset ("kFreeBSD.vfs.root.mountfrom");
+ cmd = grub_command_find ("kfreebsd");
+ if (cmd)
+ {
+ if (!(cmd->func) (cmd, cutargc, cutargs))
+ {
+ kernel_type = KFREEBSD;
+ goto out;
+ }
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+ {
+ char **bsdargs;
+ int bsdargc;
+ char bsddevname[sizeof ("wdXXXXXXXXXXXXY")];
+ int found = 0;
+
+ if (bsd_device == -1)
+ {
+ bsdargs = cutargs;
+ bsdargc = cutargc;
+ }
+ else
+ {
+ char rbuf[3] = "-r";
+ bsdargc = cutargc + 2;
+ bsdargs = grub_calloc (bsdargc, sizeof (bsdargs[0]));
+ if (!bsdargs)
+ {
+ err = grub_errno;
+ goto out;
+ }
+ grub_memcpy (bsdargs, args, argc * sizeof (bsdargs[0]));
+ bsdargs[argc] = rbuf;
+ bsdargs[argc + 1] = bsddevname;
+ grub_snprintf (bsddevname, sizeof (bsddevname),
+ "wd%d%c", bsd_device,
+ bsd_part != -1 ? bsd_part + 'a' : 'c');
+ }
+ if (kernel_type == GUESS_IT || kernel_type == KNETBSD)
+ {
+ cmd = grub_command_find ("knetbsd");
+ if (cmd)
+ {
+ if (!(cmd->func) (cmd, bsdargc, bsdargs))
+ {
+ kernel_type = KNETBSD;
+ found = 1;
+ goto free_bsdargs;
+ }
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+ if (kernel_type == GUESS_IT || kernel_type == KOPENBSD)
+ {
+ cmd = grub_command_find ("kopenbsd");
+ if (cmd)
+ {
+ if (!(cmd->func) (cmd, bsdargc, bsdargs))
+ {
+ kernel_type = KOPENBSD;
+ found = 1;
+ goto free_bsdargs;
+ }
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+free_bsdargs:
+ if (bsdargs != cutargs)
+ grub_free (bsdargs);
+ if (found)
+ goto out;
+ }
+ }
+ }
+ while (0);
+
+ err = grub_error (GRUB_ERR_BAD_OS, "couldn't load file %s",
+ args[0]);
+out:
+ grub_free (cutargs);
+ return err;
+}
+
+static grub_err_t
+grub_cmd_legacy_initrd (struct grub_command *mycmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ struct grub_command *cmd;
+
+ if (kernel_type == LINUX)
+ {
+#ifdef GRUB_MACHINE_PCBIOS
+ cmd = grub_command_find ("initrd16");
+#else
+ cmd = grub_command_find ("initrd");
+#endif
+ if (!cmd)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"),
+#ifdef GRUB_MACHINE_PCBIOS
+ "initrd16"
+#else
+ "initrd"
+#endif
+ );
+
+ return cmd->func (cmd, argc ? 1 : 0, args);
+ }
+ if (kernel_type == MULTIBOOT)
+ {
+ cmd = grub_command_find ("module");
+ if (!cmd)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"),
+ "module");
+
+ return cmd->func (cmd, argc, args);
+ }
+
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("you need to load the kernel first"));
+}
+
+static grub_err_t
+grub_cmd_legacy_initrdnounzip (struct grub_command *mycmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ struct grub_command *cmd;
+
+ if (kernel_type == LINUX)
+ {
+ cmd = grub_command_find ("initrd16");
+ if (!cmd)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"),
+ "initrd16");
+
+ return cmd->func (cmd, argc, args);
+ }
+ if (kernel_type == MULTIBOOT)
+ {
+ char **newargs;
+ grub_err_t err;
+ char nounzipbuf[10] = "--nounzip";
+
+ cmd = grub_command_find ("module");
+ if (!cmd)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"),
+ "module");
+
+ newargs = grub_calloc (argc + 1, sizeof (newargs[0]));
+ if (!newargs)
+ return grub_errno;
+ grub_memcpy (newargs + 1, args, argc * sizeof (newargs[0]));
+ newargs[0] = nounzipbuf;
+
+ err = cmd->func (cmd, argc + 1, newargs);
+ grub_free (newargs);
+ return err;
+ }
+
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("you need to load the kernel first"));
+}
+
+static grub_err_t
+check_password_deny (const char *user __attribute__ ((unused)),
+ const char *entered __attribute__ ((unused)),
+ void *password __attribute__ ((unused)))
+{
+ return GRUB_ACCESS_DENIED;
+}
+
+#define MD5_HASHLEN 16
+
+struct legacy_md5_password
+{
+ grub_uint8_t *salt;
+ int saltlen;
+ grub_uint8_t hash[MD5_HASHLEN];
+};
+
+static int
+check_password_md5_real (const char *entered,
+ struct legacy_md5_password *pw)
+{
+ grub_size_t enteredlen = grub_strlen (entered);
+ unsigned char alt_result[MD5_HASHLEN];
+ unsigned char *digest;
+ grub_uint8_t *ctx;
+ grub_size_t i;
+ int ret;
+
+ ctx = grub_zalloc (GRUB_MD_MD5->contextsize);
+ if (!ctx)
+ return 0;
+
+ GRUB_MD_MD5->init (ctx);
+ GRUB_MD_MD5->write (ctx, entered, enteredlen);
+ GRUB_MD_MD5->write (ctx, pw->salt + 3, pw->saltlen - 3);
+ GRUB_MD_MD5->write (ctx, entered, enteredlen);
+ digest = GRUB_MD_MD5->read (ctx);
+ GRUB_MD_MD5->final (ctx);
+ grub_memcpy (alt_result, digest, MD5_HASHLEN);
+
+ GRUB_MD_MD5->init (ctx);
+ GRUB_MD_MD5->write (ctx, entered, enteredlen);
+ GRUB_MD_MD5->write (ctx, pw->salt, pw->saltlen); /* include the $1$ header */
+ for (i = enteredlen; i > 16; i -= 16)
+ GRUB_MD_MD5->write (ctx, alt_result, 16);
+ GRUB_MD_MD5->write (ctx, alt_result, i);
+
+ for (i = enteredlen; i > 0; i >>= 1)
+ GRUB_MD_MD5->write (ctx, entered + ((i & 1) ? enteredlen : 0), 1);
+ digest = GRUB_MD_MD5->read (ctx);
+ GRUB_MD_MD5->final (ctx);
+
+ for (i = 0; i < 1000; i++)
+ {
+ grub_memcpy (alt_result, digest, 16);
+
+ GRUB_MD_MD5->init (ctx);
+ if ((i & 1) != 0)
+ GRUB_MD_MD5->write (ctx, entered, enteredlen);
+ else
+ GRUB_MD_MD5->write (ctx, alt_result, 16);
+
+ if (i % 3 != 0)
+ GRUB_MD_MD5->write (ctx, pw->salt + 3, pw->saltlen - 3);
+
+ if (i % 7 != 0)
+ GRUB_MD_MD5->write (ctx, entered, enteredlen);
+
+ if ((i & 1) != 0)
+ GRUB_MD_MD5->write (ctx, alt_result, 16);
+ else
+ GRUB_MD_MD5->write (ctx, entered, enteredlen);
+ digest = GRUB_MD_MD5->read (ctx);
+ GRUB_MD_MD5->final (ctx);
+ }
+
+ ret = (grub_crypto_memcmp (digest, pw->hash, MD5_HASHLEN) == 0);
+ grub_free (ctx);
+ return ret;
+}
+
+static grub_err_t
+check_password_md5 (const char *user,
+ const char *entered,
+ void *password)
+{
+ if (!check_password_md5_real (entered, password))
+ return GRUB_ACCESS_DENIED;
+
+ grub_auth_authenticate (user);
+
+ return GRUB_ERR_NONE;
+}
+
+static inline int
+ib64t (char c)
+{
+ if (c == '.')
+ return 0;
+ if (c == '/')
+ return 1;
+ if (c >= '0' && c <= '9')
+ return c - '0' + 2;
+ if (c >= 'A' && c <= 'Z')
+ return c - 'A' + 12;
+ if (c >= 'a' && c <= 'z')
+ return c - 'a' + 38;
+ return -1;
+}
+
+static struct legacy_md5_password *
+parse_legacy_md5 (int argc, char **args)
+{
+ const char *salt, *saltend;
+ struct legacy_md5_password *pw = NULL;
+ int i;
+ const char *p;
+
+ if (grub_memcmp (args[0], "--md5", sizeof ("--md5")) != 0)
+ goto fail;
+ if (argc == 1)
+ goto fail;
+ if (grub_strlen(args[1]) <= 3)
+ goto fail;
+ salt = args[1];
+ saltend = grub_strchr (salt + 3, '$');
+ if (!saltend)
+ goto fail;
+ pw = grub_malloc (sizeof (*pw));
+ if (!pw)
+ goto fail;
+
+ p = saltend + 1;
+ for (i = 0; i < 5; i++)
+ {
+ int n;
+ grub_uint32_t w = 0;
+
+ for (n = 0; n < 4; n++)
+ {
+ int ww = ib64t(*p++);
+ if (ww == -1)
+ goto fail;
+ w |= ww << (n * 6);
+ }
+ pw->hash[i == 4 ? 5 : 12+i] = w & 0xff;
+ pw->hash[6+i] = (w >> 8) & 0xff;
+ pw->hash[i] = (w >> 16) & 0xff;
+ }
+ {
+ int n;
+ grub_uint32_t w = 0;
+ for (n = 0; n < 2; n++)
+ {
+ int ww = ib64t(*p++);
+ if (ww == -1)
+ goto fail;
+ w |= ww << (6 * n);
+ }
+ if (w >= 0x100)
+ goto fail;
+ pw->hash[11] = w;
+ }
+
+ pw->saltlen = saltend - salt;
+ pw->salt = (grub_uint8_t *) grub_strndup (salt, pw->saltlen);
+ if (!pw->salt)
+ goto fail;
+
+ return pw;
+
+ fail:
+ grub_free (pw);
+ return NULL;
+}
+
+static grub_err_t
+grub_cmd_legacy_password (struct grub_command *mycmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ struct legacy_md5_password *pw = NULL;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+ if (args[0][0] != '-' || args[0][1] != '-')
+ return grub_normal_set_password ("legacy", args[0]);
+
+ pw = parse_legacy_md5 (argc, args);
+
+ if (pw)
+ return grub_auth_register_authentication ("legacy", check_password_md5, pw);
+ else
+ /* This is to imitate minor difference between grub-legacy in GRUB2.
+ If 2 password commands are executed in a row and second one fails
+ on GRUB2 the password of first one is used, whereas in grub-legacy
+ authenthication is denied. In case of no password command was executed
+ early both versions deny any access. */
+ return grub_auth_register_authentication ("legacy", check_password_deny,
+ NULL);
+}
+
+int
+grub_legacy_check_md5_password (int argc, char **args,
+ char *entered)
+{
+ struct legacy_md5_password *pw = NULL;
+ int ret;
+
+ if (args[0][0] != '-' || args[0][1] != '-')
+ {
+ char correct[GRUB_AUTH_MAX_PASSLEN];
+
+ grub_memset (correct, 0, sizeof (correct));
+ grub_strncpy (correct, args[0], sizeof (correct));
+
+ return grub_crypto_memcmp (entered, correct, GRUB_AUTH_MAX_PASSLEN) == 0;
+ }
+
+ pw = parse_legacy_md5 (argc, args);
+
+ if (!pw)
+ return 0;
+
+ ret = check_password_md5_real (entered, pw);
+ grub_free (pw);
+ return ret;
+}
+
+static grub_err_t
+grub_cmd_legacy_check_password (struct grub_command *mycmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ char entered[GRUB_AUTH_MAX_PASSLEN];
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+ grub_puts_ (N_("Enter password: "));
+ if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN))
+ return GRUB_ACCESS_DENIED;
+
+ if (!grub_legacy_check_md5_password (argc, args,
+ entered))
+ return GRUB_ACCESS_DENIED;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd_source, cmd_configfile;
+static grub_command_t cmd_source_extract, cmd_configfile_extract;
+static grub_command_t cmd_kernel, cmd_initrd, cmd_initrdnounzip;
+static grub_command_t cmd_password, cmd_check_password;
+
+GRUB_MOD_INIT(legacycfg)
+{
+ cmd_source
+ = grub_register_command ("legacy_source",
+ grub_cmd_legacy_source,
+ N_("FILE"),
+ /* TRANSLATORS: "legacy config" means
+ "config as used by grub-legacy". */
+ N_("Parse legacy config in same context"));
+ cmd_configfile
+ = grub_register_command ("legacy_configfile",
+ grub_cmd_legacy_source,
+ N_("FILE"),
+ N_("Parse legacy config in new context"));
+ cmd_source_extract
+ = grub_register_command ("extract_legacy_entries_source",
+ grub_cmd_legacy_source,
+ N_("FILE"),
+ N_("Parse legacy config in same context taking only menu entries"));
+ cmd_configfile_extract
+ = grub_register_command ("extract_legacy_entries_configfile",
+ grub_cmd_legacy_source,
+ N_("FILE"),
+ N_("Parse legacy config in new context taking only menu entries"));
+
+ cmd_kernel = grub_register_command ("legacy_kernel",
+ grub_cmd_legacy_kernel,
+ N_("[--no-mem-option] [--type=TYPE] FILE [ARG ...]"),
+ N_("Simulate grub-legacy `kernel' command"));
+
+ cmd_initrd = grub_register_command ("legacy_initrd",
+ grub_cmd_legacy_initrd,
+ N_("FILE [ARG ...]"),
+ N_("Simulate grub-legacy `initrd' command"));
+ cmd_initrdnounzip = grub_register_command ("legacy_initrd_nounzip",
+ grub_cmd_legacy_initrdnounzip,
+ N_("FILE [ARG ...]"),
+ N_("Simulate grub-legacy `modulenounzip' command"));
+
+ cmd_password = grub_register_command ("legacy_password",
+ grub_cmd_legacy_password,
+ N_("[--md5] PASSWD [FILE]"),
+ N_("Simulate grub-legacy `password' command"));
+
+ cmd_check_password = grub_register_command ("legacy_check_password",
+ grub_cmd_legacy_check_password,
+ N_("[--md5] PASSWD [FILE]"),
+ N_("Simulate grub-legacy `password' command in menu entry mode"));
+
+}
+
+GRUB_MOD_FINI(legacycfg)
+{
+ grub_unregister_command (cmd_source);
+ grub_unregister_command (cmd_configfile);
+ grub_unregister_command (cmd_source_extract);
+ grub_unregister_command (cmd_configfile_extract);
+
+ grub_unregister_command (cmd_kernel);
+ grub_unregister_command (cmd_initrd);
+ grub_unregister_command (cmd_initrdnounzip);
+
+ grub_unregister_command (cmd_password);
+ grub_unregister_command (cmd_check_password);
+}
diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c
new file mode 100644
index 0000000..3fd664a
--- /dev/null
+++ b/grub-core/commands/loadenv.c
@@ -0,0 +1,470 @@
+/* loadenv.c - command to load/save environment variable. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008,2009,2010 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/mm.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/misc.h>
+#include <grub/env.h>
+#include <grub/partition.h>
+#include <grub/lib/envblk.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =
+ {
+ /* TRANSLATORS: This option is used to override default filename
+ for loading and storing environment. */
+ {"file", 'f', 0, N_("Specify filename."), 0, ARG_TYPE_PATHNAME},
+ {"skip-sig", 's', 0,
+ N_("Skip signature-checking of the environment file."), 0, ARG_TYPE_NONE},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+/* Opens 'filename' with compression filters disabled. Optionally disables the
+ PUBKEY filter (that insists upon properly signed files) as well. PUBKEY
+ filter is restored before the function returns. */
+static grub_file_t
+open_envblk_file (char *filename,
+ enum grub_file_type type)
+{
+ grub_file_t file;
+ char *buf = 0;
+
+ if (! filename)
+ {
+ const char *prefix;
+ int len;
+
+ prefix = grub_env_get ("prefix");
+ if (! prefix)
+ {
+ grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix");
+ return 0;
+ }
+
+ len = grub_strlen (prefix);
+ buf = grub_malloc (len + 1 + sizeof (GRUB_ENVBLK_DEFCFG));
+ if (! buf)
+ return 0;
+ filename = buf;
+
+ grub_strcpy (filename, prefix);
+ filename[len] = '/';
+ grub_strcpy (filename + len + 1, GRUB_ENVBLK_DEFCFG);
+ }
+
+ file = grub_file_open (filename, type);
+
+ grub_free (buf);
+ return file;
+}
+
+static grub_envblk_t
+read_envblk_file (grub_file_t file)
+{
+ grub_off_t offset = 0;
+ char *buf;
+ grub_size_t size = grub_file_size (file);
+ grub_envblk_t envblk;
+
+ buf = grub_malloc (size);
+ if (! buf)
+ return 0;
+
+ while (size > 0)
+ {
+ grub_ssize_t ret;
+
+ ret = grub_file_read (file, buf + offset, size);
+ if (ret <= 0)
+ {
+ grub_free (buf);
+ return 0;
+ }
+
+ size -= ret;
+ offset += ret;
+ }
+
+ envblk = grub_envblk_open (buf, offset);
+ if (! envblk)
+ {
+ grub_free (buf);
+ grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block");
+ return 0;
+ }
+
+ return envblk;
+}
+
+struct grub_env_whitelist
+{
+ grub_size_t len;
+ char **list;
+};
+typedef struct grub_env_whitelist grub_env_whitelist_t;
+
+static int
+test_whitelist_membership (const char* name,
+ const grub_env_whitelist_t* whitelist)
+{
+ grub_size_t i;
+
+ for (i = 0; i < whitelist->len; i++)
+ if (grub_strcmp (name, whitelist->list[i]) == 0)
+ return 1; /* found it */
+
+ return 0; /* not found */
+}
+
+/* Helper for grub_cmd_load_env. */
+static int
+set_var (const char *name, const char *value, void *whitelist)
+{
+ if (! whitelist)
+ {
+ grub_env_set (name, value);
+ return 0;
+ }
+
+ if (test_whitelist_membership (name,
+ (const grub_env_whitelist_t *) whitelist))
+ grub_env_set (name, value);
+
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ grub_file_t file;
+ grub_envblk_t envblk;
+ grub_env_whitelist_t whitelist;
+
+ whitelist.len = argc;
+ whitelist.list = args;
+
+ /* state[0] is the -f flag; state[1] is the --skip-sig flag */
+ file = open_envblk_file ((state[0].set) ? state[0].arg : 0,
+ GRUB_FILE_TYPE_LOADENV
+ | (state[1].set
+ ? GRUB_FILE_TYPE_SKIP_SIGNATURE : GRUB_FILE_TYPE_NONE));
+ if (! file)
+ return grub_errno;
+
+ envblk = read_envblk_file (file);
+ if (! envblk)
+ goto fail;
+
+ /* argc > 0 indicates caller provided a whitelist of variables to read. */
+ grub_envblk_iterate (envblk, argc > 0 ? &whitelist : 0, set_var);
+ grub_envblk_close (envblk);
+
+ fail:
+ grub_file_close (file);
+ return grub_errno;
+}
+
+/* Print all variables in current context. */
+static int
+print_var (const char *name, const char *value,
+ void *hook_data __attribute__ ((unused)))
+{
+ grub_printf ("%s=%s\n", name, value);
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_list_env (grub_extcmd_context_t ctxt,
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ struct grub_arg_list *state = ctxt->state;
+ grub_file_t file;
+ grub_envblk_t envblk;
+
+ file = open_envblk_file ((state[0].set) ? state[0].arg : 0,
+ GRUB_FILE_TYPE_LOADENV
+ | (state[1].set
+ ? GRUB_FILE_TYPE_SKIP_SIGNATURE : GRUB_FILE_TYPE_NONE));
+ if (! file)
+ return grub_errno;
+
+ envblk = read_envblk_file (file);
+ if (! envblk)
+ goto fail;
+
+ grub_envblk_iterate (envblk, NULL, print_var);
+ grub_envblk_close (envblk);
+
+ fail:
+ grub_file_close (file);
+ return grub_errno;
+}
+
+/* Used to maintain a variable length of blocklists internally. */
+struct blocklist
+{
+ grub_disk_addr_t sector;
+ unsigned offset;
+ unsigned length;
+ struct blocklist *next;
+};
+
+static void
+free_blocklists (struct blocklist *p)
+{
+ struct blocklist *q;
+
+ for (; p; p = q)
+ {
+ q = p->next;
+ grub_free (p);
+ }
+}
+
+static grub_err_t
+check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
+ grub_file_t file)
+{
+ grub_size_t total_length;
+ grub_size_t index;
+ grub_disk_t disk;
+ grub_disk_addr_t part_start;
+ struct blocklist *p;
+ char *buf;
+
+ /* Sanity checks. */
+ total_length = 0;
+ for (p = blocklists; p; p = p->next)
+ {
+ struct blocklist *q;
+ /* Check if any pair of blocks overlap. */
+ for (q = p->next; q; q = q->next)
+ {
+ grub_disk_addr_t s1, s2;
+ grub_disk_addr_t e1, e2;
+
+ s1 = p->sector;
+ e1 = s1 + ((p->length + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
+
+ s2 = q->sector;
+ e2 = s2 + ((q->length + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
+
+ if (s1 < e2 && s2 < e1)
+ {
+ /* This might be actually valid, but it is unbelievable that
+ any filesystem makes such a silly allocation. */
+ return grub_error (GRUB_ERR_BAD_FS, "malformed file");
+ }
+ }
+
+ total_length += p->length;
+ }
+
+ if (total_length != grub_file_size (file))
+ {
+ /* Maybe sparse, unallocated sectors. No way in GRUB. */
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "sparse file not allowed");
+ }
+
+ /* One more sanity check. Re-read all sectors by blocklists, and compare
+ those with the data read via a file. */
+ disk = file->device->disk;
+
+ part_start = grub_partition_get_start (disk->partition);
+
+ buf = grub_envblk_buffer (envblk);
+ char *blockbuf = NULL;
+ grub_size_t blockbuf_len = 0;
+ for (p = blocklists, index = 0; p; index += p->length, p = p->next)
+ {
+ if (p->length > blockbuf_len)
+ {
+ grub_free (blockbuf);
+ blockbuf_len = 2 * p->length;
+ blockbuf = grub_malloc (blockbuf_len);
+ if (!blockbuf)
+ return grub_errno;
+ }
+
+ if (grub_disk_read (disk, p->sector - part_start,
+ p->offset, p->length, blockbuf))
+ return grub_errno;
+
+ if (grub_memcmp (buf + index, blockbuf, p->length) != 0)
+ return grub_error (GRUB_ERR_FILE_READ_ERROR, "invalid blocklist");
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static int
+write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
+ grub_file_t file)
+{
+ char *buf;
+ grub_disk_t disk;
+ grub_disk_addr_t part_start;
+ struct blocklist *p;
+ grub_size_t index;
+
+ buf = grub_envblk_buffer (envblk);
+ disk = file->device->disk;
+ part_start = grub_partition_get_start (disk->partition);
+
+ index = 0;
+ for (p = blocklists; p; index += p->length, p = p->next)
+ {
+ if (grub_disk_write (disk, p->sector - part_start,
+ p->offset, p->length, buf + index))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Context for grub_cmd_save_env. */
+struct grub_cmd_save_env_ctx
+{
+ struct blocklist *head, *tail;
+};
+
+/* Store blocklists in a linked list. */
+static void
+save_env_read_hook (grub_disk_addr_t sector, unsigned offset, unsigned length,
+ void *data)
+{
+ struct grub_cmd_save_env_ctx *ctx = data;
+ struct blocklist *block;
+
+ block = grub_malloc (sizeof (*block));
+ if (! block)
+ return;
+
+ block->sector = sector;
+ block->offset = offset;
+ block->length = length;
+
+ /* Slightly complicated, because the list should be FIFO. */
+ block->next = 0;
+ if (ctx->tail)
+ ctx->tail->next = block;
+ ctx->tail = block;
+ if (! ctx->head)
+ ctx->head = block;
+}
+
+static grub_err_t
+grub_cmd_save_env (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ grub_file_t file;
+ grub_envblk_t envblk;
+ struct grub_cmd_save_env_ctx ctx = {
+ .head = 0,
+ .tail = 0
+ };
+
+ if (! argc)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no variable is specified");
+
+ file = open_envblk_file ((state[0].set) ? state[0].arg : 0,
+ GRUB_FILE_TYPE_SAVEENV
+ | GRUB_FILE_TYPE_SKIP_SIGNATURE);
+ if (! file)
+ return grub_errno;
+
+ if (! file->device->disk)
+ {
+ grub_file_close (file);
+ return grub_error (GRUB_ERR_BAD_DEVICE, "disk device required");
+ }
+
+ file->read_hook = save_env_read_hook;
+ file->read_hook_data = &ctx;
+ envblk = read_envblk_file (file);
+ file->read_hook = 0;
+ if (! envblk)
+ goto fail;
+
+ if (check_blocklists (envblk, ctx.head, file))
+ goto fail;
+
+ while (argc)
+ {
+ const char *value;
+
+ value = grub_env_get (args[0]);
+ if (value)
+ {
+ if (! grub_envblk_set (envblk, args[0], value))
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "environment block too small");
+ goto fail;
+ }
+ }
+ else
+ grub_envblk_delete (envblk, args[0]);
+
+ argc--;
+ args++;
+ }
+
+ write_blocklists (envblk, ctx.head, file);
+
+ fail:
+ if (envblk)
+ grub_envblk_close (envblk);
+ free_blocklists (ctx.head);
+ grub_file_close (file);
+ return grub_errno;
+}
+
+static grub_extcmd_t cmd_load, cmd_list, cmd_save;
+
+GRUB_MOD_INIT(loadenv)
+{
+ cmd_load =
+ grub_register_extcmd ("load_env", grub_cmd_load_env, 0,
+ N_("[-f FILE] [-s|--skip-sig] [variable_name_to_whitelist] [...]"),
+ N_("Load variables from environment block file."),
+ options);
+ cmd_list =
+ grub_register_extcmd ("list_env", grub_cmd_list_env, 0, N_("[-f FILE]"),
+ N_("List variables from environment block file."),
+ options);
+ cmd_save =
+ grub_register_extcmd ("save_env", grub_cmd_save_env, 0,
+ N_("[-f FILE] variable_name [...]"),
+ N_("Save variables to environment block file."),
+ options);
+}
+
+GRUB_MOD_FINI(loadenv)
+{
+ grub_unregister_extcmd (cmd_load);
+ grub_unregister_extcmd (cmd_list);
+ grub_unregister_extcmd (cmd_save);
+}
diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c
new file mode 100644
index 0000000..8e98c73
--- /dev/null
+++ b/grub-core/commands/ls.c
@@ -0,0 +1,302 @@
+/* ls.c - command to list files and devices */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2005,2007,2008,2009 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/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/disk.h>
+#include <grub/device.h>
+#include <grub/term.h>
+#include <grub/partition.h>
+#include <grub/file.h>
+#include <grub/normal.h>
+#include <grub/extcmd.h>
+#include <grub/datetime.h>
+#include <grub/i18n.h>
+#include <grub/net.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =
+ {
+ {"long", 'l', 0, N_("Show a long list with more detailed information."), 0, 0},
+ {"human-readable", 'h', 0, N_("Print sizes in a human readable format."), 0, 0},
+ {"all", 'a', 0, N_("List all files."), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+/* Helper for grub_ls_list_devices. */
+static int
+grub_ls_print_devices (const char *name, void *data)
+{
+ int *longlist = data;
+
+ if (*longlist)
+ grub_normal_print_device_info (name);
+ else
+ grub_printf ("(%s) ", name);
+
+ return 0;
+}
+
+static grub_err_t
+grub_ls_list_devices (int longlist)
+{
+ grub_device_iterate (grub_ls_print_devices, &longlist);
+ grub_xputs ("\n");
+
+#if 0
+ {
+ grub_net_app_level_t proto;
+ int first = 1;
+ FOR_NET_APP_LEVEL (proto)
+ {
+ if (first)
+ grub_puts_ (N_("Network protocols:"));
+ first = 0;
+ grub_printf ("%s ", proto->name);
+ }
+ grub_xputs ("\n");
+ }
+#endif
+
+ grub_refresh ();
+
+ return 0;
+}
+
+/* Context for grub_ls_list_files. */
+struct grub_ls_list_files_ctx
+{
+ char *dirname;
+ int all;
+ int human;
+};
+
+/* Helper for grub_ls_list_files. */
+static int
+print_files (const char *filename, const struct grub_dirhook_info *info,
+ void *data)
+{
+ struct grub_ls_list_files_ctx *ctx = data;
+
+ if (ctx->all || filename[0] != '.')
+ grub_printf ("%s%s ", filename, info->dir ? "/" : "");
+
+ return 0;
+}
+
+/* Helper for grub_ls_list_files. */
+static int
+print_files_long (const char *filename, const struct grub_dirhook_info *info,
+ void *data)
+{
+ struct grub_ls_list_files_ctx *ctx = data;
+
+ if ((! ctx->all) && (filename[0] == '.'))
+ return 0;
+
+ if (! info->dir)
+ {
+ grub_file_t file;
+ char *pathname;
+
+ if (ctx->dirname[grub_strlen (ctx->dirname) - 1] == '/')
+ pathname = grub_xasprintf ("%s%s", ctx->dirname, filename);
+ else
+ pathname = grub_xasprintf ("%s/%s", ctx->dirname, filename);
+
+ if (!pathname)
+ return 1;
+
+ /* XXX: For ext2fs symlinks are detected as files while they
+ should be reported as directories. */
+ file = grub_file_open (pathname, GRUB_FILE_TYPE_GET_SIZE
+ | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (! file)
+ {
+ grub_errno = 0;
+ grub_free (pathname);
+ return 0;
+ }
+
+ if (! ctx->human)
+ grub_printf ("%-12llu", (unsigned long long) file->size);
+ else
+ grub_printf ("%-12s", grub_get_human_size (file->size,
+ GRUB_HUMAN_SIZE_SHORT));
+ grub_file_close (file);
+ grub_free (pathname);
+ }
+ else
+ grub_printf ("%-12s", _("DIR"));
+
+ if (info->mtimeset)
+ {
+ struct grub_datetime datetime;
+ grub_unixtime2datetime (info->mtime, &datetime);
+ if (ctx->human)
+ grub_printf (" %d-%02d-%02d %02d:%02d:%02d %-11s ",
+ datetime.year, datetime.month, datetime.day,
+ datetime.hour, datetime.minute,
+ datetime.second,
+ grub_get_weekday_name (&datetime));
+ else
+ grub_printf (" %04d%02d%02d%02d%02d%02d ",
+ datetime.year, datetime.month,
+ datetime.day, datetime.hour,
+ datetime.minute, datetime.second);
+ }
+ grub_printf ("%s%s\n", filename, info->dir ? "/" : "");
+
+ return 0;
+}
+
+static grub_err_t
+grub_ls_list_files (char *dirname, int longlist, int all, int human)
+{
+ char *device_name;
+ grub_fs_t fs;
+ const char *path;
+ grub_device_t dev;
+
+ device_name = grub_file_get_device_name (dirname);
+ dev = grub_device_open (device_name);
+ if (! dev)
+ goto fail;
+
+ fs = grub_fs_probe (dev);
+ path = grub_strchr (dirname, ')');
+ if (! path)
+ path = dirname;
+ else
+ path++;
+
+ if (! path && ! device_name)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument");
+ goto fail;
+ }
+
+ if (! *path && device_name)
+ {
+ if (grub_errno == GRUB_ERR_UNKNOWN_FS)
+ grub_errno = GRUB_ERR_NONE;
+
+#ifdef GRUB_MACHINE_IEEE1275
+ /*
+ * Close device to prevent a double open in grub_normal_print_device_info().
+ * Otherwise it may lead to hangs on some IEEE 1275 platforms.
+ */
+ grub_device_close (dev);
+ dev = NULL;
+#endif
+
+ grub_normal_print_device_info (device_name);
+ }
+ else if (fs)
+ {
+ struct grub_ls_list_files_ctx ctx = {
+ .dirname = dirname,
+ .all = all,
+ .human = human
+ };
+
+ if (longlist)
+ (fs->fs_dir) (dev, path, print_files_long, &ctx);
+ else
+ (fs->fs_dir) (dev, path, print_files, &ctx);
+
+ if (grub_errno == GRUB_ERR_BAD_FILE_TYPE
+ && path[grub_strlen (path) - 1] != '/')
+ {
+ /* PATH might be a regular file. */
+ char *p;
+ grub_file_t file;
+ struct grub_dirhook_info info;
+ grub_errno = 0;
+
+ file = grub_file_open (dirname, GRUB_FILE_TYPE_GET_SIZE
+ | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (! file)
+ goto fail;
+
+ grub_file_close (file);
+
+ p = grub_strrchr (dirname, '/') + 1;
+ dirname = grub_strndup (dirname, p - dirname);
+ if (! dirname)
+ goto fail;
+
+ all = 1;
+ grub_memset (&info, 0, sizeof (info));
+ if (longlist)
+ print_files_long (p, &info, &ctx);
+ else
+ print_files (p, &info, &ctx);
+
+ grub_free (dirname);
+ }
+
+ if (grub_errno == GRUB_ERR_NONE)
+ grub_xputs ("\n");
+
+ grub_refresh ();
+ }
+
+ fail:
+ if (dev)
+ grub_device_close (dev);
+
+ grub_free (device_name);
+
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_ls (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ int i;
+
+ if (argc == 0)
+ grub_ls_list_devices (state[0].set);
+ else
+ for (i = 0; i < argc; i++)
+ grub_ls_list_files (args[i], state[0].set, state[2].set,
+ state[1].set);
+
+ return 0;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(ls)
+{
+ cmd = grub_register_extcmd ("ls", grub_cmd_ls, 0,
+ N_("[-l|-h|-a] [FILE ...]"),
+ N_("List devices and files."), options);
+}
+
+GRUB_MOD_FINI(ls)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/lsacpi.c b/grub-core/commands/lsacpi.c
new file mode 100644
index 0000000..0824914
--- /dev/null
+++ b/grub-core/commands/lsacpi.c
@@ -0,0 +1,314 @@
+/* acpi.c - Display acpi tables. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/normal.h>
+#include <grub/acpi.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+#include <grub/dl.h>
+
+#pragma GCC diagnostic ignored "-Wcast-align"
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static void
+print_strn (grub_uint8_t *str, grub_size_t len)
+{
+ for (; *str && len; str++, len--)
+ grub_printf ("%c", *str);
+ for (len++; len; len--)
+ grub_printf (" ");
+}
+
+#define print_field(x) print_strn(x, sizeof (x))
+
+static void
+disp_acpi_table (struct grub_acpi_table_header *t)
+{
+ print_field (t->signature);
+ grub_printf ("%4" PRIuGRUB_UINT32_T "B rev=%u chksum=0x%02x (%s) OEM=", t->length, t->revision, t->checksum,
+ grub_byte_checksum (t, t->length) == 0 ? "valid" : "invalid");
+ print_field (t->oemid);
+ print_field (t->oemtable);
+ grub_printf ("OEMrev=%08" PRIxGRUB_UINT32_T " ", t->oemrev);
+ print_field (t->creator_id);
+ grub_printf (" %08" PRIxGRUB_UINT32_T "\n", t->creator_rev);
+}
+
+static void
+disp_madt_table (struct grub_acpi_madt *t)
+{
+ struct grub_acpi_madt_entry_header *d;
+ grub_uint32_t len;
+
+ disp_acpi_table (&t->hdr);
+ grub_printf ("Local APIC=%08" PRIxGRUB_UINT32_T " Flags=%08"
+ PRIxGRUB_UINT32_T "\n",
+ t->lapic_addr, t->flags);
+ len = t->hdr.length - sizeof (struct grub_acpi_madt);
+ d = t->entries;
+ for (;len > 0; len -= d->len, d = (void *) ((grub_uint8_t *) d + d->len))
+ {
+ switch (d->type)
+ {
+ case GRUB_ACPI_MADT_ENTRY_TYPE_LAPIC:
+ {
+ struct grub_acpi_madt_entry_lapic *dt = (void *) d;
+ grub_printf (" LAPIC ACPI_ID=%02x APIC_ID=%02x Flags=%08x\n",
+ dt->acpiid, dt->apicid, dt->flags);
+ if (dt->hdr.len != sizeof (*dt))
+ grub_printf (" table size mismatch %d != %d\n", dt->hdr.len,
+ (int) sizeof (*dt));
+ break;
+ }
+
+ case GRUB_ACPI_MADT_ENTRY_TYPE_IOAPIC:
+ {
+ struct grub_acpi_madt_entry_ioapic *dt = (void *) d;
+ grub_printf (" IOAPIC ID=%02x address=%08x GSI=%08x\n",
+ dt->id, dt->address, dt->global_sys_interrupt);
+ if (dt->hdr.len != sizeof (*dt))
+ grub_printf (" table size mismatch %d != %d\n", dt->hdr.len,
+ (int) sizeof (*dt));
+ if (dt->pad)
+ grub_printf (" non-zero pad: %02x\n", dt->pad);
+ break;
+ }
+
+ case GRUB_ACPI_MADT_ENTRY_TYPE_INTERRUPT_OVERRIDE:
+ {
+ struct grub_acpi_madt_entry_interrupt_override *dt = (void *) d;
+ grub_printf (" Int Override bus=%x src=%x GSI=%08x Flags=%04x\n",
+ dt->bus, dt->source, dt->global_sys_interrupt,
+ dt->flags);
+ if (dt->hdr.len != sizeof (*dt))
+ grub_printf (" table size mismatch %d != %d\n", dt->hdr.len,
+ (int) sizeof (*dt));
+ }
+ break;
+
+ case GRUB_ACPI_MADT_ENTRY_TYPE_LAPIC_NMI:
+ {
+ struct grub_acpi_madt_entry_lapic_nmi *dt = (void *) d;
+ grub_printf (" LAPIC_NMI ACPI_ID=%02x Flags=%04x lint=%02x\n",
+ dt->acpiid, dt->flags, dt->lint);
+ if (dt->hdr.len != sizeof (*dt))
+ grub_printf (" table size mismatch %d != %d\n", dt->hdr.len,
+ (int) sizeof (*dt));
+ break;
+ }
+
+ case GRUB_ACPI_MADT_ENTRY_TYPE_SAPIC:
+ {
+ struct grub_acpi_madt_entry_sapic *dt = (void *) d;
+ grub_printf (" IOSAPIC Id=%02x GSI=%08x Addr=%016" PRIxGRUB_UINT64_T
+ "\n",
+ dt->id, dt->global_sys_interrupt_base,
+ dt->addr);
+ if (dt->hdr.len != sizeof (*dt))
+ grub_printf (" table size mismatch %d != %d\n", dt->hdr.len,
+ (int) sizeof (*dt));
+ if (dt->pad)
+ grub_printf (" non-zero pad: %02x\n", dt->pad);
+
+ }
+ break;
+ case GRUB_ACPI_MADT_ENTRY_TYPE_LSAPIC:
+ {
+ struct grub_acpi_madt_entry_lsapic *dt = (void *) d;
+ grub_printf (" LSAPIC ProcId=%02x ID=%02x EID=%02x Flags=%x",
+ dt->cpu_id, dt->id, dt->eid, dt->flags);
+ if (dt->flags & GRUB_ACPI_MADT_ENTRY_SAPIC_FLAGS_ENABLED)
+ grub_printf (" Enabled\n");
+ else
+ grub_printf (" Disabled\n");
+ if (d->len > sizeof (struct grub_acpi_madt_entry_sapic))
+ grub_printf (" UID val=%08x, Str=%s\n", dt->cpu_uid,
+ dt->cpu_uid_str);
+ if (dt->hdr.len != sizeof (*dt) + grub_strlen ((char *) dt->cpu_uid_str) + 1)
+ grub_printf (" table size mismatch %d != %d\n", dt->hdr.len,
+ (int) sizeof (*dt));
+ if (dt->pad[0] || dt->pad[1] || dt->pad[2])
+ grub_printf (" non-zero pad: %02x%02x%02x\n", dt->pad[0], dt->pad[1], dt->pad[2]);
+ }
+ break;
+ case GRUB_ACPI_MADT_ENTRY_TYPE_PLATFORM_INT_SOURCE:
+ {
+ struct grub_acpi_madt_entry_platform_int_source *dt = (void *) d;
+ static const char * const platint_type[] =
+ {"Nul", "PMI", "INIT", "CPEI"};
+
+ grub_printf (" Platform INT flags=%04x type=%02x (%s)"
+ " ID=%02x EID=%02x\n",
+ dt->flags, dt->inttype,
+ (dt->inttype < ARRAY_SIZE (platint_type))
+ ? platint_type[dt->inttype] : "??", dt->cpu_id,
+ dt->cpu_eid);
+ grub_printf (" IOSAPIC Vec=%02x GSI=%08x source flags=%08x\n",
+ dt->sapic_vector, dt->global_sys_int, dt->src_flags);
+ }
+ break;
+ default:
+ grub_printf (" type=%x l=%u ", d->type, d->len);
+ grub_printf (" ??\n");
+ }
+ }
+}
+
+static void
+disp_acpi_xsdt_table (struct grub_acpi_table_header *t)
+{
+ grub_uint32_t len;
+ grub_uint64_t *desc;
+
+ disp_acpi_table (t);
+ len = t->length - sizeof (*t);
+ desc = (grub_uint64_t *) (t + 1);
+ for (; len >= sizeof (*desc); desc++, len -= sizeof (*desc))
+ {
+#if GRUB_CPU_SIZEOF_VOID_P == 4
+ if (*desc >= (1ULL << 32))
+ {
+ grub_printf ("Unreachable table\n");
+ continue;
+ }
+#endif
+ t = (struct grub_acpi_table_header *) (grub_addr_t) *desc;
+
+ if (t == NULL)
+ continue;
+
+ if (grub_memcmp (t->signature, GRUB_ACPI_MADT_SIGNATURE,
+ sizeof (t->signature)) == 0)
+ disp_madt_table ((struct grub_acpi_madt *) t);
+ else
+ disp_acpi_table (t);
+ }
+}
+
+static void
+disp_acpi_rsdt_table (struct grub_acpi_table_header *t)
+{
+ grub_uint32_t len;
+ grub_uint32_t *desc;
+
+ disp_acpi_table (t);
+ len = t->length - sizeof (*t);
+ desc = (grub_uint32_t *) (t + 1);
+ for (; len >= sizeof (*desc); desc++, len -= sizeof (*desc))
+ {
+ t = (struct grub_acpi_table_header *) (grub_addr_t) *desc;
+
+ if (t == NULL)
+ continue;
+
+ if (grub_memcmp (t->signature, GRUB_ACPI_MADT_SIGNATURE,
+ sizeof (t->signature)) == 0)
+ disp_madt_table ((struct grub_acpi_madt *) t);
+ else
+ disp_acpi_table (t);
+ }
+}
+
+static void
+disp_acpi_rsdpv1 (struct grub_acpi_rsdp_v10 *rsdp)
+{
+ print_field (rsdp->signature);
+ grub_printf ("chksum:%02x (%s), OEM-ID: ", rsdp->checksum, grub_byte_checksum (rsdp, sizeof (*rsdp)) == 0 ? "valid" : "invalid");
+ print_field (rsdp->oemid);
+ grub_printf ("rev=%d\n", rsdp->revision);
+ grub_printf ("RSDT=%08" PRIxGRUB_UINT32_T "\n", rsdp->rsdt_addr);
+}
+
+static void
+disp_acpi_rsdpv2 (struct grub_acpi_rsdp_v20 *rsdp)
+{
+ disp_acpi_rsdpv1 (&rsdp->rsdpv1);
+ grub_printf ("len=%d chksum=%02x (%s) XSDT=%016" PRIxGRUB_UINT64_T "\n", rsdp->length, rsdp->checksum, grub_byte_checksum (rsdp, rsdp->length) == 0 ? "valid" : "invalid",
+ rsdp->xsdt_addr);
+ if (rsdp->length != sizeof (*rsdp))
+ grub_printf (" length mismatch %d != %d\n", rsdp->length,
+ (int) sizeof (*rsdp));
+ if (rsdp->reserved[0] || rsdp->reserved[1] || rsdp->reserved[2])
+ grub_printf (" non-zero reserved %02x%02x%02x\n", rsdp->reserved[0], rsdp->reserved[1], rsdp->reserved[2]);
+}
+
+static const struct grub_arg_option options[] = {
+ {"v1", '1', 0, N_("Show version 1 tables only."), 0, ARG_TYPE_NONE},
+ {"v2", '2', 0, N_("Show version 2 and version 3 tables only."), 0, ARG_TYPE_NONE},
+ {0, 0, 0, 0, 0, 0}
+};
+
+static grub_err_t
+grub_cmd_lsacpi (struct grub_extcmd_context *ctxt,
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ if (!ctxt->state[1].set)
+ {
+ struct grub_acpi_rsdp_v10 *rsdp1 = grub_acpi_get_rsdpv1 ();
+ if (!rsdp1)
+ grub_printf ("No RSDPv1\n");
+ else
+ {
+ grub_printf ("RSDPv1 signature:");
+ disp_acpi_rsdpv1 (rsdp1);
+ disp_acpi_rsdt_table ((void *) (grub_addr_t) rsdp1->rsdt_addr);
+ }
+ }
+
+ if (!ctxt->state[0].set)
+ {
+ struct grub_acpi_rsdp_v20 *rsdp2 = grub_acpi_get_rsdpv2 ();
+ if (!rsdp2)
+ grub_printf ("No RSDPv2\n");
+ else
+ {
+#if GRUB_CPU_SIZEOF_VOID_P == 4
+ if (rsdp2->xsdt_addr >= (1ULL << 32))
+ grub_printf ("Unreachable RSDPv2\n");
+ else
+#endif
+ {
+ grub_printf ("RSDPv2 signature:");
+ disp_acpi_rsdpv2 (rsdp2);
+ disp_acpi_xsdt_table ((void *) (grub_addr_t) rsdp2->xsdt_addr);
+ grub_printf ("\n");
+ }
+ }
+ }
+ return GRUB_ERR_NONE;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(lsapi)
+{
+ cmd = grub_register_extcmd ("lsacpi", grub_cmd_lsacpi, 0, "[-1|-2]",
+ N_("Show ACPI information."), options);
+}
+
+GRUB_MOD_FINI(lsacpi)
+{
+ grub_unregister_extcmd (cmd);
+}
+
+
diff --git a/grub-core/commands/lsmmap.c b/grub-core/commands/lsmmap.c
new file mode 100644
index 0000000..816ee47
--- /dev/null
+++ b/grub-core/commands/lsmmap.c
@@ -0,0 +1,85 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/memory.h>
+#include <grub/mm.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#ifndef GRUB_MACHINE_EMU
+static const char *names[] =
+ {
+ [GRUB_MEMORY_AVAILABLE] = N_("available RAM"),
+ [GRUB_MEMORY_RESERVED] = N_("reserved RAM"),
+ /* TRANSLATORS: this refers to memory where ACPI tables are stored
+ and which can be used by OS once it loads ACPI tables. */
+ [GRUB_MEMORY_ACPI] = N_("ACPI reclaimable RAM"),
+ /* TRANSLATORS: this refers to memory which ACPI-compliant OS
+ is required to save accross hibernations. */
+ [GRUB_MEMORY_NVS] = N_("ACPI non-volatile storage RAM"),
+ [GRUB_MEMORY_BADRAM] = N_("faulty RAM (BadRAM)"),
+ [GRUB_MEMORY_PERSISTENT] = N_("persistent RAM"),
+ [GRUB_MEMORY_PERSISTENT_LEGACY] = N_("persistent RAM (legacy)"),
+ [GRUB_MEMORY_COREBOOT_TABLES] = N_("RAM holding coreboot tables"),
+ [GRUB_MEMORY_CODE] = N_("RAM holding firmware code")
+ };
+
+/* Helper for grub_cmd_lsmmap. */
+static int
+lsmmap_hook (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type,
+ void *data __attribute__ ((unused)))
+{
+ if (type < (int) ARRAY_SIZE (names) && type >= 0 && names[type])
+ grub_printf_ (N_("base_addr = 0x%llx, length = 0x%llx, %s\n"),
+ (long long) addr, (long long) size, _(names[type]));
+ else
+ grub_printf_ (N_("base_addr = 0x%llx, length = 0x%llx, type = 0x%x\n"),
+ (long long) addr, (long long) size, type);
+ return 0;
+}
+#endif
+
+static grub_err_t
+grub_cmd_lsmmap (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+
+{
+#ifndef GRUB_MACHINE_EMU
+ grub_machine_mmap_iterate (lsmmap_hook, NULL);
+#endif
+
+ return 0;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(lsmmap)
+{
+ cmd = grub_register_command ("lsmmap", grub_cmd_lsmmap,
+ 0, N_("List memory map provided by firmware."));
+}
+
+GRUB_MOD_FINI(lsmmap)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/lspci.c b/grub-core/commands/lspci.c
new file mode 100644
index 0000000..65213a3
--- /dev/null
+++ b/grub-core/commands/lspci.c
@@ -0,0 +1,238 @@
+/* lspci.c - List PCI devices. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008, 2009 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/pci.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+#include <grub/mm.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+struct grub_pci_classname
+{
+ int class;
+ int subclass;
+ const char *desc;
+};
+
+static const struct grub_pci_classname grub_pci_classes[] =
+ {
+ { 0, 0, "" },
+ { 1, 0, "SCSI Controller" },
+ { 1, 1, "IDE Controller" },
+ { 1, 2, "Floppy Controller" },
+ { 1, 3, "IPI Controller" },
+ { 1, 4, "RAID Controller" },
+ { 1, 6, "SATA Controller" },
+ { 1, 0x80, "Mass storage Controller" },
+ { 2, 0, "Ethernet Controller" },
+ { 2, 1, "Token Ring Controller" },
+ { 2, 2, "FDDI Controller" },
+ { 2, 3, "ATM Controller" },
+ { 2, 4, "ISDN Controller" },
+ { 2, 0x80, "Network controller" },
+ { 3, 0, "VGA Controller" },
+ { 3, 1, "XGA Controller" },
+ { 3, 2, "3D Controller" },
+ { 3, 0x80, "Display Controller" },
+ { 4, 0, "Multimedia Video Device" },
+ { 4, 1, "Multimedia Audio Device" },
+ { 4, 2, "Multimedia Telephony Device" },
+ { 4, 0x80, "Multimedia device" },
+ { 5, 0, "RAM Controller" },
+ { 5, 1, "Flash Memory Controller" },
+ { 5, 0x80, "Memory Controller" },
+ { 6, 0, "Host Bridge" },
+ { 6, 1, "ISA Bridge" },
+ { 6, 2, "EISA Bride" },
+ { 6, 3, "MCA Bridge" },
+ { 6, 4, "PCI-PCI Bridge" },
+ { 6, 5, "PCMCIA Bridge" },
+ { 6, 6, "NuBus Bridge" },
+ { 6, 7, "CardBus Bridge" },
+ { 6, 8, "Raceway Bridge" },
+ { 6, 0x80, "Unknown Bridge" },
+ { 7, 0x80, "Communication controller" },
+ { 8, 0x80, "System hardware" },
+ { 9, 0, "Keyboard Controller" },
+ { 9, 1, "Digitizer" },
+ { 9, 2, "Mouse Controller" },
+ { 9, 3, "Scanner Controller" },
+ { 9, 4, "Gameport Controller" },
+ { 9, 0x80, "Unknown Input Device" },
+ { 10, 0, "Generic Docking Station" },
+ { 10, 0x80, "Unknown Docking Station" },
+ { 11, 0, "80386 Processor" },
+ { 11, 1, "80486 Processor" },
+ { 11, 2, "Pentium Processor" },
+ { 11, 0x10, "Alpha Processor" },
+ { 11, 0x20, "PowerPC Processor" },
+ { 11, 0x30, "MIPS Processor" },
+ { 11, 0x40, "Co-Processor" },
+ { 11, 0x80, "Unknown Processor" },
+ { 12, 3, "USB Controller" },
+ { 12, 0x80, "Serial Bus Controller" },
+ { 13, 0x80, "Wireless Controller" },
+ { 14, 0, "I2O" },
+ { 15, 0, "IrDA Controller" },
+ { 15, 1, "Consumer IR" },
+ { 15, 0x10, "RF-Controller" },
+ { 15, 0x80, "Satellite Communication Controller" },
+ { 16, 0, "Network Decryption" },
+ { 16, 1, "Entertainment Decryption" },
+ { 16, 0x80, "Unknown Decryption Controller" },
+ { 17, 0, "Digital IO Module" },
+ { 17, 0x80, "Unknown Data Input System" },
+ { 0, 0, 0 },
+ };
+
+static const char *
+grub_pci_get_class (int class, int subclass)
+{
+ const struct grub_pci_classname *curr = grub_pci_classes;
+
+ while (curr->desc)
+ {
+ if (curr->class == class && curr->subclass == subclass)
+ return curr->desc;
+ curr++;
+ }
+
+ return 0;
+}
+
+static const struct grub_arg_option options[] =
+ {
+ {"iospace", 'i', 0, "show I/O spaces", 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static int iospace;
+
+static int
+grub_lspci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
+ void *data __attribute__ ((unused)))
+{
+ grub_uint32_t class;
+ const char *sclass;
+ grub_pci_address_t addr;
+ int reg;
+
+ grub_printf ("%02x:%02x.%x %04x:%04x", grub_pci_get_bus (dev),
+ grub_pci_get_device (dev), grub_pci_get_function (dev),
+ pciid & 0xFFFF, pciid >> 16);
+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
+ class = grub_pci_read (addr);
+
+ /* Lookup the class name, if there isn't a specific one,
+ retry with 0x80 to get the generic class name. */
+ sclass = grub_pci_get_class (class >> 24, (class >> 16) & 0xFF);
+ if (! sclass)
+ sclass = grub_pci_get_class (class >> 24, 0x80);
+ if (! sclass)
+ sclass = "";
+
+ grub_printf (" [%04x] %s", (class >> 16) & 0xffff, sclass);
+
+ grub_uint8_t pi = (class >> 8) & 0xff;
+ if (pi)
+ grub_printf (" [PI %02x]", pi);
+
+ grub_printf ("\n");
+
+ if (iospace)
+ {
+ reg = GRUB_PCI_REG_ADDRESSES;
+ while (reg < GRUB_PCI_REG_CIS_POINTER)
+ {
+ grub_uint64_t space;
+ addr = grub_pci_make_address (dev, reg);
+ space = grub_pci_read (addr);
+
+ reg += sizeof (grub_uint32_t);
+
+ if (space == 0)
+ continue;
+
+ switch (space & GRUB_PCI_ADDR_SPACE_MASK)
+ {
+ case GRUB_PCI_ADDR_SPACE_IO:
+ grub_printf ("\tIO space %d at 0x%llx\n",
+ (unsigned) ((reg - GRUB_PCI_REG_ADDRESSES)
+ / sizeof (grub_uint32_t)) - 1,
+ (unsigned long long)
+ (space & GRUB_PCI_ADDR_IO_MASK));
+ break;
+ case GRUB_PCI_ADDR_SPACE_MEMORY:
+ if ((space & GRUB_PCI_ADDR_MEM_TYPE_MASK)
+ == GRUB_PCI_ADDR_MEM_TYPE_64)
+ {
+ addr = grub_pci_make_address (dev, reg);
+ space |= ((grub_uint64_t) grub_pci_read (addr)) << 32;
+ reg += sizeof (grub_uint32_t);
+ grub_printf ("\t64-bit memory space %d at 0x%016llx [%s]\n",
+ (unsigned) ((reg - GRUB_PCI_REG_ADDRESSES)
+ / sizeof (grub_uint32_t)) - 2,
+ (unsigned long long)
+ (space & GRUB_PCI_ADDR_MEM_MASK),
+ space & GRUB_PCI_ADDR_MEM_PREFETCH
+ ? "prefetchable" : "non-prefetchable");
+
+ }
+ else
+ grub_printf ("\t32-bit memory space %d at 0x%016llx [%s]\n",
+ (unsigned) ((reg - GRUB_PCI_REG_ADDRESSES)
+ / sizeof (grub_uint32_t)) - 1,
+ (unsigned long long)
+ (space & GRUB_PCI_ADDR_MEM_MASK),
+ space & GRUB_PCI_ADDR_MEM_PREFETCH
+ ? "prefetchable" : "non-prefetchable");
+ break;
+ }
+ }
+ }
+
+
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_lspci (grub_extcmd_context_t ctxt,
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ iospace = ctxt->state[0].set;
+ grub_pci_iterate (grub_lspci_iter, NULL);
+ return GRUB_ERR_NONE;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(lspci)
+{
+ cmd = grub_register_extcmd ("lspci", grub_cmd_lspci, 0, "[-i]",
+ N_("List PCI devices."), options);
+}
+
+GRUB_MOD_FINI(lspci)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/macbless.c b/grub-core/commands/macbless.c
new file mode 100644
index 0000000..85cefd0
--- /dev/null
+++ b/grub-core/commands/macbless.c
@@ -0,0 +1,235 @@
+/* hfspbless.c - set the hfs+ boot directory. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2005,2007,2008,2009,2012,2013 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/command.h>
+#include <grub/fs.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+#include <grub/hfsplus.h>
+#include <grub/hfs.h>
+#include <grub/partition.h>
+#include <grub/file.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+struct find_node_context
+{
+ grub_uint64_t inode_found;
+ char *dirname;
+ enum
+ { FOUND_NONE, FOUND_FILE, FOUND_DIR } found;
+};
+
+static int
+find_inode (const char *filename,
+ const struct grub_dirhook_info *info, void *data)
+{
+ struct find_node_context *ctx = data;
+ if (!info->inodeset)
+ return 0;
+
+ if ((grub_strcmp (ctx->dirname, filename) == 0
+ || (info->case_insensitive
+ && grub_strcasecmp (ctx->dirname, filename) == 0)))
+ {
+ ctx->inode_found = info->inode;
+ ctx->found = info->dir ? FOUND_DIR : FOUND_FILE;
+ }
+ return 0;
+}
+
+grub_err_t
+grub_mac_bless_inode (grub_device_t dev, grub_uint32_t inode, int is_dir,
+ int intel)
+{
+ grub_err_t err;
+ union
+ {
+ struct grub_hfs_sblock hfs;
+ struct grub_hfsplus_volheader hfsplus;
+ } volheader;
+ grub_disk_addr_t embedded_offset;
+
+ if (intel && is_dir)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "can't bless a directory for mactel");
+ if (!intel && !is_dir)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "can't bless a file for mac PPC");
+
+ /* Read the bootblock. */
+ err = grub_disk_read (dev->disk, GRUB_HFSPLUS_SBLOCK, 0, sizeof (volheader),
+ (char *) &volheader);
+ if (err)
+ return err;
+
+ embedded_offset = 0;
+ if (grub_be_to_cpu16 (volheader.hfs.magic) == GRUB_HFS_MAGIC)
+ {
+ int extent_start;
+ int ablk_size;
+ int ablk_start;
+
+ /* See if there's an embedded HFS+ filesystem. */
+ if (grub_be_to_cpu16 (volheader.hfs.embed_sig) != GRUB_HFSPLUS_MAGIC)
+ {
+ if (intel)
+ volheader.hfs.intel_bootfile = grub_be_to_cpu32 (inode);
+ else
+ volheader.hfs.ppc_bootdir = grub_be_to_cpu32 (inode);
+ return GRUB_ERR_NONE;
+ }
+
+ /* Calculate the offset needed to translate HFS+ sector numbers. */
+ extent_start =
+ grub_be_to_cpu16 (volheader.hfs.embed_extent.first_block);
+ ablk_size = grub_be_to_cpu32 (volheader.hfs.blksz);
+ ablk_start = grub_be_to_cpu16 (volheader.hfs.first_block);
+ embedded_offset = (ablk_start
+ + ((grub_uint64_t) extent_start)
+ * (ablk_size >> GRUB_DISK_SECTOR_BITS));
+
+ err =
+ grub_disk_read (dev->disk, embedded_offset + GRUB_HFSPLUS_SBLOCK, 0,
+ sizeof (volheader), (char *) &volheader);
+ if (err)
+ return err;
+ }
+
+ if ((grub_be_to_cpu16 (volheader.hfsplus.magic) != GRUB_HFSPLUS_MAGIC)
+ && (grub_be_to_cpu16 (volheader.hfsplus.magic) != GRUB_HFSPLUSX_MAGIC))
+ return grub_error (GRUB_ERR_BAD_FS, "not a HFS+ filesystem");
+ if (intel)
+ volheader.hfsplus.intel_bootfile = grub_be_to_cpu32 (inode);
+ else
+ volheader.hfsplus.ppc_bootdir = grub_be_to_cpu32 (inode);
+
+ return grub_disk_write (dev->disk, embedded_offset + GRUB_HFSPLUS_SBLOCK, 0,
+ sizeof (volheader), (char *) &volheader);
+}
+
+grub_err_t
+grub_mac_bless_file (grub_device_t dev, const char *path_in, int intel)
+{
+ grub_fs_t fs;
+
+ char *path, *tail;
+ struct find_node_context ctx;
+
+ fs = grub_fs_probe (dev);
+ if (!fs || (grub_strcmp (fs->name, "hfsplus") != 0
+ && grub_strcmp (fs->name, "hfs") != 0))
+ return grub_error (GRUB_ERR_BAD_FS, "no suitable FS found");
+
+ path = grub_strdup (path_in);
+ if (!path)
+ return grub_errno;
+
+ tail = path + grub_strlen (path) - 1;
+
+ /* Remove trailing '/'. */
+ while (tail != path && *tail == '/')
+ *(tail--) = 0;
+
+ tail = grub_strrchr (path, '/');
+ ctx.found = 0;
+
+ if (tail)
+ {
+ *tail = 0;
+ ctx.dirname = tail + 1;
+
+ (fs->fs_dir) (dev, *path == 0 ? "/" : path, find_inode, &ctx);
+ }
+ else
+ {
+ ctx.dirname = path + 1;
+ (fs->fs_dir) (dev, "/", find_inode, &ctx);
+ }
+ if (!ctx.found)
+ {
+ grub_free (path);
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"),
+ path_in);
+ }
+ grub_free (path);
+
+ return grub_mac_bless_inode (dev, (grub_uint32_t) ctx.inode_found,
+ (ctx.found == FOUND_DIR), intel);
+}
+
+static grub_err_t
+grub_cmd_macbless (grub_command_t cmd, int argc, char **args)
+{
+ char *device_name;
+ char *path = 0;
+ grub_device_t dev = 0;
+ grub_err_t err;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+ device_name = grub_file_get_device_name (args[0]);
+ dev = grub_device_open (device_name);
+
+ path = grub_strchr (args[0], ')');
+ if (!path)
+ path = args[0];
+ else
+ path = path + 1;
+
+ if (!path || *path == 0 || !dev)
+ {
+ if (dev)
+ grub_device_close (dev);
+
+ grub_free (device_name);
+
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument");
+ }
+
+ err = grub_mac_bless_file (dev, path, cmd->name[3] == 't');
+
+ grub_device_close (dev);
+ grub_free (device_name);
+ return err;
+}
+
+static grub_command_t cmd, cmd_ppc;
+
+GRUB_MOD_INIT(macbless)
+{
+ cmd = grub_register_command ("mactelbless", grub_cmd_macbless,
+ N_("FILE"),
+ N_
+ ("Bless FILE of HFS or HFS+ partition for intel macs."));
+ cmd_ppc =
+ grub_register_command ("macppcbless", grub_cmd_macbless, N_("DIR"),
+ N_
+ ("Bless DIR of HFS or HFS+ partition for PPC macs."));
+}
+
+GRUB_MOD_FINI(macbless)
+{
+ grub_unregister_command (cmd);
+ grub_unregister_command (cmd_ppc);
+}
diff --git a/grub-core/commands/memrw.c b/grub-core/commands/memrw.c
new file mode 100644
index 0000000..d401a6d
--- /dev/null
+++ b/grub-core/commands/memrw.c
@@ -0,0 +1,158 @@
+/* memrw.c - command to read / write physical memory */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/misc.h>
+#include <grub/extcmd.h>
+#include <grub/env.h>
+#include <grub/i18n.h>
+#include <grub/lockdown.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_extcmd_t cmd_read_byte, cmd_read_word, cmd_read_dword;
+static grub_command_t cmd_write_byte, cmd_write_word, cmd_write_dword;
+
+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_read (grub_extcmd_context_t ctxt, int argc, char **argv)
+{
+ grub_addr_t addr;
+ grub_uint32_t value = 0;
+ char buf[sizeof ("XXXXXXXX")];
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+
+ addr = grub_strtoul (argv[0], 0, 0);
+ switch (ctxt->extcmd->cmd->name[sizeof ("read_") - 1])
+ {
+ case 'd':
+ value = *((volatile grub_uint32_t *) addr);
+ break;
+
+ case 'w':
+ value = *((volatile grub_uint16_t *) addr);
+ break;
+
+ case 'b':
+ value = *((volatile grub_uint8_t *) addr);
+ break;
+ }
+
+ if (ctxt->state[0].set)
+ {
+ grub_snprintf (buf, sizeof (buf), "%x", value);
+ grub_env_set (ctxt->state[0].arg, buf);
+ }
+ else
+ grub_printf ("0x%x\n", value);
+
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_write (grub_command_t cmd, int argc, char **argv)
+{
+ grub_addr_t addr;
+ grub_uint32_t value;
+ grub_uint32_t mask = 0xffffffff;
+
+ if (argc != 2 && argc != 3)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
+
+ addr = grub_strtoul (argv[0], 0, 0);
+ value = grub_strtoul (argv[1], 0, 0);
+ if (argc == 3)
+ mask = grub_strtoul (argv[2], 0, 0);
+ value &= mask;
+ switch (cmd->name[sizeof ("write_") - 1])
+ {
+ case 'd':
+ if (mask != 0xffffffff)
+ *((volatile grub_uint32_t *) addr)
+ = (*((volatile grub_uint32_t *) addr) & ~mask) | value;
+ else
+ *((volatile grub_uint32_t *) addr) = value;
+ break;
+
+ case 'w':
+ if ((mask & 0xffff) != 0xffff)
+ *((volatile grub_uint16_t *) addr)
+ = (*((volatile grub_uint16_t *) addr) & ~mask) | value;
+ else
+ *((volatile grub_uint16_t *) addr) = value;
+ break;
+
+ case 'b':
+ if ((mask & 0xff) != 0xff)
+ *((volatile grub_uint8_t *) addr)
+ = (*((volatile grub_uint8_t *) addr) & ~mask) | value;
+ else
+ *((volatile grub_uint8_t *) addr) = value;
+ break;
+ }
+
+ return 0;
+}
+
+GRUB_MOD_INIT(memrw)
+{
+ cmd_read_byte =
+ grub_register_extcmd ("read_byte", grub_cmd_read, 0,
+ N_("ADDR"), N_("Read 8-bit value from ADDR."),
+ options);
+ cmd_read_word =
+ grub_register_extcmd ("read_word", grub_cmd_read, 0,
+ N_("ADDR"), N_("Read 16-bit value from ADDR."),
+ options);
+ cmd_read_dword =
+ grub_register_extcmd ("read_dword", grub_cmd_read, 0,
+ N_("ADDR"), N_("Read 32-bit value from ADDR."),
+ options);
+ cmd_write_byte =
+ grub_register_command_lockdown ("write_byte", grub_cmd_write,
+ N_("ADDR VALUE [MASK]"),
+ N_("Write 8-bit VALUE to ADDR."));
+ cmd_write_word =
+ grub_register_command_lockdown ("write_word", grub_cmd_write,
+ N_("ADDR VALUE [MASK]"),
+ N_("Write 16-bit VALUE to ADDR."));
+ cmd_write_dword =
+ grub_register_command_lockdown ("write_dword", grub_cmd_write,
+ N_("ADDR VALUE [MASK]"),
+ N_("Write 32-bit VALUE to ADDR."));
+}
+
+GRUB_MOD_FINI(memrw)
+{
+ grub_unregister_extcmd (cmd_read_byte);
+ grub_unregister_extcmd (cmd_read_word);
+ grub_unregister_extcmd (cmd_read_dword);
+ grub_unregister_command (cmd_write_byte);
+ grub_unregister_command (cmd_write_word);
+ grub_unregister_command (cmd_write_dword);
+}
diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c
new file mode 100644
index 0000000..720e6d8
--- /dev/null
+++ b/grub-core/commands/menuentry.c
@@ -0,0 +1,337 @@
+/* menuentry.c - menuentry command */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010 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/types.h>
+#include <grub/misc.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+#include <grub/normal.h>
+
+static const struct grub_arg_option options[] =
+ {
+ {"class", 1, GRUB_ARG_OPTION_REPEATABLE,
+ N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING},
+ {"users", 2, 0,
+ N_("List of users allowed to boot this entry."), N_("USERNAME[,USERNAME]"),
+ ARG_TYPE_STRING},
+ {"hotkey", 3, 0,
+ N_("Keyboard key to quickly boot this entry."), N_("KEYBOARD_KEY"), ARG_TYPE_STRING},
+ {"source", 4, 0,
+ N_("Use STRING as menu entry body."), N_("STRING"), ARG_TYPE_STRING},
+ {"id", 0, 0, N_("Menu entry identifier."), N_("STRING"), ARG_TYPE_STRING},
+ /* TRANSLATORS: menu entry can either be bootable by anyone or only by
+ handful of users. By default when security is active only superusers can
+ boot a given menu entry. With --unrestricted (this option)
+ anyone can boot it. */
+ {"unrestricted", 0, 0, N_("This entry can be booted by any user."),
+ 0, ARG_TYPE_NONE},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static struct
+{
+ const char *name;
+ int key;
+} hotkey_aliases[] =
+ {
+ {"backspace", GRUB_TERM_BACKSPACE},
+ {"tab", GRUB_TERM_TAB},
+ {"delete", GRUB_TERM_KEY_DC},
+ {"insert", GRUB_TERM_KEY_INSERT},
+ {"f1", GRUB_TERM_KEY_F1},
+ {"f2", GRUB_TERM_KEY_F2},
+ {"f3", GRUB_TERM_KEY_F3},
+ {"f4", GRUB_TERM_KEY_F4},
+ {"f5", GRUB_TERM_KEY_F5},
+ {"f6", GRUB_TERM_KEY_F6},
+ {"f7", GRUB_TERM_KEY_F7},
+ {"f8", GRUB_TERM_KEY_F8},
+ {"f9", GRUB_TERM_KEY_F9},
+ {"f10", GRUB_TERM_KEY_F10},
+ {"f11", GRUB_TERM_KEY_F11},
+ {"f12", GRUB_TERM_KEY_F12},
+ };
+
+/* Add a menu entry to the current menu context (as given by the environment
+ variable data slot `menu'). As the configuration file is read, the script
+ parser calls this when a menu entry is to be created. */
+grub_err_t
+grub_normal_add_menu_entry (int argc, const char **args,
+ char **classes, const char *id,
+ const char *users, const char *hotkey,
+ const char *prefix, const char *sourcecode,
+ int submenu)
+{
+ int menu_hotkey = 0;
+ char **menu_args = NULL;
+ char *menu_users = NULL;
+ char *menu_title = NULL;
+ char *menu_sourcecode = NULL;
+ char *menu_id = NULL;
+ struct grub_menu_entry_class *menu_classes = NULL;
+
+ grub_menu_t menu;
+ grub_menu_entry_t *last;
+
+ menu = grub_env_get_menu ();
+ if (! menu)
+ return grub_error (GRUB_ERR_MENU, "no menu context");
+
+ last = &menu->entry_list;
+
+ menu_sourcecode = grub_xasprintf ("%s%s", prefix ?: "", sourcecode);
+ if (! menu_sourcecode)
+ return grub_errno;
+
+ if (classes && classes[0])
+ {
+ int i;
+ for (i = 0; classes[i]; i++); /* count # of menuentry classes */
+ menu_classes = grub_zalloc (sizeof (struct grub_menu_entry_class)
+ * (i + 1));
+ if (! menu_classes)
+ goto fail;
+
+ for (i = 0; classes[i]; i++)
+ {
+ menu_classes[i].name = grub_strdup (classes[i]);
+ if (! menu_classes[i].name)
+ goto fail;
+ menu_classes[i].next = classes[i + 1] ? &menu_classes[i + 1] : NULL;
+ }
+ }
+
+ if (users)
+ {
+ menu_users = grub_strdup (users);
+ if (! menu_users)
+ goto fail;
+ }
+
+ if (hotkey)
+ {
+ unsigned i;
+ for (i = 0; i < ARRAY_SIZE (hotkey_aliases); i++)
+ if (grub_strcmp (hotkey, hotkey_aliases[i].name) == 0)
+ {
+ menu_hotkey = hotkey_aliases[i].key;
+ break;
+ }
+ if (i == ARRAY_SIZE (hotkey_aliases))
+ menu_hotkey = hotkey[0];
+ }
+
+ if (! argc)
+ {
+ grub_error (GRUB_ERR_MENU, "menuentry is missing title");
+ goto fail;
+ }
+
+ menu_title = grub_strdup (args[0]);
+ if (! menu_title)
+ goto fail;
+
+ menu_id = grub_strdup (id ? : menu_title);
+ if (! menu_id)
+ goto fail;
+
+ /* Save argc, args to pass as parameters to block arg later. */
+ menu_args = grub_calloc (argc + 1, sizeof (char *));
+ if (! menu_args)
+ goto fail;
+
+ {
+ int i;
+ for (i = 0; i < argc; i++)
+ {
+ menu_args[i] = grub_strdup (args[i]);
+ if (! menu_args[i])
+ goto fail;
+ }
+ menu_args[argc] = NULL;
+ }
+
+ /* Add the menu entry at the end of the list. */
+ while (*last)
+ last = &(*last)->next;
+
+ *last = grub_zalloc (sizeof (**last));
+ if (! *last)
+ goto fail;
+
+ (*last)->title = menu_title;
+ (*last)->id = menu_id;
+ (*last)->hotkey = menu_hotkey;
+ (*last)->classes = menu_classes;
+ if (menu_users)
+ (*last)->restricted = 1;
+ (*last)->users = menu_users;
+ (*last)->argc = argc;
+ (*last)->args = menu_args;
+ (*last)->sourcecode = menu_sourcecode;
+ (*last)->submenu = submenu;
+
+ menu->size++;
+ return GRUB_ERR_NONE;
+
+ fail:
+
+ grub_free (menu_sourcecode);
+ {
+ int i;
+ for (i = 0; menu_classes && menu_classes[i].name; i++)
+ grub_free (menu_classes[i].name);
+ grub_free (menu_classes);
+ }
+
+ {
+ int i;
+ for (i = 0; menu_args && menu_args[i]; i++)
+ grub_free (menu_args[i]);
+ grub_free (menu_args);
+ }
+
+ grub_free (menu_users);
+ grub_free (menu_title);
+ grub_free (menu_id);
+ return grub_errno;
+}
+
+static char *
+setparams_prefix (int argc, char **args)
+{
+ int i;
+ int j;
+ char *p;
+ char *result;
+ grub_size_t len = 10;
+
+ /* Count resulting string length */
+ for (i = 0; i < argc; i++)
+ {
+ len += 3; /* 3 = 1 space + 2 quotes */
+ p = args[i];
+ while (*p)
+ len += (*p++ == '\'' ? 4 : 1);
+ }
+
+ result = grub_malloc (len + 2);
+ if (! result)
+ return 0;
+
+ grub_strcpy (result, "setparams");
+ p = result + 9;
+
+ for (j = 0; j < argc; j++)
+ {
+ *p++ = ' ';
+ *p++ = '\'';
+ p = grub_strchrsub (p, args[j], '\'', "'\\''");
+ *p++ = '\'';
+ }
+ *p++ = '\n';
+ *p = '\0';
+ return result;
+}
+
+static grub_err_t
+grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ char ch;
+ char *src;
+ char *prefix;
+ unsigned len;
+ grub_err_t r;
+ const char *users;
+
+ if (! argc)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments");
+
+ if (ctxt->state[3].set && ctxt->script)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple menuentry definitions");
+
+ if (! ctxt->state[3].set && ! ctxt->script)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition");
+
+ if (ctxt->state[1].set)
+ users = ctxt->state[1].arg;
+ else if (ctxt->state[5].set)
+ users = NULL;
+ else
+ users = "";
+
+ if (! ctxt->script)
+ return grub_normal_add_menu_entry (argc, (const char **) args,
+ (ctxt->state[0].set ? ctxt->state[0].args
+ : NULL),
+ ctxt->state[4].arg,
+ users,
+ ctxt->state[2].arg, 0,
+ ctxt->state[3].arg,
+ ctxt->extcmd->cmd->name[0] == 's');
+
+ src = args[argc - 1];
+ args[argc - 1] = NULL;
+
+ len = grub_strlen(src);
+ ch = src[len - 1];
+ src[len - 1] = '\0';
+
+ prefix = setparams_prefix (argc - 1, args);
+ if (! prefix)
+ return grub_errno;
+
+ r = grub_normal_add_menu_entry (argc - 1, (const char **) args,
+ ctxt->state[0].args, ctxt->state[4].arg,
+ users,
+ ctxt->state[2].arg, prefix, src + 1,
+ ctxt->extcmd->cmd->name[0] == 's');
+
+ src[len - 1] = ch;
+ args[argc - 1] = src;
+ grub_free (prefix);
+ return r;
+}
+
+static grub_extcmd_t cmd, cmd_sub;
+
+void
+grub_menu_init (void)
+{
+ cmd = grub_register_extcmd ("menuentry", grub_cmd_menuentry,
+ GRUB_COMMAND_FLAG_BLOCKS
+ | GRUB_COMMAND_ACCEPT_DASH
+ | GRUB_COMMAND_FLAG_EXTRACTOR,
+ N_("BLOCK"), N_("Define a menu entry."), options);
+ cmd_sub = grub_register_extcmd ("submenu", grub_cmd_menuentry,
+ GRUB_COMMAND_FLAG_BLOCKS
+ | GRUB_COMMAND_ACCEPT_DASH
+ | GRUB_COMMAND_FLAG_EXTRACTOR,
+ N_("BLOCK"), N_("Define a submenu."),
+ options);
+}
+
+void
+grub_menu_fini (void)
+{
+ grub_unregister_extcmd (cmd);
+ grub_unregister_extcmd (cmd_sub);
+}
diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c
new file mode 100644
index 0000000..fa49893
--- /dev/null
+++ b/grub-core/commands/minicmd.c
@@ -0,0 +1,227 @@
+/* minicmd.c - commands for the rescue mode */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2005,2006,2007,2009 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/mm.h>
+#include <grub/err.h>
+#include <grub/env.h>
+#include <grub/misc.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/term.h>
+#include <grub/loader.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* cat FILE */
+static grub_err_t
+grub_mini_cmd_cat (struct grub_command *cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ grub_file_t file;
+ char buf[GRUB_DISK_SECTOR_SIZE];
+ grub_ssize_t size;
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ file = grub_file_open (argv[0], GRUB_FILE_TYPE_CAT);
+ if (! file)
+ return grub_errno;
+
+ while ((size = grub_file_read (file, buf, sizeof (buf))) > 0)
+ {
+ int i;
+
+ for (i = 0; i < size; i++)
+ {
+ unsigned char c = buf[i];
+
+ if ((grub_isprint (c) || grub_isspace (c)) && c != '\r')
+ grub_printf ("%c", c);
+ else
+ {
+ grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
+ grub_printf ("<%x>", (int) c);
+ grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
+ }
+ }
+ }
+
+ grub_xputs ("\n");
+ grub_refresh ();
+ grub_file_close (file);
+
+ return 0;
+}
+
+/* help */
+static grub_err_t
+grub_mini_cmd_help (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ grub_command_t p;
+
+ for (p = grub_command_list; p; p = p->next)
+ grub_printf ("%s (%d%c)\t%s\n", p->name,
+ p->prio & GRUB_COMMAND_PRIO_MASK,
+ (p->prio & GRUB_COMMAND_FLAG_ACTIVE) ? '+' : '-',
+ p->description);
+
+ return 0;
+}
+
+/* dump ADDRESS [SIZE] */
+static grub_err_t
+grub_mini_cmd_dump (struct grub_command *cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ grub_uint8_t *addr;
+ grub_size_t size = 4;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no address specified");
+
+#if GRUB_CPU_SIZEOF_VOID_P == GRUB_CPU_SIZEOF_LONG
+#define grub_strtoaddr grub_strtoul
+#else
+#define grub_strtoaddr grub_strtoull
+#endif
+
+ addr = (grub_uint8_t *) grub_strtoaddr (argv[0], 0, 0);
+ if (grub_errno)
+ return grub_errno;
+
+ if (argc > 1)
+ size = (grub_size_t) grub_strtoaddr (argv[1], 0, 0);
+
+ while (size--)
+ {
+ grub_printf ("%x%x ", *addr >> 4, *addr & 0xf);
+ addr++;
+ }
+
+ return 0;
+}
+
+/* rmmod MODULE */
+static grub_err_t
+grub_mini_cmd_rmmod (struct grub_command *cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ grub_dl_t mod;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
+
+ mod = grub_dl_get (argv[0]);
+ if (! mod)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such module");
+
+ if (grub_dl_is_persistent (mod))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload persistent module");
+
+ if (grub_dl_ref_count (mod) > 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload referenced module");
+
+ grub_dl_unref (mod);
+ grub_dl_unload (mod);
+
+ return 0;
+}
+
+/* lsmod */
+static grub_err_t
+grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ grub_dl_t mod;
+
+ /* TRANSLATORS: this is module list header. Name
+ is module name, Ref Count is a reference counter
+ (how many modules or open descriptors use it).
+ Dependencies are the other modules it uses.
+ */
+ grub_printf_ (N_("Name\tRef Count\tDependencies\n"));
+ FOR_DL_MODULES (mod)
+ {
+ grub_dl_dep_t dep;
+
+ grub_printf ("%s\t%d\t\t", mod->name, mod->ref_count);
+ for (dep = mod->dep; dep; dep = dep->next)
+ {
+ if (dep != mod->dep)
+ grub_xputs (",");
+
+ grub_printf ("%s", dep->mod->name);
+ }
+ grub_xputs ("\n");
+ }
+
+ return 0;
+}
+
+/* exit */
+static grub_err_t __attribute__ ((noreturn))
+grub_mini_cmd_exit (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ grub_exit ();
+ /* Not reached. */
+}
+
+static grub_command_t cmd_cat, cmd_help;
+static grub_command_t cmd_dump, cmd_rmmod, cmd_lsmod, cmd_exit;
+
+GRUB_MOD_INIT(minicmd)
+{
+ cmd_cat =
+ grub_register_command ("cat", grub_mini_cmd_cat,
+ N_("FILE"), N_("Show the contents of a file."));
+ cmd_help =
+ grub_register_command ("help", grub_mini_cmd_help,
+ 0, N_("Show this message."));
+ cmd_dump =
+ grub_register_command ("dump", grub_mini_cmd_dump,
+ N_("ADDR [SIZE]"), N_("Show memory contents."));
+ cmd_rmmod =
+ grub_register_command ("rmmod", grub_mini_cmd_rmmod,
+ N_("MODULE"), N_("Remove a module."));
+ cmd_lsmod =
+ grub_register_command ("lsmod", grub_mini_cmd_lsmod,
+ 0, N_("Show loaded modules."));
+ cmd_exit =
+ grub_register_command ("exit", grub_mini_cmd_exit,
+ 0, N_("Exit from GRUB."));
+}
+
+GRUB_MOD_FINI(minicmd)
+{
+ grub_unregister_command (cmd_cat);
+ grub_unregister_command (cmd_help);
+ grub_unregister_command (cmd_dump);
+ grub_unregister_command (cmd_rmmod);
+ grub_unregister_command (cmd_lsmod);
+ grub_unregister_command (cmd_exit);
+}
diff --git a/grub-core/commands/mips/loongson/lsspd.c b/grub-core/commands/mips/loongson/lsspd.c
new file mode 100644
index 0000000..a88ab87
--- /dev/null
+++ b/grub-core/commands/mips/loongson/lsspd.c
@@ -0,0 +1,103 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010 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/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/command.h>
+#include <grub/cs5536.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+grub_cmd_lsspd (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ grub_pci_device_t dev;
+ grub_port_t smbbase;
+ int i;
+ grub_err_t err;
+
+ if (!grub_cs5536_find (&dev))
+ {
+ grub_puts_ (N_("No CS5536 found"));
+ return GRUB_ERR_NONE;
+ }
+ grub_printf_ (N_("CS5536 at %d:%d.%d\n"), grub_pci_get_bus (dev),
+ grub_pci_get_device (dev), grub_pci_get_function (dev));
+
+ err = grub_cs5536_init_smbus (dev, 0x7fff, &smbbase);
+ if (err)
+ return err;
+
+ /* TRANSLATORS: System management bus is often used to access components like
+ RAM (info only, not data) or batteries. I/O space is where in memory
+ its ports are. */
+ grub_printf_ (N_("System management bus controller I/O space is at 0x%x\n"),
+ smbbase);
+
+ for (i = GRUB_SMB_RAM_START_ADDR;
+ i < GRUB_SMB_RAM_START_ADDR + GRUB_SMB_RAM_NUM_MAX; i++)
+ {
+ struct grub_smbus_spd spd;
+ grub_memset (&spd, 0, sizeof (spd));
+ /* TRANSLATORS: it's shown in a report in a way
+ like number 1: ... number 2: ...
+ */
+ grub_printf_ (N_("RAM slot number %d\n"), i);
+ err = grub_cs5536_read_spd (smbbase, i, &spd);
+ if (err)
+ {
+ grub_print_error ();
+ continue;
+ }
+ grub_printf_ (N_("Written SPD bytes: %d B.\n"), spd.written_size);
+ grub_printf_ (N_("Total flash size: %d B.\n"),
+ 1 << spd.log_total_flash_size);
+ if (spd.memory_type == GRUB_SMBUS_SPD_MEMORY_TYPE_DDR2)
+ {
+ char str[sizeof (spd.ddr2.part_number) + 1];
+ grub_puts_ (N_("Memory type: DDR2."));
+ grub_memcpy (str, spd.ddr2.part_number,
+ sizeof (spd.ddr2.part_number));
+ str[sizeof (spd.ddr2.part_number)] = 0;
+ grub_printf_ (N_("Part no: %s.\n"), str);
+ }
+ else
+ grub_puts_ (N_("Memory type: Unknown."));
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(lsspd)
+{
+ cmd = grub_register_command ("lsspd", grub_cmd_lsspd, 0,
+ N_("Print Memory information."));
+}
+
+GRUB_MOD_FINI(lsspd)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/nativedisk.c b/grub-core/commands/nativedisk.c
new file mode 100644
index 0000000..7c8f97f
--- /dev/null
+++ b/grub-core/commands/nativedisk.c
@@ -0,0 +1,332 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/device.h>
+#include <grub/mm.h>
+#include <grub/fs.h>
+#include <grub/env.h>
+#include <grub/file.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const char *modnames_def[] = {
+ /* FIXME: autogenerate this. */
+#if defined (__i386__) || defined (__x86_64__) || defined (GRUB_MACHINE_MIPS_LOONGSON)
+ "pata", "ahci", "usbms", "ohci", "uhci", "ehci"
+#elif defined (GRUB_MACHINE_MIPS_QEMU_MIPS)
+ "pata"
+#else
+#error "Fill this"
+#endif
+ };
+
+static grub_err_t
+get_uuid (const char *name, char **uuid, int getnative)
+{
+ grub_device_t dev;
+ grub_fs_t fs = 0;
+
+ *uuid = 0;
+
+ dev = grub_device_open (name);
+ if (!dev)
+ return grub_errno;
+
+ if (!dev->disk)
+ {
+ grub_dprintf ("nativedisk", "Skipping non-disk\n");
+ grub_device_close (dev);
+ return 0;
+ }
+
+ switch (dev->disk->dev->id)
+ {
+ /* Firmware disks. */
+ case GRUB_DISK_DEVICE_BIOSDISK_ID:
+ case GRUB_DISK_DEVICE_OFDISK_ID:
+ case GRUB_DISK_DEVICE_OBDISK_ID:
+ case GRUB_DISK_DEVICE_EFIDISK_ID:
+ case GRUB_DISK_DEVICE_NAND_ID:
+ case GRUB_DISK_DEVICE_ARCDISK_ID:
+ case GRUB_DISK_DEVICE_HOSTDISK_ID:
+ case GRUB_DISK_DEVICE_UBOOTDISK_ID:
+ break;
+
+ /* Native disks. */
+ case GRUB_DISK_DEVICE_ATA_ID:
+ case GRUB_DISK_DEVICE_SCSI_ID:
+ case GRUB_DISK_DEVICE_XEN:
+ if (getnative)
+ break;
+ /* FALLTHROUGH */
+
+ /* Virtual disks. */
+ /* GRUB dynamically generated files. */
+ case GRUB_DISK_DEVICE_PROCFS_ID:
+ /* To access through host OS routines (grub-emu only). */
+ case GRUB_DISK_DEVICE_HOST_ID:
+ /* To access coreboot roms. */
+ case GRUB_DISK_DEVICE_CBFSDISK_ID:
+ /* GRUB-only memdisk. Can't match any of firmware devices. */
+ case GRUB_DISK_DEVICE_MEMDISK_ID:
+ grub_dprintf ("nativedisk", "Skipping native disk %s\n",
+ dev->disk->name);
+ grub_device_close (dev);
+ return 0;
+
+ /* FIXME: those probably need special handling. */
+ case GRUB_DISK_DEVICE_LOOPBACK_ID:
+ case GRUB_DISK_DEVICE_DISKFILTER_ID:
+ case GRUB_DISK_DEVICE_CRYPTODISK_ID:
+ break;
+ }
+ if (dev)
+ fs = grub_fs_probe (dev);
+ if (!fs)
+ {
+ grub_device_close (dev);
+ return grub_errno;
+ }
+ if (!fs->fs_uuid || fs->fs_uuid (dev, uuid) || !*uuid)
+ {
+ grub_device_close (dev);
+
+ if (!grub_errno)
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ N_("%s does not support UUIDs"), fs->name);
+
+ return grub_errno;
+ }
+ grub_device_close (dev);
+ return GRUB_ERR_NONE;
+}
+
+struct search_ctx
+{
+ char *root_uuid;
+ char *prefix_uuid;
+ const char *prefix_path;
+ int prefix_found, root_found;
+};
+
+static int
+iterate_device (const char *name, void *data)
+{
+ struct search_ctx *ctx = data;
+ char *cur_uuid;
+
+ if (get_uuid (name, &cur_uuid, 1))
+ {
+ if (grub_errno == GRUB_ERR_UNKNOWN_FS)
+ grub_errno = 0;
+ grub_print_error ();
+ return 0;
+ }
+
+ grub_dprintf ("nativedisk", "checking %s: %s\n", name,
+ cur_uuid);
+ if (ctx->prefix_uuid && grub_strcasecmp (cur_uuid, ctx->prefix_uuid) == 0)
+ {
+ char *prefix;
+ prefix = grub_xasprintf ("(%s)/%s", name, ctx->prefix_path);
+ grub_env_set ("prefix", prefix);
+ grub_free (prefix);
+ ctx->prefix_found = 1;
+ }
+ if (ctx->root_uuid && grub_strcasecmp (cur_uuid, ctx->root_uuid) == 0)
+ {
+ grub_env_set ("root", name);
+ ctx->root_found = 1;
+ }
+ return ctx->prefix_found && ctx->root_found;
+}
+
+static grub_err_t
+grub_cmd_nativedisk (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args_in)
+{
+ char *uuid_root = 0, *uuid_prefix, *prefdev = 0;
+ const char *prefix = 0;
+ const char *path_prefix = 0;
+ int mods_loaded = 0;
+ grub_dl_t *mods;
+ const char **args;
+ int i;
+
+ if (argc == 0)
+ {
+ argc = ARRAY_SIZE (modnames_def);
+ args = modnames_def;
+ }
+ else
+ args = (const char **) args_in;
+
+ prefix = grub_env_get ("prefix");
+
+ if (! prefix)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix");
+
+ if (prefix)
+ path_prefix = (prefix[0] == '(') ? grub_strchr (prefix, ')') : NULL;
+ if (path_prefix)
+ path_prefix++;
+ else
+ path_prefix = prefix;
+
+ mods = grub_calloc (argc, sizeof (mods[0]));
+ if (!mods)
+ return grub_errno;
+
+ if (get_uuid (NULL, &uuid_root, 0))
+ {
+ grub_free (mods);
+ return grub_errno;
+ }
+
+ prefdev = grub_file_get_device_name (prefix);
+ if (grub_errno)
+ {
+ grub_print_error ();
+ prefdev = 0;
+ }
+
+ if (get_uuid (prefdev, &uuid_prefix, 0))
+ {
+ grub_free (uuid_root);
+ grub_free (prefdev);
+ grub_free (mods);
+ return grub_errno;
+ }
+
+ grub_dprintf ("nativedisk", "uuid_prefix = %s, uuid_root = %s\n",
+ uuid_prefix, uuid_root);
+
+ for (mods_loaded = 0; mods_loaded < argc; mods_loaded++)
+ {
+ char *filename;
+ grub_dl_t mod;
+ grub_file_t file = NULL;
+ grub_ssize_t size;
+ void *core = 0;
+
+ mod = grub_dl_get (args[mods_loaded]);
+ if (mod)
+ {
+ mods[mods_loaded] = 0;
+ continue;
+ }
+
+ filename = grub_xasprintf ("%s/" GRUB_TARGET_CPU "-" GRUB_PLATFORM "/%s.mod",
+ prefix, args[mods_loaded]);
+ if (! filename)
+ goto fail;
+
+ file = grub_file_open (filename,
+ GRUB_FILE_TYPE_GRUB_MODULE);
+ grub_free (filename);
+ if (! file)
+ goto fail;
+
+ size = grub_file_size (file);
+ core = grub_malloc (size);
+ if (! core)
+ {
+ grub_file_close (file);
+ goto fail;
+ }
+
+ if (grub_file_read (file, core, size) != (grub_ssize_t) size)
+ {
+ grub_file_close (file);
+ grub_free (core);
+ goto fail;
+ }
+
+ grub_file_close (file);
+
+ mods[mods_loaded] = grub_dl_load_core_noinit (core, size);
+ if (! mods[mods_loaded])
+ goto fail;
+ }
+
+ for (i = 0; i < argc; i++)
+ if (mods[i])
+ grub_dl_init (mods[i]);
+
+ if (uuid_prefix || uuid_root)
+ {
+ struct search_ctx ctx;
+ grub_fs_autoload_hook_t saved_autoload;
+
+ /* No need to autoload FS since obviously we already have the necessary fs modules. */
+ saved_autoload = grub_fs_autoload_hook;
+ grub_fs_autoload_hook = 0;
+
+ ctx.root_uuid = uuid_root;
+ ctx.prefix_uuid = uuid_prefix;
+ ctx.prefix_path = path_prefix;
+ ctx.prefix_found = !uuid_prefix;
+ ctx.root_found = !uuid_root;
+
+ /* FIXME: try to guess the correct values. */
+ grub_device_iterate (iterate_device, &ctx);
+
+ grub_fs_autoload_hook = saved_autoload;
+ }
+ grub_free (uuid_root);
+ grub_free (uuid_prefix);
+ grub_free (prefdev);
+ grub_free (mods);
+
+ return GRUB_ERR_NONE;
+
+ fail:
+ grub_free (uuid_root);
+ grub_free (uuid_prefix);
+ grub_free (prefdev);
+
+ for (i = 0; i < mods_loaded; i++)
+ if (mods[i])
+ {
+ mods[i]->fini = 0;
+ grub_dl_unload (mods[i]);
+ }
+ grub_free (mods);
+
+ return grub_errno;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(nativedisk)
+{
+ cmd = grub_register_command ("nativedisk", grub_cmd_nativedisk, N_("[MODULE1 MODULE2 ...]"),
+ N_("Switch to native disk drivers. If no modules are specified default set (pata,ahci,usbms,ohci,uhci,ehci) is used"));
+}
+
+GRUB_MOD_FINI(nativedisk)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/parttool.c b/grub-core/commands/parttool.c
new file mode 100644
index 0000000..051e313
--- /dev/null
+++ b/grub-core/commands/parttool.c
@@ -0,0 +1,357 @@
+/* parttool.c - common dispatcher and parser for partition operations */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/parttool.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv2+");
+
+static struct grub_parttool *parts = 0;
+static int curhandle = 0;
+static grub_dl_t mymod;
+static char helpmsg[] =
+ N_("Perform COMMANDS on partition.\n"
+ "Use `parttool PARTITION help' for the list "
+ "of available commands.");
+
+int
+grub_parttool_register(const char *part_name,
+ const grub_parttool_function_t func,
+ const struct grub_parttool_argdesc *args)
+{
+ struct grub_parttool *cur;
+ int nargs = 0;
+
+ if (! parts)
+ grub_dl_ref (mymod);
+
+ cur = (struct grub_parttool *) grub_malloc (sizeof (struct grub_parttool));
+ cur->next = parts;
+ cur->name = grub_strdup (part_name);
+ cur->handle = curhandle++;
+ for (nargs = 0; args[nargs].name != 0; nargs++);
+ cur->nargs = nargs;
+ cur->args = (struct grub_parttool_argdesc *)
+ grub_calloc (nargs + 1, sizeof (struct grub_parttool_argdesc));
+ if (!cur->args)
+ {
+ grub_free (cur);
+ curhandle--;
+ return -1;
+ }
+ grub_memcpy (cur->args, args,
+ (nargs + 1) * sizeof (struct grub_parttool_argdesc));
+
+ cur->func = func;
+ parts = cur;
+ return cur->handle;
+}
+
+void
+grub_parttool_unregister (int handle)
+{
+ struct grub_parttool *prev = 0, *cur, *t;
+ for (cur = parts; cur; )
+ if (cur->handle == handle)
+ {
+ grub_free (cur->args);
+ grub_free (cur->name);
+ if (prev)
+ prev->next = cur->next;
+ else
+ parts = cur->next;
+ t = cur;
+ cur = cur->next;
+ grub_free (t);
+ }
+ else
+ {
+ prev = cur;
+ cur = cur->next;
+ }
+ if (! parts)
+ grub_dl_unref (mymod);
+}
+
+static grub_err_t
+show_help (grub_device_t dev)
+{
+ int found = 0;
+ struct grub_parttool *cur;
+
+ for (cur = parts; cur; cur = cur->next)
+ if (grub_strcmp (dev->disk->partition->partmap->name, cur->name) == 0)
+ {
+ struct grub_parttool_argdesc *curarg;
+ found = 1;
+ for (curarg = cur->args; curarg->name; curarg++)
+ {
+ int spacing = 20;
+
+ spacing -= grub_strlen (curarg->name);
+ grub_printf ("%s", curarg->name);
+
+ switch (curarg->type)
+ {
+ case GRUB_PARTTOOL_ARG_BOOL:
+ grub_printf ("+/-");
+ spacing -= 3;
+ break;
+
+ case GRUB_PARTTOOL_ARG_VAL:
+ grub_xputs (_("=VAL"));
+ spacing -= 4;
+ break;
+
+ case GRUB_PARTTOOL_ARG_END:
+ break;
+ }
+ while (spacing-- > 0)
+ grub_printf (" ");
+ grub_puts_ (curarg->desc);
+ }
+ }
+ if (! found)
+ grub_printf_ (N_("Sorry, no parttool is available for %s\n"),
+ dev->disk->partition->partmap->name);
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_parttool (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ grub_device_t dev;
+ struct grub_parttool *cur, *ptool;
+ int *parsed;
+ int i, j;
+ grub_err_t err = GRUB_ERR_NONE;
+
+ if (argc < 1)
+ {
+ grub_puts_ (helpmsg);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "too few arguments");
+ }
+
+ if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')')
+ {
+ args[0][grub_strlen (args[0]) - 1] = 0;
+ dev = grub_device_open (args[0] + 1);
+ args[0][grub_strlen (args[0]) - 1] = ')';
+ }
+ else
+ dev = grub_device_open (args[0]);
+
+ if (! dev)
+ return grub_errno;
+
+ if (! dev->disk)
+ {
+ grub_device_close (dev);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk");
+ }
+
+ if (! dev->disk->partition)
+ {
+ grub_device_close (dev);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a partition");
+ }
+
+ /* Load modules. */
+ if (! grub_no_modules)
+ {
+ const char *prefix;
+ prefix = grub_env_get ("prefix");
+ if (prefix)
+ {
+ char *filename;
+
+ filename = grub_xasprintf ("%s/" GRUB_TARGET_CPU "-" GRUB_PLATFORM
+ "/parttool.lst", prefix);
+ if (filename)
+ {
+ grub_file_t file;
+
+ file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST);
+ if (file)
+ {
+ char *buf = 0;
+ for (;; grub_free(buf))
+ {
+ char *p, *name;
+
+ buf = grub_file_getline (file);
+
+ if (! buf)
+ break;
+
+ name = buf;
+ while (grub_isspace (name[0]))
+ name++;
+
+ if (! grub_isgraph (name[0]))
+ continue;
+
+ p = grub_strchr (name, ':');
+ if (! p)
+ continue;
+
+ *p = '\0';
+ p++;
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ if (! grub_isgraph (*p))
+ continue;
+
+ if (grub_strcmp (name, dev->disk->partition->partmap->name)
+ != 0)
+ continue;
+
+ grub_dl_load (p);
+ }
+
+ grub_file_close (file);
+ }
+
+ grub_free (filename);
+ }
+ }
+ /* Ignore errors. */
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ if (argc == 1)
+ {
+ err = show_help (dev);
+ grub_device_close (dev);
+ return err;
+ }
+
+ for (i = 1; i < argc; i++)
+ if (grub_strcmp (args[i], "help") == 0)
+ {
+ err = show_help (dev);
+ grub_device_close (dev);
+ return err;
+ }
+
+ parsed = (int *) grub_calloc (argc, sizeof (int));
+
+ for (i = 1; i < argc; i++)
+ if (! parsed[i])
+ {
+ struct grub_parttool_argdesc *curarg;
+ struct grub_parttool_args *pargs;
+ for (cur = parts; cur; cur = cur->next)
+ if (grub_strcmp (dev->disk->partition->partmap->name, cur->name) == 0)
+ {
+ for (curarg = cur->args; curarg->name; curarg++)
+ if (grub_strncmp (curarg->name, args[i],
+ grub_strlen (curarg->name)) == 0
+ && ((curarg->type == GRUB_PARTTOOL_ARG_BOOL
+ && (args[i][grub_strlen (curarg->name)] == '+'
+ || args[i][grub_strlen (curarg->name)] == '-'
+ || args[i][grub_strlen (curarg->name)] == 0))
+ || (curarg->type == GRUB_PARTTOOL_ARG_VAL
+ && args[i][grub_strlen (curarg->name)] == '=')))
+
+ break;
+ if (curarg->name)
+ break;
+ }
+ if (! cur)
+ {
+ grub_free (parsed);
+ grub_device_close (dev);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unknown argument `%s'"),
+ args[i]);
+ }
+ ptool = cur;
+ pargs = (struct grub_parttool_args *)
+ grub_calloc (ptool->nargs, sizeof (struct grub_parttool_args));
+ for (j = i; j < argc; j++)
+ if (! parsed[j])
+ {
+ for (curarg = ptool->args; curarg->name; curarg++)
+ if (grub_strncmp (curarg->name, args[j],
+ grub_strlen (curarg->name)) == 0
+ && ((curarg->type == GRUB_PARTTOOL_ARG_BOOL
+ && (args[j][grub_strlen (curarg->name)] == '+'
+ || args[j][grub_strlen (curarg->name)] == '-'
+ || args[j][grub_strlen (curarg->name)] == 0))
+ || (curarg->type == GRUB_PARTTOOL_ARG_VAL
+ && args[j][grub_strlen (curarg->name)] == '=')))
+ {
+ parsed[j] = 1;
+ pargs[curarg - ptool->args].set = 1;
+ switch (curarg->type)
+ {
+ case GRUB_PARTTOOL_ARG_BOOL:
+ pargs[curarg - ptool->args].bool
+ = (args[j][grub_strlen (curarg->name)] != '-');
+ break;
+
+ case GRUB_PARTTOOL_ARG_VAL:
+ pargs[curarg - ptool->args].str
+ = (args[j] + grub_strlen (curarg->name) + 1);
+ break;
+
+ case GRUB_PARTTOOL_ARG_END:
+ break;
+ }
+ }
+ }
+
+ err = ptool->func (dev, pargs);
+ grub_free (pargs);
+ if (err)
+ break;
+ }
+
+ grub_free (parsed);
+ grub_device_close (dev);
+ return err;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(parttool)
+{
+ mymod = mod;
+ cmd = grub_register_command ("parttool", grub_cmd_parttool,
+ N_("PARTITION COMMANDS"),
+ helpmsg);
+}
+
+GRUB_MOD_FINI(parttool)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/password.c b/grub-core/commands/password.c
new file mode 100644
index 0000000..6d42c9b
--- /dev/null
+++ b/grub-core/commands/password.c
@@ -0,0 +1,93 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/auth.h>
+#include <grub/crypto.h>
+#include <grub/list.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/env.h>
+#include <grub/normal.h>
+#include <grub/dl.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_dl_t my_mod;
+
+static grub_err_t
+check_password (const char *user, const char *entered,
+ void *password)
+{
+ if (grub_crypto_memcmp (entered, password, GRUB_AUTH_MAX_PASSLEN) != 0)
+ return GRUB_ACCESS_DENIED;
+
+ grub_auth_authenticate (user);
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_normal_set_password (const char *user, const char *password)
+{
+ grub_err_t err;
+ char *pass;
+ int copylen;
+
+ pass = grub_zalloc (GRUB_AUTH_MAX_PASSLEN);
+ if (!pass)
+ return grub_errno;
+ copylen = grub_strlen (password);
+ if (copylen >= GRUB_AUTH_MAX_PASSLEN)
+ copylen = GRUB_AUTH_MAX_PASSLEN - 1;
+ grub_memcpy (pass, password, copylen);
+
+ err = grub_auth_register_authentication (user, check_password, pass);
+ if (err)
+ {
+ grub_free (pass);
+ return err;
+ }
+ grub_dl_ref (my_mod);
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_password (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ if (argc != 2)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
+ return grub_normal_set_password (args[0], args[1]);
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(password)
+{
+ my_mod = mod;
+ cmd = grub_register_command ("password", grub_cmd_password,
+ N_("USER PASSWORD"),
+ N_("Set user password (plaintext). "
+ "Unrecommended and insecure."));
+}
+
+GRUB_MOD_FINI(password)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/password_pbkdf2.c b/grub-core/commands/password_pbkdf2.c
new file mode 100644
index 0000000..ab845d2
--- /dev/null
+++ b/grub-core/commands/password_pbkdf2.c
@@ -0,0 +1,209 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/auth.h>
+#include <grub/crypto.h>
+#include <grub/list.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/env.h>
+#include <grub/normal.h>
+#include <grub/dl.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_dl_t my_mod;
+
+struct pbkdf2_password
+{
+ grub_uint8_t *salt;
+ grub_size_t saltlen;
+ unsigned int c;
+ grub_uint8_t *expected;
+ grub_size_t buflen;
+};
+
+static grub_err_t
+check_password (const char *user, const char *entered, void *pin)
+{
+ grub_uint8_t *buf;
+ struct pbkdf2_password *pass = pin;
+ gcry_err_code_t err;
+ grub_err_t ret;
+
+ buf = grub_malloc (pass->buflen);
+ if (!buf)
+ return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY);
+
+ err = grub_crypto_pbkdf2 (GRUB_MD_SHA512, (grub_uint8_t *) entered,
+ grub_strlen (entered),
+ pass->salt, pass->saltlen, pass->c,
+ buf, pass->buflen);
+ if (err)
+ ret = grub_crypto_gcry_error (err);
+ else if (grub_crypto_memcmp (buf, pass->expected, pass->buflen) != 0)
+ ret = GRUB_ACCESS_DENIED;
+ else
+ {
+ grub_auth_authenticate (user);
+ ret = GRUB_ERR_NONE;
+ }
+
+ grub_free (buf);
+ return ret;
+}
+
+static inline int
+hex2val (char hex)
+{
+ if ('0' <= hex && hex <= '9')
+ return hex - '0';
+ if ('a' <= hex && hex <= 'f')
+ return hex - 'a' + 10;
+ if ('A' <= hex && hex <= 'F')
+ return hex - 'A' + 10;
+ return -1;
+}
+
+static grub_err_t
+grub_cmd_password (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ grub_err_t err;
+ const char *ptr, *ptr2;
+ grub_uint8_t *ptro;
+ struct pbkdf2_password *pass;
+
+ if (argc != 2)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
+
+ if (grub_memcmp (args[1], "grub.pbkdf2.sha512.",
+ sizeof ("grub.pbkdf2.sha512.") - 1) != 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid PBKDF2 password"));
+
+ ptr = args[1] + sizeof ("grub.pbkdf2.sha512.") - 1;
+
+ pass = grub_malloc (sizeof (*pass));
+ if (!pass)
+ return grub_errno;
+
+ pass->c = grub_strtoul (ptr, &ptr, 0);
+ if (grub_errno)
+ {
+ grub_free (pass);
+ return grub_errno;
+ }
+ if (*ptr != '.')
+ {
+ grub_free (pass);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid PBKDF2 password"));
+ }
+ ptr++;
+
+ ptr2 = grub_strchr (ptr, '.');
+ if (!ptr2 || ((ptr2 - ptr) & 1) || grub_strlen (ptr2 + 1) & 1)
+ {
+ grub_free (pass);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid PBKDF2 password"));
+ }
+
+ pass->saltlen = (ptr2 - ptr) >> 1;
+ pass->buflen = grub_strlen (ptr2 + 1) >> 1;
+ ptro = pass->salt = grub_malloc (pass->saltlen);
+ if (!ptro)
+ {
+ grub_free (pass);
+ return grub_errno;
+ }
+ while (ptr < ptr2)
+ {
+ int hex1, hex2;
+ hex1 = hex2val (*ptr);
+ ptr++;
+ hex2 = hex2val (*ptr);
+ ptr++;
+ if (hex1 < 0 || hex2 < 0)
+ {
+ grub_free (pass->salt);
+ grub_free (pass);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ /* TRANSLATORS: it means that the string which
+ was supposed to be a password hash doesn't
+ have a correct format, not to password
+ mismatch. */
+ N_("invalid PBKDF2 password"));
+ }
+
+ *ptro = (hex1 << 4) | hex2;
+ ptro++;
+ }
+
+ ptro = pass->expected = grub_malloc (pass->buflen);
+ if (!ptro)
+ {
+ grub_free (pass->salt);
+ grub_free (pass);
+ return grub_errno;
+ }
+ ptr = ptr2 + 1;
+ ptr2 += grub_strlen (ptr2);
+ while (ptr < ptr2)
+ {
+ int hex1, hex2;
+ hex1 = hex2val (*ptr);
+ ptr++;
+ hex2 = hex2val (*ptr);
+ ptr++;
+ if (hex1 < 0 || hex2 < 0)
+ {
+ grub_free (pass->expected);
+ grub_free (pass->salt);
+ grub_free (pass);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("invalid PBKDF2 password"));
+ }
+
+ *ptro = (hex1 << 4) | hex2;
+ ptro++;
+ }
+
+ err = grub_auth_register_authentication (args[0], check_password, pass);
+ if (err)
+ {
+ grub_free (pass);
+ return err;
+ }
+ grub_dl_ref (my_mod);
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(password_pbkdf2)
+{
+ my_mod = mod;
+ cmd = grub_register_command ("password_pbkdf2", grub_cmd_password,
+ N_("USER PBKDF2_PASSWORD"),
+ N_("Set user password (PBKDF2). "));
+}
+
+GRUB_MOD_FINI(password_pbkdf2)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/pcidump.c b/grub-core/commands/pcidump.c
new file mode 100644
index 0000000..f72628f
--- /dev/null
+++ b/grub-core/commands/pcidump.c
@@ -0,0 +1,174 @@
+/* lspci.c - List PCI devices. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/pci.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/extcmd.h>
+#include <grub/env.h>
+#include <grub/mm.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+struct iter_cxt
+{
+ grub_uint32_t pciid_check_mask, pciid_check_value;
+ int bus, device, function;
+ int check_bus, check_device, check_function;
+};
+
+static const struct grub_arg_option options[] =
+ {
+ {0, 'd', 0, N_("Select device by vendor and device IDs."),
+ N_("[vendor]:[device]"), ARG_TYPE_STRING},
+ {0, 's', 0, N_("Select device by its position on the bus."),
+ N_("[bus]:[slot][.func]"), ARG_TYPE_STRING},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static int
+grub_pcidump_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
+ void *data)
+{
+ struct iter_cxt *ctx = data;
+ grub_pci_address_t addr;
+ int i;
+
+ if ((pciid & ctx->pciid_check_mask) != ctx->pciid_check_value)
+ return 0;
+
+ if (ctx->check_bus && grub_pci_get_bus (dev) != ctx->bus)
+ return 0;
+
+ if (ctx->check_device && grub_pci_get_device (dev) != ctx->device)
+ return 0;
+
+ if (ctx->check_function && grub_pci_get_function (dev) != ctx->function)
+ return 0;
+
+ for (i = 0; i < 256; i += 4)
+ {
+ addr = grub_pci_make_address (dev, i);
+ grub_printf ("%08x ", grub_pci_read (addr));
+ if ((i & 0xc) == 0xc)
+ grub_printf ("\n");
+ }
+
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_pcidump (grub_extcmd_context_t ctxt,
+ int argc __attribute__ ((unused)),
+ char **argv __attribute__ ((unused)))
+{
+ const char *ptr;
+ struct iter_cxt ctx =
+ {
+ .pciid_check_value = 0,
+ .pciid_check_mask = 0,
+ .check_bus = 0,
+ .check_device = 0,
+ .check_function = 0,
+ .bus = 0,
+ .function = 0,
+ .device = 0
+ };
+
+ if (ctxt->state[0].set)
+ {
+ ptr = ctxt->state[0].arg;
+ ctx.pciid_check_value |= (grub_strtoul (ptr, &ptr, 16) & 0xffff);
+ if (grub_errno == GRUB_ERR_BAD_NUMBER)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ ptr = ctxt->state[0].arg;
+ }
+ else
+ ctx.pciid_check_mask |= 0xffff;
+ if (grub_errno)
+ return grub_errno;
+ if (*ptr != ':')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("missing `%c' symbol"), ':');
+ ptr++;
+ ctx.pciid_check_value |= (grub_strtoul (ptr, &ptr, 16) & 0xffff) << 16;
+ if (grub_errno == GRUB_ERR_BAD_NUMBER)
+ grub_errno = GRUB_ERR_NONE;
+ else
+ ctx.pciid_check_mask |= 0xffff0000;
+ }
+
+ ctx.pciid_check_value &= ctx.pciid_check_mask;
+
+ if (ctxt->state[1].set)
+ {
+ const char *optr;
+
+ ptr = ctxt->state[1].arg;
+ optr = ptr;
+ ctx.bus = grub_strtoul (ptr, &ptr, 16);
+ if (grub_errno == GRUB_ERR_BAD_NUMBER)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ ptr = optr;
+ }
+ else
+ ctx.check_bus = 1;
+ if (grub_errno)
+ return grub_errno;
+ if (*ptr != ':')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("missing `%c' symbol"), ':');
+ ptr++;
+ optr = ptr;
+ ctx.device = grub_strtoul (ptr, &ptr, 16);
+ if (grub_errno == GRUB_ERR_BAD_NUMBER)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ ptr = optr;
+ }
+ else
+ ctx.check_device = 1;
+ if (*ptr == '.')
+ {
+ ptr++;
+ ctx.function = grub_strtoul (ptr, &ptr, 16);
+ if (grub_errno)
+ return grub_errno;
+ ctx.check_function = 1;
+ }
+ }
+
+ grub_pci_iterate (grub_pcidump_iter, &ctx);
+ return GRUB_ERR_NONE;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(pcidump)
+{
+ cmd = grub_register_extcmd ("pcidump", grub_cmd_pcidump, 0,
+ N_("[-s POSITION] [-d DEVICE]"),
+ N_("Show raw dump of the PCI configuration space."), options);
+}
+
+GRUB_MOD_FINI(pcidump)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
new file mode 100644
index 0000000..5daa1e9
--- /dev/null
+++ b/grub-core/commands/pgp.c
@@ -0,0 +1,1018 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/file.h>
+#include <grub/command.h>
+#include <grub/crypto.h>
+#include <grub/i18n.h>
+#include <grub/gcrypt/gcrypt.h>
+#include <grub/pubkey.h>
+#include <grub/env.h>
+#include <grub/kernel.h>
+#include <grub/extcmd.h>
+#include <grub/verify.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+enum
+ {
+ OPTION_SKIP_SIG = 0
+ };
+
+static const struct grub_arg_option options[] =
+ {
+ {"skip-sig", 's', 0,
+ N_("Skip signature-checking of the public key file."), 0, ARG_TYPE_NONE},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static grub_err_t
+read_packet_header (grub_file_t sig, grub_uint8_t *out_type, grub_size_t *len)
+{
+ grub_uint8_t type;
+ grub_uint8_t l;
+ grub_uint16_t l16;
+ grub_uint32_t l32;
+
+ /* New format. */
+ switch (grub_file_read (sig, &type, sizeof (type)))
+ {
+ case 1:
+ break;
+ case 0:
+ {
+ *out_type = 0xff;
+ return 0;
+ }
+ default:
+ if (grub_errno)
+ return grub_errno;
+ /* TRANSLATORS: it's about GNUPG signatures. */
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ }
+
+ if (type == 0)
+ {
+ *out_type = 0xfe;
+ return 0;
+ }
+
+ if (!(type & 0x80))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ if (type & 0x40)
+ {
+ *out_type = (type & 0x3f);
+ if (grub_file_read (sig, &l, sizeof (l)) != 1)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ if (l < 192)
+ {
+ *len = l;
+ return 0;
+ }
+ if (l < 224)
+ {
+ *len = (l - 192) << GRUB_CHAR_BIT;
+ if (grub_file_read (sig, &l, sizeof (l)) != 1)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ *len |= l;
+ return 0;
+ }
+ if (l == 255)
+ {
+ if (grub_file_read (sig, &l32, sizeof (l32)) != sizeof (l32))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ *len = grub_be_to_cpu32 (l32);
+ return 0;
+ }
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ }
+ *out_type = ((type >> 2) & 0xf);
+ switch (type & 0x3)
+ {
+ case 0:
+ if (grub_file_read (sig, &l, sizeof (l)) != sizeof (l))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ *len = l;
+ return 0;
+ case 1:
+ if (grub_file_read (sig, &l16, sizeof (l16)) != sizeof (l16))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ *len = grub_be_to_cpu16 (l16);
+ return 0;
+ case 2:
+ if (grub_file_read (sig, &l32, sizeof (l32)) != sizeof (l32))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ *len = grub_be_to_cpu32 (l32);
+ return 0;
+ }
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+}
+
+struct signature_v4_header
+{
+ grub_uint8_t type;
+ grub_uint8_t pkeyalgo;
+ grub_uint8_t hash;
+ grub_uint16_t hashed_sub;
+} GRUB_PACKED;
+
+const char *hashes[] = {
+ [0x01] = "md5",
+ [0x02] = "sha1",
+ [0x03] = "ripemd160",
+ [0x08] = "sha256",
+ [0x09] = "sha384",
+ [0x0a] = "sha512",
+ [0x0b] = "sha224"
+};
+
+struct gcry_pk_spec *grub_crypto_pk_dsa;
+struct gcry_pk_spec *grub_crypto_pk_ecdsa;
+struct gcry_pk_spec *grub_crypto_pk_rsa;
+
+static int
+dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
+static int
+rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
+
+struct
+{
+ const char *name;
+ grub_size_t nmpisig;
+ grub_size_t nmpipub;
+ struct gcry_pk_spec **algo;
+ int (*pad) (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
+ const char *module;
+} pkalgos[] =
+ {
+ [1] = { "rsa", 1, 2, &grub_crypto_pk_rsa, rsa_pad, "gcry_rsa" },
+ [3] = { "rsa", 1, 2, &grub_crypto_pk_rsa, rsa_pad, "gcry_rsa" },
+ [17] = { "dsa", 2, 4, &grub_crypto_pk_dsa, dsa_pad, "gcry_dsa" },
+ };
+
+struct grub_public_key
+{
+ struct grub_public_key *next;
+ struct grub_public_subkey *subkeys;
+};
+
+struct grub_public_subkey
+{
+ struct grub_public_subkey *next;
+ grub_uint8_t type;
+ grub_uint32_t fingerprint[5];
+ gcry_mpi_t mpis[10];
+};
+
+static void
+free_pk (struct grub_public_key *pk)
+{
+ struct grub_public_subkey *nsk, *sk;
+ for (sk = pk->subkeys; sk; sk = nsk)
+ {
+ grub_size_t i;
+ for (i = 0; i < ARRAY_SIZE (sk->mpis); i++)
+ if (sk->mpis[i])
+ gcry_mpi_release (sk->mpis[i]);
+ nsk = sk->next;
+ grub_free (sk);
+ }
+ grub_free (pk);
+}
+
+#define READBUF_SIZE 4096
+
+struct grub_public_key *
+grub_load_public_key (grub_file_t f)
+{
+ grub_err_t err;
+ struct grub_public_key *ret;
+ struct grub_public_subkey **last = 0;
+ void *fingerprint_context = NULL;
+ grub_uint8_t *buffer = NULL;
+
+ ret = grub_zalloc (sizeof (*ret));
+ if (!ret)
+ {
+ grub_free (fingerprint_context);
+ return NULL;
+ }
+
+ buffer = grub_zalloc (READBUF_SIZE);
+ fingerprint_context = grub_zalloc (GRUB_MD_SHA1->contextsize);
+
+ if (!buffer || !fingerprint_context)
+ goto fail;
+
+ last = &ret->subkeys;
+
+ while (1)
+ {
+ grub_uint8_t type;
+ grub_size_t len;
+ grub_uint8_t v, pk;
+ grub_uint32_t creation_time;
+ grub_off_t pend;
+ struct grub_public_subkey *sk;
+ grub_size_t i;
+ grub_uint16_t len_be;
+
+ err = read_packet_header (f, &type, &len);
+
+ if (err)
+ goto fail;
+ if (type == 0xfe)
+ continue;
+ if (type == 0xff)
+ {
+ grub_free (fingerprint_context);
+ grub_free (buffer);
+ return ret;
+ }
+
+ grub_dprintf ("crypt", "len = %x\n", (int) len);
+
+ pend = grub_file_tell (f) + len;
+ if (type != 6 && type != 14
+ && type != 5 && type != 7)
+ {
+ grub_file_seek (f, pend);
+ continue;
+ }
+
+ if (grub_file_read (f, &v, sizeof (v)) != sizeof (v))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ goto fail;
+ }
+
+ grub_dprintf ("crypt", "v = %x\n", v);
+
+ if (v != 4)
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ goto fail;
+ }
+ if (grub_file_read (f, &creation_time, sizeof (creation_time)) != sizeof (creation_time))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ goto fail;
+ }
+
+ grub_dprintf ("crypt", "time = %x\n", creation_time);
+
+ if (grub_file_read (f, &pk, sizeof (pk)) != sizeof (pk))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ goto fail;
+ }
+
+ grub_dprintf ("crypt", "pk = %x\n", pk);
+
+ if (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL)
+ {
+ grub_file_seek (f, pend);
+ continue;
+ }
+
+ sk = grub_zalloc (sizeof (struct grub_public_subkey));
+ if (!sk)
+ goto fail;
+
+ grub_memset (fingerprint_context, 0, GRUB_MD_SHA1->contextsize);
+ GRUB_MD_SHA1->init (fingerprint_context);
+ GRUB_MD_SHA1->write (fingerprint_context, "\x99", 1);
+ len_be = grub_cpu_to_be16 (len);
+ GRUB_MD_SHA1->write (fingerprint_context, &len_be, sizeof (len_be));
+ GRUB_MD_SHA1->write (fingerprint_context, &v, sizeof (v));
+ GRUB_MD_SHA1->write (fingerprint_context, &creation_time, sizeof (creation_time));
+ GRUB_MD_SHA1->write (fingerprint_context, &pk, sizeof (pk));
+
+ for (i = 0; i < pkalgos[pk].nmpipub; i++)
+ {
+ grub_uint16_t l;
+ grub_size_t lb;
+ if (grub_file_read (f, &l, sizeof (l)) != sizeof (l))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ break;
+ }
+
+ lb = (grub_be_to_cpu16 (l) + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT;
+ if (lb > READBUF_SIZE - sizeof (grub_uint16_t))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ break;
+ }
+ if (grub_file_read (f, buffer + sizeof (grub_uint16_t), lb) != (grub_ssize_t) lb)
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ break;
+ }
+ grub_memcpy (buffer, &l, sizeof (l));
+
+ GRUB_MD_SHA1->write (fingerprint_context, buffer, lb + sizeof (grub_uint16_t));
+
+ if (gcry_mpi_scan (&sk->mpis[i], GCRYMPI_FMT_PGP,
+ buffer, lb + sizeof (grub_uint16_t), 0))
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ break;
+ }
+ }
+
+ if (i < pkalgos[pk].nmpipub)
+ {
+ grub_free (sk);
+ goto fail;
+ }
+
+ GRUB_MD_SHA1->final (fingerprint_context);
+
+ grub_memcpy (sk->fingerprint, GRUB_MD_SHA1->read (fingerprint_context), 20);
+
+ *last = sk;
+ last = &sk->next;
+
+ grub_dprintf ("crypt", "actual pos: %x, expected: %x\n", (int)grub_file_tell (f), (int)pend);
+
+ grub_file_seek (f, pend);
+ }
+ fail:
+ free_pk (ret);
+ grub_free (fingerprint_context);
+ grub_free (buffer);
+ return NULL;
+}
+
+struct grub_public_key *grub_pk_trusted;
+
+struct grub_public_subkey *
+grub_crypto_pk_locate_subkey (grub_uint64_t keyid, struct grub_public_key *pkey)
+{
+ struct grub_public_subkey *sk;
+ for (sk = pkey->subkeys; sk; sk = sk->next)
+ if (grub_memcmp (sk->fingerprint + 3, &keyid, 8) == 0)
+ return sk;
+ return 0;
+}
+
+struct grub_public_subkey *
+grub_crypto_pk_locate_subkey_in_trustdb (grub_uint64_t keyid)
+{
+ struct grub_public_key *pkey;
+ struct grub_public_subkey *sk;
+ for (pkey = grub_pk_trusted; pkey; pkey = pkey->next)
+ {
+ sk = grub_crypto_pk_locate_subkey (keyid, pkey);
+ if (sk)
+ return sk;
+ }
+ return 0;
+}
+
+
+static int
+dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
+{
+ unsigned nbits = gcry_mpi_get_nbits (sk->mpis[1]);
+ grub_dprintf ("crypt", "must be %u bits got %d bits\n", nbits,
+ (int)(8 * hash->mdlen));
+ return gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, hval,
+ nbits / 8 < (unsigned) hash->mdlen ? nbits / 8
+ : (unsigned) hash->mdlen, 0);
+}
+
+static int
+rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
+{
+ grub_size_t tlen, emlen, fflen;
+ grub_uint8_t *em, *emptr;
+ unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]);
+ int ret;
+ tlen = hash->mdlen + hash->asnlen;
+ emlen = (nbits + 7) / 8;
+ if (emlen < tlen + 11)
+ return 1;
+
+ em = grub_malloc (emlen);
+ if (!em)
+ return 1;
+
+ em[0] = 0x00;
+ em[1] = 0x01;
+ fflen = emlen - tlen - 3;
+ for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
+ *emptr = 0xff;
+ *emptr++ = 0x00;
+ grub_memcpy (emptr, hash->asnoid, hash->asnlen);
+ emptr += hash->asnlen;
+ grub_memcpy (emptr, hval, hash->mdlen);
+
+ ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
+ grub_free (em);
+ return ret;
+}
+
+struct grub_pubkey_context
+{
+ grub_file_t sig;
+ struct signature_v4_header v4;
+ grub_uint8_t v;
+ const gcry_md_spec_t *hash;
+ void *hash_context;
+};
+
+static grub_err_t
+grub_verify_signature_init (struct grub_pubkey_context *ctxt, grub_file_t sig)
+{
+ grub_size_t len;
+ grub_uint8_t h;
+ grub_uint8_t t;
+ grub_uint8_t pk;
+ grub_err_t err;
+ grub_uint8_t type = 0;
+
+ grub_memset (ctxt, 0, sizeof (*ctxt));
+
+ err = read_packet_header (sig, &type, &len);
+ if (err)
+ return err;
+
+ if (type != 0x2)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ if (grub_file_read (sig, &ctxt->v, sizeof (ctxt->v)) != sizeof (ctxt->v))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ if (ctxt->v != 4)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ if (grub_file_read (sig, &ctxt->v4, sizeof (ctxt->v4)) != sizeof (ctxt->v4))
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ h = ctxt->v4.hash;
+ t = ctxt->v4.type;
+ pk = ctxt->v4.pkeyalgo;
+
+ if (t != 0)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ if (h >= ARRAY_SIZE (hashes) || hashes[h] == NULL)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, "unknown hash");
+
+ if (pk >= ARRAY_SIZE (pkalgos) || pkalgos[pk].name == NULL)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+
+ ctxt->hash = grub_crypto_lookup_md_by_name (hashes[h]);
+ if (!ctxt->hash)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, "hash `%s' not loaded", hashes[h]);
+
+ grub_dprintf ("crypt", "alive\n");
+
+ ctxt->hash_context = grub_zalloc (ctxt->hash->contextsize);
+ if (!ctxt->hash_context)
+ return grub_errno;
+
+ ctxt->hash->init (ctxt->hash_context);
+ ctxt->sig = sig;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_pubkey_write (void *ctxt_, void *buf, grub_size_t size)
+{
+ struct grub_pubkey_context *ctxt = ctxt_;
+ ctxt->hash->write (ctxt->hash_context, buf, size);
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_verify_signature_real (struct grub_pubkey_context *ctxt,
+ struct grub_public_key *pkey)
+{
+ gcry_mpi_t mpis[10];
+ grub_uint8_t pk = ctxt->v4.pkeyalgo;
+ grub_size_t i;
+ grub_uint8_t *readbuf = NULL;
+ unsigned char *hval;
+ grub_ssize_t rem = grub_be_to_cpu16 (ctxt->v4.hashed_sub);
+ grub_uint32_t headlen = grub_cpu_to_be32 (rem + 6);
+ grub_uint8_t s;
+ grub_uint16_t unhashed_sub;
+ grub_ssize_t r;
+ grub_uint8_t hash_start[2];
+ gcry_mpi_t hmpi;
+ grub_uint64_t keyid = 0;
+ struct grub_public_subkey *sk;
+
+ readbuf = grub_malloc (READBUF_SIZE);
+ if (!readbuf)
+ goto fail;
+
+ ctxt->hash->write (ctxt->hash_context, &ctxt->v, sizeof (ctxt->v));
+ ctxt->hash->write (ctxt->hash_context, &ctxt->v4, sizeof (ctxt->v4));
+ while (rem)
+ {
+ r = grub_file_read (ctxt->sig, readbuf,
+ rem < READBUF_SIZE ? rem : READBUF_SIZE);
+ if (r < 0)
+ goto fail;
+ if (r == 0)
+ break;
+ ctxt->hash->write (ctxt->hash_context, readbuf, r);
+ rem -= r;
+ }
+ ctxt->hash->write (ctxt->hash_context, &ctxt->v, sizeof (ctxt->v));
+ s = 0xff;
+ ctxt->hash->write (ctxt->hash_context, &s, sizeof (s));
+ ctxt->hash->write (ctxt->hash_context, &headlen, sizeof (headlen));
+ r = grub_file_read (ctxt->sig, &unhashed_sub, sizeof (unhashed_sub));
+ if (r != sizeof (unhashed_sub))
+ goto fail;
+ {
+ grub_uint8_t *ptr;
+ grub_uint32_t l;
+ rem = grub_be_to_cpu16 (unhashed_sub);
+ if (rem > READBUF_SIZE)
+ goto fail;
+ r = grub_file_read (ctxt->sig, readbuf, rem);
+ if (r != rem)
+ goto fail;
+ for (ptr = readbuf; ptr < readbuf + rem; ptr += l)
+ {
+ if (*ptr < 192)
+ l = *ptr++;
+ else if (*ptr < 255)
+ {
+ if (ptr + 1 >= readbuf + rem)
+ break;
+ l = (((ptr[0] & ~192) << GRUB_CHAR_BIT) | ptr[1]) + 192;
+ ptr += 2;
+ }
+ else
+ {
+ if (ptr + 5 >= readbuf + rem)
+ break;
+ l = grub_be_to_cpu32 (grub_get_unaligned32 (ptr + 1));
+ ptr += 5;
+ }
+ if (*ptr == 0x10 && l >= 8)
+ keyid = grub_get_unaligned64 (ptr + 1);
+ }
+ }
+
+ ctxt->hash->final (ctxt->hash_context);
+
+ grub_dprintf ("crypt", "alive\n");
+
+ hval = ctxt->hash->read (ctxt->hash_context);
+
+ if (grub_file_read (ctxt->sig, hash_start, sizeof (hash_start)) != sizeof (hash_start))
+ goto fail;
+ if (grub_memcmp (hval, hash_start, sizeof (hash_start)) != 0)
+ goto fail;
+
+ grub_dprintf ("crypt", "@ %x\n", (int)grub_file_tell (ctxt->sig));
+
+ for (i = 0; i < pkalgos[pk].nmpisig; i++)
+ {
+ grub_uint16_t l;
+ grub_size_t lb;
+ grub_dprintf ("crypt", "alive\n");
+ if (grub_file_read (ctxt->sig, &l, sizeof (l)) != sizeof (l))
+ goto fail;
+ grub_dprintf ("crypt", "alive\n");
+ lb = (grub_be_to_cpu16 (l) + 7) / 8;
+ grub_dprintf ("crypt", "l = 0x%04x\n", grub_be_to_cpu16 (l));
+ if (lb > READBUF_SIZE - sizeof (grub_uint16_t))
+ goto fail;
+ grub_dprintf ("crypt", "alive\n");
+ if (grub_file_read (ctxt->sig, readbuf + sizeof (grub_uint16_t), lb) != (grub_ssize_t) lb)
+ goto fail;
+ grub_dprintf ("crypt", "alive\n");
+ grub_memcpy (readbuf, &l, sizeof (l));
+ grub_dprintf ("crypt", "alive\n");
+
+ if (gcry_mpi_scan (&mpis[i], GCRYMPI_FMT_PGP,
+ readbuf, lb + sizeof (grub_uint16_t), 0))
+ goto fail;
+ grub_dprintf ("crypt", "alive\n");
+ }
+
+ if (pkey)
+ sk = grub_crypto_pk_locate_subkey (keyid, pkey);
+ else
+ sk = grub_crypto_pk_locate_subkey_in_trustdb (keyid);
+ if (!sk)
+ {
+ /* TRANSLATORS: %08x is 32-bit key id. */
+ grub_error (GRUB_ERR_BAD_SIGNATURE,
+ N_("public key %08" PRIxGRUB_UINT64_T " not found"), keyid);
+ goto fail;
+ }
+
+ if (pkalgos[pk].pad (&hmpi, hval, ctxt->hash, sk))
+ goto fail;
+ if (!*pkalgos[pk].algo)
+ {
+ grub_dl_load (pkalgos[pk].module);
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ if (!*pkalgos[pk].algo)
+ {
+ grub_error (GRUB_ERR_BAD_SIGNATURE, N_("module `%s' isn't loaded"),
+ pkalgos[pk].module);
+ goto fail;
+ }
+ if ((*pkalgos[pk].algo)->verify (0, hmpi, mpis, sk->mpis, 0, 0))
+ goto fail;
+
+ grub_free (readbuf);
+
+ return GRUB_ERR_NONE;
+
+ fail:
+ grub_free (readbuf);
+ if (!grub_errno)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad signature"));
+ return grub_errno;
+}
+
+static void
+grub_pubkey_close_real (struct grub_pubkey_context *ctxt)
+{
+ if (ctxt->sig)
+ grub_file_close (ctxt->sig);
+ if (ctxt->hash_context)
+ grub_free (ctxt->hash_context);
+}
+
+static void
+grub_pubkey_close (void *ctxt)
+{
+ grub_pubkey_close_real (ctxt);
+ grub_free (ctxt);
+}
+
+grub_err_t
+grub_verify_signature (grub_file_t f, const char *fsig,
+ struct grub_public_key *pkey)
+{
+ grub_file_t sig;
+ grub_err_t err;
+ struct grub_pubkey_context ctxt;
+ grub_uint8_t *readbuf = NULL;
+
+ sig = grub_file_open (fsig,
+ GRUB_FILE_TYPE_SIGNATURE
+ | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (!sig)
+ return grub_errno;
+
+ err = grub_verify_signature_init (&ctxt, sig);
+ if (err)
+ {
+ grub_file_close (sig);
+ return err;
+ }
+
+ readbuf = grub_zalloc (READBUF_SIZE);
+ if (!readbuf)
+ goto fail;
+
+ while (1)
+ {
+ grub_ssize_t r;
+ r = grub_file_read (f, readbuf, READBUF_SIZE);
+ if (r < 0)
+ goto fail;
+ if (r == 0)
+ break;
+ err = grub_pubkey_write (&ctxt, readbuf, r);
+ if (err)
+ return err;
+ }
+
+ grub_verify_signature_real (&ctxt, pkey);
+ fail:
+ grub_pubkey_close_real (&ctxt);
+ return grub_errno;
+}
+
+static grub_err_t
+grub_cmd_trust (grub_extcmd_context_t ctxt,
+ int argc, char **args)
+{
+ grub_file_t pkf;
+ struct grub_public_key *pk = NULL;
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+
+ pkf = grub_file_open (args[0],
+ GRUB_FILE_TYPE_PUBLIC_KEY_TRUST
+ | GRUB_FILE_TYPE_NO_DECOMPRESS
+ | (ctxt->state[OPTION_SKIP_SIG].set
+ ? GRUB_FILE_TYPE_SKIP_SIGNATURE
+ : GRUB_FILE_TYPE_NONE));
+ if (!pkf)
+ return grub_errno;
+ pk = grub_load_public_key (pkf);
+ if (!pk)
+ {
+ grub_file_close (pkf);
+ return grub_errno;
+ }
+ grub_file_close (pkf);
+
+ pk->next = grub_pk_trusted;
+ grub_pk_trusted = pk;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_list (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ struct grub_public_key *pk = NULL;
+ struct grub_public_subkey *sk = NULL;
+
+ for (pk = grub_pk_trusted; pk; pk = pk->next)
+ for (sk = pk->subkeys; sk; sk = sk->next)
+ {
+ unsigned i;
+ for (i = 0; i < 20; i += 2)
+ grub_printf ("%02x%02x ", ((grub_uint8_t *) sk->fingerprint)[i],
+ ((grub_uint8_t *) sk->fingerprint)[i + 1]);
+ grub_printf ("\n");
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_distrust (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ grub_uint32_t keyid, keyid_be;
+ struct grub_public_key **pkey;
+ struct grub_public_subkey *sk;
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+ keyid = grub_strtoull (args[0], 0, 16);
+ if (grub_errno)
+ return grub_errno;
+ keyid_be = grub_cpu_to_be32 (keyid);
+
+ for (pkey = &grub_pk_trusted; *pkey; pkey = &((*pkey)->next))
+ {
+ struct grub_public_key *next;
+ for (sk = (*pkey)->subkeys; sk; sk = sk->next)
+ if (grub_memcmp (sk->fingerprint + 4, &keyid_be, 4) == 0)
+ break;
+ if (!sk)
+ continue;
+ next = (*pkey)->next;
+ free_pk (*pkey);
+ *pkey = next;
+ return GRUB_ERR_NONE;
+ }
+ /* TRANSLATORS: %08x is 32-bit key id. */
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("public key %08x not found"), keyid);
+}
+
+static grub_err_t
+grub_cmd_verify_signature (grub_extcmd_context_t ctxt,
+ int argc, char **args)
+{
+ grub_file_t f = NULL;
+ grub_err_t err = GRUB_ERR_NONE;
+ struct grub_public_key *pk = NULL;
+
+ grub_dprintf ("crypt", "alive\n");
+
+ if (argc < 2)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
+
+ grub_dprintf ("crypt", "alive\n");
+
+ if (argc > 2)
+ {
+ grub_file_t pkf;
+ pkf = grub_file_open (args[2],
+ GRUB_FILE_TYPE_PUBLIC_KEY
+ | GRUB_FILE_TYPE_NO_DECOMPRESS
+ | (ctxt->state[OPTION_SKIP_SIG].set
+ ? GRUB_FILE_TYPE_SKIP_SIGNATURE
+ : GRUB_FILE_TYPE_NONE));
+ if (!pkf)
+ return grub_errno;
+ pk = grub_load_public_key (pkf);
+ if (!pk)
+ {
+ grub_file_close (pkf);
+ return grub_errno;
+ }
+ grub_file_close (pkf);
+ }
+
+ f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
+ if (!f)
+ {
+ err = grub_errno;
+ goto fail;
+ }
+
+ err = grub_verify_signature (f, args[1], pk);
+ fail:
+ if (f)
+ grub_file_close (f);
+ if (pk)
+ free_pk (pk);
+ return err;
+}
+
+static int sec = 0;
+
+static grub_err_t
+grub_pubkey_init (grub_file_t io, enum grub_file_type type __attribute__ ((unused)),
+ void **context, enum grub_verify_flags *flags)
+{
+ grub_file_t sig;
+ char *fsuf, *ptr;
+ grub_err_t err;
+ struct grub_pubkey_context *ctxt;
+
+ if (!sec)
+ {
+ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
+ return GRUB_ERR_NONE;
+ }
+
+ fsuf = grub_malloc (grub_strlen (io->name) + sizeof (".sig"));
+ if (!fsuf)
+ return grub_errno;
+ ptr = grub_stpcpy (fsuf, io->name);
+ grub_memcpy (ptr, ".sig", sizeof (".sig"));
+
+ sig = grub_file_open (fsuf, GRUB_FILE_TYPE_SIGNATURE);
+ grub_free (fsuf);
+ if (!sig)
+ return grub_errno;
+
+ ctxt = grub_malloc (sizeof (*ctxt));
+ if (!ctxt)
+ {
+ grub_file_close (sig);
+ return grub_errno;
+ }
+ err = grub_verify_signature_init (ctxt, sig);
+ if (err)
+ {
+ grub_free (ctxt);
+ grub_file_close (sig);
+ return err;
+ }
+ *context = ctxt;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_pubkey_fini (void *ctxt)
+{
+ return grub_verify_signature_real (ctxt, NULL);
+}
+
+static char *
+grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)),
+ const char *val)
+{
+ sec = (*val == '1') || (*val == 'e');
+ 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",
+ .init = grub_pubkey_init,
+ .fini = grub_pubkey_fini,
+ .write = grub_pubkey_write,
+ .close = grub_pubkey_close,
+ };
+
+static grub_extcmd_t cmd, cmd_trust;
+static grub_command_t cmd_distrust, cmd_list;
+
+GRUB_MOD_INIT(pgp)
+{
+ const char *val;
+ struct grub_module_header *header;
+
+ val = grub_env_get ("check_signatures");
+ if (val && (val[0] == '1' || val[0] == 'e'))
+ sec = 1;
+ else
+ sec = 0;
+
+ grub_register_variable_hook ("check_signatures", 0, grub_env_write_sec);
+ grub_env_export ("check_signatures");
+
+ grub_pk_trusted = 0;
+ FOR_MODULES (header)
+ {
+ struct grub_file pseudo_file;
+ struct grub_public_key *pk = NULL;
+
+ grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
+
+ /* Not an ELF module, skip. */
+ if (header->type != OBJ_TYPE_PUBKEY)
+ continue;
+
+ pseudo_file.fs = &pseudo_fs;
+ pseudo_file.size = (header->size - sizeof (struct grub_module_header));
+ pseudo_file.data = (char *) header + sizeof (struct grub_module_header);
+
+ pk = grub_load_public_key (&pseudo_file);
+ if (!pk)
+ grub_fatal ("error loading initial key: %s\n", grub_errmsg);
+
+ pk->next = grub_pk_trusted;
+ grub_pk_trusted = pk;
+ }
+
+ if (!val)
+ grub_env_set ("check_signatures", grub_pk_trusted ? "enforce" : "no");
+
+ cmd = grub_register_extcmd ("verify_detached", grub_cmd_verify_signature, 0,
+ N_("[-s|--skip-sig] FILE SIGNATURE_FILE [PUBKEY_FILE]"),
+ N_("Verify detached signature."),
+ options);
+ cmd_trust = grub_register_extcmd ("trust", grub_cmd_trust, 0,
+ N_("[-s|--skip-sig] PUBKEY_FILE"),
+ N_("Add PUBKEY_FILE to trusted keys."),
+ options);
+ cmd_list = grub_register_command ("list_trusted", grub_cmd_list,
+ 0,
+ N_("Show the list of trusted keys."));
+ cmd_distrust = grub_register_command ("distrust", grub_cmd_distrust,
+ N_("PUBKEY_ID"),
+ N_("Remove PUBKEY_ID from trusted keys."));
+
+ grub_verifier_register (&grub_pubkey_verifier);
+}
+
+GRUB_MOD_FINI(pgp)
+{
+ grub_verifier_unregister (&grub_pubkey_verifier);
+ grub_unregister_extcmd (cmd);
+ grub_unregister_extcmd (cmd_trust);
+ grub_unregister_command (cmd_list);
+ grub_unregister_command (cmd_distrust);
+}
diff --git a/grub-core/commands/probe.c b/grub-core/commands/probe.c
new file mode 100644
index 0000000..e53b611
--- /dev/null
+++ b/grub-core/commands/probe.c
@@ -0,0 +1,225 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/gpt_partition.h>
+#include <grub/net.h>
+#include <grub/fs.h>
+#include <grub/file.h>
+#include <grub/misc.h>
+#include <grub/env.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+#include <grub/i386/pc/boot.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =
+ {
+ {"set", 's', 0,
+ N_("Set a variable to return value."), N_("VARNAME"), ARG_TYPE_STRING},
+ /* TRANSLATORS: It's a driver that is currently in use to access
+ the diven disk. */
+ {"driver", 'd', 0, N_("Determine driver."), 0, 0},
+ {"partmap", 'p', 0, N_("Determine partition map type."), 0, 0},
+ {"fs", 'f', 0, N_("Determine filesystem type."), 0, 0},
+ {"fs-uuid", 'u', 0, N_("Determine filesystem UUID."), 0, 0},
+ {"label", 'l', 0, N_("Determine filesystem label."), 0, 0},
+ {"part-uuid", 0, 0, N_("Determine partition UUID."), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static grub_err_t
+grub_cmd_probe (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ grub_device_t dev;
+ grub_fs_t fs;
+ char *ptr;
+ grub_err_t err;
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
+
+ ptr = args[0] + grub_strlen (args[0]) - 1;
+ if (args[0][0] == '(' && *ptr == ')')
+ {
+ *ptr = 0;
+ dev = grub_device_open (args[0] + 1);
+ *ptr = ')';
+ }
+ else
+ dev = grub_device_open (args[0]);
+ if (! dev)
+ return grub_errno;
+
+ if (state[1].set)
+ {
+ const char *val = "none";
+ if (dev->net)
+ val = dev->net->protocol->name;
+ if (dev->disk)
+ val = dev->disk->dev->name;
+ if (state[0].set)
+ grub_env_set (state[0].arg, val);
+ else
+ grub_printf ("%s", val);
+ grub_device_close (dev);
+ return GRUB_ERR_NONE;
+ }
+ if (state[2].set)
+ {
+ const char *val = "none";
+ if (dev->disk && dev->disk->partition)
+ val = dev->disk->partition->partmap->name;
+ if (state[0].set)
+ grub_env_set (state[0].arg, val);
+ else
+ grub_printf ("%s", val);
+ grub_device_close (dev);
+ return GRUB_ERR_NONE;
+ }
+ if (state[6].set)
+ {
+ /* AAAABBBB-CCCC-DDDD-EEEE-FFFFFFFFFFFF + null terminator */
+ char val[37] = "none";
+ if (dev->disk && dev->disk->partition)
+ {
+ struct grub_partition *p = dev->disk->partition;
+ grub_disk_t disk = grub_disk_open(dev->disk->name);
+
+ if (!disk)
+ {
+ grub_device_close (dev);
+ return grub_errno;
+ }
+
+ if (grub_strcmp(dev->disk->partition->partmap->name, "gpt") == 0)
+ {
+ struct grub_gpt_partentry entry;
+ grub_gpt_part_guid_t *guid;
+
+ if (grub_disk_read(disk, p->offset, p->index, sizeof(entry), &entry))
+ return grub_errno;
+ guid = &entry.guid;
+ grub_snprintf (val, sizeof(val),
+ "%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]);
+ }
+ else if (grub_strcmp(dev->disk->partition->partmap->name, "msdos") == 0)
+ {
+ grub_uint32_t nt_disk_sig;
+
+ if (grub_disk_read(disk, 0, GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
+ sizeof(nt_disk_sig), &nt_disk_sig) == 0)
+ grub_snprintf (val, sizeof(val), "%08x-%02x",
+ grub_le_to_cpu32(nt_disk_sig), 1 + p->number);
+ }
+ grub_disk_close(disk);
+ }
+ if (state[0].set)
+ grub_env_set (state[0].arg, val);
+ else
+ grub_printf ("%s", val);
+ grub_device_close (dev);
+ return GRUB_ERR_NONE;
+ }
+ fs = grub_fs_probe (dev);
+ if (! fs)
+ return grub_errno;
+ if (state[3].set)
+ {
+ if (state[0].set)
+ grub_env_set (state[0].arg, fs->name);
+ else
+ grub_printf ("%s", fs->name);
+ grub_device_close (dev);
+ return GRUB_ERR_NONE;
+ }
+ if (state[4].set)
+ {
+ char *uuid;
+ if (! fs->fs_uuid)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ N_("%s does not support UUIDs"), fs->name);
+ err = fs->fs_uuid (dev, &uuid);
+ if (err)
+ return err;
+ if (! uuid)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ N_("%s does not support UUIDs"), fs->name);
+
+ if (state[0].set)
+ grub_env_set (state[0].arg, uuid);
+ else
+ grub_printf ("%s", uuid);
+ grub_free (uuid);
+ grub_device_close (dev);
+ return GRUB_ERR_NONE;
+ }
+ if (state[5].set)
+ {
+ char *label;
+ if (! fs->fs_label)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ N_("filesystem `%s' does not support labels"),
+ fs->name);
+ err = fs->fs_label (dev, &label);
+ if (err)
+ return err;
+ if (! label)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ N_("filesystem `%s' does not support labels"),
+ fs->name);
+
+ if (state[0].set)
+ grub_env_set (state[0].arg, label);
+ else
+ grub_printf ("%s", label);
+ grub_free (label);
+ grub_device_close (dev);
+ return GRUB_ERR_NONE;
+ }
+ grub_device_close (dev);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "unrecognised target");
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT (probe)
+{
+ cmd = grub_register_extcmd ("probe", grub_cmd_probe, 0, N_("DEVICE"),
+ N_("Retrieve device info."), options);
+}
+
+GRUB_MOD_FINI (probe)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/read.c b/grub-core/commands/read.c
new file mode 100644
index 0000000..fe3e88b
--- /dev/null
+++ b/grub-core/commands/read.c
@@ -0,0 +1,92 @@
+/* read.c - Command to read variables from user. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/env.h>
+#include <grub/term.h>
+#include <grub/types.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static char *
+grub_getline (void)
+{
+ int i;
+ char *line;
+ char *tmp;
+ char c;
+
+ i = 0;
+ line = grub_malloc (1 + i + sizeof('\0'));
+ if (! line)
+ return NULL;
+
+ while (1)
+ {
+ c = grub_getkey ();
+ if ((c == '\n') || (c == '\r'))
+ break;
+
+ line[i] = c;
+ if (grub_isprint (c))
+ grub_printf ("%c", c);
+ i++;
+ tmp = grub_realloc (line, 1 + i + sizeof('\0'));
+ if (! tmp)
+ {
+ grub_free (line);
+ return NULL;
+ }
+ line = tmp;
+ }
+ line[i] = '\0';
+
+ return line;
+}
+
+static grub_err_t
+grub_cmd_read (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
+{
+ char *line = grub_getline ();
+ if (! line)
+ return grub_errno;
+ if (argc > 0)
+ grub_env_set (args[0], line);
+
+ grub_free (line);
+ return 0;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(read)
+{
+ cmd = grub_register_command ("read", grub_cmd_read,
+ N_("[ENVVAR]"),
+ N_("Set variable with user input."));
+}
+
+GRUB_MOD_FINI(read)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/reboot.c b/grub-core/commands/reboot.c
new file mode 100644
index 0000000..46d364c
--- /dev/null
+++ b/grub-core/commands/reboot.c
@@ -0,0 +1,46 @@
+/* reboot.c - command to reboot the computer. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2007,2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/command.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t __attribute__ ((noreturn))
+grub_cmd_reboot (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ grub_reboot ();
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(reboot)
+{
+ cmd = grub_register_command ("reboot", grub_cmd_reboot,
+ 0, N_("Reboot the computer."));
+}
+
+GRUB_MOD_FINI(reboot)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/regexp.c b/grub-core/commands/regexp.c
new file mode 100644
index 0000000..612003f
--- /dev/null
+++ b/grub-core/commands/regexp.c
@@ -0,0 +1,168 @@
+/* regexp.c -- The regexp command. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2007 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/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/env.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+#include <grub/script_sh.h>
+#include <regex.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =
+ {
+ { "set", 's', GRUB_ARG_OPTION_REPEATABLE,
+ /* TRANSLATORS: in regexp you can mark some
+ groups with parentheses. These groups are
+ then numbered and you can save some of
+ them in variables. In other programs
+ those components aree often referenced with
+ back slash, e.g. \1. Compare
+ sed -e 's,\([a-z][a-z]*\),lowercase=\1,g'
+ The whole matching component is saved in VARNAME, not its number.
+ */
+ N_("Store matched component NUMBER in VARNAME."),
+ N_("[NUMBER:]VARNAME"), ARG_TYPE_STRING },
+ { 0, 0, 0, 0, 0, 0 }
+ };
+
+static grub_err_t
+setvar (char *str, char *v, regmatch_t *m)
+{
+ char ch;
+ grub_err_t err;
+ ch = str[m->rm_eo];
+ str[m->rm_eo] = '\0';
+ err = grub_env_set (v, str + m->rm_so);
+ str[m->rm_eo] = ch;
+ return err;
+}
+
+static grub_err_t
+set_matches (char **varnames, char *str, grub_size_t nmatches,
+ regmatch_t *matches)
+{
+ int i;
+ char *p;
+ const char * q;
+ grub_err_t err;
+ unsigned long j;
+
+ for (i = 0; varnames && varnames[i]; i++)
+ {
+ err = GRUB_ERR_NONE;
+ p = grub_strchr (varnames[i], ':');
+ if (! p)
+ {
+ /* varname w/o index defaults to 1 */
+ if (nmatches < 2 || matches[1].rm_so == -1)
+ grub_env_unset (varnames[i]);
+ else
+ err = setvar (str, varnames[i], &matches[1]);
+ }
+ else
+ {
+ j = grub_strtoul (varnames[i], &q, 10);
+ if (q != p)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "invalid variable name format %s", varnames[i]);
+
+ if (nmatches <= j || matches[j].rm_so == -1)
+ grub_env_unset (p + 1);
+ else
+ err = setvar (str, p + 1, &matches[j]);
+ }
+
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_regexp (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ regex_t regex;
+ int ret;
+ grub_size_t s;
+ char *comperr;
+ grub_err_t err;
+ regmatch_t *matches = 0;
+
+ if (argc != 2)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
+
+ ret = regcomp (&regex, args[0], REG_EXTENDED);
+ if (ret)
+ goto fail;
+
+ matches = grub_calloc (regex.re_nsub + 1, sizeof (*matches));
+ if (! matches)
+ goto fail;
+
+ ret = regexec (&regex, args[1], regex.re_nsub + 1, matches, 0);
+ if (!ret)
+ {
+ err = set_matches (ctxt->state[0].args, args[1],
+ regex.re_nsub + 1, matches);
+ regfree (&regex);
+ grub_free (matches);
+ return err;
+ }
+
+ fail:
+ grub_free (matches);
+ s = regerror (ret, &regex, 0, 0);
+ comperr = grub_malloc (s);
+ if (!comperr)
+ {
+ regfree (&regex);
+ return grub_errno;
+ }
+ regerror (ret, &regex, comperr, s);
+ err = grub_error (GRUB_ERR_TEST_FAILURE, "%s", comperr);
+ regfree (&regex);
+ grub_free (comperr);
+ return err;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(regexp)
+{
+ cmd = grub_register_extcmd ("regexp", grub_cmd_regexp, 0,
+ /* TRANSLATORS: This are two arguments. So it's
+ two separate units to translate and pay
+ attention not to reverse them. */
+ N_("REGEXP STRING"),
+ N_("Test if REGEXP matches STRING."), options);
+
+ /* Setup GRUB script wildcard translator. */
+ grub_wildcard_translator = &grub_filename_translator;
+}
+
+GRUB_MOD_FINI(regexp)
+{
+ grub_unregister_extcmd (cmd);
+ grub_wildcard_translator = 0;
+}
diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c
new file mode 100644
index 0000000..ed090b3
--- /dev/null
+++ b/grub-core/commands/search.c
@@ -0,0 +1,337 @@
+/* search.c - search devices based on a file or a filesystem label */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2007,2008,2009 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/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/device.h>
+#include <grub/file.h>
+#include <grub/env.h>
+#include <grub/command.h>
+#include <grub/search.h>
+#include <grub/i18n.h>
+#include <grub/disk.h>
+#include <grub/partition.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+struct cache_entry
+{
+ struct cache_entry *next;
+ char *key;
+ char *value;
+};
+
+static struct cache_entry *cache;
+
+/* Context for FUNC_NAME. */
+struct search_ctx
+{
+ const char *key;
+ const char *var;
+ int no_floppy;
+ char **hints;
+ unsigned nhints;
+ int count;
+ int is_cache;
+};
+
+/* Helper for FUNC_NAME. */
+static int
+iterate_device (const char *name, void *data)
+{
+ struct search_ctx *ctx = data;
+ int found = 0;
+
+ /* Skip floppy drives when requested. */
+ if (ctx->no_floppy &&
+ name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9')
+ return 1;
+
+#ifdef DO_SEARCH_FS_UUID
+#define compare_fn grub_strcasecmp
+#else
+#define compare_fn grub_strcmp
+#endif
+
+#ifdef DO_SEARCH_FILE
+ {
+ char *buf;
+ grub_file_t file;
+
+ buf = grub_xasprintf ("(%s)%s", name, ctx->key);
+ if (! buf)
+ return 1;
+
+ file = grub_file_open (buf, GRUB_FILE_TYPE_FS_SEARCH
+ | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (file)
+ {
+ found = 1;
+ grub_file_close (file);
+ }
+ grub_free (buf);
+ }
+#else
+ {
+ /* SEARCH_FS_UUID or SEARCH_LABEL */
+ grub_device_t dev;
+ grub_fs_t fs;
+ char *quid;
+
+ dev = grub_device_open (name);
+ if (dev)
+ {
+ fs = grub_fs_probe (dev);
+
+#ifdef DO_SEARCH_FS_UUID
+#define read_fn fs_uuid
+#else
+#define read_fn fs_label
+#endif
+
+ if (fs && fs->read_fn)
+ {
+ fs->read_fn (dev, &quid);
+
+ if (grub_errno == GRUB_ERR_NONE && quid)
+ {
+ if (compare_fn (quid, ctx->key) == 0)
+ found = 1;
+
+ grub_free (quid);
+ }
+ }
+
+ grub_device_close (dev);
+ }
+ }
+#endif
+
+ if (!ctx->is_cache && found && ctx->count == 0)
+ {
+ struct cache_entry *cache_ent;
+ cache_ent = grub_malloc (sizeof (*cache_ent));
+ if (cache_ent)
+ {
+ cache_ent->key = grub_strdup (ctx->key);
+ cache_ent->value = grub_strdup (name);
+ if (cache_ent->value && cache_ent->key)
+ {
+ cache_ent->next = cache;
+ cache = cache_ent;
+ }
+ else
+ {
+ grub_free (cache_ent->value);
+ grub_free (cache_ent->key);
+ grub_free (cache_ent);
+ grub_errno = GRUB_ERR_NONE;
+ }
+ }
+ else
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ if (found)
+ {
+ ctx->count++;
+ if (ctx->var)
+ grub_env_set (ctx->var, name);
+ else
+ grub_printf (" %s", name);
+ }
+
+ grub_errno = GRUB_ERR_NONE;
+ return (found && ctx->var);
+}
+
+/* Helper for FUNC_NAME. */
+static int
+part_hook (grub_disk_t disk, const grub_partition_t partition, void *data)
+{
+ struct search_ctx *ctx = data;
+ char *partition_name, *devname;
+ int ret;
+
+ partition_name = grub_partition_get_name (partition);
+ if (! partition_name)
+ return 1;
+
+ devname = grub_xasprintf ("%s,%s", disk->name, partition_name);
+ grub_free (partition_name);
+ if (!devname)
+ return 1;
+ ret = iterate_device (devname, ctx);
+ grub_free (devname);
+
+ return ret;
+}
+
+/* Helper for FUNC_NAME. */
+static void
+try (struct search_ctx *ctx)
+{
+ unsigned i;
+ struct cache_entry **prev;
+ struct cache_entry *cache_ent;
+
+ for (prev = &cache, cache_ent = *prev; cache_ent;
+ prev = &cache_ent->next, cache_ent = *prev)
+ if (compare_fn (cache_ent->key, ctx->key) == 0)
+ break;
+ if (cache_ent)
+ {
+ ctx->is_cache = 1;
+ if (iterate_device (cache_ent->value, ctx))
+ {
+ ctx->is_cache = 0;
+ return;
+ }
+ ctx->is_cache = 0;
+ /* Cache entry was outdated. Remove it. */
+ if (!ctx->count)
+ {
+ *prev = cache_ent->next;
+ grub_free (cache_ent->key);
+ grub_free (cache_ent->value);
+ grub_free (cache_ent);
+ }
+ }
+
+ for (i = 0; i < ctx->nhints; i++)
+ {
+ char *end;
+ if (!ctx->hints[i][0])
+ continue;
+ end = ctx->hints[i] + grub_strlen (ctx->hints[i]) - 1;
+ if (*end == ',')
+ *end = 0;
+ if (iterate_device (ctx->hints[i], ctx))
+ {
+ if (!*end)
+ *end = ',';
+ return;
+ }
+ if (!*end)
+ {
+ grub_device_t dev;
+ int ret;
+ dev = grub_device_open (ctx->hints[i]);
+ if (!dev)
+ {
+ if (!*end)
+ *end = ',';
+ continue;
+ }
+ if (!dev->disk)
+ {
+ grub_device_close (dev);
+ if (!*end)
+ *end = ',';
+ continue;
+ }
+ ret = grub_partition_iterate (dev->disk, part_hook, ctx);
+ if (!*end)
+ *end = ',';
+ grub_device_close (dev);
+ if (ret)
+ return;
+ }
+ }
+ grub_device_iterate (iterate_device, ctx);
+}
+
+void
+FUNC_NAME (const char *key, const char *var, int no_floppy,
+ char **hints, unsigned nhints)
+{
+ struct search_ctx ctx = {
+ .key = key,
+ .var = var,
+ .no_floppy = no_floppy,
+ .hints = hints,
+ .nhints = nhints,
+ .count = 0,
+ .is_cache = 0
+ };
+ grub_fs_autoload_hook_t saved_autoload;
+
+ /* First try without autoloading if we're setting variable. */
+ if (var)
+ {
+ saved_autoload = grub_fs_autoload_hook;
+ grub_fs_autoload_hook = 0;
+ try (&ctx);
+
+ /* Restore autoload hook. */
+ grub_fs_autoload_hook = saved_autoload;
+
+ /* Retry with autoload if nothing found. */
+ if (grub_errno == GRUB_ERR_NONE && ctx.count == 0)
+ try (&ctx);
+ }
+ else
+ try (&ctx);
+
+ if (grub_errno == GRUB_ERR_NONE && ctx.count == 0)
+ grub_error (GRUB_ERR_FILE_NOT_FOUND, "no such device: %s", key);
+}
+
+static grub_err_t
+grub_cmd_do_search (grub_command_t cmd __attribute__ ((unused)), int argc,
+ char **args)
+{
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+
+ FUNC_NAME (args[0], argc == 1 ? 0 : args[1], 0, (args + 2),
+ argc > 2 ? argc - 2 : 0);
+
+ return grub_errno;
+}
+
+static grub_command_t cmd;
+
+#ifdef DO_SEARCH_FILE
+GRUB_MOD_INIT(search_fs_file)
+#elif defined (DO_SEARCH_FS_UUID)
+GRUB_MOD_INIT(search_fs_uuid)
+#else
+GRUB_MOD_INIT(search_label)
+#endif
+{
+ cmd =
+ grub_register_command (COMMAND_NAME, grub_cmd_do_search,
+ N_("NAME [VARIABLE] [HINTS]"),
+ HELP_MESSAGE);
+}
+
+#ifdef DO_SEARCH_FILE
+GRUB_MOD_FINI(search_fs_file)
+#elif defined (DO_SEARCH_FS_UUID)
+GRUB_MOD_FINI(search_fs_uuid)
+#else
+GRUB_MOD_FINI(search_label)
+#endif
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/search_file.c b/grub-core/commands/search_file.c
new file mode 100644
index 0000000..cc2a5f9
--- /dev/null
+++ b/grub-core/commands/search_file.c
@@ -0,0 +1,5 @@
+#define DO_SEARCH_FILE 1
+#define FUNC_NAME grub_search_fs_file
+#define COMMAND_NAME "search.file"
+#define HELP_MESSAGE N_("Search devices by file. If VARIABLE is specified, the first device found is set to a variable.")
+#include "search.c"
diff --git a/grub-core/commands/search_label.c b/grub-core/commands/search_label.c
new file mode 100644
index 0000000..12e7c18
--- /dev/null
+++ b/grub-core/commands/search_label.c
@@ -0,0 +1,5 @@
+#define DO_SEARCH_FS_LABEL 1
+#define FUNC_NAME grub_search_label
+#define COMMAND_NAME "search.fs_label"
+#define HELP_MESSAGE N_("Search devices by label. If VARIABLE is specified, the first device found is set to a variable.")
+#include "search.c"
diff --git a/grub-core/commands/search_uuid.c b/grub-core/commands/search_uuid.c
new file mode 100644
index 0000000..541bcf5
--- /dev/null
+++ b/grub-core/commands/search_uuid.c
@@ -0,0 +1,5 @@
+#define DO_SEARCH_FS_UUID 1
+#define FUNC_NAME grub_search_fs_uuid
+#define COMMAND_NAME "search.fs_uuid"
+#define HELP_MESSAGE N_("Search devices by UUID. If VARIABLE is specified, the first device found is set to a variable.")
+#include "search.c"
diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c
new file mode 100644
index 0000000..47fc8eb
--- /dev/null
+++ b/grub-core/commands/search_wrap.c
@@ -0,0 +1,220 @@
+/* search.c - search devices based on a file or a filesystem label */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2007,2008,2009 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/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/env.h>
+#include <grub/extcmd.h>
+#include <grub/search.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =
+ {
+ {"file", 'f', 0, N_("Search devices by a file."), 0, 0},
+ {"label", 'l', 0, N_("Search devices by a filesystem label."),
+ 0, 0},
+ {"fs-uuid", 'u', 0, N_("Search devices by a filesystem UUID."),
+ 0, 0},
+ {"set", 's', GRUB_ARG_OPTION_OPTIONAL,
+ N_("Set a variable to the first device found."), N_("VARNAME"),
+ ARG_TYPE_STRING},
+ {"no-floppy", 'n', 0, N_("Do not probe any floppy drive."), 0, 0},
+ {"hint", 'h', GRUB_ARG_OPTION_REPEATABLE,
+ N_("First try the device HINT. If HINT ends in comma, "
+ "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING},
+ {"hint-ieee1275", 0, GRUB_ARG_OPTION_REPEATABLE,
+ N_("First try the device HINT if currently running on IEEE1275. "
+ "If HINT ends in comma, also try subpartitions"),
+ N_("HINT"), ARG_TYPE_STRING},
+ {"hint-bios", 0, GRUB_ARG_OPTION_REPEATABLE,
+ N_("First try the device HINT if currently running on BIOS. "
+ "If HINT ends in comma, also try subpartitions"),
+ N_("HINT"), ARG_TYPE_STRING},
+ {"hint-baremetal", 0, GRUB_ARG_OPTION_REPEATABLE,
+ N_("First try the device HINT if direct hardware access is supported. "
+ "If HINT ends in comma, also try subpartitions"),
+ N_("HINT"), ARG_TYPE_STRING},
+ {"hint-efi", 0, GRUB_ARG_OPTION_REPEATABLE,
+ N_("First try the device HINT if currently running on EFI. "
+ "If HINT ends in comma, also try subpartitions"),
+ N_("HINT"), ARG_TYPE_STRING},
+ {"hint-arc", 0, GRUB_ARG_OPTION_REPEATABLE,
+ N_("First try the device HINT if currently running on ARC."
+ " If HINT ends in comma, also try subpartitions"),
+ N_("HINT"), ARG_TYPE_STRING},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+enum options
+ {
+ SEARCH_FILE,
+ SEARCH_LABEL,
+ SEARCH_FS_UUID,
+ SEARCH_SET,
+ SEARCH_NO_FLOPPY,
+ SEARCH_HINT,
+ SEARCH_HINT_IEEE1275,
+ SEARCH_HINT_BIOS,
+ SEARCH_HINT_BAREMETAL,
+ SEARCH_HINT_EFI,
+ SEARCH_HINT_ARC,
+ };
+
+static grub_err_t
+grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ const char *var = 0;
+ const char *id = 0;
+ int i = 0, j = 0, nhints = 0;
+ char **hints = NULL;
+
+ if (state[SEARCH_HINT].set)
+ for (i = 0; state[SEARCH_HINT].args[i]; i++)
+ nhints++;
+
+#ifdef GRUB_MACHINE_IEEE1275
+ if (state[SEARCH_HINT_IEEE1275].set)
+ for (i = 0; state[SEARCH_HINT_IEEE1275].args[i]; i++)
+ nhints++;
+#endif
+
+#ifdef GRUB_MACHINE_EFI
+ if (state[SEARCH_HINT_EFI].set)
+ for (i = 0; state[SEARCH_HINT_EFI].args[i]; i++)
+ nhints++;
+#endif
+
+#ifdef GRUB_MACHINE_PCBIOS
+ if (state[SEARCH_HINT_BIOS].set)
+ for (i = 0; state[SEARCH_HINT_BIOS].args[i]; i++)
+ nhints++;
+#endif
+
+#ifdef GRUB_MACHINE_ARC
+ if (state[SEARCH_HINT_ARC].set)
+ for (i = 0; state[SEARCH_HINT_ARC].args[i]; i++)
+ nhints++;
+#endif
+
+ if (state[SEARCH_HINT_BAREMETAL].set)
+ for (i = 0; state[SEARCH_HINT_BAREMETAL].args[i]; i++)
+ nhints++;
+
+ hints = grub_calloc (nhints, sizeof (hints[0]));
+ if (!hints)
+ return grub_errno;
+ j = 0;
+
+ if (state[SEARCH_HINT].set)
+ for (i = 0; state[SEARCH_HINT].args[i]; i++)
+ hints[j++] = state[SEARCH_HINT].args[i];
+
+#ifdef GRUB_MACHINE_IEEE1275
+ if (state[SEARCH_HINT_IEEE1275].set)
+ for (i = 0; state[SEARCH_HINT_IEEE1275].args[i]; i++)
+ hints[j++] = state[SEARCH_HINT_IEEE1275].args[i];
+#endif
+
+#ifdef GRUB_MACHINE_EFI
+ if (state[SEARCH_HINT_EFI].set)
+ for (i = 0; state[SEARCH_HINT_EFI].args[i]; i++)
+ hints[j++] = state[SEARCH_HINT_EFI].args[i];
+#endif
+
+#ifdef GRUB_MACHINE_ARC
+ if (state[SEARCH_HINT_ARC].set)
+ for (i = 0; state[SEARCH_HINT_ARC].args[i]; i++)
+ hints[j++] = state[SEARCH_HINT_ARC].args[i];
+#endif
+
+#ifdef GRUB_MACHINE_PCBIOS
+ if (state[SEARCH_HINT_BIOS].set)
+ for (i = 0; state[SEARCH_HINT_BIOS].args[i]; i++)
+ hints[j++] = state[SEARCH_HINT_BIOS].args[i];
+#endif
+
+ if (state[SEARCH_HINT_BAREMETAL].set)
+ for (i = 0; state[SEARCH_HINT_BAREMETAL].args[i]; i++)
+ hints[j++] = state[SEARCH_HINT_BAREMETAL].args[i];
+
+ /* Skip hints for future platforms. */
+ for (j = 0; j < argc; j++)
+ if (grub_memcmp (args[j], "--hint-", sizeof ("--hint-") - 1) != 0)
+ break;
+
+ if (state[SEARCH_SET].set)
+ var = state[SEARCH_SET].arg ? state[SEARCH_SET].arg : "root";
+
+ if (argc != j)
+ id = args[j];
+ else if (state[SEARCH_SET].set && state[SEARCH_SET].arg)
+ {
+ id = state[SEARCH_SET].arg;
+ var = "root";
+ }
+ else
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+ goto out;
+ }
+
+ if (state[SEARCH_LABEL].set)
+ grub_search_label (id, var, state[SEARCH_NO_FLOPPY].set,
+ hints, nhints);
+ else if (state[SEARCH_FS_UUID].set)
+ grub_search_fs_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);
+ else
+ grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type");
+
+out:
+ grub_free (hints);
+ return grub_errno;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(search)
+{
+ cmd =
+ grub_register_extcmd ("search", grub_cmd_search,
+ GRUB_COMMAND_FLAG_EXTRACTOR | GRUB_COMMAND_ACCEPT_DASH,
+ N_("[-f|-l|-u|-s|-n] [--hint HINT [--hint HINT] ...]"
+ " NAME"),
+ N_("Search devices by file, filesystem label"
+ " or filesystem UUID."
+ " If --set is specified, the first device found is"
+ " set to a variable. If no variable name is"
+ " specified, `root' is used."),
+ options);
+}
+
+GRUB_MOD_FINI(search)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/setpci.c b/grub-core/commands/setpci.c
new file mode 100644
index 0000000..8a0c91f
--- /dev/null
+++ b/grub-core/commands/setpci.c
@@ -0,0 +1,340 @@
+/* lspci.c - List PCI devices. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008, 2009 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/pci.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/extcmd.h>
+#include <grub/env.h>
+#include <grub/mm.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+struct pci_register
+{
+ const char *name;
+ grub_uint16_t addr;
+ unsigned size;
+};
+
+static struct pci_register pci_registers[] =
+ {
+ {"VENDOR_ID", GRUB_PCI_REG_VENDOR , 2},
+ {"DEVICE_ID", GRUB_PCI_REG_DEVICE , 2},
+ {"COMMAND", GRUB_PCI_REG_COMMAND , 2},
+ {"STATUS", GRUB_PCI_REG_STATUS , 2},
+ {"REVISION", GRUB_PCI_REG_REVISION , 1},
+ {"CLASS_PROG", GRUB_PCI_REG_CLASS + 1 , 1},
+ {"CLASS_DEVICE", GRUB_PCI_REG_CLASS + 2 , 2},
+ {"CACHE_LINE_SIZE", GRUB_PCI_REG_CACHELINE , 1},
+ {"LATENCY_TIMER", GRUB_PCI_REG_LAT_TIMER , 1},
+ {"HEADER_TYPE", GRUB_PCI_REG_HEADER_TYPE , 1},
+ {"BIST", GRUB_PCI_REG_BIST , 1},
+ {"BASE_ADDRESS_0", GRUB_PCI_REG_ADDRESS_REG0, 4},
+ {"BASE_ADDRESS_1", GRUB_PCI_REG_ADDRESS_REG1, 4},
+ {"BASE_ADDRESS_2", GRUB_PCI_REG_ADDRESS_REG2, 4},
+ {"BASE_ADDRESS_3", GRUB_PCI_REG_ADDRESS_REG3, 4},
+ {"BASE_ADDRESS_4", GRUB_PCI_REG_ADDRESS_REG4, 4},
+ {"BASE_ADDRESS_5", GRUB_PCI_REG_ADDRESS_REG5, 4},
+ {"CARDBUS_CIS", GRUB_PCI_REG_CIS_POINTER , 4},
+ {"SUBVENDOR_ID", GRUB_PCI_REG_SUBVENDOR , 2},
+ {"SUBSYSTEM_ID", GRUB_PCI_REG_SUBSYSTEM , 2},
+ {"ROM_ADDRESS", GRUB_PCI_REG_ROM_ADDRESS , 4},
+ {"CAP_POINTER", GRUB_PCI_REG_CAP_POINTER , 1},
+ {"INTERRUPT_LINE", GRUB_PCI_REG_IRQ_LINE , 1},
+ {"INTERRUPT_PIN", GRUB_PCI_REG_IRQ_PIN , 1},
+ {"MIN_GNT", GRUB_PCI_REG_MIN_GNT , 1},
+ {"MAX_LAT", GRUB_PCI_REG_MIN_GNT , 1},
+ };
+
+static const struct grub_arg_option options[] =
+ {
+ {0, 'd', 0, N_("Select device by vendor and device IDs."),
+ N_("[vendor]:[device]"), ARG_TYPE_STRING},
+ {0, 's', 0, N_("Select device by its position on the bus."),
+ N_("[bus]:[slot][.func]"), ARG_TYPE_STRING},
+ {0, 'v', 0, N_("Save read value into variable VARNAME."),
+ N_("VARNAME"), ARG_TYPE_STRING},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static grub_uint32_t pciid_check_mask, pciid_check_value;
+static int bus, device, function;
+static int check_bus, check_device, check_function;
+static grub_uint32_t write_mask, regwrite;
+static int regsize;
+static grub_uint16_t regaddr;
+static const char *varname;
+
+static int
+grub_setpci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
+ void *data __attribute__ ((unused)))
+{
+ grub_uint32_t regval = 0;
+ grub_pci_address_t addr;
+
+ if ((pciid & pciid_check_mask) != pciid_check_value)
+ return 0;
+
+ if (check_bus && grub_pci_get_bus (dev) != bus)
+ return 0;
+
+ if (check_device && grub_pci_get_device (dev) != device)
+ return 0;
+
+ if (check_function && grub_pci_get_function (dev) != function)
+ return 0;
+
+ addr = grub_pci_make_address (dev, regaddr);
+
+ switch (regsize)
+ {
+ case 1:
+ regval = grub_pci_read_byte (addr);
+ break;
+
+ case 2:
+ regval = grub_pci_read_word (addr);
+ break;
+
+ case 4:
+ regval = grub_pci_read (addr);
+ break;
+ }
+
+ if (varname)
+ {
+ char buf[sizeof ("XXXXXXXX")];
+ grub_snprintf (buf, sizeof (buf), "%x", regval);
+ grub_env_set (varname, buf);
+ return 1;
+ }
+
+ if (!write_mask)
+ {
+ grub_printf (_("Register %x of %x:%02x.%x is %x\n"), regaddr,
+ grub_pci_get_bus (dev),
+ grub_pci_get_device (dev),
+ grub_pci_get_function (dev),
+ regval);
+ return 0;
+ }
+
+ regval = (regval & ~write_mask) | regwrite;
+
+ switch (regsize)
+ {
+ case 1:
+ grub_pci_write_byte (addr, regval);
+ break;
+
+ case 2:
+ grub_pci_write_word (addr, regval);
+ break;
+
+ case 4:
+ grub_pci_write (addr, regval);
+ break;
+ }
+
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_setpci (grub_extcmd_context_t ctxt, int argc, char **argv)
+{
+ const char *ptr;
+ unsigned i;
+
+ pciid_check_value = 0;
+ pciid_check_mask = 0;
+
+ if (ctxt->state[0].set)
+ {
+ ptr = ctxt->state[0].arg;
+ pciid_check_value |= (grub_strtoul (ptr, &ptr, 16) & 0xffff);
+ if (grub_errno == GRUB_ERR_BAD_NUMBER)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ ptr = ctxt->state[0].arg;
+ }
+ else
+ pciid_check_mask |= 0xffff;
+ if (grub_errno)
+ return grub_errno;
+ if (*ptr != ':')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("missing `%c' symbol"), ':');
+ ptr++;
+ pciid_check_value |= (grub_strtoul (ptr, &ptr, 16) & 0xffff) << 16;
+ if (grub_errno == GRUB_ERR_BAD_NUMBER)
+ grub_errno = GRUB_ERR_NONE;
+ else
+ pciid_check_mask |= 0xffff0000;
+ }
+
+ pciid_check_value &= pciid_check_mask;
+
+ check_bus = check_device = check_function = 0;
+
+ if (ctxt->state[1].set)
+ {
+ const char *optr;
+
+ ptr = ctxt->state[1].arg;
+ optr = ptr;
+ bus = grub_strtoul (ptr, &ptr, 16);
+ if (grub_errno == GRUB_ERR_BAD_NUMBER)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ ptr = optr;
+ }
+ else
+ check_bus = 1;
+ if (grub_errno)
+ return grub_errno;
+ if (*ptr != ':')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("missing `%c' symbol"), ':');
+ ptr++;
+ optr = ptr;
+ device = grub_strtoul (ptr, &ptr, 16);
+ if (grub_errno == GRUB_ERR_BAD_NUMBER)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ ptr = optr;
+ }
+ else
+ check_device = 1;
+ if (*ptr == '.')
+ {
+ ptr++;
+ function = grub_strtoul (ptr, &ptr, 16);
+ if (grub_errno)
+ return grub_errno;
+ check_function = 1;
+ }
+ }
+
+ if (ctxt->state[2].set)
+ varname = ctxt->state[2].arg;
+ else
+ varname = NULL;
+
+ write_mask = 0;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+
+ ptr = argv[0];
+
+ for (i = 0; i < ARRAY_SIZE (pci_registers); i++)
+ {
+ if (grub_strncmp (ptr, pci_registers[i].name,
+ grub_strlen (pci_registers[i].name)) == 0)
+ break;
+ }
+ if (i == ARRAY_SIZE (pci_registers))
+ {
+ regsize = 0;
+ regaddr = grub_strtoul (ptr, &ptr, 16);
+ if (grub_errno)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown register");
+ }
+ else
+ {
+ regaddr = pci_registers[i].addr;
+ regsize = pci_registers[i].size;
+ ptr += grub_strlen (pci_registers[i].name);
+ }
+
+ if (grub_errno)
+ return grub_errno;
+
+ if (*ptr == '+')
+ {
+ ptr++;
+ regaddr += grub_strtoul (ptr, &ptr, 16);
+ if (grub_errno)
+ return grub_errno;
+ }
+
+ if (grub_memcmp (ptr, ".L", sizeof (".L") - 1) == 0
+ || grub_memcmp (ptr, ".l", sizeof (".l") - 1) == 0)
+ {
+ regsize = 4;
+ ptr += sizeof (".l") - 1;
+ }
+ else if (grub_memcmp (ptr, ".W", sizeof (".W") - 1) == 0
+ || grub_memcmp (ptr, ".w", sizeof (".w") - 1) == 0)
+ {
+ regsize = 2;
+ ptr += sizeof (".w") - 1;
+ }
+ else if (grub_memcmp (ptr, ".B", sizeof (".B") - 1) == 0
+ || grub_memcmp (ptr, ".b", sizeof (".b") - 1) == 0)
+ {
+ regsize = 1;
+ ptr += sizeof (".b") - 1;
+ }
+
+ if (!regsize)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "unknown register size");
+
+ write_mask = 0;
+ if (*ptr == '=')
+ {
+ ptr++;
+ regwrite = grub_strtoul (ptr, &ptr, 16);
+ if (grub_errno)
+ return grub_errno;
+ write_mask = 0xffffffff;
+ if (*ptr == ':')
+ {
+ ptr++;
+ write_mask = grub_strtoul (ptr, &ptr, 16);
+ if (grub_errno)
+ return grub_errno;
+ write_mask = 0xffffffff;
+ }
+ regwrite &= write_mask;
+ }
+
+ if (write_mask && varname)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "option -v isn't valid for writes");
+
+ grub_pci_iterate (grub_setpci_iter, NULL);
+ return GRUB_ERR_NONE;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(setpci)
+{
+ cmd = grub_register_extcmd_lockdown ("setpci", grub_cmd_setpci, 0,
+ N_("[-s POSITION] [-d DEVICE] [-v VAR] "
+ "REGISTER[=VALUE[:MASK]]"),
+ N_("Manipulate PCI devices."), options);
+}
+
+GRUB_MOD_FINI(setpci)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/sleep.c b/grub-core/commands/sleep.c
new file mode 100644
index 0000000..a1370b7
--- /dev/null
+++ b/grub-core/commands/sleep.c
@@ -0,0 +1,117 @@
+/* sleep.c - Command to wait a specified number of seconds. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/term.h>
+#include <grub/time.h>
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =
+ {
+ {"verbose", 'v', 0, N_("Verbose countdown."), 0, 0},
+ {"interruptible", 'i', 0, N_("Allow to interrupt with ESC."), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static struct grub_term_coordinate *pos;
+
+static void
+do_print (int n)
+{
+ grub_term_restore_pos (pos);
+ /* NOTE: Do not remove the trailing space characters.
+ They are required to clear the line. */
+ grub_printf ("%d ", n);
+ grub_refresh ();
+}
+
+/* Based on grub_millisleep() from kern/generic/millisleep.c. */
+static int
+grub_interruptible_millisleep (grub_uint32_t ms)
+{
+ grub_uint64_t start;
+
+ start = grub_get_time_ms ();
+
+ while (grub_get_time_ms () - start < ms)
+ if (grub_key_is_interrupt (grub_getkey_noblock ()))
+ return 1;
+
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_sleep (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ int n;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+
+ n = grub_strtoul (args[0], 0, 10);
+
+ if (n == 0)
+ {
+ /* Either `0' or broken input. */
+ return 0;
+ }
+
+ grub_refresh ();
+
+ pos = grub_term_save_pos ();
+
+ for (; n; n--)
+ {
+ if (state[0].set)
+ do_print (n);
+
+ if (state[1].set)
+ {
+ if (grub_interruptible_millisleep (1000))
+ return 1;
+ }
+ else
+ grub_millisleep (1000);
+ }
+ if (state[0].set)
+ do_print (0);
+
+ return 0;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(sleep)
+{
+ cmd = grub_register_extcmd ("sleep", grub_cmd_sleep, 0,
+ N_("NUMBER_OF_SECONDS"),
+ N_("Wait for a specified number of seconds."),
+ options);
+}
+
+GRUB_MOD_FINI(sleep)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/smbios.c b/grub-core/commands/smbios.c
new file mode 100644
index 0000000..1a9086d
--- /dev/null
+++ b/grub-core/commands/smbios.c
@@ -0,0 +1,398 @@
+/* smbios.c - retrieve smbios information. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2019 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+");
+
+/* 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;
+
+static grub_extcmd_t cmd;
+
+/* 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. */
+static 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;
+}
+
+static char *
+linux_string (const char *value)
+{
+ char *out = grub_malloc( grub_strlen (value) + 1);
+ const char *src = value;
+ char *dst = out;
+
+ for (; *src; src++)
+ if (*src > ' ' && *src < 127 && *src != ':')
+ *dst++ = *src;
+
+ *dst = 0;
+ return out;
+}
+
+/*
+ * 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. When the requested data is
+ * successfully retrieved and formatted, the pointer to the string is returned;
+ * otherwise, NULL is returned on failure. Don't free the result.
+ */
+
+static const char *
+grub_smbios_format_byte (const grub_uint8_t *structure, grub_uint8_t offset)
+{
+ static char buffer[sizeof ("255")];
+
+ grub_snprintf (buffer, sizeof (buffer), "%u", structure[offset]);
+
+ return (const char *)buffer;
+}
+
+static const char *
+grub_smbios_format_word (const grub_uint8_t *structure, grub_uint8_t offset)
+{
+ static char buffer[sizeof ("65535")];
+
+ grub_uint16_t value = grub_get_unaligned16 (structure + offset);
+ grub_snprintf (buffer, sizeof (buffer), "%u", value);
+
+ return (const char *)buffer;
+}
+
+static const char *
+grub_smbios_format_dword (const grub_uint8_t *structure, grub_uint8_t offset)
+{
+ static char buffer[sizeof ("4294967295")];
+
+ grub_uint32_t value = grub_get_unaligned32 (structure + offset);
+ grub_snprintf (buffer, sizeof (buffer), "%" PRIuGRUB_UINT32_T, value);
+
+ return (const char *)buffer;
+}
+
+static const char *
+grub_smbios_format_qword (const grub_uint8_t *structure, grub_uint8_t offset)
+{
+ static char buffer[sizeof ("18446744073709551615")];
+
+ grub_uint64_t value = grub_get_unaligned64 (structure + offset);
+ grub_snprintf (buffer, sizeof (buffer), "%" PRIuGRUB_UINT64_T, value);
+
+ return (const char *)buffer;
+}
+
+static const char *
+grub_smbios_get_string (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 (const grub_uint8_t *structure, grub_uint8_t offset)
+{
+ static char buffer[sizeof ("ffffffff-ffff-ffff-ffff-ffffffffffff")];
+ const grub_uint8_t *f = structure + offset; /* little-endian fields */
+ const grub_uint8_t *g = f + 8; /* byte-by-byte fields */
+
+ grub_snprintf (buffer, sizeof (buffer),
+ "%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. */
+static const struct {
+ const char *(*format) (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))
+#define LINUX_OPT (FIRST_GETTER_OPT + ARRAY_SIZE(field_extractors) + 1)
+
+static const struct grub_arg_option options[] = {
+ {"type", 't', 0, N_("Match structures with the given type."),
+ N_("type"), ARG_TYPE_INT},
+ {"handle", 'h', 0, N_("Match structures 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},
+ {"linux", '\0', 0, N_("Filter the result like linux does."),
+ N_("variable"), ARG_TYPE_NONE},
+ {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 *modified_value = NULL;
+ 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 || option > 65535)
+ 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 (structure, offset);
+ if (value == NULL)
+ return grub_error (GRUB_ERR_IO,
+ N_("failed to retrieve the structure field"));
+
+ if (state[LINUX_OPT].set)
+ value = modified_value = linux_string (value);
+
+ /* 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);
+
+ grub_free(modified_value);
+
+ return GRUB_ERR_NONE;
+}
+
+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);
+}
diff --git a/grub-core/commands/syslinuxcfg.c b/grub-core/commands/syslinuxcfg.c
new file mode 100644
index 0000000..7be28fa
--- /dev/null
+++ b/grub-core/commands/syslinuxcfg.c
@@ -0,0 +1,217 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/types.h>
+#include <grub/misc.h>
+#include <grub/extcmd.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/file.h>
+#include <grub/normal.h>
+#include <grub/script_sh.h>
+#include <grub/i18n.h>
+#include <grub/term.h>
+#include <grub/syslinux_parse.h>
+#include <grub/crypto.h>
+#include <grub/auth.h>
+#include <grub/disk.h>
+#include <grub/partition.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* Helper for syslinux_file. */
+static grub_err_t
+syslinux_file_getline (char **line, int cont __attribute__ ((unused)),
+ void *data __attribute__ ((unused)))
+{
+ *line = 0;
+ return GRUB_ERR_NONE;
+}
+
+static const struct grub_arg_option options[] =
+ {
+ {"root", 'r', 0,
+ N_("root directory of the syslinux disk [default=/]."),
+ N_("DIR"), ARG_TYPE_STRING},
+ {"cwd", 'c', 0,
+ N_("current directory of syslinux [default is parent directory of input file]."),
+ N_("DIR"), ARG_TYPE_STRING},
+ {"isolinux", 'i', 0, N_("assume input is an isolinux configuration file."), 0, 0},
+ {"pxelinux", 'p', 0, N_("assume input is a pxelinux configuration file."), 0, 0},
+ {"syslinux", 's', 0, N_("assume input is a syslinux configuration file."), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+enum
+ {
+ OPTION_ROOT,
+ OPTION_CWD,
+ OPTION_ISOLINUX,
+ OPTION_PXELINUX,
+ OPTION_SYSLINUX
+ };
+
+static grub_err_t
+syslinux_file (grub_extcmd_context_t ctxt, const char *filename)
+{
+ char *result;
+ const char *root = ctxt->state[OPTION_ROOT].set ? ctxt->state[OPTION_ROOT].arg : "/";
+ const char *cwd = ctxt->state[OPTION_CWD].set ? ctxt->state[OPTION_CWD].arg : NULL;
+ grub_syslinux_flavour_t flav = GRUB_SYSLINUX_UNKNOWN;
+ char *cwdf = NULL;
+ grub_menu_t menu;
+
+ if (ctxt->state[OPTION_ISOLINUX].set)
+ flav = GRUB_SYSLINUX_ISOLINUX;
+ if (ctxt->state[OPTION_PXELINUX].set)
+ flav = GRUB_SYSLINUX_PXELINUX;
+ if (ctxt->state[OPTION_SYSLINUX].set)
+ flav = GRUB_SYSLINUX_SYSLINUX;
+
+ if (!cwd)
+ {
+ char *p;
+ cwdf = grub_strdup (filename);
+ if (!cwdf)
+ return grub_errno;
+ p = grub_strrchr (cwdf, '/');
+ if (!p)
+ {
+ grub_free (cwdf);
+ cwd = "/";
+ cwdf = NULL;
+ }
+ else
+ {
+ *p = '\0';
+ cwd = cwdf;
+ }
+ }
+
+ grub_dprintf ("syslinux",
+ "transforming syslinux config %s, root = %s, cwd = %s\n",
+ filename, root, cwd);
+
+ result = grub_syslinux_config_file (root, root, cwd, cwd, filename, flav);
+ if (!result)
+ return grub_errno;
+
+ grub_dprintf ("syslinux", "syslinux config transformed\n");
+
+ menu = grub_env_get_menu ();
+ if (! menu)
+ {
+ menu = grub_zalloc (sizeof (*menu));
+ if (! menu)
+ {
+ grub_free (result);
+ return grub_errno;
+ }
+
+ grub_env_set_menu (menu);
+ }
+
+ grub_normal_parse_line (result, syslinux_file_getline, NULL);
+ grub_print_error ();
+ grub_free (result);
+ grub_free (cwdf);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_syslinux_source (grub_extcmd_context_t ctxt,
+ int argc, char **args)
+{
+ int new_env, extractor;
+ grub_err_t ret;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ extractor = (ctxt->extcmd->cmd->name[0] == 'e');
+ new_env = (ctxt->extcmd->cmd->name[extractor ? (sizeof ("extract_syslinux_entries_") - 1)
+ : (sizeof ("syslinux_") - 1)] == 'c');
+
+ if (new_env)
+ grub_cls ();
+
+ if (new_env && !extractor)
+ grub_env_context_open ();
+ if (extractor)
+ grub_env_extractor_open (!new_env);
+
+ ret = syslinux_file (ctxt, args[0]);
+
+ if (new_env)
+ {
+ grub_menu_t menu;
+ menu = grub_env_get_menu ();
+ if (menu && menu->size)
+ grub_show_menu (menu, 1, 0);
+ if (!extractor)
+ grub_env_context_close ();
+ }
+ if (extractor)
+ grub_env_extractor_close (!new_env);
+
+ return ret;
+}
+
+
+static grub_extcmd_t cmd_source, cmd_configfile;
+static grub_extcmd_t cmd_source_extract, cmd_configfile_extract;
+
+GRUB_MOD_INIT(syslinuxcfg)
+{
+ cmd_source
+ = grub_register_extcmd ("syslinux_source",
+ grub_cmd_syslinux_source, 0,
+ N_("FILE"),
+ /* TRANSLATORS: "syslinux config" means
+ "config as used by syslinux". */
+ N_("Execute syslinux config in same context"),
+ options);
+ cmd_configfile
+ = grub_register_extcmd ("syslinux_configfile",
+ grub_cmd_syslinux_source, 0,
+ N_("FILE"),
+ N_("Execute syslinux config in new context"),
+ options);
+ cmd_source_extract
+ = grub_register_extcmd ("extract_syslinux_entries_source",
+ grub_cmd_syslinux_source, 0,
+ N_("FILE"),
+ N_("Execute syslinux config in same context taking only menu entries"),
+ options);
+ cmd_configfile_extract
+ = grub_register_extcmd ("extract_syslinux_entries_configfile",
+ grub_cmd_syslinux_source, 0,
+ N_("FILE"),
+ N_("Execute syslinux config in new context taking only menu entries"),
+ options);
+}
+
+GRUB_MOD_FINI(syslinuxcfg)
+{
+ grub_unregister_extcmd (cmd_source);
+ grub_unregister_extcmd (cmd_configfile);
+ grub_unregister_extcmd (cmd_source_extract);
+ grub_unregister_extcmd (cmd_configfile_extract);
+}
diff --git a/grub-core/commands/terminal.c b/grub-core/commands/terminal.c
new file mode 100644
index 0000000..37e0ab8
--- /dev/null
+++ b/grub-core/commands/terminal.c
@@ -0,0 +1,285 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009,2010 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/mm.h>
+#include <grub/dl.h>
+#include <grub/command.h>
+#include <grub/term.h>
+#include <grub/i18n.h>
+#include <grub/misc.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+struct grub_term_autoload *grub_term_input_autoload = NULL;
+struct grub_term_autoload *grub_term_output_autoload = NULL;
+
+struct abstract_terminal
+{
+ struct abstract_terminal *next;
+ struct abstract_terminal *prev;
+ const char *name;
+ grub_err_t (*init) (struct abstract_terminal *term);
+ grub_err_t (*fini) (struct abstract_terminal *term);
+};
+
+static grub_err_t
+handle_command (int argc, char **args, struct abstract_terminal **enabled,
+ struct abstract_terminal **disabled,
+ struct grub_term_autoload *autoloads,
+ const char *active_str,
+ const char *available_str)
+{
+ int i;
+ struct abstract_terminal *term;
+ struct grub_term_autoload *aut;
+
+ if (argc == 0)
+ {
+ grub_puts_ (active_str);
+ for (term = *enabled; term; term = term->next)
+ grub_printf ("%s ", term->name);
+ grub_printf ("\n");
+ grub_puts_ (available_str);
+ for (term = *disabled; term; term = term->next)
+ grub_printf ("%s ", term->name);
+ /* This is quadratic but we don't expect mode than 30 terminal
+ modules ever. */
+ for (aut = autoloads; aut; aut = aut->next)
+ {
+ for (term = *disabled; term; term = term->next)
+ if (grub_strcmp (term->name, aut->name) == 0
+ || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*'
+ && grub_memcmp (term->name, aut->name,
+ grub_strlen (aut->name) - 1) == 0))
+ break;
+ if (!term)
+ for (term = *enabled; term; term = term->next)
+ if (grub_strcmp (term->name, aut->name) == 0
+ || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*'
+ && grub_memcmp (term->name, aut->name,
+ grub_strlen (aut->name) - 1) == 0))
+ break;
+ if (!term)
+ grub_printf ("%s ", aut->name);
+ }
+ grub_printf ("\n");
+ return GRUB_ERR_NONE;
+ }
+ i = 0;
+
+ if (grub_strcmp (args[0], "--append") == 0
+ || grub_strcmp (args[0], "--remove") == 0)
+ i++;
+
+ if (i == argc)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("no terminal specified"));
+
+ for (; i < argc; i++)
+ {
+ int again = 0;
+ while (1)
+ {
+ for (term = *disabled; term; term = term->next)
+ if (grub_strcmp (args[i], term->name) == 0
+ || (grub_strcmp (args[i], "ofconsole") == 0
+ && grub_strcmp ("console", term->name) == 0))
+ break;
+ if (term == 0)
+ for (term = *enabled; term; term = term->next)
+ if (grub_strcmp (args[i], term->name) == 0
+ || (grub_strcmp (args[i], "ofconsole") == 0
+ && grub_strcmp ("console", term->name) == 0))
+ break;
+ if (term)
+ break;
+ if (again)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("terminal `%s' isn't found"),
+ args[i]);
+ for (aut = autoloads; aut; aut = aut->next)
+ if (grub_strcmp (args[i], aut->name) == 0
+ || (grub_strcmp (args[i], "ofconsole") == 0
+ && grub_strcmp ("console", aut->name) == 0)
+ || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*'
+ && grub_memcmp (args[i], aut->name,
+ grub_strlen (aut->name) - 1) == 0))
+ {
+ grub_dl_t mod;
+ mod = grub_dl_load (aut->modname);
+ if (mod)
+ grub_dl_ref (mod);
+ grub_errno = GRUB_ERR_NONE;
+ break;
+ }
+ if (grub_memcmp (args[i], "serial_usb",
+ sizeof ("serial_usb") - 1) == 0
+ && grub_term_poll_usb)
+ {
+ grub_term_poll_usb (1);
+ again = 1;
+ continue;
+ }
+ if (!aut)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("terminal `%s' isn't found"),
+ args[i]);
+ again = 1;
+ }
+ }
+
+ if (grub_strcmp (args[0], "--append") == 0)
+ {
+ for (i = 1; i < argc; i++)
+ {
+ for (term = *disabled; term; term = term->next)
+ if (grub_strcmp (args[i], term->name) == 0
+ || (grub_strcmp (args[i], "ofconsole") == 0
+ && grub_strcmp ("console", term->name) == 0))
+ break;
+ if (term)
+ {
+ if (term->init && term->init (term) != GRUB_ERR_NONE)
+ return grub_errno;
+
+ grub_list_remove (GRUB_AS_LIST (term));
+ grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term));
+ }
+ }
+ return GRUB_ERR_NONE;
+ }
+
+ if (grub_strcmp (args[0], "--remove") == 0)
+ {
+ for (i = 1; i < argc; i++)
+ {
+ for (term = *enabled; term; term = term->next)
+ if (grub_strcmp (args[i], term->name) == 0
+ || (grub_strcmp (args[i], "ofconsole") == 0
+ && grub_strcmp ("console", term->name) == 0))
+ break;
+ if (term)
+ {
+ if (!term->next && term == *enabled)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "can't remove the last terminal");
+ grub_list_remove (GRUB_AS_LIST (term));
+ if (term->fini)
+ term->fini (term);
+ grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term));
+ }
+ }
+ return GRUB_ERR_NONE;
+ }
+ for (i = 0; i < argc; i++)
+ {
+ for (term = *disabled; term; term = term->next)
+ if (grub_strcmp (args[i], term->name) == 0
+ || (grub_strcmp (args[i], "ofconsole") == 0
+ && grub_strcmp ("console", term->name) == 0))
+ break;
+ if (term)
+ {
+ if (term->init && term->init (term) != GRUB_ERR_NONE)
+ return grub_errno;
+
+ grub_list_remove (GRUB_AS_LIST (term));
+ grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term));
+ }
+ }
+
+ {
+ struct abstract_terminal *next;
+ for (term = *enabled; term; term = next)
+ {
+ next = term->next;
+ for (i = 0; i < argc; i++)
+ if (grub_strcmp (args[i], term->name) == 0
+ || (grub_strcmp (args[i], "ofconsole") == 0
+ && grub_strcmp ("console", term->name) == 0))
+ break;
+ if (i == argc)
+ {
+ if (!term->next && term == *enabled)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "can't remove the last terminal");
+ grub_list_remove (GRUB_AS_LIST (term));
+ if (term->fini)
+ term->fini (term);
+ grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term));
+ }
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_terminal_input (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, next);
+ (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, prev);
+ (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, name);
+ (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, init);
+ (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, fini);
+ return handle_command (argc, args,
+ (struct abstract_terminal **) (void *) &grub_term_inputs,
+ (struct abstract_terminal **) (void *) &grub_term_inputs_disabled,
+ grub_term_input_autoload,
+ N_("Active input terminals:"),
+ N_("Available input terminals:"));
+}
+
+static grub_err_t
+grub_cmd_terminal_output (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, next);
+ (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, prev);
+ (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, name);
+ (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, init);
+ (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, fini);
+ return handle_command (argc, args,
+ (struct abstract_terminal **) (void *) &grub_term_outputs,
+ (struct abstract_terminal **) (void *) &grub_term_outputs_disabled,
+ grub_term_output_autoload,
+ N_("Active output terminals:"),
+ N_("Available output terminals:"));
+}
+
+static grub_command_t cmd_terminal_input, cmd_terminal_output;
+
+GRUB_MOD_INIT(terminal)
+{
+ cmd_terminal_input =
+ grub_register_command ("terminal_input", grub_cmd_terminal_input,
+ N_("[--append|--remove] "
+ "[TERMINAL1] [TERMINAL2] ..."),
+ N_("List or select an input terminal."));
+ cmd_terminal_output =
+ grub_register_command ("terminal_output", grub_cmd_terminal_output,
+ N_("[--append|--remove] "
+ "[TERMINAL1] [TERMINAL2] ..."),
+ N_("List or select an output terminal."));
+}
+
+GRUB_MOD_FINI(terminal)
+{
+ grub_unregister_command (cmd_terminal_input);
+ grub_unregister_command (cmd_terminal_output);
+}
diff --git a/grub-core/commands/test.c b/grub-core/commands/test.c
new file mode 100644
index 0000000..62d3fb3
--- /dev/null
+++ b/grub-core/commands/test.c
@@ -0,0 +1,455 @@
+/* test.c -- The test command.. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2007,2009 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/misc.h>
+#include <grub/mm.h>
+#include <grub/env.h>
+#include <grub/fs.h>
+#include <grub/device.h>
+#include <grub/file.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* A simple implementation for signed numbers. */
+static int
+grub_strtosl (char *arg, const char ** const end, int base)
+{
+ if (arg[0] == '-')
+ return -grub_strtoul (arg + 1, end, base);
+ return grub_strtoul (arg, end, base);
+}
+
+/* Context for test_parse. */
+struct test_parse_ctx
+{
+ int invert;
+ int or, and;
+ int file_exists;
+ struct grub_dirhook_info file_info;
+ char *filename;
+};
+
+/* Take care of discarding and inverting. */
+static void
+update_val (int val, struct test_parse_ctx *ctx)
+{
+ ctx->and = ctx->and && (ctx->invert ? ! val : val);
+ ctx->invert = 0;
+}
+
+/* A hook for iterating directories. */
+static int
+find_file (const char *cur_filename, const struct grub_dirhook_info *info,
+ void *data)
+{
+ struct test_parse_ctx *ctx = data;
+
+ if ((info->case_insensitive ? grub_strcasecmp (cur_filename, ctx->filename)
+ : grub_strcmp (cur_filename, ctx->filename)) == 0)
+ {
+ ctx->file_info = *info;
+ ctx->file_exists = 1;
+ return 1;
+ }
+ return 0;
+}
+
+/* Check if file exists and fetch its information. */
+static void
+get_fileinfo (char *path, struct test_parse_ctx *ctx)
+{
+ char *pathname;
+ char *device_name;
+ grub_fs_t fs;
+ grub_device_t dev;
+
+ ctx->file_exists = 0;
+ device_name = grub_file_get_device_name (path);
+ dev = grub_device_open (device_name);
+ if (! dev)
+ {
+ grub_free (device_name);
+ return;
+ }
+
+ fs = grub_fs_probe (dev);
+ if (! fs)
+ {
+ grub_free (device_name);
+ grub_device_close (dev);
+ return;
+ }
+
+ pathname = grub_strchr (path, ')');
+ if (! pathname)
+ pathname = path;
+ else
+ pathname++;
+
+ /* Remove trailing '/'. */
+ while (*pathname && pathname[grub_strlen (pathname) - 1] == '/')
+ pathname[grub_strlen (pathname) - 1] = 0;
+
+ /* Split into path and filename. */
+ ctx->filename = grub_strrchr (pathname, '/');
+ if (! ctx->filename)
+ {
+ path = grub_strdup ("/");
+ ctx->filename = pathname;
+ }
+ else
+ {
+ ctx->filename++;
+ path = grub_strdup (pathname);
+ path[ctx->filename - pathname] = 0;
+ }
+
+ /* It's the whole device. */
+ if (! *pathname)
+ {
+ ctx->file_exists = 1;
+ grub_memset (&ctx->file_info, 0, sizeof (ctx->file_info));
+ /* Root is always a directory. */
+ ctx->file_info.dir = 1;
+
+ /* Fetch writing time. */
+ ctx->file_info.mtimeset = 0;
+ if (fs->fs_mtime)
+ {
+ if (! fs->fs_mtime (dev, &ctx->file_info.mtime))
+ ctx->file_info.mtimeset = 1;
+ grub_errno = GRUB_ERR_NONE;
+ }
+ }
+ else
+ (fs->fs_dir) (dev, path, find_file, ctx);
+
+ grub_device_close (dev);
+ grub_free (path);
+ grub_free (device_name);
+}
+
+/* Parse a test expression starting from *argn. */
+static int
+test_parse (char **args, int *argn, int argc)
+{
+ struct test_parse_ctx ctx = {
+ .and = 1,
+ .or = 0,
+ .invert = 0
+ };
+
+ /* Here we have the real parsing. */
+ while (*argn < argc)
+ {
+ /* First try 3 argument tests. */
+ if (*argn + 2 < argc)
+ {
+ /* String tests. */
+ if (grub_strcmp (args[*argn + 1], "=") == 0
+ || grub_strcmp (args[*argn + 1], "==") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) == 0,
+ &ctx);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "!=") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) != 0,
+ &ctx);
+ (*argn) += 3;
+ continue;
+ }
+
+ /* GRUB extension: lexicographical sorting. */
+ if (grub_strcmp (args[*argn + 1], "<") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) < 0,
+ &ctx);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "<=") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) <= 0,
+ &ctx);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], ">") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) > 0,
+ &ctx);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], ">=") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) >= 0,
+ &ctx);
+ (*argn) += 3;
+ continue;
+ }
+
+ /* Number tests. */
+ if (grub_strcmp (args[*argn + 1], "-eq") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ == grub_strtosl (args[*argn + 2], 0, 0), &ctx);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "-ge") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ >= grub_strtosl (args[*argn + 2], 0, 0), &ctx);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "-gt") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ > grub_strtosl (args[*argn + 2], 0, 0), &ctx);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "-le") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ <= grub_strtosl (args[*argn + 2], 0, 0), &ctx);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "-lt") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ < grub_strtosl (args[*argn + 2], 0, 0), &ctx);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "-ne") == 0)
+ {
+ update_val (grub_strtosl (args[*argn], 0, 0)
+ != grub_strtosl (args[*argn + 2], 0, 0), &ctx);
+ (*argn) += 3;
+ continue;
+ }
+
+ /* GRUB extension: compare numbers skipping prefixes.
+ Useful for comparing versions. E.g. vmlinuz-2 -plt vmlinuz-11. */
+ if (grub_strcmp (args[*argn + 1], "-pgt") == 0
+ || grub_strcmp (args[*argn + 1], "-plt") == 0)
+ {
+ int i;
+ /* Skip common prefix. */
+ for (i = 0; args[*argn][i] == args[*argn + 2][i]
+ && args[*argn][i]; i++);
+
+ /* Go the digits back. */
+ i--;
+ while (grub_isdigit (args[*argn][i]) && i > 0)
+ i--;
+ i++;
+
+ if (grub_strcmp (args[*argn + 1], "-pgt") == 0)
+ update_val (grub_strtoul (args[*argn] + i, 0, 0)
+ > grub_strtoul (args[*argn + 2] + i, 0, 0), &ctx);
+ else
+ update_val (grub_strtoul (args[*argn] + i, 0, 0)
+ < grub_strtoul (args[*argn + 2] + i, 0, 0), &ctx);
+ (*argn) += 3;
+ continue;
+ }
+
+ /* -nt and -ot tests. GRUB extension: when doing -?t<bias> bias
+ will be added to the first mtime. */
+ if (grub_memcmp (args[*argn + 1], "-nt", 3) == 0
+ || grub_memcmp (args[*argn + 1], "-ot", 3) == 0)
+ {
+ struct grub_dirhook_info file1;
+ int file1exists;
+ int bias = 0;
+
+ /* Fetch fileinfo. */
+ get_fileinfo (args[*argn], &ctx);
+ file1 = ctx.file_info;
+ file1exists = ctx.file_exists;
+ get_fileinfo (args[*argn + 2], &ctx);
+
+ if (args[*argn + 1][3])
+ bias = grub_strtosl (args[*argn + 1] + 3, 0, 0);
+
+ if (grub_memcmp (args[*argn + 1], "-nt", 3) == 0)
+ update_val ((file1exists && ! ctx.file_exists)
+ || (file1.mtimeset && ctx.file_info.mtimeset
+ && file1.mtime + bias > ctx.file_info.mtime),
+ &ctx);
+ else
+ update_val ((! file1exists && ctx.file_exists)
+ || (file1.mtimeset && ctx.file_info.mtimeset
+ && file1.mtime + bias < ctx.file_info.mtime),
+ &ctx);
+ (*argn) += 3;
+ continue;
+ }
+ }
+
+ /* Two-argument tests. */
+ if (*argn + 1 < argc)
+ {
+ /* File tests. */
+ if (grub_strcmp (args[*argn], "-d") == 0)
+ {
+ get_fileinfo (args[*argn + 1], &ctx);
+ update_val (ctx.file_exists && ctx.file_info.dir, &ctx);
+ (*argn) += 2;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn], "-e") == 0)
+ {
+ get_fileinfo (args[*argn + 1], &ctx);
+ update_val (ctx.file_exists, &ctx);
+ (*argn) += 2;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn], "-f") == 0)
+ {
+ get_fileinfo (args[*argn + 1], &ctx);
+ /* FIXME: check for other types. */
+ update_val (ctx.file_exists && ! ctx.file_info.dir, &ctx);
+ (*argn) += 2;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn], "-s") == 0)
+ {
+ grub_file_t file;
+ file = grub_file_open (args[*argn + 1], GRUB_FILE_TYPE_GET_SIZE
+ | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ update_val (file && (grub_file_size (file) != 0), &ctx);
+ if (file)
+ grub_file_close (file);
+ grub_errno = GRUB_ERR_NONE;
+ (*argn) += 2;
+ continue;
+ }
+
+ /* String tests. */
+ if (grub_strcmp (args[*argn], "-n") == 0)
+ {
+ update_val (args[*argn + 1][0], &ctx);
+
+ (*argn) += 2;
+ continue;
+ }
+ if (grub_strcmp (args[*argn], "-z") == 0)
+ {
+ update_val (! args[*argn + 1][0], &ctx);
+ (*argn) += 2;
+ continue;
+ }
+ }
+
+ /* Special modifiers. */
+
+ /* End of expression. return to parent. */
+ if (grub_strcmp (args[*argn], ")") == 0)
+ {
+ (*argn)++;
+ return ctx.or || ctx.and;
+ }
+ /* Recursively invoke if parenthesis. */
+ if (grub_strcmp (args[*argn], "(") == 0)
+ {
+ (*argn)++;
+ update_val (test_parse (args, argn, argc), &ctx);
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn], "!") == 0)
+ {
+ ctx.invert = ! ctx.invert;
+ (*argn)++;
+ continue;
+ }
+ if (grub_strcmp (args[*argn], "-a") == 0)
+ {
+ (*argn)++;
+ continue;
+ }
+ if (grub_strcmp (args[*argn], "-o") == 0)
+ {
+ ctx.or = ctx.or || ctx.and;
+ ctx.and = 1;
+ (*argn)++;
+ continue;
+ }
+
+ /* No test found. Interpret if as just a string. */
+ update_val (args[*argn][0], &ctx);
+ (*argn)++;
+ }
+ return ctx.or || ctx.and;
+}
+
+static grub_err_t
+grub_cmd_test (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ int argn = 0;
+
+ if (argc >= 1 && grub_strcmp (args[argc - 1], "]") == 0)
+ argc--;
+
+ return test_parse (args, &argn, argc) ? GRUB_ERR_NONE
+ : grub_error (GRUB_ERR_TEST_FAILURE, N_("false"));
+}
+
+static grub_command_t cmd_1, cmd_2;
+
+GRUB_MOD_INIT(test)
+{
+ cmd_1 = grub_register_command ("[", grub_cmd_test,
+ N_("EXPRESSION ]"), N_("Evaluate an expression."));
+ cmd_1->flags |= GRUB_COMMAND_FLAG_EXTRACTOR;
+ cmd_2 = grub_register_command ("test", grub_cmd_test,
+ N_("EXPRESSION"), N_("Evaluate an expression."));
+ cmd_2->flags |= GRUB_COMMAND_FLAG_EXTRACTOR;
+}
+
+GRUB_MOD_FINI(test)
+{
+ grub_unregister_command (cmd_1);
+ grub_unregister_command (cmd_2);
+}
diff --git a/grub-core/commands/testload.c b/grub-core/commands/testload.c
new file mode 100644
index 0000000..ff01a05
--- /dev/null
+++ b/grub-core/commands/testload.c
@@ -0,0 +1,170 @@
+/* testload.c - load the same file in multiple ways */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2005,2006,2007,2009,2010 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/mm.h>
+#include <grub/err.h>
+#include <grub/env.h>
+#include <grub/misc.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/term.h>
+#include <grub/loader.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* Helper for grub_cmd_testload. */
+static void
+read_progress (grub_disk_addr_t sector __attribute__ ((unused)),
+ unsigned offset __attribute__ ((unused)),
+ unsigned len,
+ void *data __attribute__ ((unused)))
+{
+ for (; len >= GRUB_DISK_SECTOR_SIZE; len -= GRUB_DISK_SECTOR_SIZE)
+ grub_xputs (".");
+ if (len)
+ grub_xputs (".");
+ grub_refresh ();
+}
+
+static grub_err_t
+grub_cmd_testload (struct grub_command *cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ grub_file_t file;
+ char *buf;
+ grub_size_t size;
+ grub_off_t pos;
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ file = grub_file_open (argv[0], GRUB_FILE_TYPE_TESTLOAD);
+ if (! file)
+ return grub_errno;
+
+ size = grub_file_size (file) & ~(GRUB_DISK_SECTOR_SIZE - 1);
+ if (size == 0)
+ {
+ grub_file_close (file);
+ return GRUB_ERR_NONE;
+ }
+
+ buf = grub_malloc (size);
+ if (! buf)
+ goto fail;
+
+ grub_printf ("Reading %s sequentially", argv[0]);
+ file->read_hook = read_progress;
+ if (grub_file_read (file, buf, size) != (grub_ssize_t) size)
+ goto fail;
+ grub_printf (" Done.\n");
+
+ /* Read sequentially again. */
+ grub_printf ("Reading %s sequentially again", argv[0]);
+ grub_file_seek (file, 0);
+
+ for (pos = 0; pos < size;)
+ {
+ char sector[GRUB_DISK_SECTOR_SIZE];
+ grub_size_t curlen = GRUB_DISK_SECTOR_SIZE;
+
+ if (curlen > size - pos)
+ curlen = size - pos;
+
+ if (grub_file_read (file, sector, curlen)
+ != (grub_ssize_t) curlen)
+ goto fail;
+
+ if (grub_memcmp (sector, buf + pos, curlen) != 0)
+ {
+ grub_printf ("\nDiffers in %lld\n", (unsigned long long) pos);
+ goto fail;
+ }
+ pos += curlen;
+ }
+ grub_printf (" Done.\n");
+
+ /* Read backwards and compare. */
+ grub_printf ("Reading %s backwards", argv[0]);
+ pos = size;
+ while (pos > 0)
+ {
+ char sector[GRUB_DISK_SECTOR_SIZE];
+
+ if (pos >= GRUB_DISK_SECTOR_SIZE)
+ pos -= GRUB_DISK_SECTOR_SIZE;
+ else
+ pos = 0;
+
+ grub_file_seek (file, pos);
+
+ if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE)
+ != GRUB_DISK_SECTOR_SIZE)
+ goto fail;
+
+ if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0)
+ {
+ int i;
+
+ grub_printf ("\nDiffers in %lld\n", (unsigned long long) pos);
+
+ for (i = 0; i < GRUB_DISK_SECTOR_SIZE; i++)
+ {
+ grub_printf ("%02x ", buf[pos + i]);
+ if ((i & 15) == 15)
+ grub_printf ("\n");
+ }
+
+ if (i)
+ grub_refresh ();
+
+ goto fail;
+ }
+ }
+ grub_printf (" Done.\n");
+
+ return GRUB_ERR_NONE;
+
+ fail:
+
+ grub_file_close (file);
+ grub_free (buf);
+
+ if (!grub_errno)
+ grub_error (GRUB_ERR_IO, "bad read");
+ return grub_errno;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(testload)
+{
+ cmd =
+ grub_register_command ("testload", grub_cmd_testload,
+ N_("FILE"),
+ N_("Load the same file in multiple ways."));
+}
+
+GRUB_MOD_FINI(testload)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/testspeed.c b/grub-core/commands/testspeed.c
new file mode 100644
index 0000000..c13a9b8
--- /dev/null
+++ b/grub-core/commands/testspeed.c
@@ -0,0 +1,115 @@
+/* testspeed.c - Command to test file read speed */
+/*
+ * 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/mm.h>
+#include <grub/file.h>
+#include <grub/time.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+#include <grub/normal.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define DEFAULT_BLOCK_SIZE 65536
+
+static const struct grub_arg_option options[] =
+ {
+ {"size", 's', 0, N_("Specify size for each read operation"), 0, ARG_TYPE_INT},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static grub_err_t
+grub_cmd_testspeed (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ grub_uint64_t start;
+ grub_uint64_t end;
+ grub_ssize_t block_size;
+ grub_disk_addr_t total_size;
+ char *buffer;
+ grub_file_t file;
+ grub_uint64_t whole, fraction;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ block_size = (state[0].set) ?
+ grub_strtoul (state[0].arg, 0, 0) : DEFAULT_BLOCK_SIZE;
+
+ if (block_size <= 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid block size"));
+
+ buffer = grub_malloc (block_size);
+ if (buffer == NULL)
+ return grub_errno;
+
+ file = grub_file_open (args[0], GRUB_FILE_TYPE_TESTLOAD);
+ if (file == NULL)
+ goto quit;
+
+ total_size = 0;
+ start = grub_get_time_ms ();
+ while (1)
+ {
+ grub_ssize_t size = grub_file_read (file, buffer, block_size);
+ if (size <= 0)
+ break;
+ total_size += size;
+ }
+ end = grub_get_time_ms ();
+ grub_file_close (file);
+
+ grub_printf_ (N_("File size: %s\n"),
+ grub_get_human_size (total_size, GRUB_HUMAN_SIZE_NORMAL));
+ whole = grub_divmod64 (end - start, 1000, &fraction);
+ grub_printf_ (N_("Elapsed time: %d.%03d s \n"),
+ (unsigned) whole,
+ (unsigned) fraction);
+
+ if (end != start)
+ {
+ grub_uint64_t speed =
+ grub_divmod64 (total_size * 100ULL * 1000ULL, end - start, 0);
+
+ grub_printf_ (N_("Speed: %s \n"),
+ grub_get_human_size (speed,
+ GRUB_HUMAN_SIZE_SPEED));
+ }
+
+ quit:
+ grub_free (buffer);
+
+ return grub_errno;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(testspeed)
+{
+ cmd = grub_register_extcmd ("testspeed", grub_cmd_testspeed, 0, N_("[-s SIZE] FILENAME"),
+ N_("Test file read speed."),
+ options);
+}
+
+GRUB_MOD_FINI(testspeed)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/time.c b/grub-core/commands/time.c
new file mode 100644
index 0000000..40d496e
--- /dev/null
+++ b/grub-core/commands/time.c
@@ -0,0 +1,68 @@
+/* echo.c - Command to display a line of text */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2011 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/time.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+
+static grub_err_t
+grub_cmd_time (grub_command_t ctxt __attribute__ ((unused)),
+ int argc, char **args)
+{
+ grub_command_t cmd;
+ grub_uint32_t start;
+ grub_uint32_t end;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("no command is specified"));
+
+ cmd = grub_command_find (args[0]);
+
+ if (!cmd)
+ return grub_error (GRUB_ERR_UNKNOWN_COMMAND, N_("can't find command `%s'"),
+ args[0]);
+
+ start = grub_get_time_ms ();
+ (cmd->func) (cmd, argc - 1, &args[1]);
+ end = grub_get_time_ms ();
+
+ grub_printf_ (N_("Elapsed time: %d.%03d seconds \n"), (end - start) / 1000,
+ (end - start) % 1000);
+
+ return grub_errno;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(time)
+{
+ cmd = grub_register_command ("time", grub_cmd_time,
+ N_("COMMAND [ARGS]"),
+ N_("Measure time used by COMMAND"));
+}
+
+GRUB_MOD_FINI(time)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/tpm.c b/grub-core/commands/tpm.c
new file mode 100644
index 0000000..2052c36
--- /dev/null
+++ b/grub-core/commands/tpm.c
@@ -0,0 +1,95 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2018 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/>.
+ *
+ * Core TPM support code.
+ */
+
+#include <grub/err.h>
+#include <grub/i18n.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/tpm.h>
+#include <grub/term.h>
+#include <grub/verify.h>
+#include <grub/dl.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+grub_tpm_verify_init (grub_file_t io,
+ enum grub_file_type type __attribute__ ((unused)),
+ void **context, enum grub_verify_flags *flags)
+{
+ *context = io->name;
+ *flags |= GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm_verify_write (void *context, void *buf, grub_size_t size)
+{
+ return grub_tpm_measure (buf, size, GRUB_BINARY_PCR, context);
+}
+
+static grub_err_t
+grub_tpm_verify_string (char *str, enum grub_verify_string_type type)
+{
+ const char *prefix = NULL;
+ char *description;
+ grub_err_t status;
+
+ switch (type)
+ {
+ case GRUB_VERIFY_KERNEL_CMDLINE:
+ prefix = "kernel_cmdline: ";
+ break;
+ case GRUB_VERIFY_MODULE_CMDLINE:
+ prefix = "module_cmdline: ";
+ break;
+ case GRUB_VERIFY_COMMAND:
+ prefix = "grub_cmd: ";
+ break;
+ }
+ description = grub_malloc (grub_strlen (str) + grub_strlen (prefix) + 1);
+ if (!description)
+ return grub_errno;
+ grub_memcpy (description, prefix, grub_strlen (prefix));
+ grub_memcpy (description + grub_strlen (prefix), str,
+ grub_strlen (str) + 1);
+ status =
+ grub_tpm_measure ((unsigned char *) str, grub_strlen (str),
+ GRUB_STRING_PCR, description);
+ grub_free (description);
+ return status;
+}
+
+struct grub_file_verifier grub_tpm_verifier = {
+ .name = "tpm",
+ .init = grub_tpm_verify_init,
+ .write = grub_tpm_verify_write,
+ .verify_string = grub_tpm_verify_string,
+};
+
+GRUB_MOD_INIT (tpm)
+{
+ grub_verifier_register (&grub_tpm_verifier);
+}
+
+GRUB_MOD_FINI (tpm)
+{
+ grub_verifier_unregister (&grub_tpm_verifier);
+}
diff --git a/grub-core/commands/tr.c b/grub-core/commands/tr.c
new file mode 100644
index 0000000..ef72841
--- /dev/null
+++ b/grub-core/commands/tr.c
@@ -0,0 +1,126 @@
+/* tr.c -- The tr command. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010,2013 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/mm.h>
+#include <grub/err.h>
+#include <grub/env.h>
+#include <grub/i18n.h>
+#include <grub/misc.h>
+#include <grub/extcmd.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =
+ {
+ { "set", 's', 0, N_("Set a variable to return value."), N_("VARNAME"), ARG_TYPE_STRING },
+ { "upcase", 'U', 0, N_("Translate to upper case."), 0, 0 },
+ { "downcase", 'D', 0, N_("Translate to lower case."), 0, 0 },
+ { 0, 0, 0, 0, 0, 0 }
+ };
+
+static const char *letters_lowercase = "abcdefghijklmnopqrstuvwxyz";
+static const char *letters_uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+static grub_err_t
+grub_cmd_tr (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ char *var = 0;
+ const char *input = 0;
+ char *output = 0, *optr;
+ const char *s1 = 0;
+ const char *s2 = 0;
+ const char *iptr;
+
+ /* Select the defaults from options. */
+ if (ctxt->state[0].set) {
+ var = ctxt->state[0].arg;
+ input = grub_env_get (var);
+ }
+
+ if (ctxt->state[1].set) {
+ s1 = letters_lowercase;
+ s2 = letters_uppercase;
+ }
+
+ if (ctxt->state[2].set) {
+ s1 = letters_uppercase;
+ s2 = letters_lowercase;
+ }
+
+ /* Check for arguments and update the defaults. */
+ if (argc == 1)
+ input = args[0];
+
+ else if (argc == 2) {
+ s1 = args[0];
+ s2 = args[1];
+
+ } else if (argc == 3) {
+ s1 = args[0];
+ s2 = args[1];
+ input = args[2];
+
+ } else if (argc > 3)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many parameters");
+
+ if (!s1 || !s2 || !input)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing parameters");
+
+ if (grub_strlen (s1) != grub_strlen (s2))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "set sizes did not match");
+
+ /* Translate input into output buffer. */
+
+ output = grub_malloc (grub_strlen (input) + 1);
+ if (! output)
+ return grub_errno;
+
+ optr = output;
+ for (iptr = input; *iptr; iptr++)
+ {
+ char *p = grub_strchr (s1, *iptr);
+ if (p)
+ *optr++ = s2[p - s1];
+ else
+ *optr++ = *iptr;
+ }
+ *optr = '\0';
+
+ if (ctxt->state[0].set)
+ grub_env_set (var, output);
+ else
+ grub_printf ("%s\n", output);
+
+ grub_free (output);
+ return GRUB_ERR_NONE;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(tr)
+{
+ cmd = grub_register_extcmd ("tr", grub_cmd_tr, 0, N_("[OPTIONS] [SET1] [SET2] [STRING]"),
+ N_("Translate SET1 characters to SET2 in STRING."), options);
+}
+
+GRUB_MOD_FINI(tr)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/true.c b/grub-core/commands/true.c
new file mode 100644
index 0000000..8cbba65
--- /dev/null
+++ b/grub-core/commands/true.c
@@ -0,0 +1,61 @@
+/* true.c - true and false commands. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+grub_cmd_true (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_false (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ return grub_error (GRUB_ERR_TEST_FAILURE, N_("false"));
+}
+
+static grub_command_t cmd_true, cmd_false;
+
+
+GRUB_MOD_INIT(true)
+{
+ cmd_true =
+ grub_register_command ("true", grub_cmd_true,
+ /* TRANSLATORS: it's a command description. */
+ 0, N_("Do nothing, successfully."));
+ cmd_false =
+ grub_register_command ("false", grub_cmd_false,
+ /* TRANSLATORS: it's a command description. */
+ 0, N_("Do nothing, unsuccessfully."));
+}
+
+GRUB_MOD_FINI(true)
+{
+ grub_unregister_command (cmd_true);
+ grub_unregister_command (cmd_false);
+}
diff --git a/grub-core/commands/usbtest.c b/grub-core/commands/usbtest.c
new file mode 100644
index 0000000..2c6d93f
--- /dev/null
+++ b/grub-core/commands/usbtest.c
@@ -0,0 +1,227 @@
+/* usbtest.c - test module for USB */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/charset.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/usb.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const char *usb_classes[] =
+ {
+ "Unknown",
+ "Audio",
+ "Communication Interface",
+ "HID",
+ "Unknown",
+ "Physical",
+ "Image",
+ "Printer",
+ "Mass Storage",
+ "Hub",
+ "Data Interface",
+ "Smart Card",
+ "Content Security",
+ "Video"
+ };
+
+static const char *usb_endp_type[] =
+ {
+ "Control",
+ "Isochronous",
+ "Bulk",
+ "Interrupt"
+ };
+
+static const char *usb_devspeed[] =
+ {
+ "",
+ "Low",
+ "Full",
+ "High"
+ };
+
+#if __GNUC__ >= 9
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
+#endif
+
+static grub_usb_err_t
+grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, int langid,
+ char **string)
+{
+ struct grub_usb_desc_str descstr;
+ struct grub_usb_desc_str *descstrp;
+ grub_usb_err_t err;
+
+ /* Only get the length. */
+ err = grub_usb_control_msg (dev, 1 << 7,
+ 0x06, (3 << 8) | index,
+ langid, 1, (char *) &descstr);
+ if (err)
+ return err;
+
+ descstrp = grub_malloc (descstr.length);
+ if (! descstrp)
+ return GRUB_USB_ERR_INTERNAL;
+ err = grub_usb_control_msg (dev, 1 << 7,
+ 0x06, (3 << 8) | index,
+ langid, descstr.length, (char *) descstrp);
+
+ if (descstrp->length == 0)
+ {
+ grub_free (descstrp);
+ *string = grub_strdup ("");
+ if (! *string)
+ return GRUB_USB_ERR_INTERNAL;
+ return GRUB_USB_ERR_NONE;
+ }
+
+ *string = grub_malloc (descstr.length * 2 + 1);
+ if (! *string)
+ {
+ grub_free (descstrp);
+ return GRUB_USB_ERR_INTERNAL;
+ }
+
+ *grub_utf16_to_utf8 ((grub_uint8_t *) *string, descstrp->str,
+ descstrp->length / 2 - 1) = 0;
+ grub_free (descstrp);
+
+ return GRUB_USB_ERR_NONE;
+}
+
+#if __GNUC__ >= 9
+#pragma GCC diagnostic pop
+#endif
+
+static void
+usb_print_str (const char *description, grub_usb_device_t dev, int idx)
+{
+ char *name = NULL;
+ grub_usb_err_t err;
+ /* XXX: LANGID */
+
+ if (! idx)
+ return;
+
+ err = grub_usb_get_string (dev, idx, 0x0409, &name);
+ if (err)
+ grub_printf ("Error %d retrieving %s\n", err, description);
+ else
+ {
+ grub_printf ("%s: `%s'\n", description, name);
+ grub_free (name);
+ }
+}
+
+static int
+usb_iterate (grub_usb_device_t dev, void *data __attribute__ ((unused)))
+{
+ struct grub_usb_desc_device *descdev;
+ int i;
+
+ descdev = &dev->descdev;
+
+ usb_print_str ("Product", dev, descdev->strprod);
+ usb_print_str ("Vendor", dev, descdev->strvendor);
+ usb_print_str ("Serial", dev, descdev->strserial);
+
+ grub_printf ("Class: (0x%02x) %s, Subclass: 0x%02x, Protocol: 0x%02x\n",
+ descdev->class, descdev->class < ARRAY_SIZE (usb_classes)
+ ? usb_classes[descdev->class] : "Unknown",
+ descdev->subclass, descdev->protocol);
+ grub_printf ("USB version %d.%d, VendorID: 0x%02x, ProductID: 0x%02x, #conf: %d\n",
+ descdev->usbrel >> 8, (descdev->usbrel >> 4) & 0x0F,
+ descdev->vendorid, descdev->prodid, descdev->configcnt);
+
+ grub_printf ("%s speed device\n", usb_devspeed[dev->speed]);
+
+ for (i = 0; i < descdev->configcnt; i++)
+ {
+ struct grub_usb_desc_config *config;
+
+ config = dev->config[i].descconf;
+ usb_print_str ("Configuration:", dev, config->strconfig);
+ }
+
+ for (i = 0; i < dev->config[0].descconf->numif; i++)
+ {
+ int j;
+ struct grub_usb_desc_if *interf;
+ interf = dev->config[0].interf[i].descif;
+
+ grub_printf ("Interface #%d: #Endpoints: %d ",
+ i, interf->endpointcnt);
+ grub_printf ("Class: (0x%02x) %s, Subclass: 0x%02x, Protocol: 0x%02x\n",
+ interf->class, interf->class < ARRAY_SIZE (usb_classes)
+ ? usb_classes[interf->class] : "Unknown",
+ interf->subclass, interf->protocol);
+
+ usb_print_str ("Interface", dev, interf->strif);
+
+ for (j = 0; j < interf->endpointcnt; j++)
+ {
+ struct grub_usb_desc_endp *endp;
+ endp = &dev->config[0].interf[i].descendp[j];
+
+ grub_printf ("Endpoint #%d: %s, max packed size: %d, transfer type: %s, latency: %d\n",
+ endp->endp_addr & 15,
+ (endp->endp_addr & 128) ? "IN" : "OUT",
+ endp->maxpacket, usb_endp_type[endp->attrib & 3],
+ endp->interval);
+ }
+ }
+
+ grub_printf("\n");
+
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_usbtest (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ grub_usb_poll_devices (1);
+
+ grub_printf ("USB devices:\n\n");
+ grub_usb_iterate (usb_iterate, NULL);
+
+ return 0;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(usbtest)
+{
+ cmd = grub_register_command ("usb", grub_cmd_usbtest,
+ 0, N_("Test USB support."));
+}
+
+GRUB_MOD_FINI(usbtest)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/videoinfo.c b/grub-core/commands/videoinfo.c
new file mode 100644
index 0000000..016a4d8
--- /dev/null
+++ b/grub-core/commands/videoinfo.c
@@ -0,0 +1,262 @@
+/* videoinfo.c - command to list video modes. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2007,2008,2009,2010 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/video.h>
+#include <grub/dl.h>
+#include <grub/env.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+struct hook_ctx
+{
+ unsigned height, width, depth;
+ struct grub_video_mode_info *current_mode;
+};
+
+static int
+hook (const struct grub_video_mode_info *info, void *hook_arg)
+{
+ struct hook_ctx *ctx = hook_arg;
+
+ if (ctx->height && ctx->width && (info->width != ctx->width || info->height != ctx->height))
+ return 0;
+
+ if (ctx->depth && info->bpp != ctx->depth)
+ return 0;
+
+ if (info->mode_number == GRUB_VIDEO_MODE_NUMBER_INVALID)
+ grub_printf (" ");
+ else
+ {
+ if (ctx->current_mode && info->mode_number == ctx->current_mode->mode_number)
+ grub_printf ("*");
+ else
+ grub_printf (" ");
+ grub_printf (" 0x%03x ", info->mode_number);
+ }
+ grub_printf ("%4d x %4d x %2d (%4d) ", info->width, info->height, info->bpp,
+ info->pitch);
+
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT)
+ grub_xputs (_("Text-only "));
+ /* Show mask and position details for direct color modes. */
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_RGB)
+ /* TRANSLATORS: "Direct color" is a mode when the color components
+ are written dirrectly into memory. */
+ grub_printf_ (N_("Direct color, mask: %d/%d/%d/%d pos: %d/%d/%d/%d"),
+ info->red_mask_size,
+ info->green_mask_size,
+ info->blue_mask_size,
+ info->reserved_mask_size,
+ info->red_field_pos,
+ info->green_field_pos,
+ info->blue_field_pos,
+ info->reserved_field_pos);
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR)
+ /* TRANSLATORS: In "paletted color" mode you write the index of the color
+ in the palette. Synonyms include "packed pixel". */
+ grub_xputs (_("Paletted "));
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_YUV)
+ grub_xputs (_("YUV "));
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PLANAR)
+ /* TRANSLATORS: "Planar" is the video memory where you have to write
+ in several different banks "plans" to control the different color
+ components of the same pixel. */
+ grub_xputs (_("Planar "));
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_HERCULES)
+ grub_xputs (_("Hercules "));
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_CGA)
+ grub_xputs (_("CGA "));
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_NONCHAIN4)
+ /* TRANSLATORS: Non-chain 4 is a 256-color planar
+ (unchained) video memory mode. */
+ grub_xputs (_("Non-chain 4 "));
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP)
+ grub_xputs (_("Monochrome "));
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_UNKNOWN)
+ grub_xputs (_("Unknown video mode "));
+
+ grub_xputs ("\n");
+
+ return 0;
+}
+
+static void
+print_edid (struct grub_video_edid_info *edid_info)
+{
+ unsigned int edid_width, edid_height;
+
+ if (grub_video_edid_checksum (edid_info))
+ {
+ grub_puts_ (N_(" EDID checksum invalid"));
+ grub_errno = GRUB_ERR_NONE;
+ return;
+ }
+
+ grub_printf_ (N_(" EDID version: %u.%u\n"),
+ edid_info->version, edid_info->revision);
+ if (grub_video_edid_preferred_mode (edid_info, &edid_width, &edid_height)
+ == GRUB_ERR_NONE)
+ grub_printf_ (N_(" Preferred mode: %ux%u\n"), edid_width, edid_height);
+ else
+ {
+ grub_printf_ (N_(" No preferred mode available\n"));
+ grub_errno = GRUB_ERR_NONE;
+ }
+}
+
+static grub_err_t
+grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ grub_video_adapter_t adapter;
+ grub_video_driver_id_t id;
+ struct hook_ctx ctx;
+
+ ctx.height = ctx.width = ctx.depth = 0;
+ if (argc)
+ {
+ const char *ptr;
+ ptr = args[0];
+ ctx.width = grub_strtoul (ptr, &ptr, 0);
+ if (grub_errno)
+ return grub_errno;
+ if (*ptr != 'x')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("invalid video mode specification `%s'"),
+ args[0]);
+ ptr++;
+ ctx.height = grub_strtoul (ptr, &ptr, 0);
+ if (grub_errno)
+ return grub_errno;
+ if (*ptr == 'x')
+ {
+ ptr++;
+ ctx.depth = grub_strtoul (ptr, &ptr, 0);
+ if (grub_errno)
+ return grub_errno;
+ }
+ }
+
+#ifdef GRUB_MACHINE_PCBIOS
+ if (grub_strcmp (cmd->name, "vbeinfo") == 0)
+ grub_dl_load ("vbe");
+#endif
+
+ id = grub_video_get_driver_id ();
+
+ grub_puts_ (N_("List of supported video modes:"));
+ grub_puts_ (N_("Legend: mask/position=red/green/blue/reserved"));
+
+ FOR_VIDEO_ADAPTERS (adapter)
+ {
+ struct grub_video_mode_info info;
+ struct grub_video_edid_info edid_info;
+
+ grub_printf_ (N_("Adapter `%s':\n"), adapter->name);
+
+ if (!adapter->iterate)
+ {
+ grub_puts_ (N_(" No info available"));
+ continue;
+ }
+
+ ctx.current_mode = NULL;
+
+ if (adapter->id == id)
+ {
+ if (grub_video_get_info (&info) == GRUB_ERR_NONE)
+ ctx.current_mode = &info;
+ else
+ /* Don't worry about errors. */
+ grub_errno = GRUB_ERR_NONE;
+ }
+ else
+ {
+ if (adapter->init ())
+ {
+ grub_puts_ (N_(" Failed to initialize video adapter"));
+ grub_errno = GRUB_ERR_NONE;
+ continue;
+ }
+ }
+
+ if (adapter->print_adapter_specific_info)
+ adapter->print_adapter_specific_info ();
+
+ adapter->iterate (hook, &ctx);
+
+ if (adapter->get_edid && adapter->get_edid (&edid_info) == GRUB_ERR_NONE)
+ print_edid (&edid_info);
+ else
+ grub_errno = GRUB_ERR_NONE;
+
+ ctx.current_mode = NULL;
+
+ if (adapter->id != id)
+ {
+ if (adapter->fini ())
+ {
+ grub_errno = GRUB_ERR_NONE;
+ continue;
+ }
+ }
+ }
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd;
+#ifdef GRUB_MACHINE_PCBIOS
+static grub_command_t cmd_vbe;
+#endif
+
+GRUB_MOD_INIT(videoinfo)
+{
+ cmd = grub_register_command ("videoinfo", grub_cmd_videoinfo,
+ /* TRANSLATORS: "x" has to be entered in,
+ like an identifier, so please don't
+ use better Unicode codepoints. */
+ N_("[WxH[xD]]"),
+ N_("List available video modes. If "
+ "resolution is given show only modes"
+ " matching it."));
+#ifdef GRUB_MACHINE_PCBIOS
+ cmd_vbe = grub_register_command ("vbeinfo", grub_cmd_videoinfo,
+ /* TRANSLATORS: "x" has to be entered in,
+ like an identifier, so please don't
+ use better Unicode codepoints. */
+ N_("[WxH[xD]]"),
+ N_("List available video modes. If "
+ "resolution is given show only modes"
+ " matching it."));
+#endif
+}
+
+GRUB_MOD_FINI(videoinfo)
+{
+ grub_unregister_command (cmd);
+#ifdef GRUB_MACHINE_PCBIOS
+ grub_unregister_command (cmd_vbe);
+#endif
+}
+
diff --git a/grub-core/commands/videotest.c b/grub-core/commands/videotest.c
new file mode 100644
index 0000000..b6c181b
--- /dev/null
+++ b/grub-core/commands/videotest.c
@@ -0,0 +1,241 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007,2009 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/video.h>
+#include <grub/types.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/font.h>
+#include <grub/term.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/gfxmenu_view.h>
+#include <grub/env.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ grub_err_t err;
+ grub_video_color_t color;
+ unsigned int x;
+ unsigned int y;
+ unsigned int width;
+ unsigned int height;
+ int i;
+ struct grub_video_render_target *text_layer;
+ grub_video_color_t palette[16];
+ const char *mode = NULL;
+
+#ifdef GRUB_MACHINE_PCBIOS
+ if (grub_strcmp (cmd->name, "vbetest") == 0)
+ grub_dl_load ("vbe");
+#endif
+ mode = grub_env_get ("gfxmode");
+ if (argc)
+ mode = args[0];
+ if (!mode)
+ mode = "auto";
+
+ err = grub_video_set_mode (mode, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
+ if (err)
+ return err;
+
+ grub_video_get_viewport (&x, &y, &width, &height);
+
+ {
+ const char *str;
+ int texty;
+ grub_font_t sansbig;
+ grub_font_t sans;
+ grub_font_t sanssmall;
+ grub_font_t fixed;
+ struct grub_font_glyph *glyph;
+
+ if (grub_video_create_render_target (&text_layer, width, height,
+ GRUB_VIDEO_MODE_TYPE_RGB
+ | GRUB_VIDEO_MODE_TYPE_ALPHA)
+ || !text_layer)
+ goto fail;
+
+ grub_video_set_active_render_target (text_layer);
+
+ color = grub_video_map_rgb (0, 255, 255);
+ sansbig = grub_font_get ("Unknown Regular 16");
+ sans = grub_font_get ("Unknown Regular 16");
+ sanssmall = grub_font_get ("Unknown Regular 16");
+ fixed = grub_font_get ("Fixed 20");
+ if (! sansbig || ! sans || ! sanssmall || ! fixed)
+ return grub_error (GRUB_ERR_BAD_FONT, "no font loaded");
+
+ glyph = grub_font_get_glyph (fixed, '*');
+ grub_font_draw_glyph (glyph, color, 200 ,0);
+
+ color = grub_video_map_rgb (255, 255, 255);
+
+ texty = 32;
+ grub_font_draw_string ("The quick brown fox jumped over the lazy dog.",
+ sans, color, 16, texty);
+ texty += grub_font_get_descent (sans) + grub_font_get_leading (sans);
+
+ texty += grub_font_get_ascent (fixed);
+ grub_font_draw_string ("The quick brown fox jumped over the lazy dog.",
+ fixed, color, 16, texty);
+ texty += grub_font_get_descent (fixed) + grub_font_get_leading (fixed);
+
+ /* To convert Unicode characters into UTF-8 for this test, the following
+ command is useful:
+ echo -ne '\x00\x00\x26\x3A' | iconv -f UTF-32BE -t UTF-8 | od -t x1
+ This converts the Unicode character U+263A to UTF-8. */
+
+ /* Characters used:
+ Code point Description UTF-8 encoding
+ ----------- ------------------------------ --------------
+ U+263A unfilled smiley face E2 98 BA
+ U+00A1 inverted exclamation point C2 A1
+ U+00A3 British pound currency symbol C2 A3
+ U+03C4 Greek tau CF 84
+ U+00E4 lowercase letter a with umlaut C3 A4
+ U+2124 set 'Z' symbol (integers) E2 84 A4
+ U+2286 subset symbol E2 8A 86
+ U+211D set 'R' symbol (real numbers) E2 84 9D */
+
+ str =
+ "Unicode test: happy\xE2\x98\xBA \xC2\xA3 5.00"
+ " \xC2\xA1\xCF\x84\xC3\xA4u! "
+ " \xE2\x84\xA4\xE2\x8A\x86\xE2\x84\x9D";
+ color = grub_video_map_rgb (128, 128, 255);
+
+ /* All characters in the string exist in the 'Fixed 20' (10x20) font. */
+ texty += grub_font_get_ascent(fixed);
+ grub_font_draw_string (str, fixed, color, 16, texty);
+ texty += grub_font_get_descent (fixed) + grub_font_get_leading (fixed);
+
+ texty += grub_font_get_ascent(sansbig);
+ grub_font_draw_string (str, sansbig, color, 16, texty);
+ texty += grub_font_get_descent (sansbig) + grub_font_get_leading (sansbig);
+
+ texty += grub_font_get_ascent(sans);
+ grub_font_draw_string (str, sans, color, 16, texty);
+ texty += grub_font_get_descent (sans) + grub_font_get_leading (sans);
+
+ texty += grub_font_get_ascent(sanssmall);
+ grub_font_draw_string (str, sanssmall, color, 16, texty);
+ texty += (grub_font_get_descent (sanssmall)
+ + grub_font_get_leading (sanssmall));
+
+ glyph = grub_font_get_glyph (fixed, '*');
+
+ for (i = 0; i < 16; i++)
+ {
+ color = grub_video_map_color (i);
+ palette[i] = color;
+ grub_font_draw_glyph (glyph, color, 16 + i * 16, 220);
+ }
+ }
+
+ grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+
+ for (i = 0; i < 5; i++)
+ {
+
+ if (i == 0 || i == 1)
+ {
+ color = grub_video_map_rgb (0, 0, 0);
+ grub_video_fill_rect (color, 0, 0, width, height);
+
+ color = grub_video_map_rgb (255, 0, 0);
+ grub_video_fill_rect (color, 0, 0, 100, 100);
+
+ color = grub_video_map_rgb (0, 255, 0);
+ grub_video_fill_rect (color, 100, 0, 100, 100);
+
+ color = grub_video_map_rgb (0, 0, 255);
+ grub_video_fill_rect (color, 200, 0, 100, 100);
+
+ color = grub_video_map_rgb (0, 255, 255);
+ grub_video_fill_rect (color, 0, 100, 100, 100);
+
+ color = grub_video_map_rgb (255, 0, 255);
+ grub_video_fill_rect (color, 100, 100, 100, 100);
+
+ color = grub_video_map_rgb (255, 255, 0);
+ grub_video_fill_rect (color, 200, 100, 100, 100);
+
+ grub_video_set_viewport (x + 150, y + 150,
+ width - 150 * 2, height - 150 * 2);
+ color = grub_video_map_rgb (77, 33, 77);
+ grub_video_fill_rect (color, 0, 0, width, height);
+ }
+
+ color = grub_video_map_rgb (i, 33, 77);
+ grub_video_fill_rect (color, 0, 0, width, height);
+ grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_BLEND, 0, 0,
+ 0, 0, width, height);
+ grub_video_swap_buffers ();
+ }
+
+ grub_getkey ();
+
+ grub_video_delete_render_target (text_layer);
+
+ grub_video_restore ();
+
+ for (i = 0; i < 16; i++)
+ grub_printf("color %d: %08x\n", i, palette[i]);
+
+ grub_errno = GRUB_ERR_NONE;
+ return grub_errno;
+
+ fail:
+ grub_video_delete_render_target (text_layer);
+ grub_video_restore ();
+ return grub_errno;
+}
+
+static grub_command_t cmd;
+#ifdef GRUB_MACHINE_PCBIOS
+static grub_command_t cmd_vbe;
+#endif
+
+GRUB_MOD_INIT(videotest)
+{
+ cmd = grub_register_command ("videotest", grub_cmd_videotest,
+ /* TRANSLATORS: "x" has to be entered in,
+ like an identifier, so please don't
+ use better Unicode codepoints. */
+ N_("[WxH]"),
+ /* TRANSLATORS: Here, on the other hand, it's
+ nicer to use unicode cross instead of x. */
+ N_("Test video subsystem in mode WxH."));
+#ifdef GRUB_MACHINE_PCBIOS
+ cmd_vbe = grub_register_command ("vbetest", grub_cmd_videotest,
+ 0, N_("Test video subsystem."));
+#endif
+}
+
+GRUB_MOD_FINI(videotest)
+{
+ grub_unregister_command (cmd);
+#ifdef GRUB_MACHINE_PCBIOS
+ grub_unregister_command (cmd_vbe);
+#endif
+}
diff --git a/grub-core/commands/wildcard.c b/grub-core/commands/wildcard.c
new file mode 100644
index 0000000..cc32903
--- /dev/null
+++ b/grub-core/commands/wildcard.c
@@ -0,0 +1,652 @@
+/* wildcard.c - Wildcard character expansion for GRUB script. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010 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/mm.h>
+#include <grub/fs.h>
+#include <grub/env.h>
+#include <grub/file.h>
+#include <grub/device.h>
+#include <grub/script_sh.h>
+#include <grub/safemath.h>
+
+#include <regex.h>
+
+static inline int isregexop (char ch);
+static char ** merge (char **lhs, char **rhs);
+static char *make_dir (const char *prefix, const char *start, const char *end);
+static int make_regex (const char *regex_start, const char *regex_end,
+ regex_t *regexp);
+static void split_path (const char *path, const char **suffix_end, const char **regex_end);
+static char ** match_devices (const regex_t *regexp, int noparts);
+static char ** match_files (const char *prefix, const char *suffix_start,
+ const char *suffix_end, const regex_t *regexp);
+
+static grub_err_t wildcard_expand (const char *s, char ***strs);
+
+struct grub_script_wildcard_translator grub_filename_translator = {
+ .expand = wildcard_expand,
+};
+
+static char **
+merge (char **dest, char **ps)
+{
+ int i;
+ int j;
+ char **p;
+ grub_size_t sz;
+
+ if (! dest)
+ return ps;
+
+ if (! ps)
+ return dest;
+
+ for (i = 0; dest[i]; i++)
+ ;
+ for (j = 0; ps[j]; j++)
+ ;
+
+ if (grub_add (i, j, &sz) ||
+ grub_add (sz, 1, &sz) ||
+ grub_mul (sz, sizeof (char *), &sz))
+ return dest;
+
+ p = grub_realloc (dest, sz);
+ if (! p)
+ {
+ grub_free (dest);
+ grub_free (ps);
+ return 0;
+ }
+
+ dest = p;
+ for (j = 0; ps[j]; j++)
+ dest[i++] = ps[j];
+ dest[i] = 0;
+
+ grub_free (ps);
+ return dest;
+}
+
+static inline int
+isregexop (char ch)
+{
+ return grub_strchr ("*.\\|+{}[]?", ch) ? 1 : 0;
+}
+
+static char *
+make_dir (const char *prefix, const char *start, const char *end)
+{
+ char ch;
+ unsigned i;
+ unsigned n;
+ char *result;
+
+ i = grub_strlen (prefix);
+ n = i + end - start;
+
+ result = grub_malloc (n + 1);
+ if (! result)
+ return 0;
+
+ grub_strcpy (result, prefix);
+ while (start < end && (ch = *start++))
+ if (ch == '\\' && isregexop (*start))
+ result[i++] = *start++;
+ else
+ result[i++] = ch;
+
+ result[i] = '\0';
+ return result;
+}
+
+static int
+make_regex (const char *start, const char *end, regex_t *regexp)
+{
+ char ch;
+ int i = 0;
+ unsigned len = end - start;
+ char *buffer;
+ grub_size_t sz;
+
+ /* Worst case size is (len * 2 + 2 + 1). */
+ if (grub_mul (len, 2, &sz) ||
+ grub_add (sz, 3, &sz))
+ return 1;
+
+ buffer = grub_malloc (sz);
+ if (! buffer)
+ return 1;
+
+ buffer[i++] = '^';
+ while (start < end)
+ {
+ /* XXX Only * and ? expansion for now. */
+ switch ((ch = *start++))
+ {
+ case '\\':
+ buffer[i++] = ch;
+ if (*start != '\0')
+ buffer[i++] = *start++;
+ break;
+
+ case '.':
+ case '(':
+ case ')':
+ case '@':
+ case '+':
+ case '|':
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ buffer[i++] = '\\';
+ buffer[i++] = ch;
+ break;
+
+ case '*':
+ buffer[i++] = '.';
+ buffer[i++] = '*';
+ break;
+
+ case '?':
+ buffer[i++] = '.';
+ break;
+
+ default:
+ buffer[i++] = ch;
+ }
+ }
+ buffer[i++] = '$';
+ buffer[i] = '\0';
+ grub_dprintf ("expand", "Regexp is %s\n", buffer);
+
+ if (regcomp (regexp, buffer, RE_SYNTAX_GNU_AWK))
+ {
+ grub_free (buffer);
+ return 1;
+ }
+
+ grub_free (buffer);
+ return 0;
+}
+
+/* Split `str' into two parts: (1) dirname that is regexop free (2)
+ dirname that has a regexop. */
+static void
+split_path (const char *str, const char **noregexop, const char **regexop)
+{
+ char ch = 0;
+ int regex = 0;
+
+ const char *end;
+ const char *split; /* points till the end of dirnaname that doesn't
+ need expansion. */
+
+ split = end = str;
+ while ((ch = *end))
+ {
+ if (ch == '\\' && end[1])
+ end++;
+
+ else if (ch == '*' || ch == '?')
+ regex = 1;
+
+ else if (ch == '/' && ! regex)
+ split = end + 1; /* forward to next regexop-free dirname */
+
+ else if (ch == '/' && regex)
+ break; /* stop at the first dirname with a regexop */
+
+ end++;
+ }
+
+ *regexop = end;
+ if (! regex)
+ *noregexop = end;
+ else
+ *noregexop = split;
+}
+
+/* Context for match_devices. */
+struct match_devices_ctx
+{
+ const regex_t *regexp;
+ int noparts;
+ int ndev;
+ char **devs;
+};
+
+/* Helper for match_devices. */
+static int
+match_devices_iter (const char *name, void *data)
+{
+ struct match_devices_ctx *ctx = data;
+ char **t;
+ char *buffer;
+ grub_size_t sz;
+
+ /* skip partitions if asked to. */
+ if (ctx->noparts && grub_strchr (name, ','))
+ return 0;
+
+ buffer = grub_xasprintf ("(%s)", name);
+ if (! buffer)
+ return 1;
+
+ grub_dprintf ("expand", "matching: %s\n", buffer);
+ if (regexec (ctx->regexp, buffer, 0, 0, 0))
+ {
+ grub_dprintf ("expand", "not matched\n");
+ fail:
+ grub_free (buffer);
+ return 0;
+ }
+
+ if (grub_add (ctx->ndev, 2, &sz) ||
+ grub_mul (sz, sizeof (char *), &sz))
+ goto fail;
+
+ t = grub_realloc (ctx->devs, sz);
+ if (! t)
+ {
+ grub_free (buffer);
+ return 1;
+ }
+
+ ctx->devs = t;
+ ctx->devs[ctx->ndev++] = buffer;
+ ctx->devs[ctx->ndev] = 0;
+ return 0;
+}
+
+static char **
+match_devices (const regex_t *regexp, int noparts)
+{
+ struct match_devices_ctx ctx = {
+ .regexp = regexp,
+ .noparts = noparts,
+ .ndev = 0,
+ .devs = 0
+ };
+ int i;
+
+ if (grub_device_iterate (match_devices_iter, &ctx))
+ goto fail;
+
+ return ctx.devs;
+
+ fail:
+
+ for (i = 0; ctx.devs && ctx.devs[i]; i++)
+ grub_free (ctx.devs[i]);
+
+ grub_free (ctx.devs);
+
+ return 0;
+}
+
+/* Context for match_files. */
+struct match_files_ctx
+{
+ const regex_t *regexp;
+ char **files;
+ unsigned nfile;
+ char *dir;
+};
+
+/* Helper for match_files. */
+static int
+match_files_iter (const char *name,
+ const struct grub_dirhook_info *info __attribute__((unused)),
+ void *data)
+{
+ struct match_files_ctx *ctx = data;
+ char **t;
+ char *buffer;
+ grub_size_t sz;
+
+ /* skip . and .. names */
+ if (grub_strcmp(".", name) == 0 || grub_strcmp("..", name) == 0)
+ return 0;
+
+ grub_dprintf ("expand", "matching: %s in %s\n", name, ctx->dir);
+ if (regexec (ctx->regexp, name, 0, 0, 0))
+ return 0;
+
+ grub_dprintf ("expand", "matched\n");
+
+ buffer = grub_xasprintf ("%s%s", ctx->dir, name);
+ if (! buffer)
+ return 1;
+
+ if (grub_add (ctx->nfile, 2, &sz) ||
+ grub_mul (sz, sizeof (char *), &sz))
+ goto fail;
+
+ t = grub_realloc (ctx->files, sz);
+ if (!t)
+ {
+ fail:
+ grub_free (buffer);
+ return 1;
+ }
+
+ ctx->files = t;
+ ctx->files[ctx->nfile++] = buffer;
+ ctx->files[ctx->nfile] = 0;
+ return 0;
+}
+
+static char **
+match_files (const char *prefix, const char *suffix, const char *end,
+ const regex_t *regexp)
+{
+ struct match_files_ctx ctx = {
+ .regexp = regexp,
+ .nfile = 0,
+ .files = 0
+ };
+ int i;
+ const char *path;
+ char *device_name;
+ grub_fs_t fs;
+ grub_device_t dev;
+
+ dev = 0;
+ device_name = 0;
+ grub_error_push ();
+
+ ctx.dir = make_dir (prefix, suffix, end);
+ if (! ctx.dir)
+ goto fail;
+
+ device_name = grub_file_get_device_name (ctx.dir);
+ dev = grub_device_open (device_name);
+ if (! dev)
+ goto fail;
+
+ fs = grub_fs_probe (dev);
+ if (! fs)
+ goto fail;
+
+ if (ctx.dir[0] == '(')
+ {
+ path = grub_strchr (ctx.dir, ')');
+ if (!path)
+ goto fail;
+ path++;
+ }
+ else
+ path = ctx.dir;
+
+ if (fs->fs_dir (dev, path, match_files_iter, &ctx))
+ goto fail;
+
+ grub_free (ctx.dir);
+ grub_device_close (dev);
+ grub_free (device_name);
+ grub_error_pop ();
+ return ctx.files;
+
+ fail:
+
+ grub_free (ctx.dir);
+
+ for (i = 0; ctx.files && ctx.files[i]; i++)
+ grub_free (ctx.files[i]);
+
+ grub_free (ctx.files);
+
+ if (dev)
+ grub_device_close (dev);
+
+ grub_free (device_name);
+
+ grub_error_pop ();
+ return 0;
+}
+
+/* Context for check_file. */
+struct check_file_ctx
+{
+ const char *basename;
+ int found;
+};
+
+/* Helper for check_file. */
+static int
+check_file_iter (const char *name, const struct grub_dirhook_info *info,
+ void *data)
+{
+ struct check_file_ctx *ctx = data;
+
+ if (ctx->basename[0] == 0
+ || (info->case_insensitive ? grub_strcasecmp (name, ctx->basename) == 0
+ : grub_strcmp (name, ctx->basename) == 0))
+ {
+ ctx->found = 1;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+check_file (const char *dir, const char *basename)
+{
+ struct check_file_ctx ctx = {
+ .basename = basename,
+ .found = 0
+ };
+ grub_fs_t fs;
+ grub_device_t dev;
+ const char *device_name, *path;
+
+ device_name = grub_file_get_device_name (dir);
+ dev = grub_device_open (device_name);
+ if (! dev)
+ goto fail;
+
+ fs = grub_fs_probe (dev);
+ if (! fs)
+ goto fail;
+
+ if (dir[0] == '(')
+ {
+ path = grub_strchr (dir, ')');
+ if (!path)
+ goto fail;
+ path++;
+ }
+ else
+ path = dir;
+
+ fs->fs_dir (dev, path[0] ? path : "/", check_file_iter, &ctx);
+ if (grub_errno == 0 && basename[0] == 0)
+ ctx.found = 1;
+
+ fail:
+ grub_errno = 0;
+
+ return ctx.found;
+}
+
+static void
+unescape (char *out, const char *in, const char *end)
+{
+ char *optr;
+ const char *iptr;
+
+ for (optr = out, iptr = in; iptr < end;)
+ {
+ if (*iptr == '\\' && iptr + 1 < end)
+ {
+ *optr++ = iptr[1];
+ iptr += 2;
+ continue;
+ }
+ if (*iptr == '\\')
+ break;
+ *optr++ = *iptr++;
+ }
+ *optr = 0;
+}
+
+static grub_err_t
+wildcard_expand (const char *s, char ***strs)
+{
+ const char *start;
+ const char *regexop;
+ const char *noregexop;
+ char **paths = 0;
+ int had_regexp = 0;
+
+ unsigned i;
+ regex_t regexp;
+
+ *strs = 0;
+ if (s[0] != '/' && s[0] != '(' && s[0] != '*')
+ return 0;
+
+ start = s;
+ while (*start)
+ {
+ split_path (start, &noregexop, &regexop);
+
+ if (noregexop == regexop)
+ {
+ grub_dprintf ("expand", "no expansion needed\n");
+ if (paths == 0)
+ {
+ paths = grub_malloc (sizeof (char *) * 2);
+ if (!paths)
+ goto fail;
+ paths[0] = grub_malloc (regexop - start + 1);
+ if (!paths[0])
+ goto fail;
+ unescape (paths[0], start, regexop);
+ paths[1] = 0;
+ }
+ else
+ {
+ int j = 0;
+ for (i = 0; paths[i]; i++)
+ {
+ char *o, *oend;
+ char *n;
+ char *p;
+ o = paths[i];
+ oend = o + grub_strlen (o);
+ n = grub_malloc ((oend - o) + (regexop - start) + 1);
+ if (!n)
+ goto fail;
+ grub_memcpy (n, o, oend - o);
+
+ unescape (n + (oend - o), start, regexop);
+ if (had_regexp)
+ p = grub_strrchr (n, '/');
+ else
+ p = 0;
+ if (!p)
+ {
+ grub_free (o);
+ paths[j++] = n;
+ continue;
+ }
+ *p = 0;
+ if (!check_file (n, p + 1))
+ {
+ grub_dprintf ("expand", "file <%s> in <%s> not found\n",
+ p + 1, n);
+ grub_free (o);
+ grub_free (n);
+ continue;
+ }
+ *p = '/';
+ grub_free (o);
+ paths[j++] = n;
+ }
+ if (j == 0)
+ {
+ grub_free (paths);
+ paths = 0;
+ goto done;
+ }
+ paths[j] = 0;
+ }
+ grub_dprintf ("expand", "paths[0] = `%s'\n", paths[0]);
+ start = regexop;
+ continue;
+ }
+
+ if (make_regex (noregexop, regexop, &regexp))
+ goto fail;
+
+ had_regexp = 1;
+
+ if (paths == 0)
+ {
+ if (start == noregexop) /* device part has regexop */
+ paths = match_devices (&regexp, *start != '(');
+
+ else /* device part explicit wo regexop */
+ paths = match_files ("", start, noregexop, &regexp);
+ }
+ else
+ {
+ char **r = 0;
+
+ for (i = 0; paths[i]; i++)
+ {
+ char **p;
+
+ p = match_files (paths[i], start, noregexop, &regexp);
+ grub_free (paths[i]);
+ if (! p)
+ continue;
+
+ r = merge (r, p);
+ if (! r)
+ goto fail;
+ }
+ grub_free (paths);
+ paths = r;
+ }
+
+ regfree (&regexp);
+ if (! paths)
+ goto done;
+
+ start = regexop;
+ }
+
+ done:
+
+ *strs = paths;
+ return 0;
+
+ fail:
+
+ for (i = 0; paths && paths[i]; i++)
+ grub_free (paths[i]);
+ grub_free (paths);
+ regfree (&regexp);
+ return grub_errno;
+}
diff --git a/grub-core/commands/xen/lsxen.c b/grub-core/commands/xen/lsxen.c
new file mode 100644
index 0000000..9771310
--- /dev/null
+++ b/grub-core/commands/xen/lsxen.c
@@ -0,0 +1,90 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2011 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/misc.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/xen.h>
+#include <grub/term.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static int
+hook (const char *dir, void *hook_data __attribute__ ((unused)))
+{
+ grub_printf ("%s\n", dir);
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_lsxen (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ char *dir;
+ grub_err_t err;
+ char *buf;
+
+ if (argc >= 1)
+ return grub_xenstore_dir (args[0], hook, NULL);
+
+ buf = grub_xenstore_get_file ("domid", NULL);
+ if (!buf)
+ return grub_errno;
+ dir = grub_xasprintf ("/local/domain/%s", buf);
+ grub_free (buf);
+ err = grub_xenstore_dir (dir, hook, NULL);
+ grub_free (dir);
+ return err;
+}
+
+static grub_err_t
+grub_cmd_catxen (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ const char *dir = "domid";
+ char *buf;
+
+ if (argc >= 1)
+ dir = args[0];
+
+ buf = grub_xenstore_get_file (dir, NULL);
+ if (!buf)
+ return grub_errno;
+ grub_xputs (buf);
+ grub_xputs ("\n");
+ grub_free (buf);
+ return GRUB_ERR_NONE;
+
+}
+
+static grub_command_t cmd_ls, cmd_cat;
+
+GRUB_MOD_INIT (lsxen)
+{
+ cmd_ls = grub_register_command ("xen_ls", grub_cmd_lsxen, N_("[DIR]"),
+ N_("List Xen storage."));
+ cmd_cat = grub_register_command ("xen_cat", grub_cmd_catxen, N_("[DIR]"),
+ N_("List Xen storage."));
+}
+
+GRUB_MOD_FINI (lsxen)
+{
+ grub_unregister_command (cmd_ls);
+ grub_unregister_command (cmd_cat);
+}
diff --git a/grub-core/commands/xnu_uuid.c b/grub-core/commands/xnu_uuid.c
new file mode 100644
index 0000000..ae4b3a4
--- /dev/null
+++ b/grub-core/commands/xnu_uuid.c
@@ -0,0 +1,119 @@
+/* xnu_uuid.c - transform 64-bit serial number
+ to 128-bit uuid suitable for xnu. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1995,1996,1998,1999,2001,2002,
+ * 2003, 2009 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/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+#include <grub/fs.h>
+#include <grub/file.h>
+#include <grub/misc.h>
+#include <grub/env.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/crypto.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* This prefix is used by xnu and boot-132 to hash
+ together with volume serial. */
+static grub_uint8_t hash_prefix[16]
+ = {0xB3, 0xE2, 0x0F, 0x39, 0xF2, 0x92, 0x11, 0xD6,
+ 0x97, 0xA4, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC};
+
+static grub_err_t
+grub_cmd_xnu_uuid (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ grub_uint64_t serial;
+ grub_uint8_t *xnu_uuid;
+ char uuid_string[sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")];
+ char *ptr;
+ void *ctx;
+ int low = 0;
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "UUID required");
+
+ if (argc > 1 && grub_strcmp (args[0], "-l") == 0)
+ {
+ low = 1;
+ argc--;
+ args++;
+ }
+
+ serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16));
+
+ ctx = grub_zalloc (GRUB_MD_MD5->contextsize);
+ if (!ctx)
+ return grub_errno;
+ GRUB_MD_MD5->init (ctx);
+ GRUB_MD_MD5->write (ctx, hash_prefix, sizeof (hash_prefix));
+ GRUB_MD_MD5->write (ctx, &serial, sizeof (serial));
+ GRUB_MD_MD5->final (ctx);
+ xnu_uuid = GRUB_MD_MD5->read (ctx);
+
+ grub_snprintf (uuid_string, sizeof (uuid_string),
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ (unsigned int) xnu_uuid[0], (unsigned int) xnu_uuid[1],
+ (unsigned int) xnu_uuid[2], (unsigned int) xnu_uuid[3],
+ (unsigned int) xnu_uuid[4], (unsigned int) xnu_uuid[5],
+ (unsigned int) ((xnu_uuid[6] & 0xf) | 0x30),
+ (unsigned int) xnu_uuid[7],
+ (unsigned int) ((xnu_uuid[8] & 0x3f) | 0x80),
+ (unsigned int) xnu_uuid[9],
+ (unsigned int) xnu_uuid[10], (unsigned int) xnu_uuid[11],
+ (unsigned int) xnu_uuid[12], (unsigned int) xnu_uuid[13],
+ (unsigned int) xnu_uuid[14], (unsigned int) xnu_uuid[15]);
+ if (!low)
+ for (ptr = uuid_string; *ptr; ptr++)
+ *ptr = grub_toupper (*ptr);
+ if (argc == 1)
+ grub_printf ("%s\n", uuid_string);
+ if (argc > 1)
+ grub_env_set (args[1], uuid_string);
+
+ grub_free (ctx);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd;
+
+
+GRUB_MOD_INIT (xnu_uuid)
+{
+ cmd = grub_register_command ("xnu_uuid", grub_cmd_xnu_uuid,
+ /* TRANSLATORS: GRUBUUID stands for "filesystem
+ UUID as used in GRUB". */
+ N_("[-l] GRUBUUID [VARNAME]"),
+ N_("Transform 64-bit UUID to format "
+ "suitable for XNU. If -l is given keep "
+ "it lowercase as done by blkid."));
+}
+
+GRUB_MOD_FINI (xnu_uuid)
+{
+ grub_unregister_command (cmd);
+}