[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH] xen: Add EFI_LOAD_OPTION support



When booting Xen via UEFI the Xen config file can contain multiple sections
each describing different boot options. It is currently only possible to choose
which section to boot with if Xen is started through an EFI Shell. As UEFI
provides a standard to pass optional arguments to an application in this patch
we make Xen properly parse this buffer, thus making it possible to have
separate EFI boot options present for the different config sections.

Signed-off-by: Tamas K Lengyel <lengyelt@xxxxxxxxxxxx>
---
Cc: Jan Beulich <jbeulich@xxxxxxxx>
Cc: openxt@xxxxxxxxxxxxxxxx
---
 xen/common/efi/boot.c    | 41 ++++++++++++++++++++++++++++++------
 xen/include/efi/efiapi.h | 54 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+), 6 deletions(-)

diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c
index 469bf980cc..b12261b662 100644
--- a/xen/common/efi/boot.c
+++ b/xen/common/efi/boot.c
@@ -236,7 +236,7 @@ static void __init DisplayUint(UINT64 Val, INTN Width)
     PrintStr(PrintString);
 }
 
-static size_t __init __maybe_unused wstrlen(const CHAR16 *s)
+static size_t __init wstrlen(const CHAR16 *s)
 {
     const CHAR16 *sc;
 
@@ -375,12 +375,40 @@ static void __init PrintErrMesg(const CHAR16 *mesg, 
EFI_STATUS ErrCode)
 
 static unsigned int __init get_argv(unsigned int argc, CHAR16 **argv,
                                     CHAR16 *cmdline, UINTN cmdsize,
-                                    CHAR16 **options)
+                                    CHAR16 **options, bool *elo_active)
 {
     CHAR16 *ptr = (CHAR16 *)(argv + argc + 1), *prev = NULL;
     bool prev_sep = true;
 
-    for ( ; cmdsize > sizeof(*cmdline) && *cmdline;
+    if ( cmdsize > sizeof(EFI_LOAD_OPTION) )
+    {
+        /*
+         * See include/efi/efiapi.h for more info about the following
+         */
+        EFI_LOAD_OPTION *elo = (EFI_LOAD_OPTION*)cmdline;
+
+        if ( elo->Attributes & LOAD_OPTION_ACTIVE )
+        {
+            UINT8 *_opts = (UINT8*)elo;
+            UINTN _cmdsize = cmdsize;
+
+            _opts += sizeof(elo->Attributes) + sizeof(elo->FilePathListLength);
+            _opts += sizeof(L'\0') + 2*wstrlen((CHAR16*)_opts) + 
elo->FilePathListLength;
+            _cmdsize -= _opts - (UINT8*)elo;
+
+            /*
+             * Sanity check the new cmdsize to avoid an underflow
+             */
+            if ( _cmdsize < cmdsize )
+            {
+                *elo_active = true;
+                cmdline = (CHAR16*)_opts;
+                cmdsize = _cmdsize;
+            }
+        }
+    }
+
+    for ( ; cmdsize >= sizeof(*cmdline) && *cmdline;
             cmdsize -= sizeof(*cmdline), ++cmdline )
     {
         bool cur_sep = *cmdline == L' ' || *cmdline == L'\t';
@@ -1074,6 +1102,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE 
*SystemTable)
     bool base_video = false;
     char *option_str;
     bool use_cfg_file;
+    bool elo_active = false;
 
     __set_bit(EFI_BOOT, &efi_flags);
     __set_bit(EFI_LOADER, &efi_flags);
@@ -1096,17 +1125,17 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE 
*SystemTable)
     if ( use_cfg_file )
     {
         argc = get_argv(0, NULL, loaded_image->LoadOptions,
-                        loaded_image->LoadOptionsSize, NULL);
+                        loaded_image->LoadOptionsSize, NULL, &elo_active);
         if ( argc > 0 &&
              efi_bs->AllocatePool(EfiLoaderData,
                                   (argc + 1) * sizeof(*argv) +
                                       loaded_image->LoadOptionsSize,
                                   (void **)&argv) == EFI_SUCCESS )
             get_argv(argc, argv, loaded_image->LoadOptions,
-                     loaded_image->LoadOptionsSize, &options);
+                     loaded_image->LoadOptionsSize, &options, &elo_active);
         else
             argc = 0;
-        for ( i = 1; i < argc; ++i )
+        for ( i = !elo_active; i < argc; ++i )
         {
             CHAR16 *ptr = argv[i];
 
diff --git a/xen/include/efi/efiapi.h b/xen/include/efi/efiapi.h
index a616d1238a..c3dc902ac5 100644
--- a/xen/include/efi/efiapi.h
+++ b/xen/include/efi/efiapi.h
@@ -922,5 +922,59 @@ typedef struct _EFI_SYSTEM_TABLE {
 
 } EFI_SYSTEM_TABLE;
 
+//
+// EFI Load Option. This data structure describes format of UEFI boot option 
variables.
+//
+// NOTE: EFI Load Option is a byte packed buffer of variable length fields.
+// The first two fields have fixed length. They are declared as members of the
+// EFI_LOAD_OPTION structure. All the other fields are variable length fields.
+// They are listed in the comment block below for reference purposes.
+//
+typedef struct __packed _EFI_LOAD_OPTION {
+  ///
+  /// The attributes for this load option entry. All unused bits must be zero
+  /// and are reserved by the UEFI specification for future growth.
+  ///
+  UINT32                           Attributes;
+  ///
+  /// Length in bytes of the FilePathList. OptionalData starts at offset
+  /// sizeof(UINT32) + sizeof(UINT16) + StrSize(Description) + 
FilePathListLength
+  /// of the EFI_LOAD_OPTION descriptor.
+  ///
+  UINT16                           FilePathListLength;
+  ///
+  /// The user readable description for the load option.
+  /// This field ends with a Null character.
+  ///
+  //CHAR16                         Description[];
+  ///
+  /// A packed array of UEFI device paths. The first element of the array is a
+  /// device path that describes the device and location of the Image for this
+  /// load option. The FilePathList[0] is specific to the device type. Other
+  /// device paths may optionally exist in the FilePathList, but their usage is
+  /// OSV specific. Each element in the array is variable length, and ends at
+  /// the device path end structure. Because the size of Description is
+  /// arbitrary, this data structure is not guaranteed to be aligned on a
+  /// natural boundary. This data structure may have to be copied to an aligned
+  /// natural boundary before it is used.
+  ///
+  //EFI_DEVICE_PATH_PROTOCOL       FilePathList[];
+  ///
+  /// The remaining bytes in the load option descriptor are a binary data 
buffer
+  /// that is passed to the loaded image. If the field is zero bytes long, a
+  /// NULL pointer is passed to the loaded image. The number of bytes in
+  /// OptionalData can be computed by subtracting the starting offset of
+  /// OptionalData from total size in bytes of the EFI_LOAD_OPTION.
+  ///
+  //UINT8                          OptionalData[];
+} EFI_LOAD_OPTION;
+
+//
+// EFI Load Options Attributes
+//
+#define LOAD_OPTION_ACTIVE              0x00000001
+#define LOAD_OPTION_FORCE_RECONNECT     0x00000002
+#define LOAD_OPTION_HIDDEN              0x00000008
+
 #endif
 
-- 
2.11.0


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.