Looks good
Reviewed-by: Vladimir Serbinenko phco...@gmail.com

Regards
Vladimir 'phcoder' Serbinenko

Le lun. 12 mai 2025, 14:55, Yair Yarom <ir...@cs.huji.ac.il> a écrit :

> Initial testpci module and command used to query if PCI devices are
> present.
>
> ---
>  docs/grub.texi               |  39 +++++++
>  grub-core/Makefile.core.def  |   7 ++
>  grub-core/commands/testpci.c | 194 +++++++++++++++++++++++++++++++++++
>  grub-core/kern/efi/sb.c      |   1 +
>  include/grub/file.h          |   2 +
>  5 files changed, 243 insertions(+)
>  create mode 100644 grub-core/commands/testpci.c
>
> diff --git a/docs/grub.texi b/docs/grub.texi
> index 2b3d536d3..a5712012e 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -4139,6 +4139,7 @@ Modules can be loaded via the @command{insmod}
> (@pxref{insmod}) command.
>  * test_module::
>  * test_blockarg_module::
>  * testload_module::
> +* testpci_module::
>  * testspeed_module::
>  * tftp_module::
>  * tga_module::
> @@ -5728,6 +5729,12 @@ argument function in GRUB internal functions via a
> test command
>  This module is intended for performing a functional test of some file
> reading /
>  seeking functions in GRUB internals via a test command @command{testload}.
>
> +@node testpci_module
> +@section testpci
> +This module provides support for the @command{testpci} command. This
> +command can be used to test if specific PCI / PCIe devices are found on
> +the system.
> +
>  @node testspeed_module
>  @section testspeed
>  This module provides support for the @command{testspeed} command to test
> and
> @@ -8052,6 +8059,38 @@ either @var{expression1} or @var{expression2} is
> true
>  @end table
>  @end deffn
>
> +@node testpci
> +@subsection testpci
> +
> +@deffn Command testpci [@option{--file} device.lst] [@var{device} [...]]
> +Test if a PCI device is present.
> +
> +Gets a device list to check from command line arguments, and/or from the
> +@var{device.lst} file.
> +
> +If any of the devices in the list are present on the machine - the
> +command exits with zero status.
> +
> +If the list is empty; Or non of the devices in the list are present; Or
> +any error occurred (bad device format, missing file, memory, etc.) - a
> +non-zero exit code is returned.
> +
> +Each @var{device} should be in the format @code{xxxx:yyyy}, where
> +@code{xxxx} is the vendor id, and @code{yyyy} is the device id. All
> +lower case as appear in the output of the @command{lspci} command.
> +
> +If @var{device.lst} file is given, each line should contain a single
> +@var{device}. Space padding, comments starting with #, and empty lines
> +are ignored.
> +
> +For example:
> +@example
> +if testpci --file $prefix/device.lst 10de:233b 1002:74a5; then
> +   set somevar=somevalue
> +fi
> +@end example
> +@end deffn
> +
>  @node tpm2_key_protector_init
>  @subsection tpm2_key_protector_init
>
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index f70e02e69..f18d2304d 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -1032,6 +1032,13 @@ module = {
>    enable = pci;
>  };
>
> +module = {
> +  name = testpci;
> +  common = commands/testpci.c;
> +
> +  enable = pci;
> +};
> +
>  module = {
>    name = memrw;
>    common = commands/memrw.c;
> diff --git a/grub-core/commands/testpci.c b/grub-core/commands/testpci.c
> new file mode 100644
> index 000000000..8af2a57a2
> --- /dev/null
> +++ b/grub-core/commands/testpci.c
> @@ -0,0 +1,194 @@
> +/* testpci.c - Test if PCI exists by ID.  */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2025  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/mm.h>
> +#include <grub/file.h>
> +#include <grub/normal.h>
> +#include <grub/pci.h>
> +
> +GRUB_MOD_LICENSE ("GPLv3+");
> +
> +static const struct grub_arg_option options[] = {
> +  {"file", 'f', 0, "read device list from file", "FILE", ARG_TYPE_STRING},
> +  {0, 0, 0, 0, 0, 0}
> +};
> +
> +struct grub_testpci_devlist {
> +  /* devices list */
> +  char** devices;
> +
> +  /* size of devices list */
> +  int devices_size;
> +
> +  /* number of allocated devices in the list <= devices_size */
> +  int n_devices;
> +
> +  bool found;
> +};
> +
> +static int
> +grub_testpci_iter (grub_pci_device_t dev  __attribute__ ((unused)),
> +                   grub_pci_id_t pciid,
> +                   void *data) {
> +
> +  struct grub_testpci_devlist* devlist = (struct
> grub_testpci_devlist*)data;
> +  char device[10];
> +
> +  grub_snprintf(device, sizeof(device),
> +                "%04x:%04x", pciid & 0xFFFF, pciid >> 16);
> +  for (int i = 0; i < devlist->n_devices; i++) {
> +    if (grub_strcasecmp(device, devlist->devices[i]) == 0) {
> +      devlist->found = true;
> +      return 1;
> +    }
> +  }
> +
> +  return 0;
> +}
> +
> +static void
> +testpci_clear_device_list(struct grub_testpci_devlist* devlist)
> +{
> +  for (int i = 0; i < devlist->n_devices; i++) {
> +    grub_free(devlist->devices[i]);
> +  }
> +  grub_free(devlist->devices);
> +  devlist->n_devices = 0;
> +  devlist->devices_size = 0;
> +}
> +
> +static grub_err_t
> +testpci_add_device_to_list(struct grub_testpci_devlist* devlist,
> +                           char* device)
> +{
> +  if (devlist->n_devices == devlist->devices_size) {
> +    devlist->devices_size *= 2;
> +    char** tmp = grub_realloc(devlist->devices,
> +                              devlist->devices_size * sizeof(char*));
> +    if (!tmp) {
> +      return grub_errno;
> +    }
> +    devlist->devices = tmp;
> +  }
> +  char* tmp = grub_strdup(device);
> +  if (!tmp) {
> +    return grub_errno;
> +  }
> +  devlist->devices[devlist->n_devices++] = tmp;
> +  return GRUB_ERR_NONE;
> +}
> +
> +static grub_err_t
> +grub_cmd_testpci (grub_extcmd_context_t ctxt,
> +                  int argc, char **args)
> +{
> +
> +  struct grub_testpci_devlist devlist;
> +
> +  devlist.found = false;
> +  devlist.n_devices = 0;
> +  devlist.devices_size = argc + (ctxt->state[0].set ? 5 : 0);
> +  devlist.devices = grub_malloc(devlist.devices_size * sizeof(char*));
> +  if (!(devlist.devices)) {
> +    return grub_errno;
> +  }
> +
> +  for (int i = 0; i < argc; i++) {
> +    grub_err_t err = testpci_add_device_to_list(&devlist, args[i]);
> +    if (err) {
> +      testpci_clear_device_list(&devlist);
> +      return err;
> +    }
> +  }
> +
> +  /* device list from file */
> +  if (ctxt->state[0].set) {
> +
> +    grub_file_t listfile = grub_file_open(ctxt->state[0].arg,
> GRUB_FILE_TYPE_DEVICE_LIST);
> +    if (listfile) {
> +
> +      char *buf = NULL;
> +      while (grub_free (buf), (buf = grub_file_getline (listfile))) {
> +
> +        /* remove comments */
> +        char *p = grub_strchr(buf, '#');
> +        if (p) {
> +          *p = '\0';
> +        }
> +
> +        /* remove suffix spaces */
> +        p = buf + grub_strlen(buf) - 1;
> +        while (p >= buf && *p && grub_isspace(*p)) {
> +          *p-- = '\0';
> +        }
> +
> +        /* remove prefix spaces */
> +        p = buf;
> +        while (*p && grub_isspace(*p)) {
> +          p++;
> +        }
> +
> +        /* ignore empty */
> +        if (*p == '\0')
> +          continue;
> +
> +        grub_err_t err = testpci_add_device_to_list(&devlist, p);
> +        if (err) {
> +          testpci_clear_device_list(&devlist);
> +          return err;
> +        }
> +      }
> +
> +      grub_file_close (listfile);
> +    } else {
> +      return grub_errno;
> +    }
> +  }
> +
> +  for (int d = 0 ; d < devlist.n_devices; d++) {
> +    if (grub_strlen(devlist.devices[d]) != 9 || devlist.devices[d][4] !=
> ':') {
> +      grub_printf("invalid device (%d) \"%s\", expected xxxx:xxxx\n", d,
> devlist.devices[d]);
> +      testpci_clear_device_list(&devlist);
> +      return grub_error(GRUB_ERR_BAD_ARGUMENT, "invalid device");
> +    }
> +  }
> +
> +  grub_pci_iterate (grub_testpci_iter, (void*)&devlist);
> +
> +  testpci_clear_device_list(&devlist);
> +
> +  return devlist.found ?
> +    GRUB_ERR_NONE : grub_error(GRUB_ERR_TEST_FAILURE, "device not found");
> +}
> +
> +static grub_extcmd_t cmd;
> +
> +GRUB_MOD_INIT(testpci)
> +{
> +  cmd = grub_register_extcmd ("testpci", grub_cmd_testpci, 0,
> +                              "[<devid> [...]] [--file <filename>]",
> +                              N_("Check if any of the PCI devices
> exist."), options);
> +}
> +
> +GRUB_MOD_FINI(testpci)
> +{
> +  grub_unregister_extcmd (cmd);
> +}
> diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c
> index 8d3e41360..0c7f45ec5 100644
> --- a/grub-core/kern/efi/sb.c
> +++ b/grub-core/kern/efi/sb.c
> @@ -168,6 +168,7 @@ shim_lock_verifier_init (grub_file_t io __attribute__
> ((unused)),
>      case GRUB_FILE_TYPE_THEME:
>      case GRUB_FILE_TYPE_GETTEXT_CATALOG:
>      case GRUB_FILE_TYPE_FS_SEARCH:
> +    case GRUB_FILE_TYPE_DEVICE_LIST:
>      case GRUB_FILE_TYPE_LOADENV:
>      case GRUB_FILE_TYPE_SAVEENV:
>      case GRUB_FILE_TYPE_VERIFY_SIGNATURE:
> diff --git a/include/grub/file.h b/include/grub/file.h
> index a5bf3a792..80ebaba90 100644
> --- a/include/grub/file.h
> +++ b/include/grub/file.h
> @@ -126,6 +126,8 @@ enum grub_file_type
>      GRUB_FILE_TYPE_FS_SEARCH,
>      GRUB_FILE_TYPE_AUDIO,
>      GRUB_FILE_TYPE_VBE_DUMP,
> +    /* device list for testpci command */
> +    GRUB_FILE_TYPE_DEVICE_LIST,
>
>      GRUB_FILE_TYPE_LOADENV,
>      GRUB_FILE_TYPE_SAVEENV,
> --
> 2.39.5
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
>
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to