From: "Vladimir 'φ-coder/phcoder' Serbinenko" <phcoder@gmail.com>
To: The development of GRUB 2 <grub-devel@gnu.org>
Cc: nando4eva@gmail.com
Subject: [PATCH] Re: Feature Request: 32-bit mem write and 'setpci -s' type command in menu.lst
Date: Tue, 22 Dec 2009 17:25:30 +0100 [thread overview]
Message-ID: <4B30F2FA.7070508@gmail.com> (raw)
In-Reply-To: <4116f8730910220433ga7d2237q8a72589713c13d94@mail.gmail.com>
[-- Attachment #1.1: Type: text/plain, Size: 808 bytes --]
Nando wrote:
> Hi everyone,
>
>
> 2/ Ability to do a setpci -s type command
> ==============================
>
> Also, if possible, could a small subset of 'setpci' be incorporated as
> well? I guess I could figure out the address I need to write to by
> calculation, but would be nice if I could do the equivalent of the
> following in grub, associated with a menu entry. This would help the
> DIY ViDock project that needs to setup PCI Bridge windows prior to
> Windows load, something that many bios doesn't do, neither does Windows.
>
> setpci -s 00:02.0 40l=20
>
I attach two patches. One iorw.diff for reading/writing I/O space.
Another one setpci.diff is self-explanatory. But it depends on pciclean
patch I posted today.
--
Regards
Vladimir 'φ-coder/phcoder' Serbinenko
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: setpci.diff --]
[-- Type: text/x-diff; name="setpci.diff", Size: 10022 bytes --]
=== added file 'commands/setpci.c'
--- commands/setpci.c 1970-01-01 00:00:00 +0000
+++ commands/setpci.c 2009-12-22 15:42:45 +0000
@@ -0,0 +1,340 @@
+/* lspci.c - List PCI devices. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/pci.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/extcmd.h>
+#include <grub/env.h>
+#include <grub/mm.h>
+
+struct pci_register
+{
+ const char *name;
+ grub_uint16_t addr;
+ unsigned size;
+};
+
+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) != device)
+ 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_sprintf (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_t cmd, int argc, char **argv)
+{
+ const char *ptr;
+ unsigned i;
+
+ pciid_check_value = 0;
+ pciid_check_mask = 0;
+
+ if (cmd->state[0].set)
+ {
+ ptr = cmd->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 = cmd->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 (cmd->state[1].set)
+ {
+ const char *optr;
+
+ ptr = cmd->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 (cmd->state[2].set)
+ varname = cmd->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, GRUB_COMMAND_FLAG_BOTH,
+ "setpci [-s POSITION] [-d DEVICE] [-v VAR] "
+ "[REGISTER][=VALUE[:MASK]]",
+ "Manipulate PCI devices.", options);
+}
+
+GRUB_MOD_FINI(setpci)
+{
+ grub_unregister_extcmd (cmd);
+}
=== modified file 'conf/i386.rmk'
--- conf/i386.rmk 2009-11-25 22:39:59 +0000
+++ conf/i386.rmk 2009-12-22 15:42:45 +0000
@@ -25,3 +25,9 @@
ata_mod_SOURCES = disk/ata.c
ata_mod_CFLAGS = $(COMMON_CFLAGS)
ata_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For setpci.mod
+pkglib_MODULES += setpci.mod
+setpci_mod_SOURCES = commands/setpci.c
+setpci_mod_CFLAGS = $(COMMON_CFLAGS)
+setpci_mod_LDFLAGS = $(COMMON_LDFLAGS)
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.3: iorw.diff --]
[-- Type: text/x-diff; name="iorw.diff", Size: 4949 bytes --]
=== added file 'commands/iorw.c'
--- commands/iorw.c 1970-01-01 00:00:00 +0000
+++ commands/iorw.c 2009-12-22 16:18:48 +0000
@@ -0,0 +1,146 @@
+/* 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>
+
+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, "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_t cmd, 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 (cmd->cmd->name[sizeof ("grub_in") - 1])
+ {
+ case 'l':
+ value = grub_inl (addr);
+ break;
+
+ case 'w':
+ value = grub_inw (addr);
+ break;
+
+ case 'b':
+ value = grub_inb (addr);
+ break;
+ }
+
+ if (cmd->state[0].set)
+ {
+ grub_sprintf (buf, "%x", value);
+ grub_env_set (cmd->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 ("grub_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 ("grub_inb", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH,
+ "grub_inb PORT", "Read byte from PORT.", options);
+ cmd_read_word =
+ grub_register_extcmd ("grub_inw", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH,
+ "grub_inw PORT", "Read word from PORT.", options);
+ cmd_read_dword =
+ grub_register_extcmd ("grub_inl", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH,
+ "grub_inl PORT", "Read dword from PORT.", options);
+ cmd_write_byte =
+ grub_register_command ("grub_outb", grub_cmd_write,
+ "grub_outb PORT VALUE [MASK]", "Write byte VALUE to PORT.");
+ cmd_write_word =
+ grub_register_command ("grub_outw", grub_cmd_write,
+ "grub_outw PORT VALUE [MASK]", "Write word VALUE to PORT.");
+ cmd_write_dword =
+ grub_register_command ("grub_outl", grub_cmd_write,
+ "grub_outl ADDR VALUE [MASK]", "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);
+}
=== modified file 'conf/i386.rmk'
--- conf/i386.rmk 2009-11-25 22:39:59 +0000
+++ conf/i386.rmk 2009-12-22 16:18:48 +0000
@@ -25,3 +25,9 @@
ata_mod_SOURCES = disk/ata.c
ata_mod_CFLAGS = $(COMMON_CFLAGS)
ata_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For iorw.mod.
+pkglib_MODULES += iorw.mod
+iorw_mod_SOURCES = commands/iorw.c
+iorw_mod_CFLAGS = $(COMMON_CFLAGS)
+iorw_mod_LDFLAGS = $(COMMON_LDFLAGS)
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 293 bytes --]
prev parent reply other threads:[~2009-12-22 16:26 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-10-22 11:33 Feature Request: 32-bit mem write and 'setpci -s' type command in menu.lst Nando
2009-10-22 11:51 ` Vladimir 'phcoder' Serbinenko
2009-10-23 13:53 ` Nando
2009-10-23 14:42 ` Vladimir 'phcoder' Serbinenko
2009-10-24 8:42 ` Nando
2009-10-24 8:54 ` Vladimir 'phcoder' Serbinenko
2009-10-24 10:57 ` Seth Goldberg
2009-10-24 8:55 ` Bean
2009-12-22 16:27 ` Vladimir 'φ-coder/phcoder' Serbinenko
2009-12-22 16:25 ` Vladimir 'φ-coder/phcoder' Serbinenko [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4B30F2FA.7070508@gmail.com \
--to=phcoder@gmail.com \
--cc=grub-devel@gnu.org \
--cc=nando4eva@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.