Add a command to read values from the qemu fwcfg store. This allows data to be passed from the qemu command line to grub.
Example use: echo '(hd0,1)' >rootdev qemu -fw_cfg opt/rootdev,file=rootdev fwconfig opt/rootdev root --- docs/grub.texi | 6 +++ grub-core/Makefile.core.def | 6 +++ grub-core/commands/fwconfig.c | 121 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 grub-core/commands/fwconfig.c diff --git a/docs/grub.texi b/docs/grub.texi index 4469638..4f8a378 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -3818,6 +3818,7 @@ you forget a command, you can run the command @command{help} * eval:: Evaluate agruments as GRUB commands * export:: Export an environment variable * false:: Do nothing, unsuccessfully +* fwconfig:: Retrieves a value from the qemu fwcfg store * getenv:: Retrieve an EFI firmware variable * gettext:: Translate a string * gptsync:: Fill an MBR based on GPT entries @@ -4259,6 +4260,11 @@ Do nothing, unsuccessfully. This is mainly useful in control constructs such as @code{if} and @code{while} (@pxref{Shell-like scripting}). @end deffn +@node fwconfig +@subsection fwconig +@deffn Command fwconfig fwpath envvar +Retrieves @var{fwpath} from the qemu fwcfg store and stores it in @var{envvar} + @node getenv @subsection getenv diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index db77a7f..f6b6f38 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -2362,3 +2362,9 @@ module = { common = loader/i386/xen_file64.c; extra_dist = loader/i386/xen_fileXX.c; }; + +module = { + name = fwconfig; + common = commands/fwconfig.c; + enable = x86; +}; diff --git a/grub-core/commands/fwconfig.c b/grub-core/commands/fwconfig.c new file mode 100644 index 0000000..289d167 --- /dev/null +++ b/grub-core/commands/fwconfig.c @@ -0,0 +1,121 @@ +/* fwconfig.c - command to read config from qemu fwconfig */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2015 CoreOS, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/dl.h> +#include <grub/misc.h> +#include <grub/extcmd.h> +#include <grub/env.h> +#include <grub/cpu/io.h> +#include <grub/i18n.h> +#include <grub/mm.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define SELECTOR 0x510 +#define DATA 0x511 + +#define SIGNATURE_INDEX 0x00 +#define DIRECTORY_INDEX 0x19 + +static grub_extcmd_t cmd_read_fwconfig; + +struct grub_qemu_fwcfgfile { + grub_uint32_t size; + grub_uint16_t select; + grub_uint16_t reserved; + char name[56]; +}; + +static const struct grub_arg_option options[] = + { + {0, 'v', 0, N_("Save read value into variable VARNAME."), + N_("VARNAME"), ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + +static grub_err_t +grub_cmd_fwconfig (grub_extcmd_context_t ctxt, int argc, char **argv) +{ + grub_uint32_t i, j, value = 0; + struct grub_qemu_fwcfgfile file; + char fwsig[4], signature[4] = { 'Q', 'E', 'M', 'U' }; + + if (argc != 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected")); + + /* Verify that we have meaningful hardware here */ + grub_outw(SIGNATURE_INDEX, SELECTOR); + for (i=0; i<sizeof(fwsig); i++) + fwsig[i] = grub_inb(DATA); + + if (grub_memcmp(fwsig, signature, sizeof(signature)) != 0) + return grub_error (GRUB_ERR_BAD_DEVICE, N_("invalid fwconfig hardware signature: got 0x%x%x%x%x"), fwsig[0], fwsig[1], fwsig[2], fwsig[3]); + + /* Find out how many file entries we have */ + grub_outw(DIRECTORY_INDEX, SELECTOR); + value = grub_inb(DATA) | grub_inb(DATA) << 8 | grub_inb(DATA) << 16 | grub_inb(DATA) << 24; + value = grub_be_to_cpu32(value); + /* Read the file description for each file */ + for (i=0; i<value; i++) + { + for (j=0; j<sizeof(file); j++) + { + ((char *)&file)[j] = grub_inb(DATA); + } + /* Check whether it matches what we're looking for, and if so read the file */ + if (grub_strncmp(file.name, argv[0], sizeof(file.name)) == 0) + { + grub_uint32_t filesize = grub_be_to_cpu32(file.size); + grub_uint16_t location = grub_be_to_cpu16(file.select); + char *data = grub_malloc(filesize+1); + + if (!data) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate buffer for data")); + + grub_outw(location, SELECTOR); + for (j=0; j<filesize; j++) + { + data[j] = grub_inb(DATA); + } + + data[filesize] = '\0'; + + grub_env_set (argv[1], data); + + grub_free(data); + return 0; + } + } + + return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("couldn't find entry %s"), argv[0]); +} + +GRUB_MOD_INIT(fwconfig) +{ + cmd_read_fwconfig = + grub_register_extcmd ("fwconfig", grub_cmd_fwconfig, 0, + N_("PATH VAR"), + N_("Set VAR to the contents of fwconfig PATH"), + options); +} + +GRUB_MOD_FINI(fwconfig) +{ + grub_unregister_extcmd (cmd_read_fwconfig); +} -- 2.9.3 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel