aboutsummaryrefslogtreecommitdiffstats
path: root/grub-core/commands
diff options
context:
space:
mode:
authorJames <james.mckenzie@citrix.com>2012-11-16 10:41:01 +0000
committerJames <james.mckenzie@citrix.com>2012-11-16 10:41:01 +0000
commit041d1ea37802bf7178a31a53f96c26efa6b8fb7b (patch)
treec193e84ad1237f25a79d0f6a267722e44c73f56a /grub-core/commands
downloadgrub-1.99-041d1ea37802bf7178a31a53f96c26efa6b8fb7b.tar.gz
grub-1.99-041d1ea37802bf7178a31a53f96c26efa6b8fb7b.tar.bz2
grub-1.99-041d1ea37802bf7178a31a53f96c26efa6b8fb7b.zip
fish
Diffstat (limited to 'grub-core/commands')
-rw-r--r--grub-core/commands/acpi.c774
-rw-r--r--grub-core/commands/acpihalt.c332
-rw-r--r--grub-core/commands/blocklist.c122
-rw-r--r--grub-core/commands/boot.c198
-rw-r--r--grub-core/commands/cat.c104
-rw-r--r--grub-core/commands/cmp.c120
-rw-r--r--grub-core/commands/configfile.c98
-rw-r--r--grub-core/commands/date.c148
-rw-r--r--grub-core/commands/echo.c141
-rw-r--r--grub-core/commands/efi/acpi.c59
-rw-r--r--grub-core/commands/efi/fixvideo.c112
-rw-r--r--grub-core/commands/efi/loadbios.c220
-rw-r--r--grub-core/commands/efi/lsefimmap.c145
-rw-r--r--grub-core/commands/efi/lsefisystab.c110
-rw-r--r--grub-core/commands/efi/lssal.c165
-rw-r--r--grub-core/commands/extcmd.c118
-rw-r--r--grub-core/commands/gptsync.c258
-rw-r--r--grub-core/commands/halt.c48
-rw-r--r--grub-core/commands/hashsum.c300
-rw-r--r--grub-core/commands/hdparm.c422
-rw-r--r--grub-core/commands/help.c143
-rw-r--r--grub-core/commands/hexdump.c133
-rw-r--r--grub-core/commands/i386/cmostest.c92
-rw-r--r--grub-core/commands/i386/cpuid.c100
-rw-r--r--grub-core/commands/i386/pc/acpi.c81
-rw-r--r--grub-core/commands/i386/pc/drivemap.c422
-rw-r--r--grub-core/commands/i386/pc/drivemap_int13h.S110
-rw-r--r--grub-core/commands/i386/pc/halt.c127
-rw-r--r--grub-core/commands/i386/pc/lsapm.c115
-rw-r--r--grub-core/commands/i386/pc/play.c275
-rw-r--r--grub-core/commands/i386/pc/pxecmd.c54
-rw-r--r--grub-core/commands/i386/pc/sendkey.c385
-rw-r--r--grub-core/commands/ieee1275/suspend.c51
-rw-r--r--grub-core/commands/iorw.c152
-rw-r--r--grub-core/commands/keylayouts.c299
-rw-r--r--grub-core/commands/keystatus.c110
-rw-r--r--grub-core/commands/legacycfg.c820
-rw-r--r--grub-core/commands/loadenv.c399
-rw-r--r--grub-core/commands/ls.c282
-rw-r--r--grub-core/commands/lsacpi.c252
-rw-r--r--grub-core/commands/lsmmap.c74
-rw-r--r--grub-core/commands/lspci.c236
-rw-r--r--grub-core/commands/memrw.c151
-rw-r--r--grub-core/commands/menuentry.c307
-rw-r--r--grub-core/commands/minicmd.c230
-rw-r--r--grub-core/commands/mips/yeeloong/lsspd.c94
-rw-r--r--grub-core/commands/parttool.c333
-rw-r--r--grub-core/commands/password.c93
-rw-r--r--grub-core/commands/password_pbkdf2.c199
-rw-r--r--grub-core/commands/probe.c162
-rw-r--r--grub-core/commands/read.c92
-rw-r--r--grub-core/commands/reboot.c47
-rw-r--r--grub-core/commands/regexp.c151
-rw-r--r--grub-core/commands/search.c245
-rw-r--r--grub-core/commands/search_file.c6
-rw-r--r--grub-core/commands/search_label.c6
-rw-r--r--grub-core/commands/search_uuid.c6
-rw-r--r--grub-core/commands/search_wrap.c109
-rw-r--r--grub-core/commands/setpci.c343
-rw-r--r--grub-core/commands/sleep.c114
-rw-r--r--grub-core/commands/terminal.c258
-rw-r--r--grub-core/commands/test.c438
-rw-r--r--grub-core/commands/testload.c157
-rw-r--r--grub-core/commands/true.c59
-rw-r--r--grub-core/commands/usbtest.c218
-rw-r--r--grub-core/commands/videoinfo.c186
-rw-r--r--grub-core/commands/videotest.c218
-rw-r--r--grub-core/commands/wildcard.c495
-rw-r--r--grub-core/commands/xnu_uuid.c102
69 files changed, 13525 insertions, 0 deletions
diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c
new file mode 100644
index 0000000..8f44296
--- /dev/null
+++ b/grub-core/commands/acpi.c
@@ -0,0 +1,774 @@
+/* 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>
+
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/efi.h>
+#include <grub/efi/api.h>
+#endif
+
+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_("Expose v1 tables."), 0, ARG_TYPE_NONE},
+ {"v2", '2', 0, N_("Expose v2 and v3 tables."), 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},
+ {"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}
+};
+
+/* Simple checksum by summing all bytes. Used by ACPI and SMBIOS. */
+grub_uint8_t
+grub_byte_checksum (void *base, grub_size_t size)
+{
+ grub_uint8_t *ptr;
+ grub_uint8_t ret = 0;
+ for (ptr = (grub_uint8_t *) base; ptr < ((grub_uint8_t *) base) + size;
+ ptr++)
+ ret += *ptr;
+ return ret;
+}
+
+/* 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 ();
+}
+
+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;
+}
+
+grub_err_t
+grub_acpi_create_ebda (void)
+{
+ int ebda_kb_len;
+ int ebda_len;
+ int mmapregion = 0;
+ grub_uint8_t *ebda, *v1inebda = 0, *v2inebda = 0;
+ grub_uint64_t highestlow = 0;
+ grub_uint8_t *targetebda, *target;
+ struct grub_acpi_rsdp_v10 *v1;
+ struct grub_acpi_rsdp_v20 *v2;
+ auto int NESTED_FUNC_ATTR find_hook (grub_uint64_t, grub_uint64_t,
+ grub_uint32_t);
+ int NESTED_FUNC_ATTR find_hook (grub_uint64_t start, grub_uint64_t size,
+ grub_memory_type_t type)
+ {
+ grub_uint64_t end = start + size;
+ if (type != GRUB_MEMORY_AVAILABLE)
+ return 0;
+ if (end > 0x100000)
+ end = 0x100000;
+ if (end > start + ebda_len
+ && highestlow < ((end - ebda_len) & (~0xf)) )
+ highestlow = (end - ebda_len) & (~0xf);
+ return 0;
+ }
+
+ ebda = (grub_uint8_t *) UINT_TO_PTR ((*((grub_uint16_t *)0x40e)) << 4);
+ ebda_kb_len = *(grub_uint16_t *) ebda;
+ if (! ebda || ebda_kb_len > 16)
+ ebda_kb_len = 0;
+ ebda_len = (ebda_kb_len + 1) << 10;
+
+ /* FIXME: use low-memory mm allocation once it's available. */
+ grub_mmap_iterate (find_hook);
+ targetebda = (grub_uint8_t *) UINT_TO_PTR (highestlow);
+ grub_dprintf ("acpi", "creating ebda @%llx\n",
+ (unsigned long long) highestlow);
+ if (! highestlow)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't find space for the new EBDA");
+
+ mmapregion = grub_mmap_register (PTR_TO_UINT64 (targetebda), 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, "RSD PTR ", 8) == 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 *) ((((long) target - 1) | 0xf) + 1);
+ 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, "RSD PTR ", 8) == 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 *) ((((long) target - 1) | 0xf) + 1);
+ 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 *) ((((long) target - 1) | 0xf) + 1);
+ 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 *) ((((long) target - 1) | 0xf) + 1);
+ 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, "RSD PTR ", 8) == 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)) = ((long)targetebda) >> 4;
+ grub_dprintf ("acpi", "EBDA switched\n");
+
+ return GRUB_ERR_NONE;
+}
+
+/* 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 = PTR_TO_UINT32 (table_dsdt);
+ fadt->facs_addr = facs_addr;
+
+ /* Does a revision 2 exist at all? */
+ if (fadt->hdr.revision >= 3)
+ {
+ fadt->dsdt_xaddr = PTR_TO_UINT64 (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) + 4 * 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) + 4 * 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++) = PTR_TO_UINT32 (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), "RSD PTR ",
+ sizeof (rsdpv1_new->signature));
+ grub_memcpy (&(rsdpv1_new->oemid), root_oemid, sizeof (rsdpv1_new->oemid));
+ rsdpv1_new->revision = 0;
+ rsdpv1_new->rsdt_addr = PTR_TO_UINT32 (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) + 8 * numoftables;
+
+ xsdt_entry = (grub_uint64_t *)(xsdt + 1);
+ for (cur = acpi_tables; cur; cur = cur->next)
+ *(xsdt_entry++) = PTR_TO_UINT64 (cur->addr);
+ grub_memcpy (&(xsdt->signature), "XSDT", 4);
+ xsdt->length = sizeof (struct grub_acpi_table_header) + 8 * 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), "RSD PTR ",
+ 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 = PTR_TO_UINT32 (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 = PTR_TO_UINT64 (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;
+ grub_err_t err;
+ 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 ();
+
+ 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 *) UINT_TO_PTR (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 *) UINT_TO_PTR (*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 *)
+ UINT_TO_PTR (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_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't allocate table");
+ }
+ 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_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't allocate table structure");
+ }
+ table->size = curtable->length;
+ table->addr = grub_malloc (table->size);
+ playground_size += table->size;
+ if (! table->addr)
+ {
+ free_tables ();
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't allocate table");
+ }
+ 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]);
+ if (! file)
+ {
+ free_tables ();
+ return grub_error (GRUB_ERR_BAD_OS, "couldn't open file %s", args[i]);
+ }
+
+ 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, "file %s is too small", args[i]);
+ }
+
+ buf = (char *) grub_malloc (size);
+ if (! buf)
+ {
+ grub_file_close (file);
+ free_tables ();
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't read file %s", args[i]);
+ }
+
+ if (grub_file_read (file, buf, size) != (int) size)
+ {
+ grub_file_close (file);
+ free_tables ();
+ return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[i]);
+ }
+ 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_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't allocate table structure");
+ }
+
+ 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) + 4 * numoftables;
+ /* RSDPv1. */
+ playground_size += sizeof (struct grub_acpi_rsdp_v10);
+ /* XSDT. */
+ playground_size += sizeof (struct grub_acpi_table_header) + 8 * 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 (! state[9].set && (err = grub_acpi_create_ebda ()))
+ {
+ rsdpv1_new = 0;
+ rsdpv2_new = 0;
+ grub_mmap_free_and_unregister (mmapregion);
+ return err;
+ }
+
+#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;
+
+ grub_efi_system_table->boot_services->install_configuration_table
+ (&acpi20, grub_acpi_get_rsdpv2 ());
+ 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 ("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..9a4cda5
--- /dev/null
+++ b/grub-core/commands/acpihalt.c
@@ -0,0 +1,332 @@
+/*
+ * 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>
+
+#define grub_dprintf(cond, args...) printf ( args )
+#define grub_printf printf
+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/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:
+ 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;
+ 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_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_OPERATION_REGION:
+ ptr++;
+ ptr += skip_name_string (ptr, end);
+ ptr++;
+ ptr += add = skip_data_ref_object (ptr, end);
+ if (!add)
+ return 0;
+ ptr += add = skip_data_ref_object (ptr, end);
+ if (!add)
+ return 0;
+ break;
+ case GRUB_ACPI_EXTOPCODE_FIELD_OP:
+ case GRUB_ACPI_EXTOPCODE_INDEX_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 *end)
+{
+ grub_uint8_t *ptr, *prev = table;
+ int sleep_type = -1;
+
+ 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_NAME:
+ ptr++;
+ if (memcmp (ptr, "_S5_", 4) == 0 || 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:
+ sleep_type = 0;
+ break;
+ case GRUB_ACPI_OPCODE_ONE:
+ sleep_type = 1;
+ break;
+ case GRUB_ACPI_OPCODE_BYTE_CONST:
+ sleep_type = ptr2[1];
+ break;
+ 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_SCOPE:
+ case GRUB_ACPI_OPCODE_IF:
+ case GRUB_ACPI_OPCODE_METHOD:
+ {
+ ptr++;
+ ptr += decode_length (ptr, 0);
+ break;
+ }
+ }
+ }
+
+ grub_dprintf ("acpi", "TYP = %d\n", sleep_type);
+ return sleep_type;
+}
+
+#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 = 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 ("Couldn't malloc buffer\n");
+ fclose (f);
+ return 2;
+ }
+ if (fread (buf, 1, len, f) != len)
+ {
+ printf ("Read failed\n");
+ free (buf);
+ fclose (f);
+ return 2;
+ }
+
+ printf ("Sleep type = %d\n", get_sleep_type (buf, buf + len));
+ 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;
+
+ 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)
+ {
+ grub_uint32_t port;
+ 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;
+ int sleep_type = -1;
+
+ port = fadt->pm1a;
+
+ grub_dprintf ("acpi", "PM1a port=%x\n", port);
+
+ if (grub_memcmp (dsdt->signature, "DSDT",
+ sizeof (dsdt->signature)) != 0)
+ break;
+
+ sleep_type = get_sleep_type ((grub_uint8_t *) dsdt,
+ (grub_uint8_t *) dsdt + dsdt->length);
+
+ if (sleep_type < 0 || sleep_type >= 8)
+ break;
+
+ grub_dprintf ("acpi", "SLP_TYP = %d, port = 0x%x\n",
+ sleep_type, port);
+
+ grub_outw (GRUB_ACPI_SLP_EN
+ | (sleep_type << GRUB_ACPI_SLP_TYP_OFFSET), port & 0xffff);
+ }
+ }
+
+ grub_millisleep (1500);
+
+ grub_printf ("ACPI shutdown failed\n");
+}
+#endif
diff --git a/grub-core/commands/blocklist.c b/grub-core/commands/blocklist.c
new file mode 100644
index 0000000..5eb12e4
--- /dev/null
+++ b/grub-core/commands/blocklist.c
@@ -0,0 +1,122 @@
+/* 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+");
+
+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];
+ unsigned long start_sector = 0;
+ unsigned num_sectors = 0;
+ int num_entries = 0;
+ grub_disk_addr_t part_start = 0;
+ auto void NESTED_FUNC_ATTR read_blocklist (grub_disk_addr_t sector, unsigned offset,
+ unsigned length);
+ auto void NESTED_FUNC_ATTR print_blocklist (grub_disk_addr_t sector, unsigned num,
+ unsigned offset, unsigned length);
+
+ void NESTED_FUNC_ATTR read_blocklist (grub_disk_addr_t sector, unsigned offset,
+ unsigned length)
+ {
+ if (num_sectors > 0)
+ {
+ if (start_sector + num_sectors == sector
+ && offset == 0 && length == GRUB_DISK_SECTOR_SIZE)
+ {
+ num_sectors++;
+ return;
+ }
+
+ print_blocklist (start_sector, num_sectors, 0, 0);
+ num_sectors = 0;
+ }
+
+ if (offset == 0 && length == GRUB_DISK_SECTOR_SIZE)
+ {
+ start_sector = sector;
+ num_sectors++;
+ }
+ else
+ print_blocklist (sector, 0, offset, length);
+ }
+
+ void NESTED_FUNC_ATTR print_blocklist (grub_disk_addr_t sector, unsigned num,
+ unsigned offset, unsigned length)
+ {
+ if (num_entries++)
+ grub_printf (",");
+
+ grub_printf ("%llu", (unsigned long long) (sector - part_start));
+ if (num > 0)
+ grub_printf ("+%u", num);
+ if (offset != 0 || length != 0)
+ grub_printf ("[%u-%u]", offset, offset + length);
+ }
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
+
+ grub_file_filter_disable_compression ();
+ file = grub_file_open (args[0]);
+ if (! file)
+ return grub_errno;
+
+ if (! file->device->disk)
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ "this command is available only for disk devices");
+
+ part_start = grub_partition_get_start (file->device->disk->partition);
+
+ file->read_hook = read_blocklist;
+
+ while (grub_file_read (file, buf, sizeof (buf)) > 0)
+ ;
+
+ if (num_sectors > 0)
+ print_blocklist (start_sector, num_sectors, 0, 0);
+
+ 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..7714011
--- /dev/null
+++ b/grub-core/commands/boot.c
@@ -0,0 +1,198 @@
+/* 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_noreturn;
+
+struct grub_preboot_t
+{
+ grub_err_t (*preboot_func) (int);
+ grub_err_t (*preboot_rest_func) (void);
+ grub_loader_preboot_hook_prio_t prio;
+ struct grub_preboot_t *next;
+ struct grub_preboot_t *prev;
+};
+
+static int grub_loader_loaded;
+static struct grub_preboot_t *preboots_head = 0,
+ *preboots_tail = 0;
+
+int
+grub_loader_is_loaded (void)
+{
+ return grub_loader_loaded;
+}
+
+/* Register a preboot hook. */
+void *
+grub_loader_register_preboot_hook (grub_err_t (*preboot_func) (int noreturn),
+ grub_err_t (*preboot_rest_func) (void),
+ grub_loader_preboot_hook_prio_t prio)
+{
+ struct grub_preboot_t *cur, *new_preboot;
+
+ if (! preboot_func && ! preboot_rest_func)
+ return 0;
+
+ new_preboot = (struct grub_preboot_t *)
+ grub_malloc (sizeof (struct grub_preboot_t));
+ if (! new_preboot)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, "hook not added");
+ 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 (void *hnd)
+{
+ struct grub_preboot_t *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 noreturn)
+{
+ if (grub_loader_loaded && grub_loader_unload_func)
+ grub_loader_unload_func ();
+
+ grub_loader_boot_func = boot;
+ grub_loader_unload_func = unload;
+ grub_loader_noreturn = noreturn;
+
+ 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_t *cur;
+
+ if (! grub_loader_loaded)
+ return grub_error (GRUB_ERR_NO_KERNEL, "no loaded kernel");
+
+ if (grub_loader_noreturn)
+ grub_machine_fini ();
+
+ for (cur = preboots_head; cur; cur = cur->next)
+ {
+ err = cur->preboot_func (grub_loader_noreturn);
+ 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/cat.c b/grub-core/commands/cat.c
new file mode 100644
index 0000000..9be6cbc
--- /dev/null
+++ b/grub-core/commands/cat.c
@@ -0,0 +1,104 @@
+/* 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>
+
+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;
+ char buf[GRUB_DISK_SECTOR_SIZE];
+ grub_ssize_t size;
+ int key = 0;
+
+ if (state[0].set)
+ dos = 1;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
+
+ file = grub_file_open (args[0]);
+ 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++)
+ {
+ unsigned char c = buf[i];
+
+ if ((grub_isprint (c) || grub_isspace (c)) && c != '\r')
+ grub_printf ("%c", c);
+ else if (dos && c == '\r' && i + 1 < size && buf[i + 1] == '\n')
+ {
+ grub_printf ("\n");
+ i++;
+ }
+ else
+ {
+ grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
+ grub_printf ("<%x>", (int) c);
+ grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
+ }
+ }
+
+ while (grub_checkkey () >= 0 &&
+ (key = grub_getkey ()) != GRUB_TERM_ESC)
+ ;
+ }
+
+ 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..0222927
--- /dev/null
+++ b/grub-core/commands/cmp.c
@@ -0,0 +1,120 @@
+/* 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, "two arguments required");
+
+ grub_printf ("Compare file `%s' with `%s':\n", args[0],
+ args[1]);
+
+ file1 = grub_file_open (args[0]);
+ file2 = grub_file_open (args[1]);
+ if (! file1 || ! file2)
+ goto cleanup;
+
+ if (grub_file_size (file1) != grub_file_size (file2))
+ grub_printf ("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 ("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);
+
+ grub_printf ("The files are identical.\n");
+ }
+
+cleanup:
+
+ if (buf1)
+ grub_free (buf1);
+ if (buf2)
+ 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..124a09a
--- /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, "file name required");
+
+ 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 menuentries.")
+ );
+
+ cmd_extractor_configfile =
+ grub_register_command ("extract_entries_configfile", grub_cmd_source,
+ N_("FILE"),
+ N_("Load another config file without changing context but take only menuentries.")
+ );
+
+ 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..d271620
--- /dev/null
+++ b/grub-core/commands/date.c
@@ -0,0 +1,148 @@
+/* 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++)
+ {
+ char *p, 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_("Command to 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/acpi.c b/grub-core/commands/efi/acpi.c
new file mode 100644
index 0000000..93a560d
--- /dev/null
+++ b/grub-core/commands/efi/acpi.c
@@ -0,0 +1,59 @@
+/* acpi.c - get 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/acpi.h>
+#include <grub/misc.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/api.h>
+
+struct grub_acpi_rsdp_v10 *
+grub_machine_acpi_get_rsdpv1 (void)
+{
+ unsigned i;
+ static grub_efi_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID;
+
+ for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
+ {
+ grub_efi_guid_t *guid =
+ &grub_efi_system_table->configuration_table[i].vendor_guid;
+
+ if (! grub_memcmp (guid, &acpi_guid, sizeof (grub_efi_guid_t)))
+ return (struct grub_acpi_rsdp_v10 *)
+ grub_efi_system_table->configuration_table[i].vendor_table;
+ }
+ return 0;
+}
+
+struct grub_acpi_rsdp_v20 *
+grub_machine_acpi_get_rsdpv2 (void)
+{
+ unsigned i;
+ static grub_efi_guid_t acpi20_guid = GRUB_EFI_ACPI_20_TABLE_GUID;
+
+ for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
+ {
+ grub_efi_guid_t *guid =
+ &grub_efi_system_table->configuration_table[i].vendor_guid;
+
+ if (! grub_memcmp (guid, &acpi20_guid, sizeof (grub_efi_guid_t)))
+ return (struct grub_acpi_rsdp_v20 *)
+ grub_efi_system_table->configuration_table[i].vendor_table;
+ }
+ return 0;
+}
diff --git a/grub-core/commands/efi/fixvideo.c b/grub-core/commands/efi/fixvideo.c
new file mode 100644
index 0000000..c53e47d
--- /dev/null
+++ b/grub-core/commands/efi/fixvideo.c
@@ -0,0 +1,112 @@
+/* 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>
+
+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 NESTED_FUNC_ATTR
+scan_card (grub_pci_device_t dev, grub_pci_id_t pciid)
+{
+ 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_target_addr_t base;
+
+ grub_printf ("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_printf ("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_printf ("Old value don't match\n");
+ else
+ {
+ *((volatile grub_uint32_t *) base) = 0;
+ if (*((volatile grub_uint32_t *) base))
+ grub_printf ("Set MMIO fails\n");
+ }
+ }
+
+ return 1;
+ }
+ p++;
+ }
+
+ grub_printf ("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);
+ 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..1383112
--- /dev/null
+++ b/grub-core/commands/efi/loadbios.c
@@ -0,0 +1,220 @@
+/* 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_printf ("ROM image is present.\n");
+ 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_printf ("Can\'t enable ROM area.\n");
+ 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_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, "no ROM image specified");
+
+ if (argc > 1)
+ {
+ file = grub_file_open (argv[1]);
+ 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]);
+ 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 ("fakebios", grub_cmd_fakebios,
+ 0, N_("Fake BIOS."));
+
+ cmd_loadbios = grub_register_command ("loadbios", grub_cmd_loadbios,
+ "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/lsefimmap.c b/grub-core/commands/efi/lsefimmap.c
new file mode 100644
index 0000000..215b45b
--- /dev/null
+++ b/grub-core/commands/efi/lsefimmap.c
@@ -0,0 +1,145 @@
+/* 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"
+ };
+ 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;
+ size <<= (12 - 10);
+ if (size < 1024)
+ grub_printf (" %4" PRIuGRUB_UINT64_T "KB", size);
+ else
+ {
+ size /= 1024;
+ if (size < 1024)
+ grub_printf (" %4" PRIuGRUB_UINT64_T "MB", size);
+ else
+ {
+ size /= 1024;
+ grub_printf (" %4" PRIuGRUB_UINT64_T "GB", size);
+ }
+ }
+
+ 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");
+
+ 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..b235925
--- /dev/null
+++ b/grub-core/commands/efi/lsefisystab.c
@@ -0,0 +1,110 @@
+/* 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_SAL_TABLE_GUID, "SAL"},
+ { GRUB_EFI_SMBIOS_TABLE_GUID, "SMBIOS"},
+ { GRUB_EFI_MPS_TABLE_GUID, "MPS"},
+ { GRUB_EFI_HCDP_TABLE_GUID, "HCDP"}
+ };
+
+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 ("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++);
+ vendor = grub_malloc (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 ("%ld tables:\n", 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..fa8005b
--- /dev/null
+++ b/grub-core/commands/efi/lssal.c
@@ -0,0 +1,165 @@
+/* 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;
+
+ 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);
+ while (len > 0)
+ {
+ 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;
+ 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_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_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/extcmd.c b/grub-core/commands/extcmd.c
new file mode 100644
index 0000000..69574e2
--- /dev/null
+++ b/grub-core/commands/extcmd.c
@@ -0,0 +1,118 @@
+/* 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/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);
+}
+
+void
+grub_unregister_extcmd (grub_extcmd_t ext)
+{
+ grub_unregister_command (ext->cmd);
+ grub_free (ext);
+}
diff --git a/grub-core/commands/gptsync.c b/grub-core/commands/gptsync.c
new file mode 100644
index 0000000..e92dc20
--- /dev/null
+++ b/grub-core/commands/gptsync.c
@@ -0,0 +1,258 @@
+/* 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 (int lba, grub_uint8_t *cl, grub_uint8_t *ch,
+ grub_uint8_t *dh)
+{
+ int cylinder, head, sector;
+ int 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;
+
+ 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 (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. */
+ if (mbr.entries[0].type != GRUB_PC_PARTITION_TYPE_GPT_DISK)
+ {
+ grub_device_close (dev);
+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
+ }
+
+ int i;
+ 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, "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 (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 (GRUB_PC_PARTITION_SIGNATURE);
+
+ if (grub_disk_write (dev->disk, 0, 0, sizeof (mbr), &mbr))
+ {
+ grub_device_close (dev);
+ return grub_errno;
+ }
+
+ grub_printf ("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]]] ..."),
+ 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..317f775
--- /dev/null
+++ b/grub-core/commands/halt.c
@@ -0,0 +1,48 @@
+/* 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
+grub_cmd_halt (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ grub_halt ();
+ return 0;
+}
+
+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..6825d48
--- /dev/null
+++ b/grub-core/commands/hashsum.c
@@ -0,0 +1,300 @@
+/*
+ * 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 hash list file."), N_("FILE"), ARG_TYPE_STRING},
+ {"prefix", 'p', 0, N_("Base directory for hash list."), N_("DIRECTORY"),
+ 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)
+{
+ grub_uint8_t context[hash->contextsize];
+ grub_uint8_t readbuf[4096];
+
+ grub_memset (context, 0, sizeof (context));
+ hash->init (context);
+ while (1)
+ {
+ grub_ssize_t r;
+ r = grub_file_read (file, readbuf, sizeof (readbuf));
+ if (r < 0)
+ return grub_errno;
+ if (r == 0)
+ break;
+ hash->write (context, readbuf, r);
+ }
+ hash->final (context);
+ grub_memcpy (result, hash->read (context), hash->mdlen);
+
+ return GRUB_ERR_NONE;
+}
+
+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[hash->mdlen];
+ grub_uint8_t actual[hash->mdlen];
+ grub_err_t err;
+ unsigned i;
+ unsigned unread = 0, mismatch = 0;
+
+ hashlist = grub_file_open (hashfilename);
+ if (!hashlist)
+ return grub_errno;
+
+ while (grub_free (buf), (buf = grub_file_getline (hashlist)))
+ {
+ const char *p = buf;
+ for (i = 0; i < hash->mdlen; i++)
+ {
+ int high, low;
+ high = hextoval (*p++);
+ low = hextoval (*p++);
+ if (high < 0 || low < 0)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list");
+ expected[i] = (high << 4) | low;
+ }
+ if (*p++ != ' ' || *p++ != ' ')
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list");
+ if (prefix)
+ {
+ char *filename;
+
+ filename = grub_xasprintf ("%s/%s", prefix, p);
+ if (!filename)
+ return grub_errno;
+ if (!uncompress)
+ grub_file_filter_disable_compression ();
+ file = grub_file_open (filename);
+ grub_free (filename);
+ }
+ else
+ {
+ if (!uncompress)
+ grub_file_filter_disable_compression ();
+ file = grub_file_open (p);
+ }
+ 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 ("%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 ("%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 ("%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 (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_uint8_t result[hash->mdlen];
+ grub_file_t file;
+ grub_err_t err;
+ unsigned j;
+ if (!uncompress)
+ grub_file_filter_disable_compression ();
+ file = grub_file_open (args[i]);
+ 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", 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,
+ "hashsum -h HASH [-c FILE [-p PREFIX]] "
+ "[FILE1 [FILE2 ...]]",
+ 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..0c12b88
--- /dev/null
+++ b/grub-core/commands/hdparm.c
@@ -0,0 +1,422 @@
+/* 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/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_("Check 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_("Check 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_("Dump 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_disk_t disk, 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[GRUB_ATA_REG_CMD] = cmd;
+ apt.taskfile[GRUB_ATA_REG_FEATURES] = features;
+ apt.taskfile[GRUB_ATA_REG_SECTORS] = sectors;
+ apt.buffer = buffer;
+ apt.size = size;
+
+ if (grub_disk_ata_pass_through (disk, &apt))
+ return grub_errno;
+
+ return GRUB_ERR_NONE;
+}
+
+static int
+grub_hdparm_do_check_powermode_cmd (grub_disk_t disk)
+{
+ struct grub_disk_ata_pass_through_parms apt;
+ grub_memset (&apt, 0, sizeof (apt));
+
+ apt.taskfile[GRUB_ATA_REG_CMD] = GRUB_ATA_CMD_CHECK_POWER_MODE;
+
+ if (grub_disk_ata_pass_through (disk, &apt))
+ return -1;
+
+ return apt.taskfile[GRUB_ATA_REG_SECTORS];
+}
+
+static int
+grub_hdparm_do_smart_cmd (grub_disk_t disk, grub_uint8_t features)
+{
+ struct grub_disk_ata_pass_through_parms apt;
+ grub_memset (&apt, 0, sizeof (apt));
+
+ apt.taskfile[GRUB_ATA_REG_CMD] = GRUB_ATA_CMD_SMART;
+ apt.taskfile[GRUB_ATA_REG_FEATURES] = features;
+ apt.taskfile[GRUB_ATA_REG_LBAMID] = 0x4f;
+ apt.taskfile[GRUB_ATA_REG_LBAHIGH] = 0xc2;
+
+ if (grub_disk_ata_pass_through (disk, &apt))
+ return -1;
+
+ if (features == GRUB_ATA_FEAT_SMART_STATUS)
+ {
+ if ( apt.taskfile[GRUB_ATA_REG_LBAMID] == 0x4f
+ && apt.taskfile[GRUB_ATA_REG_LBAHIGH] == 0xc2)
+ return 0; /* Good SMART status. */
+ else if ( apt.taskfile[GRUB_ATA_REG_LBAMID] == 0xf4
+ && apt.taskfile[GRUB_ATA_REG_LBAHIGH] == 0x2c)
+ return 1; /* Bad SMART status. */
+ else
+ return -1;
+ }
+ return 0;
+}
+
+static grub_err_t
+grub_hdparm_simple_cmd (const char * msg,
+ grub_disk_t disk, grub_uint8_t cmd)
+{
+ if (! quiet && msg)
+ grub_printf ("%s", msg);
+
+ grub_err_t err = grub_hdparm_do_ata_cmd (disk, 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_disk_t disk, 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 (disk, cmd, features, sectors,
+ NULL, 0);
+
+ if (! quiet && msg)
+ grub_printf ("%s\n", ! err ? "" : ": not supported");
+ return err;
+}
+
+static const char *
+le16_to_char (char *dest, const grub_uint16_t * src16, unsigned bytes)
+{
+ grub_uint16_t * dest16 = (grub_uint16_t *) dest;
+ unsigned i;
+ for (i = 0; i < bytes / 2; i++)
+ dest16[i] = grub_be_to_cpu16 (src16[i]);
+ return dest;
+}
+
+static void
+grub_hdparm_print_identify (const char * idbuf)
+{
+ const grub_uint16_t * idw = (const grub_uint16_t *) idbuf;
+
+ /* Print identity strings. */
+ char tmp[40];
+ 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) // state????
+{
+ struct grub_arg_list *state = ctxt->state;
+
+ /* Check command line. */
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing device name argument");
+
+ grub_size_t len = grub_strlen (args[0]);
+ if (! (args[0][0] == '(' && args[0][len - 1] == ')'))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "argument is not a device name");
+ args[0][len - 1] = 0;
+
+ if (! grub_disk_ata_pass_through)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "ATA pass through not available");
+
+ 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 (&args[0][1]);
+ if (! disk)
+ return grub_errno;
+
+ if (disk->partition)
+ {
+ grub_disk_close (disk);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "partition not allowed");
+ }
+
+ /* Change settings. */
+ if (aam >= 0)
+ grub_hdparm_set_val_cmd ("Automatic Acoustic Management", (aam ? aam : -1),
+ disk, GRUB_ATA_CMD_SET_FEATURES, (aam ? 0x42 : 0xc2), aam);
+
+ if (apm >= 0)
+ grub_hdparm_set_val_cmd ("Advanced Power Management",
+ (apm != 255 ? apm : -1), disk, 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, disk, 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 (disk, (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", disk,
+ GRUB_ATA_CMD_SECURITY_FREEZE_LOCK);
+
+ /* Print/dump IDENTIFY. */
+ if (ident || dumpid)
+ {
+ char buf[GRUB_DISK_SECTOR_SIZE];
+ if (grub_hdparm_do_ata_cmd (disk, 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, buf, sizeof (buf));
+ }
+ }
+
+ /* Check power mode. */
+ if (power)
+ {
+ grub_printf ("Disk power mode is: ");
+ int mode = grub_hdparm_do_check_powermode_cmd (disk);
+ 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 (disk, 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", disk,
+ GRUB_ATA_CMD_STANDBY_IMMEDIATE);
+
+ if (sleep_now)
+ grub_hdparm_simple_cmd ("Set disk to sleep mode", disk,
+ 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 ("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..82f3200
--- /dev/null
+++ b/grub-core/commands/help.c
@@ -0,0 +1,143 @@
+/* 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_PRIO_LIST_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;
+
+ for (i = 0; i < argc; i++)
+ {
+ currarg = args[i];
+ FOR_COMMANDS(cmd)
+ {
+ if (cmd->prio & GRUB_PRIO_LIST_FLAG_ACTIVE)
+ {
+ if (! grub_strncmp (cmd->name, currarg, grub_strlen (currarg)))
+ {
+ 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..9ba8359
--- /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, "file name required");
+
+ 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]);
+ 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_("Dump the contents of a file or memory."),
+ options);
+}
+
+GRUB_MOD_FINI (hexdump)
+{
+ grub_unregister_extcmd (cmd);
+}
diff --git a/grub-core/commands/i386/cmostest.c b/grub-core/commands/i386/cmostest.c
new file mode 100644
index 0000000..c79bd03
--- /dev/null
+++ b/grub-core/commands/i386/cmostest.c
@@ -0,0 +1,92 @@
+/*
+ * 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>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+parse_args (int argc, char *argv[], int *byte, int *bit)
+{
+ 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, bit;
+ grub_err_t err;
+
+ err = parse_args (argc, argv, &byte, &bit);
+ if (err)
+ return err;
+
+ if (grub_cmos_read (byte) & (1 << bit))
+ return GRUB_ERR_NONE;
+
+ return grub_error (GRUB_ERR_TEST_FAILURE, "false");
+}
+
+static grub_err_t
+grub_cmd_cmosclean (struct grub_command *cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ int byte, bit;
+ grub_err_t err;
+
+ err = parse_args (argc, argv, &byte, &bit);
+ if (err)
+ return err;
+
+ grub_cmos_write (byte, grub_cmos_read (byte) & (~(1 << bit)));
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd, cmd_clean;
+
+
+GRUB_MOD_INIT(cmostest)
+{
+ cmd = grub_register_command ("cmostest", grub_cmd_cmostest,
+ "cmostest BYTE:BIT",
+ "Test bit at BYTE:BIT in CMOS.");
+ cmd_clean = grub_register_command ("cmosclean", grub_cmd_cmosclean,
+ "cmosclean BYTE:BIT",
+ "Clean bit at BYTE:BIT in CMOS.");
+}
+
+GRUB_MOD_FINI(cmostest)
+{
+ grub_unregister_command (cmd);
+ grub_unregister_command (cmd_clean);
+}
diff --git a/grub-core/commands/i386/cpuid.c b/grub-core/commands/i386/cpuid.c
new file mode 100644
index 0000000..6a771ba
--- /dev/null
+++ b/grub-core/commands/i386/cpuid.c
@@ -0,0 +1,100 @@
+/* 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+");
+
+#define cpuid(num,a,b,c,d) \
+ asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" \
+ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
+ : "0" (num))
+
+static const struct grub_arg_option options[] =
+ {
+ {"long-mode", 'l', 0, N_("Check for long mode flag (default)."), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+#define bit_LM (1 << 29)
+
+unsigned char grub_cpuid_has_longmode = 0;
+
+static grub_err_t
+grub_cmd_cpuid (grub_extcmd_context_t ctxt __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ return grub_cpuid_has_longmode ? GRUB_ERR_NONE
+ : grub_error (GRUB_ERR_TEST_FAILURE, "false");
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(cpuid)
+{
+#ifdef __x86_64__
+ /* grub-emu */
+ grub_cpuid_has_longmode = 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. */
+ cpuid (0, eax, ebx, ecx, edx);
+ /* We only look at the first four characters. */
+ max_level = eax;
+ if (max_level == 0)
+ goto done;
+
+ cpuid (0x80000000, eax, ebx, ecx, edx);
+ ext_level = eax;
+ if (ext_level < 0x80000000)
+ goto done;
+
+ 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/acpi.c b/grub-core/commands/i386/pc/acpi.c
new file mode 100644
index 0000000..88e4f55
--- /dev/null
+++ b/grub-core/commands/i386/pc/acpi.c
@@ -0,0 +1,81 @@
+/* acpi.c - get 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/acpi.h>
+#include <grub/misc.h>
+
+struct grub_acpi_rsdp_v10 *
+grub_machine_acpi_get_rsdpv1 (void)
+{
+ int ebda_len;
+ grub_uint8_t *ebda, *ptr;
+
+ grub_dprintf ("acpi", "Looking for RSDP. Scanning EBDA\n");
+ ebda = (grub_uint8_t *) ((* ((grub_uint16_t *) 0x40e)) << 4);
+ ebda_len = * (grub_uint16_t *) ebda;
+ if (! ebda_len)
+ return 0;
+ for (ptr = ebda; ptr < ebda + 0x400; ptr += 16)
+ if (grub_memcmp (ptr, "RSD PTR ", 8) == 0
+ && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
+ && ((struct grub_acpi_rsdp_v10 *) ptr)->revision == 0)
+ return (struct grub_acpi_rsdp_v10 *) ptr;
+
+ grub_dprintf ("acpi", "Looking for RSDP. Scanning BIOS\n");
+ for (ptr = (grub_uint8_t *) 0xe0000; ptr < (grub_uint8_t *) 0x100000;
+ ptr += 16)
+ if (grub_memcmp (ptr, "RSD PTR ", 8) == 0
+ && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
+ && ((struct grub_acpi_rsdp_v10 *) ptr)->revision == 0)
+ return (struct grub_acpi_rsdp_v10 *) ptr;
+ return 0;
+}
+
+struct grub_acpi_rsdp_v20 *
+grub_machine_acpi_get_rsdpv2 (void)
+{
+ int ebda_len;
+ grub_uint8_t *ebda, *ptr;
+
+ grub_dprintf ("acpi", "Looking for RSDP. Scanning EBDA\n");
+ ebda = (grub_uint8_t *) ((* ((grub_uint16_t *) 0x40e)) << 4);
+ ebda_len = * (grub_uint16_t *) ebda;
+ if (! ebda_len)
+ return 0;
+ for (ptr = ebda; ptr < ebda + 0x400; ptr += 16)
+ if (grub_memcmp (ptr, "RSD PTR ", 8) == 0
+ && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
+ && ((struct grub_acpi_rsdp_v10 *) ptr)->revision != 0
+ && ((struct grub_acpi_rsdp_v20 *) ptr)->length < 1024
+ && grub_byte_checksum (ptr, ((struct grub_acpi_rsdp_v20 *) ptr)->length)
+ == 0)
+ return (struct grub_acpi_rsdp_v20 *) ptr;
+
+ grub_dprintf ("acpi", "Looking for RSDP. Scanning BIOS\n");
+ for (ptr = (grub_uint8_t *) 0xe0000; ptr < (grub_uint8_t *) 0x100000;
+ ptr += 16)
+ if (grub_memcmp (ptr, "RSD PTR ", 8) == 0
+ && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
+ && ((struct grub_acpi_rsdp_v10 *) ptr)->revision != 0
+ && ((struct grub_acpi_rsdp_v20 *) ptr)->length < 1024
+ && grub_byte_checksum (ptr, ((struct grub_acpi_rsdp_v20 *) ptr)->length)
+ == 0)
+ return (struct grub_acpi_rsdp_v20 *) ptr;
+ return 0;
+}
diff --git a/grub-core/commands/i386/pc/drivemap.c b/grub-core/commands/i386/pc/drivemap.c
new file mode 100644
index 0000000..c9c8881
--- /dev/null
+++ b/grub-core/commands/i386/pc/drivemap.c
@@ -0,0 +1,422 @@
+/* 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 = UINT_TO_PTR (4 * 0x13);
+
+/* Remember to update enum opt_idxs accordingly. */
+static const struct grub_arg_option options[] = {
+ {"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 __attribute__ ((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_error (GRUB_ERR_OUT_OF_MEMORY,
+ "cannot allocate map entry, not enough memory");
+ 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_printf ("No drives have been remapped\n");
+ return GRUB_ERR_NONE;
+ }
+
+ grub_printf ("OS disk #num ------> GRUB/BIOS device\n");
+ 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, "two arguments required");
+
+ 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, total_size,
+ &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)
+{
+ 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..b460cd7
--- /dev/null
+++ b/grub-core/commands/i386/pc/drivemap_int13h.S
@@ -0,0 +1,110 @@
+/* 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
+ movw $INT13H_OFFSET(LOCAL (mapstart)), %bx
+
+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
+
+ lcall *%cs:INT13H_OFFSET (LOCAL (oldhandler))
+
+ 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
+
+ lcall *%cs:INT13H_OFFSET (LOCAL (oldhandler))
+
+ 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..e7c191d
--- /dev/null
+++ b/grub-core/commands/i386/pc/halt.c
@@ -0,0 +1,127 @@
+/* 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
+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
+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);
+ return 0;
+}
+
+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..17bcfd6
--- /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, "no APM found");
+
+ grub_printf ("Vesion %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..57980eb
--- /dev/null
+++ b/grub-core/commands/i386/pc/play.c
@@ -0,0 +1,275 @@
+/* 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/machine/time.h>
+#include <grub/cpu/io.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define BASE_TEMPO (60 * GRUB_TICKS_PER_SECOND)
+
+/* The speaker port. */
+#define SPEAKER 0x61
+
+/* If 0, follow state of SPEAKER_DATA bit, otherwise enable output
+ from timer 2. */
+#define SPEAKER_TMR2 0x01
+
+/* If SPEAKER_TMR2 is not set, this provides direct input into the
+ speaker. Otherwise, this enables or disables the output from the
+ timer. */
+#define SPEAKER_DATA 0x02
+
+/* The PIT channel value ports. You can write to and read from them.
+ Do not mess with timer 0 or 1. */
+#define PIT_COUNTER_0 0x40
+#define PIT_COUNTER_1 0x41
+#define PIT_COUNTER_2 0x42
+
+/* The frequency of the PIT clock. */
+#define PIT_FREQUENCY 0x1234dd
+
+/* The PIT control port. You can only write to it. Do not mess with
+ timer 0 or 1. */
+#define PIT_CTRL 0x43
+#define PIT_CTRL_SELECT_MASK 0xc0
+#define PIT_CTRL_SELECT_0 0x00
+#define PIT_CTRL_SELECT_1 0x40
+#define PIT_CTRL_SELECT_2 0x80
+
+/* Read and load control. */
+#define PIT_CTRL_READLOAD_MASK 0x30
+#define PIT_CTRL_COUNTER_LATCH 0x00 /* Hold timer value until read. */
+#define PIT_CTRL_READLOAD_LSB 0x10 /* Read/load the LSB. */
+#define PIT_CTRL_READLOAD_MSB 0x20 /* Read/load the MSB. */
+#define PIT_CTRL_READLOAD_WORD 0x30 /* Read/load the LSB then the MSB. */
+
+/* Mode control. */
+#define PIT_CTRL_MODE_MASK 0x0e
+
+/* Interrupt on terminal count. Setting the mode sets output to low.
+ When counter is set and terminated, output is set to high. */
+#define PIT_CTRL_INTR_ON_TERM 0x00
+
+/* Programmable one-shot. When loading counter, output is set to
+ high. When counter terminated, output is set to low. Can be
+ triggered again from that point on by setting the gate pin to
+ high. */
+#define PIT_CTRL_PROGR_ONE_SHOT 0x02
+
+/* Rate generator. Output is low for one period of the counter, and
+ high for the other. */
+#define PIT_CTRL_RATE_GEN 0x04
+
+/* Square wave generator. Output is low for one half of the period,
+ and high for the other half. */
+#define PIT_CTRL_SQUAREWAVE_GEN 0x06
+
+/* Software triggered strobe. Setting the mode sets output to high.
+ When counter is set and terminated, output is set to low. */
+#define PIT_CTRL_SOFTSTROBE 0x08
+
+/* Hardware triggered strobe. Like software triggered strobe, but
+ only starts the counter when the gate pin is set to high. */
+#define PIT_CTRL_HARDSTROBE 0x0a
+
+/* Count mode. */
+#define PIT_CTRL_COUNT_MASK 0x01
+#define PIT_CTRL_COUNT_BINARY 0x00 /* 16-bit binary counter. */
+#define PIT_CTRL_COUNT_BCD 0x01 /* 4-decade BCD counter. */
+
+#define T_REST ((grub_uint16_t) 0)
+#define T_FINE ((grub_uint16_t) -1)
+
+struct note
+{
+ grub_uint16_t pitch;
+ grub_uint16_t duration;
+};
+
+static void
+beep_off (void)
+{
+ unsigned char status;
+
+ status = grub_inb (SPEAKER);
+ grub_outb (status & ~(SPEAKER_TMR2 | SPEAKER_DATA), SPEAKER);
+}
+
+static void
+beep_on (grub_uint16_t pitch)
+{
+ unsigned char status;
+ unsigned int counter;
+
+ if (pitch < 20)
+ pitch = 20;
+ else if (pitch > 20000)
+ pitch = 20000;
+
+ counter = PIT_FREQUENCY / pitch;
+
+ /* Program timer 2. */
+ grub_outb (PIT_CTRL_SELECT_2 | PIT_CTRL_READLOAD_WORD
+ | PIT_CTRL_SQUAREWAVE_GEN | PIT_CTRL_COUNT_BINARY, PIT_CTRL);
+ grub_outb (counter & 0xff, PIT_COUNTER_2); /* LSB */
+ grub_outb ((counter >> 8) & 0xff, PIT_COUNTER_2); /* MSB */
+
+ /* Start speaker. */
+ status = grub_inb (SPEAKER);
+ grub_outb (status | SPEAKER_TMR2 | SPEAKER_DATA, SPEAKER);
+}
+
+/* Returns whether playing should continue. */
+static int
+play (unsigned tempo, struct note *note)
+{
+ unsigned int to;
+
+ if (note->pitch == T_FINE || grub_checkkey () >= 0)
+ return 1;
+
+ grub_dprintf ("play", "pitch = %d, duration = %d\n", note->pitch,
+ note->duration);
+
+ switch (note->pitch)
+ {
+ case T_REST:
+ beep_off ();
+ break;
+
+ default:
+ beep_on (note->pitch);
+ break;
+ }
+
+ to = grub_get_rtc () + BASE_TEMPO * note->duration / tempo;
+ while (((unsigned int) grub_get_rtc () <= to) && (grub_checkkey () < 0))
+ ;
+
+ 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, "file name or tempo and notes required");
+
+ if (argc == 1)
+ {
+ struct note buf;
+ grub_uint32_t tempo;
+ grub_file_t file;
+
+ file = grub_file_open (args[0]);
+
+ if (! file)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
+
+ if (grub_file_read (file, &tempo, sizeof (tempo)) != sizeof (tempo))
+ {
+ grub_file_close (file);
+ return grub_error (GRUB_ERR_FILE_READ_ERROR,
+ "file doesn't even contains a full tempo record");
+ }
+
+ 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
+ {
+ char *end;
+ unsigned tempo;
+ struct note note;
+ int i;
+
+ tempo = grub_strtoul (args[0], &end, 0);
+
+ if (*end)
+ /* Was not a number either, assume it was supposed to be a file name. */
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
+
+ grub_dprintf ("play","tempo = %d\n", tempo);
+
+ for (i = 1; i + 1 < argc; i += 2)
+ {
+ note.pitch = grub_strtoul (args[i], &end, 0);
+ if (*end)
+ {
+ grub_error (GRUB_ERR_BAD_NUMBER, "bogus pitch number");
+ break;
+ }
+
+ note.duration = grub_strtoul (args[i + 1], &end, 0);
+ if (*end)
+ {
+ grub_error (GRUB_ERR_BAD_NUMBER, "bogus duration number");
+ break;
+ }
+
+ if (play (tempo, &note))
+ break;
+ }
+ }
+
+ beep_off ();
+
+ while (grub_checkkey () > 0)
+ grub_getkey ();
+
+ 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/pxecmd.c b/grub-core/commands/i386/pc/pxecmd.c
new file mode 100644
index 0000000..dffa15a
--- /dev/null
+++ b/grub-core/commands/i386/pc/pxecmd.c
@@ -0,0 +1,54 @@
+/* pxe.c - command to control the pxe driver */
+/*
+ * 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/dl.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/machine/pxe.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+grub_cmd_pxe_unload (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ if (! grub_pxe_pxenv)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no pxe environment");
+
+ grub_pxe_unload ();
+
+ return 0;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(pxecmd)
+{
+ cmd = grub_register_command ("pxe_unload", grub_cmd_pxe_unload,
+ 0,
+ N_("Unload PXE environment."));
+}
+
+GRUB_MOD_FINI(pxecmd)
+{
+ 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..a55d17b
--- /dev/null
+++ b/grub-core/commands/i386/pc/sendkey.c
@@ -0,0 +1,385 @@
+/* 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>
+
+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, "set numlock mode", "[on|off]", ARG_TYPE_STRING},
+ {"caps", 'c', 0, "set capslock mode", "[on|off]", ARG_TYPE_STRING},
+ {"scroll", 's', 0, "set scrolllock mode", "[on|off]", ARG_TYPE_STRING},
+ {"insert", 0, 0, "set insert mode", "[on|off]", ARG_TYPE_STRING},
+ {"pause", 0, 0, "set pause mode", "[on|off]", ARG_TYPE_STRING},
+ {"left-shift", 0, 0, "press left shift", "[on|off]", ARG_TYPE_STRING},
+ {"right-shift", 0, 0, "press right shift", "[on|off]", ARG_TYPE_STRING},
+ {"sysrq", 0, 0, "press SysRq", "[on|off]", ARG_TYPE_STRING},
+ {"numkey", 0, 0, "press NumLock key", "[on|off]", ARG_TYPE_STRING},
+ {"capskey", 0, 0, "press CapsLock key", "[on|off]", ARG_TYPE_STRING},
+ {"scrollkey", 0, 0, "press ScrollLock key", "[on|off]", ARG_TYPE_STRING},
+ {"insertkey", 0, 0, "press Insert key", "[on|off]", ARG_TYPE_STRING},
+ {"left-alt", 0, 0, "press left alt", "[on|off]", ARG_TYPE_STRING},
+ {"right-alt", 0, 0, "press right alt", "[on|off]", ARG_TYPE_STRING},
+ {"left-ctrl", 0, 0, "press left ctrl", "[on|off]", ARG_TYPE_STRING},
+ {"right-ctrl", 0, 0, "press right ctrl", "[on|off]", ARG_TYPE_STRING},
+ {"no-led", 0, 0, "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
+{
+ char *unshifted_name; /* the name in unshifted state */
+ 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;
+}
+
+static grub_err_t
+grub_cmd_sendkey (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+
+ auto int find_key_code (char *key);
+ auto int find_ascii_code (char *key);
+
+ int find_key_code (char *key)
+ {
+ unsigned i;
+
+ for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); 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;
+ }
+
+ int find_ascii_code (char *key)
+ {
+ unsigned i;
+
+ for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); 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;
+ }
+
+ 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 < sizeof (simple_flag_offsets)
+ / sizeof (simple_flag_offsets[0]); i++)
+ grub_sendkey_set_simple_flag (simple_flag_offsets[i],
+ grub_sendkey_parse_op(state[i]));
+ }
+
+ /* Set noled. */
+ noled = (state[sizeof (simple_flag_offsets)
+ / sizeof (simple_flag_offsets[0])].set);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_extcmd_t cmd;
+static void *preboot_hook;
+
+GRUB_MOD_INIT (sendkey)
+{
+ cmd = grub_register_extcmd ("sendkey", grub_cmd_sendkey, 0,
+ "sendkey [KEYSTROKE1] [KEYSTROKE2] ...",
+ "Emulate a keystroke", 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/ieee1275/suspend.c b/grub-core/commands/ieee1275/suspend.c
new file mode 100644
index 0000000..de06895
--- /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_printf ("Run 'go' to resume GRUB.\n");
+ 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 Open Firmware 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..e7035b5
--- /dev/null
+++ b/grub-core/commands/iorw.c
@@ -0,0 +1,152 @@
+/* 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>
+
+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_target_addr_t addr;
+ grub_uint32_t value = 0;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of arguments");
+
+ 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_target_addr_t addr;
+ grub_uint32_t value;
+ grub_uint32_t mask = 0xffffffff;
+
+ if (argc != 2 && argc != 3)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of arguments");
+
+ 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 byte from PORT."), options);
+ cmd_read_word =
+ grub_register_extcmd ("inw", grub_cmd_read, 0,
+ N_("PORT"), N_("Read word from PORT."), options);
+ cmd_read_dword =
+ grub_register_extcmd ("inl", grub_cmd_read, 0,
+ N_("PORT"), N_("Read dword from PORT."), options);
+ cmd_write_byte =
+ grub_register_command ("outb", grub_cmd_write,
+ N_("PORT VALUE [MASK]"),
+ N_("Write byte VALUE to PORT."));
+ cmd_write_word =
+ grub_register_command ("outw", grub_cmd_write,
+ N_("PORT VALUE [MASK]"),
+ N_("Write word VALUE to PORT."));
+ cmd_write_dword =
+ grub_register_command ("outl", grub_cmd_write,
+ N_("ADDR VALUE [MASK]"),
+ N_("Write dword 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..6c5913a
--- /dev/null
+++ b/grub-core/commands/keylayouts.c
@@ -0,0 +1,299 @@
+/*
+ * 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', '\e', '\b', '\t', ' ', '-', '=', '[',
+ /* 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, '\e' | GRUB_TERM_SHIFT,
+ /* 0x2a */ '\b' | GRUB_TERM_SHIFT, '\t' | 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 (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);
+
+ 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, "No prefix set");
+ filename = grub_xasprintf ("%s/layouts/%s.gkb", prefix, argv[0]);
+ if (!filename)
+ return grub_errno;
+ }
+ else
+ filename = argv[0];
+
+ file = grub_file_open (filename);
+ if (! file)
+ goto fail;
+
+ if (grub_file_read (file, magic, sizeof (magic)) != sizeof (magic))
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "file is too short");
+ 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, "file is too short");
+ goto fail;
+ }
+
+ if (grub_le_to_cpu32 (version) != 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, "file is too short");
+ 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..f3a6699
--- /dev/null
+++ b/grub-core/commands/keystatus.c
@@ -0,0 +1,110 @@
+/* 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[] =
+ {
+ {"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 int
+grub_getkeystatus (void)
+{
+ int status = 0;
+ grub_term_input_t term;
+
+ if (grub_term_poll_usb)
+ grub_term_poll_usb ();
+
+ FOR_ACTIVE_TERM_INPUTS(term)
+ {
+ if (term->getkeystatus)
+ status |= term->getkeystatus (term);
+ }
+
+ return status;
+}
+
+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, "false");
+ else
+ nterms++;
+ if (!nterms)
+ return grub_error (GRUB_ERR_TEST_FAILURE, "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, "false");
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(keystatus)
+{
+ cmd = grub_register_extcmd ("keystatus", grub_cmd_keystatus, 0,
+ N_("[--shift] [--ctrl] [--alt]"),
+ 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..e68b331
--- /dev/null
+++ b/grub-core/commands/legacycfg.c
@@ -0,0 +1,820 @@
+/*
+ * 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>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+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 ("");
+
+ auto grub_err_t getline (char **line, int cont);
+ grub_err_t getline (char **line,
+ int cont __attribute__ ((unused)))
+ {
+ *line = 0;
+ return GRUB_ERR_NONE;
+ }
+
+ if (!suffix)
+ return grub_errno;
+
+ file = grub_file_open (filename);
+ if (! file)
+ return grub_errno;
+
+ menu = grub_env_get_menu ();
+ if (! menu)
+ {
+ menu = grub_zalloc (sizeof (*menu));
+ if (! menu)
+ 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);
+ 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;
+
+ t = suffix;
+ suffix = grub_realloc (suffix, grub_strlen (suffix)
+ + grub_strlen (newsuffix) + 1);
+ if (!suffix)
+ {
+ grub_free (t);
+ 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, NULL, NULL,
+ entrysrc, 0);
+ grub_free (args);
+ entrysrc[0] = 0;
+ grub_free (oldname);
+ }
+ }
+
+ if (parsed && !entryname)
+ {
+ grub_normal_parse_line (parsed, getline);
+ grub_print_error ();
+ grub_free (parsed);
+ parsed = NULL;
+ }
+ else if (parsed)
+ {
+ if (!entrysrc)
+ entrysrc = parsed;
+ else
+ {
+ char *t;
+
+ t = entrysrc;
+ entrysrc = grub_realloc (entrysrc, grub_strlen (entrysrc)
+ + grub_strlen (parsed) + 1);
+ if (!entrysrc)
+ {
+ grub_free (t);
+ 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);
+ return grub_errno;
+ }
+ args[0] = entryname;
+ grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, NULL, entrysrc, 0);
+ grub_free (args);
+ }
+
+ grub_normal_parse_line (suffix, getline);
+ 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, "file name required");
+
+ 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;
+
+ 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, "filename required");
+
+ cutargs = grub_malloc (sizeof (cutargs[0]) * (argc - 1));
+ 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)
+ {
+ cmd = grub_command_find ("linux16");
+ if (cmd)
+ {
+ if (!(cmd->func) (cmd, cutargc, cutargs))
+ {
+ kernel_type = LINUX;
+ return GRUB_ERR_NONE;
+ }
+ }
+ 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;
+ return GRUB_ERR_NONE;
+ }
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ {
+ int bsd_device = -1;
+ int bsd_slice = -1;
+ int bsd_part = -1;
+ {
+ grub_device_t dev;
+ 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->dev->id >= 0x80 && dev->disk->dev->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;
+ }
+ }
+
+ /* 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;
+ return GRUB_ERR_NONE;
+ }
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+ {
+ char **bsdargs;
+ int bsdargc;
+ char bsddevname[sizeof ("wdXXXXXXXXXXXXY")];
+ if (bsd_device == -1)
+ {
+ bsdargs = cutargs;
+ bsdargc = cutargc;
+ }
+ else
+ {
+ bsdargc = cutargc + 2;
+ bsdargs = grub_malloc (sizeof (bsdargs[0]) * bsdargc);
+ grub_memcpy (bsdargs, args, argc * sizeof (bsdargs[0]));
+ bsdargs[argc] = "-r";
+ 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;
+ return GRUB_ERR_NONE;
+ }
+ }
+ 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;
+ return GRUB_ERR_NONE;
+ }
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+ if (bsdargs != cutargs)
+ grub_free (bsdargs);
+ }
+ }
+ }
+ while (0);
+
+ return grub_error (GRUB_ERR_BAD_OS, "couldn't load file %s\n",
+ args[0]);
+}
+
+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)
+ {
+ cmd = grub_command_find ("initrd16");
+ if (!cmd)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "command initrd16 not found");
+
+ return cmd->func (cmd, argc, args);
+ }
+ if (kernel_type == MULTIBOOT)
+ {
+ cmd = grub_command_find ("module");
+ if (!cmd)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "command module not found");
+
+ return cmd->func (cmd, argc, args);
+ }
+
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "no kernel with module support is loaded in legacy way");
+}
+
+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, "command initrd16 not found");
+
+ return cmd->func (cmd, argc, args);
+ }
+ if (kernel_type == MULTIBOOT)
+ {
+ char **newargs;
+ grub_err_t err;
+ newargs = grub_malloc ((argc + 1) * sizeof (newargs[0]));
+ if (!newargs)
+ return grub_errno;
+ grub_memcpy (newargs + 1, args, argc * sizeof (newargs[0]));
+ newargs[0] = "--nounzip";
+ cmd = grub_command_find ("module");
+ if (!cmd)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "command module not found");
+
+ err = cmd->func (cmd, argc + 1, newargs);
+ grub_free (newargs);
+ return err;
+ }
+
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "no kernel with module support is loaded in legacy way");
+}
+
+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)
+{
+ int enteredlen = grub_strlen (entered);
+ unsigned char alt_result[MD5_HASHLEN];
+ unsigned char *digest;
+ grub_uint8_t ctx[GRUB_MD_MD5->contextsize];
+ int i;
+
+ 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);
+ 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++)
+ {
+ 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);
+ }
+
+ return (grub_crypto_memcmp (digest, pw->hash, MD5_HASHLEN) == 0);
+}
+
+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, "arguments 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);
+}
+
+static grub_err_t
+grub_cmd_legacy_check_password (struct grub_command *mycmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ struct legacy_md5_password *pw = NULL;
+ char entered[GRUB_AUTH_MAX_PASSLEN];
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "arguments expected");
+ grub_printf ("Enter password:");
+ if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN))
+ return GRUB_ACCESS_DENIED;
+
+ 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));
+
+ if (grub_crypto_memcmp (entered, correct, GRUB_AUTH_MAX_PASSLEN) != 0)
+ return GRUB_ACCESS_DENIED;
+ return GRUB_ERR_NONE;
+ }
+
+ pw = parse_legacy_md5 (argc, args);
+
+ if (!pw)
+ return GRUB_ACCESS_DENIED;
+
+ if (!check_password_md5_real (entered, pw))
+ 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"),
+ 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 menuentry 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..5d53a8e
--- /dev/null
+++ b/grub-core/commands/loadenv.c
@@ -0,0 +1,399 @@
+/* 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[] =
+ {
+ {"file", 'f', 0, N_("Specify filename."), 0, ARG_TYPE_PATHNAME},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static grub_file_t
+open_envblk_file (char *filename)
+{
+ grub_file_t file;
+
+ if (! filename)
+ {
+ char *prefix;
+
+ prefix = grub_env_get ("prefix");
+ if (prefix)
+ {
+ int len;
+
+ len = grub_strlen (prefix);
+ filename = grub_malloc (len + 1 + sizeof (GRUB_ENVBLK_DEFCFG));
+ if (! filename)
+ return 0;
+
+ grub_strcpy (filename, prefix);
+ filename[len] = '/';
+ grub_strcpy (filename + len + 1, GRUB_ENVBLK_DEFCFG);
+ grub_file_filter_disable_compression ();
+ file = grub_file_open (filename);
+ grub_free (filename);
+ return file;
+ }
+ else
+ {
+ grub_error (GRUB_ERR_FILE_NOT_FOUND, "prefix is not found");
+ return 0;
+ }
+ }
+
+ grub_file_filter_disable_compression ();
+ return grub_file_open (filename);
+}
+
+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)
+ {
+ if (grub_errno == GRUB_ERR_NONE)
+ grub_error (GRUB_ERR_FILE_READ_ERROR, "cannot read");
+ 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;
+}
+
+static grub_err_t
+grub_cmd_load_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;
+
+ auto int set_var (const char *name, const char *value);
+ int set_var (const char *name, const char *value)
+ {
+ grub_env_set (name, value);
+ return 0;
+ }
+
+ file = open_envblk_file ((state[0].set) ? state[0].arg : 0);
+ if (! file)
+ return grub_errno;
+
+ envblk = read_envblk_file (file);
+ if (! envblk)
+ goto fail;
+
+ grub_envblk_iterate (envblk, set_var);
+ grub_envblk_close (envblk);
+
+ fail:
+ grub_file_close (file);
+ return grub_errno;
+}
+
+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;
+
+ /* Print all variables in current context. */
+ auto int print_var (const char *name, const char *value);
+ int print_var (const char *name, const char *value)
+ {
+ grub_printf ("%s=%s\n", name, value);
+ return 0;
+ }
+
+ file = open_envblk_file ((state[0].set) ? state[0].arg : 0);
+ if (! file)
+ return grub_errno;
+
+ envblk = read_envblk_file (file);
+ if (! envblk)
+ goto fail;
+
+ grub_envblk_iterate (envblk, 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;
+ for (q = p->next; q; q = q->next)
+ {
+ /* Check if any pair of blocks overlap. */
+ if (p->sector == q->sector)
+ {
+ /* 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);
+ for (p = blocklists, index = 0; p; index += p->length, p = p->next)
+ {
+ char blockbuf[GRUB_DISK_SECTOR_SIZE];
+
+ 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;
+}
+
+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 blocklist *head = 0;
+ struct blocklist *tail = 0;
+
+ /* Store blocklists in a linked list. */
+ auto void NESTED_FUNC_ATTR read_hook (grub_disk_addr_t sector,
+ unsigned offset,
+ unsigned length);
+ void NESTED_FUNC_ATTR read_hook (grub_disk_addr_t sector,
+ unsigned offset, unsigned length)
+ {
+ struct blocklist *block;
+
+ if (offset + length > GRUB_DISK_SECTOR_SIZE)
+ /* Seemingly a bug. */
+ return;
+
+ 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 (tail)
+ tail->next = block;
+ tail = block;
+ if (! head)
+ head = block;
+ }
+
+ if (! argc)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no variable is specified");
+
+ file = open_envblk_file ((state[0].set) ? state[0].arg : 0);
+ 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 = read_hook;
+ envblk = read_envblk_file (file);
+ file->read_hook = 0;
+ if (! envblk)
+ goto fail;
+
+ if (check_blocklists (envblk, head, file))
+ goto fail;
+
+ while (argc)
+ {
+ 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;
+ }
+ }
+
+ argc--;
+ args++;
+ }
+
+ write_blocklists (envblk, head, file);
+
+ fail:
+ if (envblk)
+ grub_envblk_close (envblk);
+ free_blocklists (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]"),
+ 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..5fc648a
--- /dev/null
+++ b/grub-core/commands/ls.c
@@ -0,0 +1,282 @@
+/* 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>
+
+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}
+ };
+
+static const char grub_human_sizes[] = {' ', 'K', 'M', 'G', 'T'};
+
+static grub_err_t
+grub_ls_list_devices (int longlist)
+{
+ auto int grub_ls_print_devices (const char *name);
+ int grub_ls_print_devices (const char *name)
+ {
+ if (longlist)
+ grub_normal_print_device_info (name);
+ else
+ grub_printf ("(%s) ", name);
+
+ return 0;
+ }
+
+ grub_device_iterate (grub_ls_print_devices);
+ grub_xputs ("\n");
+ grub_refresh ();
+
+ 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;
+
+ auto int print_files (const char *filename,
+ const struct grub_dirhook_info *info);
+ auto int print_files_long (const char *filename,
+ const struct grub_dirhook_info *info);
+
+ int print_files (const char *filename, const struct grub_dirhook_info *info)
+ {
+ if (all || filename[0] != '.')
+ grub_printf ("%s%s ", filename, info->dir ? "/" : "");
+
+ return 0;
+ }
+
+ int print_files_long (const char *filename,
+ const struct grub_dirhook_info *info)
+ {
+ if ((! all) && (filename[0] == '.'))
+ return 0;
+
+ if (! info->dir)
+ {
+ grub_file_t file;
+ char *pathname;
+
+ if (dirname[grub_strlen (dirname) - 1] == '/')
+ pathname = grub_xasprintf ("%s%s", dirname, filename);
+ else
+ pathname = grub_xasprintf ("%s/%s", dirname, filename);
+
+ if (!pathname)
+ return 1;
+
+ /* XXX: For ext2fs symlinks are detected as files while they
+ should be reported as directories. */
+ grub_file_filter_disable_compression ();
+ file = grub_file_open (pathname);
+ if (! file)
+ {
+ grub_errno = 0;
+ grub_free (pathname);
+ return 0;
+ }
+
+ if (! human)
+ grub_printf ("%-12llu", (unsigned long long) file->size);
+ else
+ {
+ grub_uint64_t fsize = file->size * 100ULL;
+ int fsz = file->size;
+ int units = 0;
+ char buf[20];
+
+ while (fsz / 1024)
+ {
+ fsize = (fsize + 512) / 1024;
+ fsz /= 1024;
+ units++;
+ }
+
+ if (units)
+ {
+ grub_uint32_t whole, fraction;
+
+ whole = grub_divmod64 (fsize, 100, &fraction);
+ grub_snprintf (buf, sizeof (buf),
+ "%u.%02u%c", whole, fraction,
+ grub_human_sizes[units]);
+ grub_printf ("%-12s", buf);
+ }
+ else
+ grub_printf ("%-12llu", (unsigned long long) file->size);
+
+ }
+ 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 (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;
+ }
+
+ 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)
+ {
+ if (grub_errno == GRUB_ERR_UNKNOWN_FS)
+ grub_errno = GRUB_ERR_NONE;
+
+ grub_normal_print_device_info (device_name);
+ }
+ else if (fs)
+ {
+ if (longlist)
+ (fs->dir) (dev, path, print_files_long);
+ else
+ (fs->dir) (dev, path, print_files);
+
+ 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;
+
+ grub_file_filter_disable_compression ();
+ file = grub_file_open (dirname);
+ 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);
+ else
+ print_files (p, &info);
+
+ 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..fd19e38
--- /dev/null
+++ b/grub-core/commands/lsacpi.c
@@ -0,0 +1,252 @@
+/* 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>
+
+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 OEM=", t->length, t->revision);
+ 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))
+ {
+ grub_printf (" type=%x l=%u ", d->type, d->len);
+
+ switch (d->type)
+ {
+ 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);
+ }
+ 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);
+ }
+ 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);
+ }
+ 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 (" ??\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 > 0; desc++, len -= sizeof (*desc))
+ {
+ if (sizeof (grub_addr_t) == 4 && *desc >= (1ULL << 32))
+ {
+ grub_printf ("Unreachable table\n");
+ continue;
+ }
+ 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 > 0; 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, OEM-ID: ", rsdp->checksum);
+ 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 XSDT=%016" PRIxGRUB_UINT64_T "\n", rsdp->length,
+ rsdp->xsdt_addr);
+}
+
+static const struct grub_arg_option options[] = {
+ {"v1", '1', 0, N_("Show v1 tables only."), 0, ARG_TYPE_NONE},
+ {"v2", '2', 0, N_("Show v2 and v3 tablesv only."), 0, ARG_TYPE_NONE}
+};
+
+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 (sizeof (grub_addr_t) == 4 && rsdp2->xsdt_addr >= (1ULL << 32))
+ grub_printf ("Unreachable RSDPv2\n");
+ else
+ {
+ 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, N_("[-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..44598f0
--- /dev/null
+++ b/grub-core/commands/lsmmap.c
@@ -0,0 +1,74 @@
+/*
+ * 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>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const char *names[] =
+ {
+ [GRUB_MEMORY_AVAILABLE] = "available",
+ [GRUB_MEMORY_RESERVED] = "reserved",
+ [GRUB_MEMORY_ACPI] = "ACPI reclamaible",
+ [GRUB_MEMORY_NVS] = "NVS",
+ [GRUB_MEMORY_BADRAM] = "BadRAM",
+ [GRUB_MEMORY_CODE] = "firmware code",
+ [GRUB_MEMORY_HOLE] = "hole"
+ };
+
+static grub_err_t
+grub_cmd_lsmmap (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+
+{
+ auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_memory_type_t);
+ int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
+ grub_memory_type_t type)
+ {
+ if (type < ARRAY_SIZE (names) && names[type])
+ grub_printf ("base_addr = 0x%llx, length = 0x%llx, %s\n",
+ (long long) addr, (long long) size, names[type]);
+ else
+ grub_printf ("base_addr = 0x%llx, length = 0x%llx, type = 0x%x\n",
+ (long long) addr, (long long) size, type);
+ return 0;
+ }
+#ifndef GRUB_MACHINE_EMU
+ grub_machine_mmap_iterate (hook);
+#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..03541df
--- /dev/null
+++ b/grub-core/commands/lspci.c
@@ -0,0 +1,236 @@
+/* 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>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+struct grub_pci_classname
+{
+ int class;
+ int subclass;
+ 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 NESTED_FUNC_ATTR
+grub_lspci_iter (grub_pci_device_t dev, grub_pci_id_t pciid)
+{
+ 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);
+ 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/memrw.c b/grub-core/commands/memrw.c
new file mode 100644
index 0000000..3b51189
--- /dev/null
+++ b/grub-core/commands/memrw.c
@@ -0,0 +1,151 @@
+/* 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>
+
+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."),
+ "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_target_addr_t addr;
+ grub_uint32_t value = 0;
+ char buf[sizeof ("XXXXXXXX")];
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid number of arguments");
+
+ 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_target_addr_t addr;
+ grub_uint32_t value;
+ grub_uint32_t mask = 0xffffffff;
+
+ if (argc != 2 && argc != 3)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid number of arguments");
+
+ 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 byte from ADDR."), options);
+ cmd_read_word =
+ grub_register_extcmd ("read_word", grub_cmd_read, 0,
+ N_("ADDR"), N_("Read word from ADDR."), options);
+ cmd_read_dword =
+ grub_register_extcmd ("read_dword", grub_cmd_read, 0,
+ N_("ADDR"), N_("Read dword from ADDR."), options);
+ cmd_write_byte =
+ grub_register_command ("write_byte", grub_cmd_write,
+ N_("ADDR VALUE [MASK]"), N_("Write byte VALUE to ADDR."));
+ cmd_write_word =
+ grub_register_command ("write_word", grub_cmd_write,
+ N_("ADDR VALUE [MASK]"), N_("Write word VALUE to ADDR."));
+ cmd_write_dword =
+ grub_register_command ("write_dword", grub_cmd_write,
+ N_("ADDR VALUE [MASK]"), N_("Write dword 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..4849f8b
--- /dev/null
+++ b/grub-core/commands/menuentry.c
@@ -0,0 +1,307 @@
+/* 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."), "STRING", ARG_TYPE_STRING},
+ {"users", 2, 0,
+ N_("Users allowed to boot this entry."), "USERNAME", ARG_TYPE_STRING},
+ {"hotkey", 3, 0,
+ N_("Keyboard key for this entry."), "KEY", ARG_TYPE_STRING},
+ {"source", 4, 0,
+ N_("Menu entry definition as a string."), "STRING", ARG_TYPE_STRING},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static struct
+{
+ char *name;
+ int key;
+} hotkey_aliases[] =
+ {
+ {"backspace", '\b'},
+ {"tab", '\t'},
+ {"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 *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;
+ 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);
+ 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;
+
+ /* Save argc, args to pass as parameters to block arg later. */
+ menu_args = grub_malloc (sizeof (char*) * (argc + 1));
+ 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)->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);
+ 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++ == '\'' ? 3 : 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;
+
+ 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->script)
+ return grub_normal_add_menu_entry (argc, (const char **) args,
+ (ctxt->state[0].set ? ctxt->state[0].args
+ : NULL), ctxt->state[1].arg,
+ 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[1].arg,
+ 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_FLAG_EXTRACTOR,
+ N_("BLOCK"), N_("Define a menuentry."), options);
+ cmd_sub = grub_register_extcmd ("submenu", grub_cmd_menuentry,
+ GRUB_COMMAND_FLAG_BLOCKS
+ | 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..c7d1ec4
--- /dev/null
+++ b/grub-core/commands/minicmd.c
@@ -0,0 +1,230 @@
+/* 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, "no file specified");
+
+ file = grub_file_open (argv[0]);
+ 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_PRIO_LIST_PRIO_MASK,
+ (p->prio & GRUB_PRIO_LIST_FLAG_ACTIVE) ? '+' : '-',
+ p->description);
+
+ return 0;
+}
+
+#if 0
+static void
+grub_rescue_cmd_info (void)
+{
+ extern void grub_disk_cache_get_performance (unsigned long *,
+ unsigned long *);
+ unsigned long hits, misses;
+
+ grub_disk_cache_get_performance (&hits, &misses);
+ grub_printf ("Disk cache: hits = %u, misses = %u ", hits, misses);
+ if (hits + misses)
+ {
+ unsigned long ratio = hits * 10000 / (hits + misses);
+ grub_printf ("(%u.%u%%)\n", ratio / 100, ratio % 100);
+ }
+ else
+ grub_printf ("(N/A)\n");
+}
+#endif
+
+/* 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");
+
+ addr = (grub_uint8_t *) grub_strtoul (argv[0], 0, 0);
+ if (grub_errno)
+ return grub_errno;
+
+ if (argc > 1)
+ size = (grub_size_t) grub_strtoul (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_unref (mod) <= 0)
+ 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;
+
+ grub_printf ("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
+grub_mini_cmd_exit (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ grub_exit ();
+ return 0;
+}
+
+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"), N_("Dump memory."));
+ 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/yeeloong/lsspd.c b/grub-core/commands/mips/yeeloong/lsspd.c
new file mode 100644
index 0000000..c1c5e2e
--- /dev/null
+++ b/grub-core/commands/mips/yeeloong/lsspd.c
@@ -0,0 +1,94 @@
+/*
+ * 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>
+
+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_printf ("No CS5536 found\n");
+ return GRUB_ERR_NONE;
+ }
+ grub_printf ("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;
+
+ grub_printf ("SMB base = 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));
+ grub_printf ("Device %d\n", i);
+ err = grub_cs5536_read_spd (smbbase, i, &spd);
+ if (err)
+ {
+ grub_print_error ();
+ continue;
+ }
+ grub_printf ("Written SPD bytes: %d B.\n", spd.written_size);
+ grub_printf ("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_printf ("Memory type: DDR2.\n");
+ grub_memcpy (str, spd.ddr2.part_number,
+ sizeof (spd.ddr2.part_number));
+ str[sizeof (spd.ddr2.part_number)] = 0;
+ grub_printf ("Part no: %s.\n", str);
+ }
+ else
+ grub_printf ("Memory type: Unknown.\n");
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(lsspd)
+{
+ cmd = grub_register_command ("lsspd", grub_cmd_lsspd, 0,
+ "Print Memory information.");
+}
+
+GRUB_MOD_FINI(lsspd)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/parttool.c b/grub-core/commands/parttool.c
new file mode 100644
index 0000000..a542861
--- /dev/null
+++ b/grub-core/commands/parttool.c
@@ -0,0 +1,333 @@
+/* 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[] =
+ "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_malloc ((nargs + 1) * sizeof (struct grub_parttool_argdesc));
+ 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
+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;
+
+ auto grub_err_t show_help (void);
+ grub_err_t show_help (void)
+ {
+ int found = 0;
+ 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_printf ("=VAL");
+ spacing -= 4;
+ break;
+
+ case GRUB_PARTTOOL_ARG_END:
+ break;
+ }
+ while (spacing-- > 0)
+ grub_printf (" ");
+ grub_printf ("%s\n", curarg->desc);
+ }
+ }
+ if (! found)
+ grub_printf ("Sorry no parttool is available for %s\n",
+ dev->disk->partition->partmap->name);
+ return GRUB_ERR_NONE;
+ }
+
+ if (argc < 1)
+ {
+ grub_printf ("%s\n", 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_autoload)
+ {
+ const char *prefix;
+ prefix = grub_env_get ("prefix");
+ if (prefix)
+ {
+ char *filename;
+
+ filename = grub_xasprintf ("%s/parttool.lst", prefix);
+ if (filename)
+ {
+ grub_file_t file;
+
+ file = grub_file_open (filename);
+ if (file)
+ {
+ char *buf = 0;
+ for (;; grub_free(buf))
+ {
+ char *p, *name;
+
+ buf = grub_file_getline (file);
+
+ if (! buf)
+ break;
+
+ name = buf;
+
+ if (! grub_isgraph (name[0]))
+ continue;
+
+ p = grub_strchr (name, ':');
+ if (! p)
+ continue;
+
+ *p = '\0';
+ while (*++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)
+ return show_help ();
+
+ for (i = 1; i < argc; i++)
+ if (grub_strcmp (args[i], "help") == 0)
+ return show_help ();
+
+ parsed = (int *) grub_zalloc (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)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "unrecognised argument %s",
+ args[i]);
+ ptool = cur;
+ pargs = (struct grub_parttool_args *)
+ grub_zalloc (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..8821607
--- /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, "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..05a6272
--- /dev/null
+++ b/grub-core/commands/password_pbkdf2.c
@@ -0,0 +1,199 @@
+/*
+ * 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;
+
+ 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)
+ {
+ grub_free (buf);
+ return grub_crypto_gcry_error (err);
+ }
+
+ if (grub_crypto_memcmp (buf, pass->expected, pass->buflen) != 0)
+ return GRUB_ACCESS_DENIED;
+
+ grub_auth_authenticate (user);
+
+ return GRUB_ERR_NONE;
+}
+
+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;
+ char *ptr, *ptr2;
+ grub_uint8_t *ptro;
+ struct pbkdf2_password *pass;
+
+ if (argc != 2)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Two arguments expected.");
+
+ if (grub_memcmp (args[1], "grub.pbkdf2.sha512.",
+ sizeof ("grub.pbkdf2.sha512.") - 1) != 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect 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 (*ptr != '.')
+ {
+ grub_free (pass);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect 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, "Incorrect 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,
+ "Incorrect 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,
+ "Incorrect 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/probe.c b/grub-core/commands/probe.c
new file mode 100644
index 0000000..c5f9463
--- /dev/null
+++ b/grub-core/commands/probe.c
@@ -0,0 +1,162 @@
+/*
+ * 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/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>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =
+ {
+ {"set", 's', 0,
+ N_("Set a variable to return value."), "VAR", ARG_TYPE_STRING},
+ {"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},
+ {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_error (GRUB_ERR_BAD_DEVICE, "couldn't open device");
+
+ if (state[1].set)
+ {
+ const char *val = "none";
+ if (dev->net)
+ val = dev->net->dev->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);
+ 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);
+ return GRUB_ERR_NONE;
+ }
+ fs = grub_fs_probe (dev);
+ if (! fs)
+ return grub_error (GRUB_ERR_UNKNOWN_FS, "unrecognised fs");
+ if (state[3].set)
+ {
+ if (state[0].set)
+ grub_env_set (state[0].arg, fs->name);
+ else
+ grub_printf ("%s", fs->name);
+ return GRUB_ERR_NONE;
+ }
+ if (state[4].set)
+ {
+ char *uuid;
+ if (! fs->uuid)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "uuid for this FS isn't supported yet");
+ err = fs->uuid (dev, &uuid);
+ if (err)
+ return err;
+ if (! uuid)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "uuid for this FS isn't supported yet");
+
+ if (state[0].set)
+ grub_env_set (state[0].arg, uuid);
+ else
+ grub_printf ("%s", uuid);
+ grub_free (uuid);
+ return GRUB_ERR_NONE;
+ }
+ if (state[5].set)
+ {
+ char *label;
+ if (! fs->label)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "label for this FS isn't supported yet");
+ err = fs->label (dev, &label);
+ if (err)
+ return err;
+ if (! label)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "uuid for this FS isn't supported yet");
+
+ if (state[0].set)
+ grub_env_set (state[0].arg, label);
+ else
+ grub_printf ("%s", label);
+ grub_free (label);
+ return GRUB_ERR_NONE;
+ }
+ 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..8e18083
--- /dev/null
+++ b/grub-core/commands/reboot.c
@@ -0,0 +1,47 @@
+/* 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
+grub_cmd_reboot (grub_command_t cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ grub_reboot ();
+ return 0;
+}
+
+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..1e8a6f3
--- /dev/null
+++ b/grub-core/commands/regexp.c
@@ -0,0 +1,151 @@
+/* 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,
+ N_("Variable names to update with matches."),
+ N_("[NUMBER:]VARNAME"), ARG_TYPE_STRING },
+ { 0, 0, 0, 0, 0, 0 }
+ };
+
+static grub_err_t
+set_matches (char **varnames, char *str, grub_size_t nmatches,
+ regmatch_t *matches)
+{
+ int i;
+ char ch;
+ char *p;
+ char *q;
+ grub_err_t err;
+ unsigned long j;
+
+ auto void setvar (char *v, regmatch_t *m);
+ void setvar (char *v, regmatch_t *m)
+ {
+ ch = str[m->rm_eo];
+ str[m->rm_eo] = '\0';
+ err = grub_env_set (v, str + m->rm_so);
+ str[m->rm_eo] = ch;
+ }
+
+ for (i = 0; varnames && varnames[i]; i++)
+ {
+ if (! (p = grub_strchr (varnames[i], ':')))
+ {
+ /* varname w/o index defaults to 1 */
+ if (nmatches < 2 || matches[1].rm_so == -1)
+ grub_env_unset (varnames[i]);
+ else
+ setvar (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
+ setvar (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, "2 arguments expected");
+
+ ret = regcomp (&regex, args[0], REG_EXTENDED);
+ if (ret)
+ goto fail;
+
+ matches = grub_zalloc (sizeof (*matches) * (regex.re_nsub + 1));
+ 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, 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..ba80d80
--- /dev/null
+++ b/grub-core/commands/search.c
@@ -0,0 +1,245 @@
+/* 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+");
+
+void
+FUNC_NAME (const char *key, const char *var, int no_floppy,
+ char **hints, unsigned nhints)
+{
+ int count = 0;
+ grub_fs_autoload_hook_t saved_autoload;
+
+ auto int iterate_device (const char *name);
+ int iterate_device (const char *name)
+ {
+ int found = 0;
+
+ /* Skip floppy drives when requested. */
+ if (no_floppy &&
+ name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9')
+ return 0;
+
+#ifdef DO_SEARCH_FILE
+ {
+ char *buf;
+ grub_file_t file;
+
+ buf = grub_xasprintf ("(%s)%s", name, key);
+ if (! buf)
+ return 1;
+
+ grub_file_filter_disable_compression ();
+ file = grub_file_open (buf);
+ 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 compare_fn grub_strcasecmp
+#define read_fn uuid
+#else
+#define compare_fn grub_strcmp
+#define read_fn label
+#endif
+
+ if (fs && fs->read_fn)
+ {
+ fs->read_fn (dev, &quid);
+
+ if (grub_errno == GRUB_ERR_NONE && quid)
+ {
+ if (compare_fn (quid, key) == 0)
+ found = 1;
+
+ grub_free (quid);
+ }
+ }
+
+ grub_device_close (dev);
+ }
+ }
+#endif
+
+ if (found)
+ {
+ count++;
+ if (var)
+ grub_env_set (var, name);
+ else
+ grub_printf (" %s", name);
+ }
+
+ grub_errno = GRUB_ERR_NONE;
+ return (found && var);
+ }
+
+ auto int part_hook (grub_disk_t disk, const grub_partition_t partition);
+ int part_hook (grub_disk_t disk, const grub_partition_t partition)
+ {
+ 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);
+ grub_free (devname);
+
+ return ret;
+ }
+
+ auto void try (void);
+ void try (void)
+ {
+ unsigned i;
+ for (i = 0; i < nhints; i++)
+ {
+ char *end;
+ if (!hints[i][0])
+ continue;
+ end = hints[i] + grub_strlen (hints[i]) - 1;
+ if (*end == ',')
+ *end = 0;
+ if (iterate_device (hints[i]))
+ {
+ if (!*end)
+ *end = ',';
+ return;
+ }
+ if (!*end)
+ {
+ grub_device_t dev;
+ int ret;
+ dev = grub_device_open (hints[i]);
+ if (!dev)
+ {
+ *end = ',';
+ continue;
+ }
+ if (!dev->disk)
+ {
+ grub_device_close (dev);
+ *end = ',';
+ continue;
+ }
+ ret = grub_partition_iterate (dev->disk, part_hook);
+ *end = ',';
+ grub_device_close (dev);
+ if (ret)
+ return;
+ }
+ }
+ grub_device_iterate (iterate_device);
+ }
+
+ /* First try without autoloading if we're setting variable. */
+ if (var)
+ {
+ saved_autoload = grub_fs_autoload_hook;
+ grub_fs_autoload_hook = 0;
+ try ();
+
+ /* Restore autoload hook. */
+ grub_fs_autoload_hook = saved_autoload;
+
+ /* Retry with autoload if nothing found. */
+ if (grub_errno == GRUB_ERR_NONE && count == 0)
+ try ();
+ }
+ else
+ try ();
+
+ if (grub_errno == GRUB_ERR_NONE && 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, "no argument specified");
+
+ 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..73ce89c
--- /dev/null
+++ b/grub-core/commands/search_file.c
@@ -0,0 +1,6 @@
+#define DO_SEARCH_FILE 1
+#define FUNC_NAME grub_search_fs_file
+#define COMMAND_NAME "search.file"
+#define SEARCH_TARGET "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..ee9c792
--- /dev/null
+++ b/grub-core/commands/search_label.c
@@ -0,0 +1,6 @@
+#define DO_SEARCH_FS_LABEL 1
+#define FUNC_NAME grub_search_label
+#define COMMAND_NAME "search.fs_label"
+#define SEARCH_TARGET "filesystem 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..52f8381
--- /dev/null
+++ b/grub-core/commands/search_uuid.c
@@ -0,0 +1,6 @@
+#define DO_SEARCH_FS_UUID 1
+#define FUNC_NAME grub_search_fs_uuid
+#define COMMAND_NAME "search.fs_uuid"
+#define SEARCH_TARGET "filesystem 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..7b0a995
--- /dev/null
+++ b/grub-core/commands/search_wrap.c
@@ -0,0 +1,109 @@
+/* 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."), "VAR", 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},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+enum options
+ {
+ SEARCH_FILE,
+ SEARCH_LABEL,
+ SEARCH_FS_UUID,
+ SEARCH_SET,
+ SEARCH_NO_FLOPPY,
+ SEARCH_HINT
+ };
+
+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;
+ int nhints = 0;
+
+ if (state[SEARCH_HINT].set)
+ while (state[SEARCH_HINT].args[nhints])
+ nhints++;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no argument specified");
+
+ if (state[SEARCH_SET].set)
+ var = state[SEARCH_SET].arg ? state[SEARCH_SET].arg : "root";
+
+ if (state[SEARCH_LABEL].set)
+ grub_search_label (args[0], var, state[SEARCH_NO_FLOPPY].set,
+ state[SEARCH_HINT].args, nhints);
+ else if (state[SEARCH_FS_UUID].set)
+ grub_search_fs_uuid (args[0], var, state[SEARCH_NO_FLOPPY].set,
+ state[SEARCH_HINT].args, nhints);
+ else if (state[SEARCH_FILE].set)
+ grub_search_fs_file (args[0], var, state[SEARCH_NO_FLOPPY].set,
+ state[SEARCH_HINT].args, nhints);
+ else
+ return grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type");
+
+ return grub_errno;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(search)
+{
+ cmd =
+ grub_register_extcmd ("search", grub_cmd_search, GRUB_COMMAND_FLAG_EXTRACTOR,
+ 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..70f5bcd
--- /dev/null
+++ b/grub-core/commands/setpci.c
@@ -0,0 +1,343 @@
+/* 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, "Select device by vendor and device IDs.",
+ "[vendor]:[device]", ARG_TYPE_STRING},
+ {0, 's', 0, "Select device by its position on the bus.",
+ "[bus]:[slot][.func]", ARG_TYPE_STRING},
+ {0, 'v', 0, "Save read value into variable VARNAME.",
+ "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 NESTED_FUNC_ATTR
+grub_setpci_iter (grub_pci_device_t dev, grub_pci_id_t pciid)
+{
+ 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 %d:%d.%d 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, (char **) &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, "Colon expected.");
+ ptr++;
+ pciid_check_value |= (grub_strtoul (ptr, (char **) &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, (char **) &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, "Colon expected.");
+ ptr++;
+ optr = ptr;
+ device = grub_strtoul (ptr, (char **) &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, (char **) &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 == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Command expected.");
+
+ if (argc > 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Only one command is supported.");
+
+ 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, (char **) &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, (char **) &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, (char **) &ptr, 16);
+ if (grub_errno)
+ return grub_errno;
+ write_mask = 0xffffffff;
+ if (*ptr == ':')
+ {
+ ptr++;
+ write_mask = grub_strtoul (ptr, (char **) &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);
+ return GRUB_ERR_NONE;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(setpci)
+{
+ cmd = grub_register_extcmd ("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..97e7a40
--- /dev/null
+++ b/grub-core/commands/sleep.c
@@ -0,0 +1,114 @@
+/* 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_("Interruptible with ESC."), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static grub_uint16_t *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);
+}
+
+/* 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_checkkey () >= 0 && grub_getkey () == GRUB_TERM_ESC)
+ 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, "missing operand");
+
+ n = grub_strtoul (args[0], 0, 10);
+
+ if (n == 0)
+ {
+ /* Either `0' or broken input. */
+ return 0;
+ }
+
+ 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/terminal.c b/grub-core/commands/terminal.c
new file mode 100644
index 0000000..0adfd3d
--- /dev/null
+++ b/grub-core/commands/terminal.c
@@ -0,0 +1,258 @@
+/*
+ * 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;
+ 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)
+ break;
+ if (term == 0)
+ for (term = *enabled; term; term = term->next)
+ if (grub_strcmp (args[i], term->name) == 0)
+ break;
+ if (term)
+ break;
+ if (again)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n",
+ args[i]);
+ for (aut = autoloads; aut; aut = aut->next)
+ if (grub_strcmp (args[i], 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 (!aut)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n",
+ 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)
+ break;
+ if (term)
+ {
+ if (term->init && term->init (term) != GRUB_ERR_NONE)
+ return grub_errno;
+
+ grub_list_remove (GRUB_AS_LIST_P (disabled), 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)
+ 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_P (enabled), 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)
+ break;
+ if (term)
+ {
+ if (term->init && term->init (term) != GRUB_ERR_NONE)
+ return grub_errno;
+
+ grub_list_remove (GRUB_AS_LIST_P (disabled), 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)
+ 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_P (enabled), 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 *, 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 *, 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..50d5aba
--- /dev/null
+++ b/grub-core/commands/test.c
@@ -0,0 +1,438 @@
+/* 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, char **end, int base)
+{
+ if (arg[0] == '-')
+ return -grub_strtoul (arg + 1, end, base);
+ return grub_strtoul (arg, end, base);
+}
+
+/* Parse a test expression starting from *argn. */
+static int
+test_parse (char **args, int *argn, int argc)
+{
+ int ret = 0, discard = 0, invert = 0;
+ int file_exists;
+ struct grub_dirhook_info file_info;
+
+ auto void update_val (int val);
+ auto void get_fileinfo (char *pathname);
+
+ /* Take care of discarding and inverting. */
+ void update_val (int val)
+ {
+ if (! discard)
+ ret = invert ? ! val : val;
+ invert = discard = 0;
+ }
+
+ /* Check if file exists and fetch its information. */
+ void get_fileinfo (char *path)
+ {
+ char *filename, *pathname;
+ char *device_name;
+ grub_fs_t fs;
+ grub_device_t dev;
+
+ /* A hook for iterating directories. */
+ auto int find_file (const char *cur_filename,
+ const struct grub_dirhook_info *info);
+ int find_file (const char *cur_filename,
+ const struct grub_dirhook_info *info)
+ {
+ if ((info->case_insensitive ? grub_strcasecmp (cur_filename, filename)
+ : grub_strcmp (cur_filename, filename)) == 0)
+ {
+ file_info = *info;
+ file_exists = 1;
+ return 1;
+ }
+ return 0;
+ }
+
+ 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. */
+ filename = grub_strrchr (pathname, '/');
+ if (! filename)
+ {
+ path = grub_strdup ("/");
+ filename = pathname;
+ }
+ else
+ {
+ filename++;
+ path = grub_strdup (pathname);
+ path[filename - pathname] = 0;
+ }
+
+ /* It's the whole device. */
+ if (! *pathname)
+ {
+ file_exists = 1;
+ grub_memset (&file_info, 0, sizeof (file_info));
+ /* Root is always a directory. */
+ file_info.dir = 1;
+
+ /* Fetch writing time. */
+ file_info.mtimeset = 0;
+ if (fs->mtime)
+ {
+ if (! fs->mtime (dev, &file_info.mtime))
+ file_info.mtimeset = 1;
+ grub_errno = GRUB_ERR_NONE;
+ }
+ }
+ else
+ (fs->dir) (dev, path, find_file);
+
+ grub_device_close (dev);
+ grub_free (path);
+ grub_free (device_name);
+ }
+
+ /* 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);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "!=") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) != 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ /* GRUB extension: lexicographical sorting. */
+ if (grub_strcmp (args[*argn + 1], "<") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) < 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], "<=") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) <= 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], ">") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) > 0);
+ (*argn) += 3;
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn + 1], ">=") == 0)
+ {
+ update_val (grub_strcmp (args[*argn], args[*argn + 2]) >= 0);
+ (*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));
+ (*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));
+ (*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));
+ (*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));
+ (*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));
+ (*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));
+ (*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));
+ else
+ update_val (grub_strtoul (args[*argn] + i, 0, 0)
+ < grub_strtoul (args[*argn + 2] + i, 0, 0));
+ (*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]);
+ file1 = file_info;
+ file1exists = file_exists;
+ get_fileinfo (args[*argn + 2]);
+
+ 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 && ! file_exists)
+ || (file1.mtimeset && file_info.mtimeset
+ && file1.mtime + bias > file_info.mtime));
+ else
+ update_val ((! file1exists && file_exists)
+ || (file1.mtimeset && file_info.mtimeset
+ && file1.mtime + bias < file_info.mtime));
+ (*argn) += 3;
+ continue;
+ }
+ }
+
+ /* Two-argument tests. */
+ if (*argn + 1 < argc)
+ {
+ /* File tests. */
+ if (grub_strcmp (args[*argn], "-d") == 0)
+ {
+ get_fileinfo (args[*argn + 1]);
+ update_val (file_exists && file_info.dir);
+ (*argn) += 2;
+ return ret;
+ }
+
+ if (grub_strcmp (args[*argn], "-e") == 0)
+ {
+ get_fileinfo (args[*argn + 1]);
+ update_val (file_exists);
+ (*argn) += 2;
+ return ret;
+ }
+
+ if (grub_strcmp (args[*argn], "-f") == 0)
+ {
+ get_fileinfo (args[*argn + 1]);
+ /* FIXME: check for other types. */
+ update_val (file_exists && ! file_info.dir);
+ (*argn) += 2;
+ return ret;
+ }
+
+ if (grub_strcmp (args[*argn], "-s") == 0)
+ {
+ grub_file_t file;
+ grub_file_filter_disable_compression ();
+ file = grub_file_open (args[*argn + 1]);
+ update_val (file && (grub_file_size (file) != 0));
+ if (file)
+ grub_file_close (file);
+ grub_errno = GRUB_ERR_NONE;
+ (*argn) += 2;
+ return ret;
+ }
+
+ /* String tests. */
+ if (grub_strcmp (args[*argn], "-n") == 0)
+ {
+ update_val (args[*argn + 1][0]);
+
+ (*argn) += 2;
+ continue;
+ }
+ if (grub_strcmp (args[*argn], "-z") == 0)
+ {
+ update_val (! args[*argn + 1][0]);
+ (*argn) += 2;
+ continue;
+ }
+ }
+
+ /* Special modifiers. */
+
+ /* End of expression. return to parent. */
+ if (grub_strcmp (args[*argn], ")") == 0)
+ {
+ (*argn)++;
+ return ret;
+ }
+ /* Recursively invoke if parenthesis. */
+ if (grub_strcmp (args[*argn], "(") == 0)
+ {
+ (*argn)++;
+ update_val (test_parse (args, argn, argc));
+ continue;
+ }
+
+ if (grub_strcmp (args[*argn], "!") == 0)
+ {
+ invert = ! invert;
+ (*argn)++;
+ continue;
+ }
+ if (grub_strcmp (args[*argn], "-a") == 0)
+ {
+ /* If current value is 0 second value is to be discarded. */
+ discard = ! ret;
+ (*argn)++;
+ continue;
+ }
+ if (grub_strcmp (args[*argn], "-o") == 0)
+ {
+ /* If current value is 1 second value is to be discarded. */
+ discard = ret;
+ (*argn)++;
+ continue;
+ }
+
+ /* No test found. Interpret if as just a string. */
+ update_val (args[*argn][0]);
+ (*argn)++;
+ }
+ return ret;
+}
+
+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, "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..fe06f3d
--- /dev/null
+++ b/grub-core/commands/testload.c
@@ -0,0 +1,157 @@
+/* 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+");
+
+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;
+ auto void NESTED_FUNC_ATTR read_func (grub_disk_addr_t sector, unsigned offset, unsigned len);
+
+ void NESTED_FUNC_ATTR read_func (grub_disk_addr_t sector __attribute__ ((unused)),
+ unsigned offset __attribute__ ((unused)),
+ unsigned len __attribute__ ((unused)))
+ {
+ grub_xputs (".");
+ grub_refresh ();
+ }
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
+
+ file = grub_file_open (argv[0]);
+ 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_func;
+ 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; pos += GRUB_DISK_SECTOR_SIZE)
+ {
+ char sector[GRUB_DISK_SECTOR_SIZE];
+
+ 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)
+ {
+ grub_printf ("\nDiffers in %lld\n", (unsigned long long) pos);
+ goto fail;
+ }
+ }
+ 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];
+
+ pos -= GRUB_DISK_SECTOR_SIZE;
+
+ 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/true.c b/grub-core/commands/true.c
new file mode 100644
index 0000000..82775e7
--- /dev/null
+++ b/grub-core/commands/true.c
@@ -0,0 +1,59 @@
+/* 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, "false");
+}
+
+static grub_command_t cmd_true, cmd_false;
+
+
+GRUB_MOD_INIT(true)
+{
+ cmd_true =
+ grub_register_command ("true", grub_cmd_true,
+ 0, N_("Do nothing, successfully."));
+ cmd_false =
+ grub_register_command ("false", grub_cmd_false,
+ 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..4a051ad
--- /dev/null
+++ b/grub-core/commands/usbtest.c
@@ -0,0 +1,218 @@
+/* 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"
+ };
+
+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;
+}
+
+static void
+usb_print_str (const char *description, grub_usb_device_t dev, int idx)
+{
+ char *name;
+ 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)
+{
+ 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 ();
+
+ grub_printf ("USB devices:\n\n");
+ grub_usb_iterate (usb_iterate);
+
+ 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..3e0c1a1
--- /dev/null
+++ b/grub-core/commands/videoinfo.c
@@ -0,0 +1,186 @@
+/* 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+");
+
+static unsigned height, width, depth;
+
+static int
+hook (const struct grub_video_mode_info *info)
+{
+ if (height && width && (info->width != width || info->height != height))
+ return 0;
+
+ if (depth && info->bpp != depth)
+ return 0;
+
+ if (info->mode_number == GRUB_VIDEO_MODE_NUMBER_INVALID)
+ grub_printf (" ");
+ else
+ grub_printf (" 0x%03x ", info->mode_number);
+ grub_printf ("%4d x %4d x %2d ", info->width, info->height, info->bpp);
+
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT)
+ grub_printf ("Text-only ");
+ /* Show mask and position details for direct color modes. */
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_RGB)
+ grub_printf ("Direct, 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)
+ grub_printf ("Packed ");
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_YUV)
+ grub_printf ("YUV ");
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PLANAR)
+ grub_printf ("Planar ");
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_HERCULES)
+ grub_printf ("Hercules ");
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_CGA)
+ grub_printf ("CGA ");
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_NONCHAIN4)
+ grub_printf ("Non-chain 4 ");
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP)
+ grub_printf ("Monochrome ");
+ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_UNKNOWN)
+ grub_printf ("Unknown ");
+
+ grub_printf ("\n");
+
+ return 0;
+}
+
+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;
+
+ height = width = depth = 0;
+ if (argc)
+ {
+ char *ptr;
+ ptr = args[0];
+ width = grub_strtoul (ptr, &ptr, 0);
+ if (grub_errno)
+ return grub_errno;
+ if (*ptr != 'x')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid mode specification");
+ ptr++;
+ height = grub_strtoul (ptr, &ptr, 0);
+ if (grub_errno)
+ return grub_errno;
+ if (*ptr == 'x')
+ {
+ ptr++;
+ 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_printf ("List of supported video modes:\n");
+ grub_printf ("Legend: P=Packed pixel, D=Direct color, "
+ "mask/pos=R/G/B/reserved\n");
+
+ FOR_VIDEO_ADAPTERS (adapter)
+ {
+ grub_printf ("Adapter '%s':\n", adapter->name);
+
+ if (!adapter->iterate)
+ {
+ grub_printf (" No info available\n");
+ continue;
+ }
+
+ if (adapter->id != id)
+ {
+ if (adapter->init ())
+ {
+ grub_printf (" Failed\n");
+ grub_errno = GRUB_ERR_NONE;
+ continue;
+ }
+ }
+
+ if (adapter->print_adapter_specific_info)
+ adapter->print_adapter_specific_info ();
+
+ adapter->iterate (hook);
+
+ 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, "[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, "[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..dc7a648
--- /dev/null
+++ b/grub-core/commands/videotest.c
@@ -0,0 +1,218 @@
+/*
+ * 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;
+
+ grub_video_create_render_target (&text_layer, width, height,
+ GRUB_VIDEO_MODE_TYPE_RGB
+ | GRUB_VIDEO_MODE_TYPE_ALPHA);
+
+ 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+2287 subset symbol E2 8A 87
+ 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\x87\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 < 2; i++)
+ {
+ 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, 255);
+ grub_video_fill_rect (color, 100, 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);
+ grub_video_swap_buffers ();
+ }
+
+ for (i = 0; i < 5; i++)
+ {
+ 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;
+}
+
+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,
+ "[WxH]",
+ 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..32561ab
--- /dev/null
+++ b/grub-core/commands/wildcard.c
@@ -0,0 +1,495 @@
+/* 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 <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 char* wildcard_escape (const char *s);
+static char* wildcard_unescape (const char *s);
+static grub_err_t wildcard_expand (const char *s, char ***strs);
+
+struct grub_script_wildcard_translator grub_filename_translator = {
+ .expand = wildcard_expand,
+ .escape = wildcard_escape,
+ .unescape = wildcard_unescape
+};
+
+static char **
+merge (char **dest, char **ps)
+{
+ int i;
+ int j;
+ char **p;
+
+ if (! dest)
+ return ps;
+
+ if (! ps)
+ return dest;
+
+ for (i = 0; dest[i]; i++)
+ ;
+ for (j = 0; ps[j]; j++)
+ ;
+
+ p = grub_realloc (dest, sizeof (char*) * (i + j + 1));
+ 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_malloc (len * 2 + 2 + 1); /* worst case size. */
+
+ if (! buffer)
+ return 1;
+
+ buffer[i++] = '^';
+ while (start < end)
+ {
+ /* XXX Only * expansion for now. */
+ switch ((ch = *start++))
+ {
+ case '\\':
+ buffer[i++] = ch;
+ if (*start != '\0')
+ buffer[i++] = *start++;
+ break;
+
+ case '.':
+ case '(':
+ case ')':
+ buffer[i++] = '\\';
+ buffer[i++] = ch;
+ break;
+
+ case '*':
+ buffer[i++] = '.';
+ 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 (isregexop (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;
+}
+
+static char **
+match_devices (const regex_t *regexp, int noparts)
+{
+ int i;
+ int ndev;
+ char **devs;
+
+ auto int match (const char *name);
+ int match (const char *name)
+ {
+ char **t;
+ char *buffer;
+
+ /* skip partitions if asked to. */
+ if (noparts && grub_strchr(name, ','))
+ return 0;
+
+ buffer = grub_xasprintf ("(%s)", name);
+ if (! buffer)
+ return 1;
+
+ grub_dprintf ("expand", "matching: %s\n", buffer);
+ if (regexec (regexp, buffer, 0, 0, 0))
+ {
+ grub_dprintf ("expand", "not matched\n");
+ grub_free (buffer);
+ return 0;
+ }
+
+ t = grub_realloc (devs, sizeof (char*) * (ndev + 2));
+ if (! t)
+ return 1;
+
+ devs = t;
+ devs[ndev++] = buffer;
+ devs[ndev] = 0;
+ return 0;
+ }
+
+ ndev = 0;
+ devs = 0;
+
+ if (grub_device_iterate (match))
+ goto fail;
+
+ return devs;
+
+ fail:
+
+ for (i = 0; devs && devs[i]; i++)
+ grub_free (devs[i]);
+
+ if (devs)
+ grub_free (devs);
+
+ return 0;
+}
+
+static char **
+match_files (const char *prefix, const char *suffix, const char *end,
+ const regex_t *regexp)
+{
+ int i;
+ char **files;
+ unsigned nfile;
+ char *dir;
+ const char *path;
+ char *device_name;
+ grub_fs_t fs;
+ grub_device_t dev;
+
+ auto int match (const char *name, const struct grub_dirhook_info *info);
+ int match (const char *name, const struct grub_dirhook_info *info)
+ {
+ char **t;
+ char *buffer;
+
+ /* skip . and .. names */
+ if (grub_strcmp(".", name) == 0 || grub_strcmp("..", name) == 0)
+ return 0;
+
+ grub_dprintf ("expand", "matching: %s in %s\n", name, dir);
+ if (regexec (regexp, name, 0, 0, 0))
+ return 0;
+
+ buffer = grub_xasprintf ("%s%s", dir, name);
+ if (! buffer)
+ return 1;
+
+ t = grub_realloc (files, sizeof (char*) * (nfile + 2));
+ if (! t)
+ {
+ grub_free (buffer);
+ return 1;
+ }
+
+ files = t;
+ files[nfile++] = buffer;
+ files[nfile] = 0;
+ return 0;
+ }
+
+ nfile = 0;
+ files = 0;
+ dev = 0;
+ device_name = 0;
+ grub_error_push ();
+
+ dir = make_dir (prefix, suffix, end);
+ if (! dir)
+ goto fail;
+
+ 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;
+
+ path = grub_strchr (dir, ')');
+ if (! path)
+ goto fail;
+ path++;
+
+ if (fs->dir (dev, path, match))
+ goto fail;
+
+ grub_free (dir);
+ grub_device_close (dev);
+ grub_free (device_name);
+ grub_error_pop ();
+ return files;
+
+ fail:
+
+ if (dir)
+ grub_free (dir);
+
+ for (i = 0; files && files[i]; i++)
+ grub_free (files[i]);
+
+ if (files)
+ grub_free (files);
+
+ if (dev)
+ grub_device_close (dev);
+
+ if (device_name)
+ grub_free (device_name);
+
+ grub_error_pop ();
+ return 0;
+}
+
+static char*
+wildcard_escape (const char *s)
+{
+ int i;
+ int len;
+ char ch;
+ char *p;
+
+ len = grub_strlen (s);
+ p = grub_malloc (len * 2 + 1);
+ if (! p)
+ return NULL;
+
+ i = 0;
+ while ((ch = *s++))
+ {
+ if (isregexop (ch))
+ p[i++] = '\\';
+ p[i++] = ch;
+ }
+ p[i] = '\0';
+ return p;
+}
+
+static char*
+wildcard_unescape (const char *s)
+{
+ int i;
+ int len;
+ char ch;
+ char *p;
+
+ len = grub_strlen (s);
+ p = grub_malloc (len + 1);
+ if (! p)
+ return NULL;
+
+ i = 0;
+ while ((ch = *s++))
+ {
+ if (ch == '\\' && isregexop (*s))
+ p[i++] = *s++;
+ else
+ p[i++] = ch;
+ }
+ p[i] = '\0';
+ return p;
+}
+
+static grub_err_t
+wildcard_expand (const char *s, char ***strs)
+{
+ const char *start;
+ const char *regexop;
+ const char *noregexop;
+ char **paths = 0;
+
+ unsigned i;
+ regex_t regexp;
+
+ start = s;
+ while (*start)
+ {
+ split_path (start, &noregexop, &regexop);
+ if (noregexop >= regexop) /* no more wildcards */
+ break;
+
+ if (make_regex (noregexop, regexop, &regexp))
+ goto fail;
+
+ if (paths == 0)
+ {
+ if (start == noregexop) /* device part has regexop */
+ paths = match_devices (&regexp, *start != '(');
+
+ else if (*start == '(') /* device part explicit wo regexop */
+ paths = match_files ("", start, noregexop, &regexp);
+
+ else if (*start == '/') /* no device part */
+ {
+ char *root;
+ char *prefix;
+
+ root = grub_env_get ("root");
+ if (! root)
+ goto fail;
+
+ prefix = grub_xasprintf ("(%s)", root);
+ if (! prefix)
+ goto fail;
+
+ paths = match_files (prefix, start, noregexop, &regexp);
+ grub_free (prefix);
+ }
+ }
+ else
+ {
+ char **r = 0;
+
+ for (i = 0; paths[i]; i++)
+ {
+ char **p;
+
+ p = match_files (paths[i], start, noregexop, &regexp);
+ if (! p)
+ continue;
+
+ r = merge (r, p);
+ if (! r)
+ goto fail;
+ }
+ 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/xnu_uuid.c b/grub-core/commands/xnu_uuid.c
new file mode 100644
index 0000000..f618b4e
--- /dev/null
+++ b/grub-core/commands/xnu_uuid.c
@@ -0,0 +1,102 @@
+/* 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;
+ grub_uint8_t ctx[GRUB_MD_MD5->contextsize];
+
+ if (argc < 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "UUID required");
+
+ serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16));
+
+ 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]);
+ for (ptr = uuid_string; *ptr; ptr++)
+ *ptr = grub_toupper (*ptr);
+ if (argc == 1)
+ grub_printf ("%s", uuid_string);
+ if (argc > 1)
+ grub_env_set (args[1], uuid_string);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd;
+
+
+GRUB_MOD_INIT (xnu_uuid)
+{
+ cmd = grub_register_command ("xnu_uuid", grub_cmd_xnu_uuid,
+ N_("GRUBUUID [VARNAME]"),
+ N_("Transform 64-bit UUID to format "
+ "suitable for XNU."));
+}
+
+GRUB_MOD_FINI (xnu_uuid)
+{
+ grub_unregister_command (cmd);
+}