diff --git a/.gitignore b/.gitignore
index 4acae17..dca6c5b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-SOURCES/gnulib-fixes.tar.gz
+SOURCES/gnulib-9f48fb992a3d7e96610c4ce8be969cff2d61a01b.tar.gz
 SOURCES/grub-2.06.tar.xz
 SOURCES/theme.tar.bz2
 SOURCES/unifont-13.0.06.pcf.gz
diff --git a/.grub2.metadata b/.grub2.metadata
index 88b5cc8..3b87954 100644
--- a/.grub2.metadata
+++ b/.grub2.metadata
@@ -1,4 +1,4 @@
-1a07692dfaa916675a92b1383885141f490f98d2 SOURCES/gnulib-fixes.tar.gz
+d08376d97163f99ce0d61fce160d6f7667c5c944 SOURCES/gnulib-9f48fb992a3d7e96610c4ce8be969cff2d61a01b.tar.gz
 c9f93f1e195ec7a5a21d36a13b469788c0b29f0f SOURCES/grub-2.06.tar.xz
 cf0b7763c528902da7e8b05cfa248f20c8825ce5 SOURCES/theme.tar.bz2
 3b39cb0830367171760ec536cab805abdbe08bc5 SOURCES/unifont-13.0.06.pcf.gz
diff --git a/README.debrand b/README.debrand
deleted file mode 100644
index 01c46d2..0000000
--- a/README.debrand
+++ /dev/null
@@ -1,2 +0,0 @@
-Warning: This package was configured for automatic debranding, but the changes
-failed to apply.
diff --git a/SOURCES/0007-Add-secureboot-support-on-efi-chainloader.patch b/SOURCES/0007-Add-secureboot-support-on-efi-chainloader.patch
index bfb5a9b..34ead63 100644
--- a/SOURCES/0007-Add-secureboot-support-on-efi-chainloader.patch
+++ b/SOURCES/0007-Add-secureboot-support-on-efi-chainloader.patch
@@ -164,18 +164,33 @@ following branches:
 
 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1347291
 Signed-off-by: Laszlo Ersek <lersek@redhat.com>
+
+Also:
+
+commit cc06f149fbd2d8c1da1e83173d21629ba97e0d92
+Author: Raymund Will <rw@suse.com>
+
+chainloader: Define machine types for RISC-V
+
+The commit "Add secureboot support on efi chainloader" didn't add machine
+types for RISC-V, so this patch adds them.
+
+Note, that grub-core/loader/riscv/linux.c is skipped because Linux is not
+supported yet. This patch might need a new revision once that's the case.
+
+Signed-off-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
 ---
  grub-core/kern/efi/efi.c           |  14 +-
  grub-core/loader/arm64/linux.c     |   4 +-
- grub-core/loader/efi/chainloader.c | 816 +++++++++++++++++++++++++++++++++----
+ grub-core/loader/efi/chainloader.c | 820 +++++++++++++++++++++++++++++++++----
  grub-core/loader/efi/linux.c       |  25 +-
  grub-core/loader/i386/efi/linux.c  |  17 +-
  include/grub/efi/linux.h           |   2 +-
  include/grub/efi/pe32.h            |  52 ++-
- 7 files changed, 840 insertions(+), 90 deletions(-)
+ 7 files changed, 844 insertions(+), 90 deletions(-)
 
 diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
-index 35b8f670602..4a2259aa1c7 100644
+index 35b8f67060..4a2259aa1c 100644
 --- a/grub-core/kern/efi/efi.c
 +++ b/grub-core/kern/efi/efi.c
 @@ -296,14 +296,20 @@ grub_efi_secure_boot (void)
@@ -204,7 +219,7 @@ index 35b8f670602..4a2259aa1c7 100644
    if (*secure_boot && !*setup_mode)
      ret = 1;
 diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
-index a312c668685..04994d5c67d 100644
+index a312c66868..04994d5c67 100644
 --- a/grub-core/loader/arm64/linux.c
 +++ b/grub-core/loader/arm64/linux.c
 @@ -284,6 +284,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
@@ -226,7 +241,7 @@ index a312c668685..04994d5c67d 100644
        grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
        goto fail;
 diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
-index 2bd80f4db3d..b54cf6986fc 100644
+index 2bd80f4db3..e6a8d4ad0e 100644
 --- a/grub-core/loader/efi/chainloader.c
 +++ b/grub-core/loader/efi/chainloader.c
 @@ -32,6 +32,8 @@
@@ -261,7 +276,7 @@ index 2bd80f4db3d..b54cf6986fc 100644
  
    grub_dl_unref (my_mod);
    return GRUB_ERR_NONE;
-@@ -213,20 +221,690 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
+@@ -213,20 +221,694 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
    return file_path;
  }
  
@@ -376,6 +391,10 @@ index 2bd80f4db3d..b54cf6986fc 100644
 +  GRUB_PE32_MACHINE_I386;
 +#elif defined(__ia64__)
 +  GRUB_PE32_MACHINE_IA64;
++#elif defined(__riscv) && (__riscv_xlen == 32)
++  GRUB_PE32_MACHINE_RISCV32;
++#elif defined(__riscv) && (__riscv_xlen == 64)
++  GRUB_PE32_MACHINE_RISCV64;
 +#else
 +#error this architecture is not supported by grub2
 +#endif
@@ -955,7 +974,7 @@ index 2bd80f4db3d..b54cf6986fc 100644
  
    if (argc == 0)
      return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
-@@ -238,15 +916,45 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+@@ -238,15 +920,45 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
    address = 0;
    image_handle = 0;
    file_path = 0;
@@ -1003,7 +1022,7 @@ index 2bd80f4db3d..b54cf6986fc 100644
    if (! dev)
      goto fail;
  
-@@ -283,17 +991,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+@@ -283,17 +995,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
    if (! file_path)
      goto fail;
  
@@ -1024,7 +1043,7 @@ index 2bd80f4db3d..b54cf6986fc 100644
  
    status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES,
  			      GRUB_EFI_LOADER_CODE,
-@@ -307,7 +1012,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+@@ -307,7 +1016,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
      }
  
    boot_image = (void *) ((grub_addr_t) address);
@@ -1033,7 +1052,7 @@ index 2bd80f4db3d..b54cf6986fc 100644
      {
        if (grub_errno == GRUB_ERR_NONE)
  	grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
-@@ -317,7 +1022,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+@@ -317,7 +1026,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
      }
  
  #if defined (__i386__) || defined (__x86_64__)
@@ -1042,7 +1061,7 @@ index 2bd80f4db3d..b54cf6986fc 100644
      {
        struct grub_macho_fat_header *head = boot_image;
        if (head->magic
-@@ -326,6 +1031,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+@@ -326,6 +1035,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
  	  grub_uint32_t i;
  	  struct grub_macho_fat_arch *archs
  	    = (struct grub_macho_fat_arch *) (head + 1);
@@ -1057,7 +1076,7 @@ index 2bd80f4db3d..b54cf6986fc 100644
  	  for (i = 0; i < grub_cpu_to_le32 (head->nfat_arch); i++)
  	    {
  	      if (GRUB_MACHO_CPUTYPE_IS_HOST_CURRENT (archs[i].cputype))
-@@ -340,79 +1053,39 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+@@ -340,79 +1057,39 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
  	      > ~grub_cpu_to_le32 (archs[i].size)
  	      || grub_cpu_to_le32 (archs[i].offset)
  	      + grub_cpu_to_le32 (archs[i].size)
@@ -1154,7 +1173,7 @@ index 2bd80f4db3d..b54cf6986fc 100644
    if (dev)
      grub_device_close (dev);
  
-@@ -424,6 +1097,9 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+@@ -424,6 +1101,9 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
    if (address)
      efi_call_2 (b->free_pages, address, pages);
  
@@ -1165,7 +1184,7 @@ index 2bd80f4db3d..b54cf6986fc 100644
  
    return grub_errno;
 diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
-index c24202a5dd1..c8ecce6dfd0 100644
+index c24202a5dd..c8ecce6dfd 100644
 --- a/grub-core/loader/efi/linux.c
 +++ b/grub-core/loader/efi/linux.c
 @@ -33,21 +33,34 @@ struct grub_efi_shim_lock
@@ -1210,7 +1229,7 @@ index c24202a5dd1..c8ecce6dfd0 100644
  
  #pragma GCC diagnostic push
 diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index bb2616a8092..6b24cbb9483 100644
+index bb2616a809..6b24cbb948 100644
 --- a/grub-core/loader/i386/efi/linux.c
 +++ b/grub-core/loader/i386/efi/linux.c
 @@ -117,6 +117,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
@@ -1278,7 +1297,7 @@ index bb2616a8092..6b24cbb9483 100644
      grub_file_close (file);
  
 diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
-index d9ede36773b..0033d9305a9 100644
+index d9ede36773..0033d9305a 100644
 --- a/include/grub/efi/linux.h
 +++ b/include/grub/efi/linux.h
 @@ -22,7 +22,7 @@
@@ -1291,7 +1310,7 @@ index d9ede36773b..0033d9305a9 100644
  grub_err_t
  EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset,
 diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
-index 0ed8781f037..a43adf27464 100644
+index 0ed8781f03..a43adf2746 100644
 --- a/include/grub/efi/pe32.h
 +++ b/include/grub/efi/pe32.h
 @@ -223,7 +223,11 @@ struct grub_pe64_optional_header
diff --git a/SOURCES/0010-re-write-.gitignore.patch b/SOURCES/0010-re-write-.gitignore.patch
index 74cb0da..b6fa0be 100644
--- a/SOURCES/0010-re-write-.gitignore.patch
+++ b/SOURCES/0010-re-write-.gitignore.patch
@@ -4,14 +4,14 @@ Date: Mon, 8 Jul 2019 12:55:29 +0200
 Subject: [PATCH] re-write .gitignore
 
 ---
- .gitignore                        | 152 ++++++++++++++++++++++++++++++++++++++
+ .gitignore                        | 150 ++++++++++++++++++++++++++++++++++++++
  docs/.gitignore                   |   5 ++
  grub-core/.gitignore              |  16 ++++
  grub-core/lib/.gitignore          |   1 +
  include/grub/gcrypt/.gitignore    |   2 +
  po/.gitignore                     |   5 ++
  util/bash-completion.d/.gitignore |   2 +
- 7 files changed, 183 insertions(+)
+ 7 files changed, 181 insertions(+)
  create mode 100644 docs/.gitignore
  create mode 100644 grub-core/.gitignore
  create mode 100644 grub-core/lib/.gitignore
@@ -20,10 +20,10 @@ Subject: [PATCH] re-write .gitignore
  create mode 100644 util/bash-completion.d/.gitignore
 
 diff --git a/.gitignore b/.gitignore
-index f6a1bd05175..594d0134d33 100644
+index f6a1bd0517..208d1d2325 100644
 --- a/.gitignore
 +++ b/.gitignore
-@@ -275,3 +275,155 @@ widthspec.bin
+@@ -275,3 +275,153 @@ widthspec.bin
  /xfs_test
  /xzcompress_test
  /zfs_test
@@ -152,8 +152,6 @@ index f6a1bd05175..594d0134d33 100644
 +/grub*-reboot.8
 +/grub*-render-label
 +/grub*-render-label.1
-+/grub*-rpm-sort
-+/grub*-rpm-sort.8
 +/grub*-script-check
 +/grub*-script-check.1
 +/grub*-set-bootflag
@@ -181,7 +179,7 @@ index f6a1bd05175..594d0134d33 100644
 +/widthspec.h
 diff --git a/docs/.gitignore b/docs/.gitignore
 new file mode 100644
-index 00000000000..e1d849ef95b
+index 0000000000..e1d849ef95
 --- /dev/null
 +++ b/docs/.gitignore
 @@ -0,0 +1,5 @@
@@ -192,7 +190,7 @@ index 00000000000..e1d849ef95b
 +/version*.texi
 diff --git a/grub-core/.gitignore b/grub-core/.gitignore
 new file mode 100644
-index 00000000000..2acce281159
+index 0000000000..2acce28115
 --- /dev/null
 +++ b/grub-core/.gitignore
 @@ -0,0 +1,16 @@
@@ -214,14 +212,14 @@ index 00000000000..2acce281159
 +/trigtables.c
 diff --git a/grub-core/lib/.gitignore b/grub-core/lib/.gitignore
 new file mode 100644
-index 00000000000..68154591404
+index 0000000000..6815459140
 --- /dev/null
 +++ b/grub-core/lib/.gitignore
 @@ -0,0 +1 @@
 +/libgcrypt-grub/
 diff --git a/include/grub/gcrypt/.gitignore b/include/grub/gcrypt/.gitignore
 new file mode 100644
-index 00000000000..8fbf5646246
+index 0000000000..8fbf564624
 --- /dev/null
 +++ b/include/grub/gcrypt/.gitignore
 @@ -0,0 +1,2 @@
@@ -229,7 +227,7 @@ index 00000000000..8fbf5646246
 +gcrypt.h
 diff --git a/po/.gitignore b/po/.gitignore
 new file mode 100644
-index 00000000000..f507e7741e3
+index 0000000000..f507e7741e
 --- /dev/null
 +++ b/po/.gitignore
 @@ -0,0 +1,5 @@
@@ -240,7 +238,7 @@ index 00000000000..f507e7741e3
 +/stamp-po
 diff --git a/util/bash-completion.d/.gitignore b/util/bash-completion.d/.gitignore
 new file mode 100644
-index 00000000000..6813a527ad3
+index 0000000000..6813a527ad
 --- /dev/null
 +++ b/util/bash-completion.d/.gitignore
 @@ -0,0 +1,2 @@
diff --git a/SOURCES/0011-IBM-client-architecture-CAS-reboot-support.patch b/SOURCES/0011-IBM-client-architecture-CAS-reboot-support.patch
index eaaf9a4..316b9eb 100644
--- a/SOURCES/0011-IBM-client-architecture-CAS-reboot-support.patch
+++ b/SOURCES/0011-IBM-client-architecture-CAS-reboot-support.patch
@@ -7,16 +7,20 @@ This is an implementation of IBM client architecture (CAS) reboot for GRUB.
 
 There are cases where the POWER firmware must reboot in order to support
 specific features requested by a kernel. The kernel calls
-ibm,client-architecture-support and it may either return or reboot with the new
-feature set. eg:
+ibm,client-architecture-support and it may either return or reboot with
+the new feature set. eg:
 
 Calling ibm,client-architecture-support.../
 Elapsed time since release of system processors: 70959 mins 50 secs
 Welcome to GRUB!
 
-Instead of return to the GRUB menu, it will check if the flag for CAS reboot is
-set. If so, grub will automatically boot the last booted kernel using the same
-parameters
+Instead of return to the GRUB menu, it will check if the flag for CAS
+reboot is set. If so, grub will automatically boot the last booted
+kernel using the same parameters
+
+Signed-off-by: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
+[rharwood@redhat.com: commit message rewrap]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  grub-core/kern/ieee1275/openfw.c | 63 ++++++++++++++++++++++++++++++++++++++++
  grub-core/normal/main.c          | 19 ++++++++++++
@@ -25,7 +29,7 @@ parameters
  4 files changed, 91 insertions(+)
 
 diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c
-index 4d493ab7661..3a6689abb11 100644
+index 4d493ab766..3a6689abb1 100644
 --- a/grub-core/kern/ieee1275/openfw.c
 +++ b/grub-core/kern/ieee1275/openfw.c
 @@ -591,3 +591,66 @@ grub_ieee1275_get_boot_dev (void)
@@ -96,7 +100,7 @@ index 4d493ab7661..3a6689abb11 100644
 +  return 0;
 +}
 diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
-index c4ebe9e22ad..70614de1565 100644
+index c4ebe9e22a..70614de156 100644
 --- a/grub-core/normal/main.c
 +++ b/grub-core/normal/main.c
 @@ -34,6 +34,9 @@
@@ -133,7 +137,7 @@ index c4ebe9e22ad..70614de1565 100644
        grub_errno = GRUB_ERR_NONE;
      }
 diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c
-index 25158407dd8..ad80399246a 100644
+index 25158407dd..ad80399246 100644
 --- a/grub-core/script/execute.c
 +++ b/grub-core/script/execute.c
 @@ -28,6 +28,9 @@
@@ -158,7 +162,7 @@ index 25158407dd8..ad80399246a 100644
      {
        char *line;
 diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
-index 73e2f464475..0a599607f31 100644
+index 73e2f46447..0a599607f3 100644
 --- a/include/grub/ieee1275/ieee1275.h
 +++ b/include/grub/ieee1275/ieee1275.h
 @@ -254,6 +254,8 @@ int EXPORT_FUNC(grub_ieee1275_devalias_next) (struct grub_ieee1275_devalias *ali
diff --git a/SOURCES/0012-for-ppc-reset-console-display-attr-when-clear-screen.patch b/SOURCES/0012-for-ppc-reset-console-display-attr-when-clear-screen.patch
index c8bb9d3..121af84 100644
--- a/SOURCES/0012-for-ppc-reset-console-display-attr-when-clear-screen.patch
+++ b/SOURCES/0012-for-ppc-reset-console-display-attr-when-clear-screen.patch
@@ -10,12 +10,14 @@ This should fix this bugzilla:
 https://bugzilla.redhat.com/show_bug.cgi?id=908519
 
 Signed-off-by: Peter Jones <pjones@redhat.com>
+Signed-off-by: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  grub-core/term/terminfo.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
 
 diff --git a/grub-core/term/terminfo.c b/grub-core/term/terminfo.c
-index 85ecf06b4df..05c88dcf49e 100644
+index 85ecf06b4d..05c88dcf49 100644
 --- a/grub-core/term/terminfo.c
 +++ b/grub-core/term/terminfo.c
 @@ -151,7 +151,7 @@ grub_terminfo_set_current (struct grub_term_output *term,
diff --git a/SOURCES/0013-Disable-GRUB-video-support-for-IBM-power-machines.patch b/SOURCES/0013-Disable-GRUB-video-support-for-IBM-power-machines.patch
index 430f600..917943f 100644
--- a/SOURCES/0013-Disable-GRUB-video-support-for-IBM-power-machines.patch
+++ b/SOURCES/0013-Disable-GRUB-video-support-for-IBM-power-machines.patch
@@ -5,6 +5,9 @@ Subject: [PATCH] Disable GRUB video support for IBM power machines
 
 Should fix the problem in bugzilla:
 https://bugzilla.redhat.com/show_bug.cgi?id=973205
+
+Signed-off-by: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  grub-core/kern/ieee1275/cmain.c  | 5 ++++-
  grub-core/video/ieee1275.c       | 9 ++++++---
@@ -12,7 +15,7 @@ https://bugzilla.redhat.com/show_bug.cgi?id=973205
  3 files changed, 12 insertions(+), 4 deletions(-)
 
 diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c
-index 20cbbd761ec..04df9d2c667 100644
+index 20cbbd761e..04df9d2c66 100644
 --- a/grub-core/kern/ieee1275/cmain.c
 +++ b/grub-core/kern/ieee1275/cmain.c
 @@ -90,7 +90,10 @@ grub_ieee1275_find_options (void)
@@ -28,7 +31,7 @@ index 20cbbd761ec..04df9d2c667 100644
    /* Old Macs have no key repeat, newer ones have fully working one.
       The ones inbetween when repeated key generates an escaoe sequence
 diff --git a/grub-core/video/ieee1275.c b/grub-core/video/ieee1275.c
-index 17a3dbbb575..b8e4b3feb32 100644
+index 17a3dbbb57..b8e4b3feb3 100644
 --- a/grub-core/video/ieee1275.c
 +++ b/grub-core/video/ieee1275.c
 @@ -352,9 +352,12 @@ static struct grub_video_adapter grub_video_ieee1275_adapter =
@@ -48,7 +51,7 @@ index 17a3dbbb575..b8e4b3feb32 100644
  
  GRUB_MOD_FINI(ieee1275_fb)
 diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
-index 0a599607f31..b5a1d49bbc3 100644
+index 0a599607f3..b5a1d49bbc 100644
 --- a/include/grub/ieee1275/ieee1275.h
 +++ b/include/grub/ieee1275/ieee1275.h
 @@ -148,6 +148,8 @@ enum grub_ieee1275_flag
diff --git a/SOURCES/0018-Migrate-PPC-from-Yaboot-to-Grub2.patch b/SOURCES/0018-Migrate-PPC-from-Yaboot-to-Grub2.patch
index ee8c7ab..1e310e9 100644
--- a/SOURCES/0018-Migrate-PPC-from-Yaboot-to-Grub2.patch
+++ b/SOURCES/0018-Migrate-PPC-from-Yaboot-to-Grub2.patch
@@ -3,8 +3,11 @@ From: Mark Hamzy <hamzy@us.ibm.com>
 Date: Wed, 28 Mar 2012 14:46:41 -0500
 Subject: [PATCH] Migrate PPC from Yaboot to Grub2
 
-Add configuration support for serial terminal consoles.  This will set the
-maximum screen size so that text is not overwritten.
+Add configuration support for serial terminal consoles.  This will set
+the maximum screen size so that text is not overwritten.
+
+Signed-off-by: Mark Hamzy <hamzy@us.ibm.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  Makefile.util.def              |   7 +++
  util/grub.d/20_ppc_terminfo.in | 114 +++++++++++++++++++++++++++++++++++++++++
@@ -12,7 +15,7 @@ maximum screen size so that text is not overwritten.
  create mode 100644 util/grub.d/20_ppc_terminfo.in
 
 diff --git a/Makefile.util.def b/Makefile.util.def
-index f8b356cc1fa..2c9b283a230 100644
+index f8b356cc1f..2c9b283a23 100644
 --- a/Makefile.util.def
 +++ b/Makefile.util.def
 @@ -508,6 +508,13 @@ script = {
@@ -31,7 +34,7 @@ index f8b356cc1fa..2c9b283a230 100644
    common = util/grub.d/30_os-prober.in;
 diff --git a/util/grub.d/20_ppc_terminfo.in b/util/grub.d/20_ppc_terminfo.in
 new file mode 100644
-index 00000000000..10d66586820
+index 0000000000..10d6658682
 --- /dev/null
 +++ b/util/grub.d/20_ppc_terminfo.in
 @@ -0,0 +1,114 @@
diff --git a/SOURCES/0019-Add-fw_path-variable-revised.patch b/SOURCES/0019-Add-fw_path-variable-revised.patch
index df9ef83..804938b 100644
--- a/SOURCES/0019-Add-fw_path-variable-revised.patch
+++ b/SOURCES/0019-Add-fw_path-variable-revised.patch
@@ -8,13 +8,16 @@ found. It was originally written by Matthew Garrett, and adapted to fix the
 "No modules are loaded on grub2 network boot" issue:
 
 https://bugzilla.redhat.com/show_bug.cgi?id=857936
+
+Signed-off-by: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
 ---
  grub-core/kern/main.c   | 13 ++++++-------
  grub-core/normal/main.c | 25 ++++++++++++++++++++++++-
  2 files changed, 30 insertions(+), 8 deletions(-)
 
 diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
-index 73967e2f5b0..d1de9fa6873 100644
+index 73967e2f5b..d1de9fa687 100644
 --- a/grub-core/kern/main.c
 +++ b/grub-core/kern/main.c
 @@ -128,16 +128,15 @@ grub_set_prefix_and_root (void)
@@ -41,7 +44,7 @@ index 73967e2f5b0..d1de9fa6873 100644
      }
  
 diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
-index 70614de1565..62571e6dfcc 100644
+index 70614de156..62571e6dfc 100644
 --- a/grub-core/normal/main.c
 +++ b/grub-core/normal/main.c
 @@ -339,7 +339,30 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
diff --git a/SOURCES/0023-Don-t-write-messages-to-the-screen.patch b/SOURCES/0023-Don-t-write-messages-to-the-screen.patch
deleted file mode 100644
index 01d0264..0000000
--- a/SOURCES/0023-Don-t-write-messages-to-the-screen.patch
+++ /dev/null
@@ -1,176 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: William Jon McCann <william.jon.mccann@gmail.com>
-Date: Wed, 15 May 2013 13:30:20 -0400
-Subject: [PATCH] Don't write messages to the screen
-
-Writing messages to the screen before the menus or boot splash
-happens so quickly it looks like something is wrong and isn't
-very appealing.
----
- grub-core/gettext/gettext.c       | 25 +++++--------------------
- grub-core/kern/main.c             |  5 -----
- grub-core/boot/i386/pc/boot.S     |  3 ---
- grub-core/boot/i386/pc/diskboot.S |  5 -----
- util/grub.d/10_linux.in           |  7 -------
- 5 files changed, 5 insertions(+), 40 deletions(-)
-
-diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c
-index 4d02e62c109..84d520cd494 100644
---- a/grub-core/gettext/gettext.c
-+++ b/grub-core/gettext/gettext.c
-@@ -434,16 +434,12 @@ static char *
- grub_gettext_env_write_lang (struct grub_env_var *var
- 			     __attribute__ ((unused)), const char *val)
- {
--  grub_err_t err;
-+  grub_err_t __attribute__((__unused__)) err;
-   err = grub_gettext_init_ext (&main_context, val, grub_env_get ("locale_dir"),
- 			       grub_env_get ("prefix"));
--  if (err)
--    grub_print_error ();
- 
-   err = grub_gettext_init_ext (&secondary_context, val,
- 			       grub_env_get ("secondary_locale_dir"), 0);
--  if (err)
--    grub_print_error ();
- 
-   return grub_strdup (val);
- }
-@@ -451,23 +447,19 @@ grub_gettext_env_write_lang (struct grub_env_var *var
- void
- grub_gettext_reread_prefix (const char *val)
- {
--  grub_err_t err;
-+  grub_err_t __attribute__((__unused__)) err;
-   err = grub_gettext_init_ext (&main_context, grub_env_get ("lang"), 
- 			       grub_env_get ("locale_dir"),
- 			       val);
--  if (err)
--    grub_print_error ();
- }
- 
- static char *
- read_main (struct grub_env_var *var
- 	   __attribute__ ((unused)), const char *val)
- {
--  grub_err_t err;
-+  grub_err_t __attribute__((__unused__)) err;
-   err = grub_gettext_init_ext (&main_context, grub_env_get ("lang"), val,
- 			       grub_env_get ("prefix"));
--  if (err)
--    grub_print_error ();
-   return grub_strdup (val);
- }
- 
-@@ -475,12 +467,9 @@ static char *
- read_secondary (struct grub_env_var *var
- 		__attribute__ ((unused)), const char *val)
- {
--  grub_err_t err;
-+  grub_err_t __attribute__((__unused__)) err;
-   err = grub_gettext_init_ext (&secondary_context, grub_env_get ("lang"), val,
- 			       0);
--  if (err)
--    grub_print_error ();
--
-   return grub_strdup (val);
- }
- 
-@@ -500,18 +489,14 @@ grub_cmd_translate (grub_command_t cmd __attribute__ ((unused)),
- GRUB_MOD_INIT (gettext)
- {
-   const char *lang;
--  grub_err_t err;
-+  grub_err_t __attribute__((__unused__)) err;
- 
-   lang = grub_env_get ("lang");
- 
-   err = grub_gettext_init_ext (&main_context, lang, grub_env_get ("locale_dir"),
- 			       grub_env_get ("prefix"));
--  if (err)
--    grub_print_error ();
-   err = grub_gettext_init_ext (&secondary_context, lang,
- 			       grub_env_get ("secondary_locale_dir"), 0);
--  if (err)
--    grub_print_error ();
- 
-   grub_register_variable_hook ("locale_dir", NULL, read_main);
-   grub_register_variable_hook ("secondary_locale_dir", NULL, read_secondary);
-diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
-index d1de9fa6873..48058d983ce 100644
---- a/grub-core/kern/main.c
-+++ b/grub-core/kern/main.c
-@@ -269,11 +269,6 @@ grub_main (void)
- 
-   grub_boot_time ("After machine init.");
- 
--  /* Hello.  */
--  grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
--  grub_printf ("Welcome to GRUB!\n\n");
--  grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
--
-   /* Init verifiers API. */
-   grub_verifiers_init ();
- 
-diff --git a/grub-core/boot/i386/pc/boot.S b/grub-core/boot/i386/pc/boot.S
-index 2bd0b2d2866..ea167fe1206 100644
---- a/grub-core/boot/i386/pc/boot.S
-+++ b/grub-core/boot/i386/pc/boot.S
-@@ -249,9 +249,6 @@ real_start:
- 	/* save drive reference first thing! */
- 	pushw	%dx
- 
--	/* print a notification message on the screen */
--	MSG(notification_string)
--
- 	/* set %si to the disk address packet */
- 	movw	$disk_address_packet, %si
- 
-diff --git a/grub-core/boot/i386/pc/diskboot.S b/grub-core/boot/i386/pc/diskboot.S
-index c1addc0df29..68d31de0c4c 100644
---- a/grub-core/boot/i386/pc/diskboot.S
-+++ b/grub-core/boot/i386/pc/diskboot.S
-@@ -50,11 +50,6 @@ _start:
- 	/* save drive reference first thing! */
- 	pushw	%dx
- 
--	/* print a notification message on the screen */
--	pushw	%si
--	MSG(notification_string)
--	popw	%si
--
- 	/* this sets up for the first run through "bootloop" */
- 	movw	$LOCAL(firstlist), %di
- 
-diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
-index dc75a1c30bf..ad2ac4b078d 100644
---- a/util/grub.d/10_linux.in
-+++ b/util/grub.d/10_linux.in
-@@ -138,27 +138,20 @@ linux_entry ()
-     fi
-     printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/"
-   fi
--  message="$(gettext_printf "Loading Linux %s ..." ${version})"
-   sed "s/^/$submenu_indentation/" << EOF
--	echo	'$(echo "$message" | grub_quote)'
- 	linux	${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
- EOF
-   if test -n "${initrd}" ; then
--    # TRANSLATORS: ramdisk isn't identifier. Should be translated.
--    message="$(gettext_printf "Loading initial ramdisk ...")"
-     initrd_path=
-     for i in ${initrd}; do
-       initrd_path="${initrd_path} ${rel_dirname}/${i}"
-     done
-     sed "s/^/$submenu_indentation/" << EOF
--	echo	'$(echo "$message" | grub_quote)'
- 	initrd	$(echo $initrd_path)
- EOF
-   fi
-   if test -n "${fdt}" ; then
--    message="$(gettext_printf "Loading fdt ...")"
-     sed "s/^/$submenu_indentation/" << EOF
--	echo	'$(echo "$message" | grub_quote)'
- 	devicetree	${rel_dirname}/${fdt}
- EOF
-   fi
diff --git a/SOURCES/0023-Enable-pager-by-default.-985860.patch b/SOURCES/0023-Enable-pager-by-default.-985860.patch
new file mode 100644
index 0000000..63cf787
--- /dev/null
+++ b/SOURCES/0023-Enable-pager-by-default.-985860.patch
@@ -0,0 +1,23 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 28 Oct 2013 10:09:27 -0400
+Subject: [PATCH] Enable pager by default. (#985860)
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub.d/00_header.in | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
+index 93a90233ea..858b526c92 100644
+--- a/util/grub.d/00_header.in
++++ b/util/grub.d/00_header.in
+@@ -43,6 +43,8 @@ if [ "x${GRUB_DEFAULT_BUTTON}" = "xsaved" ] ; then GRUB_DEFAULT_BUTTON='${saved_
+ if [ "x${GRUB_TIMEOUT_BUTTON}" = "x" ] ; then GRUB_TIMEOUT_BUTTON="$GRUB_TIMEOUT" ; fi
+ 
+ cat << EOF
++set pager=1
++
+ if [ -s \$prefix/grubenv ]; then
+   load_env
+ fi
diff --git a/SOURCES/0024-Don-t-print-GNU-GRUB-header.patch b/SOURCES/0024-Don-t-print-GNU-GRUB-header.patch
deleted file mode 100644
index c903fd4..0000000
--- a/SOURCES/0024-Don-t-print-GNU-GRUB-header.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: William Jon McCann <william.jon.mccann@gmail.com>
-Date: Wed, 15 May 2013 13:53:48 -0400
-Subject: [PATCH] Don't print GNU GRUB header
-
-No one cares.
----
- grub-core/normal/main.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
-diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
-index 7ca2e5400b1..5d5f7b539f5 100644
---- a/grub-core/normal/main.c
-+++ b/grub-core/normal/main.c
-@@ -208,15 +208,16 @@ read_config_file (const char *config)
- /* Initialize the screen.  */
- void
- grub_normal_init_page (struct grub_term_output *term,
--		       int y)
-+		       int y __attribute__((__unused__)))
- {
-+  grub_term_cls (term);
-+
-+#if 0
-   grub_ssize_t msg_len;
-   int posx;
-   char *msg_formatted;
-   grub_uint32_t *unicode_msg;
-   grub_uint32_t *last_position;
-- 
--  grub_term_cls (term);
- 
-   msg_formatted = grub_xasprintf (_("GNU GRUB  version %s"), PACKAGE_VERSION);
-   if (!msg_formatted)
-@@ -241,6 +242,7 @@ grub_normal_init_page (struct grub_term_output *term,
-   grub_putcode ('\n', term);
-   grub_putcode ('\n', term);
-   grub_free (unicode_msg);
-+#endif
- }
- 
- static void
diff --git a/SOURCES/0024-Don-t-say-GNU-Linux-in-generated-menus.patch b/SOURCES/0024-Don-t-say-GNU-Linux-in-generated-menus.patch
new file mode 100644
index 0000000..5b96784
--- /dev/null
+++ b/SOURCES/0024-Don-t-say-GNU-Linux-in-generated-menus.patch
@@ -0,0 +1,85 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 14 Mar 2011 14:27:42 -0400
+Subject: [PATCH] Don't say "GNU/Linux" in generated menus.
+
+[rharwood: say it even less]
+---
+ grub-core/normal/main.c         | 2 +-
+ tests/util/grub-shell-tester.in | 2 +-
+ tests/util/grub-shell.in        | 2 +-
+ util/grub.d/10_linux.in         | 4 ++--
+ util/grub.d/20_linux_xen.in     | 4 ++--
+ 5 files changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index 7ca2e5400b..98372217ad 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -218,7 +218,7 @@ grub_normal_init_page (struct grub_term_output *term,
+  
+   grub_term_cls (term);
+ 
+-  msg_formatted = grub_xasprintf (_("GNU GRUB  version %s"), PACKAGE_VERSION);
++  msg_formatted = grub_xasprintf (_("GRUB version %s"), PACKAGE_VERSION);
+   if (!msg_formatted)
+     return;
+  
+diff --git a/tests/util/grub-shell-tester.in b/tests/util/grub-shell-tester.in
+index 8a87109b15..9a4319d4f4 100644
+--- a/tests/util/grub-shell-tester.in
++++ b/tests/util/grub-shell-tester.in
+@@ -56,7 +56,7 @@ for option in "$@"; do
+ 	usage
+ 	exit 0 ;;
+     -v | --version)
+-	echo "$0 (GNU GRUB ${PACKAGE_VERSION})"
++	echo "$0 (GRUB ${PACKAGE_VERSION})"
+ 	exit 0 ;;
+     --modules=*)
+ 	ms=`echo "$option" | sed -e 's/--modules=//'`
+diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in
+index 93e9f51484..ec1182bf93 100644
+--- a/tests/util/grub-shell.in
++++ b/tests/util/grub-shell.in
+@@ -209,7 +209,7 @@ for option in "$@"; do
+ 	usage
+ 	exit 0 ;;
+     -v | --version)
+-	echo "$0 (GNU GRUB ${PACKAGE_VERSION})"
++	echo "$0 (GRUB ${PACKAGE_VERSION})"
+ 	exit 0 ;;
+     --trim)
+ 	trim=1
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index dc75a1c30b..4a499c53a6 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -29,9 +29,9 @@ export TEXTDOMAINDIR="@localedir@"
+ CLASS="--class gnu-linux --class gnu --class os"
+ 
+ if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
+-  OS=GNU/Linux
++  OS="$(sed 's, release .*$,,g' /etc/system-release)"
+ else
+-  OS="${GRUB_DISTRIBUTOR} GNU/Linux"
++  OS="${GRUB_DISTRIBUTOR}"
+   CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}"
+ fi
+ 
+diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in
+index 3b1f470492..ada20775a1 100644
+--- a/util/grub.d/20_linux_xen.in
++++ b/util/grub.d/20_linux_xen.in
+@@ -29,9 +29,9 @@ export TEXTDOMAINDIR="@localedir@"
+ CLASS="--class gnu-linux --class gnu --class os --class xen"
+ 
+ if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
+-  OS=GNU/Linux
++  OS="$(sed 's, release .*$,,g' /etc/system-release)"
+ else
+-  OS="${GRUB_DISTRIBUTOR} GNU/Linux"
++  OS="${GRUB_DISTRIBUTOR}"
+   CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}"
+ fi
+ 
diff --git a/SOURCES/0025-Add-.eh_frame-to-list-of-relocations-stripped.patch b/SOURCES/0025-Add-.eh_frame-to-list-of-relocations-stripped.patch
new file mode 100644
index 0000000..0532a04
--- /dev/null
+++ b/SOURCES/0025-Add-.eh_frame-to-list-of-relocations-stripped.patch
@@ -0,0 +1,22 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Fedora Ninjas <grub2-owner@fedoraproject.org>
+Date: Mon, 13 Jan 2014 21:50:59 -0500
+Subject: [PATCH] Add .eh_frame to list of relocations stripped
+
+---
+ conf/Makefile.common | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/conf/Makefile.common b/conf/Makefile.common
+index 2a1a886f6d..191b1a70c6 100644
+--- a/conf/Makefile.common
++++ b/conf/Makefile.common
+@@ -38,7 +38,7 @@ CFLAGS_KERNEL = $(CFLAGS_PLATFORM) -ffreestanding
+ LDFLAGS_KERNEL = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC)
+ CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1
+ CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
+-STRIPFLAGS_KERNEL = -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx
++STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx
+ 
+ CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding
+ LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d
diff --git a/SOURCES/0025-Don-t-add-to-highlighted-row.patch b/SOURCES/0025-Don-t-add-to-highlighted-row.patch
deleted file mode 100644
index b83f543..0000000
--- a/SOURCES/0025-Don-t-add-to-highlighted-row.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: William Jon McCann <william.jon.mccann@gmail.com>
-Date: Wed, 15 May 2013 17:49:45 -0400
-Subject: [PATCH] Don't add '*' to highlighted row
-
-It is already highlighted.
----
- grub-core/normal/menu_text.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
-index 18240e76cea..65deafda531 100644
---- a/grub-core/normal/menu_text.c
-+++ b/grub-core/normal/menu_text.c
-@@ -242,7 +242,7 @@ print_entry (int y, int highlight, grub_menu_entry_t entry,
-       unicode_title[i] = ' ';
- 
-   if (data->geo.num_entries > 1)
--    grub_putcode (highlight ? '*' : ' ', data->term);
-+    grub_putcode (' ', data->term);
- 
-   grub_print_ucs4_menu (unicode_title,
- 			unicode_title + len,
diff --git a/SOURCES/0026-Don-t-require-a-password-to-boot-entries-generated-b.patch b/SOURCES/0026-Don-t-require-a-password-to-boot-entries-generated-b.patch
new file mode 100644
index 0000000..89887c1
--- /dev/null
+++ b/SOURCES/0026-Don-t-require-a-password-to-boot-entries-generated-b.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 11 Feb 2014 11:14:50 -0500
+Subject: [PATCH] Don't require a password to boot entries generated by
+ grub-mkconfig.
+
+When we set a password, we just want that to mean you can't /edit/ an entry.
+
+Resolves: rhbz#1030176
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub.d/10_linux.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 4a499c53a6..cf8d118698 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -26,7 +26,7 @@ datarootdir="@datarootdir@"
+ export TEXTDOMAIN=@PACKAGE@
+ export TEXTDOMAINDIR="@localedir@"
+ 
+-CLASS="--class gnu-linux --class gnu --class os"
++CLASS="--class gnu-linux --class gnu --class os --unrestricted"
+ 
+ if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
+   OS="$(sed 's, release .*$,,g' /etc/system-release)"
diff --git a/SOURCES/0026-Message-string-cleanups.patch b/SOURCES/0026-Message-string-cleanups.patch
deleted file mode 100644
index e23ee1a..0000000
--- a/SOURCES/0026-Message-string-cleanups.patch
+++ /dev/null
@@ -1,68 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: William Jon McCann <william.jon.mccann@gmail.com>
-Date: Fri, 7 Jun 2013 11:09:04 -0400
-Subject: [PATCH] Message string cleanups
-
-Make use of terminology consistent. Remove jargon.
----
- grub-core/normal/menu_text.c | 21 +++++++++------------
- 1 file changed, 9 insertions(+), 12 deletions(-)
-
-diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
-index 65deafda531..cc5837ed2b8 100644
---- a/grub-core/normal/menu_text.c
-+++ b/grub-core/normal/menu_text.c
-@@ -157,9 +157,8 @@ print_message (int nested, int edit, struct grub_term_output *term, int dry_run)
- 
-   if (edit)
-     {
--      ret += grub_print_message_indented_real (_("Minimum Emacs-like screen editing is \
--supported. TAB lists completions. Press Ctrl-x or F10 to boot, Ctrl-c or F2 for a \
--command-line or ESC to discard edits and return to the GRUB menu."),
-+      ret += grub_print_message_indented_real (_("Press Ctrl-x or F10 to start, Ctrl-c or F2 for a \
-+command prompt or Escape to discard edits and return to the menu. Pressing Tab lists possible completions."),
- 					       STANDARD_MARGIN, STANDARD_MARGIN,
- 					       term, dry_run);
-     }
-@@ -167,8 +166,8 @@ command-line or ESC to discard edits and return to the GRUB menu."),
-     {
-       char *msg_translated;
- 
--      msg_translated = grub_xasprintf (_("Use the %C and %C keys to select which "
--					 "entry is highlighted."),
-+      msg_translated = grub_xasprintf (_("Use the %C and %C keys to change the "
-+					 "selection."),
- 				       GRUB_UNICODE_UPARROW,
- 				       GRUB_UNICODE_DOWNARROW);
-       if (!msg_translated)
-@@ -181,17 +180,15 @@ command-line or ESC to discard edits and return to the GRUB menu."),
-       if (nested)
- 	{
- 	  ret += grub_print_message_indented_real
--	    (_("Press enter to boot the selected OS, "
--	       "`e' to edit the commands before booting "
--	       "or `c' for a command-line. ESC to return previous menu."),
-+	    (_("Press 'e' to edit the selected item, "
-+	       "or 'c' for a command prompt. Press Escape to return to the previous menu."),
- 	     STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
- 	}
-       else
- 	{
- 	  ret += grub_print_message_indented_real
--	    (_("Press enter to boot the selected OS, "
--	       "`e' to edit the commands before booting "
--	       "or `c' for a command-line."),
-+	    (_("Press 'e' to edit the selected item, "
-+	       "or 'c' for a command prompt."),
- 	     STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
- 	}	
-     }
-@@ -443,7 +440,7 @@ menu_text_print_timeout (int timeout, void *dataptr)
-       || data->timeout_msg == TIMEOUT_TERSE_NO_MARGIN)
-     msg_translated = grub_xasprintf (_("%ds"), timeout);
-   else
--    msg_translated = grub_xasprintf (_("The highlighted entry will be executed automatically in %ds."), timeout);
-+    msg_translated = grub_xasprintf (_("The selected entry will be started automatically in %ds."), timeout);
-   if (!msg_translated)
-     {
-       grub_print_error ();
diff --git a/SOURCES/0027-Fix-border-spacing-now-that-we-aren-t-displaying-it.patch b/SOURCES/0027-Fix-border-spacing-now-that-we-aren-t-displaying-it.patch
deleted file mode 100644
index 920ef79..0000000
--- a/SOURCES/0027-Fix-border-spacing-now-that-we-aren-t-displaying-it.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: William Jon McCann <william.jon.mccann@gmail.com>
-Date: Fri, 7 Jun 2013 14:08:23 -0400
-Subject: [PATCH] Fix border spacing now that we aren't displaying it
-
----
- grub-core/normal/menu_text.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
-index cc5837ed2b8..b49835a9af7 100644
---- a/grub-core/normal/menu_text.c
-+++ b/grub-core/normal/menu_text.c
-@@ -331,12 +331,12 @@ grub_menu_init_page (int nested, int edit,
-   int empty_lines = 1;
-   int version_msg = 1;
- 
--  geo->border = 1;
--  geo->first_entry_x = 1 /* margin */ + 1 /* border */;
-+  geo->border = 0;
-+  geo->first_entry_x = 0 /* margin */ + 0 /* border */;
-   geo->entry_width = grub_term_width (term) - 5;
- 
-   geo->first_entry_y = 2 /* two empty lines*/
--    + 1 /* GNU GRUB version text  */ + 1 /* top border */;
-+    + 0 /* GNU GRUB version text  */ + 1 /* top border */;
- 
-   geo->timeout_lines = 2;
- 
diff --git a/SOURCES/0027-use-fw_path-prefix-when-fallback-searching-for-grub-.patch b/SOURCES/0027-use-fw_path-prefix-when-fallback-searching-for-grub-.patch
new file mode 100644
index 0000000..1da91e1
--- /dev/null
+++ b/SOURCES/0027-use-fw_path-prefix-when-fallback-searching-for-grub-.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Fedora Ninjas <grub2-owner@fedoraproject.org>
+Date: Wed, 19 Feb 2014 15:58:43 -0500
+Subject: [PATCH] use fw_path prefix when fallback searching for grub config
+
+When PXE booting via UEFI firmware, grub was searching for grub.cfg
+in the fw_path directory where the grub application was found. If
+that didn't exist, a fallback search would look for config file names
+based on MAC and IP address. However, the search would look in the
+prefix directory which may not be the same fw_path. This patch
+changes that behavior to use the fw_path directory for the fallback
+search. Only if fw_path is NULL will the prefix directory be searched.
+
+Signed-off-by: Mark Salter <msalter@redhat.com>
+---
+ grub-core/normal/main.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index 98372217ad..bf24e65713 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -347,7 +347,7 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
+       char *config;
+       const char *prefix, *fw_path;
+ 
+-      fw_path = grub_env_get ("fw_path");
++      prefix = fw_path = grub_env_get ("fw_path");
+       if (fw_path)
+ 	{
+ 	  config = grub_xasprintf ("%s/grub.cfg", fw_path);
+@@ -370,7 +370,8 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
+ 	    }
+ 	}
+ 
+-      prefix = grub_env_get ("prefix");
++      if (! prefix)
++	      prefix = grub_env_get ("prefix");
+       if (prefix)
+         {
+           grub_size_t config_len;
diff --git a/SOURCES/0028-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch b/SOURCES/0028-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch
new file mode 100644
index 0000000..0d77281
--- /dev/null
+++ b/SOURCES/0028-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch
@@ -0,0 +1,127 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 8 Jul 2019 17:33:22 +0200
+Subject: [PATCH] Try mac/guid/etc before grub.cfg on tftp config files.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/normal/main.c | 97 ++++++++++++++++++++++++++-----------------------
+ 1 file changed, 51 insertions(+), 46 deletions(-)
+
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index bf24e65713..0a99768f75 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -345,61 +345,66 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
+       /* Guess the config filename. It is necessary to make CONFIG static,
+ 	 so that it won't get broken by longjmp.  */
+       char *config;
+-      const char *prefix, *fw_path;
+-
+-      prefix = fw_path = grub_env_get ("fw_path");
+-      if (fw_path)
+-	{
+-	  config = grub_xasprintf ("%s/grub.cfg", fw_path);
+-	  if (config)
+-	    {
+-	      grub_file_t file;
+-
+-	      file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG);
+-	      if (file)
+-		{
+-		  grub_file_close (file);
+-		  grub_enter_normal_mode (config);
+-		}
+-              else
+-                {
+-                  /*  Ignore all errors.  */
+-                  grub_errno = 0;
+-                }
+-	      grub_free (config);
+-	    }
+-	}
++      const char *prefix;
++      const char *net_search_cfg;
++      int disable_net_search = 0;
+ 
++      prefix = grub_env_get ("fw_path");
+       if (! prefix)
+ 	      prefix = grub_env_get ("prefix");
++
++      net_search_cfg = grub_env_get ("feature_net_search_cfg");
++      if (net_search_cfg && net_search_cfg[0] == 'n')
++	      disable_net_search = 1;
++
+       if (prefix)
+         {
+-          grub_size_t config_len;
+-          int disable_net_search = 0;
+-          const char *net_search_cfg;
+-
+-          config_len = grub_strlen (prefix) +
+-                       sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
+-          config = grub_malloc (config_len);
+-
+-          if (!config)
+-            goto quit;
+-
+-          grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
+-
+-          net_search_cfg = grub_env_get ("feature_net_search_cfg");
+-          if (net_search_cfg && net_search_cfg[0] == 'n')
+-            disable_net_search = 1;
+-
+           if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0 &&
+               !disable_net_search)
+-            grub_net_search_config_file (config);
++            {
++              grub_size_t config_len;
++              config_len = grub_strlen (prefix) +
++                sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
++              config = grub_malloc (config_len);
+ 
+-	  grub_enter_normal_mode (config);
+-	  grub_free (config);
+-	}
++              if (! config)
++                goto quit;
++
++              grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
++
++              grub_net_search_configfile (config);
++
++              grub_enter_normal_mode (config);
++              grub_free (config);
++              config = NULL;
++            }
++
++          if (!config)
++            {
++              config = grub_xasprintf ("%s/grub.cfg", prefix);
++              if (config)
++                {
++                  grub_file_t file;
++
++                  file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG);
++                  if (file)
++                    {
++                      grub_file_close (file);
++                      grub_enter_normal_mode (config);
++                    }
++                  else
++                    {
++                      /*  Ignore all errors.  */
++                      grub_errno = 0;
++                    }
++                  grub_free (config);
++                }
++            }
++        }
+       else
+-	grub_enter_normal_mode (0);
++        {
++          grub_enter_normal_mode (0);
++        }
+     }
+   else
+     grub_enter_normal_mode (argv[0]);
diff --git a/SOURCES/0028-Use-the-correct-indentation-for-the-term-help-text.patch b/SOURCES/0028-Use-the-correct-indentation-for-the-term-help-text.patch
deleted file mode 100644
index 0ce3b04..0000000
--- a/SOURCES/0028-Use-the-correct-indentation-for-the-term-help-text.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: William Jon McCann <william.jon.mccann@gmail.com>
-Date: Fri, 7 Jun 2013 14:08:49 -0400
-Subject: [PATCH] Use the correct indentation for the term help text
-
-That is consistent with the menu help text
----
- grub-core/normal/main.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
-index 5d5f7b539f5..ec1cd257397 100644
---- a/grub-core/normal/main.c
-+++ b/grub-core/normal/main.c
-@@ -440,8 +440,8 @@ grub_normal_reader_init (int nested)
-     grub_normal_init_page (term, 1);
-     grub_term_setcursor (term, 1);
- 
--    if (grub_term_width (term) > 3 + STANDARD_MARGIN + 20)
--      grub_print_message_indented (msg_formatted, 3, STANDARD_MARGIN, term);
-+    if (grub_term_width (term) > 2 * STANDARD_MARGIN + 20)
-+      grub_print_message_indented (msg_formatted, STANDARD_MARGIN, STANDARD_MARGIN, term);
-     else
-       grub_print_message_indented (msg_formatted, 0, 0, term);
-     grub_putcode ('\n', term);
diff --git a/SOURCES/0029-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch b/SOURCES/0029-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch
new file mode 100644
index 0000000..f22e6f9
--- /dev/null
+++ b/SOURCES/0029-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 4 Sep 2014 14:23:23 -0400
+Subject: [PATCH] Generate OS and CLASS in 10_linux from /etc/os-release
+
+This makes us use pretty names in the titles we generate in
+grub2-mkconfig when GRUB_DISTRIBUTOR isn't set.
+
+Resolves: rhbz#996794
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub.d/10_linux.in | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index cf8d118698..5f6d3c8d52 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -29,7 +29,8 @@ export TEXTDOMAINDIR="@localedir@"
+ CLASS="--class gnu-linux --class gnu --class os --unrestricted"
+ 
+ if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
+-  OS="$(sed 's, release .*$,,g' /etc/system-release)"
++  OS="$(eval $(grep PRETTY_NAME /etc/os-release) ; echo ${PRETTY_NAME})"
++  CLASS="--class $(eval $(grep '^ID_LIKE=\|^ID=' /etc/os-release) ; [ -n "${ID_LIKE}" ] && echo ${ID_LIKE} || echo ${ID}) ${CLASS}"
+ else
+   OS="${GRUB_DISTRIBUTOR}"
+   CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}"
diff --git a/SOURCES/0029-Indent-menu-entries.patch b/SOURCES/0029-Indent-menu-entries.patch
deleted file mode 100644
index 7e588fd..0000000
--- a/SOURCES/0029-Indent-menu-entries.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: William Jon McCann <william.jon.mccann@gmail.com>
-Date: Fri, 7 Jun 2013 14:30:55 -0400
-Subject: [PATCH] Indent menu entries
-
----
- grub-core/normal/menu_text.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
-index b49835a9af7..6a57376fa80 100644
---- a/grub-core/normal/menu_text.c
-+++ b/grub-core/normal/menu_text.c
-@@ -239,7 +239,8 @@ print_entry (int y, int highlight, grub_menu_entry_t entry,
-       unicode_title[i] = ' ';
- 
-   if (data->geo.num_entries > 1)
--    grub_putcode (' ', data->term);
-+    for (i = 0; i < STANDARD_MARGIN; i++)
-+      grub_putcode (' ', data->term);
- 
-   grub_print_ucs4_menu (unicode_title,
- 			unicode_title + len,
diff --git a/SOURCES/0030-Fix-margins.patch b/SOURCES/0030-Fix-margins.patch
deleted file mode 100644
index baa10ed..0000000
--- a/SOURCES/0030-Fix-margins.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: William Jon McCann <william.jon.mccann@gmail.com>
-Date: Fri, 7 Jun 2013 14:59:36 -0400
-Subject: [PATCH] Fix margins
-
----
- grub-core/normal/menu_text.c | 8 +++-----
- 1 file changed, 3 insertions(+), 5 deletions(-)
-
-diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
-index 6a57376fa80..cbd62f714cb 100644
---- a/grub-core/normal/menu_text.c
-+++ b/grub-core/normal/menu_text.c
-@@ -333,17 +333,15 @@ grub_menu_init_page (int nested, int edit,
-   int version_msg = 1;
- 
-   geo->border = 0;
--  geo->first_entry_x = 0 /* margin */ + 0 /* border */;
--  geo->entry_width = grub_term_width (term) - 5;
-+  geo->first_entry_x = 0; /* no margin */
-+  geo->entry_width = grub_term_width (term) - 1;
- 
--  geo->first_entry_y = 2 /* two empty lines*/
--    + 0 /* GNU GRUB version text  */ + 1 /* top border */;
-+  geo->first_entry_y = 3; /* three empty lines*/
- 
-   geo->timeout_lines = 2;
- 
-   /* 3 lines for timeout message and bottom margin.  2 lines for the border.  */
-   geo->num_entries = grub_term_height (term) - geo->first_entry_y
--    - 1 /* bottom border */
-     - 1 /* empty line before info message*/
-     - geo->timeout_lines /* timeout */
-     - 1 /* empty final line  */;
diff --git a/SOURCES/0030-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch b/SOURCES/0030-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch
new file mode 100644
index 0000000..f4d83da
--- /dev/null
+++ b/SOURCES/0030-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch
@@ -0,0 +1,30 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 4 Sep 2014 15:52:08 -0400
+Subject: [PATCH] Minimize the sort ordering for .debug and -rescue- kernels.
+
+Resolves: rhbz#1065360
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub-mkconfig_lib.in | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
+index 301d1ac229..0f6505bf3b 100644
+--- a/util/grub-mkconfig_lib.in
++++ b/util/grub-mkconfig_lib.in
+@@ -253,6 +253,14 @@ version_test_gt ()
+     *.old:*.old) ;;
+     *.old:*) version_test_gt_a="`echo "$version_test_gt_a" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=gt ;;
+     *:*.old) version_test_gt_b="`echo "$version_test_gt_b" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=ge ;;
++    *-rescue*:*-rescue*) ;;
++    *?debug:*?debug) ;;
++    *-rescue*:*?debug) return 1 ;;
++    *?debug:*-rescue*) return 0 ;;
++    *-rescue*:*) return 1 ;;
++    *:*-rescue*) return 0 ;;
++    *?debug:*) return 1 ;;
++    *:*?debug) return 0 ;;
+   esac
+   version_test_numeric "$version_test_gt_a" "$version_test_gt_cmp" "$version_test_gt_b"
+   return "$?"
diff --git a/SOURCES/0031-Try-prefix-if-fw_path-doesn-t-work.patch b/SOURCES/0031-Try-prefix-if-fw_path-doesn-t-work.patch
new file mode 100644
index 0000000..a1c0d9e
--- /dev/null
+++ b/SOURCES/0031-Try-prefix-if-fw_path-doesn-t-work.patch
@@ -0,0 +1,222 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 9 Jul 2019 10:35:16 +0200
+Subject: [PATCH] Try $prefix if $fw_path doesn't work.
+
+Related: rhbz#1148652
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/ieee1275/init.c |  28 +++++----
+ grub-core/net/net.c            |   2 +-
+ grub-core/normal/main.c        | 134 ++++++++++++++++++++---------------------
+ 3 files changed, 82 insertions(+), 82 deletions(-)
+
+diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
+index e71d158416..0cd2a62723 100644
+--- a/grub-core/kern/ieee1275/init.c
++++ b/grub-core/kern/ieee1275/init.c
+@@ -127,23 +127,25 @@ grub_machine_get_bootlocation (char **device, char **path)
+       grub_free (canon);
+     }
+   else
+-    *device = grub_ieee1275_encode_devname (bootpath);
+-  grub_free (type);
+-
+-  filename = grub_ieee1275_get_filename (bootpath);
+-  if (filename)
+     {
+-      char *lastslash = grub_strrchr (filename, '\\');
+-
+-      /* Truncate at last directory.  */
+-      if (lastslash)
++      filename = grub_ieee1275_get_filename (bootpath);
++      if (filename)
+         {
+-	  *lastslash = '\0';
+-	  grub_translate_ieee1275_path (filename);
++          char *lastslash = grub_strrchr (filename, '\\');
+ 
+-	  *path = filename;
+-	}
++          /* Truncate at last directory.  */
++          if (lastslash)
++            {
++              *lastslash = '\0';
++              grub_translate_ieee1275_path (filename);
++
++              *path = filename;
++            }
++        }
++      *device = grub_ieee1275_encode_devname (bootpath);
+     }
++
++  grub_free (type);
+   grub_free (bootpath);
+ }
+ 
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index 4d3eb5c1a5..0ef148f4ad 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -1869,7 +1869,7 @@ grub_net_search_config_file (char *config)
+   /* Remove the remaining minus sign at the end. */
+   config[config_len] = '\0';
+ 
+-  return GRUB_ERR_NONE;
++  return GRUB_ERR_FILE_NOT_FOUND;
+ }
+ 
+ static struct grub_preboot *fini_hnd;
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index 0a99768f75..55558cc0b9 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -335,81 +335,79 @@ grub_enter_normal_mode (const char *config)
+   grub_boot_time ("Exiting normal mode");
+ }
+ 
++static grub_err_t
++grub_try_normal (const char *variable)
++{
++    char *config;
++    const char *prefix;
++    grub_err_t err = GRUB_ERR_FILE_NOT_FOUND;
++    const char *net_search_cfg;
++    int disable_net_search = 0;
++
++    prefix = grub_env_get (variable);
++    if (!prefix)
++      return GRUB_ERR_FILE_NOT_FOUND;
++
++    net_search_cfg = grub_env_get ("feature_net_search_cfg");
++    if (net_search_cfg && net_search_cfg[0] == 'n')
++      disable_net_search = 1;
++
++    if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0 &&
++        !disable_net_search)
++      {
++       grub_size_t config_len;
++       config_len = grub_strlen (prefix) +
++         sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
++       config = grub_malloc (config_len);
++
++       if (! config)
++         return GRUB_ERR_FILE_NOT_FOUND;
++
++       grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
++       err = grub_net_search_config_file (config);
++      }
++
++    if (err != GRUB_ERR_NONE)
++      {
++       config = grub_xasprintf ("%s/grub.cfg", prefix);
++       if (config)
++         {
++           grub_file_t file;
++           file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG);
++           if (file)
++             {
++               grub_file_close (file);
++               err = GRUB_ERR_NONE;
++             }
++         }
++      }
++
++    if (err == GRUB_ERR_NONE)
++      grub_enter_normal_mode (config);
++
++    grub_errno = 0;
++    grub_free (config);
++    return err;
++}
++
+ /* Enter normal mode from rescue mode.  */
+ static grub_err_t
+ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
+ 		 int argc, char *argv[])
+ {
+-  if (argc == 0)
+-    {
+-      /* Guess the config filename. It is necessary to make CONFIG static,
+-	 so that it won't get broken by longjmp.  */
+-      char *config;
+-      const char *prefix;
+-      const char *net_search_cfg;
+-      int disable_net_search = 0;
+-
+-      prefix = grub_env_get ("fw_path");
+-      if (! prefix)
+-	      prefix = grub_env_get ("prefix");
+-
+-      net_search_cfg = grub_env_get ("feature_net_search_cfg");
+-      if (net_search_cfg && net_search_cfg[0] == 'n')
+-	      disable_net_search = 1;
+-
+-      if (prefix)
+-        {
+-          if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0 &&
+-              !disable_net_search)
+-            {
+-              grub_size_t config_len;
+-              config_len = grub_strlen (prefix) +
+-                sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
+-              config = grub_malloc (config_len);
+-
+-              if (! config)
+-                goto quit;
+-
+-              grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
+-
+-              grub_net_search_configfile (config);
+-
+-              grub_enter_normal_mode (config);
+-              grub_free (config);
+-              config = NULL;
+-            }
+-
+-          if (!config)
+-            {
+-              config = grub_xasprintf ("%s/grub.cfg", prefix);
+-              if (config)
+-                {
+-                  grub_file_t file;
+-
+-                  file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG);
+-                  if (file)
+-                    {
+-                      grub_file_close (file);
+-                      grub_enter_normal_mode (config);
+-                    }
+-                  else
+-                    {
+-                      /*  Ignore all errors.  */
+-                      grub_errno = 0;
+-                    }
+-                  grub_free (config);
+-                }
+-            }
+-        }
+-      else
+-        {
+-          grub_enter_normal_mode (0);
+-        }
+-    }
+-  else
++  if (argc)
+     grub_enter_normal_mode (argv[0]);
++  else
++    {
++      /* Guess the config filename. */
++      grub_err_t err;
++      err = grub_try_normal ("fw_path");
++      if (err == GRUB_ERR_FILE_NOT_FOUND)
++        err = grub_try_normal ("prefix");
++      if (err == GRUB_ERR_FILE_NOT_FOUND)
++        grub_enter_normal_mode (0);
++    }
+ 
+-quit:
+   return 0;
+ }
+ 
diff --git a/SOURCES/0031-Use-2-instead-of-1-for-our-right-hand-margin-so-line.patch b/SOURCES/0031-Use-2-instead-of-1-for-our-right-hand-margin-so-line.patch
deleted file mode 100644
index 7932180..0000000
--- a/SOURCES/0031-Use-2-instead-of-1-for-our-right-hand-margin-so-line.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Fri, 21 Jun 2013 14:44:08 -0400
-Subject: [PATCH] Use -2 instead of -1 for our right-hand margin, so
- linewrapping works (#976643).
-
-Signed-off-by: Peter Jones <grub2-owner@fedoraproject.org>
----
- grub-core/normal/menu_text.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
-index cbd62f714cb..26e9e82042a 100644
---- a/grub-core/normal/menu_text.c
-+++ b/grub-core/normal/menu_text.c
-@@ -334,7 +334,7 @@ grub_menu_init_page (int nested, int edit,
- 
-   geo->border = 0;
-   geo->first_entry_x = 0; /* no margin */
--  geo->entry_width = grub_term_width (term) - 1;
-+  geo->entry_width = grub_term_width (term) - 2;
- 
-   geo->first_entry_y = 3; /* three empty lines*/
- 
diff --git a/SOURCES/0032-Enable-pager-by-default.-985860.patch b/SOURCES/0032-Enable-pager-by-default.-985860.patch
deleted file mode 100644
index d92fbcc..0000000
--- a/SOURCES/0032-Enable-pager-by-default.-985860.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 28 Oct 2013 10:09:27 -0400
-Subject: [PATCH] Enable pager by default. (#985860)
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- util/grub.d/00_header.in | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
-index 93a90233ead..858b526c925 100644
---- a/util/grub.d/00_header.in
-+++ b/util/grub.d/00_header.in
-@@ -43,6 +43,8 @@ if [ "x${GRUB_DEFAULT_BUTTON}" = "xsaved" ] ; then GRUB_DEFAULT_BUTTON='${saved_
- if [ "x${GRUB_TIMEOUT_BUTTON}" = "x" ] ; then GRUB_TIMEOUT_BUTTON="$GRUB_TIMEOUT" ; fi
- 
- cat << EOF
-+set pager=1
-+
- if [ -s \$prefix/grubenv ]; then
-   load_env
- fi
diff --git a/SOURCES/0032-Make-grub2-mkconfig-construct-titles-that-look-like-.patch b/SOURCES/0032-Make-grub2-mkconfig-construct-titles-that-look-like-.patch
new file mode 100644
index 0000000..db101c0
--- /dev/null
+++ b/SOURCES/0032-Make-grub2-mkconfig-construct-titles-that-look-like-.patch
@@ -0,0 +1,69 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 28 Apr 2015 11:15:03 -0400
+Subject: [PATCH] Make grub2-mkconfig construct titles that look like the ones
+ we want elsewhere.
+
+Resolves: rhbz#1215839
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub.d/10_linux.in | 34 +++++++++++++++++++++++++++-------
+ 1 file changed, 27 insertions(+), 7 deletions(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 5f6d3c8d52..786dbabb4a 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -78,6 +78,32 @@ case x"$GRUB_FS" in
+ 	;;
+ esac
+ 
++mktitle ()
++{
++  local title_type
++  local version
++  local OS_NAME
++  local OS_VERS
++
++  title_type=$1 && shift
++  version=$1 && shift
++
++  OS_NAME="$(eval $(grep ^NAME= /etc/os-release) ; echo ${NAME})"
++  OS_VERS="$(eval $(grep ^VERSION= /etc/os-release) ; echo ${VERSION})"
++
++  case $title_type in
++    recovery)
++      title=$(printf '%s (%s) %s (recovery mode)' \
++                     "${OS_NAME}" "${version}" "${OS_VERS}")
++      ;;
++    *)
++      title=$(printf '%s (%s) %s' \
++                     "${OS_NAME}" "${version}" "${OS_VERS}")
++      ;;
++  esac
++  echo -n ${title}
++}
++
+ title_correction_code=
+ 
+ linux_entry ()
+@@ -91,17 +117,11 @@ linux_entry ()
+       boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+   fi
+   if [ x$type != xsimple ] ; then
+-      case $type in
+-	  recovery)
+-	      title="$(gettext_printf "%s, with Linux %s (recovery mode)" "${os}" "${version}")" ;;
+-	  *)
+-	      title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;;
+-      esac
++      title=$(mktitle "$type" "$version")
+       if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then
+ 	  replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')"
+ 	  quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)"
+ 	  title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;"
+-	  grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")"
+       fi
+       echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+   else
diff --git a/SOURCES/0033-Add-friendly-grub2-password-config-tool-985962.patch b/SOURCES/0033-Add-friendly-grub2-password-config-tool-985962.patch
new file mode 100644
index 0000000..f430e96
--- /dev/null
+++ b/SOURCES/0033-Add-friendly-grub2-password-config-tool-985962.patch
@@ -0,0 +1,245 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Thu, 25 Jun 2015 11:13:11 -0400
+Subject: [PATCH] Add friendly grub2 password config tool (#985962)
+
+Provided a tool for users to reset the grub2 root user password
+without having to alter the grub.cfg. The hashed password now
+lives in a root-only-readable configuration file.
+
+Resolves: rhbz#985962
+
+Signed-off-by: Robert Marshall <rmarshall@redhat.com>
+[pjones: fix the efidir in grub-setpassword and rename tool]
+Signed-off-by: Peter Jones <pjones@redhat.com>
+[luto: fix grub-setpassword -o's output path]
+Signed-off-by: Andy Lutomirski <luto@kernel.org>
+[rharwood: migrate man page to h2m, context]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ configure.ac                   |   1 +
+ Makefile.util.def              |  13 +++++
+ docs/man/grub-set-password.h2m |   2 +
+ util/grub-mkconfig.in          |   2 +
+ util/grub-set-password.in      | 128 +++++++++++++++++++++++++++++++++++++++++
+ util/grub.d/01_users.in        |  11 ++++
+ 6 files changed, 157 insertions(+)
+ create mode 100644 docs/man/grub-set-password.h2m
+ create mode 100644 util/grub-set-password.in
+ create mode 100644 util/grub.d/01_users.in
+
+diff --git a/configure.ac b/configure.ac
+index 8331f95b64..7f59ad788f 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -72,6 +72,7 @@ grub_TRANSFORM([grub-mkrelpath])
+ grub_TRANSFORM([grub-mkrescue])
+ grub_TRANSFORM([grub-probe])
+ grub_TRANSFORM([grub-reboot])
++grub_TRANSFORM([grub-set-password])
+ grub_TRANSFORM([grub-script-check])
+ grub_TRANSFORM([grub-set-default])
+ grub_TRANSFORM([grub-sparc64-setup])
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 2c9b283a23..4ee22c5daa 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -452,6 +452,12 @@ script = {
+   installdir = grubconf;
+ };
+ 
++script = {
++  name = '01_users';
++  common = util/grub.d/01_users.in;
++  installdir = grubconf;
++};
++
+ script = {
+   name = '10_windows';
+   common = util/grub.d/10_windows.in;
+@@ -724,6 +730,13 @@ script = {
+   installdir = sbin;
+ };
+ 
++script = {
++  name = grub-set-password;
++  common = util/grub-set-password.in;
++  mansection = 8;
++  installdir = sbin;
++};
++
+ script = {
+   name = grub-mkconfig_lib;
+   common = util/grub-mkconfig_lib.in;
+diff --git a/docs/man/grub-set-password.h2m b/docs/man/grub-set-password.h2m
+new file mode 100644
+index 0000000000..10ee82f4d5
+--- /dev/null
++++ b/docs/man/grub-set-password.h2m
+@@ -0,0 +1,2 @@
++[NAME]
++grub-set-password \- generate the user.cfg file containing the hashed grub bootloader password
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index 8ea2315ebc..ba14cf6261 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -276,6 +276,8 @@ for i in "${grub_mkconfig_dir}"/* ; do
+     *~) ;;
+     # emacsen autosave files. FIXME: support other editors
+     */\#*\#) ;;
++    # rpm config files of yore.
++    *.rpmsave|*.rpmnew|*.rpmorig) ;;
+     *)
+       if grub_file_is_not_garbage "$i" && test -x "$i" ; then
+         echo
+diff --git a/util/grub-set-password.in b/util/grub-set-password.in
+new file mode 100644
+index 0000000000..5ebf50576d
+--- /dev/null
++++ b/util/grub-set-password.in
+@@ -0,0 +1,128 @@
++#!/bin/sh -e
++
++EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/')
++if [ -d /sys/firmware/efi/efivars/ ]; then
++    grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'`
++else
++    grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`
++fi
++
++PACKAGE_VERSION="@PACKAGE_VERSION@"
++PACKAGE_NAME="@PACKAGE_NAME@"
++self=`basename $0`
++bindir="@bindir@"
++grub_mkpasswd="${bindir}/@grub_mkpasswd_pbkdf2@"
++
++# Usage: usage
++# Print the usage.
++usage () {
++    cat <<EOF
++Usage: $0 [OPTION]
++$0 prompts the user to set a password on the grub bootloader. The password
++is written to a file named user.cfg which lives in the GRUB directory
++located by default at ${grubdir}.
++
++  -h, --help                     print this message and exit
++  -v, --version                  print the version information and exit
++  -o, --output_path <DIRECTORY>  put user.cfg in a user-selected directory
++
++Report bugs at https://bugzilla.redhat.com.
++EOF
++}
++
++argument () {
++    opt=$1
++    shift
++
++    if test $# -eq 0; then
++        gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$opt" 1>&2
++        exit 1
++    fi
++    echo $1
++}
++
++# Ensure that it's the root user running this script
++if [ "${EUID}" -ne 0 ]; then
++    echo "The grub bootloader password may only be set by root."
++    usage
++    exit 2
++fi
++
++# Check the arguments.
++while test $# -gt 0
++do
++    option=$1
++    shift
++
++    case "$option" in
++    -h | --help)
++	usage
++	exit 0 ;;
++    -v | --version)
++	echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}"
++	exit 0 ;;
++    -o | --output)
++        OUTPUT_PATH=`argument $option "$@"`; shift ;;
++    --output=*)
++        OUTPUT_PATH=`echo "$option" | sed 's/--output=//'` ;;
++    -o=*)
++        OUTPUT_PATH=`echo "$option" | sed 's/-o=//'` ;;
++    esac
++done
++
++# set user input or default path for user.cfg file
++if [ -z "${OUTPUT_PATH}" ]; then
++    OUTPUT_PATH="${grubdir}"
++fi
++
++if [ ! -d "${OUTPUT_PATH}" ]; then
++    echo "${OUTPUT_PATH} does not exist."
++    usage
++    exit 2;
++fi
++
++ttyopt=$(stty -g)
++fixtty() {
++      stty ${ttyopt}
++}
++
++trap fixtty EXIT
++stty -echo
++
++# prompt & confirm new grub2 root user password
++echo -n "Enter password: "
++read PASSWORD
++echo
++echo -n "Confirm password: "
++read PASSWORD_CONFIRM
++echo
++stty ${ttyopt}
++
++getpass() {
++    local P0
++    local P1
++    P0="$1" && shift
++    P1="$1" && shift
++
++    ( echo ${P0} ; echo ${P1} ) | \
++        LC_ALL=C ${grub_mkpasswd} | \
++        grep -v '[eE]nter password:' | \
++        sed -e "s/PBKDF2 hash of your password is //"
++}
++
++MYPASS="$(getpass "${PASSWORD}" "${PASSWORD_CONFIRM}")"
++if [ -z "${MYPASS}" ]; then
++      echo "${self}: error: empty password" 1>&2
++      exit 1
++fi
++
++# on the ESP, these will fail to set the permissions, but it's okay because
++# the directory is protected.
++install -m 0600 /dev/null "${OUTPUT_PATH}/user.cfg" 2>/dev/null || :
++chmod 0600 "${OUTPUT_PATH}/user.cfg" 2>/dev/null || :
++echo "GRUB2_PASSWORD=${MYPASS}" > "${OUTPUT_PATH}/user.cfg"
++
++if ! grep -q "^### BEGIN /etc/grub.d/01_users ###$" "${OUTPUT_PATH}/grub.cfg"; then
++    echo "WARNING: The current configuration lacks password support!"
++    echo "Update your configuration with @grub_mkconfig@ to support this feature."
++fi
+diff --git a/util/grub.d/01_users.in b/util/grub.d/01_users.in
+new file mode 100644
+index 0000000000..db2f44bfb7
+--- /dev/null
++++ b/util/grub.d/01_users.in
+@@ -0,0 +1,11 @@
++#!/bin/sh -e
++cat << EOF
++if [ -f \${prefix}/user.cfg ]; then
++  source \${prefix}/user.cfg
++  if [ -n "\${GRUB2_PASSWORD}" ]; then
++    set superusers="root"
++    export superusers
++    password_pbkdf2 root \${GRUB2_PASSWORD}
++  fi
++fi
++EOF
diff --git a/SOURCES/0033-F10-doesn-t-work-on-serial-so-don-t-tell-the-user-to.patch b/SOURCES/0033-F10-doesn-t-work-on-serial-so-don-t-tell-the-user-to.patch
deleted file mode 100644
index 7e9e829..0000000
--- a/SOURCES/0033-F10-doesn-t-work-on-serial-so-don-t-tell-the-user-to.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 28 Oct 2013 10:13:27 -0400
-Subject: [PATCH] F10 doesn't work on serial, so don't tell the user to hit it
- (#987443)
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/normal/menu_text.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
-index 26e9e82042a..4895ffe7d1d 100644
---- a/grub-core/normal/menu_text.c
-+++ b/grub-core/normal/menu_text.c
-@@ -157,7 +157,7 @@ print_message (int nested, int edit, struct grub_term_output *term, int dry_run)
- 
-   if (edit)
-     {
--      ret += grub_print_message_indented_real (_("Press Ctrl-x or F10 to start, Ctrl-c or F2 for a \
-+      ret += grub_print_message_indented_real (_("Press Ctrl-x to start, Ctrl-c for a \
- command prompt or Escape to discard edits and return to the menu. Pressing Tab lists possible completions."),
- 					       STANDARD_MARGIN, STANDARD_MARGIN,
- 					       term, dry_run);
diff --git a/SOURCES/0034-Don-t-say-GNU-Linux-in-generated-menus.patch b/SOURCES/0034-Don-t-say-GNU-Linux-in-generated-menus.patch
deleted file mode 100644
index db2a8b5..0000000
--- a/SOURCES/0034-Don-t-say-GNU-Linux-in-generated-menus.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 14 Mar 2011 14:27:42 -0400
-Subject: [PATCH] Don't say "GNU/Linux" in generated menus.
-
----
- util/grub.d/10_linux.in     | 4 ++--
- util/grub.d/20_linux_xen.in | 4 ++--
- 2 files changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
-index ad2ac4b078d..4fc58c83304 100644
---- a/util/grub.d/10_linux.in
-+++ b/util/grub.d/10_linux.in
-@@ -29,9 +29,9 @@ export TEXTDOMAINDIR="@localedir@"
- CLASS="--class gnu-linux --class gnu --class os"
- 
- if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
--  OS=GNU/Linux
-+  OS="$(sed 's, release .*$,,g' /etc/system-release)"
- else
--  OS="${GRUB_DISTRIBUTOR} GNU/Linux"
-+  OS="${GRUB_DISTRIBUTOR}"
-   CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}"
- fi
- 
-diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in
-index 3b1f4704921..ada20775a14 100644
---- a/util/grub.d/20_linux_xen.in
-+++ b/util/grub.d/20_linux_xen.in
-@@ -29,9 +29,9 @@ export TEXTDOMAINDIR="@localedir@"
- CLASS="--class gnu-linux --class gnu --class os --class xen"
- 
- if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
--  OS=GNU/Linux
-+  OS="$(sed 's, release .*$,,g' /etc/system-release)"
- else
--  OS="${GRUB_DISTRIBUTOR} GNU/Linux"
-+  OS="${GRUB_DISTRIBUTOR}"
-   CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}"
- fi
- 
diff --git a/SOURCES/0034-tcp-add-window-scaling-support.patch b/SOURCES/0034-tcp-add-window-scaling-support.patch
new file mode 100644
index 0000000..61b5a67
--- /dev/null
+++ b/SOURCES/0034-tcp-add-window-scaling-support.patch
@@ -0,0 +1,87 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Josef Bacik <jbacik@fb.com>
+Date: Wed, 12 Aug 2015 08:57:55 -0700
+Subject: [PATCH] tcp: add window scaling support
+
+Sometimes we have to provision boxes across regions, such as California to
+Sweden.  The http server has a 10 minute timeout, so if we can't get our 250mb
+image transferred fast enough our provisioning fails, which is not ideal.  So
+add tcp window scaling on open connections and set the window size to 1mb.  With
+this change we're able to get higher sustained transfers between regions and can
+transfer our image in well below 10 minutes.  Without this patch we'd time out
+every time halfway through the transfer.  Thanks,
+
+Signed-off-by: Josef Bacik <jbacik@fb.com>
+---
+ grub-core/net/tcp.c | 42 +++++++++++++++++++++++++++++-------------
+ 1 file changed, 29 insertions(+), 13 deletions(-)
+
+diff --git a/grub-core/net/tcp.c b/grub-core/net/tcp.c
+index e8ad34b84d..7d4b822626 100644
+--- a/grub-core/net/tcp.c
++++ b/grub-core/net/tcp.c
+@@ -106,6 +106,18 @@ struct tcphdr
+   grub_uint16_t urgent;
+ } GRUB_PACKED;
+ 
++struct tcp_scale_opt {
++  grub_uint8_t kind;
++  grub_uint8_t length;
++  grub_uint8_t scale;
++} GRUB_PACKED;
++
++struct tcp_synhdr {
++  struct tcphdr tcphdr;
++  struct tcp_scale_opt scale_opt;
++  grub_uint8_t padding;
++};
++
+ struct tcp_pseudohdr
+ {
+   grub_uint32_t src;
+@@ -566,7 +578,7 @@ grub_net_tcp_open (char *server,
+   grub_net_tcp_socket_t socket;
+   static grub_uint16_t in_port = 21550;
+   struct grub_net_buff *nb;
+-  struct tcphdr *tcph;
++  struct tcp_synhdr *tcph;
+   int i;
+   grub_uint8_t *nbd;
+   grub_net_link_level_address_t ll_target_addr;
+@@ -635,20 +647,24 @@ grub_net_tcp_open (char *server,
+     }
+ 
+   tcph = (void *) nb->data;
++  grub_memset(tcph, 0, sizeof (*tcph));
+   socket->my_start_seq = grub_get_time_ms ();
+   socket->my_cur_seq = socket->my_start_seq + 1;
+-  socket->my_window = 8192;
+-  tcph->seqnr = grub_cpu_to_be32 (socket->my_start_seq);
+-  tcph->ack = grub_cpu_to_be32_compile_time (0);
+-  tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_SYN);
+-  tcph->window = grub_cpu_to_be16 (socket->my_window);
+-  tcph->urgent = 0;
+-  tcph->src = grub_cpu_to_be16 (socket->in_port);
+-  tcph->dst = grub_cpu_to_be16 (socket->out_port);
+-  tcph->checksum = 0;
+-  tcph->checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP,
+-						   &socket->inf->address,
+-						   &socket->out_nla);
++  socket->my_window = 32768;
++  tcph->tcphdr.seqnr = grub_cpu_to_be32 (socket->my_start_seq);
++  tcph->tcphdr.ack = grub_cpu_to_be32_compile_time (0);
++  tcph->tcphdr.flags = grub_cpu_to_be16_compile_time ((6 << 12) | TCP_SYN);
++  tcph->tcphdr.window = grub_cpu_to_be16 (socket->my_window);
++  tcph->tcphdr.urgent = 0;
++  tcph->tcphdr.src = grub_cpu_to_be16 (socket->in_port);
++  tcph->tcphdr.dst = grub_cpu_to_be16 (socket->out_port);
++  tcph->tcphdr.checksum = 0;
++  tcph->scale_opt.kind = 3;
++  tcph->scale_opt.length = 3;
++  tcph->scale_opt.scale = 5;
++  tcph->tcphdr.checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP,
++							  &socket->inf->address,
++							  &socket->out_nla);
+ 
+   tcp_socket_register (socket);
+ 
diff --git a/SOURCES/0035-Don-t-draw-a-border-around-the-menu.patch b/SOURCES/0035-Don-t-draw-a-border-around-the-menu.patch
deleted file mode 100644
index 31a973e..0000000
--- a/SOURCES/0035-Don-t-draw-a-border-around-the-menu.patch
+++ /dev/null
@@ -1,71 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: William Jon McCann <william.jon.mccann@gmail.com>
-Date: Wed, 15 May 2013 16:47:33 -0400
-Subject: [PATCH] Don't draw a border around the menu
-
-It looks cleaner without it.
----
- grub-core/normal/menu_text.c | 43 -------------------------------------------
- 1 file changed, 43 deletions(-)
-
-diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
-index 4895ffe7d1d..e72ed438ba3 100644
---- a/grub-core/normal/menu_text.c
-+++ b/grub-core/normal/menu_text.c
-@@ -108,47 +108,6 @@ grub_print_message_indented (const char *msg, int margin_left, int margin_right,
-   grub_print_message_indented_real (msg, margin_left, margin_right, term, 0);
- }
- 
--static void
--draw_border (struct grub_term_output *term, const struct grub_term_screen_geometry *geo)
--{
--  int i;
--
--  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
--
--  grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1,
--	geo->first_entry_y - 1 });
--  grub_putcode (GRUB_UNICODE_CORNER_UL, term);
--  for (i = 0; i < geo->entry_width + 1; i++)
--    grub_putcode (GRUB_UNICODE_HLINE, term);
--  grub_putcode (GRUB_UNICODE_CORNER_UR, term);
--
--  for (i = 0; i < geo->num_entries; i++)
--    {
--      grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1,
--	    geo->first_entry_y + i });
--      grub_putcode (GRUB_UNICODE_VLINE, term);
--      grub_term_gotoxy (term,
--			(struct grub_term_coordinate) { geo->first_entry_x + geo->entry_width + 1,
--			    geo->first_entry_y + i });
--      grub_putcode (GRUB_UNICODE_VLINE, term);
--    }
--
--  grub_term_gotoxy (term,
--		    (struct grub_term_coordinate) { geo->first_entry_x - 1,
--			geo->first_entry_y - 1 + geo->num_entries + 1 });
--  grub_putcode (GRUB_UNICODE_CORNER_LL, term);
--  for (i = 0; i < geo->entry_width + 1; i++)
--    grub_putcode (GRUB_UNICODE_HLINE, term);
--  grub_putcode (GRUB_UNICODE_CORNER_LR, term);
--
--  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
--
--  grub_term_gotoxy (term,
--		    (struct grub_term_coordinate) { geo->first_entry_x - 1,
--			(geo->first_entry_y - 1 + geo->num_entries
--			 + GRUB_TERM_MARGIN + 1) });
--}
--
- static int
- print_message (int nested, int edit, struct grub_term_output *term, int dry_run)
- {
-@@ -406,8 +365,6 @@ grub_menu_init_page (int nested, int edit,
- 
-   grub_term_normal_color = grub_color_menu_normal;
-   grub_term_highlight_color = grub_color_menu_highlight;
--  if (geo->border)
--    draw_border (term, geo);
-   grub_term_normal_color = old_color_normal;
-   grub_term_highlight_color = old_color_highlight;
-   geo->timeout_y = geo->first_entry_y + geo->num_entries
diff --git a/SOURCES/0035-efinet-and-bootp-add-support-for-dhcpv6.patch b/SOURCES/0035-efinet-and-bootp-add-support-for-dhcpv6.patch
new file mode 100644
index 0000000..efeeee0
--- /dev/null
+++ b/SOURCES/0035-efinet-and-bootp-add-support-for-dhcpv6.patch
@@ -0,0 +1,651 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 9 Jul 2019 11:47:37 +0200
+Subject: [PATCH] efinet and bootp: add support for dhcpv6
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/bootp.c              | 173 +++++++++++++++++++++++++++++++++++++
+ grub-core/net/drivers/efi/efinet.c |  53 ++++++++++--
+ grub-core/net/net.c                |  72 +++++++++++++++
+ grub-core/net/tftp.c               |   4 +
+ include/grub/efi/api.h             | 129 +++++++++++++++++++++++++--
+ include/grub/net.h                 |  60 +++++++++++++
+ 6 files changed, 477 insertions(+), 14 deletions(-)
+
+diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
+index 6fb5627025..e28fb6a09f 100644
+--- a/grub-core/net/bootp.c
++++ b/grub-core/net/bootp.c
+@@ -902,6 +902,179 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
+ 
+ static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp;
+ 
++struct grub_net_network_level_interface *
++grub_net_configure_by_dhcpv6_ack (const char *name,
++				  struct grub_net_card *card,
++				  grub_net_interface_flags_t flags
++				    __attribute__((__unused__)),
++				  const grub_net_link_level_address_t *hwaddr,
++				  const struct grub_net_dhcpv6_packet *packet,
++				  int is_def, char **device, char **path)
++{
++  struct grub_net_network_level_interface *inter = NULL;
++  struct grub_net_network_level_address addr;
++  int mask = -1;
++
++  if (!device || !path)
++    return NULL;
++
++  *device = 0;
++  *path = 0;
++
++  grub_dprintf ("net", "mac address is %02x:%02x:%02x:%02x:%02x:%02x\n",
++		hwaddr->mac[0], hwaddr->mac[1], hwaddr->mac[2],
++		hwaddr->mac[3], hwaddr->mac[4], hwaddr->mac[5]);
++
++  if (is_def)
++    grub_net_default_server = 0;
++
++  if (is_def && !grub_net_default_server && packet)
++    {
++      const grub_uint8_t *options = packet->dhcp_options;
++      unsigned int option_max = 1024 - OFFSET_OF (dhcp_options, packet);
++      unsigned int i;
++
++      for (i = 0; i < option_max - sizeof (grub_net_dhcpv6_option_t); )
++	{
++	  grub_uint16_t num, len;
++	  grub_net_dhcpv6_option_t *opt =
++	    (grub_net_dhcpv6_option_t *)(options + i);
++
++	  num = grub_be_to_cpu16(opt->option_num);
++	  len = grub_be_to_cpu16(opt->option_len);
++
++	  grub_dprintf ("net", "got dhcpv6 option %d len %d\n", num, len);
++
++	  if (len == 0)
++	    break;
++
++	  if (len + i > 1024)
++	    break;
++
++	  if (num == GRUB_NET_DHCP6_BOOTFILE_URL)
++	    {
++	      char *scheme, *userinfo, *host, *file;
++	      char *tmp;
++	      int hostlen;
++	      int port;
++	      int rc = extract_url_info ((const char *)opt->option_data,
++					 (grub_size_t)len,
++					 &scheme, &userinfo, &host, &port,
++					 &file);
++	      if (rc < 0)
++		continue;
++
++	      /* right now this only handles tftp. */
++	      if (grub_strcmp("tftp", scheme))
++		{
++		  grub_free (scheme);
++		  grub_free (userinfo);
++		  grub_free (host);
++		  grub_free (file);
++		  continue;
++		}
++	      grub_free (userinfo);
++
++	      hostlen = grub_strlen (host);
++	      if (hostlen > 2 && host[0] == '[' && host[hostlen-1] == ']')
++		{
++		  tmp = host+1;
++		  host[hostlen-1] = '\0';
++		}
++	      else
++		tmp = host;
++
++	      *device = grub_xasprintf ("%s,%s", scheme, tmp);
++	      grub_free (scheme);
++	      grub_free (host);
++
++	      if (file && *file)
++		{
++		  tmp = grub_strrchr (file, '/');
++		  if (tmp)
++		    *(tmp+1) = '\0';
++		  else
++		    file[0] = '\0';
++		}
++	      else if (!file)
++		file = grub_strdup ("");
++
++	      if (file[0] == '/')
++		{
++		  *path = grub_strdup (file+1);
++		  grub_free (file);
++		}
++	      else
++		*path = file;
++	    }
++	  else if (num == GRUB_NET_DHCP6_IA_NA)
++	    {
++	      const grub_net_dhcpv6_option_t *ia_na_opt;
++	      const grub_net_dhcpv6_opt_ia_na_t *ia_na =
++		(const grub_net_dhcpv6_opt_ia_na_t *)opt;
++	      unsigned int left = len - OFFSET_OF (options, ia_na);
++	      unsigned int j;
++
++	      if ((grub_uint8_t *)ia_na + left >
++		  (grub_uint8_t *)options + option_max)
++		left -= ((grub_uint8_t *)ia_na + left)
++		        - ((grub_uint8_t *)options + option_max);
++
++	      if (len < OFFSET_OF (option_data, opt)
++			+ sizeof (grub_net_dhcpv6_option_t))
++		{
++		  grub_dprintf ("net",
++				"found dhcpv6 ia_na option with no address\n");
++		  continue;
++		}
++
++	      for (j = 0; left > sizeof (grub_net_dhcpv6_option_t); )
++		{
++		  ia_na_opt = (const grub_net_dhcpv6_option_t *)
++			       (ia_na->options + j);
++		  grub_uint16_t ia_na_opt_num, ia_na_opt_len;
++
++		  ia_na_opt_num = grub_be_to_cpu16 (ia_na_opt->option_num);
++		  ia_na_opt_len = grub_be_to_cpu16 (ia_na_opt->option_len);
++		  if (ia_na_opt_len == 0)
++		    break;
++		  if (j + ia_na_opt_len > left)
++		    break;
++		  if (ia_na_opt_num == GRUB_NET_DHCP6_IA_ADDRESS)
++		    {
++		      const grub_net_dhcpv6_opt_ia_address_t *ia_addr;
++
++		      ia_addr = (const grub_net_dhcpv6_opt_ia_address_t *)
++				 ia_na_opt;
++		      addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++		      grub_memcpy(addr.ipv6, ia_addr->ipv6_address,
++				  sizeof (ia_addr->ipv6_address));
++		      inter = grub_net_add_addr (name, card, &addr, hwaddr, 0);
++		    }
++
++		  j += ia_na_opt_len;
++		  left -= ia_na_opt_len;
++		}
++	    }
++
++	  i += len + 4;
++	}
++
++      grub_print_error ();
++    }
++
++  if (is_def)
++    {
++      grub_env_set ("net_default_interface", name);
++      grub_env_export ("net_default_interface");
++    }
++
++    if (inter)
++      grub_net_add_ipv6_local (inter, mask);
++    return inter;
++}
++
++
+ void
+ grub_bootp_init (void)
+ {
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index 5388f952ba..173fb63153 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -18,11 +18,14 @@
+ 
+ #include <grub/net/netbuff.h>
+ #include <grub/dl.h>
++#include <grub/env.h>
+ #include <grub/net.h>
+ #include <grub/time.h>
+ #include <grub/efi/api.h>
+ #include <grub/efi/efi.h>
+ #include <grub/i18n.h>
++#include <grub/lib/hexdump.h>
++#include <grub/types.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -329,7 +332,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 			  char **path)
+ {
+   struct grub_net_card *card;
+-  grub_efi_device_path_t *dp;
++  grub_efi_device_path_t *dp, *ldp = NULL;
+ 
+   dp = grub_efi_get_device_path (hnd);
+   if (! dp)
+@@ -340,14 +343,19 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+     grub_efi_device_path_t *cdp;
+     struct grub_efi_pxe *pxe;
+     struct grub_efi_pxe_mode *pxe_mode;
++
+     if (card->driver != &efidriver)
+       continue;
++
+     cdp = grub_efi_get_device_path (card->efi_handle);
+     if (! cdp)
+       continue;
++
++    ldp = grub_efi_find_last_device_path (dp);
++
+     if (grub_efi_compare_device_paths (dp, cdp) != 0)
+       {
+-	grub_efi_device_path_t *ldp, *dup_dp, *dup_ldp;
++	grub_efi_device_path_t *dup_dp, *dup_ldp;
+ 	int match;
+ 
+ 	/* EDK2 UEFI PXE driver creates pseudo devices with type IPv4/IPv6
+@@ -356,7 +364,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 	   devices. We skip them when enumerating cards, so here we need to
+ 	   find matching MAC device.
+          */
+-	ldp = grub_efi_find_last_device_path (dp);
+ 	if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+ 	    || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
+ 		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
+@@ -373,16 +380,46 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 	if (!match)
+ 	  continue;
+       }
++
+     pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
+ 				  GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+     if (! pxe)
+       continue;
++
+     pxe_mode = pxe->mode;
+-    grub_net_configure_by_dhcp_ack (card->name, card, 0,
+-				    (struct grub_net_bootp_packet *)
+-				    &pxe_mode->dhcp_ack,
+-				    sizeof (pxe_mode->dhcp_ack),
+-				    1, device, path);
++    if (pxe_mode->using_ipv6)
++      {
++	grub_net_link_level_address_t hwaddr;
++	struct grub_net_network_level_interface *intf;
++
++	grub_dprintf ("efinet", "using ipv6 and dhcpv6\n");
++	grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n",
++		      pxe_mode->dhcp_ack_received ? "yes" : "no",
++		      pxe_mode->dhcp_ack_received ? "" : " cannot continue");
++	if (!pxe_mode->dhcp_ack_received)
++	  continue;
++
++	hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
++	grub_memcpy (hwaddr.mac,
++		     card->efi_net->mode->current_address,
++		     sizeof (hwaddr.mac));
++
++	intf = grub_net_configure_by_dhcpv6_ack (card->name, card, 0, &hwaddr,
++	      (const struct grub_net_dhcpv6_packet *)&pxe_mode->dhcp_ack.dhcpv6,
++	      1, device, path);
++	if (intf && device && path)
++	  grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
++      }
++    else
++      {
++	grub_dprintf ("efinet", "using ipv4 and dhcp\n");
++	grub_net_configure_by_dhcp_ack (card->name, card, 0,
++					(struct grub_net_bootp_packet *)
++					&pxe_mode->dhcp_ack,
++					sizeof (pxe_mode->dhcp_ack),
++					1, device, path);
++	grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
++      }
+     return;
+   }
+ }
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index 0ef148f4ad..22f2689aae 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -960,6 +960,78 @@ grub_net_network_level_interface_register (struct grub_net_network_level_interfa
+   grub_net_network_level_interfaces = inter;
+ }
+ 
++int
++grub_ipv6_get_masksize (grub_uint16_t be_mask[8])
++{
++  grub_uint8_t *mask;
++  grub_uint16_t mask16[8];
++  int x, y;
++  int ret = 128;
++
++  grub_memcpy (mask16, be_mask, sizeof (mask16));
++  for (x = 0; x < 8; x++)
++    mask16[x] = grub_be_to_cpu16 (mask16[x]);
++
++  mask = (grub_uint8_t *)mask16;
++
++  for (x = 15; x >= 0; x--)
++    {
++      grub_uint8_t octet = mask[x];
++      if (!octet)
++	{
++	  ret -= 8;
++	  continue;
++	}
++      for (y = 0; y < 8; y++)
++	{
++	  if (octet & (1 << y))
++	    break;
++	  else
++	    ret--;
++	}
++      break;
++    }
++
++  return ret;
++}
++
++grub_err_t
++grub_net_add_ipv6_local (struct grub_net_network_level_interface *inter,
++			 int mask)
++{
++  struct grub_net_route *route;
++
++  if (inter->address.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6)
++    return 0;
++
++  if (mask == -1)
++      mask = grub_ipv6_get_masksize ((grub_uint16_t *)inter->address.ipv6);
++
++  if (mask == -1)
++    return 0;
++
++  route = grub_zalloc (sizeof (*route));
++  if (!route)
++    return grub_errno;
++
++  route->name = grub_xasprintf ("%s:local", inter->name);
++  if (!route->name)
++    {
++      grub_free (route);
++      return grub_errno;
++    }
++
++  route->target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++  grub_memcpy (route->target.ipv6.base, inter->address.ipv6,
++	       sizeof (inter->address.ipv6));
++  route->target.ipv6.masksize = mask;
++  route->is_gateway = 0;
++  route->interface = inter;
++
++  grub_net_route_register (route);
++
++  return 0;
++}
+ 
+ grub_err_t
+ grub_net_add_ipv4_local (struct grub_net_network_level_interface *inter,
+diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
+index 7f44b30f52..4ab2f5c735 100644
+--- a/grub-core/net/tftp.c
++++ b/grub-core/net/tftp.c
+@@ -358,18 +358,22 @@ tftp_open (struct grub_file *file, const char *filename)
+   file->not_easily_seekable = 1;
+   file->data = data;
+ 
++  grub_dprintf("tftp", "resolving address for %s\n", file->device->net->server);
+   err = grub_net_resolve_address (file->device->net->server, &addr);
+   if (err)
+     {
++      grub_dprintf("tftp", "Address resolution failed: %d\n", err);
+       grub_free (data);
+       return err;
+     }
+ 
++  grub_dprintf("tftp", "opening connection\n");
+   data->sock = grub_net_udp_open (addr,
+ 				  TFTP_SERVER_PORT, tftp_receive,
+ 				  file);
+   if (!data->sock)
+     {
++      grub_dprintf("tftp", "connection failed\n");
+       grub_free (data);
+       return grub_errno;
+     }
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index f1a52210c0..117469450d 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -592,10 +592,16 @@ typedef void *grub_efi_handle_t;
+ typedef void *grub_efi_event_t;
+ typedef grub_efi_uint64_t grub_efi_lba_t;
+ typedef grub_efi_uintn_t grub_efi_tpl_t;
+-typedef grub_uint8_t grub_efi_mac_address_t[32];
+-typedef grub_uint8_t grub_efi_ipv4_address_t[4];
+-typedef grub_uint16_t grub_efi_ipv6_address_t[8];
+-typedef grub_uint8_t grub_efi_ip_address_t[8] __attribute__ ((aligned(4)));
++typedef grub_efi_uint8_t grub_efi_mac_address_t[32];
++typedef grub_efi_uint8_t grub_efi_ipv4_address_t[4];
++typedef grub_efi_uint8_t grub_efi_ipv6_address_t[16];
++typedef union
++{
++  grub_efi_uint32_t addr[4];
++  grub_efi_ipv4_address_t v4;
++  grub_efi_ipv6_address_t v6;
++} grub_efi_ip_address_t __attribute__ ((aligned(4)));
++
+ typedef grub_efi_uint64_t grub_efi_physical_address_t;
+ typedef grub_efi_uint64_t grub_efi_virtual_address_t;
+ 
+@@ -1474,16 +1480,127 @@ struct grub_efi_simple_text_output_interface
+ };
+ typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output_interface_t;
+ 
+-typedef grub_uint8_t grub_efi_pxe_packet_t[1472];
++typedef struct grub_efi_pxe_dhcpv4_packet
++{
++  grub_efi_uint8_t bootp_opcode;
++  grub_efi_uint8_t bootp_hwtype;
++  grub_efi_uint8_t bootp_hwaddr_len;
++  grub_efi_uint8_t bootp_gate_hops;
++  grub_efi_uint32_t bootp_ident;
++  grub_efi_uint16_t bootp_seconds;
++  grub_efi_uint16_t bootp_flags;
++  grub_efi_uint8_t bootp_ci_addr[4];
++  grub_efi_uint8_t bootp_yi_addr[4];
++  grub_efi_uint8_t bootp_si_addr[4];
++  grub_efi_uint8_t bootp_gi_addr[4];
++  grub_efi_uint8_t bootp_hw_addr[16];
++  grub_efi_uint8_t bootp_srv_name[64];
++  grub_efi_uint8_t bootp_boot_file[128];
++  grub_efi_uint32_t dhcp_magik;
++  grub_efi_uint8_t dhcp_options[56];
++} grub_efi_pxe_dhcpv4_packet_t;
++
++struct grub_efi_pxe_dhcpv6_packet
++{
++  grub_efi_uint32_t message_type:8;
++  grub_efi_uint32_t transaction_id:24;
++  grub_efi_uint8_t dhcp_options[1024];
++} GRUB_PACKED;
++typedef struct grub_efi_pxe_dhcpv6_packet grub_efi_pxe_dhcpv6_packet_t;
++
++typedef union
++{
++  grub_efi_uint8_t raw[1472];
++  grub_efi_pxe_dhcpv4_packet_t dhcpv4;
++  grub_efi_pxe_dhcpv6_packet_t dhcpv6;
++} grub_efi_pxe_packet_t;
++
++#define GRUB_EFI_PXE_MAX_IPCNT 8
++#define GRUB_EFI_PXE_MAX_ARP_ENTRIES 8
++#define GRUB_EFI_PXE_MAX_ROUTE_ENTRIES 8
++
++typedef struct grub_efi_pxe_ip_filter
++{
++  grub_efi_uint8_t filters;
++  grub_efi_uint8_t ip_count;
++  grub_efi_uint8_t reserved;
++  grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT];
++} grub_efi_pxe_ip_filter_t;
++
++typedef struct grub_efi_pxe_arp_entry
++{
++  grub_efi_ip_address_t ip_addr;
++  grub_efi_mac_address_t mac_addr;
++} grub_efi_pxe_arp_entry_t;
++
++typedef struct grub_efi_pxe_route_entry
++{
++  grub_efi_ip_address_t ip_addr;
++  grub_efi_ip_address_t subnet_mask;
++  grub_efi_ip_address_t gateway_addr;
++} grub_efi_pxe_route_entry_t;
++
++typedef struct grub_efi_pxe_icmp_error
++{
++  grub_efi_uint8_t type;
++  grub_efi_uint8_t code;
++  grub_efi_uint16_t checksum;
++  union
++    {
++      grub_efi_uint32_t reserved;
++      grub_efi_uint32_t mtu;
++      grub_efi_uint32_t pointer;
++      struct
++	{
++	  grub_efi_uint16_t identifier;
++	  grub_efi_uint16_t sequence;
++	} echo;
++    } u;
++  grub_efi_uint8_t data[494];
++} grub_efi_pxe_icmp_error_t;
++
++typedef struct grub_efi_pxe_tftp_error
++{
++  grub_efi_uint8_t error_code;
++  grub_efi_char8_t error_string[127];
++} grub_efi_pxe_tftp_error_t;
+ 
+ typedef struct grub_efi_pxe_mode
+ {
+-  grub_uint8_t unused[52];
++  grub_efi_boolean_t started;
++  grub_efi_boolean_t ipv6_available;
++  grub_efi_boolean_t ipv6_supported;
++  grub_efi_boolean_t using_ipv6;
++  grub_efi_boolean_t bis_supported;
++  grub_efi_boolean_t bis_detected;
++  grub_efi_boolean_t auto_arp;
++  grub_efi_boolean_t send_guid;
++  grub_efi_boolean_t dhcp_discover_valid;
++  grub_efi_boolean_t dhcp_ack_received;
++  grub_efi_boolean_t proxy_offer_received;
++  grub_efi_boolean_t pxe_discover_valid;
++  grub_efi_boolean_t pxe_reply_received;
++  grub_efi_boolean_t pxe_bis_reply_received;
++  grub_efi_boolean_t icmp_error_received;
++  grub_efi_boolean_t tftp_error_received;
++  grub_efi_boolean_t make_callbacks;
++  grub_efi_uint8_t ttl;
++  grub_efi_uint8_t tos;
++  grub_efi_ip_address_t station_ip;
++  grub_efi_ip_address_t subnet_mask;
+   grub_efi_pxe_packet_t dhcp_discover;
+   grub_efi_pxe_packet_t dhcp_ack;
+   grub_efi_pxe_packet_t proxy_offer;
+   grub_efi_pxe_packet_t pxe_discover;
+   grub_efi_pxe_packet_t pxe_reply;
++  grub_efi_pxe_packet_t pxe_bis_reply;
++  grub_efi_pxe_ip_filter_t ip_filter;
++  grub_efi_uint32_t arp_cache_entries;
++  grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_MAX_ARP_ENTRIES];
++  grub_efi_uint32_t route_table_entries;
++  grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_MAX_ROUTE_ENTRIES];
++  grub_efi_pxe_icmp_error_t icmp_error;
++  grub_efi_pxe_tftp_error_t tftp_error;
+ } grub_efi_pxe_mode_t;
+ 
+ typedef struct grub_efi_pxe
+diff --git a/include/grub/net.h b/include/grub/net.h
+index 7ae4b6bd80..8a05ec4fe7 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -447,6 +447,51 @@ struct grub_net_bootp_packet
+   grub_uint8_t vendor[0];
+ } GRUB_PACKED;
+ 
++enum
++  {
++    GRUB_NET_DHCP6_IA_NA = 3,
++    GRUB_NET_DHCP6_IA_ADDRESS = 5,
++    GRUB_NET_DHCP6_BOOTFILE_URL = 59,
++  };
++
++struct grub_net_dhcpv6_option
++{
++  grub_uint16_t option_num;
++  grub_uint16_t option_len;
++  grub_uint8_t option_data[];
++} GRUB_PACKED;
++typedef struct grub_net_dhcpv6_option grub_net_dhcpv6_option_t;
++
++struct grub_net_dhcpv6_opt_ia_na
++{
++  grub_uint16_t option_num;
++  grub_uint16_t option_len;
++  grub_uint32_t iaid;
++  grub_uint32_t t1;
++  grub_uint32_t t2;
++  grub_uint8_t options[];
++} GRUB_PACKED;
++typedef struct grub_net_dhcpv6_opt_ia_na grub_net_dhcpv6_opt_ia_na_t;
++
++struct grub_net_dhcpv6_opt_ia_address
++{
++  grub_uint16_t option_num;
++  grub_uint16_t option_len;
++  grub_uint64_t ipv6_address[2];
++  grub_uint32_t preferred_lifetime;
++  grub_uint32_t valid_lifetime;
++  grub_uint8_t options[];
++} GRUB_PACKED;
++typedef struct grub_net_dhcpv6_opt_ia_address grub_net_dhcpv6_opt_ia_address_t;
++
++struct grub_net_dhcpv6_packet
++{
++  grub_uint32_t message_type:8;
++  grub_uint32_t transaction_id:24;
++  grub_uint8_t dhcp_options[1024];
++} GRUB_PACKED;
++typedef struct grub_net_dhcpv6_packet grub_net_dhcpv6_packet_t;
++
+ #define	GRUB_NET_BOOTP_RFC1048_MAGIC_0	0x63
+ #define	GRUB_NET_BOOTP_RFC1048_MAGIC_1	0x82
+ #define	GRUB_NET_BOOTP_RFC1048_MAGIC_2	0x53
+@@ -482,6 +527,21 @@ grub_net_configure_by_dhcp_ack (const char *name,
+ 				grub_size_t size,
+ 				int is_def, char **device, char **path);
+ 
++struct grub_net_network_level_interface *
++grub_net_configure_by_dhcpv6_ack (const char *name,
++				 struct grub_net_card *card,
++				 grub_net_interface_flags_t flags,
++				 const grub_net_link_level_address_t *hwaddr,
++				 const struct grub_net_dhcpv6_packet *packet,
++				 int is_def, char **device, char **path);
++
++int
++grub_ipv6_get_masksize(grub_uint16_t *mask);
++
++grub_err_t
++grub_net_add_ipv6_local (struct grub_net_network_level_interface *inf,
++			 int mask);
++
+ grub_err_t
+ grub_net_add_ipv4_local (struct grub_net_network_level_interface *inf,
+ 			 int mask);
diff --git a/SOURCES/0036-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch b/SOURCES/0036-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch
new file mode 100644
index 0000000..95490cd
--- /dev/null
+++ b/SOURCES/0036-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch
@@ -0,0 +1,271 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 23 Jun 2016 11:01:39 -0400
+Subject: [PATCH] Add grub-get-kernel-settings and use it in 10_linux
+
+This patch adds grub-get-kernel-settings, which reads the system kernel
+installation configuration from /etc/sysconfig/kernel, and outputs
+${GRUB_...} variables suitable for evaluation by grub-mkconfig.  Those
+variables are then used by 10_linux to choose whether or not to create
+debug stanzas.
+
+Resolves: rhbz#1226325
+[rharwood: migrate man page to h2m]
+---
+ configure.ac                                   |  1 +
+ Makefile.util.def                              |  7 ++
+ docs/man/grub-get-kernel-settings.h2m          |  2 +
+ util/bash-completion.d/grub-completion.bash.in | 22 +++++++
+ util/grub-get-kernel-settings.in               | 88 ++++++++++++++++++++++++++
+ util/grub-mkconfig.in                          |  3 +
+ util/grub.d/10_linux.in                        | 23 +++++--
+ 7 files changed, 141 insertions(+), 5 deletions(-)
+ create mode 100644 docs/man/grub-get-kernel-settings.h2m
+ create mode 100644 util/grub-get-kernel-settings.in
+
+diff --git a/configure.ac b/configure.ac
+index 7f59ad788f..0d0e6782a1 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -65,6 +65,7 @@ grub_TRANSFORM([grub-install])
+ grub_TRANSFORM([grub-mkconfig])
+ grub_TRANSFORM([grub-mkfont])
+ grub_TRANSFORM([grub-mkimage])
++grub_TRANSFORM([grub-get-kernel-settings])
+ grub_TRANSFORM([grub-glue-efi])
+ grub_TRANSFORM([grub-mklayout])
+ grub_TRANSFORM([grub-mkpasswd-pbkdf2])
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 4ee22c5daa..18a9242776 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -716,6 +716,13 @@ script = {
+   installdir = sbin;
+ };
+ 
++script = {
++  name = grub-get-kernel-settings;
++  common = util/grub-get-kernel-settings.in;
++  mansection = 3;
++  installdir = sbin;
++};
++
+ script = {
+   name = grub-set-default;
+   common = util/grub-set-default.in;
+diff --git a/docs/man/grub-get-kernel-settings.h2m b/docs/man/grub-get-kernel-settings.h2m
+new file mode 100644
+index 0000000000..b8051f01f3
+--- /dev/null
++++ b/docs/man/grub-get-kernel-settings.h2m
+@@ -0,0 +1,2 @@
++[NAME]
++grub-get-kernel-settings \- Evaluate the system's kernel installation settings for use while making a grub configuration file
+diff --git a/util/bash-completion.d/grub-completion.bash.in b/util/bash-completion.d/grub-completion.bash.in
+index 44bf135b9f..5c4acd496d 100644
+--- a/util/bash-completion.d/grub-completion.bash.in
++++ b/util/bash-completion.d/grub-completion.bash.in
+@@ -264,6 +264,28 @@ have ${__grub_sparc64_setup_program} && \
+ unset __grub_sparc64_setup_program
+ 
+ 
++#
++# grub-get-kernel-settings
++#
++_grub_get_kernel_settings () {
++    local cur
++
++    COMPREPLY=()
++    cur=`_get_cword`
++
++    if [[ "$cur" == -* ]]; then
++        __grubcomp "$(__grub_get_options_from_help)"
++    else
++        # Default complete with a filename
++        _filedir
++    fi
++}
++__grub_get_kernel_settings_program="@grub_get_kernel_settings@"
++have ${__grub_get_kernel_settings_program} && \
++ complete -F _grub_get_kernel_settings -o filenames ${__grub_get_kernel_settings_program}
++unset __grub_get_kernel_settings_program
++
++
+ #
+ # grub-install
+ #
+diff --git a/util/grub-get-kernel-settings.in b/util/grub-get-kernel-settings.in
+new file mode 100644
+index 0000000000..7e87dfccc0
+--- /dev/null
++++ b/util/grub-get-kernel-settings.in
+@@ -0,0 +1,88 @@
++#!/bin/sh
++set -e
++
++# Evaluate new-kernel-pkg's configuration file.
++# Copyright (C) 2016 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/>.
++
++PACKAGE_NAME=@PACKAGE_NAME@
++PACKAGE_VERSION=@PACKAGE_VERSION@
++datadir="@datadir@"
++if [ "x$pkgdatadir" = x ]; then
++    pkgdatadir="${datadir}/@PACKAGE@"
++fi
++
++self=`basename $0`
++
++export TEXTDOMAIN=@PACKAGE@
++export TEXTDOMAINDIR="@localedir@"
++
++. "${pkgdatadir}/grub-mkconfig_lib"
++
++# Usage: usage
++# Print the usage.
++usage () {
++    gettext_printf "Usage: %s [OPTION]\n" "$self"
++    gettext "Evaluate new-kernel-pkg configuration"; echo
++    echo
++    print_option_help "-h, --help" "$(gettext "print this message and exit")"
++    print_option_help "-v, --version" "$(gettext "print the version information and exit")"
++    echo
++}
++
++# Check the arguments.
++while test $# -gt 0
++do
++    option=$1
++    shift
++
++    case "$option" in
++    -h | --help)
++	usage
++	exit 0 ;;
++    -v | --version)
++	echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}"
++	exit 0 ;;
++    -*)
++	gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2
++	usage
++	exit 1
++	;;
++    # Explicitly ignore non-option arguments, for compatibility.
++    esac
++done
++
++if test -f /etc/sysconfig/kernel ; then
++    . /etc/sysconfig/kernel
++fi
++
++if [ "$MAKEDEBUG" = "yes" ]; then
++    echo GRUB_LINUX_MAKE_DEBUG=true
++    echo export GRUB_LINUX_MAKE_DEBUG
++    echo GRUB_CMDLINE_LINUX_DEBUG=\"systemd.log_level=debug systemd.log_target=kmsg\"
++    echo export GRUB_CMDLINE_LINUX_DEBUG
++    echo GRUB_LINUX_DEBUG_TITLE_POSTFIX=\" with debugging\"
++    echo export GRUB_LINUX_DEBUG_TITLE_POSTFIX
++fi
++if [ "$DEFAULTDEBUG" = "yes" ]; then
++    echo GRUB_DEFAULT_TO_DEBUG=true
++else
++    echo GRUB_DEFAULT_TO_DEBUG=false
++fi
++echo export GRUB_DEFAULT_TO_DEBUG
++if [ "$UPDATEDEFAULT" = "yes" ]; then
++    echo GRUB_UPDATE_DEFAULT_KERNEL=true
++    echo export GRUB_UPDATE_DEFAULT_KERNEL
++fi
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index ba14cf6261..005f093809 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -45,6 +45,7 @@ grub_probe="${sbindir}/@grub_probe@"
+ grub_file="${bindir}/@grub_file@"
+ grub_editenv="${bindir}/@grub_editenv@"
+ grub_script_check="${bindir}/@grub_script_check@"
++grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@"
+ 
+ export TEXTDOMAIN=@PACKAGE@
+ export TEXTDOMAINDIR="@localedir@"
+@@ -158,6 +159,8 @@ if test -f ${sysconfdir}/default/grub ; then
+   . ${sysconfdir}/default/grub
+ fi
+ 
++eval "$("${grub_get_kernel_settings}")" || true
++
+ if [ "x${GRUB_DISABLE_UUID}" = "xtrue" ]; then
+   if [ -z "${GRUB_DISABLE_LINUX_UUID}" ]; then
+     GRUB_DISABLE_LINUX_UUID="true"
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 786dbabb4a..292e333324 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -111,7 +111,8 @@ linux_entry ()
+   os="$1"
+   version="$2"
+   type="$3"
+-  args="$4"
++  isdebug="$4"
++  args="$5"
+ 
+   if [ -z "$boot_device_id" ]; then
+       boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+@@ -123,6 +124,9 @@ linux_entry ()
+ 	  quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)"
+ 	  title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;"
+       fi
++      if [ x$isdebug = xdebug ]; then
++	  title="$title${GRUB_LINUX_DEBUG_TITLE_POSTFIX}"
++      fi
+       echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+   else
+       echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+@@ -306,11 +310,15 @@ while [ "x$list" != "x" ] ; do
+   fi
+ 
+   if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then
+-    linux_entry "${OS}" "${version}" simple \
++    linux_entry "${OS}" "${version}" simple standard \
+     "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
++    if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
++      linux_entry "${OS}" "${version}" simple debug \
++        "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}"
++    fi
+ 
+     submenu_indentation="$grub_tab"
+-    
++
+     if [ -z "$boot_device_id" ]; then
+ 	boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+     fi
+@@ -319,10 +327,15 @@ while [ "x$list" != "x" ] ; do
+     is_top_level=false
+   fi
+ 
+-  linux_entry "${OS}" "${version}" advanced \
++  linux_entry "${OS}" "${version}" advanced standard \
+               "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
++  if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
++    linux_entry "${OS}" "${version}" advanced debug \
++                "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}"
++  fi
++
+   if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
+-    linux_entry "${OS}" "${version}" recovery \
++    linux_entry "${OS}" "${version}" recovery standard \
+                 "single ${GRUB_CMDLINE_LINUX}"
+   fi
+ 
diff --git a/SOURCES/0036-Use-the-standard-margin-for-the-timeout-string.patch b/SOURCES/0036-Use-the-standard-margin-for-the-timeout-string.patch
deleted file mode 100644
index 49a382d..0000000
--- a/SOURCES/0036-Use-the-standard-margin-for-the-timeout-string.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: William Jon McCann <william.jon.mccann@gmail.com>
-Date: Fri, 7 Jun 2013 10:52:32 -0400
-Subject: [PATCH] Use the standard margin for the timeout string
-
-So that it aligns with the other messages
----
- grub-core/normal/menu_text.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
-index e72ed438ba3..ca135624356 100644
---- a/grub-core/normal/menu_text.c
-+++ b/grub-core/normal/menu_text.c
-@@ -372,7 +372,7 @@ grub_menu_init_page (int nested, int edit,
-   if (bottom_message)
-     {
-       grub_term_gotoxy (term,
--			(struct grub_term_coordinate) { GRUB_TERM_MARGIN,
-+			(struct grub_term_coordinate) { STANDARD_MARGIN,
- 			    geo->timeout_y });
- 
-       print_message (nested, edit, term, 0);
-@@ -407,14 +407,14 @@ menu_text_print_timeout (int timeout, void *dataptr)
-   if (data->timeout_msg == TIMEOUT_UNKNOWN)
-     {
-       data->timeout_msg = grub_print_message_indented_real (msg_translated,
--							    3, 1, data->term, 1)
-+							    STANDARD_MARGIN, 1, data->term, 1)
- 	<= data->geo.timeout_lines ? TIMEOUT_NORMAL : TIMEOUT_TERSE;
-       if (data->timeout_msg == TIMEOUT_TERSE)
- 	{
- 	  grub_free (msg_translated);
- 	  msg_translated = grub_xasprintf (_("%ds"), timeout);
- 	  if (grub_term_width (data->term) < 10)
--	    data->timeout_msg = TIMEOUT_TERSE_NO_MARGIN;
-+	    data->timeout_msg = STANDARD_MARGIN;
- 	}
-     }
- 
diff --git a/SOURCES/0037-Add-.eh_frame-to-list-of-relocations-stripped.patch b/SOURCES/0037-Add-.eh_frame-to-list-of-relocations-stripped.patch
deleted file mode 100644
index ed48c5c..0000000
--- a/SOURCES/0037-Add-.eh_frame-to-list-of-relocations-stripped.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Fedora Ninjas <grub2-owner@fedoraproject.org>
-Date: Mon, 13 Jan 2014 21:50:59 -0500
-Subject: [PATCH] Add .eh_frame to list of relocations stripped
-
----
- conf/Makefile.common | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/conf/Makefile.common b/conf/Makefile.common
-index 2a1a886f6d5..191b1a70c6b 100644
---- a/conf/Makefile.common
-+++ b/conf/Makefile.common
-@@ -38,7 +38,7 @@ CFLAGS_KERNEL = $(CFLAGS_PLATFORM) -ffreestanding
- LDFLAGS_KERNEL = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC)
- CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1
- CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
--STRIPFLAGS_KERNEL = -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx
-+STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx
- 
- CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding
- LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d
diff --git a/SOURCES/0037-bz1374141-fix-incorrect-mask-for-ppc64.patch b/SOURCES/0037-bz1374141-fix-incorrect-mask-for-ppc64.patch
new file mode 100644
index 0000000..15b2111
--- /dev/null
+++ b/SOURCES/0037-bz1374141-fix-incorrect-mask-for-ppc64.patch
@@ -0,0 +1,48 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Masahiro Matsuya <mmatsuya@redhat.com>
+Date: Sat, 29 Oct 2016 08:35:26 +0900
+Subject: [PATCH] bz1374141 fix incorrect mask for ppc64
+
+The netmask configured in firmware is not respected on ppc64 (big endian).
+When 255.255.252.0 is set as netmask in firmware, the following is the value of bootpath string in grub_ieee1275_parse_bootpath().
+
+ /vdevice/l-lan@30000002:speed=auto,duplex=auto,192.168.88.10,,192.168.89.113,192.168.88.1,5,5,255.255.252.0,512
+
+The netmask in this bootpath is no problem, since it's a value specified in firmware. But,
+The value of 'subnet_mask.ipv4' was set with 0xfffffc00, and __builtin_ctz (~grub_le_to_cpu32 (subnet_mask.ipv4)) returned 16 (not 22).
+As a result, 16 was used for netmask wrongly.
+
+1111 1111 1111 1111 1111 1100 0000 0000 # subnet_mask.ipv4 (=0xfffffc00)
+0000 0000 1111 1100 1111 1111 1111 1111 # grub_le_to_cpu32 (subnet_mask.ipv4)
+1111 1111 0000 0011 0000 0000 0000 0000 # ~grub_le_to_cpu32 (subnet_mask.ipv4)
+
+And, the count of zero with __builtin_ctz can be 16.
+This patch changes it as below.
+
+1111 1111 1111 1111 1111 1100 0000 0000 # subnet_mask.ipv4 (=0xfffffc00)
+0000 0000 1111 1100 1111 1111 1111 1111 # grub_le_to_cpu32 (subnet_mask.ipv4)
+1111 1111 1111 1111 1111 1100 0000 0000 # grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4))
+0000 0000 0000 0000 0000 0011 1111 1111 # ~grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4))
+
+The count of zero with __builtin_clz can be 22. (clz counts the number of one bits preceding the most significant zero bit)
+
+Signed-off-by: Masahiro Matsuya <mmatsuya@redhat.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/net/drivers/ieee1275/ofnet.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c
+index ac4e62a95c..3860b6f78d 100644
+--- a/grub-core/net/drivers/ieee1275/ofnet.c
++++ b/grub-core/net/drivers/ieee1275/ofnet.c
+@@ -220,8 +220,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath,
+                                  flags);
+       inter->vlantag = vlantag;
+       grub_net_add_ipv4_local (inter,
+-                          __builtin_ctz (~grub_le_to_cpu32 (subnet_mask.ipv4)));
+-
++                          __builtin_clz (~grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4))));
+     }
+ 
+   if (gateway_addr.ipv4 != 0)
diff --git a/SOURCES/0038-Don-t-require-a-password-to-boot-entries-generated-b.patch b/SOURCES/0038-Don-t-require-a-password-to-boot-entries-generated-b.patch
deleted file mode 100644
index fb0e197..0000000
--- a/SOURCES/0038-Don-t-require-a-password-to-boot-entries-generated-b.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 11 Feb 2014 11:14:50 -0500
-Subject: [PATCH] Don't require a password to boot entries generated by
- grub-mkconfig.
-
-When we set a password, we just want that to mean you can't /edit/ an entry.
-
-Resolves: rhbz#1030176
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- util/grub.d/10_linux.in | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
-index 4fc58c83304..635d2fe0cd3 100644
---- a/util/grub.d/10_linux.in
-+++ b/util/grub.d/10_linux.in
-@@ -26,7 +26,7 @@ datarootdir="@datarootdir@"
- export TEXTDOMAIN=@PACKAGE@
- export TEXTDOMAINDIR="@localedir@"
- 
--CLASS="--class gnu-linux --class gnu --class os"
-+CLASS="--class gnu-linux --class gnu --class os --unrestricted"
- 
- if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
-   OS="$(sed 's, release .*$,,g' /etc/system-release)"
diff --git a/SOURCES/0038-Make-grub_fatal-also-backtrace.patch b/SOURCES/0038-Make-grub_fatal-also-backtrace.patch
new file mode 100644
index 0000000..f876575
--- /dev/null
+++ b/SOURCES/0038-Make-grub_fatal-also-backtrace.patch
@@ -0,0 +1,172 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 27 Jan 2016 09:22:42 -0500
+Subject: [PATCH] Make grub_fatal() also backtrace.
+
+---
+ grub-core/Makefile.core.def     |  3 ++
+ grub-core/kern/misc.c           |  8 +++++-
+ grub-core/lib/arm64/backtrace.c | 62 +++++++++++++++++++++++++++++++++++++++++
+ grub-core/lib/backtrace.c       |  2 ++
+ grub-core/lib/i386/backtrace.c  | 14 +++++++++-
+ 5 files changed, 87 insertions(+), 2 deletions(-)
+ create mode 100644 grub-core/lib/arm64/backtrace.c
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index c15e91943b..058c88ac3a 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -188,6 +188,9 @@ kernel = {
+ 
+   softdiv = lib/division.c;
+ 
++  x86 = lib/i386/backtrace.c;
++  x86 = lib/backtrace.c;
++
+   i386 = kern/i386/dl.c;
+   i386_xen = kern/i386/dl.c;
+   i386_xen_pvh = kern/i386/dl.c;
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index 63b586d09c..a3e215155b 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -24,6 +24,7 @@
+ #include <grub/term.h>
+ #include <grub/env.h>
+ #include <grub/i18n.h>
++#include <grub/backtrace.h>
+ 
+ union printf_arg
+ {
+@@ -1199,8 +1200,13 @@ grub_printf_fmt_check (const char *fmt, const char *fmt_expected)
+ static void __attribute__ ((noreturn))
+ grub_abort (void)
+ {
++#ifndef GRUB_UTIL
++#if defined(__i386__) || defined(__x86_64__)
++  grub_backtrace();
++#endif
++#endif
+   grub_printf ("\nAborted.");
+-  
++
+ #ifndef GRUB_UTIL
+   if (grub_term_inputs)
+ #endif
+diff --git a/grub-core/lib/arm64/backtrace.c b/grub-core/lib/arm64/backtrace.c
+new file mode 100644
+index 0000000000..1079b5380e
+--- /dev/null
++++ b/grub-core/lib/arm64/backtrace.c
+@@ -0,0 +1,62 @@
++/*
++ *  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/misc.h>
++#include <grub/command.h>
++#include <grub/err.h>
++#include <grub/dl.h>
++#include <grub/mm.h>
++#include <grub/term.h>
++#include <grub/backtrace.h>
++
++#define MAX_STACK_FRAME 102400
++
++void
++grub_backtrace_pointer (int frame)
++{
++  while (1)
++    {
++      void *lp = __builtin_return_address (frame);
++      if (!lp)
++	break;
++
++      lp = __builtin_extract_return_addr (lp);
++
++      grub_printf ("%p: ", lp);
++      grub_backtrace_print_address (lp);
++      grub_printf (" (");
++      for (i = 0; i < 2; i++)
++	grub_printf ("%p,", ((void **)ptr) [i + 2]);
++      grub_printf ("%p)\n", ((void **)ptr) [i + 2]);
++      nptr = *(void **)ptr;
++      if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME
++	  || nptr == ptr)
++	{
++	  grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr);
++	  break;
++	}
++      ptr = nptr;
++    }
++}
++
++void
++grub_backtrace (void)
++{
++  grub_backtrace_pointer (1);
++}
++
+diff --git a/grub-core/lib/backtrace.c b/grub-core/lib/backtrace.c
+index 825a8800e2..c0ad6ab8be 100644
+--- a/grub-core/lib/backtrace.c
++++ b/grub-core/lib/backtrace.c
+@@ -29,6 +29,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ void
+ grub_backtrace_print_address (void *addr)
+ {
++#ifndef GRUB_UTIL
+   grub_dl_t mod;
+ 
+   FOR_DL_MODULES (mod)
+@@ -44,6 +45,7 @@ grub_backtrace_print_address (void *addr)
+ 	}
+   }
+ 
++#endif
+   grub_printf ("%p", addr);
+ }
+ 
+diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c
+index c3e03c7275..c67273db3a 100644
+--- a/grub-core/lib/i386/backtrace.c
++++ b/grub-core/lib/i386/backtrace.c
+@@ -15,11 +15,23 @@
+  *  You should have received a copy of the GNU General Public License
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
++#include <config.h>
++#ifdef GRUB_UTIL
++#define REALLY_GRUB_UTIL GRUB_UTIL
++#undef GRUB_UTIL
++#endif
++
++#include <grub/symbol.h>
++#include <grub/dl.h>
++
++#ifdef REALLY_GRUB_UTIL
++#define GRUB_UTIL REALLY_GRUB_UTIL
++#undef REALLY_GRUB_UTIL
++#endif
+ 
+ #include <grub/misc.h>
+ #include <grub/command.h>
+ #include <grub/err.h>
+-#include <grub/dl.h>
+ #include <grub/mm.h>
+ #include <grub/term.h>
+ #include <grub/backtrace.h>
diff --git a/SOURCES/0039-Don-t-emit-Booting-.-message.patch b/SOURCES/0039-Don-t-emit-Booting-.-message.patch
deleted file mode 100644
index 4133b52..0000000
--- a/SOURCES/0039-Don-t-emit-Booting-.-message.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 18 Feb 2014 09:37:49 -0500
-Subject: [PATCH] Don't emit "Booting ..." message.
-
-UI team still hates this stuff, so we're disabling it for RHEL 7.
-
-Resolves: rhbz#1023142
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/normal/menu.c       | 4 +++-
- grub-core/normal/menu_entry.c | 3 ---
- 2 files changed, 3 insertions(+), 4 deletions(-)
-
-diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
-index d7a222e681b..37d753d8081 100644
---- a/grub-core/normal/menu.c
-+++ b/grub-core/normal/menu.c
-@@ -838,12 +838,14 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
- 
- /* Callback invoked immediately before a menu entry is executed.  */
- static void
--notify_booting (grub_menu_entry_t entry,
-+notify_booting (grub_menu_entry_t __attribute__((unused)) entry,
- 		void *userdata __attribute__((unused)))
- {
-+#if 0
-   grub_printf ("  ");
-   grub_printf_ (N_("Booting `%s'"), entry->title);
-   grub_printf ("\n\n");
-+#endif
- }
- 
- /* Callback invoked when a default menu entry executed because of a timeout
-diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c
-index 50eef918cf6..de64a367c4e 100644
---- a/grub-core/normal/menu_entry.c
-+++ b/grub-core/normal/menu_entry.c
-@@ -1176,9 +1176,6 @@ run (struct screen *screen)
-   char *dummy[1] = { NULL };
- 
-   grub_cls ();
--  grub_printf ("  ");
--  grub_printf_ (N_("Booting a command list"));
--  grub_printf ("\n\n");
- 
-   errs_before = grub_err_printed_errors;
- 
diff --git a/SOURCES/0039-Make-our-info-pages-say-grub2-where-appropriate.patch b/SOURCES/0039-Make-our-info-pages-say-grub2-where-appropriate.patch
new file mode 100644
index 0000000..afba285
--- /dev/null
+++ b/SOURCES/0039-Make-our-info-pages-say-grub2-where-appropriate.patch
@@ -0,0 +1,1008 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 9 Jul 2019 12:59:58 +0200
+Subject: [PATCH] Make our info pages say "grub2" where appropriate.
+
+This needs to be hooked up to --program-transform=, but I haven't had
+time.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ docs/grub-dev.texi |   4 +-
+ docs/grub.texi     | 321 ++++++++++++++++++++++++++++-------------------------
+ 2 files changed, 171 insertions(+), 154 deletions(-)
+
+diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
+index 6c629a23e2..19f708ee66 100644
+--- a/docs/grub-dev.texi
++++ b/docs/grub-dev.texi
+@@ -1,7 +1,7 @@
+ \input texinfo
+ @c -*-texinfo-*-
+ @c %**start of header
+-@setfilename grub-dev.info
++@setfilename grub2-dev.info
+ @include version-dev.texi
+ @settitle GNU GRUB Developers Manual @value{VERSION}
+ @c Unify all our little indices for now.
+@@ -32,7 +32,7 @@ Invariant Sections.
+ 
+ @dircategory Kernel
+ @direntry
+-* grub-dev: (grub-dev).                 The GRand Unified Bootloader Dev
++* grub2-dev: (grub2-dev).                 The GRand Unified Bootloader Dev
+ @end direntry
+ 
+ @setchapternewpage odd
+diff --git a/docs/grub.texi b/docs/grub.texi
+index 69f08d289f..0615d0ed97 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -1,7 +1,7 @@
+ \input texinfo
+ @c -*-texinfo-*-
+ @c %**start of header
+-@setfilename grub.info
++@setfilename grub2.info
+ @include version.texi
+ @settitle GNU GRUB Manual @value{VERSION}
+ @c Unify all our little indices for now.
+@@ -32,15 +32,15 @@ Invariant Sections.
+ 
+ @dircategory Kernel
+ @direntry
+-* GRUB: (grub).                 The GRand Unified Bootloader
+-* grub-install: (grub)Invoking grub-install.    Install GRUB on your drive
+-* grub-mkconfig: (grub)Invoking grub-mkconfig.  Generate GRUB configuration
+-* grub-mkpasswd-pbkdf2: (grub)Invoking grub-mkpasswd-pbkdf2.
+-* grub-mkrelpath: (grub)Invoking grub-mkrelpath.
+-* grub-mkrescue: (grub)Invoking grub-mkrescue.  Make a GRUB rescue image
+-* grub-mount: (grub)Invoking grub-mount.        Mount a file system using GRUB
+-* grub-probe: (grub)Invoking grub-probe.        Probe device information
+-* grub-script-check: (grub)Invoking grub-script-check.
++* GRUB2: (grub2).                 The GRand Unified Bootloader
++* grub2-install: (grub2)Invoking grub2-install.    Install GRUB on your drive
++* grub2-mkconfig: (grub2)Invoking grub2-mkconfig.  Generate GRUB configuration
++* grub2-mkpasswd-pbkdf2: (grub2)Invoking grub2-mkpasswd-pbkdf2.
++* grub2-mkrelpath: (grub2)Invoking grub2-mkrelpath.
++* grub2-mkrescue: (grub2)Invoking grub2-mkrescue.  Make a GRUB rescue image
++* grub2-mount: (grub2)Invoking grub2-mount.        Mount a file system using GRUB
++* grub2-probe: (grub2)Invoking grub2-probe.        Probe device information
++* grub2-script-check: (grub2)Invoking grub2-script-check.
+ @end direntry
+ 
+ @setchapternewpage odd
+@@ -103,15 +103,15 @@ This edition documents version @value{VERSION}.
+ * Platform-specific operations:: Platform-specific operations
+ * Supported kernels::           The list of supported kernels
+ * Troubleshooting::             Error messages produced by GRUB
+-* Invoking grub-install::       How to use the GRUB installer
+-* Invoking grub-mkconfig::      Generate a GRUB configuration file
+-* Invoking grub-mkpasswd-pbkdf2::
++* Invoking grub2-install::       How to use the GRUB installer
++* Invoking grub2-mkconfig::      Generate a GRUB configuration file
++* Invoking grub2-mkpasswd-pbkdf2::
+                                 Generate GRUB password hashes
+-* Invoking grub-mkrelpath::     Make system path relative to its root
+-* Invoking grub-mkrescue::      Make a GRUB rescue image
+-* Invoking grub-mount::         Mount a file system using GRUB
+-* Invoking grub-probe::         Probe device information for GRUB
+-* Invoking grub-script-check::  Check GRUB script file for syntax errors
++* Invoking grub2-mkrelpath::     Make system path relative to its root
++* Invoking grub2-mkrescue::      Make a GRUB rescue image
++* Invoking grub2-mount::         Mount a file system using GRUB
++* Invoking grub2-probe::         Probe device information for GRUB
++* Invoking grub2-script-check::  Check GRUB script file for syntax errors
+ * Obtaining and Building GRUB:: How to obtain and build GRUB
+ * Reporting bugs::              Where you should send a bug report
+ * Future::                      Some future plans on GRUB
+@@ -230,7 +230,7 @@ surprising.
+ 
+ @item
+ @file{grub.cfg} is typically automatically generated by
+-@command{grub-mkconfig} (@pxref{Simple configuration}).  This makes it
++@command{grub2-mkconfig} (@pxref{Simple configuration}).  This makes it
+ easier to handle versioned kernel upgrades.
+ 
+ @item
+@@ -244,7 +244,7 @@ scripting language: variables, conditionals, and loops are available.
+ @item
+ A small amount of persistent storage is available across reboots, using the
+ @command{save_env} and @command{load_env} commands in GRUB and the
+-@command{grub-editenv} utility.  This is not available in all configurations
++@command{grub2-editenv} utility.  This is not available in all configurations
+ (@pxref{Environment block}).
+ 
+ @item
+@@ -549,7 +549,7 @@ On OS which have device nodes similar to Unix-like OS GRUB tools use the
+ OS name. E.g. for GNU/Linux:
+ 
+ @example
+-# @kbd{grub-install /dev/sda}
++# @kbd{grub2-install /dev/sda}
+ @end example
+ 
+ On AROS we use another syntax. For volumes:
+@@ -572,7 +572,7 @@ For disks we use syntax:
+ E.g.
+ 
+ @example
+-# @kbd{grub-install //:ata.device/0/0}
++# @kbd{grub2-install //:ata.device/0/0}
+ @end example
+ 
+ On Windows we use UNC path. For volumes it's typically
+@@ -599,7 +599,7 @@ For disks it's
+ E.g.
+ 
+ @example
+-# @kbd{grub-install \\?\PhysicalDrive0}
++# @kbd{grub2-install \\?\PhysicalDrive0}
+ @end example
+ 
+ Beware that you may need to further escape the backslashes depending on your
+@@ -609,7 +609,7 @@ When compiled with cygwin support then cygwin drive names are automatically
+ when needed. E.g.
+ 
+ @example
+-# @kbd{grub-install /dev/sda}
++# @kbd{grub2-install /dev/sda}
+ @end example
+ 
+ @node Installation
+@@ -622,7 +622,7 @@ from the source tarball, or as a package for your OS.
+ 
+ After you have done that, you need to install the boot loader on a
+ drive (floppy or hard disk) by using the utility
+-@command{grub-install} (@pxref{Invoking grub-install}) on a UNIX-like OS.
++@command{grub2-install} (@pxref{Invoking grub2-install}) on a UNIX-like OS.
+ 
+ GRUB comes with boot images, which are normally put in the directory
+ @file{/usr/lib/grub/<cpu>-<platform>} (for BIOS-based machines
+@@ -633,22 +633,22 @@ loader needs to find them (usually @file{/boot}) will be called
+ the @dfn{boot directory}.
+ 
+ @menu
+-* Installing GRUB using grub-install::
++* Installing GRUB using grub2-install::
+ * Making a GRUB bootable CD-ROM::
+ * Device map::
+ * BIOS installation::
+ @end menu
+ 
+ 
+-@node Installing GRUB using grub-install
+-@section Installing GRUB using grub-install
++@node Installing GRUB using grub2-install
++@section Installing GRUB using grub2-install
+ 
+ For information on where GRUB should be installed on PC BIOS platforms,
+ @pxref{BIOS installation}.
+ 
+ In order to install GRUB under a UNIX-like OS (such
+-as @sc{gnu}), invoke the program @command{grub-install} (@pxref{Invoking
+-grub-install}) as the superuser (@dfn{root}).
++as @sc{gnu}), invoke the program @command{grub2-install} (@pxref{Invoking
++grub2-install}) as the superuser (@dfn{root}).
+ 
+ The usage is basically very simple. You only need to specify one
+ argument to the program, namely, where to install the boot loader. The
+@@ -657,13 +657,13 @@ For example, under Linux the following will install GRUB into the MBR
+ of the first IDE disk:
+ 
+ @example
+-# @kbd{grub-install /dev/sda}
++# @kbd{grub2-install /dev/sda}
+ @end example
+ 
+ Likewise, under GNU/Hurd, this has the same effect:
+ 
+ @example
+-# @kbd{grub-install /dev/hd0}
++# @kbd{grub2-install /dev/hd0}
+ @end example
+ 
+ But all the above examples assume that GRUB should put images under
+@@ -677,7 +677,7 @@ boot floppy with a filesystem. Here is an example:
+ # @kbd{mke2fs /dev/fd0}
+ # @kbd{mount -t ext2 /dev/fd0 /mnt}
+ # @kbd{mkdir /mnt/boot}
+-# @kbd{grub-install --boot-directory=/mnt/boot /dev/fd0}
++# @kbd{grub2-install --boot-directory=/mnt/boot /dev/fd0}
+ # @kbd{umount /mnt}
+ @end group
+ @end example
+@@ -689,30 +689,37 @@ floppy instead of exposing the USB drive as a hard disk (they call it
+ @example
+ # @kbd{losetup /dev/loop0 /dev/sdb1}
+ # @kbd{mount /dev/loop0 /mnt/usb}
+-# @kbd{grub-install --boot-directory=/mnt/usb/bugbios --force --allow-floppy /dev/loop0}
++# @kbd{grub2-install --boot-directory=/mnt/usb/bugbios --force --allow-floppy /dev/loop0}
+ @end example
+ 
+ This install doesn't conflict with standard install as long as they are in
+ separate directories.
+ 
++Note that @command{grub2-install} is actually just a shell script and the
++real task is done by other tools such as @command{grub2-mkimage}. Therefore,
++you may run those commands directly to install GRUB, without using
++@command{grub2-install}. Don't do that, however, unless you are very familiar
++with the internals of GRUB. Installing a boot loader on a running OS may be
++extremely dangerous.
++
+ On EFI systems for fixed disk install you have to mount EFI System Partition.
+ If you mount it at @file{/boot/efi} then you don't need any special arguments:
+ 
+ @example
+-# @kbd{grub-install}
++# @kbd{grub2-install}
+ @end example
+ 
+ Otherwise you need to specify where your EFI System partition is mounted:
+ 
+ @example
+-# @kbd{grub-install --efi-directory=/mnt/efi}
++# @kbd{grub2-install --efi-directory=/mnt/efi}
+ @end example
+ 
+ For removable installs you have to use @option{--removable} and specify both
+ @option{--boot-directory} and @option{--efi-directory}:
+ 
+ @example
+-# @kbd{grub-install --efi-directory=/mnt/usb --boot-directory=/mnt/usb/boot --removable}
++# @kbd{grub2-install --efi-directory=/mnt/usb --boot-directory=/mnt/usb/boot --removable}
+ @end example
+ 
+ @node Making a GRUB bootable CD-ROM
+@@ -732,10 +739,10 @@ usually also need to include a configuration file @file{grub.cfg} and some
+ other GRUB modules.
+ 
+ To make a simple generic GRUB rescue CD, you can use the
+-@command{grub-mkrescue} program (@pxref{Invoking grub-mkrescue}):
++@command{grub2-mkrescue} program (@pxref{Invoking grub2-mkrescue}):
+ 
+ @example
+-$ @kbd{grub-mkrescue -o grub.iso}
++$ @kbd{grub2-mkrescue -o grub.iso}
+ @end example
+ 
+ You will often need to include other files in your image. To do this, first
+@@ -758,7 +765,7 @@ directory @file{iso/}.
+ Finally, make the image:
+ 
+ @example
+-$ @kbd{grub-mkrescue -o grub.iso iso}
++$ @kbd{grub2-mkrescue -o grub.iso iso}
+ @end example
+ 
+ This produces a file named @file{grub.iso}, which then can be burned
+@@ -774,7 +781,7 @@ storage devices.
+ @node Device map
+ @section The map between BIOS drives and OS devices
+ 
+-If the device map file exists, the GRUB utilities (@command{grub-probe},
++If the device map file exists, the GRUB utilities (@command{grub2-probe},
+ etc.) read it to map BIOS drives to OS devices.  This file consists of lines
+ like this:
+ 
+@@ -1254,23 +1261,23 @@ need to write the whole thing by hand.
+ @node Simple configuration
+ @section Simple configuration handling
+ 
+-The program @command{grub-mkconfig} (@pxref{Invoking grub-mkconfig})
++The program @command{grub2-mkconfig} (@pxref{Invoking grub2-mkconfig})
+ generates @file{grub.cfg} files suitable for most cases.  It is suitable for
+ use when upgrading a distribution, and will discover available kernels and
+ attempt to generate menu entries for them.
+ 
+-@command{grub-mkconfig} does have some limitations.  While adding extra
++@command{grub2-mkconfig} does have some limitations.  While adding extra
+ custom menu entries to the end of the list can be done by editing
+-@file{/etc/grub.d/40_custom} or creating @file{/boot/grub/custom.cfg},
++@file{/etc/grub.d/40_custom} or creating @file{/boot/grub2/custom.cfg},
+ changing the order of menu entries or changing their titles may require
+ making complex changes to shell scripts stored in @file{/etc/grub.d/}.  This
+ may be improved in the future.  In the meantime, those who feel that it
+ would be easier to write @file{grub.cfg} directly are encouraged to do so
+ (@pxref{Booting}, and @ref{Shell-like scripting}), and to disable any system
+-provided by their distribution to automatically run @command{grub-mkconfig}.
++provided by their distribution to automatically run @command{grub2-mkconfig}.
+ 
+ The file @file{/etc/default/grub} controls the operation of
+-@command{grub-mkconfig}.  It is sourced by a shell script, and so must be
++@command{grub2-mkconfig}.  It is sourced by a shell script, and so must be
+ valid POSIX shell input; normally, it will just be a sequence of
+ @samp{KEY=value} lines, but if the value contains spaces or other special
+ characters then it must be quoted.  For example:
+@@ -1308,7 +1315,7 @@ works it's not recommended since titles often contain unstable device names
+ and may be translated
+ 
+ If you set this to @samp{saved}, then the default menu entry will be that
+-saved by @samp{GRUB_SAVEDEFAULT} or @command{grub-set-default}.  This relies on
++saved by @samp{GRUB_SAVEDEFAULT} or @command{grub2-set-default}.  This relies on
+ the environment block, which may not be available in all situations
+ (@pxref{Environment block}).
+ 
+@@ -1319,7 +1326,7 @@ If this option is set to @samp{true}, then, when an entry is selected, save
+ it as a new default entry for use by future runs of GRUB.  This is only
+ useful if @samp{GRUB_DEFAULT=saved}; it is a separate option because
+ @samp{GRUB_DEFAULT=saved} is useful without this option, in conjunction with
+-@command{grub-set-default}.  Unset by default.
++@command{grub2-set-default}.  Unset by default.
+ This option relies on the environment block, which may not be available in
+ all situations (@pxref{Environment block}).
+ 
+@@ -1449,7 +1456,7 @@ intel-uc.img intel-ucode.img amd-uc.img amd-ucode.img early_ucode.cpio microcode
+ @end example
+ 
+ @item GRUB_DISABLE_LINUX_UUID
+-Normally, @command{grub-mkconfig} will generate menu entries that use
++Normally, @command{grub2-mkconfig} will generate menu entries that use
+ universally-unique identifiers (UUIDs) to identify the root filesystem to
+ the Linux kernel, using a @samp{root=UUID=...} kernel parameter.  This is
+ usually more reliable, but in some cases it may not be appropriate.  To
+@@ -1471,7 +1478,7 @@ If this option is set to @samp{true}, disable the generation of recovery
+ mode menu entries.
+ 
+ @item GRUB_DISABLE_UUID
+-Normally, @command{grub-mkconfig} will generate menu entries that use
++Normally, @command{grub2-mkconfig} will generate menu entries that use
+ universally-unique identifiers (UUIDs) to identify various filesystems to
+ search for files.  This is usually more reliable, but in some cases it may
+ not be appropriate.  To disable this use of UUIDs, set this option to
+@@ -1482,12 +1489,12 @@ not be appropriate.  To disable this use of UUIDs, set this option to
+ @item GRUB_VIDEO_BACKEND
+ If graphical video support is required, either because the @samp{gfxterm}
+ graphical terminal is in use or because @samp{GRUB_GFXPAYLOAD_LINUX} is set,
+-then @command{grub-mkconfig} will normally load all available GRUB video
++then @command{grub2-mkconfig} will normally load all available GRUB video
+ drivers and use the one most appropriate for your hardware.  If you need to
+ override this for some reason, then you can set this option.
+ 
+-After @command{grub-install} has been run, the available video drivers are
+-listed in @file{/boot/grub/video.lst}.
++After @command{grub2-install} has been run, the available video drivers are
++listed in @file{/boot/grub2/video.lst}.
+ 
+ @item GRUB_GFXMODE
+ Set the resolution used on the @samp{gfxterm} graphical terminal.  Note that
+@@ -1519,7 +1526,7 @@ boot sequence.  If you have problems, set this option to @samp{text} and
+ GRUB will tell Linux to boot in normal text mode.
+ 
+ @item GRUB_DISABLE_OS_PROBER
+-Normally, @command{grub-mkconfig} will try to use the external
++Normally, @command{grub2-mkconfig} will try to use the external
+ @command{os-prober} program, if installed, to discover other operating
+ systems installed on the same system and generate appropriate menu entries
+ for them.  Set this option to @samp{true} to disable this.
+@@ -1529,7 +1536,7 @@ List of space-separated FS UUIDs of filesystems to be ignored from os-prober
+ output. For efi chainloaders it's <UUID>@@<EFI FILE>
+ 
+ @item GRUB_DISABLE_SUBMENU
+-Normally, @command{grub-mkconfig} will generate top level menu entry for
++Normally, @command{grub2-mkconfig} will generate top level menu entry for
+ the kernel with highest version number and put all other found kernels
+ or alternative menu entries for recovery mode in submenu. For entries returned
+ by @command{os-prober} first entry will be put on top level and all others
+@@ -1537,11 +1544,11 @@ in submenu. If this option is set to @samp{true}, flat menu with all entries
+ on top level will be generated instead. Changing this option will require
+ changing existing values of @samp{GRUB_DEFAULT}, @samp{fallback} (@pxref{fallback})
+ and @samp{default} (@pxref{default}) environment variables as well as saved
+-default entry using @command{grub-set-default} and value used with
+-@command{grub-reboot}.
++default entry using @command{grub2-set-default} and value used with
++@command{grub2-reboot}.
+ 
+ @item GRUB_ENABLE_CRYPTODISK
+-If set to @samp{y}, @command{grub-mkconfig} and @command{grub-install} will
++If set to @samp{y}, @command{grub2-mkconfig} and @command{grub2-install} will
+ check for encrypted disks and generate additional commands needed to access
+ them during boot.  Note that in this case unattended boot is not possible
+ because GRUB will wait for passphrase to unlock encrypted container.
+@@ -1600,7 +1607,7 @@ confusing @samp{GRUB_TIMEOUT_STYLE=countdown} or
+ 
+ @end table
+ 
+-For more detailed customisation of @command{grub-mkconfig}'s output, you may
++For more detailed customisation of @command{grub2-mkconfig}'s output, you may
+ edit the scripts in @file{/etc/grub.d} directly.
+ @file{/etc/grub.d/40_custom} is particularly useful for adding entire custom
+ menu entries; simply type the menu entries you want to add at the end of
+@@ -1862,7 +1869,7 @@ images as well.
+ Mount this partition on/mnt/boot and disable GRUB in all OSes and manually
+ install self-compiled latest GRUB with:
+ 
+-@code{grub-install --boot-directory=/mnt/boot /dev/sda}
++@code{grub2-install --boot-directory=/mnt/boot /dev/sda}
+ 
+ In all the OSes install GRUB tools but disable installing GRUB in bootsector,
+ so you'll have menu.lst and grub.cfg available for use. Also disable os-prober
+@@ -1872,20 +1879,20 @@ use by setting:
+ 
+ in /etc/default/grub
+ 
+-Then write a grub.cfg (/mnt/boot/grub/grub.cfg):
++Then write a grub.cfg (/mnt/boot/grub2/grub.cfg):
+ 
+ @example
+ 
+ menuentry "OS using grub2" @{
+    insmod xfs
+    search --set=root --label OS1 --hint hd0,msdos8
+-   configfile /boot/grub/grub.cfg
++   configfile /boot/grub2/grub.cfg
+ @}
+ 
+ menuentry "OS using grub2-legacy" @{
+    insmod ext2
+    search --set=root --label OS2 --hint hd0,msdos6
+-   legacy_configfile /boot/grub/menu.lst
++   legacy_configfile /boot/grub2/menu.lst
+ @}
+ 
+ menuentry "Windows XP" @{
+@@ -1948,15 +1955,15 @@ GRUB supports embedding a configuration file directly into the core image,
+ so that it is loaded before entering normal mode.  This is useful, for
+ example, when it is not straightforward to find the real configuration file,
+ or when you need to debug problems with loading that file.
+-@command{grub-install} uses this feature when it is not using BIOS disk
++@command{grub2-install} uses this feature when it is not using BIOS disk
+ functions or when installing to a different disk from the one containing
+ @file{/boot/grub}, in which case it needs to use the @command{search}
+ command (@pxref{search}) to find @file{/boot/grub}.
+ 
+ To embed a configuration file, use the @option{-c} option to
+-@command{grub-mkimage}.  The file is copied into the core image, so it may
++@command{grub2-mkimage}.  The file is copied into the core image, so it may
+ reside anywhere on the file system, and may be removed after running
+-@command{grub-mkimage}.
++@command{grub2-mkimage}.
+ 
+ After the embedded configuration file (if any) is executed, GRUB will load
+ the @samp{normal} module (@pxref{normal}), which will then read the real
+@@ -1991,13 +1998,13 @@ included in the core image:
+ @example
+ @group
+ search.fs_label grub root
+-if [ -e /boot/grub/example/test1.cfg ]; then
++if [ -e /boot/grub2/example/test1.cfg ]; then
+     set prefix=($root)/boot/grub
+-    configfile /boot/grub/example/test1.cfg
++    configfile /boot/grub2/example/test1.cfg
+ else
+-    if [ -e /boot/grub/example/test2.cfg ]; then
++    if [ -e /boot/grub2/example/test2.cfg ]; then
+         set prefix=($root)/boot/grub
+-        configfile /boot/grub/example/test2.cfg
++        configfile /boot/grub2/example/test2.cfg
+     else
+         echo "Could not find an example configuration file!"
+     fi
+@@ -2521,7 +2528,7 @@ grub-mknetdir --net-directory=/srv/tftp --subdir=/boot/grub -d /usr/lib/grub/i38
+ @end group
+ @end example
+ 
+-Then follow instructions printed out by grub-mknetdir on configuring your DHCP
++Then follow instructions printed out by grub2-mknetdir on configuring your DHCP
+ server.
+ 
+ The grub.cfg file is placed in the same directory as the path output by
+@@ -2715,7 +2722,7 @@ team are:
+ @end table
+ 
+ To take full advantage of this function, install GRUB into the MBR
+-(@pxref{Installing GRUB using grub-install}).
++(@pxref{Installing GRUB using grub2-install}).
+ 
+ If you have a laptop which has a similar feature and not in the above list
+ could you figure your address and contribute?
+@@ -2776,7 +2783,7 @@ bytes.
+ The sole function of @file{boot.img} is to read the first sector of the core
+ image from a local disk and jump to it.  Because of the size restriction,
+ @file{boot.img} cannot understand any file system structure, so
+-@command{grub-install} hardcodes the location of the first sector of the
++@command{grub2-install} hardcodes the location of the first sector of the
+ core image into @file{boot.img} when installing GRUB.
+ 
+ @item diskboot.img
+@@ -2806,7 +2813,7 @@ images.
+ 
+ @item core.img
+ This is the core image of GRUB.  It is built dynamically from the kernel
+-image and an arbitrary list of modules by the @command{grub-mkimage}
++image and an arbitrary list of modules by the @command{grub2-mkimage}
+ program.  Usually, it contains enough modules to access @file{/boot/grub},
+ and loads everything else (including menu handling, the ability to load
+ target operating systems, and so on) from the file system at run-time.  The
+@@ -2858,7 +2865,7 @@ GRUB 2 has no single Stage 2 image.  Instead, it loads modules from
+ In GRUB 2, images for booting from CD-ROM drives are now constructed using
+ @file{cdboot.img} and @file{core.img}, making sure that the core image
+ contains the @samp{iso9660} module.  It is usually best to use the
+-@command{grub-mkrescue} program for this.
++@command{grub2-mkrescue} program for this.
+ 
+ @item nbgrub
+ There is as yet no equivalent for @file{nbgrub} in GRUB 2; it was used by
+@@ -3014,8 +3021,8 @@ There are two ways to specify files, by @dfn{absolute file name} and by
+ 
+ An absolute file name resembles a Unix absolute file name, using
+ @samp{/} for the directory separator (not @samp{\} as in DOS). One
+-example is @samp{(hd0,1)/boot/grub/grub.cfg}. This means the file
+-@file{/boot/grub/grub.cfg} in the first partition of the first hard
++example is @samp{(hd0,1)/boot/grub2/grub.cfg}. This means the file
++@file{/boot/grub2/grub.cfg} in the first partition of the first hard
+ disk. If you omit the device name in an absolute file name, GRUB uses
+ GRUB's @dfn{root device} implicitly. So if you set the root device to,
+ say, @samp{(hd1,1)} by the command @samp{set root=(hd1,1)} (@pxref{set}),
+@@ -3023,8 +3030,8 @@ then @code{/boot/kernel} is the same as @code{(hd1,1)/boot/kernel}.
+ 
+ On ZFS filesystem the first path component must be
+ @var{volume}@samp{@@}[@var{snapshot}].
+-So @samp{/rootvol@@snap-129/boot/grub/grub.cfg} refers to file
+-@samp{/boot/grub/grub.cfg} in snapshot of volume @samp{rootvol} with name
++So @samp{/rootvol@@snap-129/boot/grub2/grub.cfg} refers to file
++@samp{/boot/grub2/grub.cfg} in snapshot of volume @samp{rootvol} with name
+ @samp{snap-129}.  Trailing @samp{@@} after volume name is mandatory even if
+ snapshot name is omitted.
+ 
+@@ -3427,7 +3434,7 @@ The more recent release of Minix would then be identified as
+ @samp{other>minix>minix-3.4.0}.
+ 
+ This variable is often set by @samp{GRUB_DEFAULT} (@pxref{Simple
+-configuration}), @command{grub-set-default}, or @command{grub-reboot}.
++configuration}), @command{grub2-set-default}, or @command{grub2-reboot}.
+ 
+ 
+ @node fallback
+@@ -3517,7 +3524,7 @@ If this variable is set, it names the language code that the
+ example, French would be named as @samp{fr}, and Simplified Chinese as
+ @samp{zh_CN}.
+ 
+-@command{grub-mkconfig} (@pxref{Simple configuration}) will try to set a
++@command{grub2-mkconfig} (@pxref{Simple configuration}) will try to set a
+ reasonable default for this variable based on the system locale.
+ 
+ 
+@@ -3525,10 +3532,10 @@ reasonable default for this variable based on the system locale.
+ @subsection locale_dir
+ 
+ If this variable is set, it names the directory where translation files may
+-be found (@pxref{gettext}), usually @file{/boot/grub/locale}.  Otherwise,
++be found (@pxref{gettext}), usually @file{/boot/grub2/locale}.  Otherwise,
+ internationalization is disabled.
+ 
+-@command{grub-mkconfig} (@pxref{Simple configuration}) will set a reasonable
++@command{grub2-mkconfig} (@pxref{Simple configuration}) will set a reasonable
+ default for this variable if internationalization is needed and any
+ translation files are available.
+ 
+@@ -3646,7 +3653,7 @@ input.  The default is not to pause output.
+ 
+ The location of the @samp{/boot/grub} directory as an absolute file name
+ (@pxref{File name syntax}).  This is normally set by GRUB at startup based
+-on information provided by @command{grub-install}.  GRUB modules are
++on information provided by @command{grub2-install}.  GRUB modules are
+ dynamically loaded from this directory, so it must be set correctly in order
+ for many parts of GRUB to work.
+ 
+@@ -3737,17 +3744,17 @@ GRUB provides an ``environment block'' which can be used to save a small
+ amount of state.
+ 
+ The environment block is a preallocated 1024-byte file, which normally lives
+-in @file{/boot/grub/grubenv} (although you should not assume this).  At boot
++in @file{/boot/grub2/grubenv} (although you should not assume this).  At boot
+ time, the @command{load_env} command (@pxref{load_env}) loads environment
+ variables from it, and the @command{save_env} (@pxref{save_env}) command
+ saves environment variables to it.  From a running system, the
+-@command{grub-editenv} utility can be used to edit the environment block.
++@command{grub2-editenv} utility can be used to edit the environment block.
+ 
+ For safety reasons, this storage is only available when installed on a plain
+ disk (no LVM or RAID), using a non-checksumming filesystem (no ZFS), and
+ using BIOS or EFI functions (no ATA, USB or IEEE1275).
+ 
+-@command{grub-mkconfig} uses this facility to implement
++@command{grub2-mkconfig} uses this facility to implement
+ @samp{GRUB_SAVEDEFAULT} (@pxref{Simple configuration}).
+ 
+ 
+@@ -4476,7 +4483,7 @@ Translate @var{string} into the current language.
+ 
+ The current language code is stored in the @samp{lang} variable in GRUB's
+ environment (@pxref{lang}).  Translation files in MO format are read from
+-@samp{locale_dir} (@pxref{locale_dir}), usually @file{/boot/grub/locale}.
++@samp{locale_dir} (@pxref{locale_dir}), usually @file{/boot/grub2/locale}.
+ @end deffn
+ 
+ 
+@@ -4871,7 +4878,7 @@ Define a user named @var{user} with password @var{clear-password}.
+ 
+ @deffn Command password_pbkdf2 user hashed-password
+ Define a user named @var{user} with password hash @var{hashed-password}.
+-Use @command{grub-mkpasswd-pbkdf2} (@pxref{Invoking grub-mkpasswd-pbkdf2})
++Use @command{grub2-mkpasswd-pbkdf2} (@pxref{Invoking grub2-mkpasswd-pbkdf2})
+ to generate password hashes.  @xref{Security}.
+ @end deffn
+ 
+@@ -5814,8 +5821,8 @@ The @samp{password} (@pxref{password}) and @samp{password_pbkdf2}
+ which has an associated password.  @samp{password} sets the password in
+ plain text, requiring @file{grub.cfg} to be secure; @samp{password_pbkdf2}
+ sets the password hashed using the Password-Based Key Derivation Function
+-(RFC 2898), requiring the use of @command{grub-mkpasswd-pbkdf2}
+-(@pxref{Invoking grub-mkpasswd-pbkdf2}) to generate password hashes.
++(RFC 2898), requiring the use of @command{grub2-mkpasswd-pbkdf2}
++(@pxref{Invoking grub2-mkpasswd-pbkdf2}) to generate password hashes.
+ 
+ In order to enable authentication support, the @samp{superusers} environment
+ variable must be set to a list of usernames, separated by any of spaces,
+@@ -5860,7 +5867,7 @@ menuentry "May be run by user1 or a superuser" --users user1 @{
+ @end group
+ @end example
+ 
+-The @command{grub-mkconfig} program does not yet have built-in support for
++The @command{grub2-mkconfig} program does not yet have built-in support for
+ generating configuration files with authentication.  You can use
+ @file{/etc/grub.d/40_custom} to add simple superuser authentication, by
+ adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2}
+@@ -5887,7 +5894,17 @@ may halt or otherwise impact the boot process.
+ 
+ An initial trusted public key can be embedded within the GRUB @file{core.img}
+ using the @code{--pubkey} option to @command{grub-install}
+-(@pxref{Invoking grub-install}).
++(@pxref{Invoking grub2-install}).
++
++@comment Unfortunately --pubkey is not yet supported by grub2-install,
++@comment but we should not bring up internal detail grub2-mkimage here
++@comment in the user guide (as opposed to developer's manual).
++
++@comment An initial trusted public key can be embedded within the GRUB
++@comment @file{core.img} using the @code{--pubkey} option to
++@comment @command{grub2-mkimage} (@pxref{Invoking grub2-install}).  Presently it
++@comment is necessary to write a custom wrapper around @command{grub2-mkimage}
++@comment using the @code{--grub-mkimage} flag to @command{grub2-install}.
+ 
+ GRUB uses GPG-style detached signatures (meaning that a file
+ @file{foo.sig} will be produced when file @file{foo} is signed), and
+@@ -5907,8 +5924,8 @@ gpg --detach-sign /path/to/file
+ For successful validation of all of GRUB's subcomponents and the
+ loaded OS kernel, they must all be signed.  One way to accomplish this
+ is the following (after having already produced the desired
+-@file{grub.cfg} file, e.g., by running @command{grub-mkconfig}
+-(@pxref{Invoking grub-mkconfig}):
++@file{grub.cfg} file, e.g., by running @command{grub2-mkconfig}
++(@pxref{Invoking grub2-mkconfig}):
+ 
+ @example
+ @group
+@@ -5930,7 +5947,7 @@ See also: @ref{check_signatures}, @ref{verify_detached}, @ref{trust},
+ Note that internally signature enforcement is controlled by setting
+ the environment variable @code{check_signatures} equal to
+ @code{enforce}.  Passing one or more @code{--pubkey} options to
+-@command{grub-mkimage} implicitly defines @code{check_signatures}
++@command{grub2-mkimage} implicitly defines @code{check_signatures}
+ equal to @code{enforce} in @file{core.img} prior to processing any
+ configuration files.
+ 
+@@ -6388,10 +6405,10 @@ Required files are:
+ 
+ GRUB's normal start-up procedure involves setting the @samp{prefix}
+ environment variable to a value set in the core image by
+-@command{grub-install}, setting the @samp{root} variable to match, loading
++@command{grub2-install}, setting the @samp{root} variable to match, loading
+ the @samp{normal} module from the prefix, and running the @samp{normal}
+ command (@pxref{normal}).  This command is responsible for reading
+-@file{/boot/grub/grub.cfg}, running the menu, and doing all the useful
++@file{/boot/grub2/grub.cfg}, running the menu, and doing all the useful
+ things GRUB is supposed to do.
+ 
+ If, instead, you only get a rescue shell, this usually means that GRUB
+@@ -6417,8 +6434,8 @@ normal
+ 
+ However, any problem that leaves you in the rescue shell probably means that
+ GRUB was not correctly installed.  It may be more useful to try to reinstall
+-it properly using @kbd{grub-install @var{device}} (@pxref{Invoking
+-grub-install}).  When doing this, there are a few things to remember:
++it properly using @kbd{grub2-install @var{device}} (@pxref{Invoking
++grub2-install}).  When doing this, there are a few things to remember:
+ 
+ @itemize @bullet{}
+ @item
+@@ -6430,7 +6447,7 @@ is usually better to use UUIDs or file system labels and avoid depending on
+ drive ordering entirely.
+ 
+ @item
+-At least on BIOS systems, if you tell @command{grub-install} to install GRUB
++At least on BIOS systems, if you tell @command{grub2-install} to install GRUB
+ to a partition but GRUB has already been installed in the master boot
+ record, then the GRUB installation in the partition will be ignored.
+ 
+@@ -6461,21 +6478,21 @@ entry which claims partition start at block 0. This change will not hamper
+ bootability on other machines.
+ 
+ 
+-@node Invoking grub-install
+-@chapter Invoking grub-install
++@node Invoking grub2-install
++@chapter Invoking grub2-install
+ 
+-The program @command{grub-install} generates a GRUB core image using
+-@command{grub-mkimage} and installs it on your system.  You must specify the
++The program @command{grub2-install} generates a GRUB core image using
++@command{grub2-mkimage} and installs it on your system.  You must specify the
+ device name on which you want to install GRUB, like this:
+ 
+ @example
+-grub-install @var{install_device}
++grub2-install @var{install_device}
+ @end example
+ 
+ The device name @var{install_device} is an OS device name or a GRUB
+ device name.
+ 
+-@command{grub-install} accepts the following options:
++@command{grub2-install} accepts the following options:
+ 
+ @table @option
+ @item --help
+@@ -6491,13 +6508,13 @@ separate partition or a removable disk.
+ If this option is not specified then it defaults to @file{/boot}, so
+ 
+ @example
+-@kbd{grub-install /dev/sda}
++@kbd{grub2-install /dev/sda}
+ @end example
+ 
+ is equivalent to
+ 
+ @example
+-@kbd{grub-install --boot-directory=/boot/ /dev/sda}
++@kbd{grub2-install --boot-directory=/boot/ /dev/sda}
+ @end example
+ 
+ Here is an example in which you have a separate @dfn{boot} partition which is 
+@@ -6505,16 +6522,16 @@ mounted on
+ @file{/mnt/boot}:
+ 
+ @example
+-@kbd{grub-install --boot-directory=/mnt/boot /dev/sdb}
++@kbd{grub2-install --boot-directory=/mnt/boot /dev/sdb}
+ @end example
+ 
+ @item --recheck
+-Recheck the device map, even if @file{/boot/grub/device.map} already
++Recheck the device map, even if @file{/boot/grub2/device.map} already
+ exists. You should use this option whenever you add/remove a disk
+ into/from your computer.
+ 
+ @item --no-rs-codes
+-By default on x86 BIOS systems, @command{grub-install} will use some
++By default on x86 BIOS systems, @command{grub2-install} will use some
+ extra space in the bootloader embedding area for Reed-Solomon
+ error-correcting codes. This enables GRUB to still boot successfully
+ if some blocks are corrupted.  The exact amount of protection offered
+@@ -6527,17 +6544,17 @@ installation}) where GRUB does not reside in any unpartitioned space
+ outside of the MBR.  Disable the Reed-Solomon codes with this option.
+ @end table
+ 
+-@node Invoking grub-mkconfig
+-@chapter Invoking grub-mkconfig
++@node Invoking grub2-mkconfig
++@chapter Invoking grub2-mkconfig
+ 
+-The program @command{grub-mkconfig} generates a configuration file for GRUB
++The program @command{grub2-mkconfig} generates a configuration file for GRUB
+ (@pxref{Simple configuration}).
+ 
+ @example
+-grub-mkconfig -o /boot/grub/grub.cfg
++grub-mkconfig -o /boot/grub2/grub.cfg
+ @end example
+ 
+-@command{grub-mkconfig} accepts the following options:
++@command{grub2-mkconfig} accepts the following options:
+ 
+ @table @option
+ @item --help
+@@ -6553,17 +6570,17 @@ it to standard output.
+ @end table
+ 
+ 
+-@node Invoking grub-mkpasswd-pbkdf2
+-@chapter Invoking grub-mkpasswd-pbkdf2
++@node Invoking grub2-mkpasswd-pbkdf2
++@chapter Invoking grub2-mkpasswd-pbkdf2
+ 
+-The program @command{grub-mkpasswd-pbkdf2} generates password hashes for
++The program @command{grub2-mkpasswd-pbkdf2} generates password hashes for
+ GRUB (@pxref{Security}).
+ 
+ @example
+ grub-mkpasswd-pbkdf2
+ @end example
+ 
+-@command{grub-mkpasswd-pbkdf2} accepts the following options:
++@command{grub2-mkpasswd-pbkdf2} accepts the following options:
+ 
+ @table @option
+ @item -c @var{number}
+@@ -6581,23 +6598,23 @@ Length of the salt.  Defaults to 64.
+ @end table
+ 
+ 
+-@node Invoking grub-mkrelpath
+-@chapter Invoking grub-mkrelpath
++@node Invoking grub2-mkrelpath
++@chapter Invoking grub2-mkrelpath
+ 
+-The program @command{grub-mkrelpath} makes a file system path relative to
++The program @command{grub2-mkrelpath} makes a file system path relative to
+ the root of its containing file system.  For instance, if @file{/usr} is a
+ mount point, then:
+ 
+ @example
+-$ @kbd{grub-mkrelpath /usr/share/grub/unicode.pf2}
++$ @kbd{grub2-mkrelpath /usr/share/grub/unicode.pf2}
+ @samp{/share/grub/unicode.pf2}
+ @end example
+ 
+ This is mainly used internally by other GRUB utilities such as
+-@command{grub-mkconfig} (@pxref{Invoking grub-mkconfig}), but may
++@command{grub2-mkconfig} (@pxref{Invoking grub2-mkconfig}), but may
+ occasionally also be useful for debugging.
+ 
+-@command{grub-mkrelpath} accepts the following options:
++@command{grub2-mkrelpath} accepts the following options:
+ 
+ @table @option
+ @item --help
+@@ -6608,17 +6625,17 @@ Print the version number of GRUB and exit.
+ @end table
+ 
+ 
+-@node Invoking grub-mkrescue
+-@chapter Invoking grub-mkrescue
++@node Invoking grub2-mkrescue
++@chapter Invoking grub2-mkrescue
+ 
+-The program @command{grub-mkrescue} generates a bootable GRUB rescue image
++The program @command{grub2-mkrescue} generates a bootable GRUB rescue image
+ (@pxref{Making a GRUB bootable CD-ROM}).
+ 
+ @example
+ grub-mkrescue -o grub.iso
+ @end example
+ 
+-All arguments not explicitly listed as @command{grub-mkrescue} options are
++All arguments not explicitly listed as @command{grub2-mkrescue} options are
+ passed on directly to @command{xorriso} in @command{mkisofs} emulation mode.
+ Options passed to @command{xorriso} will normally be interpreted as
+ @command{mkisofs} options; if the option @samp{--} is used, then anything
+@@ -6633,7 +6650,7 @@ mkdir -p disk/boot/grub
+ grub-mkrescue -o grub.iso disk
+ @end example
+ 
+-@command{grub-mkrescue} accepts the following options:
++@command{grub2-mkrescue} accepts the following options:
+ 
+ @table @option
+ @item --help
+@@ -6661,15 +6678,15 @@ Use @var{file} as the @command{xorriso} program, rather than the built-in
+ default.
+ 
+ @item --grub-mkimage=@var{file}
+-Use @var{file} as the @command{grub-mkimage} program, rather than the
++Use @var{file} as the @command{grub2-mkimage} program, rather than the
+ built-in default.
+ @end table
+ 
+ 
+-@node Invoking grub-mount
+-@chapter Invoking grub-mount
++@node Invoking grub2-mount
++@chapter Invoking grub2-mount
+ 
+-The program @command{grub-mount} performs a read-only mount of any file
++The program @command{grub2-mount} performs a read-only mount of any file
+ system or file system image that GRUB understands, using GRUB's file system
+ drivers via FUSE.  (It is only available if FUSE development files were
+ present when GRUB was built.)  This has a number of uses:
+@@ -6701,13 +6718,13 @@ even if nobody has yet written a FUSE module specifically for that file
+ system type.
+ @end itemize
+ 
+-Using @command{grub-mount} is normally as simple as:
++Using @command{grub2-mount} is normally as simple as:
+ 
+ @example
+ grub-mount /dev/sda1 /mnt
+ @end example
+ 
+-@command{grub-mount} must be given one or more images and a mount point as
++@command{grub2-mount} must be given one or more images and a mount point as
+ non-option arguments (if it is given more than one image, it will treat them
+ as a RAID set), and also accepts the following options:
+ 
+@@ -6729,13 +6746,13 @@ Show debugging output for conditions matching @var{string}.
+ @item -K prompt|@var{file}
+ @itemx --zfs-key=prompt|@var{file}
+ Load a ZFS encryption key.  If you use @samp{prompt} as the argument,
+-@command{grub-mount} will read a passphrase from the terminal; otherwise, it
++@command{grub2-mount} will read a passphrase from the terminal; otherwise, it
+ will read key material from the specified file.
+ 
+ @item -r @var{device}
+ @itemx --root=@var{device}
+ Set the GRUB root device to @var{device}.  You do not normally need to set
+-this; @command{grub-mount} will automatically set the root device to the
++this; @command{grub2-mount} will automatically set the root device to the
+ root of the supplied file system.
+ 
+ If @var{device} is just a number, then it will be treated as a partition
+@@ -6753,10 +6770,10 @@ Print verbose messages.
+ @end table
+ 
+ 
+-@node Invoking grub-probe
+-@chapter Invoking grub-probe
++@node Invoking grub2-probe
++@chapter Invoking grub2-probe
+ 
+-The program @command{grub-probe} probes device information for a given path
++The program @command{grub2-probe} probes device information for a given path
+ or device.
+ 
+ @example
+@@ -6764,7 +6781,7 @@ grub-probe --target=fs /boot/grub
+ grub-probe --target=drive --device /dev/sda1
+ @end example
+ 
+-@command{grub-probe} must be given a path or device as a non-option
++@command{grub2-probe} must be given a path or device as a non-option
+ argument, and also accepts the following options:
+ 
+ @table @option
+@@ -6777,16 +6794,16 @@ Print the version number of GRUB and exit.
+ @item -d
+ @itemx --device
+ If this option is given, then the non-option argument is a system device
+-name (such as @samp{/dev/sda1}), and @command{grub-probe} will print
++name (such as @samp{/dev/sda1}), and @command{grub2-probe} will print
+ information about that device.  If it is not given, then the non-option
+ argument is a filesystem path (such as @samp{/boot/grub}), and
+-@command{grub-probe} will print information about the device containing that
++@command{grub2-probe} will print information about the device containing that
+ part of the filesystem.
+ 
+ @item -m @var{file}
+ @itemx --device-map=@var{file}
+ Use @var{file} as the device map (@pxref{Device map}) rather than the
+-default, usually @samp{/boot/grub/device.map}.
++default, usually @samp{/boot/grub2/device.map}.
+ 
+ @item -t @var{target}
+ @itemx --target=@var{target}
+@@ -6839,19 +6856,19 @@ Print verbose messages.
+ @end table
+ 
+ 
+-@node Invoking grub-script-check
+-@chapter Invoking grub-script-check
++@node Invoking grub2-script-check
++@chapter Invoking grub2-script-check
+ 
+-The program @command{grub-script-check} takes a GRUB script file
++The program @command{grub2-script-check} takes a GRUB script file
+ (@pxref{Shell-like scripting}) and checks it for syntax errors, similar to
+ commands such as @command{sh -n}.  It may take a @var{path} as a non-option
+ argument; if none is supplied, it will read from standard input.
+ 
+ @example
+-grub-script-check /boot/grub/grub.cfg
++grub-script-check /boot/grub2/grub.cfg
+ @end example
+ 
+-@command{grub-script-check} accepts the following options:
++@command{grub2-script-check} accepts the following options:
+ 
+ @table @option
+ @item --help
diff --git a/SOURCES/0040-Replace-a-lot-of-man-pages-with-slightly-nicer-ones.patch b/SOURCES/0040-Replace-a-lot-of-man-pages-with-slightly-nicer-ones.patch
deleted file mode 100644
index daa6fae..0000000
--- a/SOURCES/0040-Replace-a-lot-of-man-pages-with-slightly-nicer-ones.patch
+++ /dev/null
@@ -1,1959 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 4 Mar 2014 11:00:23 -0500
-Subject: [PATCH] Replace a lot of man pages with slightly nicer ones.
-
-Replace a bunch of machine generated ones with ones that look nicer.
----
- configure.ac                      |  23 ++++++
- conf/Makefile.extra-dist          |   1 -
- docs/Makefile.am                  |   2 -
- docs/man/grub-bios-setup.h2m      |   6 --
- docs/man/grub-editenv.h2m         |   5 --
- docs/man/grub-emu.h2m             |   6 --
- docs/man/grub-file.h2m            |   2 -
- docs/man/grub-fstest.h2m          |   4 -
- docs/man/grub-glue-efi.h2m        |   4 -
- docs/man/grub-install.h2m         |   6 --
- docs/man/grub-kbdcomp.h2m         |  10 ---
- docs/man/grub-macbless.h2m        |   4 -
- docs/man/grub-macho2img.h2m       |   4 -
- docs/man/grub-menulst2cfg.h2m     |   4 -
- docs/man/grub-mkconfig.h2m        |   4 -
- docs/man/grub-mkfont.h2m          |   4 -
- docs/man/grub-mkimage.h2m         |   6 --
- docs/man/grub-mklayout.h2m        |  10 ---
- docs/man/grub-mknetdir.h2m        |   4 -
- docs/man/grub-mkpasswd-pbkdf2.h2m |   4 -
- docs/man/grub-mkrelpath.h2m       |   4 -
- docs/man/grub-mkrescue.h2m        |   4 -
- docs/man/grub-mkstandalone.h2m    |   4 -
- docs/man/grub-mount.h2m           |   2 -
- docs/man/grub-ofpathname.h2m      |   4 -
- docs/man/grub-pe2elf.h2m          |   4 -
- docs/man/grub-probe.h2m           |   4 -
- docs/man/grub-reboot.h2m          |   5 --
- docs/man/grub-render-label.h2m    |   3 -
- docs/man/grub-script-check.h2m    |   4 -
- docs/man/grub-set-default.h2m     |   5 --
- docs/man/grub-sparc64-setup.h2m   |   6 --
- docs/man/grub-syslinux2cfg.h2m    |   4 -
- gentpl.py                         |   5 +-
- util/grub-bios-setup.8            |  54 +++++++++++++
- util/grub-editenv.1               |  46 +++++++++++
- util/grub-file.1                  | 165 ++++++++++++++++++++++++++++++++++++++
- util/grub-fstest.1                |  99 +++++++++++++++++++++++
- util/grub-glue-efi.1              |  31 +++++++
- util/grub-install.8               | 128 +++++++++++++++++++++++++++++
- util/grub-kbdcomp.1               |  19 +++++
- util/grub-macbless.1              |  22 +++++
- util/grub-menulst2cfg.1           |  12 +++
- util/grub-mkconfig.8              |  17 ++++
- util/grub-mkfont.1                |  87 ++++++++++++++++++++
- util/grub-mkimage.1               |  95 ++++++++++++++++++++++
- util/grub-mklayout.1              |  27 +++++++
- util/grub-mknetdir.1              |  12 +++
- util/grub-mkpasswd-pbkdf2.1       |  27 +++++++
- util/grub-mkrelpath.1             |  12 +++
- util/grub-mkrescue.1              | 123 ++++++++++++++++++++++++++++
- util/grub-mkstandalone.1          | 100 +++++++++++++++++++++++
- util/grub-ofpathname.8            |  12 +++
- util/grub-probe.8                 |  80 ++++++++++++++++++
- util/grub-reboot.8                |  21 +++++
- util/grub-render-label.1          |  51 ++++++++++++
- util/grub-script-check.1          |  21 +++++
- util/grub-set-default.8           |  21 +++++
- util/grub-sparc64-setup.8         |  12 +++
- 59 files changed, 1318 insertions(+), 147 deletions(-)
- delete mode 100644 docs/man/grub-bios-setup.h2m
- delete mode 100644 docs/man/grub-editenv.h2m
- delete mode 100644 docs/man/grub-emu.h2m
- delete mode 100644 docs/man/grub-file.h2m
- delete mode 100644 docs/man/grub-fstest.h2m
- delete mode 100644 docs/man/grub-glue-efi.h2m
- delete mode 100644 docs/man/grub-install.h2m
- delete mode 100644 docs/man/grub-kbdcomp.h2m
- delete mode 100644 docs/man/grub-macbless.h2m
- delete mode 100644 docs/man/grub-macho2img.h2m
- delete mode 100644 docs/man/grub-menulst2cfg.h2m
- delete mode 100644 docs/man/grub-mkconfig.h2m
- delete mode 100644 docs/man/grub-mkfont.h2m
- delete mode 100644 docs/man/grub-mkimage.h2m
- delete mode 100644 docs/man/grub-mklayout.h2m
- delete mode 100644 docs/man/grub-mknetdir.h2m
- delete mode 100644 docs/man/grub-mkpasswd-pbkdf2.h2m
- delete mode 100644 docs/man/grub-mkrelpath.h2m
- delete mode 100644 docs/man/grub-mkrescue.h2m
- delete mode 100644 docs/man/grub-mkstandalone.h2m
- delete mode 100644 docs/man/grub-mount.h2m
- delete mode 100644 docs/man/grub-ofpathname.h2m
- delete mode 100644 docs/man/grub-pe2elf.h2m
- delete mode 100644 docs/man/grub-probe.h2m
- delete mode 100644 docs/man/grub-reboot.h2m
- delete mode 100644 docs/man/grub-render-label.h2m
- delete mode 100644 docs/man/grub-script-check.h2m
- delete mode 100644 docs/man/grub-set-default.h2m
- delete mode 100644 docs/man/grub-sparc64-setup.h2m
- delete mode 100644 docs/man/grub-syslinux2cfg.h2m
- create mode 100644 util/grub-bios-setup.8
- create mode 100644 util/grub-editenv.1
- create mode 100644 util/grub-file.1
- create mode 100644 util/grub-fstest.1
- create mode 100644 util/grub-glue-efi.1
- create mode 100644 util/grub-install.8
- create mode 100644 util/grub-kbdcomp.1
- create mode 100644 util/grub-macbless.1
- create mode 100644 util/grub-menulst2cfg.1
- create mode 100644 util/grub-mkconfig.8
- create mode 100644 util/grub-mkfont.1
- create mode 100644 util/grub-mkimage.1
- create mode 100644 util/grub-mklayout.1
- create mode 100644 util/grub-mknetdir.1
- create mode 100644 util/grub-mkpasswd-pbkdf2.1
- create mode 100644 util/grub-mkrelpath.1
- create mode 100644 util/grub-mkrescue.1
- create mode 100644 util/grub-mkstandalone.1
- create mode 100644 util/grub-ofpathname.8
- create mode 100644 util/grub-probe.8
- create mode 100644 util/grub-reboot.8
- create mode 100644 util/grub-render-label.1
- create mode 100644 util/grub-script-check.1
- create mode 100644 util/grub-set-default.8
- create mode 100644 util/grub-sparc64-setup.8
-
-diff --git a/configure.ac b/configure.ac
-index 8331f95b645..bec8535af70 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -77,6 +77,29 @@ grub_TRANSFORM([grub-set-default])
- grub_TRANSFORM([grub-sparc64-setup])
- grub_TRANSFORM([grub-render-label])
- grub_TRANSFORM([grub-file])
-+grub_TRANSFORM([grub-bios-setup.3])
-+grub_TRANSFORM([grub-editenv.1])
-+grub_TRANSFORM([grub-fstest.3])
-+grub_TRANSFORM([grub-glue-efi.3])
-+grub_TRANSFORM([grub-install.1])
-+grub_TRANSFORM([grub-kbdcomp.3])
-+grub_TRANSFORM([grub-menulst2cfg.1])
-+grub_TRANSFORM([grub-mkconfig.1])
-+grub_TRANSFORM([grub-mkfont.3])
-+grub_TRANSFORM([grub-mkimage.1])
-+grub_TRANSFORM([grub-mklayout.3])
-+grub_TRANSFORM([grub-mknetdir.3])
-+grub_TRANSFORM([grub-mkpasswd-pbkdf2.3])
-+grub_TRANSFORM([grub-mkrelpath.3])
-+grub_TRANSFORM([grub-mkrescue.1])
-+grub_TRANSFORM([grub-mkstandalone.3])
-+grub_TRANSFORM([grub-ofpathname.3])
-+grub_TRANSFORM([grub-probe.3])
-+grub_TRANSFORM([grub-reboot.3])
-+grub_TRANSFORM([grub-render-label.3])
-+grub_TRANSFORM([grub-script-check.3])
-+grub_TRANSFORM([grub-set-default.1])
-+grub_TRANSFORM([grub-sparc64-setup.3])
- 
- # Optimization flag.  Allow user to override.
- if test "x$TARGET_CFLAGS" = x; then
-diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist
-index 8f1485d52a5..b909f2c073a 100644
---- a/conf/Makefile.extra-dist
-+++ b/conf/Makefile.extra-dist
-@@ -11,7 +11,6 @@ EXTRA_DIST += unicode
- EXTRA_DIST += util/import_gcry.py
- EXTRA_DIST += util/import_unicode.py
- 
--EXTRA_DIST += docs/man
- EXTRA_DIST += docs/autoiso.cfg
- EXTRA_DIST += docs/grub.cfg
- EXTRA_DIST += docs/osdetect.cfg
-diff --git a/docs/Makefile.am b/docs/Makefile.am
-index 93eb3962765..ab28f199694 100644
---- a/docs/Makefile.am
-+++ b/docs/Makefile.am
-@@ -5,5 +5,3 @@ info_TEXINFOS = grub.texi grub-dev.texi
- grub_TEXINFOS = fdl.texi
- 
- EXTRA_DIST = font_char_metrics.png font_char_metrics.txt
--
--
-diff --git a/docs/man/grub-bios-setup.h2m b/docs/man/grub-bios-setup.h2m
-deleted file mode 100644
-index ac6ede36296..00000000000
---- a/docs/man/grub-bios-setup.h2m
-+++ /dev/null
-@@ -1,6 +0,0 @@
--[NAME]
--grub-bios-setup \- set up a device to boot using GRUB
--[SEE ALSO]
--.BR grub-install (8),
--.BR grub-mkimage (1),
--.BR grub-mkrescue (1)
-diff --git a/docs/man/grub-editenv.h2m b/docs/man/grub-editenv.h2m
-deleted file mode 100644
-index 3859d3d4c4f..00000000000
---- a/docs/man/grub-editenv.h2m
-+++ /dev/null
-@@ -1,5 +0,0 @@
--[NAME]
--grub-editenv \- edit GRUB environment block
--[SEE ALSO]
--.BR grub-reboot (8),
--.BR grub-set-default (8)
-diff --git a/docs/man/grub-emu.h2m b/docs/man/grub-emu.h2m
-deleted file mode 100644
-index ef1c000656a..00000000000
---- a/docs/man/grub-emu.h2m
-+++ /dev/null
-@@ -1,6 +0,0 @@
--[NAME]
--grub-emu \- GRUB emulator
--[SEE ALSO]
--If you are trying to install GRUB, then you should use
--.BR grub-install (8)
--rather than this program.
-diff --git a/docs/man/grub-file.h2m b/docs/man/grub-file.h2m
-deleted file mode 100644
-index e09bb4d3101..00000000000
---- a/docs/man/grub-file.h2m
-+++ /dev/null
-@@ -1,2 +0,0 @@
--[NAME]
--grub-file \- check file type
-diff --git a/docs/man/grub-fstest.h2m b/docs/man/grub-fstest.h2m
-deleted file mode 100644
-index 9676b159afd..00000000000
---- a/docs/man/grub-fstest.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-fstest \- debug tool for GRUB filesystem drivers
--[SEE ALSO]
--.BR grub-probe (8)
-diff --git a/docs/man/grub-glue-efi.h2m b/docs/man/grub-glue-efi.h2m
-deleted file mode 100644
-index c1c6ded49ff..00000000000
---- a/docs/man/grub-glue-efi.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-glue-efi \- generate a fat binary for EFI
--[DESCRIPTION]
--grub-glue-efi processes ia32 and amd64 EFI images and glues them according to Apple format.
-diff --git a/docs/man/grub-install.h2m b/docs/man/grub-install.h2m
-deleted file mode 100644
-index 8cbbc87a0f2..00000000000
---- a/docs/man/grub-install.h2m
-+++ /dev/null
-@@ -1,6 +0,0 @@
--[NAME]
--grub-install \- install GRUB to a device
--[SEE ALSO]
--.BR grub-mkconfig (8),
--.BR grub-mkimage (1),
--.BR grub-mkrescue (1)
-diff --git a/docs/man/grub-kbdcomp.h2m b/docs/man/grub-kbdcomp.h2m
-deleted file mode 100644
-index d81f9157e01..00000000000
---- a/docs/man/grub-kbdcomp.h2m
-+++ /dev/null
-@@ -1,10 +0,0 @@
--[NAME]
--grub-kbdcomp \- generate a GRUB keyboard layout file
--[DESCRIPTION]
--grub-kbdcomp processes a X keyboard layout description in
--.BR keymaps (5)
--format into a format that can be used by GRUB's
--.B keymap
--command.
--[SEE ALSO]
--.BR grub-mklayout (8)
-diff --git a/docs/man/grub-macbless.h2m b/docs/man/grub-macbless.h2m
-deleted file mode 100644
-index 0197c0087d7..00000000000
---- a/docs/man/grub-macbless.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-macbless \- bless a mac file/directory
--[SEE ALSO]
--.BR grub-install (1)
-diff --git a/docs/man/grub-macho2img.h2m b/docs/man/grub-macho2img.h2m
-deleted file mode 100644
-index d79aaeed8f9..00000000000
---- a/docs/man/grub-macho2img.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-macho2img \- convert Mach-O to raw image
--[SEE ALSO]
--.BR grub-mkimage (1)
-diff --git a/docs/man/grub-menulst2cfg.h2m b/docs/man/grub-menulst2cfg.h2m
-deleted file mode 100644
-index c2e0055ed7e..00000000000
---- a/docs/man/grub-menulst2cfg.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-menulst2cfg \- transform legacy menu.lst into grub.cfg
--[SEE ALSO]
--.BR grub-mkconfig (8)
-diff --git a/docs/man/grub-mkconfig.h2m b/docs/man/grub-mkconfig.h2m
-deleted file mode 100644
-index 9b42f813010..00000000000
---- a/docs/man/grub-mkconfig.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-mkconfig \- generate a GRUB configuration file
--[SEE ALSO]
--.BR grub-install (8)
-diff --git a/docs/man/grub-mkfont.h2m b/docs/man/grub-mkfont.h2m
-deleted file mode 100644
-index d46fe600eca..00000000000
---- a/docs/man/grub-mkfont.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-mkfont \- make GRUB font files
--[SEE ALSO]
--.BR grub-mkconfig (8)
-diff --git a/docs/man/grub-mkimage.h2m b/docs/man/grub-mkimage.h2m
-deleted file mode 100644
-index f0fbc2bb197..00000000000
---- a/docs/man/grub-mkimage.h2m
-+++ /dev/null
-@@ -1,6 +0,0 @@
--[NAME]
--grub-mkimage \- make a bootable image of GRUB
--[SEE ALSO]
--.BR grub-install (8),
--.BR grub-mkrescue (1),
--.BR grub-mknetdir (8)
-diff --git a/docs/man/grub-mklayout.h2m b/docs/man/grub-mklayout.h2m
-deleted file mode 100644
-index 1e43409c0ab..00000000000
---- a/docs/man/grub-mklayout.h2m
-+++ /dev/null
-@@ -1,10 +0,0 @@
--[NAME]
--grub-mklayout \- generate a GRUB keyboard layout file
--[DESCRIPTION]
--grub-mklayout processes a keyboard layout description in
--.BR keymaps (5)
--format into a format that can be used by GRUB's
--.B keymap
--command.
--[SEE ALSO]
--.BR grub-mkconfig (8)
-diff --git a/docs/man/grub-mknetdir.h2m b/docs/man/grub-mknetdir.h2m
-deleted file mode 100644
-index a2ef13ec111..00000000000
---- a/docs/man/grub-mknetdir.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-mknetdir \- prepare a GRUB netboot directory.
--[SEE ALSO]
--.BR grub-mkimage (1)
-diff --git a/docs/man/grub-mkpasswd-pbkdf2.h2m b/docs/man/grub-mkpasswd-pbkdf2.h2m
-deleted file mode 100644
-index 4d202f3da7e..00000000000
---- a/docs/man/grub-mkpasswd-pbkdf2.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-mkpasswd-pbkdf2 \- generate hashed password for GRUB
--[SEE ALSO]
--.BR grub-mkconfig (8)
-diff --git a/docs/man/grub-mkrelpath.h2m b/docs/man/grub-mkrelpath.h2m
-deleted file mode 100644
-index d01f3961e3f..00000000000
---- a/docs/man/grub-mkrelpath.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-mkrelpath \- make a system path relative to its root
--[SEE ALSO]
--.BR grub-probe (8)
-diff --git a/docs/man/grub-mkrescue.h2m b/docs/man/grub-mkrescue.h2m
-deleted file mode 100644
-index a427f02e3c6..00000000000
---- a/docs/man/grub-mkrescue.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-mkrescue \- make a GRUB rescue image
--[SEE ALSO]
--.BR grub-mkimage (1)
-diff --git a/docs/man/grub-mkstandalone.h2m b/docs/man/grub-mkstandalone.h2m
-deleted file mode 100644
-index c77313978ad..00000000000
---- a/docs/man/grub-mkstandalone.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-mkstandalone \- make a memdisk-based GRUB image
--[SEE ALSO]
--.BR grub-mkimage (1)
-diff --git a/docs/man/grub-mount.h2m b/docs/man/grub-mount.h2m
-deleted file mode 100644
-index 8d168982d72..00000000000
---- a/docs/man/grub-mount.h2m
-+++ /dev/null
-@@ -1,2 +0,0 @@
--[NAME]
--grub-mount \- export GRUB filesystem with FUSE
-diff --git a/docs/man/grub-ofpathname.h2m b/docs/man/grub-ofpathname.h2m
-deleted file mode 100644
-index 74b43eea039..00000000000
---- a/docs/man/grub-ofpathname.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-ofpathname \- find OpenBOOT path for a device
--[SEE ALSO]
--.BR grub-probe (8)
-diff --git a/docs/man/grub-pe2elf.h2m b/docs/man/grub-pe2elf.h2m
-deleted file mode 100644
-index 7ca29bd703c..00000000000
---- a/docs/man/grub-pe2elf.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-pe2elf \- convert PE image to ELF
--[SEE ALSO]
--.BR grub-mkimage (1)
-diff --git a/docs/man/grub-probe.h2m b/docs/man/grub-probe.h2m
-deleted file mode 100644
-index 6e1ffdcf937..00000000000
---- a/docs/man/grub-probe.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-probe \- probe device information for GRUB
--[SEE ALSO]
--.BR grub-fstest (1)
-diff --git a/docs/man/grub-reboot.h2m b/docs/man/grub-reboot.h2m
-deleted file mode 100644
-index e4acace65ce..00000000000
---- a/docs/man/grub-reboot.h2m
-+++ /dev/null
-@@ -1,5 +0,0 @@
--[NAME]
--grub-reboot \- set the default boot entry for GRUB, for the next boot only
--[SEE ALSO]
--.BR grub-set-default (8),
--.BR grub-editenv (1)
-diff --git a/docs/man/grub-render-label.h2m b/docs/man/grub-render-label.h2m
-deleted file mode 100644
-index 50ae5247c05..00000000000
---- a/docs/man/grub-render-label.h2m
-+++ /dev/null
-@@ -1,3 +0,0 @@
--[NAME]
--grub-render-label \- generate a .disk_label for Apple Macs.
--
-diff --git a/docs/man/grub-script-check.h2m b/docs/man/grub-script-check.h2m
-deleted file mode 100644
-index 3653682671a..00000000000
---- a/docs/man/grub-script-check.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-script-check \- check grub.cfg for syntax errors
--[SEE ALSO]
--.BR grub-mkconfig (8)
-diff --git a/docs/man/grub-set-default.h2m b/docs/man/grub-set-default.h2m
-deleted file mode 100644
-index 7945001c154..00000000000
---- a/docs/man/grub-set-default.h2m
-+++ /dev/null
-@@ -1,5 +0,0 @@
--[NAME]
--grub-set-default \- set the saved default boot entry for GRUB
--[SEE ALSO]
--.BR grub-reboot (8),
--.BR grub-editenv (1)
-diff --git a/docs/man/grub-sparc64-setup.h2m b/docs/man/grub-sparc64-setup.h2m
-deleted file mode 100644
-index 18f803a50db..00000000000
---- a/docs/man/grub-sparc64-setup.h2m
-+++ /dev/null
-@@ -1,6 +0,0 @@
--[NAME]
--grub-sparc64-setup \- set up a device to boot using GRUB
--[SEE ALSO]
--.BR grub-install (8),
--.BR grub-mkimage (1),
--.BR grub-mkrescue (1)
-diff --git a/docs/man/grub-syslinux2cfg.h2m b/docs/man/grub-syslinux2cfg.h2m
-deleted file mode 100644
-index ad25c8ab753..00000000000
---- a/docs/man/grub-syslinux2cfg.h2m
-+++ /dev/null
-@@ -1,4 +0,0 @@
--[NAME]
--grub-syslinux2cfg \- transform syslinux config into grub.cfg
--[SEE ALSO]
--.BR grub-menulst2cfg (8)
-diff --git a/gentpl.py b/gentpl.py
-index c86550d4f9e..2cba0bbbd6f 100644
---- a/gentpl.py
-+++ b/gentpl.py
-@@ -805,10 +805,7 @@ def manpage(defn, adddeps):
- 
-     output("if COND_MAN_PAGES\n")
-     gvar_add("man_MANS", name + "." + mansection)
--    rule(name + "." + mansection, name + " " + adddeps, """
--chmod a+x """ + name + """
--PATH=$(builddir):$$PATH pkgdatadir=$(builddir) $(HELP2MAN) --section=""" + mansection + """ -i $(top_srcdir)/docs/man/""" + name + """.h2m -o $@ """ + name + """
--""")
-+    rule(name + "." + mansection, name + " " + adddeps, "cat $(top_srcdir)/util/" + name + "." + mansection + " | $(top_builddir)/config.status --file=$@:-")
-     gvar_add("CLEANFILES", name + "." + mansection)
-     output("endif\n")
- 
-diff --git a/util/grub-bios-setup.8 b/util/grub-bios-setup.8
-new file mode 100644
-index 00000000000..56f582b3d75
---- /dev/null
-+++ b/util/grub-bios-setup.8
-@@ -0,0 +1,54 @@
-+.TH GRUB-BIOS-SETUP 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-bios-setup\fR \(em Set up images to boot from a device.
-+
-+.SH SYNOPSIS
-+\fBgrub-bios-setup\fR [-a | --allow-floppy] [-b | --boot-image=\fIFILE\fR]
-+.RS 17
-+[-c | --core-image=\fIFILE\fR] [-d | --directory=\fIDIR\fR]
-+.RE
-+.RS 17
-+[-f | --force] [-m | --device-map=\fIFILE\fR]
-+.RE
-+.RS 17
-+[-s | --skip-fs-probe] [-v | --verbose] \fIDEVICE\fR
-+
-+.SH DESCRIPTION
-+You should not normally run this program directly.  Use grub-install instead.
-+
-+.SH OPTIONS
-+.TP
-+\fB--allow-floppy\fR
-+Make the device also bootable as a floppy.  This option is the default for
-+/dev/fdX devices.  Some BIOSes will not boot images created with this option.
-+
-+.TP
-+\fB--boot-image\fR=\fIFILE\fR
-+Use FILE as the boot image.  The default value is \fBboot.img\fR.
-+
-+.TP
-+\fB--core-image\fR=\fIFILE\fR
-+Use FILE as ther core image.  The default value is \fBcore.img\fR.
-+
-+.TP
-+\fB--directory\fR=\fIDIR\fR
-+Use GRUB files in the directory DIR.  The default value is \fB/boot/grub\fR.
-+
-+.TP
-+\fB--force\fR
-+Install even if problems are detected.
-+
-+.TP
-+\fB--device-map\fR=\fIFILE\fR
-+Use FILE as the device map.  The default value is /boot/grub/device.map .
-+
-+.TP
-+\fB--skip-fs-probe\fR
-+Do not probe DEVICE for filesystems.
-+
-+.TP
-+\fB--verbose\fR
-+Print verbose messages.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-editenv.1 b/util/grub-editenv.1
-new file mode 100644
-index 00000000000..d28ba03ba42
---- /dev/null
-+++ b/util/grub-editenv.1
-@@ -0,0 +1,46 @@
-+.TH GRUB-EDITENV 1 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-editenv\fR \(em Manage the GRUB environment block.
-+
-+.SH SYNOPSIS
-+\fBgrub-editenv\fR [-v | --verbose] [\fIFILE\fR]
-+.RS 14
-+<create | list | set \fINAME\fR=\fIVALUE\fR | unset \fINAME\fR>
-+
-+.SH DESCRIPTION
-+\fBgrub-editenv\fR is a command line tool to manage GRUB's stored environment.
-+
-+.SH OPTIONS
-+.TP
-+\fB--verbose\fR
-+Print verbose messages.
-+
-+.TP
-+\fBFILE\fR
-+.RS 7
-+File name to use for grub environment.  Default is /boot/grub/grubenv .
-+.RE
-+
-+.SH COMMANDS
-+.TP
-+\fBcreate\fR
-+.RS 7
-+Create a blank environment block file.
-+.RE
-+
-+.TP
-+\fBlist\fR
-+.RS 7
-+List the current variables.
-+.RE
-+
-+.TP
-+\fBset\fR [\fINAME\fR=\fIVALUE\fR ...]
-+Set variables.
-+
-+.TP
-+\fBunset [\fINAME\fR ...]
-+Delete variables.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-file.1 b/util/grub-file.1
-new file mode 100644
-index 00000000000..b29cb327889
---- /dev/null
-+++ b/util/grub-file.1
-@@ -0,0 +1,165 @@
-+.TH GRUB-FILE 1 "Web Feb 26 2014"
-+.SH NAME
-+\fBgrub-file\fR \(em Check if FILE is of specified type.
-+
-+.SH SYNOPSIS
-+\fBgrub-file\fR (--is-i386-xen-pae-domu | --is-x86_64-xen-domu |
-+.RS 11
-+--is-x86-xen-dom0 | --is-x86-multiboot |
-+.RE
-+.RS 11
-+--is-x86-multiboot2 | --is-arm-linux | --is-arm64-linux |
-+.RE
-+.RS 11
-+--is-ia64-linux | --is-mips-linux | --is-mipsel-linux |
-+.RE
-+.RS 11
-+--is-sparc64-linux | --is-powerpc-linux | --is-x86-linux |
-+.RE
-+.RS 11
-+--is-x86-linux32 | --is-x86-kfreebsd | --is-i386-kfreebsd |
-+.RE
-+.RS 11
-+--is-x86_64-kfreebsd | --is-x86-knetbsd |
-+.RE
-+.RS 11
-+--is-i386-knetbsd | --is-x86_64-knetbsd | --is-i386-efi |
-+.RE
-+.RS 11
-+--is-x86_64-efi | --is-ia64-efi | --is-arm64-efi |
-+.RE
-+.RS 11
-+--is-arm-efi | --is-hibernated-hiberfil | --is-x86_64-xnu |
-+.RE
-+.RS 11
-+--is-i386-xnu | --is-xnu-hibr | --is-x86-bios-bootsector)
-+.RE
-+.RS 11
-+\fIFILE\fR
-+
-+.SH DESCRIPTION
-+\fBgrub-file\fR is used to check if \fIFILE\fR is of a specified type.
-+
-+.SH OPTIONS
-+.TP
-+--is-i386-xen-pae-domu
-+Check if FILE can be booted as i386 PAE Xen unprivileged guest kernel
-+
-+.TP
-+--is-x86_64-xen-domu
-+Check if FILE can be booted as x86_64 Xen unprivileged guest kernel
-+
-+.TP
-+--is-x86-xen-dom0
-+Check if FILE can be used as Xen x86 privileged guest kernel
-+
-+.TP
-+--is-x86-multiboot
-+Check if FILE can be used as x86 multiboot kernel
-+
-+.TP
-+--is-x86-multiboot2
-+Check if FILE can be used as x86 multiboot2 kernel
-+
-+.TP
-+--is-arm-linux
-+Check if FILE is ARM Linux
-+
-+.TP
-+--is-arm64-linux
-+Check if FILE is ARM64 Linux
-+
-+.TP
-+--is-ia64-linux
-+Check if FILE is IA64 Linux
-+
-+.TP
-+--is-mips-linux
-+Check if FILE is MIPS Linux
-+
-+.TP
-+--is-mipsel-linux
-+Check if FILE is MIPSEL Linux
-+
-+.TP
-+--is-sparc64-linux
-+Check if FILE is SPARC64 Linux
-+
-+.TP
-+--is-powerpc-linux
-+Check if FILE is POWERPC Linux
-+
-+.TP
-+--is-x86-linux
-+Check if FILE is x86 Linux
-+
-+.TP
-+--is-x86-linux32
-+Check if FILE is x86 Linux supporting 32-bit protocol
-+
-+.TP
-+--is-x86-kfreebsd
-+Check if FILE is x86 kFreeBSD
-+
-+.TP
-+--is-i386-kfreebsd
-+Check if FILE is i386 kFreeBSD
-+
-+.TP
-+--is-x86_64-kfreebsd
-+Check if FILE is x86_64 kFreeBSD
-+
-+.TP
-+--is-x86-knetbsd
-+Check if FILE is x86 kNetBSD
-+
-+.TP
-+--is-i386-knetbsd
-+Check if FILE is i386 kNetBSD
-+
-+.TP
-+--is-x86_64-knetbsd
-+Check if FILE is x86_64 kNetBSD
-+
-+.TP
-+--is-i386-efi
-+Check if FILE is i386 EFI file
-+
-+.TP
-+--is-x86_64-efi
-+Check if FILE is x86_64 EFI file
-+
-+.TP
-+--is-ia64-efi
-+Check if FILE is IA64 EFI file
-+
-+.TP
-+--is-arm64-efi
-+Check if FILE is ARM64 EFI file
-+
-+.TP
-+--is-arm-efi
-+Check if FILE is ARM EFI file
-+
-+.TP
-+--is-hibernated-hiberfil
-+Check if FILE is hiberfil.sys in hibernated state
-+
-+.TP
-+--is-x86_64-xnu
-+Check if FILE is x86_64 XNU (Mac OS X kernel)
-+
-+.TP
-+--is-i386-xnu
-+Check if FILE is i386 XNU (Mac OS X kernel)
-+
-+.TP
-+--is-xnu-hibr
-+Check if FILE is XNU (Mac OS X kernel) hibernated image
-+
-+.TP
-+--is-x86-bios-bootsector
-+Check if FILE is BIOS bootsector
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-fstest.1 b/util/grub-fstest.1
-new file mode 100644
-index 00000000000..792fa78634c
---- /dev/null
-+++ b/util/grub-fstest.1
-@@ -0,0 +1,99 @@
-+.TH GRUB-FSTEST 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-fstest\fR — Debug tool for GRUB's filesystem driver.
-+
-+.SH SYNOPSIS
-+\fBgrub-fstest\fR [-c | --diskcount=\fINUM\fR] [-C | --crypto]
-+.RS 13
-+[-d | --debug=\fISTRING\fR] [-K | --zfs-key=\fIFILE\fR|\fIprompt\fR]
-+.RE
-+.RS 13
-+[-n | --length=\fINUM\fR] [-r | --root=\fIDEVICE_NAME\fR]
-+.RE
-+.RS 13
-+[-s | --skip=\fINUM\fR] [-u | --uncompress] [-v | --verbose]
-+.RE
-+.RS 13
-+\fIIMAGE_PATH\fR <blocklist \fIFILE\fR | cat \fIFILE\fR |
-+.RE
-+.RS 13
-+cmp \fIFILE\fR \fILOCAL\fR | cp \fIFILE\fR \fILOCAL\fR | crc \fIFILE\fR |
-+.RE
-+.RS 13
-+hex \fIFILE\fR | ls \fIPATH\fR | xnu_uuid \fIDEVICE\fR>
-+
-+.SH DESCRIPTION
-+\fBgrub-fstest\fR is a tool for testing GRUB's filesystem drivers.  You should not normally need to run this program.
-+
-+.SH OPTIONS
-+.TP
-+\fB--diskcount\fR=\fINUM\fR
-+Specify the number of input files.
-+
-+.TP
-+\fB--crypto\fR
-+Mount cryptographic devices.
-+
-+.TP
-+\fB--debug\fR=\fISTRING\fR
-+Set debug environment variable.
-+
-+.TP
-+\fB--zfs-key\fR=\fIFILE\fR|\fIprompt\fR
-+Load ZFS cryptographic key.
-+
-+.TP
-+\fB--length\fR=\fINUM\fR
-+Handle NUM bytes in output file.
-+
-+.TP
-+\fB--root\fR=\fIDEVICE_NAME\fR
-+Set root device.
-+
-+.TP
-+\fB--skip\fR=\fINUM\fR
-+Skip NUM bytes from output file.
-+
-+.TP
-+\fB--uncompress\fR
-+Uncompress data.
-+
-+.TP
-+\fB--verbose\fR
-+Print verbose messages.
-+
-+.SH COMMANDS
-+.TP
-+\fBblocklist\fR \fIFILE\fR
-+Display block list of \fIFILE\fR.
-+
-+.TP
-+\fBcat\fR \fIFILE\fR
-+Display \fIFILE\fR on standard output.
-+
-+.TP
-+\fBcmp\fR \fIFILE\fR \fILOCAL\fR
-+Compare \fIFILE\fR with local file \fILOCAL\fR.
-+
-+.TP
-+\fBcp\fR \fIFILE\fR \fILOCAL\fR
-+Copy \fIFILE\fR to local file \fILOCAL\fR.
-+
-+.TP
-+\fBcrc\fR \fIFILE\fR
-+Display the CRC-32 checksum of \fIFILE\fR.
-+
-+.TP
-+\fBhex\fR \fIFILE\fR
-+Display contents of \fIFILE\fR in hexidecimal.
-+
-+.TP
-+\fBls\fR \fIPATH\fR
-+List files at \fIPATH\fR.
-+
-+.TP
-+\fBxnu_uuid\fR \fIDEVICE\fR
-+Display the XNU UUID of \fIDEVICE\fR.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-glue-efi.1 b/util/grub-glue-efi.1
-new file mode 100644
-index 00000000000..72bd555d577
---- /dev/null
-+++ b/util/grub-glue-efi.1
-@@ -0,0 +1,31 @@
-+.TH GRUB-GLUE-EFI 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-glue-efi\fR \(em Create an Apple fat EFI binary.
-+
-+.SH SYNOPSIS
-+\fBgrub-glue-efi\fR <-3 | --input32=\fIFILE\fR> <-6 | --input64=\fIFILE\fR>
-+.RS 15
-+<-o | --output=\fIFILE\fR> [-v | --verbose]
-+
-+.SH DESCRIPTION
-+\fBgrub-glue-efi\fR creates an Apple fat EFI binary from two EFI binaries.
-+
-+.SH OPTIONS
-+.TP
-+\fB--input32\fR=\fIFILE\fR
-+Read 32-bit binary from \fIFILE\fR.
-+
-+.TP
-+\fB--input64\fR=\fIFILE\fR
-+Read 64-bit binary from \fIFILE\fR.
-+
-+.TP
-+\fB--output\fR=\fIFILE\fR
-+Write resulting fat binary to \fIFILE\fR.
-+
-+.TP
-+\fB--verbose\fR
-+Print verbose messages.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-install.8 b/util/grub-install.8
-new file mode 100644
-index 00000000000..1db89e94b3b
---- /dev/null
-+++ b/util/grub-install.8
-@@ -0,0 +1,128 @@
-+.TH GRUB-INSTALL 1 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-install\fR \(em Install GRUB on a device.
-+
-+.SH SYNOPSIS
-+\fBgrub-install\fR [--modules=\fIMODULES\fR] [--install-modules=\fIMODULES\fR]
-+.RS 14
-+[--themes=\fITHEMES\fR] [--fonts=\fIFONTS\fR] [--locales=\fILOCALES\fR]
-+.RE
-+.RS 14
-+[--compress[=\fIno\fR,\fIxz\fR,\fIgz\fR,\fIlzo\fR]] [-d | --directory=\fIDIR\fR]
-+.RE
-+.RS 14
-+[--grub-mkimage=\fIFILE\fR] [--boot-directory=\fIDIR\fR]
-+.RE
-+.RS 14
-+[--target=\fITARGET\fR] [--grub-setup=\fIFILE\fR]
-+.RE
-+.RS 14
-+[--grub-mkrelpath=\fIFILE\fR] [--grub-probe=\fIFILE\fR]
-+.RE
-+.RS 14
-+[--allow-floppy] [--recheck] [--force] [--force-file-id]
-+.RE
-+.RS 14
-+[--disk-module=\fIMODULE\fR] [--no-nvram] [--removable]
-+.RE
-+.RS 14
-+[--bootloader-id=\fIID\fR] [--efi-directory=\fIDIR\fR] \fIINSTALL_DEVICE\fR
-+
-+.SH DESCRIPTION
-+\fBgrub-install\fR installs GRUB onto a device.  This includes copying GRUB images into the target directory (generally \fI/boot/grub\fR), and on some platforms may also include installing GRUB onto a boot sector.
-+
-+.SH OPTIONS
-+.TP
-+\fB--modules\fR=\fIMODULES\fR\!
-+Pre-load modules specified by \fIMODULES\fR.
-+
-+.TP
-+\fB--install-modules\fR=\fIMODULES\fR
-+Install only \fIMODULES\fR and their dependencies.  The default is to install all available modules.
-+
-+.TP
-+\fB--themes\fR=\fITHEMES\fR
-+Install \fITHEMES\fR.  The default is to install the \fIstarfield\fR theme, if available.
-+
-+.TP
-+\fB--fonts\fR=\fIFONTS\fR
-+Install \fIFONTS\fR.  The default is to install the \fIunicode\fR font.
-+
-+.TP
-+\fB--locales\fR=\fILOCALES\fR
-+Install only locales listed in \fILOCALES\fR.  The default is to install all available locales.
-+
-+.TP
-+\fB--compress\fR=\fIno\fR,\fIxz\fR,\fIgz\fR,\fIlzo\fR
-+Compress GRUB files using the specified compression algorithm.
-+
-+.TP
-+\fB--directory\fR=\fIDIR\fR
-+Use images and modules in \fIDIR\fR.
-+
-+.TP
-+\fB--grub-mkimage\fR=\fIFILE\fR
-+Use \fIFILE\fR as \fBgrub-mkimage\fR.  The default is \fI/usr/bin/grub-mkimage\fR.
-+
-+.TP
-+\fB--boot-directory\fR=\fIDIR\fR
-+Use \fIDIR\fR as the boot directory.  The default is \fI/boot\fR.  GRUB will put its files in a subdirectory of this directory named \fIgrub\fR.
-+
-+.TP
-+\fB--target\fR=\fITARGET\fR
-+Install GRUB for \fITARGET\fR platform.  The default is the platform \fBgrub-install\fR is running on.
-+
-+.TP
-+\fB--grub-setup\fR=\fIFILE\fR
-+Use \fIFILE\fR as \fBgrub-setup\fR.  The default is \fI/usr/bin/grub-setup\fR.
-+
-+.TP
-+\fB--grub-mkrelpath\fR=\fIFILE\fR
-+Use \fIFILE\fR as \fBgrub-mkrelpath\fR.  The default is \fI/usr/bin/grub-mkrelpath\fR.
-+
-+.TP
-+\fB--grub-probe\fR=\fIFILE\fR
-+Use \fIFILE\fR as \fBgrub-probe\fR.  The default is \fI/usr/bin/grub-mkrelpath\fR.
-+
-+.TP
-+\fB--allow-floppy
-+Make the device also bootable as a floppy.  This option is the default for /dev/fdX devices. Some BIOSes will not boot images created with this option.
-+
-+.TP
-+\fB--recheck
-+Delete any existing device map and create a new one if necessary.
-+
-+.TP
-+\fB--force
-+Install even if problems are detected.
-+
-+.TP
-+\fB--force-file-id
-+Use identifier file even if UUID is available.
-+
-+.TP
-+\fB--disk-module\fR=\fIMODULE\fR
-+Use \fIMODULE\fR for disk access.  This allows you to manually specify either \fIbiosdisk\fR or \fInative\fR disk access.  This option is only available on the BIOS target platform.
-+
-+.TP
-+\fB--no-nvram
-+Do not update the \fIboot-device\fR NVRAM variable.  This option is only available on IEEE1275 target platforms.
-+
-+.TP
-+\fB--removable
-+Treat the target device as if it is removeable.  This option is only available on the EFI target platform.
-+
-+.TP
-+\fB--bootloader-id\fR=\fIID\fR
-+Use \fIID\fR as the bootloader ID.  This option is only available on the EFI target platform.
-+
-+.TP
-+\fB--efi-directory\fR=\fIDIR\fR
-+Use \fIDIR\fR as the EFI System Partition root.  This option is only available on the EFI target platform.
-+
-+.TP
-+\fIINSTALL_DEVICE\fR
-+Install GRUB to the block device \fIINSTALL_DEVICE\fR.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-kbdcomp.1 b/util/grub-kbdcomp.1
-new file mode 100644
-index 00000000000..0bb969a5b43
---- /dev/null
-+++ b/util/grub-kbdcomp.1
-@@ -0,0 +1,19 @@
-+.TH GRUB-KBDCOMP 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-kbdcomp\fR \(em Generate a GRUB keyboard layout file.
-+
-+.SH SYNOPSIS
-+\fBgrub-kbdcomp\fR <-o | --output=\fIFILE\fR> \fICKBMAP_ARGUMENTS\fR
-+
-+.SH DESCRIPTION
-+\fBgrub-kbdcomp\fR processes an X keyboard layout description in
-+\fBkeymaps\fR(5) format into a format that can be used by GRUB's \fBkeymap\fR
-+command.
-+
-+.SH OPTIONS
-+.TP
-+\fB--output\fR=\fIFILE\fR
-+Write output to \fIFILE\fR.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-macbless.1 b/util/grub-macbless.1
-new file mode 100644
-index 00000000000..41a96186f70
---- /dev/null
-+++ b/util/grub-macbless.1
-@@ -0,0 +1,22 @@
-+.TH GRUB-MACBLESS 1 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-macbless\fR \(em Mac-style bless on HFS or HFS+
-+
-+.SH SYNOPSIS
-+\fBgrub-macbless\fR [-v | --verbose] [-p | --ppc] \fIFILE\fR | [-x | --x86] \fIFILE\fR
-+
-+.SH OPTIONS
-+.TP
-+--x86
-+Bless for x86 based Macs.
-+
-+.TP
-+--ppc
-+Bless for PPC based Macs.
-+
-+.TP
-+--verbose
-+Print verbose messages.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-menulst2cfg.1 b/util/grub-menulst2cfg.1
-new file mode 100644
-index 00000000000..91e2ef87113
---- /dev/null
-+++ b/util/grub-menulst2cfg.1
-@@ -0,0 +1,12 @@
-+.TH GRUB-MENULST2CFG 1 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-menulst2cfg\fR \(em Convert a configuration file from GRUB 0.xx to GRUB 2.xx format.
-+
-+.SH SYNOPSIS
-+\fBgrub-menulst2cfg\fR [\fIINFILE\fR [\fIOUTFILE\fR]]
-+
-+.SH DESCRIPTION
-+\fBgrub-menulst2cfg\fR converts a configuration file from GRUB 0.xx to the current format.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-mkconfig.8 b/util/grub-mkconfig.8
-new file mode 100644
-index 00000000000..a2d1f577b9b
---- /dev/null
-+++ b/util/grub-mkconfig.8
-@@ -0,0 +1,17 @@
-+.TH GRUB-MKCONFIG 1 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-mkconfig\fR \(em Generate a GRUB configuration file.
-+
-+.SH SYNOPSIS
-+\fBgrub-mkconfig\fR [-o | --output=\fIFILE\fR]
-+
-+.SH DESCRIPTION
-+\fBgrub-mkconfig\fR generates a configuration file for GRUB.
-+
-+.SH OPTIONS
-+.TP
-+\fB--output\fR=\fIFILE\fR
-+Write generated output to \fIFILE\fR.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-mkfont.1 b/util/grub-mkfont.1
-new file mode 100644
-index 00000000000..3494857987d
---- /dev/null
-+++ b/util/grub-mkfont.1
-@@ -0,0 +1,87 @@
-+.TH GRUB-MKFONT 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-mkfont\fR \(em Convert common font file formats into the PF2 format.
-+
-+.SH SYNOPSIS
-+\fBgrub-mkfont\fR [--ascii-bitmaps] [-a | --force-autohint]
-+.RS 13
-+[-b | --bold] [-c | --asce=\fINUM\fR] [-d | --desc=\fINUM\fR]
-+.RE
-+.RS 13
-+[-i | --index=\fINUM\fR] [-n | --name=\fINAME\fR] [--no-bitmap]
-+.RE
-+.RS 13
-+[--no-hinting] <-o | --output=\fIFILE\fR>
-+.RE
-+.RS 13
-+[-r | --range=\fIFROM-TO\fR[\fI,FROM-TO\fR]] [-s | --size=\fISIZE\fR]
-+.RE
-+.RS 13
-+[-v | --verbose] [--width-spec] \fIFONT_FILES\fR
-+
-+.SH DESCRIPTION
-+\fBgrub-mkfont\fR converts font files from common formats into the PF2 format used by GRUB.
-+
-+.SH OPTIONS
-+.TP
-+--ascii-bitmaps
-+Save only bitmaps for ASCII characters.
-+
-+.TP
-+--force-autohint
-+Force generation of automatic hinting.
-+
-+.TP
-+--bold
-+Convert font to bold.
-+
-+.TP
-+--asce=\fINUM\fR
-+Set font ascent to \fINUM\fR.
-+
-+.TP
-+--desc=\fINUM\fR
-+Set font descent to \fINUM\fR.
-+
-+.TP
-+--index=\fINUM\fR
-+Select face index \fINUM\fR.
-+
-+.TP
-+--name=\fINAME\fR
-+Set font family to \fINAME\fR.
-+
-+.TP
-+--no-bitmap
-+Ignore bitmap strikes when loading.
-+
-+.TP
-+--no-hinting
-+Disable hinting.
-+
-+.TP
-+--output=\fIFILE\fR
-+Save ouptut to \fIFILE\fR.  This argument is required.
-+
-+.TP
-+--range=\fIFROM-TO\fR\fI,FROM-TO\fR
-+Set the font ranges to each pair of \fIFROM\fR,\fITO\fR.
-+
-+.TP
-+--size=\fISIZE\fR
-+Set font size to \fISIZE\fR.
-+
-+.TP
-+--verbose
-+Print verbose messages.
-+
-+.TP
-+--width-spec
-+Create a width summary file.
-+
-+.TP
-+\fIFONT_FILES\fR
-+The input files to be converted.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-mkimage.1 b/util/grub-mkimage.1
-new file mode 100644
-index 00000000000..4dea4f54597
---- /dev/null
-+++ b/util/grub-mkimage.1
-@@ -0,0 +1,95 @@
-+.TH GRUB-MKIMAGE 1 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-mkimage\fR \(em Make a bootable GRUB image.
-+
-+.SH SYNOPSIS
-+\fBgrub-mkimage\fR [-c | --config=\fRFILE\fI] [-C | --compression=(\fIxz\fR,\fInone\fR,\fIauto\fR)]
-+.RS 14
-+[-d | --directory=\fRDIR\fR] [-k | --pubkey=\fIFILE\fR]
-+.RE
-+.RS 14
-+[-m | --memdisk=\fIFILE\fR] [-n | --note] [-o | --output=\fIFILE\fR]
-+.RE
-+.RS 14
-+[-O | --format=\fIFORMAT\fR] [-p | --prefix=\fIDIR\fR]
-+.RE
-+.RS 14
-+[-v | --verbose] \fIMODULES\fR
-+
-+.SH DESCRIPTION
-+\fBgrub-mkimage\fI builds a bootable image of GRUB.
-+
-+.SH OPTIONS
-+.TP
-+--config=\fIFILE\fR
-+Embed \fIFILE\fR as the image's initial configuration file.
-+
-+.TP
-+--compression=(\fIxz\fR,\fInone\fR,\fIauto\fR)
-+Use one of \fIxz\fR, \fInone\fR, or \fIauto\fR as the compression method for the core image.
-+
-+.TP
-+--directory=\fIDIR\fR
-+Use images and modules from \fIDIR\fR.  The default value is \fB/usr/lib/grub/<platform>\fR.
-+
-+.TP
-+--pubkey=\fIFILE\fR
-+Embed the public key \fIFILE\fR for signature checking.
-+
-+.TP
-+--memdisk=\fIFILE\fR
-+Embed the memdisk image \fIFILE\fR.  If no \fB-p\fR option is also specified, this implies \fI-p (memdisk)/boot/grub\fR.
-+
-+.TP
-+--note
-+Add a CHRP \fINOTE\fR section.  This option is only valid on IEEE1275 platforms.
-+
-+.TP
-+--output=\fIFILE\fR
-+Write the generated file to \fIFILE\fR.  The default is to write to standard output.
-+
-+.TP
-+--format=\fIFORMAT\fR
-+Generate an image in the specified \fIFORMAT\fR.  Valid values are:
-+.RS
-+.RS 4
-+.P
-+i386-coreboot,
-+i386-multiboot,
-+i386-pc,
-+i386-pc-pxe,
-+i386-efi,
-+i386-ieee1275,
-+i386-qemu,
-+x86_64-efi,
-+mipsel-yeeloong-flash,
-+mipsel-fuloong2f-flash,
-+mipself-loongson-elf,
-+powerpc-ieee1275,
-+sparc64-ieee1275-raw,
-+sparc64-ieee1275-cdcore,
-+sparc64-ieee1275-aout,
-+ia64-efi,
-+mips-arc,
-+mipsel-arc,
-+mipsel-qemu_mips-elf,
-+mips-qemu_mips-flash,
-+mipsel-qemu_mips-flash,
-+mips-qemu_mips-elf
-+.RE
-+.RE
-+
-+.TP
-+--prefix=\fIDIR\fR
-+Set prefix directory.  The default value is \fI/boot/grub\fR.
-+
-+.TP
-+--verbose
-+Print verbose messages.
-+
-+.TP
-+\fIMODULES\fR
-+Include \fIMODULES\fR.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-mklayout.1 b/util/grub-mklayout.1
-new file mode 100644
-index 00000000000..d1bbc2ec515
---- /dev/null
-+++ b/util/grub-mklayout.1
-@@ -0,0 +1,27 @@
-+.TH GRUB-MKLAYOUT 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-mklayout\fR \(em Generate a GRUB keyboard layout file.
-+
-+.SH SYNOPSIS
-+\fBgrub-mklayout\fR [-i | --input=\fIFILE\fR] [-o | --output=\fIFILE\fR]
-+.RS 15
-+[-v | --verbose]
-+
-+.SH DESCRIPTION
-+\fBgrub-mklayout\fR generates a GRUB keyboard layout description which corresponds with the Linux console layout description given as input.
-+
-+.SH OPTIONS
-+.TP
-+--input=\fIFILE\fR
-+Use \fIFILE\fR as the input.  The default value is the standard input device.
-+
-+.TP
-+--output=\fIFILE\fR
-+Use \fIFILE\fR as the output.  The default value is the standard output device.
-+
-+.TP
-+--verbose
-+Print verbose messages.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-mknetdir.1 b/util/grub-mknetdir.1
-new file mode 100644
-index 00000000000..fa7e8d4ef0d
---- /dev/null
-+++ b/util/grub-mknetdir.1
-@@ -0,0 +1,12 @@
-+.TH GRUB-MKNETDIR 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-mknetdir\fR \(em Prepare a GRUB netboot directory.
-+
-+.SH SYNOPSIS
-+\fBgrub-mknetdir\fR
-+
-+.SH DESCRIPTION
-+\fBgrub-mknetdir\fR prepares a directory for GRUB to be netbooted from.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-mkpasswd-pbkdf2.1 b/util/grub-mkpasswd-pbkdf2.1
-new file mode 100644
-index 00000000000..73c437c15d8
---- /dev/null
-+++ b/util/grub-mkpasswd-pbkdf2.1
-@@ -0,0 +1,27 @@
-+.TH GRUB-MKPASSWD-PBKDF2 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-mkpasswd-pbkdf2\fR \(em Generate a PBKDF2 password hash.
-+
-+.SH SYNOPSIS
-+\fBgrub-mkpasswd-pbkdf2\fR [-c | --iteration-count=\fINUM\fR] [-l | --buflen=\fINUM\fR]
-+.RS 22
-+[-s | --salt=\fINUM\fR]
-+
-+.SH DESCRIPTION
-+\fBgrub-mkpasswd-pbkdf2\fR generates a PBKDF2 password string suitable for use in a GRUB configuration file.
-+
-+.SH OPTIONS
-+.TP
-+--iteration-count=\fINUM\fR
-+Number of PBKDF2 iterations.
-+
-+.TP
-+--buflen=\fINUM\fR
-+Length of generated hash.
-+
-+.TP
-+--salt=\fINUM\fR
-+Length of salt to use.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-mkrelpath.1 b/util/grub-mkrelpath.1
-new file mode 100644
-index 00000000000..85f1113621d
---- /dev/null
-+++ b/util/grub-mkrelpath.1
-@@ -0,0 +1,12 @@
-+.TH GRUB-MKRELPATH 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-mkrelpath\fR \(em Generate a relative GRUB path given an OS path.
-+
-+.SH SYNOPSIS
-+\fBgrub-mkrelpath\fR \fIFILE\fR
-+
-+.SH DESCRIPTION
-+\fBgrub-mkrelpath\fR takes an OS filesystem path for \fIFILE\fR and returns a relative path suitable for use in a GRUB configuration file.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-mkrescue.1 b/util/grub-mkrescue.1
-new file mode 100644
-index 00000000000..4ed9fc723fd
---- /dev/null
-+++ b/util/grub-mkrescue.1
-@@ -0,0 +1,123 @@
-+.TH GRUB-MKRESCUE 3 "Wed Feb 26 2014"
-+.SH NAME
-+grub-mkrescue \(em Generate a GRUB rescue image using GNU Xorriso.
-+
-+.SH SYNOPSIS
-+\fBgrub-mkrescue\fR [-o | --output=\fIFILE\fR] [--modules=\fIMODULES\fR]
-+.RS 15
-+[--install-modules=\fIMODULES\fR] [--themes=\fITHEMES\fR]
-+.RE
-+.RS 15
-+[--fonts=\fIFONTS\fR] [--locales=\fILOCALES\fR]
-+.RE
-+.RS 15
-+[--compress[=\fIno\fR,\fIxz\fR,\fIgz\fR,\fIlzo\fR]] [-d | --directory=\fIDIR\fR]
-+.RE
-+.RS 15
-+[--grub-mkimage=\fIFILE\fR] [--rom-directory=\fIDIR\fR]
-+.RE
-+.RS 15
-+[--xorriso=\fIFILE\fR] [--grub-glue-efi=\fIFILE\fR]
-+.RE
-+.RS 15
-+[--grub-render-label=\fIFILE\fR] [--label-font=\fIFILE\fR]
-+.RE
-+.RS 15
-+[--label-color=\fICOLOR\fR] [--label-bgcolor=\fIFILE\fR]
-+.RE
-+.RS 15
-+[--product-name=\fISTRING\fR] [--product-version=\fISTRING\fR]
-+.RE
-+.RS 15
-+[--sparc-boot] [--arcs-boot]
-+
-+.SH DESCRIPTION
-+\fBgrub-mkrescue\fR can be used to generate a rescue image with the GRUB bootloader.
-+
-+.SH OPTIONS
-+.TP
-+\fB--output\fR=\fIFILE\fR
-+Write the generated file to \fIFILE\fR.  The default is to write to standard output.
-+
-+.TP
-+\fB--modules\fR=\fIMODULES\fR
-+Pre-load modules specified by \fIMODULES\fR.
-+
-+.TP
-+\fB--install-modules\fR=\fIMODULES\fR
-+Install only \fIMODULES\fR and their dependencies.  The default is to install all available modules.
-+
-+.TP
-+\fB--themes\fR=\fITHEMES\fR
-+Install \fITHEMES\fR.  The default is to install the \fIstarfield\fR theme, if available.
-+
-+.TP
-+\fB--fonts\fR=\fIFONTS\fR
-+Install \fIFONTS\fR.  The default is to install the \fIunicode\fR font.
-+
-+.TP
-+\fB--locales\fR=\fILOCALES\fR
-+Install only locales listed in \fILOCALES\fR.  The default is to install all available locales.
-+
-+.TP
-+\fB--compress\fR[=\fIno\fR,\fIxz\fR,\fIgz\fR,\fIlzo\fR]
-+Compress GRUB files using the specified compression algorithm.
-+
-+.TP
-+\fB--directory\fR=\fIDIR\fR
-+Use images and modules in \fIDIR\fR.
-+
-+.TP
-+\fB--grub-mkimage\fR=\fIFILE\fR
-+Use \fIFILE\fR as \fBgrub-mkimage\fR(1).  The default is \fI/usr/bin/grub-mkimage\fR.
-+
-+.TP
-+\fB--rom-directory\fR=\fIDIR\fR
-+Save ROM images in \fIDIR\fR.
-+
-+.TP
-+\fB--xorriso\fR=\fIFILE\fR
-+Use \fIFILE\fR as \fBxorriso\fI.
-+
-+.TP
-+\fB--grub-glue-efi\fR=\fIFILE\fR
-+Use \fIFILE\fR as \fBgrub-glue-efi\fR(3).
-+
-+.TP
-+\fB--grub-render-label\fR=\fIFILE\fR
-+Use \fIFILE\fR as \fBgrub-render-label\fR(3).
-+
-+.TP
-+\fB--label-font\fR=\fIFILE\fR
-+Use \fIFILE\fR as the font file for generated labels.
-+
-+.TP
-+\fB--label-color\fR=\fICOLOR\fR
-+Use \fICOLOR\fI as the color for generated labels.
-+
-+.TP
-+\fB--label-bgcolor\fR=\fICOLOR\fR
-+Use \fICOLOR\fR as the background color for generated labels.
-+
-+.TP
-+\fB--product-name\fR=\fISTRING\fR
-+Use \fISTRING\fR as the product name in generated labels.
-+
-+.TP
-+\fB--product-version\fR=\fISTRING\fR
-+Use \fISTRING\fR as the product version in generated labels.
-+
-+.TP
-+\fB--sparc-boot\fR
-+Enable booting the SPARC platform.  This disables HFS+, APM, ARCS, and "boot as disk image" on the \fIi386-pc\fR target platform.
-+
-+.TP
-+\fB--arcs-boot\fR
-+Enable ARCS booting.  This is typically for big-endian MIPS machines, and disables HFS+, APM, sparc64, and "boot as disk image" on the \fIi386-pc\fR target platform.
-+
-+.TP
-+\fB--\fR
-+All options after a \fB--\fR will be passed directly to xorriso's command line when generating the image.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-mkstandalone.1 b/util/grub-mkstandalone.1
-new file mode 100644
-index 00000000000..ba2d2bdf279
---- /dev/null
-+++ b/util/grub-mkstandalone.1
-@@ -0,0 +1,100 @@
-+.TH GRUB-MKSTANDALONE 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-mkstandalone\fR \(em Generate a standalone image in the selected format.
-+
-+.SH SYNOPSIS
-+\fBgrub-mkstandalone\fR [-o | --output=\fIFILE\fR] [-O | --format=\fIFORMAT\fR]
-+.RS 19
-+[-C | --compression=(\fIxz\fR|\fInone\fR|\fIauto\fR)]
-+.RE
-+.RS 19
-+[--modules=\fIMODULES\fR] [--install-modules=\fIMODULES\fR]
-+.RE
-+.RS 19
-+[--themes=\fITHEMES\fR] [--fonts=\fIFONTS\fR]
-+.RE
-+.RS 19
-+[--locales=\fILOCALES\fR] [--compress[=\fIno\fR,\fIxz\fR,\fIgz\fR,\fIlzo\fR]]
-+.RE
-+.RS 19
-+[-d | --directory=\fIDIR\fR] [--grub-mkimage=\fIFILE\fR]
-+.RE
-+.RS 19
-+\fISOURCE...\fR
-+
-+.SH DESCRIPTION
-+
-+.SH OPTIONS
-+.TP
-+--output=\fIFILE\fR
-+Write the generated file to \fIFILE\fR.  The default is to write to standard output.
-+
-+.TP
-+--format=\fIFORMAT\fR
-+Generate an image in the specified \fIFORMAT\fR.  Valid values are:
-+.RS
-+.RS 4
-+.P
-+i386-coreboot,
-+i386-multiboot,
-+i386-pc,
-+i386-pc-pxe,
-+i386-efi,
-+i386-ieee1275,
-+i386-qemu,
-+x86_64-efi,
-+mipsel-yeeloong-flash,
-+mipsel-fuloong2f-flash,
-+mipself-loongson-elf,
-+powerpc-ieee1275,
-+sparc64-ieee1275-raw,
-+sparc64-ieee1275-cdcore,
-+sparc64-ieee1275-aout,
-+ia64-efi,
-+mips-arc,
-+mipsel-arc,
-+mipsel-qemu_mips-elf,
-+mips-qemu_mips-flash,
-+mipsel-qemu_mips-flash,
-+mips-qemu_mips-elf
-+.RE
-+.RE
-+
-+.TP
-+--compression=(\fIxz\fR|\fInone\fR|\fIauto\fR)
-+Use one of \fIxz\fR, \fInone\fR, or \fIauto\fR as the compression method for the core image.
-+
-+.TP
-+--modules=\fIMODULES\fR
-+Pre-load modules specified by \fIMODULES\fR.
-+
-+.TP
-+--install-modules=\fIMODULES\fR
-+Install only \fIMODULES\fR and their dependencies.  The default is to install all available modules.
-+
-+.TP
-+--themes=\fITHEMES\fR
-+Install \fITHEMES\fR.  The default is to install the \fIstarfield\fR theme, if available.
-+
-+.TP
-+--fonts=\fIFONTS\fR
-+Install \fIFONTS\fR.  The default is to install the \fIunicode\fR font.
-+
-+.TP
-+--locales=\fILOCALES\fR
-+Install only locales listed in \fILOCALES\fR.  The default is to install all available locales.
-+
-+.TP
-+--compress[=\fIno\fR,\fIxz\fR,\fIgz\fR,\fIlzo\fR]
-+Compress GRUB files using the specified compression algorithm.
-+
-+.TP
-+--directory=\fIDIR\fR
-+Use images and modules in \fIDIR\fR.
-+
-+.TP
-+--grub-mkimage=\fIFILE\fR
-+Use \fIFILE\fR as \fBgrub-mkimage\fR.  The default is \fI/usr/bin/grub-mkimage\fR.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-ofpathname.8 b/util/grub-ofpathname.8
-new file mode 100644
-index 00000000000..bf3743aeba1
---- /dev/null
-+++ b/util/grub-ofpathname.8
-@@ -0,0 +1,12 @@
-+.TH GRUB-OFPATHNAME 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-ofpathname\fR \(em Generate an IEEE-1275 device path for a specified device.
-+
-+.SH SYNOPSIS
-+\fBgrub-ofpathname\fR \fIDEVICE\fR
-+
-+.SH DESCRIPTION
-+\fBgrub-ofpathname\fR generates an IEEE-1275 device path for the specified \fIDEVICE\fR.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-probe.8 b/util/grub-probe.8
-new file mode 100644
-index 00000000000..04e26c832bb
---- /dev/null
-+++ b/util/grub-probe.8
-@@ -0,0 +1,80 @@
-+.TH GRUB-PROBE 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-probe\fR \(em Probe device information for a given path.
-+
-+.SH SYNOPSIS
-+\fBgrub-probe\fR \[-d | --device] [-m | --device-map=\fIFILE\fR]
-+.RS 12
-+[-t | --target=(fs|fs_uuid|fs_label|drive|device|partmap|
-+.RE
-+.RS 28
-+abstraction|cryptodisk_uuid|
-+.RE
-+.RS 28
-+msdos_parttype)]
-+.RE
-+.RS 12
-+[-v | --verbose] (PATH|DEVICE)
-+
-+.SH DESCRIPTION
-+\fBgrub-probe\fR probes a path or device for filesystem and related information.
-+
-+.SH OPTIONS
-+.TP
-+--device
-+Final option represents a \fIDEVICE\fR, rather than a filesystem \fIPATH\fR.
-+.TP
-+--device-map=\fIFILE\fR
-+Use \fIFILE\fR as the device map.  The default value is \fI/boot/grub/device.map\fR.
-+
-+.TP
-+--target=(fs|fs_uuid|fs_label|drive|device|partmap|msdos_parttype)
-+Select among various output definitions.  The default is \fIfs\fR.
-+.RS
-+.TP
-+\fIfs\fR
-+filesystem module
-+
-+.TP
-+\fIfs_uuid\fR
-+filesystem UUID
-+
-+.TP
-+\fIfs_label\fR
-+filesystem label
-+
-+.TP
-+\fIdrive\fR
-+GRUB drive name
-+
-+.TP
-+\fIdevice\fR
-+System device
-+
-+.TP
-+\fIpartmap\fR
-+partition map module
-+
-+.TP
-+\fIabstraction\fR
-+abstraction module
-+
-+.TP
-+\fIcryptodisk_uuid\fR
-+cryptographic container
-+
-+.TP
-+\fImsdos_partmap\fR
-+MS-DOS partition map
-+.RE
-+
-+.TP
-+--verbose
-+Print verbose output.
-+
-+.TP
-+(\fIPATH\fR|\fIDEVICE\fR)
-+If --device is passed, a block \fIDEVICE\fR.  Otherwise, the \fIPATH\fR of a file on the filesystem.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-reboot.8 b/util/grub-reboot.8
-new file mode 100644
-index 00000000000..faa5e4eece2
---- /dev/null
-+++ b/util/grub-reboot.8
-@@ -0,0 +1,21 @@
-+.TH GRUB-REBOOT 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-reboot\fR \(em Set the default boot menu entry for the next boot only.
-+
-+.SH SYNOPSIS
-+\fBgrub-reboot\fR [--boot-directory=\fIDIR\fR] \fIMENU_ENTRY\fR
-+
-+.SH DESCRIPTION
-+\fBgrub-reboot\fR sets the default boot menu entry for the next boot, but not further boots after that.  This command only works for GRUB configuration files created with \fIGRUB_DEFAULT=saved\fR in \fI/etc/default/grub\fR.
-+
-+.SH OPTIONS
-+.TP
-+--boot-directory=\fIDIR\fR
-+Find GRUB images under \fIDIR/grub\fR.  The default value is \fI/boot\fR, resulting in grub images being search for at \fI/boot/grub\fR.
-+
-+.TP
-+\fIMENU_ENTRY\fR
-+A number, a menu item title or a menu item identifier.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-render-label.1 b/util/grub-render-label.1
-new file mode 100644
-index 00000000000..4d51c8abf01
---- /dev/null
-+++ b/util/grub-render-label.1
-@@ -0,0 +1,51 @@
-+.TH GRUB-RENDER-LABEL 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-render-label\fR \(em Render an Apple disk label.
-+
-+.SH SYNOPSIS
-+\fBgrub-render-label\fR [-b | --bgcolor=\fICOLOR\fR] [-c | --color=\fICOLOR\fR]
-+.RS 19
-+[-f | --font=\fIFILE\fR] [-i | --input=\fIFILE\fR]
-+.RE
-+.RS 19
-+[-o | --output=\fIFILE\fR] [-t | --text=\fISTRING\fR]
-+.RE
-+.RS 19
-+[-v | --verbose]
-+
-+.SH DESCRIPTION
-+\fBgrub-render-label\fR renders an Apple disk label (.disk_label) file.
-+
-+
-+.SH OPTIONS
-+.TP
-+\fB--color\fR=\fICOLOR\fR
-+Use \fICOLOR\fI as the color for generated labels.
-+
-+.TP
-+\fB--bgcolor\fR=\fICOLOR\fR
-+Use \fICOLOR\fR as the background color for generated labels.
-+
-+.TP
-+\fB--font\fR=\fIFILE\fR
-+Use \fIFILE\fR as the font file for generated labels.
-+
-+.TP
-+--input=\fIFILE\fR
-+Read input text from \fIFILE\fR.
-+
-+.TP
-+--output=\fIFILE\fR
-+Render output to \fIFILE\fR.
-+
-+.TP
-+--text=\fISTRING\fR
-+Use \fISTRING\fR as input text.
-+
-+.TP
-+--verbose
-+Print verbose output.
-+
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-script-check.1 b/util/grub-script-check.1
-new file mode 100644
-index 00000000000..0f1f625b05d
---- /dev/null
-+++ b/util/grub-script-check.1
-@@ -0,0 +1,21 @@
-+.TH GRUB-SCRIPT-CHECK 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-script-check\fR \(em Check GRUB configuration file for syntax errors.
-+
-+.SH SYNOPSIS
-+\fBgrub-script-check\fR [-v | --verbose] \fIPATH\fR
-+
-+.SH DESCRIPTION
-+\fBgrub-script-check\fR verifies that a specified GRUB configuration file does not contain syntax errors.
-+
-+.SH OPTIONS
-+.TP
-+--verbose
-+Print verbose output.
-+
-+.TP
-+\fIPATH\fR
-+Path of the file to use as input.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-set-default.8 b/util/grub-set-default.8
-new file mode 100644
-index 00000000000..a96265a1509
---- /dev/null
-+++ b/util/grub-set-default.8
-@@ -0,0 +1,21 @@
-+.TH GRUB-SET-DEFAULT 1 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-set-default\fR \(em Set the default boot menu entry for GRUB.
-+
-+.SH SYNOPSIS
-+\fBgrub-set-default\fR [--boot-directory=\fIDIR\fR] \fIMENU_ENTRY\fR
-+
-+.SH DESCRIPTION
-+\fBgrub-set-default\fR sets the default boot menu entry for all subsequent boots.  This command only works for GRUB configuration files created with \fIGRUB_DEFAULT=saved\fR in \fI/etc/default/grub\fR.
-+
-+.SH OPTIONS
-+.TP
-+--boot-directory=\fIDIR\fR
-+Find GRUB images under \fIDIR/grub\fR.  The default value is \fI/boot\fR, resulting in grub images being search for at \fI/boot/grub\fR.
-+
-+.TP
-+\fIMENU_ENTRY\fR
-+A number, a menu item title or a menu item identifier.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-sparc64-setup.8 b/util/grub-sparc64-setup.8
-new file mode 100644
-index 00000000000..37ea2dd5eaa
---- /dev/null
-+++ b/util/grub-sparc64-setup.8
-@@ -0,0 +1,12 @@
-+.TH GRUB-SPARC64-SETUP 3 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-sparc64-setup\fR \(em Set up a device to boot a sparc64 GRUB image.
-+
-+.SH SYNOPSIS
-+\fBgrub-sparc64-setup\fR [OPTIONS].
-+
-+.SH DESCRIPTION
-+You should not normally run this program directly.  Use grub-install instead.
-+
-+.SH SEE ALSO
-+.BR "info grub"
diff --git a/SOURCES/0040-macos-just-build-chainloader-entries-don-t-try-any-x.patch b/SOURCES/0040-macos-just-build-chainloader-entries-don-t-try-any-x.patch
new file mode 100644
index 0000000..8d3139d
--- /dev/null
+++ b/SOURCES/0040-macos-just-build-chainloader-entries-don-t-try-any-x.patch
@@ -0,0 +1,124 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 24 May 2017 12:42:32 -0400
+Subject: [PATCH] macos: just build chainloader entries, don't try any xnu xnu.
+
+Since our bugs tell us that the xnu boot entries really just don't work
+most of the time, and they create piles of extra boot entries, because
+they can't quite figure out 32-vs-64 and other stuff like that.
+
+It's rediculous, and we should just boot their bootloader through the
+chainloader instead.
+
+So this patch does that.
+
+Resolves: rhbz#893179
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub.d/30_os-prober.in | 78 +++++++++++----------------------------------
+ 1 file changed, 18 insertions(+), 60 deletions(-)
+
+diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in
+index 1b91c102f3..4b27bd2015 100644
+--- a/util/grub.d/30_os-prober.in
++++ b/util/grub.d/30_os-prober.in
+@@ -42,68 +42,25 @@ if [ -z "${OSPROBED}" ] ; then
+ fi
+ 
+ osx_entry() {
+-    if [ x$2 = x32 ]; then
+-        # TRANSLATORS: it refers to kernel architecture (32-bit)
+-	bitstr="$(gettext "(32-bit)")"
+-    else
+-        # TRANSLATORS: it refers to kernel architecture (64-bit)
+-	bitstr="$(gettext "(64-bit)")"
+-    fi
+     # TRANSLATORS: it refers on the OS residing on device %s
+     onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+-        cat << EOF
+-menuentry '$(echo "${LONGNAME} $bitstr $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")'  {
++    hints=""
++    for hint in `"${grub_probe}" --device ${device} --target=efi_hints 2> /dev/null` ; do
++      hints="${hints} --hint=${hint}"
++    done
++    cat << EOF
++menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")'  {
+ EOF
+ 	save_default_entry | grub_add_tab
+ 	prepare_grub_to_access_device ${DEVICE} | grub_add_tab
+ 	cat << EOF
++	set gfxpayload=keep
+         load_video
+-        set do_resume=0
+-        if [ /var/vm/sleepimage -nt10 / ]; then
+-           if xnu_resume /var/vm/sleepimage; then
+-             set do_resume=1
+-           fi
+-        fi
+-        if [ \$do_resume = 0 ]; then
+-           xnu_uuid ${OSXUUID} uuid
+-           if [ -f /Extra/DSDT.aml ]; then
+-              acpi -e /Extra/DSDT.aml
+-           fi
+-           if [ /kernelcache -nt /System/Library/Extensions ]; then
+-              $1 /kernelcache boot-uuid=\${uuid} rd=*uuid
+-           elif [ -f /System/Library/Kernels/kernel ]; then
+-              $1 /System/Library/Kernels/kernel boot-uuid=\${uuid} rd=*uuid
+-              xnu_kextdir /System/Library/Extensions
+-           else
+-              $1 /mach_kernel boot-uuid=\${uuid} rd=*uuid
+-              if [ /System/Library/Extensions.mkext -nt /System/Library/Extensions ]; then
+-                xnu_mkext /System/Library/Extensions.mkext
+-              else
+-                xnu_kextdir /System/Library/Extensions
+-              fi
+-           fi
+-           if [ -f /Extra/Extensions.mkext ]; then
+-              xnu_mkext /Extra/Extensions.mkext
+-           fi
+-           if [ -d /Extra/Extensions ]; then
+-              xnu_kextdir /Extra/Extensions
+-           fi
+-           if [ -f /Extra/devprop.bin ]; then
+-              xnu_devprop_load /Extra/devprop.bin
+-           fi
+-           if [ -f /Extra/splash.jpg ]; then
+-              insmod jpeg
+-              xnu_splash /Extra/splash.jpg
+-           fi
+-           if [ -f /Extra/splash.png ]; then
+-              insmod png
+-              xnu_splash /Extra/splash.png
+-           fi
+-           if [ -f /Extra/splash.tga ]; then
+-              insmod tga
+-              xnu_splash /Extra/splash.tga
+-           fi
+-        fi
++	insmod part_gpt
++	insmod hfsplus
++	search --no-floppy --fs-uuid --set=root ${hints} $(grub_get_device_id "${DEVICE}")
++	chainloader (\$root)/System/Library/CoreServices/boot.efi
++	boot
+ }
+ EOF
+ }
+@@ -292,11 +249,12 @@ EOF
+       echo "$title_correction_code"
+     ;;
+     macosx)
+-      if [ "${UUID}" ]; then
+-	OSXUUID="${UUID}"
+-	osx_entry xnu_kernel 32
+-	osx_entry xnu_kernel64 64
+-      fi
++      for subdevice in ${DEVICE%[[:digit:]]*}* ; do
++	parttype="`"${grub_probe}" --device ${device} --target=gpt_parttype "${subdevice}" 2> /dev/null`"
++	if [[ "$parttype" = "426f6f74-0000-11aa-aa11-00306543ecac" ]]; then
++	  DEVICE="${subdevice}" osx_entry
++	fi
++      done
+     ;;
+     hurd)
+       onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
diff --git a/SOURCES/0041-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch b/SOURCES/0041-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch
new file mode 100644
index 0000000..57d2391
--- /dev/null
+++ b/SOURCES/0041-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch
@@ -0,0 +1,703 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jeff Mahoney <jeffm@suse.com>
+Date: Tue, 9 Jul 2019 13:39:45 +0200
+Subject: [PATCH] grub2/btrfs: Add ability to boot from subvolumes
+
+This patch adds the ability to specify a different root on a btrfs
+filesystem too boot from other than the default one.
+
+btrfs-list-snapshots <dev> will list the subvolumes available on the
+filesystem.
+
+set btrfs_subvol=<path> and set btrfs_subvolid=<subvolid> will specify
+which subvolume to use and any pathnames provided with either of those
+variables set will start using that root. If the subvolume or subvolume id
+doesn't exist, then an error case will result.
+
+It is possible to boot into a separate GRUB instance by exporting the
+variable and loading the config file from the subvolume.
+
+Signed-off-by: Jeff Mahoney <jeffm@suse.com>
+---
+ grub-core/fs/btrfs.c | 552 +++++++++++++++++++++++++++++++++++++++++++++++++--
+ include/grub/btrfs.h |   1 +
+ 2 files changed, 533 insertions(+), 20 deletions(-)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index 63203034df..f1fff7385b 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -38,6 +38,9 @@
+ #include <zstd.h>
+ #include <grub/i18n.h>
+ #include <grub/btrfs.h>
++#include <grub/command.h>
++#include <grub/env.h>
++#include <grub/extcmd.h>
+ #include <grub/crypto.h>
+ #include <grub/diskfilter.h>
+ #include <grub/safemath.h>
+@@ -79,9 +82,11 @@ struct grub_btrfs_superblock
+   grub_uint64_t generation;
+   grub_uint64_t root_tree;
+   grub_uint64_t chunk_tree;
+-  grub_uint8_t dummy2[0x20];
++  grub_uint8_t dummy2[0x18];
++  grub_uint64_t bytes_used;
+   grub_uint64_t root_dir_objectid;
+-  grub_uint8_t dummy3[0x41];
++  grub_uint64_t num_devices;
++  grub_uint8_t dummy3[0x39];
+   struct grub_btrfs_device this_device;
+   char label[0x100];
+   grub_uint8_t dummy4[0x100];
+@@ -121,6 +126,7 @@ struct grub_btrfs_data
+   grub_uint64_t exttree;
+   grub_size_t extsize;
+   struct grub_btrfs_extent_data *extent;
++  grub_uint64_t fs_tree;
+ };
+ 
+ struct grub_btrfs_chunk_item
+@@ -191,6 +197,14 @@ struct grub_btrfs_leaf_descriptor
+   } *data;
+ };
+ 
++struct grub_btrfs_root_ref
++{
++  grub_uint64_t dirid;
++  grub_uint64_t sequence;
++  grub_uint16_t name_len;
++  const char name[0];
++} __attribute__ ((packed));
++
+ struct grub_btrfs_time
+ {
+   grub_int64_t sec;
+@@ -236,6 +250,14 @@ struct grub_btrfs_extent_data
+ 
+ #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100
+ 
++#define GRUB_BTRFS_ROOT_TREE_OBJECTID 1ULL
++#define GRUB_BTRFS_FS_TREE_OBJECTID 5ULL
++#define GRUB_BTRFS_ROOT_REF_KEY     156
++#define GRUB_BTRFS_ROOT_ITEM_KEY     132
++
++static grub_uint64_t btrfs_default_subvolid = 0;
++static char *btrfs_default_subvol = NULL;
++
+ static grub_disk_addr_t superblock_sectors[] = { 64 * 2, 64 * 1024 * 2,
+   256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2
+ };
+@@ -1173,6 +1195,62 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
+   return GRUB_ERR_NONE;
+ }
+ 
++static grub_err_t
++get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree,
++            grub_uint64_t objectid, grub_uint64_t offset,
++            grub_uint64_t *fs_root);
++
++static grub_err_t
++lookup_root_by_id(struct grub_btrfs_data *data, grub_uint64_t id)
++{
++  grub_err_t err;
++  grub_uint64_t tree;
++
++  err = get_fs_root(data, data->sblock.root_tree, id, -1, &tree);
++  if (!err)
++    data->fs_tree = tree;
++  return err;
++}
++
++static grub_err_t
++find_path (struct grub_btrfs_data *data,
++	   const char *path, struct grub_btrfs_key *key,
++	   grub_uint64_t *tree, grub_uint8_t *type);
++
++static grub_err_t
++lookup_root_by_name(struct grub_btrfs_data *data, const char *path)
++{
++  grub_err_t err;
++  grub_uint64_t tree = 0;
++  grub_uint8_t type;
++  struct grub_btrfs_key key;
++
++  err = find_path (data, path, &key, &tree, &type);
++  if (err)
++      return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path);
++
++  if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0)
++    return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path);
++
++  data->fs_tree = tree;
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__ ((unused)))
++{
++  if (btrfs_default_subvol)
++    return lookup_root_by_name(data, btrfs_default_subvol);
++
++  if (btrfs_default_subvolid)
++    return lookup_root_by_id(data, btrfs_default_subvolid);
++
++  data->fs_tree = 0;
++
++  return GRUB_ERR_NONE;
++}
++
++
+ static struct grub_btrfs_data *
+ grub_btrfs_mount (grub_device_t dev)
+ {
+@@ -1208,6 +1286,13 @@ grub_btrfs_mount (grub_device_t dev)
+   data->devices_attached[0].dev = dev;
+   data->devices_attached[0].id = data->sblock.this_device.device_id;
+ 
++  err = btrfs_handle_subvol (data);
++  if (err)
++    {
++      grub_free (data);
++      return NULL;
++    }
++
+   return data;
+ }
+ 
+@@ -1673,6 +1758,91 @@ get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key,
+   return GRUB_ERR_NONE;
+ }
+ 
++static grub_err_t
++find_pathname(struct grub_btrfs_data *data, grub_uint64_t objectid,
++              grub_uint64_t fs_root, const char *name, char **pathname)
++{
++  grub_err_t err;
++  struct grub_btrfs_key key = {
++    .object_id = objectid,
++    .type = GRUB_BTRFS_ITEM_TYPE_INODE_REF,
++    .offset = 0,
++  };
++  struct grub_btrfs_key key_out;
++  struct grub_btrfs_leaf_descriptor desc;
++  char *p = grub_strdup (name);
++  grub_disk_addr_t elemaddr;
++  grub_size_t elemsize;
++  grub_size_t alloc = grub_strlen(name) + 1;
++
++  err = lower_bound(data, &key, &key_out, fs_root,
++                    &elemaddr, &elemsize, &desc, 0);
++  if (err)
++    return grub_error(err, "lower_bound caught %d\n", err);
++
++  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF)
++    next(data, &desc, &elemaddr, &elemsize, &key_out);
++
++  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF)
++    {
++      return grub_error(GRUB_ERR_FILE_NOT_FOUND,
++                        "Can't find inode ref for {%"PRIuGRUB_UINT64_T
++                        ", %u, %"PRIuGRUB_UINT64_T"} %"PRIuGRUB_UINT64_T
++                        "/%"PRIuGRUB_SIZE"\n",
++                        key_out.object_id, key_out.type,
++                        key_out.offset, elemaddr, elemsize);
++    }
++
++
++  while (key_out.type == GRUB_BTRFS_ITEM_TYPE_INODE_REF &&
++         key_out.object_id != key_out.offset) {
++    struct grub_btrfs_inode_ref *inode_ref;
++    char *new;
++
++    inode_ref = grub_malloc(elemsize + 1);
++    if (!inode_ref)
++      return grub_error(GRUB_ERR_OUT_OF_MEMORY,
++                        "couldn't allocate memory for inode_ref (%"PRIuGRUB_SIZE")\n", elemsize);
++
++    err = grub_btrfs_read_logical(data, elemaddr, inode_ref, elemsize, 0);
++    if (err)
++      return grub_error(err, "read_logical caught %d\n", err);
++
++    alloc += grub_le_to_cpu16 (inode_ref->n) + 2;
++    new = grub_malloc(alloc);
++    if (!new)
++      return grub_error(GRUB_ERR_OUT_OF_MEMORY,
++                        "couldn't allocate memory for name (%"PRIuGRUB_SIZE")\n", alloc);
++
++    grub_memcpy(new, inode_ref->name, grub_le_to_cpu16 (inode_ref->n));
++    if (p)
++      {
++        new[grub_le_to_cpu16 (inode_ref->n)] = '/';
++        grub_strcpy (new + grub_le_to_cpu16 (inode_ref->n) + 1, p);
++        grub_free(p);
++      }
++    else
++      new[grub_le_to_cpu16 (inode_ref->n)] = 0;
++    grub_free(inode_ref);
++
++    p = new;
++
++    key.object_id = key_out.offset;
++
++    err = lower_bound(data, &key, &key_out, fs_root, &elemaddr,
++                      &elemsize, &desc, 0);
++    if (err)
++      return grub_error(err, "lower_bound caught %d\n", err);
++
++    if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF)
++      next(data, &desc, &elemaddr, &elemsize, &key_out);
++
++  }
++
++  *pathname = p;
++  return 0;
++}
++
+ static grub_err_t
+ find_path (struct grub_btrfs_data *data,
+ 	   const char *path, struct grub_btrfs_key *key,
+@@ -1691,14 +1861,26 @@ find_path (struct grub_btrfs_data *data,
+   char *origpath = NULL;
+   unsigned symlinks_max = 32;
+ 
+-  err = get_root (data, key, tree, type);
+-  if (err)
+-    return err;
+-
+   origpath = grub_strdup (path);
+   if (!origpath)
+     return grub_errno;
+ 
++  if (data->fs_tree)
++    {
++      *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
++      *tree = data->fs_tree;
++      /* This is a tree root, so everything starts at objectid 256 */
++      key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
++      key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
++      key->offset = 0;
++    }
++  else
++    {
++      err = get_root (data, key, tree, type);
++      if (err)
++	return err;
++    }
++
+   while (1)
+     {
+       while (path[0] == '/')
+@@ -1871,9 +2053,21 @@ find_path (struct grub_btrfs_data *data,
+ 	  path = path_alloc = tmp;
+ 	  if (path[0] == '/')
+ 	    {
+-	      err = get_root (data, key, tree, type);
+-	      if (err)
+-		return err;
++	      if (data->fs_tree)
++		{
++		  *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
++		  *tree = data->fs_tree;
++		  /* This is a tree root, so everything starts at objectid 256 */
++		  key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
++		  key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
++		  key->offset = 0;
++		}
++	      else
++		{
++		  err = get_root (data, key, tree, type);
++		  if (err)
++		    return err;
++		}
+ 	    }
+ 	  continue;
+ 	}
+@@ -2114,18 +2308,10 @@ grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len)
+ 				 data->tree, file->offset, buf, len);
+ }
+ 
+-static grub_err_t
+-grub_btrfs_uuid (grub_device_t device, char **uuid)
++static char *
++btrfs_unparse_uuid(struct grub_btrfs_data *data)
+ {
+-  struct grub_btrfs_data *data;
+-
+-  *uuid = NULL;
+-
+-  data = grub_btrfs_mount (device);
+-  if (!data)
+-    return grub_errno;
+-
+-  *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
++  return  grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
+ 			  grub_be_to_cpu16 (data->sblock.uuid[0]),
+ 			  grub_be_to_cpu16 (data->sblock.uuid[1]),
+ 			  grub_be_to_cpu16 (data->sblock.uuid[2]),
+@@ -2134,6 +2320,20 @@ grub_btrfs_uuid (grub_device_t device, char **uuid)
+ 			  grub_be_to_cpu16 (data->sblock.uuid[5]),
+ 			  grub_be_to_cpu16 (data->sblock.uuid[6]),
+ 			  grub_be_to_cpu16 (data->sblock.uuid[7]));
++}
++
++static grub_err_t
++grub_btrfs_uuid (grub_device_t device, char **uuid)
++{
++  struct grub_btrfs_data *data;
++
++  *uuid = NULL;
++
++  data = grub_btrfs_mount (device);
++  if (!data)
++    return grub_errno;
++
++  *uuid = btrfs_unparse_uuid(data);
+ 
+   grub_btrfs_unmount (data);
+ 
+@@ -2190,6 +2390,242 @@ grub_btrfs_embed (grub_device_t device __attribute__ ((unused)),
+ }
+ #endif
+ 
++static grub_err_t
++grub_cmd_btrfs_info (grub_command_t cmd __attribute__ ((unused)), int argc,
++		     char **argv)
++{
++  grub_device_t dev;
++  char *devname;
++  struct grub_btrfs_data *data;
++  char *uuid;
++
++  if (argc < 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
++
++  devname = grub_file_get_device_name(argv[0]);
++
++  if (!devname)
++    return grub_errno;
++
++  dev = grub_device_open (devname);
++  grub_free (devname);
++  if (!dev)
++    return grub_errno;
++
++  data = grub_btrfs_mount (dev);
++  if (!data)
++    {
++      grub_device_close(dev);
++      return grub_error (GRUB_ERR_BAD_ARGUMENT, "failed to open fs");
++    }
++
++  if (data->sblock.label)
++    grub_printf("Label: '%s' ", data->sblock.label);
++  else
++    grub_printf("Label: none ");
++
++  uuid = btrfs_unparse_uuid(data);
++
++  grub_printf(" uuid: %s\n\tTotal devices %" PRIuGRUB_UINT64_T
++              " FS bytes used %" PRIuGRUB_UINT64_T "\n",
++	      uuid, grub_cpu_to_le64(data->sblock.num_devices),
++	      grub_cpu_to_le64(data->sblock.bytes_used));
++
++  grub_btrfs_unmount (data);
++
++  return 0;
++}
++
++static grub_err_t
++get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree,
++            grub_uint64_t objectid, grub_uint64_t offset,
++            grub_uint64_t *fs_root)
++{
++  grub_err_t err;
++  struct grub_btrfs_key key_in = {
++    .object_id = objectid,
++    .type = GRUB_BTRFS_ROOT_ITEM_KEY,
++    .offset = offset,
++  }, key_out;
++  struct grub_btrfs_leaf_descriptor desc;
++  grub_disk_addr_t elemaddr;
++  grub_size_t elemsize;
++  struct grub_btrfs_root_item ri;
++
++  err = lower_bound(data, &key_in, &key_out, tree,
++                    &elemaddr, &elemsize, &desc, 0);
++
++  if (err)
++    return err;
++
++  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM || elemaddr == 0)
++    return grub_error(GRUB_ERR_FILE_NOT_FOUND,
++                    N_("can't find fs root for subvol %"PRIuGRUB_UINT64_T"\n"),
++                    key_in.object_id);
++
++  err = grub_btrfs_read_logical (data, elemaddr, &ri, sizeof (ri), 0);
++  if (err)
++    return err;
++
++  *fs_root = ri.tree;
++
++  return GRUB_ERR_NONE;
++}
++
++static const struct grub_arg_option options[] = {
++  {"output", 'o', 0, N_("Output to a variable instead of the console."),
++   N_("VARNAME"), ARG_TYPE_STRING},
++  {"path-only", 'p', 0, N_("Show only the path of the subvolume."), 0, 0},
++  {"id-only", 'i', 0, N_("Show only the id of the subvolume."), 0, 0},
++  {0, 0, 0, 0, 0, 0}
++};
++
++static grub_err_t
++grub_cmd_btrfs_list_subvols (struct grub_extcmd_context *ctxt,
++			     int argc, char **argv)
++{
++  struct grub_btrfs_data *data;
++  grub_device_t dev;
++  char *devname;
++  grub_uint64_t tree;
++  struct grub_btrfs_key key_in = {
++    .object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID),
++    .type = GRUB_BTRFS_ROOT_REF_KEY,
++    .offset = 0,
++  }, key_out;
++  struct grub_btrfs_leaf_descriptor desc;
++  grub_disk_addr_t elemaddr;
++  grub_uint64_t fs_root = 0;
++  grub_size_t elemsize;
++  grub_size_t allocated = 0;
++  int r = 0;
++  grub_err_t err;
++  char *buf = NULL;
++  int print = 1;
++  int path_only = ctxt->state[1].set;
++  int num_only = ctxt->state[2].set;
++  char *varname = NULL;
++  char *output = NULL;
++
++  if (ctxt->state[0].set) {
++    varname = ctxt->state[0].arg;
++    print = 0;
++  }
++
++  if (argc < 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
++
++  devname = grub_file_get_device_name(argv[0]);
++  if (!devname)
++    return grub_errno;
++
++  dev = grub_device_open (devname);
++  grub_free (devname);
++  if (!dev)
++    return grub_errno;
++
++  data = grub_btrfs_mount(dev);
++  if (!data)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, "could not open device");
++
++  tree = data->sblock.root_tree;
++  err = get_fs_root(data, tree, grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID),
++                    0, &fs_root);
++  if (err)
++    goto out;
++
++  err = lower_bound(data, &key_in, &key_out, tree,
++                    &elemaddr, &elemsize, &desc, 0);
++
++  if (err)
++    {
++      grub_btrfs_unmount(data);
++      return err;
++    }
++
++  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF || elemaddr == 0)
++    {
++      r = next(data, &desc, &elemaddr, &elemsize, &key_out);
++    }
++
++  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF) {
++    err = GRUB_ERR_FILE_NOT_FOUND;
++    grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root refs"));
++    goto out;
++  }
++
++  do
++    {
++      struct grub_btrfs_root_ref *ref;
++      char *p = NULL;
++
++      if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF)
++        {
++          r = 0;
++          break;
++        }
++
++      if (elemsize > allocated)
++        {
++          grub_free(buf);
++          allocated = 2 * elemsize;
++          buf = grub_malloc(allocated + 1);
++          if (!buf)
++            {
++              r = -grub_errno;
++              break;
++            }
++        }
++      ref = (struct grub_btrfs_root_ref *)buf;
++
++      err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0);
++      if (err)
++        {
++          r = -err;
++          break;
++        }
++        buf[elemsize] = 0;
++
++      find_pathname(data, ref->dirid, fs_root, ref->name, &p);
++
++      if (print)
++        {
++          if (num_only)
++            grub_printf("ID %"PRIuGRUB_UINT64_T"\n", key_out.offset);
++          else if (path_only)
++            grub_printf("%s\n", p);
++          else
++            grub_printf("ID %"PRIuGRUB_UINT64_T" path %s\n", key_out.offset, p);
++        } else {
++          char *old = output;
++          if (num_only)
++            output = grub_xasprintf("%s%"PRIuGRUB_UINT64_T"\n",
++                                    old ?: "", key_out.offset);
++          else if (path_only)
++            output = grub_xasprintf("%s%s\n", old ?: "", p);
++          else
++            output = grub_xasprintf("%sID %"PRIuGRUB_UINT64_T" path %s\n",
++                                    old ?: "", key_out.offset, p);
++
++          if (old)
++            grub_free(old);
++        }
++
++      r = next(data, &desc, &elemaddr, &elemsize, &key_out);
++  } while(r > 0);
++
++  if (output)
++    grub_env_set(varname, output);
++
++out:
++  free_iterator(&desc);
++  grub_btrfs_unmount(data);
++
++  grub_device_close (dev);
++
++  return 0;
++}
++
+ static struct grub_fs grub_btrfs_fs = {
+   .name = "btrfs",
+   .fs_dir = grub_btrfs_dir,
+@@ -2205,12 +2641,88 @@ static struct grub_fs grub_btrfs_fs = {
+ #endif
+ };
+ 
++static grub_command_t cmd_info;
++static grub_extcmd_t cmd_list_subvols;
++
++static char *
++subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)),
++                  const char *val)
++{
++  unsigned long long result = 0;
++
++  grub_errno = GRUB_ERR_NONE;
++  if (*val)
++    {
++      result = grub_strtoull(val, NULL, 10);
++      if (grub_errno)
++        return NULL;
++    }
++
++  grub_free (btrfs_default_subvol);
++  btrfs_default_subvol = NULL;
++  btrfs_default_subvolid = result;
++  return grub_strdup(val);
++}
++
++static const char *
++subvolid_get_env (struct grub_env_var *var __attribute__ ((unused)),
++                  const char *val __attribute__ ((unused)))
++{
++  if (btrfs_default_subvol)
++    return grub_xasprintf("subvol:%s", btrfs_default_subvol);
++  else if (btrfs_default_subvolid)
++    return grub_xasprintf("%"PRIuGRUB_UINT64_T, btrfs_default_subvolid);
++  else
++    return "";
++}
++
++static char *
++subvol_set_env (struct grub_env_var *var __attribute__ ((unused)),
++                const char *val)
++{
++  grub_free (btrfs_default_subvol);
++  btrfs_default_subvol = grub_strdup (val);
++  btrfs_default_subvolid = 0;
++  return grub_strdup(val);
++}
++
++static const char *
++subvol_get_env (struct grub_env_var *var __attribute__ ((unused)),
++                const char *val __attribute__ ((unused)))
++{
++  if (btrfs_default_subvol)
++    return btrfs_default_subvol;
++  else if (btrfs_default_subvolid)
++    return grub_xasprintf("subvolid:%" PRIuGRUB_UINT64_T,
++                          btrfs_default_subvolid);
++  else
++    return "";
++}
++
+ GRUB_MOD_INIT (btrfs)
+ {
+   grub_fs_register (&grub_btrfs_fs);
++  cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info,
++				   "DEVICE",
++				   "Print BtrFS info about DEVICE.");
++  cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols",
++					 grub_cmd_btrfs_list_subvols, 0,
++					 "[-p|-n] [-o var] DEVICE",
++					 "Print list of BtrFS subvolumes on "
++					 "DEVICE.", options);
++  grub_register_variable_hook ("btrfs_subvol", subvol_get_env,
++                               subvol_set_env);
++  grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env,
++                               subvolid_set_env);
+ }
+ 
+ GRUB_MOD_FINI (btrfs)
+ {
++  grub_register_variable_hook ("btrfs_subvol", NULL, NULL);
++  grub_register_variable_hook ("btrfs_subvolid", NULL, NULL);
++  grub_unregister_command (cmd_info);
++  grub_unregister_extcmd (cmd_list_subvols);
+   grub_fs_unregister (&grub_btrfs_fs);
+ }
++
++// vim: si et sw=2:
+diff --git a/include/grub/btrfs.h b/include/grub/btrfs.h
+index 9d93fb6c18..234ad97677 100644
+--- a/include/grub/btrfs.h
++++ b/include/grub/btrfs.h
+@@ -29,6 +29,7 @@ enum
+     GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM = 0x84,
+     GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF = 0x90,
+     GRUB_BTRFS_ITEM_TYPE_DEVICE = 0xd8,
++    GRUB_BTRFS_ITEM_TYPE_ROOT_REF = 0x9c,
+     GRUB_BTRFS_ITEM_TYPE_CHUNK = 0xe4
+   };
+ 
diff --git a/SOURCES/0041-use-fw_path-prefix-when-fallback-searching-for-grub-.patch b/SOURCES/0041-use-fw_path-prefix-when-fallback-searching-for-grub-.patch
deleted file mode 100644
index 985205c..0000000
--- a/SOURCES/0041-use-fw_path-prefix-when-fallback-searching-for-grub-.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Fedora Ninjas <grub2-owner@fedoraproject.org>
-Date: Wed, 19 Feb 2014 15:58:43 -0500
-Subject: [PATCH] use fw_path prefix when fallback searching for grub config
-
-When PXE booting via UEFI firmware, grub was searching for grub.cfg
-in the fw_path directory where the grub application was found. If
-that didn't exist, a fallback search would look for config file names
-based on MAC and IP address. However, the search would look in the
-prefix directory which may not be the same fw_path. This patch
-changes that behavior to use the fw_path directory for the fallback
-search. Only if fw_path is NULL will the prefix directory be searched.
-
-Signed-off-by: Mark Salter <msalter@redhat.com>
----
- grub-core/normal/main.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
-index ec1cd257397..d85f7598d23 100644
---- a/grub-core/normal/main.c
-+++ b/grub-core/normal/main.c
-@@ -349,7 +349,7 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
-       char *config;
-       const char *prefix, *fw_path;
- 
--      fw_path = grub_env_get ("fw_path");
-+      prefix = fw_path = grub_env_get ("fw_path");
-       if (fw_path)
- 	{
- 	  config = grub_xasprintf ("%s/grub.cfg", fw_path);
-@@ -372,7 +372,8 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
- 	    }
- 	}
- 
--      prefix = grub_env_get ("prefix");
-+      if (! prefix)
-+	      prefix = grub_env_get ("prefix");
-       if (prefix)
-         {
-           grub_size_t config_len;
diff --git a/SOURCES/0042-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch b/SOURCES/0042-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch
deleted file mode 100644
index 61dd5ca..0000000
--- a/SOURCES/0042-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch
+++ /dev/null
@@ -1,127 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 8 Jul 2019 17:33:22 +0200
-Subject: [PATCH] Try mac/guid/etc before grub.cfg on tftp config files.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/normal/main.c | 97 ++++++++++++++++++++++++++-----------------------
- 1 file changed, 51 insertions(+), 46 deletions(-)
-
-diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
-index d85f7598d23..1e509fceb91 100644
---- a/grub-core/normal/main.c
-+++ b/grub-core/normal/main.c
-@@ -347,61 +347,66 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
-       /* Guess the config filename. It is necessary to make CONFIG static,
- 	 so that it won't get broken by longjmp.  */
-       char *config;
--      const char *prefix, *fw_path;
--
--      prefix = fw_path = grub_env_get ("fw_path");
--      if (fw_path)
--	{
--	  config = grub_xasprintf ("%s/grub.cfg", fw_path);
--	  if (config)
--	    {
--	      grub_file_t file;
--
--	      file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG);
--	      if (file)
--		{
--		  grub_file_close (file);
--		  grub_enter_normal_mode (config);
--		}
--              else
--                {
--                  /*  Ignore all errors.  */
--                  grub_errno = 0;
--                }
--	      grub_free (config);
--	    }
--	}
-+      const char *prefix;
-+      const char *net_search_cfg;
-+      int disable_net_search = 0;
- 
-+      prefix = grub_env_get ("fw_path");
-       if (! prefix)
- 	      prefix = grub_env_get ("prefix");
-+
-+      net_search_cfg = grub_env_get ("feature_net_search_cfg");
-+      if (net_search_cfg && net_search_cfg[0] == 'n')
-+	      disable_net_search = 1;
-+
-       if (prefix)
-         {
--          grub_size_t config_len;
--          int disable_net_search = 0;
--          const char *net_search_cfg;
--
--          config_len = grub_strlen (prefix) +
--                       sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
--          config = grub_malloc (config_len);
--
--          if (!config)
--            goto quit;
--
--          grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
--
--          net_search_cfg = grub_env_get ("feature_net_search_cfg");
--          if (net_search_cfg && net_search_cfg[0] == 'n')
--            disable_net_search = 1;
--
-           if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0 &&
-               !disable_net_search)
--            grub_net_search_config_file (config);
-+            {
-+              grub_size_t config_len;
-+              config_len = grub_strlen (prefix) +
-+                sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
-+              config = grub_malloc (config_len);
- 
--	  grub_enter_normal_mode (config);
--	  grub_free (config);
--	}
-+              if (! config)
-+                goto quit;
-+
-+              grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
-+
-+              grub_net_search_configfile (config);
-+
-+              grub_enter_normal_mode (config);
-+              grub_free (config);
-+              config = NULL;
-+            }
-+
-+          if (!config)
-+            {
-+              config = grub_xasprintf ("%s/grub.cfg", prefix);
-+              if (config)
-+                {
-+                  grub_file_t file;
-+
-+                  file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG);
-+                  if (file)
-+                    {
-+                      grub_file_close (file);
-+                      grub_enter_normal_mode (config);
-+                    }
-+                  else
-+                    {
-+                      /*  Ignore all errors.  */
-+                      grub_errno = 0;
-+                    }
-+                  grub_free (config);
-+                }
-+            }
-+        }
-       else
--	grub_enter_normal_mode (0);
-+        {
-+          grub_enter_normal_mode (0);
-+        }
-     }
-   else
-     grub_enter_normal_mode (argv[0]);
diff --git a/SOURCES/0042-export-btrfs_subvol-and-btrfs_subvolid.patch b/SOURCES/0042-export-btrfs_subvol-and-btrfs_subvolid.patch
new file mode 100644
index 0000000..719866e
--- /dev/null
+++ b/SOURCES/0042-export-btrfs_subvol-and-btrfs_subvolid.patch
@@ -0,0 +1,26 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Wed, 18 Dec 2013 09:57:04 +0000
+Subject: [PATCH] export btrfs_subvol and btrfs_subvolid
+
+We should export btrfs_subvol and btrfs_subvolid to have both visible
+to subsidiary configuration files loaded using configfile.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+---
+ grub-core/fs/btrfs.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index f1fff7385b..ad1b56b716 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -2714,6 +2714,8 @@ GRUB_MOD_INIT (btrfs)
+                                subvol_set_env);
+   grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env,
+                                subvolid_set_env);
++  grub_env_export ("btrfs_subvol");
++  grub_env_export ("btrfs_subvolid");
+ }
+ 
+ GRUB_MOD_FINI (btrfs)
diff --git a/SOURCES/0043-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch b/SOURCES/0043-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch
deleted file mode 100644
index ef0b0f4..0000000
--- a/SOURCES/0043-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 4 Sep 2014 14:23:23 -0400
-Subject: [PATCH] Generate OS and CLASS in 10_linux from /etc/os-release
-
-This makes us use pretty names in the titles we generate in
-grub2-mkconfig when GRUB_DISTRIBUTOR isn't set.
-
-Resolves: rhbz#996794
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- util/grub.d/10_linux.in | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
-index 635d2fe0cd3..fed73271478 100644
---- a/util/grub.d/10_linux.in
-+++ b/util/grub.d/10_linux.in
-@@ -29,7 +29,8 @@ export TEXTDOMAINDIR="@localedir@"
- CLASS="--class gnu-linux --class gnu --class os --unrestricted"
- 
- if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
--  OS="$(sed 's, release .*$,,g' /etc/system-release)"
-+  OS="$(eval $(grep PRETTY_NAME /etc/os-release) ; echo ${PRETTY_NAME})"
-+  CLASS="--class $(eval $(grep '^ID_LIKE=\|^ID=' /etc/os-release) ; [ -n "${ID_LIKE}" ] && echo ${ID_LIKE} || echo ${ID}) ${CLASS}"
- else
-   OS="${GRUB_DISTRIBUTOR}"
-   CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}"
diff --git a/SOURCES/0043-grub2-btrfs-03-follow_default.patch b/SOURCES/0043-grub2-btrfs-03-follow_default.patch
new file mode 100644
index 0000000..621f029
--- /dev/null
+++ b/SOURCES/0043-grub2-btrfs-03-follow_default.patch
@@ -0,0 +1,198 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 21 Aug 2014 03:39:11 +0000
+Subject: [PATCH] grub2-btrfs-03-follow_default
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/fs/btrfs.c | 107 ++++++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 76 insertions(+), 31 deletions(-)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index ad1b56b716..113c1f746c 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -1256,6 +1256,7 @@ grub_btrfs_mount (grub_device_t dev)
+ {
+   struct grub_btrfs_data *data;
+   grub_err_t err;
++  const char *relpath = grub_env_get ("btrfs_relative_path");
+ 
+   if (!dev->disk)
+     {
+@@ -1286,11 +1287,14 @@ grub_btrfs_mount (grub_device_t dev)
+   data->devices_attached[0].dev = dev;
+   data->devices_attached[0].id = data->sblock.this_device.device_id;
+ 
+-  err = btrfs_handle_subvol (data);
+-  if (err)
++  if (relpath && (relpath[0] == '1' || relpath[0] == 'y'))
+     {
+-      grub_free (data);
+-      return NULL;
++      err = btrfs_handle_subvol (data);
++      if (err)
++      {
++        grub_free (data);
++        return NULL;
++      }
+     }
+ 
+   return data;
+@@ -1855,24 +1859,39 @@ find_path (struct grub_btrfs_data *data,
+   grub_size_t allocated = 0;
+   struct grub_btrfs_dir_item *direl = NULL;
+   struct grub_btrfs_key key_out;
++  int follow_default;
+   const char *ctoken;
+   grub_size_t ctokenlen;
+   char *path_alloc = NULL;
+   char *origpath = NULL;
+   unsigned symlinks_max = 32;
++  const char *relpath = grub_env_get ("btrfs_relative_path");
+ 
++  follow_default = 0;
+   origpath = grub_strdup (path);
+   if (!origpath)
+     return grub_errno;
+ 
+-  if (data->fs_tree)
++  if (relpath && (relpath[0] == '1' || relpath[0] == 'y'))
+     {
+-      *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
+-      *tree = data->fs_tree;
+-      /* This is a tree root, so everything starts at objectid 256 */
+-      key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
+-      key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
+-      key->offset = 0;
++      if (data->fs_tree)
++        {
++          *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
++          *tree = data->fs_tree;
++          /* This is a tree root, so everything starts at objectid 256 */
++          key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
++          key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
++          key->offset = 0;
++        }
++      else
++        {
++          *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
++          *tree = data->sblock.root_tree;
++          key->object_id = data->sblock.root_dir_objectid;
++          key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
++          key->offset = 0;
++          follow_default = 1;
++        }
+     }
+   else
+     {
+@@ -1883,15 +1902,23 @@ find_path (struct grub_btrfs_data *data,
+ 
+   while (1)
+     {
+-      while (path[0] == '/')
+-	path++;
+-      if (!path[0])
+-	break;
+-      slash = grub_strchr (path, '/');
+-      if (!slash)
+-	slash = path + grub_strlen (path);
+-      ctoken = path;
+-      ctokenlen = slash - path;
++      if (!follow_default)
++	{
++	  while (path[0] == '/')
++	    path++;
++	  if (!path[0])
++	    break;
++	  slash = grub_strchr (path, '/');
++	  if (!slash)
++	    slash = path + grub_strlen (path);
++	  ctoken = path;
++	  ctokenlen = slash - path;
++	}
++      else
++	{
++	  ctoken = "default";
++	  ctokenlen = sizeof ("default") - 1;
++	}
+ 
+       if (*type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY)
+ 	{
+@@ -1902,7 +1929,9 @@ find_path (struct grub_btrfs_data *data,
+ 
+       if (ctokenlen == 1 && ctoken[0] == '.')
+ 	{
+-	  path = slash;
++	  if (!follow_default)
++	    path = slash;
++	  follow_default = 0;
+ 	  continue;
+ 	}
+       if (ctokenlen == 2 && ctoken[0] == '.' && ctoken[1] == '.')
+@@ -1933,8 +1962,9 @@ find_path (struct grub_btrfs_data *data,
+ 	  *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
+ 	  key->object_id = key_out.offset;
+ 
+-	  path = slash;
+-
++	  if (!follow_default)
++	    path = slash;
++	  follow_default = 0;
+ 	  continue;
+ 	}
+ 
+@@ -2003,7 +2033,9 @@ find_path (struct grub_btrfs_data *data,
+ 	  return err;
+ 	}
+ 
+-      path = slash;
++      if (!follow_default)
++	path = slash;
++      follow_default = 0;
+       if (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK)
+ 	{
+ 	  struct grub_btrfs_inode inode;
+@@ -2053,14 +2085,26 @@ find_path (struct grub_btrfs_data *data,
+ 	  path = path_alloc = tmp;
+ 	  if (path[0] == '/')
+ 	    {
+-	      if (data->fs_tree)
++              if (relpath && (relpath[0] == '1' || relpath[0] == 'y'))
+ 		{
+-		  *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
+-		  *tree = data->fs_tree;
+-		  /* This is a tree root, so everything starts at objectid 256 */
+-		  key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
+-		  key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
+-		  key->offset = 0;
++	          if (data->fs_tree)
++		    {
++		      *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
++		      *tree = data->fs_tree;
++		      /* This is a tree root, so everything starts at objectid 256 */
++		      key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
++		      key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
++		      key->offset = 0;
++		    }
++		  else
++		    {
++	              *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
++	              *tree = data->sblock.root_tree;
++	              key->object_id = data->sblock.root_dir_objectid;
++	              key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
++	              key->offset = 0;
++	              follow_default = 1;
++		    }
+ 		}
+ 	      else
+ 		{
+@@ -2716,6 +2760,7 @@ GRUB_MOD_INIT (btrfs)
+                                subvolid_set_env);
+   grub_env_export ("btrfs_subvol");
+   grub_env_export ("btrfs_subvolid");
++  grub_env_export ("btrfs_relative_path");
+ }
+ 
+ GRUB_MOD_FINI (btrfs)
diff --git a/SOURCES/0044-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch b/SOURCES/0044-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch
deleted file mode 100644
index 3e2d3ae..0000000
--- a/SOURCES/0044-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 4 Sep 2014 15:52:08 -0400
-Subject: [PATCH] Minimize the sort ordering for .debug and -rescue- kernels.
-
-Resolves: rhbz#1065360
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- util/grub-mkconfig_lib.in | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
-index 301d1ac229a..0f6505bf3b6 100644
---- a/util/grub-mkconfig_lib.in
-+++ b/util/grub-mkconfig_lib.in
-@@ -253,6 +253,14 @@ version_test_gt ()
-     *.old:*.old) ;;
-     *.old:*) version_test_gt_a="`echo "$version_test_gt_a" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=gt ;;
-     *:*.old) version_test_gt_b="`echo "$version_test_gt_b" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=ge ;;
-+    *-rescue*:*-rescue*) ;;
-+    *?debug:*?debug) ;;
-+    *-rescue*:*?debug) return 1 ;;
-+    *?debug:*-rescue*) return 0 ;;
-+    *-rescue*:*) return 1 ;;
-+    *:*-rescue*) return 0 ;;
-+    *?debug:*) return 1 ;;
-+    *:*?debug) return 0 ;;
-   esac
-   version_test_numeric "$version_test_gt_a" "$version_test_gt_cmp" "$version_test_gt_b"
-   return "$?"
diff --git a/SOURCES/0044-grub2-btrfs-04-grub2-install.patch b/SOURCES/0044-grub2-btrfs-04-grub2-install.patch
new file mode 100644
index 0000000..6b2bc78
--- /dev/null
+++ b/SOURCES/0044-grub2-btrfs-04-grub2-install.patch
@@ -0,0 +1,176 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 21 Aug 2014 03:39:11 +0000
+Subject: [PATCH] grub2-btrfs-04-grub2-install
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/osdep/linux/getroot.c |  7 +++++++
+ grub-core/osdep/unix/config.c   | 17 +++++++++++++++--
+ util/config.c                   | 10 ++++++++++
+ util/grub-install.c             | 15 +++++++++++++++
+ util/grub-mkrelpath.c           |  6 ++++++
+ include/grub/emu/config.h       |  1 +
+ 6 files changed, 54 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
+index 001b818fe5..caf9b1ccd3 100644
+--- a/grub-core/osdep/linux/getroot.c
++++ b/grub-core/osdep/linux/getroot.c
+@@ -376,6 +376,7 @@ get_btrfs_fs_prefix (const char *mount_path)
+   return NULL;
+ }
+ 
++int use_relative_path_on_btrfs = 0;
+ 
+ char **
+ grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
+@@ -519,6 +520,12 @@ again:
+ 	{
+ 	  ret = grub_find_root_devices_from_btrfs (dir);
+ 	  fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
++	  if (use_relative_path_on_btrfs)
++	    {
++	      if (fs_prefix)
++	        free (fs_prefix);
++	      fs_prefix = xstrdup ("/");
++	    }
+ 	}
+       else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0)
+ 	{
+diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c
+index 7d6325138c..46a881530c 100644
+--- a/grub-core/osdep/unix/config.c
++++ b/grub-core/osdep/unix/config.c
+@@ -82,6 +82,19 @@ grub_util_load_config (struct grub_util_config *cfg)
+   if (v)
+     cfg->grub_distributor = xstrdup (v);
+ 
++  v = getenv ("SUSE_BTRFS_SNAPSHOT_BOOTING");
++  if (v)
++    {
++      if (grub_strncmp(v, "true", sizeof ("true") - 1) == 0)
++        {
++          cfg->is_suse_btrfs_snapshot_enabled = 1;
++        }
++      else
++        {
++          cfg->is_suse_btrfs_snapshot_enabled = 0;
++        }
++    }
++
+   cfgfile = grub_util_get_config_filename ();
+   if (!grub_util_is_regular (cfgfile))
+     return;
+@@ -105,8 +118,8 @@ grub_util_load_config (struct grub_util_config *cfg)
+       *ptr++ = *iptr;
+     }
+ 
+-  strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" "
+-	  "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\"");
++  strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\nSUSE_BTRFS_SNAPSHOT_BOOTING=%s\\n\" "
++	  "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\" \"$SUSE_BTRFS_SNAPSHOT_BOOTING\"");
+ 
+   argv[2] = script;
+   argv[3] = '\0';
+diff --git a/util/config.c b/util/config.c
+index ebcdd8f5e2..f044a880a7 100644
+--- a/util/config.c
++++ b/util/config.c
+@@ -42,6 +42,16 @@ grub_util_parse_config (FILE *f, struct grub_util_config *cfg, int simple)
+ 	    cfg->is_cryptodisk_enabled = 1;
+ 	  continue;
+ 	}
++      if (grub_strncmp (ptr, "SUSE_BTRFS_SNAPSHOT_BOOTING=",
++			sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1) == 0)
++	{
++	  ptr += sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1;
++	  if (*ptr == '"' || *ptr == '\'')
++	    ptr++;
++	  if (grub_strncmp(ptr, "true", sizeof ("true") - 1) == 0)
++	    cfg->is_suse_btrfs_snapshot_enabled = 1;
++	  continue;
++	}
+       if (grub_strncmp (ptr, "GRUB_DISTRIBUTOR=",
+ 			sizeof ("GRUB_DISTRIBUTOR=") - 1) == 0)
+ 	{
+diff --git a/util/grub-install.c b/util/grub-install.c
+index 0fbe7f78c6..0f66f36d23 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -827,6 +827,8 @@ fill_core_services (const char *core_services)
+   free (sysv_plist);
+ }
+ 
++extern int use_relative_path_on_btrfs;
++
+ int
+ main (int argc, char *argv[])
+ {
+@@ -860,6 +862,9 @@ main (int argc, char *argv[])
+ 
+   grub_util_load_config (&config);
+ 
++  if (config.is_suse_btrfs_snapshot_enabled)
++    use_relative_path_on_btrfs = 1;
++
+   if (!bootloader_id && config.grub_distributor)
+     {
+       char *ptr;
+@@ -1352,6 +1357,16 @@ main (int argc, char *argv[])
+       fprintf (load_cfg_f, "set debug='%s'\n",
+ 	      debug_image);
+     }
++
++  if (config.is_suse_btrfs_snapshot_enabled
++      && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0)
++    {
++      if (!load_cfg_f)
++        load_cfg_f = grub_util_fopen (load_cfg, "wb");
++      have_load_cfg = 1;
++      fprintf (load_cfg_f, "set btrfs_relative_path='y'\n");
++    }
++
+   char *prefix_drive = NULL;
+   char *install_drive = NULL;
+ 
+diff --git a/util/grub-mkrelpath.c b/util/grub-mkrelpath.c
+index 47a241a391..5db7a9a7d9 100644
+--- a/util/grub-mkrelpath.c
++++ b/util/grub-mkrelpath.c
+@@ -40,9 +40,12 @@ struct arguments
+ };
+ 
+ static struct argp_option options[] = {
++  {"relative",  'r', 0, 0, "use relative path on btrfs", 0},
+   { 0, 0, 0, 0, 0, 0 }
+ };
+ 
++extern int use_relative_path_on_btrfs;
++
+ static error_t
+ argp_parser (int key, char *arg, struct argp_state *state)
+ {
+@@ -52,6 +55,9 @@ argp_parser (int key, char *arg, struct argp_state *state)
+ 
+   switch (key)
+     {
++    case 'r':
++      use_relative_path_on_btrfs = 1;
++      break;
+     case ARGP_KEY_ARG:
+       if (state->arg_num == 0)
+ 	arguments->pathname = xstrdup (arg);
+diff --git a/include/grub/emu/config.h b/include/grub/emu/config.h
+index 875d5896ce..c9a7e5f4ad 100644
+--- a/include/grub/emu/config.h
++++ b/include/grub/emu/config.h
+@@ -37,6 +37,7 @@ struct grub_util_config
+ {
+   int is_cryptodisk_enabled;
+   char *grub_distributor;
++  int is_suse_btrfs_snapshot_enabled;
+ };
+ 
+ void
diff --git a/SOURCES/0045-Try-prefix-if-fw_path-doesn-t-work.patch b/SOURCES/0045-Try-prefix-if-fw_path-doesn-t-work.patch
deleted file mode 100644
index 59489bd..0000000
--- a/SOURCES/0045-Try-prefix-if-fw_path-doesn-t-work.patch
+++ /dev/null
@@ -1,222 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 9 Jul 2019 10:35:16 +0200
-Subject: [PATCH] Try $prefix if $fw_path doesn't work.
-
-Related: rhbz#1148652
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/kern/ieee1275/init.c |  28 +++++----
- grub-core/net/net.c            |   2 +-
- grub-core/normal/main.c        | 134 ++++++++++++++++++++---------------------
- 3 files changed, 82 insertions(+), 82 deletions(-)
-
-diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
-index e71d1584164..0cd2a627231 100644
---- a/grub-core/kern/ieee1275/init.c
-+++ b/grub-core/kern/ieee1275/init.c
-@@ -127,23 +127,25 @@ grub_machine_get_bootlocation (char **device, char **path)
-       grub_free (canon);
-     }
-   else
--    *device = grub_ieee1275_encode_devname (bootpath);
--  grub_free (type);
--
--  filename = grub_ieee1275_get_filename (bootpath);
--  if (filename)
-     {
--      char *lastslash = grub_strrchr (filename, '\\');
--
--      /* Truncate at last directory.  */
--      if (lastslash)
-+      filename = grub_ieee1275_get_filename (bootpath);
-+      if (filename)
-         {
--	  *lastslash = '\0';
--	  grub_translate_ieee1275_path (filename);
-+          char *lastslash = grub_strrchr (filename, '\\');
- 
--	  *path = filename;
--	}
-+          /* Truncate at last directory.  */
-+          if (lastslash)
-+            {
-+              *lastslash = '\0';
-+              grub_translate_ieee1275_path (filename);
-+
-+              *path = filename;
-+            }
-+        }
-+      *device = grub_ieee1275_encode_devname (bootpath);
-     }
-+
-+  grub_free (type);
-   grub_free (bootpath);
- }
- 
-diff --git a/grub-core/net/net.c b/grub-core/net/net.c
-index 4d3eb5c1a52..0ef148f4adc 100644
---- a/grub-core/net/net.c
-+++ b/grub-core/net/net.c
-@@ -1869,7 +1869,7 @@ grub_net_search_config_file (char *config)
-   /* Remove the remaining minus sign at the end. */
-   config[config_len] = '\0';
- 
--  return GRUB_ERR_NONE;
-+  return GRUB_ERR_FILE_NOT_FOUND;
- }
- 
- static struct grub_preboot *fini_hnd;
-diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
-index 1e509fceb91..d5968797f4f 100644
---- a/grub-core/normal/main.c
-+++ b/grub-core/normal/main.c
-@@ -337,81 +337,79 @@ grub_enter_normal_mode (const char *config)
-   grub_boot_time ("Exiting normal mode");
- }
- 
-+static grub_err_t
-+grub_try_normal (const char *variable)
-+{
-+    char *config;
-+    const char *prefix;
-+    grub_err_t err = GRUB_ERR_FILE_NOT_FOUND;
-+    const char *net_search_cfg;
-+    int disable_net_search = 0;
-+
-+    prefix = grub_env_get (variable);
-+    if (!prefix)
-+      return GRUB_ERR_FILE_NOT_FOUND;
-+
-+    net_search_cfg = grub_env_get ("feature_net_search_cfg");
-+    if (net_search_cfg && net_search_cfg[0] == 'n')
-+      disable_net_search = 1;
-+
-+    if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0 &&
-+        !disable_net_search)
-+      {
-+       grub_size_t config_len;
-+       config_len = grub_strlen (prefix) +
-+         sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
-+       config = grub_malloc (config_len);
-+
-+       if (! config)
-+         return GRUB_ERR_FILE_NOT_FOUND;
-+
-+       grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
-+       err = grub_net_search_config_file (config);
-+      }
-+
-+    if (err != GRUB_ERR_NONE)
-+      {
-+       config = grub_xasprintf ("%s/grub.cfg", prefix);
-+       if (config)
-+         {
-+           grub_file_t file;
-+           file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG);
-+           if (file)
-+             {
-+               grub_file_close (file);
-+               err = GRUB_ERR_NONE;
-+             }
-+         }
-+      }
-+
-+    if (err == GRUB_ERR_NONE)
-+      grub_enter_normal_mode (config);
-+
-+    grub_errno = 0;
-+    grub_free (config);
-+    return err;
-+}
-+
- /* Enter normal mode from rescue mode.  */
- static grub_err_t
- grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
- 		 int argc, char *argv[])
- {
--  if (argc == 0)
--    {
--      /* Guess the config filename. It is necessary to make CONFIG static,
--	 so that it won't get broken by longjmp.  */
--      char *config;
--      const char *prefix;
--      const char *net_search_cfg;
--      int disable_net_search = 0;
--
--      prefix = grub_env_get ("fw_path");
--      if (! prefix)
--	      prefix = grub_env_get ("prefix");
--
--      net_search_cfg = grub_env_get ("feature_net_search_cfg");
--      if (net_search_cfg && net_search_cfg[0] == 'n')
--	      disable_net_search = 1;
--
--      if (prefix)
--        {
--          if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0 &&
--              !disable_net_search)
--            {
--              grub_size_t config_len;
--              config_len = grub_strlen (prefix) +
--                sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
--              config = grub_malloc (config_len);
--
--              if (! config)
--                goto quit;
--
--              grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
--
--              grub_net_search_configfile (config);
--
--              grub_enter_normal_mode (config);
--              grub_free (config);
--              config = NULL;
--            }
--
--          if (!config)
--            {
--              config = grub_xasprintf ("%s/grub.cfg", prefix);
--              if (config)
--                {
--                  grub_file_t file;
--
--                  file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG);
--                  if (file)
--                    {
--                      grub_file_close (file);
--                      grub_enter_normal_mode (config);
--                    }
--                  else
--                    {
--                      /*  Ignore all errors.  */
--                      grub_errno = 0;
--                    }
--                  grub_free (config);
--                }
--            }
--        }
--      else
--        {
--          grub_enter_normal_mode (0);
--        }
--    }
--  else
-+  if (argc)
-     grub_enter_normal_mode (argv[0]);
-+  else
-+    {
-+      /* Guess the config filename. */
-+      grub_err_t err;
-+      err = grub_try_normal ("fw_path");
-+      if (err == GRUB_ERR_FILE_NOT_FOUND)
-+        err = grub_try_normal ("prefix");
-+      if (err == GRUB_ERR_FILE_NOT_FOUND)
-+        grub_enter_normal_mode (0);
-+    }
- 
--quit:
-   return 0;
- }
- 
diff --git a/SOURCES/0045-grub2-btrfs-05-grub2-mkconfig.patch b/SOURCES/0045-grub2-btrfs-05-grub2-mkconfig.patch
new file mode 100644
index 0000000..ca3f86b
--- /dev/null
+++ b/SOURCES/0045-grub2-btrfs-05-grub2-mkconfig.patch
@@ -0,0 +1,129 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 21 Aug 2014 03:39:11 +0000
+Subject: [PATCH] grub2-btrfs-05-grub2-mkconfig
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+---
+ util/grub-mkconfig.in       |  3 ++-
+ util/grub-mkconfig_lib.in   |  4 ++++
+ util/grub.d/00_header.in    | 25 ++++++++++++++++++++++++-
+ util/grub.d/10_linux.in     |  4 ++++
+ util/grub.d/20_linux_xen.in |  4 ++++
+ 5 files changed, 38 insertions(+), 2 deletions(-)
+
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index 005f093809..535c0f0249 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -252,7 +252,8 @@ export GRUB_DEFAULT \
+   GRUB_BADRAM \
+   GRUB_OS_PROBER_SKIP_LIST \
+   GRUB_DISABLE_SUBMENU \
+-  GRUB_DEFAULT_DTB
++  GRUB_DEFAULT_DTB \
++  SUSE_BTRFS_SNAPSHOT_BOOTING
+ 
+ if test "x${grub_cfg}" != "x"; then
+   rm -f "${grub_cfg}.new"
+diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
+index 0f6505bf3b..5e96f6cc5d 100644
+--- a/util/grub-mkconfig_lib.in
++++ b/util/grub-mkconfig_lib.in
+@@ -49,7 +49,11 @@ grub_warn ()
+ 
+ make_system_path_relative_to_its_root ()
+ {
++  if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] ; then
++  "${grub_mkrelpath}" -r "$1"
++  else
+   "${grub_mkrelpath}" "$1"
++  fi
+ }
+ 
+ is_path_readable_by_grub ()
+diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
+index 858b526c92..de727e6ee6 100644
+--- a/util/grub.d/00_header.in
++++ b/util/grub.d/00_header.in
+@@ -27,6 +27,14 @@ export TEXTDOMAINDIR="@localedir@"
+ 
+ . "$pkgdatadir/grub-mkconfig_lib"
+ 
++if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] &&
++   [ "x${GRUB_FS}" = "xbtrfs" ] ; then
++    cat <<EOF
++set btrfs_relative_path="y"
++export btrfs_relative_path
++EOF
++fi
++
+ # Do this as early as possible, since other commands might depend on it.
+ # (e.g. the `loadfont' command might need lvm or raid modules)
+ for i in ${GRUB_PRELOAD_MODULES} ; do
+@@ -45,7 +53,9 @@ if [ "x${GRUB_TIMEOUT_BUTTON}" = "x" ] ; then GRUB_TIMEOUT_BUTTON="$GRUB_TIMEOUT
+ cat << EOF
+ set pager=1
+ 
+-if [ -s \$prefix/grubenv ]; then
++if [ -f \${config_directory}/grubenv ]; then
++  load_env -f \${config_directory}/grubenv
++elif [ -s \$prefix/grubenv ]; then
+   load_env
+ fi
+ EOF
+@@ -356,3 +366,16 @@ fi
+ if [ "x${GRUB_BADRAM}" != "x" ] ; then
+   echo "badram ${GRUB_BADRAM}"
+ fi
++
++if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] &&
++   [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ] &&
++   [ "x${GRUB_FS}" = "xbtrfs" ] ; then
++    # Note: No $snapshot_num on *read-only* rollback!  (bsc#901487)
++    cat <<EOF
++if [ -n "\$extra_cmdline" ]; then
++  submenu "Bootable snapshot #\$snapshot_num" {
++    menuentry "If OK, run 'snapper rollback' and reboot." { true; }
++  }
++fi
++EOF
++fi
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 292e333324..7bb3a211a7 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -66,10 +66,14 @@ fi
+ 
+ case x"$GRUB_FS" in
+     xbtrfs)
++	if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ]; then
++	GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX} \${extra_cmdline}"
++	else
+ 	rootsubvol="`make_system_path_relative_to_its_root /`"
+ 	rootsubvol="${rootsubvol#/}"
+ 	if [ "x${rootsubvol}" != x ]; then
+ 	    GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}"
++	fi
+ 	fi;;
+     xzfs)
+ 	rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true`
+diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in
+index ada20775a1..e9e73b815f 100644
+--- a/util/grub.d/20_linux_xen.in
++++ b/util/grub.d/20_linux_xen.in
+@@ -73,10 +73,14 @@ fi
+ 
+ case x"$GRUB_FS" in
+     xbtrfs)
++	if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ]; then
++	GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX} \${extra_cmdline}"
++	else
+ 	rootsubvol="`make_system_path_relative_to_its_root /`"
+ 	rootsubvol="${rootsubvol#/}"
+ 	if [ "x${rootsubvol}" != x ]; then
+ 	    GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}"
++	fi
+ 	fi;;
+     xzfs)
+ 	rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true`
diff --git a/SOURCES/0046-Use-Distribution-Package-Sort-for-grub2-mkconfig-112.patch b/SOURCES/0046-Use-Distribution-Package-Sort-for-grub2-mkconfig-112.patch
deleted file mode 100644
index 78a6fa1..0000000
--- a/SOURCES/0046-Use-Distribution-Package-Sort-for-grub2-mkconfig-112.patch
+++ /dev/null
@@ -1,458 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Robert Marshall <rmarshall@redhat.com>
-Date: Mon, 16 Mar 2015 14:14:19 -0400
-Subject: [PATCH] Use Distribution Package Sort for grub2-mkconfig (#1124074)
-
-Users reported that newly installed kernels on their systems installed
-with grub-mkconfig would not appear on the grub boot list in order
-starting with the most recent. Added an option for rpm-based systems to
-use the rpm-sort library to sort kernels instead.
-
-Resolves rhbz#1124074
-
-Signed-off-by: Robert Marshall <rmarshall@redhat.com>
-[pjones: fix --enable-rpm-sort configure option]
-Signed-off-by: Peter Jones <pjones@redhat.com>
-[thierry.vignaud: fix build with rpm-4.16]
-Signed-off-by: Thierry Vignaud <thierry.vignaud@gmail.com>
----
- configure.ac              |  38 +++++++
- Makefile.util.def         |  16 +++
- util/grub-rpm-sort.c      | 281 ++++++++++++++++++++++++++++++++++++++++++++++
- util/grub-mkconfig_lib.in |  11 +-
- util/grub-rpm-sort.8      |  12 ++
- 5 files changed, 357 insertions(+), 1 deletion(-)
- create mode 100644 util/grub-rpm-sort.c
- create mode 100644 util/grub-rpm-sort.8
-
-diff --git a/configure.ac b/configure.ac
-index bec8535af70..fdcb452581c 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -72,6 +72,7 @@ grub_TRANSFORM([grub-mkrelpath])
- grub_TRANSFORM([grub-mkrescue])
- grub_TRANSFORM([grub-probe])
- grub_TRANSFORM([grub-reboot])
-+grub_TRANSFORM([grub-rpm-sort])
- grub_TRANSFORM([grub-script-check])
- grub_TRANSFORM([grub-set-default])
- grub_TRANSFORM([grub-sparc64-setup])
-@@ -95,6 +96,7 @@ grub_TRANSFORM([grub-mkrescue.1])
- grub_TRANSFORM([grub-mkstandalone.3])
- grub_TRANSFORM([grub-ofpathname.3])
- grub_TRANSFORM([grub-probe.3])
-+grub_TRANSFORM([grub-rpm-sort.8])
- grub_TRANSFORM([grub-reboot.3])
- grub_TRANSFORM([grub-render-label.3])
- grub_TRANSFORM([grub-script-check.3])
-@@ -1860,6 +1862,42 @@ fi
- 
- AC_SUBST([LIBDEVMAPPER])
- 
-+AC_ARG_ENABLE([rpm-sort],
-+              [AS_HELP_STRING([--enable-rpm-sort],
-+                              [enable native rpm sorting of kernels in grub (default=guessed)])])
-+if test x"$enable_rpm_sort" = xno ; then
-+  rpm_sort_excuse="explicitly disabled"
-+fi
-+
-+if test x"$rpm_sort_excuse" = x ; then
-+  # Check for rpmlib header.
-+  AC_CHECK_HEADER([rpm/rpmlib.h], [],
-+               [rpm_sort_excuse="need rpm/rpmlib header"])
-+fi
-+
-+if test x"$rpm_sort_excuse" = x ; then
-+  # Check for rpm library.
-+  AC_CHECK_LIB([rpm], [rpmvercmp], [],
-+               [rpm_sort_excuse="rpmlib missing rpmvercmp"])
-+fi
-+
-+if test x"$rpm_sort_excuse" = x ; then
-+   LIBRPM="-lrpm";
-+   AC_DEFINE([HAVE_RPM], [1],
-+             [Define to 1 if you have the rpm library.])
-+fi
-+
-+if test x"$LIBRPM" = x ; then
-+  # Check for rpm library.
-+  AC_CHECK_LIB([rpmio], [rpmvercmp], [],
-+               [rpm_sort_excuse="rpmio missing rpmvercmp"])
-+   LIBRPM="-lrpmio";
-+   AC_DEFINE([HAVE_RPMIO], [1],
-+             [Define to 1 if you have the rpm library.])
-+fi
-+
-+AC_SUBST([LIBRPM])
-+
- LIBGEOM=
- if test x$host_kernel = xkfreebsd; then
-   AC_CHECK_LIB([geom], [geom_gettree], [],
-diff --git a/Makefile.util.def b/Makefile.util.def
-index 2c9b283a230..ba4cf4b29b0 100644
---- a/Makefile.util.def
-+++ b/Makefile.util.def
-@@ -703,6 +703,22 @@ program = {
-   ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
- };
- 
-+program = {
-+  name = grub-rpm-sort;
-+  mansection = 8;
-+  installdir = sbin;
-+
-+  common = grub-core/kern/emu/misc.c;
-+  common = grub-core/kern/emu/argp_common.c;
-+  common = grub-core/osdep/init.c;
-+  common = util/misc.c;
-+  common = util/grub-rpm-sort.c;
-+
-+  ldadd = libgrubkern.a;
-+  ldadd = grub-core/lib/gnulib/libgnu.a;
-+  ldadd = '$(LIBDEVMAPPER) $(LIBRPM)';
-+};
-+
- script = {
-   name = grub-mkconfig;
-   common = util/grub-mkconfig.in;
-diff --git a/util/grub-rpm-sort.c b/util/grub-rpm-sort.c
-new file mode 100644
-index 00000000000..f33bd1ed568
---- /dev/null
-+++ b/util/grub-rpm-sort.c
-@@ -0,0 +1,281 @@
-+#include <config.h>
-+#include <grub/types.h>
-+#include <grub/util/misc.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <unistd.h>
-+#include <errno.h>
-+#include <assert.h>
-+#include <argp.h>
-+#include <rpm/rpmlib.h>
-+
-+static size_t
-+read_file (const char *input, char **ret)
-+{
-+  FILE *in;
-+  size_t s;
-+  size_t sz = 2048;
-+  size_t offset = 0;
-+  char *text;
-+
-+  if (!strcmp(input, "-"))
-+    in = stdin;
-+  else
-+    in = grub_util_fopen(input, "r");
-+
-+  text = xmalloc (sz);
-+
-+  if (!in)
-+    grub_util_error (_("cannot open `%s': %s"), input, strerror (errno));
-+
-+  while ((s = fread (text + offset, 1, sz - offset, in)) != 0)
-+    {
-+      offset += s;
-+      if (sz - offset == 0)
-+	{
-+	  sz += 2048;
-+	  text = xrealloc (text, sz);
-+	}
-+    }
-+
-+  text[offset] = '\0';
-+  *ret = text;
-+
-+  if (in != stdin)
-+    fclose(in);
-+
-+  return offset + 1;
-+}
-+
-+/* returns name/version/release */
-+/* NULL string pointer returned if nothing found */
-+static void
-+split_package_string (char *package_string, char **name,
-+                     char **version, char **release)
-+{
-+  char *package_version, *package_release;
-+
-+  /* Release */
-+  package_release = strrchr (package_string, '-');
-+
-+  if (package_release != NULL)
-+      *package_release++ = '\0';
-+
-+  *release = package_release;
-+
-+  /* Version */
-+  package_version = strrchr(package_string, '-');
-+
-+  if (package_version != NULL)
-+      *package_version++ = '\0';
-+
-+  *version = package_version;
-+  /* Name */
-+  *name = package_string;
-+
-+  /* Bubble up non-null values from release to name */
-+  if (*name == NULL)
-+    {
-+      *name = (*version == NULL ? *release : *version);
-+      *version = *release;
-+      *release = NULL;
-+    }
-+  if (*version == NULL)
-+    {
-+      *version = *release;
-+      *release = NULL;
-+    }
-+}
-+
-+/*
-+ * package name-version-release comparator for qsort
-+ * expects p, q which are pointers to character strings (char *)
-+ * which will not be altered in this function
-+ */
-+static int
-+package_version_compare (const void *p, const void *q)
-+{
-+  char *local_p, *local_q;
-+  char *lhs_name, *lhs_version, *lhs_release;
-+  char *rhs_name, *rhs_version, *rhs_release;
-+  int vercmpflag = 0;
-+
-+  local_p = alloca (strlen (*(char * const *)p) + 1);
-+  local_q = alloca (strlen (*(char * const *)q) + 1);
-+
-+  /* make sure these allocated */
-+  assert (local_p);
-+  assert (local_q);
-+
-+  strcpy (local_p, *(char * const *)p);
-+  strcpy (local_q, *(char * const *)q);
-+
-+  split_package_string (local_p, &lhs_name, &lhs_version, &lhs_release);
-+  split_package_string (local_q, &rhs_name, &rhs_version, &rhs_release);
-+
-+  /* Check Name and return if unequal */
-+  vercmpflag = rpmvercmp ((lhs_name == NULL ? "" : lhs_name),
-+                          (rhs_name == NULL ? "" : rhs_name));
-+  if (vercmpflag != 0)
-+    return vercmpflag;
-+
-+  /* Check version and return if unequal */
-+  vercmpflag = rpmvercmp ((lhs_version == NULL ? "" : lhs_version),
-+                          (rhs_version == NULL ? "" : rhs_version));
-+  if (vercmpflag != 0)
-+    return vercmpflag;
-+
-+  /* Check release and return the version compare value */
-+  vercmpflag = rpmvercmp ((lhs_release == NULL ? "" : lhs_release),
-+                          (rhs_release == NULL ? "" : rhs_release));
-+
-+  return vercmpflag;
-+}
-+
-+static void
-+add_input (const char *filename, char ***package_names, size_t *n_package_names)
-+{
-+  char *orig_input_buffer = NULL;
-+  char *input_buffer;
-+  char *position_of_newline;
-+  char **names = *package_names;
-+  char **new_names = NULL;
-+  size_t n_names = *n_package_names;
-+
-+  if (!*package_names)
-+    new_names = names = xmalloc (sizeof (char *) * 2);
-+
-+  if (read_file (filename, &orig_input_buffer) < 2)
-+    {
-+      if (new_names)
-+	free (new_names);
-+      if (orig_input_buffer)
-+	free (orig_input_buffer);
-+      return;
-+    }
-+
-+  input_buffer = orig_input_buffer;
-+  while (input_buffer && *input_buffer &&
-+	 (position_of_newline = strchrnul (input_buffer, '\n')))
-+    {
-+      size_t sz = position_of_newline - input_buffer;
-+      char *new;
-+
-+      if (sz == 0)
-+	{
-+	  input_buffer = position_of_newline + 1;
-+	  continue;
-+	}
-+
-+      new = xmalloc (sz+1);
-+      strncpy (new, input_buffer, sz);
-+      new[sz] = '\0';
-+
-+      names = xrealloc (names, sizeof (char *) * (n_names + 1));
-+      names[n_names] = new;
-+      n_names++;
-+
-+      /* move buffer ahead to next line */
-+      input_buffer = position_of_newline + 1;
-+      if (*position_of_newline == '\0')
-+	input_buffer = NULL;
-+    }
-+
-+  free (orig_input_buffer);
-+
-+  *package_names = names;
-+  *n_package_names = n_names;
-+}
-+
-+static char *
-+help_filter (int key, const char *text, void *input __attribute__ ((unused)))
-+{
-+  return (char *)text;
-+}
-+
-+static struct argp_option options[] = {
-+  { 0, }
-+};
-+
-+struct arguments
-+{
-+  size_t ninputs;
-+  size_t input_max;
-+  char **inputs;
-+};
-+
-+static error_t
-+argp_parser (int key, char *arg, struct argp_state *state)
-+{
-+  struct arguments *arguments = state->input;
-+  switch (key)
-+    {
-+    case ARGP_KEY_ARG:
-+      assert (arguments->ninputs < arguments->input_max);
-+      arguments->inputs[arguments->ninputs++] = xstrdup (arg);
-+      break;
-+    default:
-+      return ARGP_ERR_UNKNOWN;
-+    }
-+  return 0;
-+}
-+
-+static struct argp argp = {
-+  options, argp_parser, N_("[INPUT_FILES]"),
-+  N_("Sort a list of strings in RPM version sort order."),
-+  NULL, help_filter, NULL
-+};
-+
-+int
-+main (int argc, char *argv[])
-+{
-+  struct arguments arguments;
-+  char **package_names = NULL;
-+  size_t n_package_names = 0;
-+  int i;
-+
-+  grub_util_host_init (&argc, &argv);
-+
-+  memset (&arguments, 0, sizeof (struct arguments));
-+  arguments.input_max = argc+1;
-+  arguments.inputs = xmalloc ((arguments.input_max + 1)
-+			      * sizeof (arguments.inputs[0]));
-+  memset (arguments.inputs, 0, (arguments.input_max + 1)
-+	  * sizeof (arguments.inputs[0]));
-+
-+  /* Parse our arguments */
-+  if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0)
-+    grub_util_error ("%s", _("Error in parsing command line arguments\n"));
-+
-+  /* If there's no inputs in argv, add one for stdin */
-+  if (!arguments.ninputs)
-+    {
-+      arguments.ninputs = 1;
-+      arguments.inputs[0] = xmalloc (2);
-+      strcpy(arguments.inputs[0], "-");
-+    }
-+
-+  for (i = 0; i < arguments.ninputs; i++)
-+    add_input(arguments.inputs[i], &package_names, &n_package_names);
-+
-+  if (package_names == NULL || n_package_names < 1)
-+    grub_util_error ("%s", _("Invalid input\n"));
-+
-+  qsort (package_names, n_package_names, sizeof (char *),
-+	 package_version_compare);
-+
-+  /* send sorted list to stdout */
-+  for (i = 0; i < n_package_names; i++)
-+    {
-+      fprintf (stdout, "%s\n", package_names[i]);
-+      free (package_names[i]);
-+    }
-+
-+  free (package_names);
-+  for (i = 0; i < arguments.ninputs; i++)
-+    free (arguments.inputs[i]);
-+
-+  free (arguments.inputs);
-+
-+  return 0;
-+}
-diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
-index 0f6505bf3b6..42c2ea9ba50 100644
---- a/util/grub-mkconfig_lib.in
-+++ b/util/grub-mkconfig_lib.in
-@@ -33,6 +33,9 @@ fi
- if test "x$grub_mkrelpath" = x; then
-   grub_mkrelpath="${bindir}/@grub_mkrelpath@"
- fi
-+if test "x$grub_rpm_sort" = x; then
-+  grub_rpm_sort="${sbindir}/@grub_rpm_sort@"
-+fi
- 
- if command -v gettext >/dev/null; then
-   :
-@@ -218,6 +221,12 @@ version_sort ()
-    esac
- }
- 
-+if [ "x$grub_rpm_sort" != x -a -x "$grub_rpm_sort" ]; then
-+  kernel_sort="$grub_rpm_sort"
-+else
-+  kernel_sort=version_sort
-+fi
-+
- version_test_numeric ()
- {
-   version_test_numeric_a="$1"
-@@ -234,7 +243,7 @@ version_test_numeric ()
-     version_test_numeric_a="$version_test_numeric_b"
-     version_test_numeric_b="$version_test_numeric_c"
-   fi
--  if (echo "$version_test_numeric_a" ; echo "$version_test_numeric_b") | version_sort | head -n 1 | grep -qx "$version_test_numeric_b" ; then
-+  if (echo "$version_test_numeric_a" ; echo "$version_test_numeric_b") | "$kernel_sort" | head -n 1 | grep -qx "$version_test_numeric_b" ; then
-     return 0
-   else
-     return 1
-diff --git a/util/grub-rpm-sort.8 b/util/grub-rpm-sort.8
-new file mode 100644
-index 00000000000..8ce21488448
---- /dev/null
-+++ b/util/grub-rpm-sort.8
-@@ -0,0 +1,12 @@
-+.TH GRUB-RPM-SORT 8 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-rpm-sort\fR \(em Sort input according to RPM version compare.
-+
-+.SH SYNOPSIS
-+\fBgrub-rpm-sort\fR [OPTIONS].
-+
-+.SH DESCRIPTION
-+You should not normally run this program directly.  Use grub-mkconfig instead.
-+
-+.SH SEE ALSO
-+.BR "info grub"
diff --git a/SOURCES/0046-grub2-btrfs-06-subvol-mount.patch b/SOURCES/0046-grub2-btrfs-06-subvol-mount.patch
new file mode 100644
index 0000000..8cdf247
--- /dev/null
+++ b/SOURCES/0046-grub2-btrfs-06-subvol-mount.patch
@@ -0,0 +1,539 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Tue, 9 Jul 2019 13:56:16 +0200
+Subject: [PATCH] grub2-btrfs-06-subvol-mount
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/fs/btrfs.c            | 195 +++++++++++++++++++++++++++++++++++++++-
+ grub-core/osdep/linux/getroot.c | 148 +++++++++++++++++++++++++++++-
+ util/grub-install.c             |  49 ++++++++++
+ include/grub/emu/getroot.h      |   5 ++
+ 4 files changed, 392 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index 113c1f746c..d323746ecf 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -41,6 +41,7 @@
+ #include <grub/command.h>
+ #include <grub/env.h>
+ #include <grub/extcmd.h>
++#include <grub/list.h>
+ #include <grub/crypto.h>
+ #include <grub/diskfilter.h>
+ #include <grub/safemath.h>
+@@ -266,6 +267,12 @@ static grub_err_t
+ grub_btrfs_read_logical (struct grub_btrfs_data *data,
+ 			 grub_disk_addr_t addr, void *buf, grub_size_t size,
+ 			 int recursion_depth);
++static grub_err_t
++get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key,
++	  grub_uint64_t *tree, grub_uint8_t *type);
++
++grub_uint64_t
++find_mtab_subvol_tree (const char *path, char **path_in_subvol);
+ 
+ static grub_err_t
+ read_sblock (grub_disk_t disk, struct grub_btrfs_superblock *sb)
+@@ -1223,9 +1230,26 @@ lookup_root_by_name(struct grub_btrfs_data *data, const char *path)
+   grub_err_t err;
+   grub_uint64_t tree = 0;
+   grub_uint8_t type;
++  grub_uint64_t saved_tree;
+   struct grub_btrfs_key key;
+ 
++  if (path[0] == '\0')
++    {
++      data->fs_tree = 0;
++      return GRUB_ERR_NONE;
++    }
++
++  err = get_root (data, &key, &tree, &type);
++  if (err)
++    return err;
++
++  saved_tree = data->fs_tree;
++  data->fs_tree = tree;
++
+   err = find_path (data, path, &key, &tree, &type);
++
++  data->fs_tree = saved_tree;
++
+   if (err)
+       return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path);
+ 
+@@ -2199,11 +2223,20 @@ grub_btrfs_dir (grub_device_t device, const char *path,
+   int r = 0;
+   grub_uint64_t tree;
+   grub_uint8_t type;
++  char *new_path = NULL;
+ 
+   if (!data)
+     return grub_errno;
+ 
+-  err = find_path (data, path, &key_in, &tree, &type);
++  tree = find_mtab_subvol_tree (path, &new_path);
++
++  if (tree)
++    data->fs_tree = tree;
++
++  err = find_path (data, new_path ? new_path : path, &key_in, &tree, &type);
++  if (new_path)
++    grub_free (new_path);
++
+   if (err)
+     {
+       grub_btrfs_unmount (data);
+@@ -2305,11 +2338,21 @@ grub_btrfs_open (struct grub_file *file, const char *name)
+   struct grub_btrfs_inode inode;
+   grub_uint8_t type;
+   struct grub_btrfs_key key_in;
++  grub_uint64_t tree;
++  char *new_path = NULL;
+ 
+   if (!data)
+     return grub_errno;
+ 
+-  err = find_path (data, name, &key_in, &data->tree, &type);
++  tree = find_mtab_subvol_tree (name, &new_path);
++
++  if (tree)
++    data->fs_tree = tree;
++
++  err = find_path (data, new_path ? new_path : name, &key_in, &data->tree, &type);
++  if (new_path)
++    grub_free (new_path);
++
+   if (err)
+     {
+       grub_btrfs_unmount (data);
+@@ -2480,6 +2523,150 @@ grub_cmd_btrfs_info (grub_command_t cmd __attribute__ ((unused)), int argc,
+   return 0;
+ }
+ 
++struct grub_btrfs_mtab
++{
++  struct grub_btrfs_mtab *next;
++  struct grub_btrfs_mtab **prev;
++  char *path;
++  char *subvol;
++  grub_uint64_t tree;
++};
++
++typedef struct grub_btrfs_mtab* grub_btrfs_mtab_t;
++
++static struct grub_btrfs_mtab *btrfs_mtab;
++
++#define FOR_GRUB_MTAB(var) FOR_LIST_ELEMENTS (var, btrfs_mtab)
++#define FOR_GRUB_MTAB_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE((var), (next), btrfs_mtab)
++
++static void
++add_mountpoint (const char *path, const char *subvol, grub_uint64_t tree)
++{
++  grub_btrfs_mtab_t m = grub_malloc (sizeof (*m));
++
++  m->path = grub_strdup (path);
++  m->subvol = grub_strdup (subvol);
++  m->tree = tree;
++  grub_list_push (GRUB_AS_LIST_P (&btrfs_mtab), GRUB_AS_LIST (m));
++}
++
++static grub_err_t
++grub_cmd_btrfs_mount_subvol (grub_command_t cmd __attribute__ ((unused)), int argc,
++		     char **argv)
++{
++  char *devname, *dirname, *subvol;
++  struct grub_btrfs_key key_in;
++  grub_uint8_t type;
++  grub_uint64_t tree;
++  grub_uint64_t saved_tree;
++  grub_err_t err;
++  struct grub_btrfs_data *data = NULL;
++  grub_device_t dev = NULL;
++
++  if (argc < 3)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, "required <dev> <dir> and <subvol>");
++
++  devname = grub_file_get_device_name(argv[0]);
++  dev = grub_device_open (devname);
++  grub_free (devname);
++
++  if (!dev)
++    {
++      err = grub_errno;
++      goto err_out;
++    }
++
++  dirname = argv[1];
++  subvol = argv[2];
++
++  data = grub_btrfs_mount (dev);
++  if (!data)
++    {
++      err = grub_errno;
++      goto err_out;
++    }
++
++  err = find_path (data, dirname, &key_in, &tree, &type);
++  if (err)
++    goto err_out;
++
++  if (type !=  GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY)
++    {
++      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
++      goto err_out;
++    }
++
++  err = get_root (data, &key_in, &tree, &type);
++
++  if (err)
++    goto err_out;
++
++  saved_tree = data->fs_tree;
++  data->fs_tree = tree;
++  err = find_path (data, subvol, &key_in, &tree, &type);
++  data->fs_tree = saved_tree;
++
++  if (err)
++    goto err_out;
++
++  if (key_in.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0)
++    {
++      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", subvol);
++      goto err_out;
++    }
++
++  grub_btrfs_unmount (data);
++  grub_device_close (dev);
++  add_mountpoint (dirname, subvol, tree);
++
++  return GRUB_ERR_NONE;
++
++err_out:
++
++  if (data)
++    grub_btrfs_unmount (data);
++
++  if (dev)
++    grub_device_close (dev);
++
++  return err;
++}
++
++grub_uint64_t
++find_mtab_subvol_tree (const char *path, char **path_in_subvol)
++{
++  grub_btrfs_mtab_t m, cm;
++  grub_uint64_t tree;
++
++  if (!path || !path_in_subvol)
++    return 0;
++
++  *path_in_subvol = NULL;
++  tree = 0;
++  cm = NULL;
++
++  FOR_GRUB_MTAB (m)
++    {
++      if (grub_strncmp (path, m->path, grub_strlen (m->path)) == 0)
++	{
++	  if (!cm)
++	    cm = m;
++	  else
++	    if (grub_strcmp (m->path, cm->path) > 0)
++	      cm = m;
++	}
++    }
++
++  if (cm)
++    {
++      const char *s = path + grub_strlen (cm->path);
++      *path_in_subvol = (s[0] == '\0') ? grub_strdup ("/") : grub_strdup (s);
++      tree = cm->tree;
++    }
++
++  return tree;
++}
++
+ static grub_err_t
+ get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree,
+             grub_uint64_t objectid, grub_uint64_t offset,
+@@ -2686,6 +2873,7 @@ static struct grub_fs grub_btrfs_fs = {
+ };
+ 
+ static grub_command_t cmd_info;
++static grub_command_t cmd_mount_subvol;
+ static grub_extcmd_t cmd_list_subvols;
+ 
+ static char *
+@@ -2749,6 +2937,9 @@ GRUB_MOD_INIT (btrfs)
+   cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info,
+ 				   "DEVICE",
+ 				   "Print BtrFS info about DEVICE.");
++  cmd_mount_subvol = grub_register_command("btrfs-mount-subvol", grub_cmd_btrfs_mount_subvol,
++				   "DEVICE DIRECTORY SUBVOL",
++				   "Set btrfs DEVICE the DIRECTORY a mountpoint of SUBVOL.");
+   cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols",
+ 					 grub_cmd_btrfs_list_subvols, 0,
+ 					 "[-p|-n] [-o var] DEVICE",
+diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
+index caf9b1ccd3..28790307e0 100644
+--- a/grub-core/osdep/linux/getroot.c
++++ b/grub-core/osdep/linux/getroot.c
+@@ -107,6 +107,14 @@ struct btrfs_ioctl_search_key
+   grub_uint32_t unused[9];
+ };
+ 
++struct btrfs_ioctl_search_header {
++  grub_uint64_t transid;
++  grub_uint64_t objectid;
++  grub_uint64_t offset;
++  grub_uint32_t type;
++  grub_uint32_t len;
++};
++
+ struct btrfs_ioctl_search_args {
+   struct btrfs_ioctl_search_key key;
+   grub_uint64_t buf[(4096 - sizeof(struct btrfs_ioctl_search_key))
+@@ -378,6 +386,109 @@ get_btrfs_fs_prefix (const char *mount_path)
+ 
+ int use_relative_path_on_btrfs = 0;
+ 
++static char *
++get_btrfs_subvol (const char *path)
++{
++  struct btrfs_ioctl_ino_lookup_args args;
++  grub_uint64_t tree_id;
++  int fd = -1;
++  char *ret = NULL;
++
++  fd = open (path, O_RDONLY);
++
++  if (fd < 0)
++    return NULL;
++
++  memset (&args, 0, sizeof(args));
++  args.objectid = GRUB_BTRFS_TREE_ROOT_OBJECTID;
++
++  if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
++    goto error;
++
++  tree_id = args.treeid;
++
++  while (tree_id != GRUB_BTRFS_ROOT_VOL_OBJECTID)
++    {
++      struct btrfs_ioctl_search_args sargs;
++      struct grub_btrfs_root_backref *br;
++      struct btrfs_ioctl_search_header *search_header;
++      char *old;
++      grub_uint16_t len;
++      grub_uint64_t inode_id;
++
++      memset (&sargs, 0, sizeof(sargs));
++
++      sargs.key.tree_id = 1;
++      sargs.key.min_objectid = tree_id;
++      sargs.key.max_objectid = tree_id;
++
++      sargs.key.min_offset = 0;
++      sargs.key.max_offset = ~0ULL;
++      sargs.key.min_transid = 0;
++      sargs.key.max_transid = ~0ULL;
++      sargs.key.min_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF;
++      sargs.key.max_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF;
++
++      sargs.key.nr_items = 1;
++
++      if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0)
++	goto error;
++
++      if (sargs.key.nr_items == 0)
++	goto error;
++
++      search_header = (struct btrfs_ioctl_search_header *)sargs.buf;
++      br = (struct grub_btrfs_root_backref *) (search_header + 1);
++
++      len = grub_le_to_cpu16 (br->n);
++      inode_id = grub_le_to_cpu64 (br->inode_id);
++      tree_id = search_header->offset;
++
++      old = ret;
++      ret = malloc (len + 1);
++      memcpy (ret, br->name, len);
++      ret[len] = '\0';
++
++      if (inode_id != GRUB_BTRFS_TREE_ROOT_OBJECTID)
++	{
++	  char *s;
++
++	  memset(&args, 0, sizeof(args));
++	  args.treeid = search_header->offset;
++	  args.objectid = inode_id;
++
++	  if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
++	    goto error;
++
++	  s = xasprintf ("%s%s", args.name, ret);
++	  free (ret);
++	  ret = s;
++	}
++
++      if (old)
++	{
++	  char *s = xasprintf ("%s/%s", ret, old);
++	  free (ret);
++	  free (old);
++	  ret = s;
++	}
++    }
++
++  close (fd);
++  return ret;
++
++error:
++
++  if (fd >= 0)
++    close (fd);
++  if (ret)
++    free (ret);
++
++  return NULL;
++}
++
++void (*grub_find_root_btrfs_mount_path_hook)(const char *mount_path);
++
+ char **
+ grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
+ {
+@@ -519,12 +630,15 @@ again:
+       else if (grub_strcmp (entries[i].fstype, "btrfs") == 0)
+ 	{
+ 	  ret = grub_find_root_devices_from_btrfs (dir);
+-	  fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
+ 	  if (use_relative_path_on_btrfs)
+ 	    {
+-	      if (fs_prefix)
+-	        free (fs_prefix);
+ 	      fs_prefix = xstrdup ("/");
++	      if (grub_find_root_btrfs_mount_path_hook)
++		grub_find_root_btrfs_mount_path_hook (entries[i].enc_path);
++	    }
++	  else
++	    {
++	      fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
+ 	    }
+ 	}
+       else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0)
+@@ -1150,6 +1264,34 @@ grub_util_get_grub_dev_os (const char *os_dev)
+   return grub_dev;
+ }
+ 
++
++char *
++grub_util_get_btrfs_subvol (const char *path, char **mount_path)
++{
++  char *mp = NULL;
++
++  if (mount_path)
++    *mount_path = NULL;
++
++  auto void
++  mount_path_hook (const char *m)
++  {
++    mp = strdup (m);
++  }
++
++  grub_find_root_btrfs_mount_path_hook = mount_path_hook;
++  grub_free (grub_find_root_devices_from_mountinfo (path, NULL));
++  grub_find_root_btrfs_mount_path_hook = NULL;
++
++  if (!mp)
++    return NULL;
++
++  if (mount_path)
++    *mount_path = mp;
++
++  return get_btrfs_subvol (mp);
++}
++
+ char *
+ grub_make_system_path_relative_to_its_root_os (const char *path)
+ {
+diff --git a/util/grub-install.c b/util/grub-install.c
+index 0f66f36d23..84ed6e88ec 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -1569,6 +1569,55 @@ main (int argc, char *argv[])
+       prefix_drive = xasprintf ("(%s)", grub_drives[0]);
+     }
+ 
++#ifdef __linux__
++
++  if (config.is_suse_btrfs_snapshot_enabled
++      && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0)
++    {
++      char *subvol = NULL;
++      char *mount_path = NULL;
++      char **rootdir_devices = NULL;
++      char *rootdir_path = grub_util_path_concat (2, "/", rootdir);
++
++      if (grub_util_is_directory (rootdir_path))
++	rootdir_devices = grub_guess_root_devices (rootdir_path);
++
++      free (rootdir_path);
++
++      if (rootdir_devices && rootdir_devices[0])
++	if (grub_strcmp (rootdir_devices[0], grub_devices[0]) == 0)
++	  subvol = grub_util_get_btrfs_subvol (platdir, &mount_path);
++
++      if (subvol && mount_path)
++	{
++	  char *def_subvol;
++
++	  def_subvol = grub_util_get_btrfs_subvol ("/", NULL);
++
++	  if (def_subvol)
++	    {
++	      if (!load_cfg_f)
++		load_cfg_f = grub_util_fopen (load_cfg, "wb");
++	      have_load_cfg = 1;
++
++	      if (grub_strcmp (subvol, def_subvol) != 0)
++		fprintf (load_cfg_f, "btrfs-mount-subvol ($root) %s %s\n", mount_path, subvol);
++	      free (def_subvol);
++	    }
++	}
++
++      for (curdev = rootdir_devices; *curdev; curdev++)
++	free (*curdev);
++      if (rootdir_devices)
++	free (rootdir_devices);
++      if (subvol)
++	free (subvol);
++      if (mount_path)
++	free (mount_path);
++    }
++
++#endif
++
+   char mkimage_target[200];
+   const char *core_name = NULL;
+ 
+diff --git a/include/grub/emu/getroot.h b/include/grub/emu/getroot.h
+index 73fa2d34ab..9c642ae3fe 100644
+--- a/include/grub/emu/getroot.h
++++ b/include/grub/emu/getroot.h
+@@ -53,6 +53,11 @@ char **
+ grub_find_root_devices_from_mountinfo (const char *dir, char **relroot);
+ #endif
+ 
++#ifdef __linux__
++char *
++grub_util_get_btrfs_subvol (const char *path, char **mount_path);
++#endif
++
+ /* Devmapper functions provided by getroot_devmapper.c.  */
+ void
+ grub_util_pull_devmapper (const char *os_dev);
diff --git a/SOURCES/0047-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch b/SOURCES/0047-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch
new file mode 100644
index 0000000..a5db09a
--- /dev/null
+++ b/SOURCES/0047-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch
@@ -0,0 +1,58 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Andrei Borzenkov <arvidjaar@gmail.com>
+Date: Tue, 21 Jun 2016 16:44:17 +0000
+Subject: [PATCH] Fallback to old subvol name scheme to support old snapshot
+ config
+
+Ref: bsc#953538
+---
+ grub-core/fs/btrfs.c | 32 +++++++++++++++++++++++++++++++-
+ 1 file changed, 31 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index d323746ecf..673ded0352 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -1260,11 +1260,41 @@ lookup_root_by_name(struct grub_btrfs_data *data, const char *path)
+   return GRUB_ERR_NONE;
+ }
+ 
++static grub_err_t
++lookup_root_by_name_fallback(struct grub_btrfs_data *data, const char *path)
++{
++  grub_err_t err;
++  grub_uint64_t tree = 0;
++  grub_uint8_t type;
++  struct grub_btrfs_key key;
++
++  err = find_path (data, path, &key, &tree, &type);
++  if (err)
++      return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path);
++
++  if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0)
++    return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path);
++
++  data->fs_tree = tree;
++  return GRUB_ERR_NONE;
++}
++
+ static grub_err_t
+ btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__ ((unused)))
+ {
+   if (btrfs_default_subvol)
+-    return lookup_root_by_name(data, btrfs_default_subvol);
++    {
++      grub_err_t err;
++      err = lookup_root_by_name(data, btrfs_default_subvol);
++
++      /* Fallback to old schemes */
++      if (err == GRUB_ERR_FILE_NOT_FOUND)
++	{
++	  err = GRUB_ERR_NONE;
++	  return lookup_root_by_name_fallback(data, btrfs_default_subvol);
++	}
++      return err;
++    }
+ 
+   if (btrfs_default_subvolid)
+     return lookup_root_by_id(data, btrfs_default_subvolid);
diff --git a/SOURCES/0047-Make-grub2-mkconfig-construct-titles-that-look-like-.patch b/SOURCES/0047-Make-grub2-mkconfig-construct-titles-that-look-like-.patch
deleted file mode 100644
index 4c474e4..0000000
--- a/SOURCES/0047-Make-grub2-mkconfig-construct-titles-that-look-like-.patch
+++ /dev/null
@@ -1,69 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 28 Apr 2015 11:15:03 -0400
-Subject: [PATCH] Make grub2-mkconfig construct titles that look like the ones
- we want elsewhere.
-
-Resolves: rhbz#1215839
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- util/grub.d/10_linux.in | 34 +++++++++++++++++++++++++++-------
- 1 file changed, 27 insertions(+), 7 deletions(-)
-
-diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
-index fed73271478..2e59f3b4197 100644
---- a/util/grub.d/10_linux.in
-+++ b/util/grub.d/10_linux.in
-@@ -78,6 +78,32 @@ case x"$GRUB_FS" in
- 	;;
- esac
- 
-+mktitle ()
-+{
-+  local title_type
-+  local version
-+  local OS_NAME
-+  local OS_VERS
-+
-+  title_type=$1 && shift
-+  version=$1 && shift
-+
-+  OS_NAME="$(eval $(grep ^NAME= /etc/os-release) ; echo ${NAME})"
-+  OS_VERS="$(eval $(grep ^VERSION= /etc/os-release) ; echo ${VERSION})"
-+
-+  case $title_type in
-+    recovery)
-+      title=$(printf '%s (%s) %s (recovery mode)' \
-+                     "${OS_NAME}" "${version}" "${OS_VERS}")
-+      ;;
-+    *)
-+      title=$(printf '%s (%s) %s' \
-+                     "${OS_NAME}" "${version}" "${OS_VERS}")
-+      ;;
-+  esac
-+  echo -n ${title}
-+}
-+
- title_correction_code=
- 
- linux_entry ()
-@@ -91,17 +117,11 @@ linux_entry ()
-       boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
-   fi
-   if [ x$type != xsimple ] ; then
--      case $type in
--	  recovery)
--	      title="$(gettext_printf "%s, with Linux %s (recovery mode)" "${os}" "${version}")" ;;
--	  *)
--	      title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;;
--      esac
-+      title=$(mktitle "$type" "$version")
-       if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then
- 	  replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')"
- 	  quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)"
- 	  title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;"
--	  grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")"
-       fi
-       echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
-   else
diff --git a/SOURCES/0048-Add-friendly-grub2-password-config-tool-985962.patch b/SOURCES/0048-Add-friendly-grub2-password-config-tool-985962.patch
deleted file mode 100644
index 9807d0e..0000000
--- a/SOURCES/0048-Add-friendly-grub2-password-config-tool-985962.patch
+++ /dev/null
@@ -1,269 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Robert Marshall <rmarshall@redhat.com>
-Date: Thu, 25 Jun 2015 11:13:11 -0400
-Subject: [PATCH] Add friendly grub2 password config tool (#985962)
-
-Provided a tool for users to reset the grub2 root user password
-without having to alter the grub.cfg. The hashed password now
-lives in a root-only-readable configuration file.
-
-Resolves: rhbz#985962
-
-Signed-off-by: Robert Marshall <rmarshall@redhat.com>
-[pjones: fix the efidir in grub-setpassword and rename tool]
-Signed-off-by: Peter Jones <pjones@redhat.com>
-[luto: fix grub-setpassword -o's output path]
-Andy Lutomirski <luto@kernel.org>
----
- configure.ac              |   1 +
- Makefile.util.def         |  13 +++++
- util/grub-mkconfig.in     |   2 +
- util/grub-set-password.8  |  28 ++++++++++
- util/grub-set-password.in | 128 ++++++++++++++++++++++++++++++++++++++++++++++
- util/grub.d/01_users.in   |  11 ++++
- 6 files changed, 183 insertions(+)
- create mode 100644 util/grub-set-password.8
- create mode 100644 util/grub-set-password.in
- create mode 100644 util/grub.d/01_users.in
-
-diff --git a/configure.ac b/configure.ac
-index fdcb452581c..30fd84d8067 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -72,6 +72,7 @@ grub_TRANSFORM([grub-mkrelpath])
- grub_TRANSFORM([grub-mkrescue])
- grub_TRANSFORM([grub-probe])
- grub_TRANSFORM([grub-reboot])
-+grub_TRANSFORM([grub-set-password])
- grub_TRANSFORM([grub-rpm-sort])
- grub_TRANSFORM([grub-script-check])
- grub_TRANSFORM([grub-set-default])
-diff --git a/Makefile.util.def b/Makefile.util.def
-index ba4cf4b29b0..1a7dd433e33 100644
---- a/Makefile.util.def
-+++ b/Makefile.util.def
-@@ -452,6 +452,12 @@ script = {
-   installdir = grubconf;
- };
- 
-+script = {
-+  name = '01_users';
-+  common = util/grub.d/01_users.in;
-+  installdir = grubconf;
-+};
-+
- script = {
-   name = '10_windows';
-   common = util/grub.d/10_windows.in;
-@@ -740,6 +746,13 @@ script = {
-   installdir = sbin;
- };
- 
-+script = {
-+  name = grub-set-password;
-+  common = util/grub-set-password.in;
-+  mansection = 8;
-+  installdir = sbin;
-+};
-+
- script = {
-   name = grub-mkconfig_lib;
-   common = util/grub-mkconfig_lib.in;
-diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
-index 8ea2315ebc2..ba14cf6261c 100644
---- a/util/grub-mkconfig.in
-+++ b/util/grub-mkconfig.in
-@@ -276,6 +276,8 @@ for i in "${grub_mkconfig_dir}"/* ; do
-     *~) ;;
-     # emacsen autosave files. FIXME: support other editors
-     */\#*\#) ;;
-+    # rpm config files of yore.
-+    *.rpmsave|*.rpmnew|*.rpmorig) ;;
-     *)
-       if grub_file_is_not_garbage "$i" && test -x "$i" ; then
-         echo
-diff --git a/util/grub-set-password.8 b/util/grub-set-password.8
-new file mode 100644
-index 00000000000..9646546e43d
---- /dev/null
-+++ b/util/grub-set-password.8
-@@ -0,0 +1,28 @@
-+.TH GRUB-SET-PASSWORD 3 "Thu Jun 25 2015"
-+.SH NAME
-+\fBgrub-set-password\fR \(em Generate the user.cfg file containing the hashed grub bootloader password.
-+
-+.SH SYNOPSIS
-+\fBgrub-set-password\fR [OPTION]
-+
-+.SH DESCRIPTION
-+\fBgrub-set-password\fR outputs the user.cfg file which contains the hashed GRUB bootloader password. This utility only supports configurations where there is a single root user.
-+
-+The file has the format:
-+GRUB2_PASSWORD=<\fIhashed password\fR>.
-+
-+.SH OPTIONS
-+.TP
-+-h, --help
-+Display program usage and exit.
-+.TP
-+-v, --version
-+Display the current version.
-+.TP
-+-o, --output=<\fIDIRECTORY\fR>
-+Choose the file path to which user.cfg will be written.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-+
-+.BR "info grub2-mkpasswd-pbkdf2"
-diff --git a/util/grub-set-password.in b/util/grub-set-password.in
-new file mode 100644
-index 00000000000..5ebf50576d6
---- /dev/null
-+++ b/util/grub-set-password.in
-@@ -0,0 +1,128 @@
-+#!/bin/sh -e
-+
-+EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/')
-+if [ -d /sys/firmware/efi/efivars/ ]; then
-+    grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'`
-+else
-+    grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`
-+fi
-+
-+PACKAGE_VERSION="@PACKAGE_VERSION@"
-+PACKAGE_NAME="@PACKAGE_NAME@"
-+self=`basename $0`
-+bindir="@bindir@"
-+grub_mkpasswd="${bindir}/@grub_mkpasswd_pbkdf2@"
-+
-+# Usage: usage
-+# Print the usage.
-+usage () {
-+    cat <<EOF
-+Usage: $0 [OPTION]
-+$0 prompts the user to set a password on the grub bootloader. The password
-+is written to a file named user.cfg which lives in the GRUB directory
-+located by default at ${grubdir}.
-+
-+  -h, --help                     print this message and exit
-+  -v, --version                  print the version information and exit
-+  -o, --output_path <DIRECTORY>  put user.cfg in a user-selected directory
-+
-+Report bugs at https://bugzilla.redhat.com.
-+EOF
-+}
-+
-+argument () {
-+    opt=$1
-+    shift
-+
-+    if test $# -eq 0; then
-+        gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$opt" 1>&2
-+        exit 1
-+    fi
-+    echo $1
-+}
-+
-+# Ensure that it's the root user running this script
-+if [ "${EUID}" -ne 0 ]; then
-+    echo "The grub bootloader password may only be set by root."
-+    usage
-+    exit 2
-+fi
-+
-+# Check the arguments.
-+while test $# -gt 0
-+do
-+    option=$1
-+    shift
-+
-+    case "$option" in
-+    -h | --help)
-+	usage
-+	exit 0 ;;
-+    -v | --version)
-+	echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}"
-+	exit 0 ;;
-+    -o | --output)
-+        OUTPUT_PATH=`argument $option "$@"`; shift ;;
-+    --output=*)
-+        OUTPUT_PATH=`echo "$option" | sed 's/--output=//'` ;;
-+    -o=*)
-+        OUTPUT_PATH=`echo "$option" | sed 's/-o=//'` ;;
-+    esac
-+done
-+
-+# set user input or default path for user.cfg file
-+if [ -z "${OUTPUT_PATH}" ]; then
-+    OUTPUT_PATH="${grubdir}"
-+fi
-+
-+if [ ! -d "${OUTPUT_PATH}" ]; then
-+    echo "${OUTPUT_PATH} does not exist."
-+    usage
-+    exit 2;
-+fi
-+
-+ttyopt=$(stty -g)
-+fixtty() {
-+      stty ${ttyopt}
-+}
-+
-+trap fixtty EXIT
-+stty -echo
-+
-+# prompt & confirm new grub2 root user password
-+echo -n "Enter password: "
-+read PASSWORD
-+echo
-+echo -n "Confirm password: "
-+read PASSWORD_CONFIRM
-+echo
-+stty ${ttyopt}
-+
-+getpass() {
-+    local P0
-+    local P1
-+    P0="$1" && shift
-+    P1="$1" && shift
-+
-+    ( echo ${P0} ; echo ${P1} ) | \
-+        LC_ALL=C ${grub_mkpasswd} | \
-+        grep -v '[eE]nter password:' | \
-+        sed -e "s/PBKDF2 hash of your password is //"
-+}
-+
-+MYPASS="$(getpass "${PASSWORD}" "${PASSWORD_CONFIRM}")"
-+if [ -z "${MYPASS}" ]; then
-+      echo "${self}: error: empty password" 1>&2
-+      exit 1
-+fi
-+
-+# on the ESP, these will fail to set the permissions, but it's okay because
-+# the directory is protected.
-+install -m 0600 /dev/null "${OUTPUT_PATH}/user.cfg" 2>/dev/null || :
-+chmod 0600 "${OUTPUT_PATH}/user.cfg" 2>/dev/null || :
-+echo "GRUB2_PASSWORD=${MYPASS}" > "${OUTPUT_PATH}/user.cfg"
-+
-+if ! grep -q "^### BEGIN /etc/grub.d/01_users ###$" "${OUTPUT_PATH}/grub.cfg"; then
-+    echo "WARNING: The current configuration lacks password support!"
-+    echo "Update your configuration with @grub_mkconfig@ to support this feature."
-+fi
-diff --git a/util/grub.d/01_users.in b/util/grub.d/01_users.in
-new file mode 100644
-index 00000000000..db2f44bfb78
---- /dev/null
-+++ b/util/grub.d/01_users.in
-@@ -0,0 +1,11 @@
-+#!/bin/sh -e
-+cat << EOF
-+if [ -f \${prefix}/user.cfg ]; then
-+  source \${prefix}/user.cfg
-+  if [ -n "\${GRUB2_PASSWORD}" ]; then
-+    set superusers="root"
-+    export superusers
-+    password_pbkdf2 root \${GRUB2_PASSWORD}
-+  fi
-+fi
-+EOF
diff --git a/SOURCES/0048-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch b/SOURCES/0048-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch
new file mode 100644
index 0000000..99c106d
--- /dev/null
+++ b/SOURCES/0048-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch
@@ -0,0 +1,274 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 11 May 2017 08:56:57 +0000
+Subject: [PATCH] Grub not working correctly with btrfs snapshots (bsc#1026511)
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/fs/btrfs.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 238 insertions(+)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index 673ded0352..2b21cbaa67 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -2887,6 +2887,238 @@ out:
+   return 0;
+ }
+ 
++static grub_err_t
++grub_btrfs_get_parent_subvol_path (struct grub_btrfs_data *data,
++		grub_uint64_t child_id,
++		const char *child_path,
++		grub_uint64_t *parent_id,
++		char **path_out)
++{
++  grub_uint64_t fs_root = 0;
++  struct grub_btrfs_key key_in = {
++    .object_id = child_id,
++    .type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF,
++    .offset = 0,
++  }, key_out;
++  struct grub_btrfs_root_ref *ref;
++  char *buf;
++  struct grub_btrfs_leaf_descriptor desc;
++  grub_size_t elemsize;
++  grub_disk_addr_t elemaddr;
++  grub_err_t err;
++  char *parent_path;
++
++  *parent_id = 0;
++  *path_out = 0;
++
++  err = lower_bound(data, &key_in, &key_out, data->sblock.root_tree,
++                    &elemaddr, &elemsize, &desc, 0);
++  if (err)
++    return err;
++
++  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF || elemaddr == 0)
++    next(data, &desc, &elemaddr, &elemsize, &key_out);
++
++  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF)
++    {
++      free_iterator(&desc);
++      return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root backrefs"));
++    }
++
++  buf = grub_malloc(elemsize + 1);
++  if (!buf)
++    {
++      free_iterator(&desc);
++      return grub_errno;
++    }
++
++  err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0);
++  if (err)
++    {
++      grub_free(buf);
++      free_iterator(&desc);
++      return err;
++    }
++
++  buf[elemsize] = 0;
++  ref = (struct grub_btrfs_root_ref *)buf;
++
++  err = get_fs_root(data, data->sblock.root_tree, grub_le_to_cpu64 (key_out.offset),
++                    0, &fs_root);
++  if (err)
++    {
++      grub_free(buf);
++      free_iterator(&desc);
++      return err;
++    }
++
++  find_pathname(data, grub_le_to_cpu64 (ref->dirid), fs_root, ref->name, &parent_path);
++
++  if (child_path)
++    {
++      *path_out = grub_xasprintf ("%s/%s", parent_path, child_path);
++      grub_free (parent_path);
++    }
++  else
++    *path_out = parent_path;
++
++  *parent_id = grub_le_to_cpu64 (key_out.offset);
++
++  grub_free(buf);
++  free_iterator(&desc);
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_btrfs_get_default_subvolume_id (struct grub_btrfs_data *data, grub_uint64_t *id)
++{
++  grub_err_t err;
++  grub_disk_addr_t elemaddr;
++  grub_size_t elemsize;
++  struct grub_btrfs_key key, key_out;
++  struct grub_btrfs_dir_item *direl = NULL;
++  const char *ctoken = "default";
++  grub_size_t ctokenlen = sizeof ("default") - 1;
++
++  *id = 0;
++  key.object_id = data->sblock.root_dir_objectid;
++  key.type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
++  key.offset = grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken, ctokenlen));
++  err = lower_bound (data, &key, &key_out, data->sblock.root_tree, &elemaddr, &elemsize,
++			 NULL, 0);
++  if (err)
++    return err;
++
++  if (key_cmp (&key, &key_out) != 0)
++    return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found"));
++
++  struct grub_btrfs_dir_item *cdirel;
++  direl = grub_malloc (elemsize + 1);
++  err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize, 0);
++  if (err)
++    {
++      grub_free (direl);
++      return err;
++    }
++  for (cdirel = direl;
++       (grub_uint8_t *) cdirel - (grub_uint8_t *) direl
++       < (grub_ssize_t) elemsize;
++       cdirel = (void *) ((grub_uint8_t *) (direl + 1)
++       + grub_le_to_cpu16 (cdirel->n)
++       + grub_le_to_cpu16 (cdirel->m)))
++    {
++      if (ctokenlen == grub_le_to_cpu16 (cdirel->n)
++        && grub_memcmp (cdirel->name, ctoken, ctokenlen) == 0)
++      break;
++    }
++  if ((grub_uint8_t *) cdirel - (grub_uint8_t *) direl
++      >= (grub_ssize_t) elemsize)
++    {
++      grub_free (direl);
++      err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found"));
++      return err;
++    }
++
++  if (cdirel->key.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM)
++    {
++      grub_free (direl);
++      err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found"));
++      return err;
++    }
++
++  *id = grub_le_to_cpu64 (cdirel->key.object_id);
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_cmd_btrfs_get_default_subvol (struct grub_extcmd_context *ctxt,
++			     int argc, char **argv)
++{
++  char *devname;
++  grub_device_t dev;
++  struct grub_btrfs_data *data;
++  grub_err_t err;
++  grub_uint64_t id;
++  char *subvol = NULL;
++  grub_uint64_t subvolid = 0;
++  char *varname = NULL;
++  char *output = NULL;
++  int path_only = ctxt->state[1].set;
++  int num_only = ctxt->state[2].set;
++
++  if (ctxt->state[0].set)
++    varname = ctxt->state[0].arg;
++
++  if (argc < 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
++
++  devname = grub_file_get_device_name(argv[0]);
++  if (!devname)
++    return grub_errno;
++
++  dev = grub_device_open (devname);
++  grub_free (devname);
++  if (!dev)
++    return grub_errno;
++
++  data = grub_btrfs_mount(dev);
++  if (!data)
++    {
++      grub_device_close (dev);
++      grub_dprintf ("btrfs", "failed to open fs\n");
++      grub_errno = GRUB_ERR_NONE;
++      return 0;
++    }
++
++  err = grub_btrfs_get_default_subvolume_id (data, &subvolid);
++  if (err)
++    {
++      grub_btrfs_unmount (data);
++      grub_device_close (dev);
++      return err;
++    }
++
++  id = subvolid;
++  while (id != GRUB_BTRFS_ROOT_VOL_OBJECTID)
++    {
++      grub_uint64_t parent_id;
++      char *path_out;
++
++      err = grub_btrfs_get_parent_subvol_path (data, grub_cpu_to_le64 (id), subvol, &parent_id, &path_out);
++      if (err)
++	{
++	  grub_btrfs_unmount (data);
++	  grub_device_close (dev);
++	  return err;
++	}
++
++      if (subvol)
++        grub_free (subvol);
++      subvol = path_out;
++      id = parent_id;
++    }
++
++  if (num_only && path_only)
++      output = grub_xasprintf ("%"PRIuGRUB_UINT64_T" /%s", subvolid, subvol);
++  else if (num_only)
++      output = grub_xasprintf ("%"PRIuGRUB_UINT64_T, subvolid);
++  else
++      output = grub_xasprintf ("/%s", subvol);
++
++  if (varname)
++    grub_env_set(varname, output);
++  else
++    grub_printf ("%s\n", output);
++
++  grub_free (output);
++  grub_free (subvol);
++
++  grub_btrfs_unmount (data);
++  grub_device_close (dev);
++
++  return GRUB_ERR_NONE;
++}
++
+ static struct grub_fs grub_btrfs_fs = {
+   .name = "btrfs",
+   .fs_dir = grub_btrfs_dir,
+@@ -2905,6 +3137,7 @@ static struct grub_fs grub_btrfs_fs = {
+ static grub_command_t cmd_info;
+ static grub_command_t cmd_mount_subvol;
+ static grub_extcmd_t cmd_list_subvols;
++static grub_extcmd_t cmd_get_default_subvol;
+ 
+ static char *
+ subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)),
+@@ -2975,6 +3208,11 @@ GRUB_MOD_INIT (btrfs)
+ 					 "[-p|-n] [-o var] DEVICE",
+ 					 "Print list of BtrFS subvolumes on "
+ 					 "DEVICE.", options);
++  cmd_get_default_subvol = grub_register_extcmd("btrfs-get-default-subvol",
++					 grub_cmd_btrfs_get_default_subvol, 0,
++					 "[-p|-n] [-o var] DEVICE",
++					 "Print default BtrFS subvolume on "
++					 "DEVICE.", options);
+   grub_register_variable_hook ("btrfs_subvol", subvol_get_env,
+                                subvol_set_env);
+   grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env,
diff --git a/SOURCES/0049-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch b/SOURCES/0049-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch
new file mode 100644
index 0000000..d07dd27
--- /dev/null
+++ b/SOURCES/0049-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch
@@ -0,0 +1,72 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 1 Jun 2017 09:59:56 -0400
+Subject: [PATCH] Add grub_efi_allocate_pool() and grub_efi_free_pool()
+ wrappers.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ include/grub/efi/efi.h | 36 ++++++++++++++++++++++++++++++++----
+ 1 file changed, 32 insertions(+), 4 deletions(-)
+
+diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
+index 585fa6662b..03f9a9d011 100644
+--- a/include/grub/efi/efi.h
++++ b/include/grub/efi/efi.h
+@@ -24,6 +24,10 @@
+ #include <grub/dl.h>
+ #include <grub/efi/api.h>
+ 
++/* Variables.  */
++extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table);
++extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle);
++
+ /* Functions.  */
+ void *EXPORT_FUNC(grub_efi_locate_protocol) (grub_efi_guid_t *protocol,
+ 					     void *registration);
+@@ -60,6 +64,33 @@ EXPORT_FUNC(grub_efi_get_memory_map) (grub_efi_uintn_t *memory_map_size,
+ 				      grub_efi_uintn_t *descriptor_size,
+ 				      grub_efi_uint32_t *descriptor_version);
+ void grub_efi_memory_fini (void);
++
++static inline grub_efi_status_t
++__attribute__((__unused__))
++grub_efi_allocate_pool (grub_efi_memory_type_t pool_type,
++			grub_efi_uintn_t buffer_size,
++			void **buffer)
++{
++  grub_efi_boot_services_t *b;
++  grub_efi_status_t status;
++
++  b = grub_efi_system_table->boot_services;
++  status = efi_call_3 (b->allocate_pool, pool_type, buffer_size, buffer);
++  return status;
++}
++
++static inline grub_efi_status_t
++__attribute__((__unused__))
++grub_efi_free_pool (void *buffer)
++{
++  grub_efi_boot_services_t *b;
++  grub_efi_status_t status;
++
++  b = grub_efi_system_table->boot_services;
++  status = efi_call_1 (b->free_pool, buffer);
++  return status;
++}
++
+ grub_efi_loaded_image_t *EXPORT_FUNC(grub_efi_get_loaded_image) (grub_efi_handle_t image_handle);
+ void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp);
+ char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp);
+@@ -115,10 +146,7 @@ void grub_efi_init (void);
+ void grub_efi_fini (void);
+ void grub_efi_set_prefix (void);
+ 
+-/* Variables.  */
+-extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table);
+-extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle);
+-
++/* More variables.  */
+ extern int EXPORT_VAR(grub_efi_is_finished);
+ 
+ struct grub_net_card;
diff --git a/SOURCES/0049-tcp-add-window-scaling-support.patch b/SOURCES/0049-tcp-add-window-scaling-support.patch
deleted file mode 100644
index 7d1996c..0000000
--- a/SOURCES/0049-tcp-add-window-scaling-support.patch
+++ /dev/null
@@ -1,87 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Josef Bacik <jbacik@fb.com>
-Date: Wed, 12 Aug 2015 08:57:55 -0700
-Subject: [PATCH] tcp: add window scaling support
-
-Sometimes we have to provision boxes across regions, such as California to
-Sweden.  The http server has a 10 minute timeout, so if we can't get our 250mb
-image transferred fast enough our provisioning fails, which is not ideal.  So
-add tcp window scaling on open connections and set the window size to 1mb.  With
-this change we're able to get higher sustained transfers between regions and can
-transfer our image in well below 10 minutes.  Without this patch we'd time out
-every time halfway through the transfer.  Thanks,
-
-Signed-off-by: Josef Bacik <jbacik@fb.com>
----
- grub-core/net/tcp.c | 42 +++++++++++++++++++++++++++++-------------
- 1 file changed, 29 insertions(+), 13 deletions(-)
-
-diff --git a/grub-core/net/tcp.c b/grub-core/net/tcp.c
-index e8ad34b84d4..7d4b822626d 100644
---- a/grub-core/net/tcp.c
-+++ b/grub-core/net/tcp.c
-@@ -106,6 +106,18 @@ struct tcphdr
-   grub_uint16_t urgent;
- } GRUB_PACKED;
- 
-+struct tcp_scale_opt {
-+  grub_uint8_t kind;
-+  grub_uint8_t length;
-+  grub_uint8_t scale;
-+} GRUB_PACKED;
-+
-+struct tcp_synhdr {
-+  struct tcphdr tcphdr;
-+  struct tcp_scale_opt scale_opt;
-+  grub_uint8_t padding;
-+};
-+
- struct tcp_pseudohdr
- {
-   grub_uint32_t src;
-@@ -566,7 +578,7 @@ grub_net_tcp_open (char *server,
-   grub_net_tcp_socket_t socket;
-   static grub_uint16_t in_port = 21550;
-   struct grub_net_buff *nb;
--  struct tcphdr *tcph;
-+  struct tcp_synhdr *tcph;
-   int i;
-   grub_uint8_t *nbd;
-   grub_net_link_level_address_t ll_target_addr;
-@@ -635,20 +647,24 @@ grub_net_tcp_open (char *server,
-     }
- 
-   tcph = (void *) nb->data;
-+  grub_memset(tcph, 0, sizeof (*tcph));
-   socket->my_start_seq = grub_get_time_ms ();
-   socket->my_cur_seq = socket->my_start_seq + 1;
--  socket->my_window = 8192;
--  tcph->seqnr = grub_cpu_to_be32 (socket->my_start_seq);
--  tcph->ack = grub_cpu_to_be32_compile_time (0);
--  tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_SYN);
--  tcph->window = grub_cpu_to_be16 (socket->my_window);
--  tcph->urgent = 0;
--  tcph->src = grub_cpu_to_be16 (socket->in_port);
--  tcph->dst = grub_cpu_to_be16 (socket->out_port);
--  tcph->checksum = 0;
--  tcph->checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP,
--						   &socket->inf->address,
--						   &socket->out_nla);
-+  socket->my_window = 32768;
-+  tcph->tcphdr.seqnr = grub_cpu_to_be32 (socket->my_start_seq);
-+  tcph->tcphdr.ack = grub_cpu_to_be32_compile_time (0);
-+  tcph->tcphdr.flags = grub_cpu_to_be16_compile_time ((6 << 12) | TCP_SYN);
-+  tcph->tcphdr.window = grub_cpu_to_be16 (socket->my_window);
-+  tcph->tcphdr.urgent = 0;
-+  tcph->tcphdr.src = grub_cpu_to_be16 (socket->in_port);
-+  tcph->tcphdr.dst = grub_cpu_to_be16 (socket->out_port);
-+  tcph->tcphdr.checksum = 0;
-+  tcph->scale_opt.kind = 3;
-+  tcph->scale_opt.length = 3;
-+  tcph->scale_opt.scale = 5;
-+  tcph->tcphdr.checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP,
-+							  &socket->inf->address,
-+							  &socket->out_nla);
- 
-   tcp_socket_register (socket);
- 
diff --git a/SOURCES/0050-Use-grub_efi_.-memory-helpers-where-reasonable.patch b/SOURCES/0050-Use-grub_efi_.-memory-helpers-where-reasonable.patch
new file mode 100644
index 0000000..2a3d27b
--- /dev/null
+++ b/SOURCES/0050-Use-grub_efi_.-memory-helpers-where-reasonable.patch
@@ -0,0 +1,106 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 1 Jun 2017 10:06:38 -0400
+Subject: [PATCH] Use grub_efi_...() memory helpers where reasonable.
+
+This uses grub_efi_allocate_pool(), grub_efi_free_pool(), and
+grub_efi_free_pages() instead of open-coded efi_call_N() calls, so we
+get more reasonable type checking.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/efi/chainloader.c | 24 +++++++++---------------
+ 1 file changed, 9 insertions(+), 15 deletions(-)
+
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index 07c4937898..89ac84cc66 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -65,7 +65,7 @@ grub_chainloader_unload (void)
+ 
+   b = grub_efi_system_table->boot_services;
+   efi_call_1 (b->unload_image, image_handle);
+-  efi_call_2 (b->free_pages, address, pages);
++  grub_efi_free_pages (address, pages);
+ 
+   grub_free (file_path);
+   grub_free (cmdline);
+@@ -108,7 +108,7 @@ grub_chainloader_boot (void)
+     }
+ 
+   if (exit_data)
+-    efi_call_1 (b->free_pool, exit_data);
++    grub_efi_free_pool (exit_data);
+ 
+   grub_loader_unset ();
+ 
+@@ -527,10 +527,9 @@ grub_efi_get_media_file_path (grub_efi_device_path_t *dp)
+ static grub_efi_boolean_t
+ handle_image (void *data, grub_efi_uint32_t datasize)
+ {
+-  grub_efi_boot_services_t *b;
+   grub_efi_loaded_image_t *li, li_bak;
+   grub_efi_status_t efi_status;
+-  char *buffer = NULL;
++  void *buffer = NULL;
+   char *buffer_aligned = NULL;
+   grub_efi_uint32_t i;
+   struct grub_pe32_section_table *section;
+@@ -541,8 +540,6 @@ handle_image (void *data, grub_efi_uint32_t datasize)
+   int found_entry_point = 0;
+   int rc;
+ 
+-  b = grub_efi_system_table->boot_services;
+-
+   rc = read_header (data, datasize, &context);
+   if (rc < 0)
+     {
+@@ -582,8 +579,8 @@ handle_image (void *data, grub_efi_uint32_t datasize)
+   grub_dprintf ("chain", "image size is %08"PRIxGRUB_UINT64_T", datasize is %08x\n",
+ 	       context.image_size, datasize);
+ 
+-  efi_status = efi_call_3 (b->allocate_pool, GRUB_EFI_LOADER_DATA,
+-			   buffer_size, &buffer);
++  efi_status = grub_efi_allocate_pool (GRUB_EFI_LOADER_DATA, buffer_size,
++				       &buffer);
+ 
+   if (efi_status != GRUB_EFI_SUCCESS)
+     {
+@@ -815,14 +812,14 @@ handle_image (void *data, grub_efi_uint32_t datasize)
+ 
+   grub_dprintf ("chain", "entry_point returned %ld\n", efi_status);
+   grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t));
+-  efi_status = efi_call_1 (b->free_pool, buffer);
++  efi_status = grub_efi_free_pool (buffer);
+ 
+   return 1;
+ 
+ error_exit:
+   grub_dprintf ("chain", "error_exit: grub_errno: %d\n", grub_errno);
+   if (buffer)
+-      efi_call_1 (b->free_pool, buffer);
++    grub_efi_free_pool (buffer);
+ 
+   return 0;
+ }
+@@ -830,10 +827,7 @@ error_exit:
+ static grub_err_t
+ grub_secureboot_chainloader_unload (void)
+ {
+-  grub_efi_boot_services_t *b;
+-
+-  b = grub_efi_system_table->boot_services;
+-  efi_call_2 (b->free_pages, address, pages);
++  grub_efi_free_pages (address, pages);
+   grub_free (file_path);
+   grub_free (cmdline);
+   cmdline = 0;
+@@ -1100,7 +1094,7 @@ fail:
+   grub_free (file_path);
+ 
+   if (address)
+-    efi_call_2 (b->free_pages, address, pages);
++    grub_efi_free_pages (address, pages);
+ 
+   if (cmdline)
+     grub_free (cmdline);
diff --git a/SOURCES/0050-efinet-and-bootp-add-support-for-dhcpv6.patch b/SOURCES/0050-efinet-and-bootp-add-support-for-dhcpv6.patch
deleted file mode 100644
index a9844b8..0000000
--- a/SOURCES/0050-efinet-and-bootp-add-support-for-dhcpv6.patch
+++ /dev/null
@@ -1,651 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 9 Jul 2019 11:47:37 +0200
-Subject: [PATCH] efinet and bootp: add support for dhcpv6
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/net/bootp.c              | 173 +++++++++++++++++++++++++++++++++++++
- grub-core/net/drivers/efi/efinet.c |  53 ++++++++++--
- grub-core/net/net.c                |  72 +++++++++++++++
- grub-core/net/tftp.c               |   4 +
- include/grub/efi/api.h             | 129 +++++++++++++++++++++++++--
- include/grub/net.h                 |  60 +++++++++++++
- 6 files changed, 477 insertions(+), 14 deletions(-)
-
-diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
-index 6fb5627025d..e28fb6a09f9 100644
---- a/grub-core/net/bootp.c
-+++ b/grub-core/net/bootp.c
-@@ -902,6 +902,179 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
- 
- static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp;
- 
-+struct grub_net_network_level_interface *
-+grub_net_configure_by_dhcpv6_ack (const char *name,
-+				  struct grub_net_card *card,
-+				  grub_net_interface_flags_t flags
-+				    __attribute__((__unused__)),
-+				  const grub_net_link_level_address_t *hwaddr,
-+				  const struct grub_net_dhcpv6_packet *packet,
-+				  int is_def, char **device, char **path)
-+{
-+  struct grub_net_network_level_interface *inter = NULL;
-+  struct grub_net_network_level_address addr;
-+  int mask = -1;
-+
-+  if (!device || !path)
-+    return NULL;
-+
-+  *device = 0;
-+  *path = 0;
-+
-+  grub_dprintf ("net", "mac address is %02x:%02x:%02x:%02x:%02x:%02x\n",
-+		hwaddr->mac[0], hwaddr->mac[1], hwaddr->mac[2],
-+		hwaddr->mac[3], hwaddr->mac[4], hwaddr->mac[5]);
-+
-+  if (is_def)
-+    grub_net_default_server = 0;
-+
-+  if (is_def && !grub_net_default_server && packet)
-+    {
-+      const grub_uint8_t *options = packet->dhcp_options;
-+      unsigned int option_max = 1024 - OFFSET_OF (dhcp_options, packet);
-+      unsigned int i;
-+
-+      for (i = 0; i < option_max - sizeof (grub_net_dhcpv6_option_t); )
-+	{
-+	  grub_uint16_t num, len;
-+	  grub_net_dhcpv6_option_t *opt =
-+	    (grub_net_dhcpv6_option_t *)(options + i);
-+
-+	  num = grub_be_to_cpu16(opt->option_num);
-+	  len = grub_be_to_cpu16(opt->option_len);
-+
-+	  grub_dprintf ("net", "got dhcpv6 option %d len %d\n", num, len);
-+
-+	  if (len == 0)
-+	    break;
-+
-+	  if (len + i > 1024)
-+	    break;
-+
-+	  if (num == GRUB_NET_DHCP6_BOOTFILE_URL)
-+	    {
-+	      char *scheme, *userinfo, *host, *file;
-+	      char *tmp;
-+	      int hostlen;
-+	      int port;
-+	      int rc = extract_url_info ((const char *)opt->option_data,
-+					 (grub_size_t)len,
-+					 &scheme, &userinfo, &host, &port,
-+					 &file);
-+	      if (rc < 0)
-+		continue;
-+
-+	      /* right now this only handles tftp. */
-+	      if (grub_strcmp("tftp", scheme))
-+		{
-+		  grub_free (scheme);
-+		  grub_free (userinfo);
-+		  grub_free (host);
-+		  grub_free (file);
-+		  continue;
-+		}
-+	      grub_free (userinfo);
-+
-+	      hostlen = grub_strlen (host);
-+	      if (hostlen > 2 && host[0] == '[' && host[hostlen-1] == ']')
-+		{
-+		  tmp = host+1;
-+		  host[hostlen-1] = '\0';
-+		}
-+	      else
-+		tmp = host;
-+
-+	      *device = grub_xasprintf ("%s,%s", scheme, tmp);
-+	      grub_free (scheme);
-+	      grub_free (host);
-+
-+	      if (file && *file)
-+		{
-+		  tmp = grub_strrchr (file, '/');
-+		  if (tmp)
-+		    *(tmp+1) = '\0';
-+		  else
-+		    file[0] = '\0';
-+		}
-+	      else if (!file)
-+		file = grub_strdup ("");
-+
-+	      if (file[0] == '/')
-+		{
-+		  *path = grub_strdup (file+1);
-+		  grub_free (file);
-+		}
-+	      else
-+		*path = file;
-+	    }
-+	  else if (num == GRUB_NET_DHCP6_IA_NA)
-+	    {
-+	      const grub_net_dhcpv6_option_t *ia_na_opt;
-+	      const grub_net_dhcpv6_opt_ia_na_t *ia_na =
-+		(const grub_net_dhcpv6_opt_ia_na_t *)opt;
-+	      unsigned int left = len - OFFSET_OF (options, ia_na);
-+	      unsigned int j;
-+
-+	      if ((grub_uint8_t *)ia_na + left >
-+		  (grub_uint8_t *)options + option_max)
-+		left -= ((grub_uint8_t *)ia_na + left)
-+		        - ((grub_uint8_t *)options + option_max);
-+
-+	      if (len < OFFSET_OF (option_data, opt)
-+			+ sizeof (grub_net_dhcpv6_option_t))
-+		{
-+		  grub_dprintf ("net",
-+				"found dhcpv6 ia_na option with no address\n");
-+		  continue;
-+		}
-+
-+	      for (j = 0; left > sizeof (grub_net_dhcpv6_option_t); )
-+		{
-+		  ia_na_opt = (const grub_net_dhcpv6_option_t *)
-+			       (ia_na->options + j);
-+		  grub_uint16_t ia_na_opt_num, ia_na_opt_len;
-+
-+		  ia_na_opt_num = grub_be_to_cpu16 (ia_na_opt->option_num);
-+		  ia_na_opt_len = grub_be_to_cpu16 (ia_na_opt->option_len);
-+		  if (ia_na_opt_len == 0)
-+		    break;
-+		  if (j + ia_na_opt_len > left)
-+		    break;
-+		  if (ia_na_opt_num == GRUB_NET_DHCP6_IA_ADDRESS)
-+		    {
-+		      const grub_net_dhcpv6_opt_ia_address_t *ia_addr;
-+
-+		      ia_addr = (const grub_net_dhcpv6_opt_ia_address_t *)
-+				 ia_na_opt;
-+		      addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
-+		      grub_memcpy(addr.ipv6, ia_addr->ipv6_address,
-+				  sizeof (ia_addr->ipv6_address));
-+		      inter = grub_net_add_addr (name, card, &addr, hwaddr, 0);
-+		    }
-+
-+		  j += ia_na_opt_len;
-+		  left -= ia_na_opt_len;
-+		}
-+	    }
-+
-+	  i += len + 4;
-+	}
-+
-+      grub_print_error ();
-+    }
-+
-+  if (is_def)
-+    {
-+      grub_env_set ("net_default_interface", name);
-+      grub_env_export ("net_default_interface");
-+    }
-+
-+    if (inter)
-+      grub_net_add_ipv6_local (inter, mask);
-+    return inter;
-+}
-+
-+
- void
- grub_bootp_init (void)
- {
-diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
-index 5388f952ba9..173fb63153c 100644
---- a/grub-core/net/drivers/efi/efinet.c
-+++ b/grub-core/net/drivers/efi/efinet.c
-@@ -18,11 +18,14 @@
- 
- #include <grub/net/netbuff.h>
- #include <grub/dl.h>
-+#include <grub/env.h>
- #include <grub/net.h>
- #include <grub/time.h>
- #include <grub/efi/api.h>
- #include <grub/efi/efi.h>
- #include <grub/i18n.h>
-+#include <grub/lib/hexdump.h>
-+#include <grub/types.h>
- 
- GRUB_MOD_LICENSE ("GPLv3+");
- 
-@@ -329,7 +332,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
- 			  char **path)
- {
-   struct grub_net_card *card;
--  grub_efi_device_path_t *dp;
-+  grub_efi_device_path_t *dp, *ldp = NULL;
- 
-   dp = grub_efi_get_device_path (hnd);
-   if (! dp)
-@@ -340,14 +343,19 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
-     grub_efi_device_path_t *cdp;
-     struct grub_efi_pxe *pxe;
-     struct grub_efi_pxe_mode *pxe_mode;
-+
-     if (card->driver != &efidriver)
-       continue;
-+
-     cdp = grub_efi_get_device_path (card->efi_handle);
-     if (! cdp)
-       continue;
-+
-+    ldp = grub_efi_find_last_device_path (dp);
-+
-     if (grub_efi_compare_device_paths (dp, cdp) != 0)
-       {
--	grub_efi_device_path_t *ldp, *dup_dp, *dup_ldp;
-+	grub_efi_device_path_t *dup_dp, *dup_ldp;
- 	int match;
- 
- 	/* EDK2 UEFI PXE driver creates pseudo devices with type IPv4/IPv6
-@@ -356,7 +364,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
- 	   devices. We skip them when enumerating cards, so here we need to
- 	   find matching MAC device.
-          */
--	ldp = grub_efi_find_last_device_path (dp);
- 	if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
- 	    || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
- 		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
-@@ -373,16 +380,46 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
- 	if (!match)
- 	  continue;
-       }
-+
-     pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
- 				  GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-     if (! pxe)
-       continue;
-+
-     pxe_mode = pxe->mode;
--    grub_net_configure_by_dhcp_ack (card->name, card, 0,
--				    (struct grub_net_bootp_packet *)
--				    &pxe_mode->dhcp_ack,
--				    sizeof (pxe_mode->dhcp_ack),
--				    1, device, path);
-+    if (pxe_mode->using_ipv6)
-+      {
-+	grub_net_link_level_address_t hwaddr;
-+	struct grub_net_network_level_interface *intf;
-+
-+	grub_dprintf ("efinet", "using ipv6 and dhcpv6\n");
-+	grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n",
-+		      pxe_mode->dhcp_ack_received ? "yes" : "no",
-+		      pxe_mode->dhcp_ack_received ? "" : " cannot continue");
-+	if (!pxe_mode->dhcp_ack_received)
-+	  continue;
-+
-+	hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
-+	grub_memcpy (hwaddr.mac,
-+		     card->efi_net->mode->current_address,
-+		     sizeof (hwaddr.mac));
-+
-+	intf = grub_net_configure_by_dhcpv6_ack (card->name, card, 0, &hwaddr,
-+	      (const struct grub_net_dhcpv6_packet *)&pxe_mode->dhcp_ack.dhcpv6,
-+	      1, device, path);
-+	if (intf && device && path)
-+	  grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
-+      }
-+    else
-+      {
-+	grub_dprintf ("efinet", "using ipv4 and dhcp\n");
-+	grub_net_configure_by_dhcp_ack (card->name, card, 0,
-+					(struct grub_net_bootp_packet *)
-+					&pxe_mode->dhcp_ack,
-+					sizeof (pxe_mode->dhcp_ack),
-+					1, device, path);
-+	grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
-+      }
-     return;
-   }
- }
-diff --git a/grub-core/net/net.c b/grub-core/net/net.c
-index 0ef148f4adc..22f2689aaeb 100644
---- a/grub-core/net/net.c
-+++ b/grub-core/net/net.c
-@@ -960,6 +960,78 @@ grub_net_network_level_interface_register (struct grub_net_network_level_interfa
-   grub_net_network_level_interfaces = inter;
- }
- 
-+int
-+grub_ipv6_get_masksize (grub_uint16_t be_mask[8])
-+{
-+  grub_uint8_t *mask;
-+  grub_uint16_t mask16[8];
-+  int x, y;
-+  int ret = 128;
-+
-+  grub_memcpy (mask16, be_mask, sizeof (mask16));
-+  for (x = 0; x < 8; x++)
-+    mask16[x] = grub_be_to_cpu16 (mask16[x]);
-+
-+  mask = (grub_uint8_t *)mask16;
-+
-+  for (x = 15; x >= 0; x--)
-+    {
-+      grub_uint8_t octet = mask[x];
-+      if (!octet)
-+	{
-+	  ret -= 8;
-+	  continue;
-+	}
-+      for (y = 0; y < 8; y++)
-+	{
-+	  if (octet & (1 << y))
-+	    break;
-+	  else
-+	    ret--;
-+	}
-+      break;
-+    }
-+
-+  return ret;
-+}
-+
-+grub_err_t
-+grub_net_add_ipv6_local (struct grub_net_network_level_interface *inter,
-+			 int mask)
-+{
-+  struct grub_net_route *route;
-+
-+  if (inter->address.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6)
-+    return 0;
-+
-+  if (mask == -1)
-+      mask = grub_ipv6_get_masksize ((grub_uint16_t *)inter->address.ipv6);
-+
-+  if (mask == -1)
-+    return 0;
-+
-+  route = grub_zalloc (sizeof (*route));
-+  if (!route)
-+    return grub_errno;
-+
-+  route->name = grub_xasprintf ("%s:local", inter->name);
-+  if (!route->name)
-+    {
-+      grub_free (route);
-+      return grub_errno;
-+    }
-+
-+  route->target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
-+  grub_memcpy (route->target.ipv6.base, inter->address.ipv6,
-+	       sizeof (inter->address.ipv6));
-+  route->target.ipv6.masksize = mask;
-+  route->is_gateway = 0;
-+  route->interface = inter;
-+
-+  grub_net_route_register (route);
-+
-+  return 0;
-+}
- 
- grub_err_t
- grub_net_add_ipv4_local (struct grub_net_network_level_interface *inter,
-diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
-index 7f44b30f521..4ab2f5c7357 100644
---- a/grub-core/net/tftp.c
-+++ b/grub-core/net/tftp.c
-@@ -358,18 +358,22 @@ tftp_open (struct grub_file *file, const char *filename)
-   file->not_easily_seekable = 1;
-   file->data = data;
- 
-+  grub_dprintf("tftp", "resolving address for %s\n", file->device->net->server);
-   err = grub_net_resolve_address (file->device->net->server, &addr);
-   if (err)
-     {
-+      grub_dprintf("tftp", "Address resolution failed: %d\n", err);
-       grub_free (data);
-       return err;
-     }
- 
-+  grub_dprintf("tftp", "opening connection\n");
-   data->sock = grub_net_udp_open (addr,
- 				  TFTP_SERVER_PORT, tftp_receive,
- 				  file);
-   if (!data->sock)
-     {
-+      grub_dprintf("tftp", "connection failed\n");
-       grub_free (data);
-       return grub_errno;
-     }
-diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
-index f1a52210c0c..117469450d3 100644
---- a/include/grub/efi/api.h
-+++ b/include/grub/efi/api.h
-@@ -592,10 +592,16 @@ typedef void *grub_efi_handle_t;
- typedef void *grub_efi_event_t;
- typedef grub_efi_uint64_t grub_efi_lba_t;
- typedef grub_efi_uintn_t grub_efi_tpl_t;
--typedef grub_uint8_t grub_efi_mac_address_t[32];
--typedef grub_uint8_t grub_efi_ipv4_address_t[4];
--typedef grub_uint16_t grub_efi_ipv6_address_t[8];
--typedef grub_uint8_t grub_efi_ip_address_t[8] __attribute__ ((aligned(4)));
-+typedef grub_efi_uint8_t grub_efi_mac_address_t[32];
-+typedef grub_efi_uint8_t grub_efi_ipv4_address_t[4];
-+typedef grub_efi_uint8_t grub_efi_ipv6_address_t[16];
-+typedef union
-+{
-+  grub_efi_uint32_t addr[4];
-+  grub_efi_ipv4_address_t v4;
-+  grub_efi_ipv6_address_t v6;
-+} grub_efi_ip_address_t __attribute__ ((aligned(4)));
-+
- typedef grub_efi_uint64_t grub_efi_physical_address_t;
- typedef grub_efi_uint64_t grub_efi_virtual_address_t;
- 
-@@ -1474,16 +1480,127 @@ struct grub_efi_simple_text_output_interface
- };
- typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output_interface_t;
- 
--typedef grub_uint8_t grub_efi_pxe_packet_t[1472];
-+typedef struct grub_efi_pxe_dhcpv4_packet
-+{
-+  grub_efi_uint8_t bootp_opcode;
-+  grub_efi_uint8_t bootp_hwtype;
-+  grub_efi_uint8_t bootp_hwaddr_len;
-+  grub_efi_uint8_t bootp_gate_hops;
-+  grub_efi_uint32_t bootp_ident;
-+  grub_efi_uint16_t bootp_seconds;
-+  grub_efi_uint16_t bootp_flags;
-+  grub_efi_uint8_t bootp_ci_addr[4];
-+  grub_efi_uint8_t bootp_yi_addr[4];
-+  grub_efi_uint8_t bootp_si_addr[4];
-+  grub_efi_uint8_t bootp_gi_addr[4];
-+  grub_efi_uint8_t bootp_hw_addr[16];
-+  grub_efi_uint8_t bootp_srv_name[64];
-+  grub_efi_uint8_t bootp_boot_file[128];
-+  grub_efi_uint32_t dhcp_magik;
-+  grub_efi_uint8_t dhcp_options[56];
-+} grub_efi_pxe_dhcpv4_packet_t;
-+
-+struct grub_efi_pxe_dhcpv6_packet
-+{
-+  grub_efi_uint32_t message_type:8;
-+  grub_efi_uint32_t transaction_id:24;
-+  grub_efi_uint8_t dhcp_options[1024];
-+} GRUB_PACKED;
-+typedef struct grub_efi_pxe_dhcpv6_packet grub_efi_pxe_dhcpv6_packet_t;
-+
-+typedef union
-+{
-+  grub_efi_uint8_t raw[1472];
-+  grub_efi_pxe_dhcpv4_packet_t dhcpv4;
-+  grub_efi_pxe_dhcpv6_packet_t dhcpv6;
-+} grub_efi_pxe_packet_t;
-+
-+#define GRUB_EFI_PXE_MAX_IPCNT 8
-+#define GRUB_EFI_PXE_MAX_ARP_ENTRIES 8
-+#define GRUB_EFI_PXE_MAX_ROUTE_ENTRIES 8
-+
-+typedef struct grub_efi_pxe_ip_filter
-+{
-+  grub_efi_uint8_t filters;
-+  grub_efi_uint8_t ip_count;
-+  grub_efi_uint8_t reserved;
-+  grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT];
-+} grub_efi_pxe_ip_filter_t;
-+
-+typedef struct grub_efi_pxe_arp_entry
-+{
-+  grub_efi_ip_address_t ip_addr;
-+  grub_efi_mac_address_t mac_addr;
-+} grub_efi_pxe_arp_entry_t;
-+
-+typedef struct grub_efi_pxe_route_entry
-+{
-+  grub_efi_ip_address_t ip_addr;
-+  grub_efi_ip_address_t subnet_mask;
-+  grub_efi_ip_address_t gateway_addr;
-+} grub_efi_pxe_route_entry_t;
-+
-+typedef struct grub_efi_pxe_icmp_error
-+{
-+  grub_efi_uint8_t type;
-+  grub_efi_uint8_t code;
-+  grub_efi_uint16_t checksum;
-+  union
-+    {
-+      grub_efi_uint32_t reserved;
-+      grub_efi_uint32_t mtu;
-+      grub_efi_uint32_t pointer;
-+      struct
-+	{
-+	  grub_efi_uint16_t identifier;
-+	  grub_efi_uint16_t sequence;
-+	} echo;
-+    } u;
-+  grub_efi_uint8_t data[494];
-+} grub_efi_pxe_icmp_error_t;
-+
-+typedef struct grub_efi_pxe_tftp_error
-+{
-+  grub_efi_uint8_t error_code;
-+  grub_efi_char8_t error_string[127];
-+} grub_efi_pxe_tftp_error_t;
- 
- typedef struct grub_efi_pxe_mode
- {
--  grub_uint8_t unused[52];
-+  grub_efi_boolean_t started;
-+  grub_efi_boolean_t ipv6_available;
-+  grub_efi_boolean_t ipv6_supported;
-+  grub_efi_boolean_t using_ipv6;
-+  grub_efi_boolean_t bis_supported;
-+  grub_efi_boolean_t bis_detected;
-+  grub_efi_boolean_t auto_arp;
-+  grub_efi_boolean_t send_guid;
-+  grub_efi_boolean_t dhcp_discover_valid;
-+  grub_efi_boolean_t dhcp_ack_received;
-+  grub_efi_boolean_t proxy_offer_received;
-+  grub_efi_boolean_t pxe_discover_valid;
-+  grub_efi_boolean_t pxe_reply_received;
-+  grub_efi_boolean_t pxe_bis_reply_received;
-+  grub_efi_boolean_t icmp_error_received;
-+  grub_efi_boolean_t tftp_error_received;
-+  grub_efi_boolean_t make_callbacks;
-+  grub_efi_uint8_t ttl;
-+  grub_efi_uint8_t tos;
-+  grub_efi_ip_address_t station_ip;
-+  grub_efi_ip_address_t subnet_mask;
-   grub_efi_pxe_packet_t dhcp_discover;
-   grub_efi_pxe_packet_t dhcp_ack;
-   grub_efi_pxe_packet_t proxy_offer;
-   grub_efi_pxe_packet_t pxe_discover;
-   grub_efi_pxe_packet_t pxe_reply;
-+  grub_efi_pxe_packet_t pxe_bis_reply;
-+  grub_efi_pxe_ip_filter_t ip_filter;
-+  grub_efi_uint32_t arp_cache_entries;
-+  grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_MAX_ARP_ENTRIES];
-+  grub_efi_uint32_t route_table_entries;
-+  grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_MAX_ROUTE_ENTRIES];
-+  grub_efi_pxe_icmp_error_t icmp_error;
-+  grub_efi_pxe_tftp_error_t tftp_error;
- } grub_efi_pxe_mode_t;
- 
- typedef struct grub_efi_pxe
-diff --git a/include/grub/net.h b/include/grub/net.h
-index 7ae4b6bd805..8a05ec4fe7a 100644
---- a/include/grub/net.h
-+++ b/include/grub/net.h
-@@ -447,6 +447,51 @@ struct grub_net_bootp_packet
-   grub_uint8_t vendor[0];
- } GRUB_PACKED;
- 
-+enum
-+  {
-+    GRUB_NET_DHCP6_IA_NA = 3,
-+    GRUB_NET_DHCP6_IA_ADDRESS = 5,
-+    GRUB_NET_DHCP6_BOOTFILE_URL = 59,
-+  };
-+
-+struct grub_net_dhcpv6_option
-+{
-+  grub_uint16_t option_num;
-+  grub_uint16_t option_len;
-+  grub_uint8_t option_data[];
-+} GRUB_PACKED;
-+typedef struct grub_net_dhcpv6_option grub_net_dhcpv6_option_t;
-+
-+struct grub_net_dhcpv6_opt_ia_na
-+{
-+  grub_uint16_t option_num;
-+  grub_uint16_t option_len;
-+  grub_uint32_t iaid;
-+  grub_uint32_t t1;
-+  grub_uint32_t t2;
-+  grub_uint8_t options[];
-+} GRUB_PACKED;
-+typedef struct grub_net_dhcpv6_opt_ia_na grub_net_dhcpv6_opt_ia_na_t;
-+
-+struct grub_net_dhcpv6_opt_ia_address
-+{
-+  grub_uint16_t option_num;
-+  grub_uint16_t option_len;
-+  grub_uint64_t ipv6_address[2];
-+  grub_uint32_t preferred_lifetime;
-+  grub_uint32_t valid_lifetime;
-+  grub_uint8_t options[];
-+} GRUB_PACKED;
-+typedef struct grub_net_dhcpv6_opt_ia_address grub_net_dhcpv6_opt_ia_address_t;
-+
-+struct grub_net_dhcpv6_packet
-+{
-+  grub_uint32_t message_type:8;
-+  grub_uint32_t transaction_id:24;
-+  grub_uint8_t dhcp_options[1024];
-+} GRUB_PACKED;
-+typedef struct grub_net_dhcpv6_packet grub_net_dhcpv6_packet_t;
-+
- #define	GRUB_NET_BOOTP_RFC1048_MAGIC_0	0x63
- #define	GRUB_NET_BOOTP_RFC1048_MAGIC_1	0x82
- #define	GRUB_NET_BOOTP_RFC1048_MAGIC_2	0x53
-@@ -482,6 +527,21 @@ grub_net_configure_by_dhcp_ack (const char *name,
- 				grub_size_t size,
- 				int is_def, char **device, char **path);
- 
-+struct grub_net_network_level_interface *
-+grub_net_configure_by_dhcpv6_ack (const char *name,
-+				 struct grub_net_card *card,
-+				 grub_net_interface_flags_t flags,
-+				 const grub_net_link_level_address_t *hwaddr,
-+				 const struct grub_net_dhcpv6_packet *packet,
-+				 int is_def, char **device, char **path);
-+
-+int
-+grub_ipv6_get_masksize(grub_uint16_t *mask);
-+
-+grub_err_t
-+grub_net_add_ipv6_local (struct grub_net_network_level_interface *inf,
-+			 int mask);
-+
- grub_err_t
- grub_net_add_ipv4_local (struct grub_net_network_level_interface *inf,
- 			 int mask);
diff --git a/SOURCES/0051-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch b/SOURCES/0051-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch
new file mode 100644
index 0000000..f649c8c
--- /dev/null
+++ b/SOURCES/0051-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch
@@ -0,0 +1,48 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 1 Jun 2017 10:07:50 -0400
+Subject: [PATCH] Add PRIxGRUB_EFI_STATUS and use it.
+
+This avoids syntax checkers getting confused about if it's llx or lx.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/efi/chainloader.c | 3 ++-
+ include/grub/efi/api.h             | 9 +++++++++
+ 2 files changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index 89ac84cc66..ac8dfd40c6 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -810,7 +810,8 @@ handle_image (void *data, grub_efi_uint32_t datasize)
+   efi_status = efi_call_2 (entry_point, grub_efi_image_handle,
+ 			   grub_efi_system_table);
+ 
+-  grub_dprintf ("chain", "entry_point returned %ld\n", efi_status);
++  grub_dprintf ("chain", "entry_point returned 0x%"PRIxGRUB_EFI_STATUS"\n",
++		efi_status);
+   grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t));
+   efi_status = grub_efi_free_pool (buffer);
+ 
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index 117469450d..9962880147 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -546,7 +546,16 @@ typedef grub_uint64_t grub_efi_uint64_t;
+ typedef grub_uint8_t grub_efi_char8_t;
+ typedef grub_uint16_t grub_efi_char16_t;
+ 
++
+ typedef grub_efi_uintn_t grub_efi_status_t;
++/* Make grub_efi_status_t reasonably printable. */
++#if GRUB_CPU_SIZEOF_VOID_P == 8
++#define PRIxGRUB_EFI_STATUS "lx"
++#define PRIdGRUB_EFI_STATUS "ld"
++#else
++#define PRIxGRUB_EFI_STATUS "llx"
++#define PRIdGRUB_EFI_STATUS "lld"
++#endif
+ 
+ #define GRUB_EFI_ERROR_CODE(value)	\
+   ((((grub_efi_status_t) 1) << (sizeof (grub_efi_status_t) * 8 - 1)) | (value))
diff --git a/SOURCES/0051-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch b/SOURCES/0051-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch
deleted file mode 100644
index e799ac1..0000000
--- a/SOURCES/0051-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch
+++ /dev/null
@@ -1,296 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 23 Jun 2016 11:01:39 -0400
-Subject: [PATCH] Add grub-get-kernel-settings and use it in 10_linux
-
-This patch adds grub-get-kernel-settings, which reads the system kernel
-installation configuration from /etc/sysconfig/kernel, and outputs
-${GRUB_...} variables suitable for evaluation by grub-mkconfig.  Those
-variables are then used by 10_linux to choose whether or not to create
-debug stanzas.
-
-Resolves: rhbz#1226325
----
- configure.ac                                   |  2 +
- Makefile.util.def                              |  7 ++
- util/bash-completion.d/grub-completion.bash.in | 22 +++++++
- util/grub-get-kernel-settings.3                | 20 ++++++
- util/grub-get-kernel-settings.in               | 88 ++++++++++++++++++++++++++
- util/grub-mkconfig.in                          |  3 +
- util/grub.d/10_linux.in                        | 23 +++++--
- 7 files changed, 160 insertions(+), 5 deletions(-)
- create mode 100644 util/grub-get-kernel-settings.3
- create mode 100644 util/grub-get-kernel-settings.in
-
-diff --git a/configure.ac b/configure.ac
-index 30fd84d8067..ed31ea457d2 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -65,6 +65,7 @@ grub_TRANSFORM([grub-install])
- grub_TRANSFORM([grub-mkconfig])
- grub_TRANSFORM([grub-mkfont])
- grub_TRANSFORM([grub-mkimage])
-+grub_TRANSFORM([grub-get-kernel-settings])
- grub_TRANSFORM([grub-glue-efi])
- grub_TRANSFORM([grub-mklayout])
- grub_TRANSFORM([grub-mkpasswd-pbkdf2])
-@@ -82,6 +83,7 @@ grub_TRANSFORM([grub-file])
- grub_TRANSFORM([grub-bios-setup.3])
- grub_TRANSFORM([grub-editenv.1])
- grub_TRANSFORM([grub-fstest.3])
-+grub_TRANSFORM([grub-get-kernel-settings.3])
- grub_TRANSFORM([grub-glue-efi.3])
- grub_TRANSFORM([grub-install.1])
- grub_TRANSFORM([grub-kbdcomp.3])
-diff --git a/Makefile.util.def b/Makefile.util.def
-index 1a7dd433e33..cdd2f51fe4b 100644
---- a/Makefile.util.def
-+++ b/Makefile.util.def
-@@ -732,6 +732,13 @@ script = {
-   installdir = sbin;
- };
- 
-+script = {
-+  name = grub-get-kernel-settings;
-+  common = util/grub-get-kernel-settings.in;
-+  mansection = 3;
-+  installdir = sbin;
-+};
-+
- script = {
-   name = grub-set-default;
-   common = util/grub-set-default.in;
-diff --git a/util/bash-completion.d/grub-completion.bash.in b/util/bash-completion.d/grub-completion.bash.in
-index 44bf135b9f8..5c4acd496d4 100644
---- a/util/bash-completion.d/grub-completion.bash.in
-+++ b/util/bash-completion.d/grub-completion.bash.in
-@@ -264,6 +264,28 @@ have ${__grub_sparc64_setup_program} && \
- unset __grub_sparc64_setup_program
- 
- 
-+#
-+# grub-get-kernel-settings
-+#
-+_grub_get_kernel_settings () {
-+    local cur
-+
-+    COMPREPLY=()
-+    cur=`_get_cword`
-+
-+    if [[ "$cur" == -* ]]; then
-+        __grubcomp "$(__grub_get_options_from_help)"
-+    else
-+        # Default complete with a filename
-+        _filedir
-+    fi
-+}
-+__grub_get_kernel_settings_program="@grub_get_kernel_settings@"
-+have ${__grub_get_kernel_settings_program} && \
-+ complete -F _grub_get_kernel_settings -o filenames ${__grub_get_kernel_settings_program}
-+unset __grub_get_kernel_settings_program
-+
-+
- #
- # grub-install
- #
-diff --git a/util/grub-get-kernel-settings.3 b/util/grub-get-kernel-settings.3
-new file mode 100644
-index 00000000000..ba33330e28d
---- /dev/null
-+++ b/util/grub-get-kernel-settings.3
-@@ -0,0 +1,20 @@
-+.TH GRUB-GET-KERNEL-SETTINGS 3 "Thu Jun 25 2015"
-+.SH NAME
-+\fBgrub-get-kernel-settings\fR \(em Evaluate the system's kernel installation settings for use while making a grub configuration file.
-+
-+.SH SYNOPSIS
-+\fBgrub-get-kernel-settings\fR [OPTION]
-+
-+.SH DESCRIPTION
-+\fBgrub-get-kernel-settings\fR reads the kernel installation settings on the host system, and emits a set of grub settings suitable for use when creating a grub configuration file.
-+
-+.SH OPTIONS
-+.TP
-+-h, --help
-+Display program usage and exit.
-+.TP
-+-v, --version
-+Display the current version.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-get-kernel-settings.in b/util/grub-get-kernel-settings.in
-new file mode 100644
-index 00000000000..7e87dfccc0e
---- /dev/null
-+++ b/util/grub-get-kernel-settings.in
-@@ -0,0 +1,88 @@
-+#!/bin/sh
-+set -e
-+
-+# Evaluate new-kernel-pkg's configuration file.
-+# Copyright (C) 2016 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/>.
-+
-+PACKAGE_NAME=@PACKAGE_NAME@
-+PACKAGE_VERSION=@PACKAGE_VERSION@
-+datadir="@datadir@"
-+if [ "x$pkgdatadir" = x ]; then
-+    pkgdatadir="${datadir}/@PACKAGE@"
-+fi
-+
-+self=`basename $0`
-+
-+export TEXTDOMAIN=@PACKAGE@
-+export TEXTDOMAINDIR="@localedir@"
-+
-+. "${pkgdatadir}/grub-mkconfig_lib"
-+
-+# Usage: usage
-+# Print the usage.
-+usage () {
-+    gettext_printf "Usage: %s [OPTION]\n" "$self"
-+    gettext "Evaluate new-kernel-pkg configuration"; echo
-+    echo
-+    print_option_help "-h, --help" "$(gettext "print this message and exit")"
-+    print_option_help "-v, --version" "$(gettext "print the version information and exit")"
-+    echo
-+}
-+
-+# Check the arguments.
-+while test $# -gt 0
-+do
-+    option=$1
-+    shift
-+
-+    case "$option" in
-+    -h | --help)
-+	usage
-+	exit 0 ;;
-+    -v | --version)
-+	echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}"
-+	exit 0 ;;
-+    -*)
-+	gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2
-+	usage
-+	exit 1
-+	;;
-+    # Explicitly ignore non-option arguments, for compatibility.
-+    esac
-+done
-+
-+if test -f /etc/sysconfig/kernel ; then
-+    . /etc/sysconfig/kernel
-+fi
-+
-+if [ "$MAKEDEBUG" = "yes" ]; then
-+    echo GRUB_LINUX_MAKE_DEBUG=true
-+    echo export GRUB_LINUX_MAKE_DEBUG
-+    echo GRUB_CMDLINE_LINUX_DEBUG=\"systemd.log_level=debug systemd.log_target=kmsg\"
-+    echo export GRUB_CMDLINE_LINUX_DEBUG
-+    echo GRUB_LINUX_DEBUG_TITLE_POSTFIX=\" with debugging\"
-+    echo export GRUB_LINUX_DEBUG_TITLE_POSTFIX
-+fi
-+if [ "$DEFAULTDEBUG" = "yes" ]; then
-+    echo GRUB_DEFAULT_TO_DEBUG=true
-+else
-+    echo GRUB_DEFAULT_TO_DEBUG=false
-+fi
-+echo export GRUB_DEFAULT_TO_DEBUG
-+if [ "$UPDATEDEFAULT" = "yes" ]; then
-+    echo GRUB_UPDATE_DEFAULT_KERNEL=true
-+    echo export GRUB_UPDATE_DEFAULT_KERNEL
-+fi
-diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
-index ba14cf6261c..005f093809b 100644
---- a/util/grub-mkconfig.in
-+++ b/util/grub-mkconfig.in
-@@ -45,6 +45,7 @@ grub_probe="${sbindir}/@grub_probe@"
- grub_file="${bindir}/@grub_file@"
- grub_editenv="${bindir}/@grub_editenv@"
- grub_script_check="${bindir}/@grub_script_check@"
-+grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@"
- 
- export TEXTDOMAIN=@PACKAGE@
- export TEXTDOMAINDIR="@localedir@"
-@@ -158,6 +159,8 @@ if test -f ${sysconfdir}/default/grub ; then
-   . ${sysconfdir}/default/grub
- fi
- 
-+eval "$("${grub_get_kernel_settings}")" || true
-+
- if [ "x${GRUB_DISABLE_UUID}" = "xtrue" ]; then
-   if [ -z "${GRUB_DISABLE_LINUX_UUID}" ]; then
-     GRUB_DISABLE_LINUX_UUID="true"
-diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
-index 2e59f3b4197..0f3c19e30cc 100644
---- a/util/grub.d/10_linux.in
-+++ b/util/grub.d/10_linux.in
-@@ -111,7 +111,8 @@ linux_entry ()
-   os="$1"
-   version="$2"
-   type="$3"
--  args="$4"
-+  isdebug="$4"
-+  args="$5"
- 
-   if [ -z "$boot_device_id" ]; then
-       boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
-@@ -123,6 +124,9 @@ linux_entry ()
- 	  quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)"
- 	  title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;"
-       fi
-+      if [ x$isdebug = xdebug ]; then
-+	  title="$title${GRUB_LINUX_DEBUG_TITLE_POSTFIX}"
-+      fi
-       echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
-   else
-       echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
-@@ -299,11 +303,15 @@ while [ "x$list" != "x" ] ; do
-   fi
- 
-   if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then
--    linux_entry "${OS}" "${version}" simple \
-+    linux_entry "${OS}" "${version}" simple standard \
-     "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
-+    if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
-+      linux_entry "${OS}" "${version}" simple debug \
-+        "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}"
-+    fi
- 
-     submenu_indentation="$grub_tab"
--    
-+
-     if [ -z "$boot_device_id" ]; then
- 	boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
-     fi
-@@ -312,10 +320,15 @@ while [ "x$list" != "x" ] ; do
-     is_top_level=false
-   fi
- 
--  linux_entry "${OS}" "${version}" advanced \
-+  linux_entry "${OS}" "${version}" advanced standard \
-               "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
-+  if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
-+    linux_entry "${OS}" "${version}" advanced debug \
-+                "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}"
-+  fi
-+
-   if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
--    linux_entry "${OS}" "${version}" recovery \
-+    linux_entry "${OS}" "${version}" recovery standard \
-                 "single ${GRUB_CMDLINE_LINUX}"
-   fi
- 
diff --git a/SOURCES/0052-bz1374141-fix-incorrect-mask-for-ppc64.patch b/SOURCES/0052-bz1374141-fix-incorrect-mask-for-ppc64.patch
deleted file mode 100644
index 1bb2658..0000000
--- a/SOURCES/0052-bz1374141-fix-incorrect-mask-for-ppc64.patch
+++ /dev/null
@@ -1,45 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Masahiro Matsuya <mmatsuya@redhat.com>
-Date: Sat, 29 Oct 2016 08:35:26 +0900
-Subject: [PATCH] bz1374141 fix incorrect mask for ppc64
-
-The netmask configured in firmware is not respected on ppc64 (big endian).
-When 255.255.252.0 is set as netmask in firmware, the following is the value of bootpath string in grub_ieee1275_parse_bootpath().
-
- /vdevice/l-lan@30000002:speed=auto,duplex=auto,192.168.88.10,,192.168.89.113,192.168.88.1,5,5,255.255.252.0,512
-
-The netmask in this bootpath is no problem, since it's a value specified in firmware. But,
-The value of 'subnet_mask.ipv4' was set with 0xfffffc00, and __builtin_ctz (~grub_le_to_cpu32 (subnet_mask.ipv4)) returned 16 (not 22).
-As a result, 16 was used for netmask wrongly.
-
-1111 1111 1111 1111 1111 1100 0000 0000 # subnet_mask.ipv4 (=0xfffffc00)
-0000 0000 1111 1100 1111 1111 1111 1111 # grub_le_to_cpu32 (subnet_mask.ipv4)
-1111 1111 0000 0011 0000 0000 0000 0000 # ~grub_le_to_cpu32 (subnet_mask.ipv4)
-
-And, the count of zero with __builtin_ctz can be 16.
-This patch changes it as below.
-
-1111 1111 1111 1111 1111 1100 0000 0000 # subnet_mask.ipv4 (=0xfffffc00)
-0000 0000 1111 1100 1111 1111 1111 1111 # grub_le_to_cpu32 (subnet_mask.ipv4)
-1111 1111 1111 1111 1111 1100 0000 0000 # grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4))
-0000 0000 0000 0000 0000 0011 1111 1111 # ~grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4))
-
-The count of zero with __builtin_clz can be 22. (clz counts the number of one bits preceding the most significant zero bit)
----
- grub-core/net/drivers/ieee1275/ofnet.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
-diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c
-index ac4e62a95c9..3860b6f78d8 100644
---- a/grub-core/net/drivers/ieee1275/ofnet.c
-+++ b/grub-core/net/drivers/ieee1275/ofnet.c
-@@ -220,8 +220,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath,
-                                  flags);
-       inter->vlantag = vlantag;
-       grub_net_add_ipv4_local (inter,
--                          __builtin_ctz (~grub_le_to_cpu32 (subnet_mask.ipv4)));
--
-+                          __builtin_clz (~grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4))));
-     }
- 
-   if (gateway_addr.ipv4 != 0)
diff --git a/SOURCES/0052-don-t-use-int-for-efi-status.patch b/SOURCES/0052-don-t-use-int-for-efi-status.patch
new file mode 100644
index 0000000..4d48e37
--- /dev/null
+++ b/SOURCES/0052-don-t-use-int-for-efi-status.patch
@@ -0,0 +1,22 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 26 Jun 2017 12:44:59 -0400
+Subject: [PATCH] don't use int for efi status
+
+---
+ grub-core/kern/efi/efi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index 05d8237a9b..ae9885edb8 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -167,7 +167,7 @@ grub_reboot (void)
+ void
+ grub_exit (int retval)
+ {
+-  int rc = GRUB_EFI_LOAD_ERROR;
++  grub_efi_status_t rc = GRUB_EFI_LOAD_ERROR;
+ 
+   if (retval == 0)
+     rc = GRUB_EFI_SUCCESS;
diff --git a/SOURCES/0053-Make-grub_fatal-also-backtrace.patch b/SOURCES/0053-Make-grub_fatal-also-backtrace.patch
deleted file mode 100644
index 3534b05..0000000
--- a/SOURCES/0053-Make-grub_fatal-also-backtrace.patch
+++ /dev/null
@@ -1,172 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Wed, 27 Jan 2016 09:22:42 -0500
-Subject: [PATCH] Make grub_fatal() also backtrace.
-
----
- grub-core/Makefile.core.def     |  3 ++
- grub-core/kern/misc.c           |  8 +++++-
- grub-core/lib/arm64/backtrace.c | 62 +++++++++++++++++++++++++++++++++++++++++
- grub-core/lib/backtrace.c       |  2 ++
- grub-core/lib/i386/backtrace.c  | 14 +++++++++-
- 5 files changed, 87 insertions(+), 2 deletions(-)
- create mode 100644 grub-core/lib/arm64/backtrace.c
-
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index c15e91943b9..058c88ac3af 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -188,6 +188,9 @@ kernel = {
- 
-   softdiv = lib/division.c;
- 
-+  x86 = lib/i386/backtrace.c;
-+  x86 = lib/backtrace.c;
-+
-   i386 = kern/i386/dl.c;
-   i386_xen = kern/i386/dl.c;
-   i386_xen_pvh = kern/i386/dl.c;
-diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
-index 63b586d09cb..a3e215155bd 100644
---- a/grub-core/kern/misc.c
-+++ b/grub-core/kern/misc.c
-@@ -24,6 +24,7 @@
- #include <grub/term.h>
- #include <grub/env.h>
- #include <grub/i18n.h>
-+#include <grub/backtrace.h>
- 
- union printf_arg
- {
-@@ -1199,8 +1200,13 @@ grub_printf_fmt_check (const char *fmt, const char *fmt_expected)
- static void __attribute__ ((noreturn))
- grub_abort (void)
- {
-+#ifndef GRUB_UTIL
-+#if defined(__i386__) || defined(__x86_64__)
-+  grub_backtrace();
-+#endif
-+#endif
-   grub_printf ("\nAborted.");
--  
-+
- #ifndef GRUB_UTIL
-   if (grub_term_inputs)
- #endif
-diff --git a/grub-core/lib/arm64/backtrace.c b/grub-core/lib/arm64/backtrace.c
-new file mode 100644
-index 00000000000..1079b5380e1
---- /dev/null
-+++ b/grub-core/lib/arm64/backtrace.c
-@@ -0,0 +1,62 @@
-+/*
-+ *  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/misc.h>
-+#include <grub/command.h>
-+#include <grub/err.h>
-+#include <grub/dl.h>
-+#include <grub/mm.h>
-+#include <grub/term.h>
-+#include <grub/backtrace.h>
-+
-+#define MAX_STACK_FRAME 102400
-+
-+void
-+grub_backtrace_pointer (int frame)
-+{
-+  while (1)
-+    {
-+      void *lp = __builtin_return_address (frame);
-+      if (!lp)
-+	break;
-+
-+      lp = __builtin_extract_return_addr (lp);
-+
-+      grub_printf ("%p: ", lp);
-+      grub_backtrace_print_address (lp);
-+      grub_printf (" (");
-+      for (i = 0; i < 2; i++)
-+	grub_printf ("%p,", ((void **)ptr) [i + 2]);
-+      grub_printf ("%p)\n", ((void **)ptr) [i + 2]);
-+      nptr = *(void **)ptr;
-+      if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME
-+	  || nptr == ptr)
-+	{
-+	  grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr);
-+	  break;
-+	}
-+      ptr = nptr;
-+    }
-+}
-+
-+void
-+grub_backtrace (void)
-+{
-+  grub_backtrace_pointer (1);
-+}
-+
-diff --git a/grub-core/lib/backtrace.c b/grub-core/lib/backtrace.c
-index 825a8800e25..c0ad6ab8be1 100644
---- a/grub-core/lib/backtrace.c
-+++ b/grub-core/lib/backtrace.c
-@@ -29,6 +29,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
- void
- grub_backtrace_print_address (void *addr)
- {
-+#ifndef GRUB_UTIL
-   grub_dl_t mod;
- 
-   FOR_DL_MODULES (mod)
-@@ -44,6 +45,7 @@ grub_backtrace_print_address (void *addr)
- 	}
-   }
- 
-+#endif
-   grub_printf ("%p", addr);
- }
- 
-diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c
-index c3e03c7275c..c67273db3ae 100644
---- a/grub-core/lib/i386/backtrace.c
-+++ b/grub-core/lib/i386/backtrace.c
-@@ -15,11 +15,23 @@
-  *  You should have received a copy of the GNU General Public License
-  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
-  */
-+#include <config.h>
-+#ifdef GRUB_UTIL
-+#define REALLY_GRUB_UTIL GRUB_UTIL
-+#undef GRUB_UTIL
-+#endif
-+
-+#include <grub/symbol.h>
-+#include <grub/dl.h>
-+
-+#ifdef REALLY_GRUB_UTIL
-+#define GRUB_UTIL REALLY_GRUB_UTIL
-+#undef REALLY_GRUB_UTIL
-+#endif
- 
- #include <grub/misc.h>
- #include <grub/command.h>
- #include <grub/err.h>
--#include <grub/dl.h>
- #include <grub/mm.h>
- #include <grub/term.h>
- #include <grub/backtrace.h>
diff --git a/SOURCES/0053-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch b/SOURCES/0053-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch
new file mode 100644
index 0000000..fb71ea5
--- /dev/null
+++ b/SOURCES/0053-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 26 Jun 2017 12:46:23 -0400
+Subject: [PATCH] make GRUB_MOD_INIT() declare its function prototypes.
+
+---
+ include/grub/dl.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/include/grub/dl.h b/include/grub/dl.h
+index b3753c9ca2..91933b85f2 100644
+--- a/include/grub/dl.h
++++ b/include/grub/dl.h
+@@ -54,6 +54,7 @@ grub_mod_fini (void)
+ 
+ #define GRUB_MOD_INIT(name)	\
+ static void grub_mod_init (grub_dl_t mod __attribute__ ((unused))) __attribute__ ((used)); \
++extern void grub_##name##_init (void); \
+ void \
+ grub_##name##_init (void) { grub_mod_init (0); } \
+ static void \
+@@ -61,6 +62,7 @@ grub_mod_init (grub_dl_t mod __attribute__ ((unused)))
+ 
+ #define GRUB_MOD_FINI(name)	\
+ static void grub_mod_fini (void) __attribute__ ((used)); \
++extern void grub_##name##_fini (void); \
+ void \
+ grub_##name##_fini (void) { grub_mod_fini (); } \
+ static void \
diff --git a/SOURCES/0054-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch b/SOURCES/0054-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch
new file mode 100644
index 0000000..ae8a8c6
--- /dev/null
+++ b/SOURCES/0054-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 20 Apr 2017 13:29:06 -0400
+Subject: [PATCH] Don't guess /boot/efi/ as HFS+ on ppc machines in
+ grub-install
+
+This should never be trying this, and since we've consolidated the
+grubenv to always be on /boot/efi/EFI/fedora/, this code causes it to
+always make the wrong decision.
+
+Resolves: rhbz#1484474
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub-install.c | 12 +-----------
+ 1 file changed, 1 insertion(+), 11 deletions(-)
+
+diff --git a/util/grub-install.c b/util/grub-install.c
+index 84ed6e88ec..a2bec7446c 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -1190,18 +1190,8 @@ main (int argc, char *argv[])
+ 	  char *d;
+ 
+ 	  is_guess = 1;
+-	  d = grub_util_path_concat (2, bootdir, "macppc");
+-	  if (!grub_util_is_directory (d))
+-	    {
+-	      free (d);
+-	      d = grub_util_path_concat (2, bootdir, "efi");
+-	    }
+ 	  /* Find the Mac HFS(+) System Partition.  */
+-	  if (!grub_util_is_directory (d))
+-	    {
+-	      free (d);
+-	      d = grub_util_path_concat (2, bootdir, "EFI");
+-	    }
++	  d = grub_util_path_concat (2, bootdir, "macppc");
+ 	  if (!grub_util_is_directory (d))
+ 	    {
+ 	      free (d);
diff --git a/SOURCES/0054-Fix-up-some-man-pages-rpmdiff-noticed.patch b/SOURCES/0054-Fix-up-some-man-pages-rpmdiff-noticed.patch
deleted file mode 100644
index 8016a62..0000000
--- a/SOURCES/0054-Fix-up-some-man-pages-rpmdiff-noticed.patch
+++ /dev/null
@@ -1,150 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 23 Sep 2014 09:58:49 -0400
-Subject: [PATCH] Fix up some man pages rpmdiff noticed.
-
----
- configure.ac             |  2 ++
- util/grub-macbless.8     | 26 +++++++++++++++++++
- util/grub-mkimage.1      |  2 +-
- util/grub-syslinux2cfg.1 | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 94 insertions(+), 1 deletion(-)
- create mode 100644 util/grub-macbless.8
- create mode 100644 util/grub-syslinux2cfg.1
-
-diff --git a/configure.ac b/configure.ac
-index ed31ea457d2..537ed411469 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -87,6 +87,7 @@ grub_TRANSFORM([grub-get-kernel-settings.3])
- grub_TRANSFORM([grub-glue-efi.3])
- grub_TRANSFORM([grub-install.1])
- grub_TRANSFORM([grub-kbdcomp.3])
-+grub_TRANSFORM([grub-macbless.8])
- grub_TRANSFORM([grub-menulst2cfg.1])
- grub_TRANSFORM([grub-mkconfig.1])
- grub_TRANSFORM([grub-mkfont.3])
-@@ -105,6 +106,7 @@ grub_TRANSFORM([grub-render-label.3])
- grub_TRANSFORM([grub-script-check.3])
- grub_TRANSFORM([grub-set-default.1])
- grub_TRANSFORM([grub-sparc64-setup.3])
-+grub_TRANSFORM([grub-syslinux2cfg.1])
- 
- # Optimization flag.  Allow user to override.
- if test "x$TARGET_CFLAGS" = x; then
-diff --git a/util/grub-macbless.8 b/util/grub-macbless.8
-new file mode 100644
-index 00000000000..ae842f3a606
---- /dev/null
-+++ b/util/grub-macbless.8
-@@ -0,0 +1,26 @@
-+.TH GRUB-MACBLESS 1 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-macbless\fR \(em Mac-style bless utility for HFS or HFS+
-+
-+.SH SYNOPSIS
-+\fBgrub-macbless\fR [-p | --ppc] [-v | --verbose] [-x | --x86] \fIFILE\fR
-+
-+.SH DESCRIPTION
-+\fBgrub-mkimage\fR blesses a file on an HFS or HFS+ file system, so that it
-+can be used to boot a Mac.
-+
-+.SH OPTIONS
-+.TP
-+--ppc
-+Bless the file for use on PPC-based Macs.
-+
-+.TP
-+--verbose
-+Print verbose messages.
-+
-+.TP
-+--x86
-+Bless the file for use on x86-based Macs.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-mkimage.1 b/util/grub-mkimage.1
-index 4dea4f54597..0eaaafe505b 100644
---- a/util/grub-mkimage.1
-+++ b/util/grub-mkimage.1
-@@ -17,7 +17,7 @@
- [-v | --verbose] \fIMODULES\fR
- 
- .SH DESCRIPTION
--\fBgrub-mkimage\fI builds a bootable image of GRUB.
-+\fBgrub-mkimage\fR builds a bootable image of GRUB.
- 
- .SH OPTIONS
- .TP
-diff --git a/util/grub-syslinux2cfg.1 b/util/grub-syslinux2cfg.1
-new file mode 100644
-index 00000000000..85309482718
---- /dev/null
-+++ b/util/grub-syslinux2cfg.1
-@@ -0,0 +1,65 @@
-+.TH GRUB-SYSLINUX2CFG 1 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-syslinux2cfg\fR \(em Transform a syslinux config file into a GRUB config.
-+
-+.SH SYNOPSIS
-+\fBgrub-syslinux2cfg\fR [-c | --cwd=\fRDIR\fI] [-r | --root=\fIDIR\fR] [-v | --verbose]
-+.RE
-+.RS 25
-+[-t | --target-root=\fIDIR\fR] [-T | --target-cwd=\fIDIR\fR]
-+.RE
-+.RS 25
-+[-o | --output=\fIFILE\fR] [[-i | --isolinux] |
-+.RE
-+.RS 46
-+ [-s | --syslinux] |
-+.RE
-+.RS 46
-+ [-p | --pxelinux]] \fIFILE\fR
-+
-+.SH DESCRIPTION
-+\fBgrub-syslinux2cfg\fR builds a GRUB configuration file out of an existing
-+syslinux configuration file.
-+
-+.SH OPTIONS
-+.TP
-+--cwd=\fIDIR\fR
-+Set \fIDIR\fR as syslinux's working directory.  The default is to use the
-+parent directory of the input file.
-+
-+.TP
-+--root=\fIDIR\fR
-+Set \fIDIR\fR as the root directory of the syslinux disk.  The default value
-+is "/".
-+
-+.TP
-+--verbose
-+Print verbose messages.
-+
-+.TP
-+--target-root=\fIDIR\fR
-+Root directory as it will be seen at runtime.  The default value is "/".
-+
-+.TP
-+--target-cwd=\fIDIR\fR
-+Working directory of syslinux as it will be seen at runtime.  The default
-+value is the parent directory of the input file.
-+
-+.TP
-+--output=\fIFILE\fR
-+Write the new config file to \fIFILE\fR.  The default value is standard output.
-+
-+.TP
-+--isolinux
-+Assume that the input file is an isolinux configuration file.
-+
-+.TP
-+--pxelinux
-+Assume that the input file is a pxelinux configuration file.
-+
-+.TP
-+--syslinux
-+Assume that the input file is a syslinux configuration file.
-+
-+.SH SEE ALSO
-+.BR "info grub"
diff --git a/SOURCES/0055-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch b/SOURCES/0055-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch
new file mode 100644
index 0000000..cd58ff4
--- /dev/null
+++ b/SOURCES/0055-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch
@@ -0,0 +1,47 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 9 Jul 2019 14:31:19 +0200
+Subject: [PATCH] 20_linux_xen: load xen or multiboot{,2} modules as needed.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub.d/20_linux_xen.in | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in
+index e9e73b815f..c23b064be6 100644
+--- a/util/grub.d/20_linux_xen.in
++++ b/util/grub.d/20_linux_xen.in
+@@ -153,6 +153,7 @@ linux_entry_xsm ()
+         else
+             xen_rm_opts="no-real-mode edd=off"
+         fi
++	insmod ${xen_module}
+ 	${xen_loader}	${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} \${xen_rm_opts}
+ 	echo	'$(echo "$lmessage" | grub_quote)'
+ 	${module_loader}	${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args}
+@@ -166,6 +167,7 @@ EOF
+     done
+     sed "s/^/$submenu_indentation/" << EOF
+ 	echo	'$(echo "$message" | grub_quote)'
++	insmod ${xen_module}
+ 	${module_loader}	--nounzip   $(echo $initrd_path)
+ EOF
+   fi
+@@ -253,13 +255,16 @@ while [ "x${xen_list}" != "x" ] ; do
+ 	echo "	submenu '$(gettext_printf "Xen hypervisor, version %s" "${xen_version}" | grub_quote)' \$menuentry_id_option 'xen-hypervisor-$xen_version-$boot_device_id' {"
+     fi
+     if ($grub_file --is-arm64-efi $current_xen); then
++	xen_module="xen_boot"
+ 	xen_loader="xen_hypervisor"
+ 	module_loader="xen_module"
+     else
+ 	if ($grub_file --is-x86-multiboot2 $current_xen); then
++	    xen_module="multiboot2"
+ 	    xen_loader="multiboot2"
+ 	    module_loader="module2"
+ 	else
++	    xen_module="multiboot"
+ 	    xen_loader="multiboot"
+ 	    module_loader="module"
+         fi
diff --git a/SOURCES/0055-Make-our-info-pages-say-grub2-where-appropriate.patch b/SOURCES/0055-Make-our-info-pages-say-grub2-where-appropriate.patch
deleted file mode 100644
index be28efd..0000000
--- a/SOURCES/0055-Make-our-info-pages-say-grub2-where-appropriate.patch
+++ /dev/null
@@ -1,1008 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 9 Jul 2019 12:59:58 +0200
-Subject: [PATCH] Make our info pages say "grub2" where appropriate.
-
-This needs to be hooked up to --program-transform=, but I haven't had
-time.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- docs/grub-dev.texi |   4 +-
- docs/grub.texi     | 321 ++++++++++++++++++++++++++++-------------------------
- 2 files changed, 171 insertions(+), 154 deletions(-)
-
-diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
-index 6c629a23e2d..19f708ee662 100644
---- a/docs/grub-dev.texi
-+++ b/docs/grub-dev.texi
-@@ -1,7 +1,7 @@
- \input texinfo
- @c -*-texinfo-*-
- @c %**start of header
--@setfilename grub-dev.info
-+@setfilename grub2-dev.info
- @include version-dev.texi
- @settitle GNU GRUB Developers Manual @value{VERSION}
- @c Unify all our little indices for now.
-@@ -32,7 +32,7 @@ Invariant Sections.
- 
- @dircategory Kernel
- @direntry
--* grub-dev: (grub-dev).                 The GRand Unified Bootloader Dev
-+* grub2-dev: (grub2-dev).                 The GRand Unified Bootloader Dev
- @end direntry
- 
- @setchapternewpage odd
-diff --git a/docs/grub.texi b/docs/grub.texi
-index 69f08d289f9..0615d0ed97e 100644
---- a/docs/grub.texi
-+++ b/docs/grub.texi
-@@ -1,7 +1,7 @@
- \input texinfo
- @c -*-texinfo-*-
- @c %**start of header
--@setfilename grub.info
-+@setfilename grub2.info
- @include version.texi
- @settitle GNU GRUB Manual @value{VERSION}
- @c Unify all our little indices for now.
-@@ -32,15 +32,15 @@ Invariant Sections.
- 
- @dircategory Kernel
- @direntry
--* GRUB: (grub).                 The GRand Unified Bootloader
--* grub-install: (grub)Invoking grub-install.    Install GRUB on your drive
--* grub-mkconfig: (grub)Invoking grub-mkconfig.  Generate GRUB configuration
--* grub-mkpasswd-pbkdf2: (grub)Invoking grub-mkpasswd-pbkdf2.
--* grub-mkrelpath: (grub)Invoking grub-mkrelpath.
--* grub-mkrescue: (grub)Invoking grub-mkrescue.  Make a GRUB rescue image
--* grub-mount: (grub)Invoking grub-mount.        Mount a file system using GRUB
--* grub-probe: (grub)Invoking grub-probe.        Probe device information
--* grub-script-check: (grub)Invoking grub-script-check.
-+* GRUB2: (grub2).                 The GRand Unified Bootloader
-+* grub2-install: (grub2)Invoking grub2-install.    Install GRUB on your drive
-+* grub2-mkconfig: (grub2)Invoking grub2-mkconfig.  Generate GRUB configuration
-+* grub2-mkpasswd-pbkdf2: (grub2)Invoking grub2-mkpasswd-pbkdf2.
-+* grub2-mkrelpath: (grub2)Invoking grub2-mkrelpath.
-+* grub2-mkrescue: (grub2)Invoking grub2-mkrescue.  Make a GRUB rescue image
-+* grub2-mount: (grub2)Invoking grub2-mount.        Mount a file system using GRUB
-+* grub2-probe: (grub2)Invoking grub2-probe.        Probe device information
-+* grub2-script-check: (grub2)Invoking grub2-script-check.
- @end direntry
- 
- @setchapternewpage odd
-@@ -103,15 +103,15 @@ This edition documents version @value{VERSION}.
- * Platform-specific operations:: Platform-specific operations
- * Supported kernels::           The list of supported kernels
- * Troubleshooting::             Error messages produced by GRUB
--* Invoking grub-install::       How to use the GRUB installer
--* Invoking grub-mkconfig::      Generate a GRUB configuration file
--* Invoking grub-mkpasswd-pbkdf2::
-+* Invoking grub2-install::       How to use the GRUB installer
-+* Invoking grub2-mkconfig::      Generate a GRUB configuration file
-+* Invoking grub2-mkpasswd-pbkdf2::
-                                 Generate GRUB password hashes
--* Invoking grub-mkrelpath::     Make system path relative to its root
--* Invoking grub-mkrescue::      Make a GRUB rescue image
--* Invoking grub-mount::         Mount a file system using GRUB
--* Invoking grub-probe::         Probe device information for GRUB
--* Invoking grub-script-check::  Check GRUB script file for syntax errors
-+* Invoking grub2-mkrelpath::     Make system path relative to its root
-+* Invoking grub2-mkrescue::      Make a GRUB rescue image
-+* Invoking grub2-mount::         Mount a file system using GRUB
-+* Invoking grub2-probe::         Probe device information for GRUB
-+* Invoking grub2-script-check::  Check GRUB script file for syntax errors
- * Obtaining and Building GRUB:: How to obtain and build GRUB
- * Reporting bugs::              Where you should send a bug report
- * Future::                      Some future plans on GRUB
-@@ -230,7 +230,7 @@ surprising.
- 
- @item
- @file{grub.cfg} is typically automatically generated by
--@command{grub-mkconfig} (@pxref{Simple configuration}).  This makes it
-+@command{grub2-mkconfig} (@pxref{Simple configuration}).  This makes it
- easier to handle versioned kernel upgrades.
- 
- @item
-@@ -244,7 +244,7 @@ scripting language: variables, conditionals, and loops are available.
- @item
- A small amount of persistent storage is available across reboots, using the
- @command{save_env} and @command{load_env} commands in GRUB and the
--@command{grub-editenv} utility.  This is not available in all configurations
-+@command{grub2-editenv} utility.  This is not available in all configurations
- (@pxref{Environment block}).
- 
- @item
-@@ -549,7 +549,7 @@ On OS which have device nodes similar to Unix-like OS GRUB tools use the
- OS name. E.g. for GNU/Linux:
- 
- @example
--# @kbd{grub-install /dev/sda}
-+# @kbd{grub2-install /dev/sda}
- @end example
- 
- On AROS we use another syntax. For volumes:
-@@ -572,7 +572,7 @@ For disks we use syntax:
- E.g.
- 
- @example
--# @kbd{grub-install //:ata.device/0/0}
-+# @kbd{grub2-install //:ata.device/0/0}
- @end example
- 
- On Windows we use UNC path. For volumes it's typically
-@@ -599,7 +599,7 @@ For disks it's
- E.g.
- 
- @example
--# @kbd{grub-install \\?\PhysicalDrive0}
-+# @kbd{grub2-install \\?\PhysicalDrive0}
- @end example
- 
- Beware that you may need to further escape the backslashes depending on your
-@@ -609,7 +609,7 @@ When compiled with cygwin support then cygwin drive names are automatically
- when needed. E.g.
- 
- @example
--# @kbd{grub-install /dev/sda}
-+# @kbd{grub2-install /dev/sda}
- @end example
- 
- @node Installation
-@@ -622,7 +622,7 @@ from the source tarball, or as a package for your OS.
- 
- After you have done that, you need to install the boot loader on a
- drive (floppy or hard disk) by using the utility
--@command{grub-install} (@pxref{Invoking grub-install}) on a UNIX-like OS.
-+@command{grub2-install} (@pxref{Invoking grub2-install}) on a UNIX-like OS.
- 
- GRUB comes with boot images, which are normally put in the directory
- @file{/usr/lib/grub/<cpu>-<platform>} (for BIOS-based machines
-@@ -633,22 +633,22 @@ loader needs to find them (usually @file{/boot}) will be called
- the @dfn{boot directory}.
- 
- @menu
--* Installing GRUB using grub-install::
-+* Installing GRUB using grub2-install::
- * Making a GRUB bootable CD-ROM::
- * Device map::
- * BIOS installation::
- @end menu
- 
- 
--@node Installing GRUB using grub-install
--@section Installing GRUB using grub-install
-+@node Installing GRUB using grub2-install
-+@section Installing GRUB using grub2-install
- 
- For information on where GRUB should be installed on PC BIOS platforms,
- @pxref{BIOS installation}.
- 
- In order to install GRUB under a UNIX-like OS (such
--as @sc{gnu}), invoke the program @command{grub-install} (@pxref{Invoking
--grub-install}) as the superuser (@dfn{root}).
-+as @sc{gnu}), invoke the program @command{grub2-install} (@pxref{Invoking
-+grub2-install}) as the superuser (@dfn{root}).
- 
- The usage is basically very simple. You only need to specify one
- argument to the program, namely, where to install the boot loader. The
-@@ -657,13 +657,13 @@ For example, under Linux the following will install GRUB into the MBR
- of the first IDE disk:
- 
- @example
--# @kbd{grub-install /dev/sda}
-+# @kbd{grub2-install /dev/sda}
- @end example
- 
- Likewise, under GNU/Hurd, this has the same effect:
- 
- @example
--# @kbd{grub-install /dev/hd0}
-+# @kbd{grub2-install /dev/hd0}
- @end example
- 
- But all the above examples assume that GRUB should put images under
-@@ -677,7 +677,7 @@ boot floppy with a filesystem. Here is an example:
- # @kbd{mke2fs /dev/fd0}
- # @kbd{mount -t ext2 /dev/fd0 /mnt}
- # @kbd{mkdir /mnt/boot}
--# @kbd{grub-install --boot-directory=/mnt/boot /dev/fd0}
-+# @kbd{grub2-install --boot-directory=/mnt/boot /dev/fd0}
- # @kbd{umount /mnt}
- @end group
- @end example
-@@ -689,30 +689,37 @@ floppy instead of exposing the USB drive as a hard disk (they call it
- @example
- # @kbd{losetup /dev/loop0 /dev/sdb1}
- # @kbd{mount /dev/loop0 /mnt/usb}
--# @kbd{grub-install --boot-directory=/mnt/usb/bugbios --force --allow-floppy /dev/loop0}
-+# @kbd{grub2-install --boot-directory=/mnt/usb/bugbios --force --allow-floppy /dev/loop0}
- @end example
- 
- This install doesn't conflict with standard install as long as they are in
- separate directories.
- 
-+Note that @command{grub2-install} is actually just a shell script and the
-+real task is done by other tools such as @command{grub2-mkimage}. Therefore,
-+you may run those commands directly to install GRUB, without using
-+@command{grub2-install}. Don't do that, however, unless you are very familiar
-+with the internals of GRUB. Installing a boot loader on a running OS may be
-+extremely dangerous.
-+
- On EFI systems for fixed disk install you have to mount EFI System Partition.
- If you mount it at @file{/boot/efi} then you don't need any special arguments:
- 
- @example
--# @kbd{grub-install}
-+# @kbd{grub2-install}
- @end example
- 
- Otherwise you need to specify where your EFI System partition is mounted:
- 
- @example
--# @kbd{grub-install --efi-directory=/mnt/efi}
-+# @kbd{grub2-install --efi-directory=/mnt/efi}
- @end example
- 
- For removable installs you have to use @option{--removable} and specify both
- @option{--boot-directory} and @option{--efi-directory}:
- 
- @example
--# @kbd{grub-install --efi-directory=/mnt/usb --boot-directory=/mnt/usb/boot --removable}
-+# @kbd{grub2-install --efi-directory=/mnt/usb --boot-directory=/mnt/usb/boot --removable}
- @end example
- 
- @node Making a GRUB bootable CD-ROM
-@@ -732,10 +739,10 @@ usually also need to include a configuration file @file{grub.cfg} and some
- other GRUB modules.
- 
- To make a simple generic GRUB rescue CD, you can use the
--@command{grub-mkrescue} program (@pxref{Invoking grub-mkrescue}):
-+@command{grub2-mkrescue} program (@pxref{Invoking grub2-mkrescue}):
- 
- @example
--$ @kbd{grub-mkrescue -o grub.iso}
-+$ @kbd{grub2-mkrescue -o grub.iso}
- @end example
- 
- You will often need to include other files in your image. To do this, first
-@@ -758,7 +765,7 @@ directory @file{iso/}.
- Finally, make the image:
- 
- @example
--$ @kbd{grub-mkrescue -o grub.iso iso}
-+$ @kbd{grub2-mkrescue -o grub.iso iso}
- @end example
- 
- This produces a file named @file{grub.iso}, which then can be burned
-@@ -774,7 +781,7 @@ storage devices.
- @node Device map
- @section The map between BIOS drives and OS devices
- 
--If the device map file exists, the GRUB utilities (@command{grub-probe},
-+If the device map file exists, the GRUB utilities (@command{grub2-probe},
- etc.) read it to map BIOS drives to OS devices.  This file consists of lines
- like this:
- 
-@@ -1254,23 +1261,23 @@ need to write the whole thing by hand.
- @node Simple configuration
- @section Simple configuration handling
- 
--The program @command{grub-mkconfig} (@pxref{Invoking grub-mkconfig})
-+The program @command{grub2-mkconfig} (@pxref{Invoking grub2-mkconfig})
- generates @file{grub.cfg} files suitable for most cases.  It is suitable for
- use when upgrading a distribution, and will discover available kernels and
- attempt to generate menu entries for them.
- 
--@command{grub-mkconfig} does have some limitations.  While adding extra
-+@command{grub2-mkconfig} does have some limitations.  While adding extra
- custom menu entries to the end of the list can be done by editing
--@file{/etc/grub.d/40_custom} or creating @file{/boot/grub/custom.cfg},
-+@file{/etc/grub.d/40_custom} or creating @file{/boot/grub2/custom.cfg},
- changing the order of menu entries or changing their titles may require
- making complex changes to shell scripts stored in @file{/etc/grub.d/}.  This
- may be improved in the future.  In the meantime, those who feel that it
- would be easier to write @file{grub.cfg} directly are encouraged to do so
- (@pxref{Booting}, and @ref{Shell-like scripting}), and to disable any system
--provided by their distribution to automatically run @command{grub-mkconfig}.
-+provided by their distribution to automatically run @command{grub2-mkconfig}.
- 
- The file @file{/etc/default/grub} controls the operation of
--@command{grub-mkconfig}.  It is sourced by a shell script, and so must be
-+@command{grub2-mkconfig}.  It is sourced by a shell script, and so must be
- valid POSIX shell input; normally, it will just be a sequence of
- @samp{KEY=value} lines, but if the value contains spaces or other special
- characters then it must be quoted.  For example:
-@@ -1308,7 +1315,7 @@ works it's not recommended since titles often contain unstable device names
- and may be translated
- 
- If you set this to @samp{saved}, then the default menu entry will be that
--saved by @samp{GRUB_SAVEDEFAULT} or @command{grub-set-default}.  This relies on
-+saved by @samp{GRUB_SAVEDEFAULT} or @command{grub2-set-default}.  This relies on
- the environment block, which may not be available in all situations
- (@pxref{Environment block}).
- 
-@@ -1319,7 +1326,7 @@ If this option is set to @samp{true}, then, when an entry is selected, save
- it as a new default entry for use by future runs of GRUB.  This is only
- useful if @samp{GRUB_DEFAULT=saved}; it is a separate option because
- @samp{GRUB_DEFAULT=saved} is useful without this option, in conjunction with
--@command{grub-set-default}.  Unset by default.
-+@command{grub2-set-default}.  Unset by default.
- This option relies on the environment block, which may not be available in
- all situations (@pxref{Environment block}).
- 
-@@ -1449,7 +1456,7 @@ intel-uc.img intel-ucode.img amd-uc.img amd-ucode.img early_ucode.cpio microcode
- @end example
- 
- @item GRUB_DISABLE_LINUX_UUID
--Normally, @command{grub-mkconfig} will generate menu entries that use
-+Normally, @command{grub2-mkconfig} will generate menu entries that use
- universally-unique identifiers (UUIDs) to identify the root filesystem to
- the Linux kernel, using a @samp{root=UUID=...} kernel parameter.  This is
- usually more reliable, but in some cases it may not be appropriate.  To
-@@ -1471,7 +1478,7 @@ If this option is set to @samp{true}, disable the generation of recovery
- mode menu entries.
- 
- @item GRUB_DISABLE_UUID
--Normally, @command{grub-mkconfig} will generate menu entries that use
-+Normally, @command{grub2-mkconfig} will generate menu entries that use
- universally-unique identifiers (UUIDs) to identify various filesystems to
- search for files.  This is usually more reliable, but in some cases it may
- not be appropriate.  To disable this use of UUIDs, set this option to
-@@ -1482,12 +1489,12 @@ not be appropriate.  To disable this use of UUIDs, set this option to
- @item GRUB_VIDEO_BACKEND
- If graphical video support is required, either because the @samp{gfxterm}
- graphical terminal is in use or because @samp{GRUB_GFXPAYLOAD_LINUX} is set,
--then @command{grub-mkconfig} will normally load all available GRUB video
-+then @command{grub2-mkconfig} will normally load all available GRUB video
- drivers and use the one most appropriate for your hardware.  If you need to
- override this for some reason, then you can set this option.
- 
--After @command{grub-install} has been run, the available video drivers are
--listed in @file{/boot/grub/video.lst}.
-+After @command{grub2-install} has been run, the available video drivers are
-+listed in @file{/boot/grub2/video.lst}.
- 
- @item GRUB_GFXMODE
- Set the resolution used on the @samp{gfxterm} graphical terminal.  Note that
-@@ -1519,7 +1526,7 @@ boot sequence.  If you have problems, set this option to @samp{text} and
- GRUB will tell Linux to boot in normal text mode.
- 
- @item GRUB_DISABLE_OS_PROBER
--Normally, @command{grub-mkconfig} will try to use the external
-+Normally, @command{grub2-mkconfig} will try to use the external
- @command{os-prober} program, if installed, to discover other operating
- systems installed on the same system and generate appropriate menu entries
- for them.  Set this option to @samp{true} to disable this.
-@@ -1529,7 +1536,7 @@ List of space-separated FS UUIDs of filesystems to be ignored from os-prober
- output. For efi chainloaders it's <UUID>@@<EFI FILE>
- 
- @item GRUB_DISABLE_SUBMENU
--Normally, @command{grub-mkconfig} will generate top level menu entry for
-+Normally, @command{grub2-mkconfig} will generate top level menu entry for
- the kernel with highest version number and put all other found kernels
- or alternative menu entries for recovery mode in submenu. For entries returned
- by @command{os-prober} first entry will be put on top level and all others
-@@ -1537,11 +1544,11 @@ in submenu. If this option is set to @samp{true}, flat menu with all entries
- on top level will be generated instead. Changing this option will require
- changing existing values of @samp{GRUB_DEFAULT}, @samp{fallback} (@pxref{fallback})
- and @samp{default} (@pxref{default}) environment variables as well as saved
--default entry using @command{grub-set-default} and value used with
--@command{grub-reboot}.
-+default entry using @command{grub2-set-default} and value used with
-+@command{grub2-reboot}.
- 
- @item GRUB_ENABLE_CRYPTODISK
--If set to @samp{y}, @command{grub-mkconfig} and @command{grub-install} will
-+If set to @samp{y}, @command{grub2-mkconfig} and @command{grub2-install} will
- check for encrypted disks and generate additional commands needed to access
- them during boot.  Note that in this case unattended boot is not possible
- because GRUB will wait for passphrase to unlock encrypted container.
-@@ -1600,7 +1607,7 @@ confusing @samp{GRUB_TIMEOUT_STYLE=countdown} or
- 
- @end table
- 
--For more detailed customisation of @command{grub-mkconfig}'s output, you may
-+For more detailed customisation of @command{grub2-mkconfig}'s output, you may
- edit the scripts in @file{/etc/grub.d} directly.
- @file{/etc/grub.d/40_custom} is particularly useful for adding entire custom
- menu entries; simply type the menu entries you want to add at the end of
-@@ -1862,7 +1869,7 @@ images as well.
- Mount this partition on/mnt/boot and disable GRUB in all OSes and manually
- install self-compiled latest GRUB with:
- 
--@code{grub-install --boot-directory=/mnt/boot /dev/sda}
-+@code{grub2-install --boot-directory=/mnt/boot /dev/sda}
- 
- In all the OSes install GRUB tools but disable installing GRUB in bootsector,
- so you'll have menu.lst and grub.cfg available for use. Also disable os-prober
-@@ -1872,20 +1879,20 @@ use by setting:
- 
- in /etc/default/grub
- 
--Then write a grub.cfg (/mnt/boot/grub/grub.cfg):
-+Then write a grub.cfg (/mnt/boot/grub2/grub.cfg):
- 
- @example
- 
- menuentry "OS using grub2" @{
-    insmod xfs
-    search --set=root --label OS1 --hint hd0,msdos8
--   configfile /boot/grub/grub.cfg
-+   configfile /boot/grub2/grub.cfg
- @}
- 
- menuentry "OS using grub2-legacy" @{
-    insmod ext2
-    search --set=root --label OS2 --hint hd0,msdos6
--   legacy_configfile /boot/grub/menu.lst
-+   legacy_configfile /boot/grub2/menu.lst
- @}
- 
- menuentry "Windows XP" @{
-@@ -1948,15 +1955,15 @@ GRUB supports embedding a configuration file directly into the core image,
- so that it is loaded before entering normal mode.  This is useful, for
- example, when it is not straightforward to find the real configuration file,
- or when you need to debug problems with loading that file.
--@command{grub-install} uses this feature when it is not using BIOS disk
-+@command{grub2-install} uses this feature when it is not using BIOS disk
- functions or when installing to a different disk from the one containing
- @file{/boot/grub}, in which case it needs to use the @command{search}
- command (@pxref{search}) to find @file{/boot/grub}.
- 
- To embed a configuration file, use the @option{-c} option to
--@command{grub-mkimage}.  The file is copied into the core image, so it may
-+@command{grub2-mkimage}.  The file is copied into the core image, so it may
- reside anywhere on the file system, and may be removed after running
--@command{grub-mkimage}.
-+@command{grub2-mkimage}.
- 
- After the embedded configuration file (if any) is executed, GRUB will load
- the @samp{normal} module (@pxref{normal}), which will then read the real
-@@ -1991,13 +1998,13 @@ included in the core image:
- @example
- @group
- search.fs_label grub root
--if [ -e /boot/grub/example/test1.cfg ]; then
-+if [ -e /boot/grub2/example/test1.cfg ]; then
-     set prefix=($root)/boot/grub
--    configfile /boot/grub/example/test1.cfg
-+    configfile /boot/grub2/example/test1.cfg
- else
--    if [ -e /boot/grub/example/test2.cfg ]; then
-+    if [ -e /boot/grub2/example/test2.cfg ]; then
-         set prefix=($root)/boot/grub
--        configfile /boot/grub/example/test2.cfg
-+        configfile /boot/grub2/example/test2.cfg
-     else
-         echo "Could not find an example configuration file!"
-     fi
-@@ -2521,7 +2528,7 @@ grub-mknetdir --net-directory=/srv/tftp --subdir=/boot/grub -d /usr/lib/grub/i38
- @end group
- @end example
- 
--Then follow instructions printed out by grub-mknetdir on configuring your DHCP
-+Then follow instructions printed out by grub2-mknetdir on configuring your DHCP
- server.
- 
- The grub.cfg file is placed in the same directory as the path output by
-@@ -2715,7 +2722,7 @@ team are:
- @end table
- 
- To take full advantage of this function, install GRUB into the MBR
--(@pxref{Installing GRUB using grub-install}).
-+(@pxref{Installing GRUB using grub2-install}).
- 
- If you have a laptop which has a similar feature and not in the above list
- could you figure your address and contribute?
-@@ -2776,7 +2783,7 @@ bytes.
- The sole function of @file{boot.img} is to read the first sector of the core
- image from a local disk and jump to it.  Because of the size restriction,
- @file{boot.img} cannot understand any file system structure, so
--@command{grub-install} hardcodes the location of the first sector of the
-+@command{grub2-install} hardcodes the location of the first sector of the
- core image into @file{boot.img} when installing GRUB.
- 
- @item diskboot.img
-@@ -2806,7 +2813,7 @@ images.
- 
- @item core.img
- This is the core image of GRUB.  It is built dynamically from the kernel
--image and an arbitrary list of modules by the @command{grub-mkimage}
-+image and an arbitrary list of modules by the @command{grub2-mkimage}
- program.  Usually, it contains enough modules to access @file{/boot/grub},
- and loads everything else (including menu handling, the ability to load
- target operating systems, and so on) from the file system at run-time.  The
-@@ -2858,7 +2865,7 @@ GRUB 2 has no single Stage 2 image.  Instead, it loads modules from
- In GRUB 2, images for booting from CD-ROM drives are now constructed using
- @file{cdboot.img} and @file{core.img}, making sure that the core image
- contains the @samp{iso9660} module.  It is usually best to use the
--@command{grub-mkrescue} program for this.
-+@command{grub2-mkrescue} program for this.
- 
- @item nbgrub
- There is as yet no equivalent for @file{nbgrub} in GRUB 2; it was used by
-@@ -3014,8 +3021,8 @@ There are two ways to specify files, by @dfn{absolute file name} and by
- 
- An absolute file name resembles a Unix absolute file name, using
- @samp{/} for the directory separator (not @samp{\} as in DOS). One
--example is @samp{(hd0,1)/boot/grub/grub.cfg}. This means the file
--@file{/boot/grub/grub.cfg} in the first partition of the first hard
-+example is @samp{(hd0,1)/boot/grub2/grub.cfg}. This means the file
-+@file{/boot/grub2/grub.cfg} in the first partition of the first hard
- disk. If you omit the device name in an absolute file name, GRUB uses
- GRUB's @dfn{root device} implicitly. So if you set the root device to,
- say, @samp{(hd1,1)} by the command @samp{set root=(hd1,1)} (@pxref{set}),
-@@ -3023,8 +3030,8 @@ then @code{/boot/kernel} is the same as @code{(hd1,1)/boot/kernel}.
- 
- On ZFS filesystem the first path component must be
- @var{volume}@samp{@@}[@var{snapshot}].
--So @samp{/rootvol@@snap-129/boot/grub/grub.cfg} refers to file
--@samp{/boot/grub/grub.cfg} in snapshot of volume @samp{rootvol} with name
-+So @samp{/rootvol@@snap-129/boot/grub2/grub.cfg} refers to file
-+@samp{/boot/grub2/grub.cfg} in snapshot of volume @samp{rootvol} with name
- @samp{snap-129}.  Trailing @samp{@@} after volume name is mandatory even if
- snapshot name is omitted.
- 
-@@ -3427,7 +3434,7 @@ The more recent release of Minix would then be identified as
- @samp{other>minix>minix-3.4.0}.
- 
- This variable is often set by @samp{GRUB_DEFAULT} (@pxref{Simple
--configuration}), @command{grub-set-default}, or @command{grub-reboot}.
-+configuration}), @command{grub2-set-default}, or @command{grub2-reboot}.
- 
- 
- @node fallback
-@@ -3517,7 +3524,7 @@ If this variable is set, it names the language code that the
- example, French would be named as @samp{fr}, and Simplified Chinese as
- @samp{zh_CN}.
- 
--@command{grub-mkconfig} (@pxref{Simple configuration}) will try to set a
-+@command{grub2-mkconfig} (@pxref{Simple configuration}) will try to set a
- reasonable default for this variable based on the system locale.
- 
- 
-@@ -3525,10 +3532,10 @@ reasonable default for this variable based on the system locale.
- @subsection locale_dir
- 
- If this variable is set, it names the directory where translation files may
--be found (@pxref{gettext}), usually @file{/boot/grub/locale}.  Otherwise,
-+be found (@pxref{gettext}), usually @file{/boot/grub2/locale}.  Otherwise,
- internationalization is disabled.
- 
--@command{grub-mkconfig} (@pxref{Simple configuration}) will set a reasonable
-+@command{grub2-mkconfig} (@pxref{Simple configuration}) will set a reasonable
- default for this variable if internationalization is needed and any
- translation files are available.
- 
-@@ -3646,7 +3653,7 @@ input.  The default is not to pause output.
- 
- The location of the @samp{/boot/grub} directory as an absolute file name
- (@pxref{File name syntax}).  This is normally set by GRUB at startup based
--on information provided by @command{grub-install}.  GRUB modules are
-+on information provided by @command{grub2-install}.  GRUB modules are
- dynamically loaded from this directory, so it must be set correctly in order
- for many parts of GRUB to work.
- 
-@@ -3737,17 +3744,17 @@ GRUB provides an ``environment block'' which can be used to save a small
- amount of state.
- 
- The environment block is a preallocated 1024-byte file, which normally lives
--in @file{/boot/grub/grubenv} (although you should not assume this).  At boot
-+in @file{/boot/grub2/grubenv} (although you should not assume this).  At boot
- time, the @command{load_env} command (@pxref{load_env}) loads environment
- variables from it, and the @command{save_env} (@pxref{save_env}) command
- saves environment variables to it.  From a running system, the
--@command{grub-editenv} utility can be used to edit the environment block.
-+@command{grub2-editenv} utility can be used to edit the environment block.
- 
- For safety reasons, this storage is only available when installed on a plain
- disk (no LVM or RAID), using a non-checksumming filesystem (no ZFS), and
- using BIOS or EFI functions (no ATA, USB or IEEE1275).
- 
--@command{grub-mkconfig} uses this facility to implement
-+@command{grub2-mkconfig} uses this facility to implement
- @samp{GRUB_SAVEDEFAULT} (@pxref{Simple configuration}).
- 
- 
-@@ -4476,7 +4483,7 @@ Translate @var{string} into the current language.
- 
- The current language code is stored in the @samp{lang} variable in GRUB's
- environment (@pxref{lang}).  Translation files in MO format are read from
--@samp{locale_dir} (@pxref{locale_dir}), usually @file{/boot/grub/locale}.
-+@samp{locale_dir} (@pxref{locale_dir}), usually @file{/boot/grub2/locale}.
- @end deffn
- 
- 
-@@ -4871,7 +4878,7 @@ Define a user named @var{user} with password @var{clear-password}.
- 
- @deffn Command password_pbkdf2 user hashed-password
- Define a user named @var{user} with password hash @var{hashed-password}.
--Use @command{grub-mkpasswd-pbkdf2} (@pxref{Invoking grub-mkpasswd-pbkdf2})
-+Use @command{grub2-mkpasswd-pbkdf2} (@pxref{Invoking grub2-mkpasswd-pbkdf2})
- to generate password hashes.  @xref{Security}.
- @end deffn
- 
-@@ -5814,8 +5821,8 @@ The @samp{password} (@pxref{password}) and @samp{password_pbkdf2}
- which has an associated password.  @samp{password} sets the password in
- plain text, requiring @file{grub.cfg} to be secure; @samp{password_pbkdf2}
- sets the password hashed using the Password-Based Key Derivation Function
--(RFC 2898), requiring the use of @command{grub-mkpasswd-pbkdf2}
--(@pxref{Invoking grub-mkpasswd-pbkdf2}) to generate password hashes.
-+(RFC 2898), requiring the use of @command{grub2-mkpasswd-pbkdf2}
-+(@pxref{Invoking grub2-mkpasswd-pbkdf2}) to generate password hashes.
- 
- In order to enable authentication support, the @samp{superusers} environment
- variable must be set to a list of usernames, separated by any of spaces,
-@@ -5860,7 +5867,7 @@ menuentry "May be run by user1 or a superuser" --users user1 @{
- @end group
- @end example
- 
--The @command{grub-mkconfig} program does not yet have built-in support for
-+The @command{grub2-mkconfig} program does not yet have built-in support for
- generating configuration files with authentication.  You can use
- @file{/etc/grub.d/40_custom} to add simple superuser authentication, by
- adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2}
-@@ -5887,7 +5894,17 @@ may halt or otherwise impact the boot process.
- 
- An initial trusted public key can be embedded within the GRUB @file{core.img}
- using the @code{--pubkey} option to @command{grub-install}
--(@pxref{Invoking grub-install}).
-+(@pxref{Invoking grub2-install}).
-+
-+@comment Unfortunately --pubkey is not yet supported by grub2-install,
-+@comment but we should not bring up internal detail grub2-mkimage here
-+@comment in the user guide (as opposed to developer's manual).
-+
-+@comment An initial trusted public key can be embedded within the GRUB
-+@comment @file{core.img} using the @code{--pubkey} option to
-+@comment @command{grub2-mkimage} (@pxref{Invoking grub2-install}).  Presently it
-+@comment is necessary to write a custom wrapper around @command{grub2-mkimage}
-+@comment using the @code{--grub-mkimage} flag to @command{grub2-install}.
- 
- GRUB uses GPG-style detached signatures (meaning that a file
- @file{foo.sig} will be produced when file @file{foo} is signed), and
-@@ -5907,8 +5924,8 @@ gpg --detach-sign /path/to/file
- For successful validation of all of GRUB's subcomponents and the
- loaded OS kernel, they must all be signed.  One way to accomplish this
- is the following (after having already produced the desired
--@file{grub.cfg} file, e.g., by running @command{grub-mkconfig}
--(@pxref{Invoking grub-mkconfig}):
-+@file{grub.cfg} file, e.g., by running @command{grub2-mkconfig}
-+(@pxref{Invoking grub2-mkconfig}):
- 
- @example
- @group
-@@ -5930,7 +5947,7 @@ See also: @ref{check_signatures}, @ref{verify_detached}, @ref{trust},
- Note that internally signature enforcement is controlled by setting
- the environment variable @code{check_signatures} equal to
- @code{enforce}.  Passing one or more @code{--pubkey} options to
--@command{grub-mkimage} implicitly defines @code{check_signatures}
-+@command{grub2-mkimage} implicitly defines @code{check_signatures}
- equal to @code{enforce} in @file{core.img} prior to processing any
- configuration files.
- 
-@@ -6388,10 +6405,10 @@ Required files are:
- 
- GRUB's normal start-up procedure involves setting the @samp{prefix}
- environment variable to a value set in the core image by
--@command{grub-install}, setting the @samp{root} variable to match, loading
-+@command{grub2-install}, setting the @samp{root} variable to match, loading
- the @samp{normal} module from the prefix, and running the @samp{normal}
- command (@pxref{normal}).  This command is responsible for reading
--@file{/boot/grub/grub.cfg}, running the menu, and doing all the useful
-+@file{/boot/grub2/grub.cfg}, running the menu, and doing all the useful
- things GRUB is supposed to do.
- 
- If, instead, you only get a rescue shell, this usually means that GRUB
-@@ -6417,8 +6434,8 @@ normal
- 
- However, any problem that leaves you in the rescue shell probably means that
- GRUB was not correctly installed.  It may be more useful to try to reinstall
--it properly using @kbd{grub-install @var{device}} (@pxref{Invoking
--grub-install}).  When doing this, there are a few things to remember:
-+it properly using @kbd{grub2-install @var{device}} (@pxref{Invoking
-+grub2-install}).  When doing this, there are a few things to remember:
- 
- @itemize @bullet{}
- @item
-@@ -6430,7 +6447,7 @@ is usually better to use UUIDs or file system labels and avoid depending on
- drive ordering entirely.
- 
- @item
--At least on BIOS systems, if you tell @command{grub-install} to install GRUB
-+At least on BIOS systems, if you tell @command{grub2-install} to install GRUB
- to a partition but GRUB has already been installed in the master boot
- record, then the GRUB installation in the partition will be ignored.
- 
-@@ -6461,21 +6478,21 @@ entry which claims partition start at block 0. This change will not hamper
- bootability on other machines.
- 
- 
--@node Invoking grub-install
--@chapter Invoking grub-install
-+@node Invoking grub2-install
-+@chapter Invoking grub2-install
- 
--The program @command{grub-install} generates a GRUB core image using
--@command{grub-mkimage} and installs it on your system.  You must specify the
-+The program @command{grub2-install} generates a GRUB core image using
-+@command{grub2-mkimage} and installs it on your system.  You must specify the
- device name on which you want to install GRUB, like this:
- 
- @example
--grub-install @var{install_device}
-+grub2-install @var{install_device}
- @end example
- 
- The device name @var{install_device} is an OS device name or a GRUB
- device name.
- 
--@command{grub-install} accepts the following options:
-+@command{grub2-install} accepts the following options:
- 
- @table @option
- @item --help
-@@ -6491,13 +6508,13 @@ separate partition or a removable disk.
- If this option is not specified then it defaults to @file{/boot}, so
- 
- @example
--@kbd{grub-install /dev/sda}
-+@kbd{grub2-install /dev/sda}
- @end example
- 
- is equivalent to
- 
- @example
--@kbd{grub-install --boot-directory=/boot/ /dev/sda}
-+@kbd{grub2-install --boot-directory=/boot/ /dev/sda}
- @end example
- 
- Here is an example in which you have a separate @dfn{boot} partition which is 
-@@ -6505,16 +6522,16 @@ mounted on
- @file{/mnt/boot}:
- 
- @example
--@kbd{grub-install --boot-directory=/mnt/boot /dev/sdb}
-+@kbd{grub2-install --boot-directory=/mnt/boot /dev/sdb}
- @end example
- 
- @item --recheck
--Recheck the device map, even if @file{/boot/grub/device.map} already
-+Recheck the device map, even if @file{/boot/grub2/device.map} already
- exists. You should use this option whenever you add/remove a disk
- into/from your computer.
- 
- @item --no-rs-codes
--By default on x86 BIOS systems, @command{grub-install} will use some
-+By default on x86 BIOS systems, @command{grub2-install} will use some
- extra space in the bootloader embedding area for Reed-Solomon
- error-correcting codes. This enables GRUB to still boot successfully
- if some blocks are corrupted.  The exact amount of protection offered
-@@ -6527,17 +6544,17 @@ installation}) where GRUB does not reside in any unpartitioned space
- outside of the MBR.  Disable the Reed-Solomon codes with this option.
- @end table
- 
--@node Invoking grub-mkconfig
--@chapter Invoking grub-mkconfig
-+@node Invoking grub2-mkconfig
-+@chapter Invoking grub2-mkconfig
- 
--The program @command{grub-mkconfig} generates a configuration file for GRUB
-+The program @command{grub2-mkconfig} generates a configuration file for GRUB
- (@pxref{Simple configuration}).
- 
- @example
--grub-mkconfig -o /boot/grub/grub.cfg
-+grub-mkconfig -o /boot/grub2/grub.cfg
- @end example
- 
--@command{grub-mkconfig} accepts the following options:
-+@command{grub2-mkconfig} accepts the following options:
- 
- @table @option
- @item --help
-@@ -6553,17 +6570,17 @@ it to standard output.
- @end table
- 
- 
--@node Invoking grub-mkpasswd-pbkdf2
--@chapter Invoking grub-mkpasswd-pbkdf2
-+@node Invoking grub2-mkpasswd-pbkdf2
-+@chapter Invoking grub2-mkpasswd-pbkdf2
- 
--The program @command{grub-mkpasswd-pbkdf2} generates password hashes for
-+The program @command{grub2-mkpasswd-pbkdf2} generates password hashes for
- GRUB (@pxref{Security}).
- 
- @example
- grub-mkpasswd-pbkdf2
- @end example
- 
--@command{grub-mkpasswd-pbkdf2} accepts the following options:
-+@command{grub2-mkpasswd-pbkdf2} accepts the following options:
- 
- @table @option
- @item -c @var{number}
-@@ -6581,23 +6598,23 @@ Length of the salt.  Defaults to 64.
- @end table
- 
- 
--@node Invoking grub-mkrelpath
--@chapter Invoking grub-mkrelpath
-+@node Invoking grub2-mkrelpath
-+@chapter Invoking grub2-mkrelpath
- 
--The program @command{grub-mkrelpath} makes a file system path relative to
-+The program @command{grub2-mkrelpath} makes a file system path relative to
- the root of its containing file system.  For instance, if @file{/usr} is a
- mount point, then:
- 
- @example
--$ @kbd{grub-mkrelpath /usr/share/grub/unicode.pf2}
-+$ @kbd{grub2-mkrelpath /usr/share/grub/unicode.pf2}
- @samp{/share/grub/unicode.pf2}
- @end example
- 
- This is mainly used internally by other GRUB utilities such as
--@command{grub-mkconfig} (@pxref{Invoking grub-mkconfig}), but may
-+@command{grub2-mkconfig} (@pxref{Invoking grub2-mkconfig}), but may
- occasionally also be useful for debugging.
- 
--@command{grub-mkrelpath} accepts the following options:
-+@command{grub2-mkrelpath} accepts the following options:
- 
- @table @option
- @item --help
-@@ -6608,17 +6625,17 @@ Print the version number of GRUB and exit.
- @end table
- 
- 
--@node Invoking grub-mkrescue
--@chapter Invoking grub-mkrescue
-+@node Invoking grub2-mkrescue
-+@chapter Invoking grub2-mkrescue
- 
--The program @command{grub-mkrescue} generates a bootable GRUB rescue image
-+The program @command{grub2-mkrescue} generates a bootable GRUB rescue image
- (@pxref{Making a GRUB bootable CD-ROM}).
- 
- @example
- grub-mkrescue -o grub.iso
- @end example
- 
--All arguments not explicitly listed as @command{grub-mkrescue} options are
-+All arguments not explicitly listed as @command{grub2-mkrescue} options are
- passed on directly to @command{xorriso} in @command{mkisofs} emulation mode.
- Options passed to @command{xorriso} will normally be interpreted as
- @command{mkisofs} options; if the option @samp{--} is used, then anything
-@@ -6633,7 +6650,7 @@ mkdir -p disk/boot/grub
- grub-mkrescue -o grub.iso disk
- @end example
- 
--@command{grub-mkrescue} accepts the following options:
-+@command{grub2-mkrescue} accepts the following options:
- 
- @table @option
- @item --help
-@@ -6661,15 +6678,15 @@ Use @var{file} as the @command{xorriso} program, rather than the built-in
- default.
- 
- @item --grub-mkimage=@var{file}
--Use @var{file} as the @command{grub-mkimage} program, rather than the
-+Use @var{file} as the @command{grub2-mkimage} program, rather than the
- built-in default.
- @end table
- 
- 
--@node Invoking grub-mount
--@chapter Invoking grub-mount
-+@node Invoking grub2-mount
-+@chapter Invoking grub2-mount
- 
--The program @command{grub-mount} performs a read-only mount of any file
-+The program @command{grub2-mount} performs a read-only mount of any file
- system or file system image that GRUB understands, using GRUB's file system
- drivers via FUSE.  (It is only available if FUSE development files were
- present when GRUB was built.)  This has a number of uses:
-@@ -6701,13 +6718,13 @@ even if nobody has yet written a FUSE module specifically for that file
- system type.
- @end itemize
- 
--Using @command{grub-mount} is normally as simple as:
-+Using @command{grub2-mount} is normally as simple as:
- 
- @example
- grub-mount /dev/sda1 /mnt
- @end example
- 
--@command{grub-mount} must be given one or more images and a mount point as
-+@command{grub2-mount} must be given one or more images and a mount point as
- non-option arguments (if it is given more than one image, it will treat them
- as a RAID set), and also accepts the following options:
- 
-@@ -6729,13 +6746,13 @@ Show debugging output for conditions matching @var{string}.
- @item -K prompt|@var{file}
- @itemx --zfs-key=prompt|@var{file}
- Load a ZFS encryption key.  If you use @samp{prompt} as the argument,
--@command{grub-mount} will read a passphrase from the terminal; otherwise, it
-+@command{grub2-mount} will read a passphrase from the terminal; otherwise, it
- will read key material from the specified file.
- 
- @item -r @var{device}
- @itemx --root=@var{device}
- Set the GRUB root device to @var{device}.  You do not normally need to set
--this; @command{grub-mount} will automatically set the root device to the
-+this; @command{grub2-mount} will automatically set the root device to the
- root of the supplied file system.
- 
- If @var{device} is just a number, then it will be treated as a partition
-@@ -6753,10 +6770,10 @@ Print verbose messages.
- @end table
- 
- 
--@node Invoking grub-probe
--@chapter Invoking grub-probe
-+@node Invoking grub2-probe
-+@chapter Invoking grub2-probe
- 
--The program @command{grub-probe} probes device information for a given path
-+The program @command{grub2-probe} probes device information for a given path
- or device.
- 
- @example
-@@ -6764,7 +6781,7 @@ grub-probe --target=fs /boot/grub
- grub-probe --target=drive --device /dev/sda1
- @end example
- 
--@command{grub-probe} must be given a path or device as a non-option
-+@command{grub2-probe} must be given a path or device as a non-option
- argument, and also accepts the following options:
- 
- @table @option
-@@ -6777,16 +6794,16 @@ Print the version number of GRUB and exit.
- @item -d
- @itemx --device
- If this option is given, then the non-option argument is a system device
--name (such as @samp{/dev/sda1}), and @command{grub-probe} will print
-+name (such as @samp{/dev/sda1}), and @command{grub2-probe} will print
- information about that device.  If it is not given, then the non-option
- argument is a filesystem path (such as @samp{/boot/grub}), and
--@command{grub-probe} will print information about the device containing that
-+@command{grub2-probe} will print information about the device containing that
- part of the filesystem.
- 
- @item -m @var{file}
- @itemx --device-map=@var{file}
- Use @var{file} as the device map (@pxref{Device map}) rather than the
--default, usually @samp{/boot/grub/device.map}.
-+default, usually @samp{/boot/grub2/device.map}.
- 
- @item -t @var{target}
- @itemx --target=@var{target}
-@@ -6839,19 +6856,19 @@ Print verbose messages.
- @end table
- 
- 
--@node Invoking grub-script-check
--@chapter Invoking grub-script-check
-+@node Invoking grub2-script-check
-+@chapter Invoking grub2-script-check
- 
--The program @command{grub-script-check} takes a GRUB script file
-+The program @command{grub2-script-check} takes a GRUB script file
- (@pxref{Shell-like scripting}) and checks it for syntax errors, similar to
- commands such as @command{sh -n}.  It may take a @var{path} as a non-option
- argument; if none is supplied, it will read from standard input.
- 
- @example
--grub-script-check /boot/grub/grub.cfg
-+grub-script-check /boot/grub2/grub.cfg
- @end example
- 
--@command{grub-script-check} accepts the following options:
-+@command{grub2-script-check} accepts the following options:
- 
- @table @option
- @item --help
diff --git a/SOURCES/0056-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch b/SOURCES/0056-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch
new file mode 100644
index 0000000..beef0f3
--- /dev/null
+++ b/SOURCES/0056-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch
@@ -0,0 +1,211 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 7 Nov 2017 17:12:17 -0500
+Subject: [PATCH] Make pmtimer tsc calibration not take 51 seconds to fail.
+
+On my laptop running at 2.4GHz, if I run a VM where tsc calibration
+using pmtimer will fail presuming a broken pmtimer, it takes ~51 seconds
+to do so (as measured with the stopwatch on my phone), with a tsc delta
+of 0x1cd1c85300, or around 125 billion cycles.
+
+If instead of trying to wait for 5-200ms to show up on the pmtimer, we try
+to wait for 5-200us, it decides it's broken in ~0x2626aa0 TSCs, aka ~2.4
+million cycles, or more or less instantly.
+
+Additionally, this reading the pmtimer was returning 0xffffffff anyway,
+and that's obviously an invalid return.  I've added a check for that and
+0 so we don't bother waiting for the test if what we're seeing is dead
+pins with no response at all.
+
+If "debug" is includes "pmtimer", you will see one of the following
+three outcomes.  If pmtimer gives all 0 or all 1 bits, you will see:
+
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 1
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 2
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 3
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 4
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 5
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 6
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 7
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 8
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 9
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 10
+kern/i386/tsc_pmtimer.c:78: timer is broken; giving up.
+
+This outcome was tested using qemu+kvm with UEFI (OVMF) firmware and
+these options: -machine pc-q35-2.10 -cpu Broadwell-noTSX
+
+If pmtimer gives any other bit patterns but is not actually marching
+forward fast enough to use for clock calibration, you will see:
+
+kern/i386/tsc_pmtimer.c:121: pmtimer delta is 0x0 (1904 iterations)
+kern/i386/tsc_pmtimer.c:124: tsc delta is implausible: 0x2626aa0
+
+This outcome was tested using grub compiled with GRUB_PMTIMER_IGNORE_BAD_READS
+defined (so as not to trip the bad read test) using qemu+kvm with UEFI
+(OVMF) firmware, and these options: -machine pc-q35-2.10 -cpu Broadwell-noTSX
+
+If pmtimer actually works, you'll see something like:
+
+kern/i386/tsc_pmtimer.c:121: pmtimer delta is 0x0 (1904 iterations)
+kern/i386/tsc_pmtimer.c:124: tsc delta is implausible: 0x2626aa0
+
+This outcome was tested using qemu+kvm with UEFI (OVMF) firmware, and
+these options: -machine pc-i440fx-2.4 -cpu Broadwell-noTSX
+
+I've also tested this outcome on a real Intel Xeon E3-1275v3 on an Intel
+Server Board S1200V3RPS using the SDV.RP.B8 "Release" build here:
+https://firmware.intel.com/sites/default/files/UEFIDevKit_S1200RP_vB8.zip
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/i386/tsc_pmtimer.c | 109 +++++++++++++++++++++++++++++++-------
+ 1 file changed, 89 insertions(+), 20 deletions(-)
+
+diff --git a/grub-core/kern/i386/tsc_pmtimer.c b/grub-core/kern/i386/tsc_pmtimer.c
+index c9c3616997..ca15c3aacd 100644
+--- a/grub-core/kern/i386/tsc_pmtimer.c
++++ b/grub-core/kern/i386/tsc_pmtimer.c
+@@ -28,40 +28,101 @@
+ #include <grub/acpi.h>
+ #include <grub/cpu/io.h>
+ 
++/*
++ * Define GRUB_PMTIMER_IGNORE_BAD_READS if you're trying to test a timer that's
++ * present but doesn't keep time well.
++ */
++// #define GRUB_PMTIMER_IGNORE_BAD_READS
++
+ grub_uint64_t
+ grub_pmtimer_wait_count_tsc (grub_port_t pmtimer,
+ 			     grub_uint16_t num_pm_ticks)
+ {
+   grub_uint32_t start;
+-  grub_uint32_t last;
+-  grub_uint32_t cur, end;
++  grub_uint64_t cur, end;
+   grub_uint64_t start_tsc;
+   grub_uint64_t end_tsc;
+-  int num_iter = 0;
++  unsigned int num_iter = 0;
++#ifndef GRUB_PMTIMER_IGNORE_BAD_READS
++  int bad_reads = 0;
++#endif
+ 
+-  start = grub_inl (pmtimer) & 0xffffff;
+-  last = start;
++  /*
++   * Some timers are 24-bit and some are 32-bit, but it doesn't make much
++   * difference to us.  Caring which one we have isn't really worth it since
++   * the low-order digits will give us enough data to calibrate TSC.  So just
++   * mask the top-order byte off.
++   */
++  cur = start = grub_inl (pmtimer) & 0xffffffUL;
+   end = start + num_pm_ticks;
+   start_tsc = grub_get_tsc ();
+   while (1)
+     {
+-      cur = grub_inl (pmtimer) & 0xffffff;
+-      if (cur < last)
+-	cur |= 0x1000000;
+-      num_iter++;
++      cur &= 0xffffffffff000000ULL;
++      cur |= grub_inl (pmtimer) & 0xffffffUL;
++
++      end_tsc = grub_get_tsc();
++
++#ifndef GRUB_PMTIMER_IGNORE_BAD_READS
++      /*
++       * If we get 10 reads in a row that are obviously dead pins, there's no
++       * reason to do this thousands of times.
++       */
++      if (cur == 0xffffffUL || cur == 0)
++	{
++	  bad_reads++;
++	  grub_dprintf ("pmtimer",
++			"pmtimer: 0x%"PRIxGRUB_UINT64_T" bad_reads: %d\n",
++			cur, bad_reads);
++	  grub_dprintf ("pmtimer", "timer is broken; giving up.\n");
++
++	  if (bad_reads == 10)
++	    return 0;
++	}
++#endif
++
++      if (cur < start)
++	cur += 0x1000000;
++
+       if (cur >= end)
+ 	{
+-	  end_tsc = grub_get_tsc ();
++	  grub_dprintf ("pmtimer", "pmtimer delta is 0x%"PRIxGRUB_UINT64_T"\n",
++			cur - start);
++	  grub_dprintf ("pmtimer", "tsc delta is 0x%"PRIxGRUB_UINT64_T"\n",
++			end_tsc - start_tsc);
+ 	  return end_tsc - start_tsc;
+ 	}
+-      /* Check for broken PM timer.
+-	 50000000 TSCs is between 5 ms (10GHz) and 200 ms (250 MHz)
+-	 if after this time we still don't have 1 ms on pmtimer, then
+-	 pmtimer is broken.
++
++      /*
++       * Check for broken PM timer.  1ms at 10GHz should be 1E+7 TSCs; at
++       * 250MHz it should be 2.5E6.  So if after 4E+7 TSCs on a 10GHz machine,
++       * we should have seen pmtimer show 4ms of change (i.e. cur =~
++       * start+14320); on a 250MHz machine that should be 16ms (start+57280).
++       * If after this a time we still don't have 1ms on pmtimer, then pmtimer
++       * is broken.
++       *
++       * Likewise, if our code is perfectly efficient and introduces no delays
++       * whatsoever, on a 10GHz system we should see a TSC delta of 3580 in
++       * ~3580 iterations.  On a 250MHz machine that should be ~900 iterations.
++       *
++       * With those factors in mind, there are two limits here.  There's a hard
++       * limit here at 8x our desired pm timer delta, picked as an arbitrarily
++       * large value that's still not a lot of time to humans, because if we
++       * get that far this is either an implausibly fast machine or the pmtimer
++       * is not running.  And there's another limit on 4x our 10GHz tsc delta
++       * without seeing cur converge on our target value.
+        */
+-      if ((num_iter & 0xffffff) == 0 && grub_get_tsc () - start_tsc > 5000000) {
+-	return 0;
+-      }
++      if ((++num_iter > (grub_uint32_t)num_pm_ticks << 3UL) ||
++	  end_tsc - start_tsc > 40000000)
++	{
++	  grub_dprintf ("pmtimer",
++			"pmtimer delta is 0x%"PRIxGRUB_UINT64_T" (%u iterations)\n",
++			cur - start, num_iter);
++	  grub_dprintf ("pmtimer",
++			"tsc delta is implausible: 0x%"PRIxGRUB_UINT64_T"\n",
++			end_tsc - start_tsc);
++	  return 0;
++	}
+     }
+ }
+ 
+@@ -74,12 +135,20 @@ grub_tsc_calibrate_from_pmtimer (void)
+ 
+   fadt = grub_acpi_find_fadt ();
+   if (!fadt)
+-    return 0;
++    {
++      grub_dprintf ("pmtimer", "No FADT found; not using pmtimer.\n");
++      return 0;
++    }
+   pmtimer = fadt->pmtimer;
+   if (!pmtimer)
+-    return 0;
++    {
++      grub_dprintf ("pmtimer", "FADT does not specify pmtimer; skipping.\n");
++      return 0;
++    }
+ 
+-  /* It's 3.579545 MHz clock. Wait 1 ms.  */
++  /*
++   * It's 3.579545 MHz clock. Wait 1 ms.
++   */
+   tsc_diff = grub_pmtimer_wait_count_tsc (pmtimer, 3580);
+   if (tsc_diff == 0)
+     return 0;
diff --git a/SOURCES/0056-macos-just-build-chainloader-entries-don-t-try-any-x.patch b/SOURCES/0056-macos-just-build-chainloader-entries-don-t-try-any-x.patch
deleted file mode 100644
index 574d117..0000000
--- a/SOURCES/0056-macos-just-build-chainloader-entries-don-t-try-any-x.patch
+++ /dev/null
@@ -1,124 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Wed, 24 May 2017 12:42:32 -0400
-Subject: [PATCH] macos: just build chainloader entries, don't try any xnu xnu.
-
-Since our bugs tell us that the xnu boot entries really just don't work
-most of the time, and they create piles of extra boot entries, because
-they can't quite figure out 32-vs-64 and other stuff like that.
-
-It's rediculous, and we should just boot their bootloader through the
-chainloader instead.
-
-So this patch does that.
-
-Resolves: rhbz#893179
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- util/grub.d/30_os-prober.in | 78 +++++++++++----------------------------------
- 1 file changed, 18 insertions(+), 60 deletions(-)
-
-diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in
-index 1b91c102f35..4b27bd20153 100644
---- a/util/grub.d/30_os-prober.in
-+++ b/util/grub.d/30_os-prober.in
-@@ -42,68 +42,25 @@ if [ -z "${OSPROBED}" ] ; then
- fi
- 
- osx_entry() {
--    if [ x$2 = x32 ]; then
--        # TRANSLATORS: it refers to kernel architecture (32-bit)
--	bitstr="$(gettext "(32-bit)")"
--    else
--        # TRANSLATORS: it refers to kernel architecture (64-bit)
--	bitstr="$(gettext "(64-bit)")"
--    fi
-     # TRANSLATORS: it refers on the OS residing on device %s
-     onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
--        cat << EOF
--menuentry '$(echo "${LONGNAME} $bitstr $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")'  {
-+    hints=""
-+    for hint in `"${grub_probe}" --device ${device} --target=efi_hints 2> /dev/null` ; do
-+      hints="${hints} --hint=${hint}"
-+    done
-+    cat << EOF
-+menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")'  {
- EOF
- 	save_default_entry | grub_add_tab
- 	prepare_grub_to_access_device ${DEVICE} | grub_add_tab
- 	cat << EOF
-+	set gfxpayload=keep
-         load_video
--        set do_resume=0
--        if [ /var/vm/sleepimage -nt10 / ]; then
--           if xnu_resume /var/vm/sleepimage; then
--             set do_resume=1
--           fi
--        fi
--        if [ \$do_resume = 0 ]; then
--           xnu_uuid ${OSXUUID} uuid
--           if [ -f /Extra/DSDT.aml ]; then
--              acpi -e /Extra/DSDT.aml
--           fi
--           if [ /kernelcache -nt /System/Library/Extensions ]; then
--              $1 /kernelcache boot-uuid=\${uuid} rd=*uuid
--           elif [ -f /System/Library/Kernels/kernel ]; then
--              $1 /System/Library/Kernels/kernel boot-uuid=\${uuid} rd=*uuid
--              xnu_kextdir /System/Library/Extensions
--           else
--              $1 /mach_kernel boot-uuid=\${uuid} rd=*uuid
--              if [ /System/Library/Extensions.mkext -nt /System/Library/Extensions ]; then
--                xnu_mkext /System/Library/Extensions.mkext
--              else
--                xnu_kextdir /System/Library/Extensions
--              fi
--           fi
--           if [ -f /Extra/Extensions.mkext ]; then
--              xnu_mkext /Extra/Extensions.mkext
--           fi
--           if [ -d /Extra/Extensions ]; then
--              xnu_kextdir /Extra/Extensions
--           fi
--           if [ -f /Extra/devprop.bin ]; then
--              xnu_devprop_load /Extra/devprop.bin
--           fi
--           if [ -f /Extra/splash.jpg ]; then
--              insmod jpeg
--              xnu_splash /Extra/splash.jpg
--           fi
--           if [ -f /Extra/splash.png ]; then
--              insmod png
--              xnu_splash /Extra/splash.png
--           fi
--           if [ -f /Extra/splash.tga ]; then
--              insmod tga
--              xnu_splash /Extra/splash.tga
--           fi
--        fi
-+	insmod part_gpt
-+	insmod hfsplus
-+	search --no-floppy --fs-uuid --set=root ${hints} $(grub_get_device_id "${DEVICE}")
-+	chainloader (\$root)/System/Library/CoreServices/boot.efi
-+	boot
- }
- EOF
- }
-@@ -292,11 +249,12 @@ EOF
-       echo "$title_correction_code"
-     ;;
-     macosx)
--      if [ "${UUID}" ]; then
--	OSXUUID="${UUID}"
--	osx_entry xnu_kernel 32
--	osx_entry xnu_kernel64 64
--      fi
-+      for subdevice in ${DEVICE%[[:digit:]]*}* ; do
-+	parttype="`"${grub_probe}" --device ${device} --target=gpt_parttype "${subdevice}" 2> /dev/null`"
-+	if [[ "$parttype" = "426f6f74-0000-11aa-aa11-00306543ecac" ]]; then
-+	  DEVICE="${subdevice}" osx_entry
-+	fi
-+      done
-     ;;
-     hurd)
-       onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
diff --git a/SOURCES/0057-align-struct-efi_variable-better.patch b/SOURCES/0057-align-struct-efi_variable-better.patch
new file mode 100644
index 0000000..361cb13
--- /dev/null
+++ b/SOURCES/0057-align-struct-efi_variable-better.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 27 Feb 2018 13:55:35 -0500
+Subject: [PATCH] align struct efi_variable better...
+
+---
+ include/grub/efiemu/runtime.h | 2 +-
+ include/grub/types.h          | 1 +
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/include/grub/efiemu/runtime.h b/include/grub/efiemu/runtime.h
+index 36d2dedf47..9d93ba88ba 100644
+--- a/include/grub/efiemu/runtime.h
++++ b/include/grub/efiemu/runtime.h
+@@ -33,5 +33,5 @@ struct efi_variable
+   grub_uint32_t namelen;
+   grub_uint32_t size;
+   grub_efi_uint32_t attributes;
+-} GRUB_PACKED;
++} GRUB_PACKED GRUB_ALIGNED(8);
+ #endif /* ! GRUB_EFI_EMU_RUNTIME_HEADER */
+diff --git a/include/grub/types.h b/include/grub/types.h
+index 0a3ff15913..ba446d9904 100644
+--- a/include/grub/types.h
++++ b/include/grub/types.h
+@@ -29,6 +29,7 @@
+ #else
+ #define GRUB_PACKED __attribute__ ((packed))
+ #endif
++#define GRUB_ALIGNED(x) __attribute__((aligned (x)))
+ 
+ #ifdef GRUB_BUILD
+ # define GRUB_CPU_SIZEOF_VOID_P	BUILD_SIZEOF_VOID_P
diff --git a/SOURCES/0057-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch b/SOURCES/0057-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch
deleted file mode 100644
index 68dfc1d..0000000
--- a/SOURCES/0057-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch
+++ /dev/null
@@ -1,703 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Jeff Mahoney <jeffm@suse.com>
-Date: Tue, 9 Jul 2019 13:39:45 +0200
-Subject: [PATCH] grub2/btrfs: Add ability to boot from subvolumes
-
-This patch adds the ability to specify a different root on a btrfs
-filesystem too boot from other than the default one.
-
-btrfs-list-snapshots <dev> will list the subvolumes available on the
-filesystem.
-
-set btrfs_subvol=<path> and set btrfs_subvolid=<subvolid> will specify
-which subvolume to use and any pathnames provided with either of those
-variables set will start using that root. If the subvolume or subvolume id
-doesn't exist, then an error case will result.
-
-It is possible to boot into a separate GRUB instance by exporting the
-variable and loading the config file from the subvolume.
-
-Signed-off-by: Jeff Mahoney <jeffm@suse.com>
----
- grub-core/fs/btrfs.c | 552 +++++++++++++++++++++++++++++++++++++++++++++++++--
- include/grub/btrfs.h |   1 +
- 2 files changed, 533 insertions(+), 20 deletions(-)
-
-diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
-index 63203034dfc..f1fff7385b5 100644
---- a/grub-core/fs/btrfs.c
-+++ b/grub-core/fs/btrfs.c
-@@ -38,6 +38,9 @@
- #include <zstd.h>
- #include <grub/i18n.h>
- #include <grub/btrfs.h>
-+#include <grub/command.h>
-+#include <grub/env.h>
-+#include <grub/extcmd.h>
- #include <grub/crypto.h>
- #include <grub/diskfilter.h>
- #include <grub/safemath.h>
-@@ -79,9 +82,11 @@ struct grub_btrfs_superblock
-   grub_uint64_t generation;
-   grub_uint64_t root_tree;
-   grub_uint64_t chunk_tree;
--  grub_uint8_t dummy2[0x20];
-+  grub_uint8_t dummy2[0x18];
-+  grub_uint64_t bytes_used;
-   grub_uint64_t root_dir_objectid;
--  grub_uint8_t dummy3[0x41];
-+  grub_uint64_t num_devices;
-+  grub_uint8_t dummy3[0x39];
-   struct grub_btrfs_device this_device;
-   char label[0x100];
-   grub_uint8_t dummy4[0x100];
-@@ -121,6 +126,7 @@ struct grub_btrfs_data
-   grub_uint64_t exttree;
-   grub_size_t extsize;
-   struct grub_btrfs_extent_data *extent;
-+  grub_uint64_t fs_tree;
- };
- 
- struct grub_btrfs_chunk_item
-@@ -191,6 +197,14 @@ struct grub_btrfs_leaf_descriptor
-   } *data;
- };
- 
-+struct grub_btrfs_root_ref
-+{
-+  grub_uint64_t dirid;
-+  grub_uint64_t sequence;
-+  grub_uint16_t name_len;
-+  const char name[0];
-+} __attribute__ ((packed));
-+
- struct grub_btrfs_time
- {
-   grub_int64_t sec;
-@@ -236,6 +250,14 @@ struct grub_btrfs_extent_data
- 
- #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100
- 
-+#define GRUB_BTRFS_ROOT_TREE_OBJECTID 1ULL
-+#define GRUB_BTRFS_FS_TREE_OBJECTID 5ULL
-+#define GRUB_BTRFS_ROOT_REF_KEY     156
-+#define GRUB_BTRFS_ROOT_ITEM_KEY     132
-+
-+static grub_uint64_t btrfs_default_subvolid = 0;
-+static char *btrfs_default_subvol = NULL;
-+
- static grub_disk_addr_t superblock_sectors[] = { 64 * 2, 64 * 1024 * 2,
-   256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2
- };
-@@ -1173,6 +1195,62 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
-   return GRUB_ERR_NONE;
- }
- 
-+static grub_err_t
-+get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree,
-+            grub_uint64_t objectid, grub_uint64_t offset,
-+            grub_uint64_t *fs_root);
-+
-+static grub_err_t
-+lookup_root_by_id(struct grub_btrfs_data *data, grub_uint64_t id)
-+{
-+  grub_err_t err;
-+  grub_uint64_t tree;
-+
-+  err = get_fs_root(data, data->sblock.root_tree, id, -1, &tree);
-+  if (!err)
-+    data->fs_tree = tree;
-+  return err;
-+}
-+
-+static grub_err_t
-+find_path (struct grub_btrfs_data *data,
-+	   const char *path, struct grub_btrfs_key *key,
-+	   grub_uint64_t *tree, grub_uint8_t *type);
-+
-+static grub_err_t
-+lookup_root_by_name(struct grub_btrfs_data *data, const char *path)
-+{
-+  grub_err_t err;
-+  grub_uint64_t tree = 0;
-+  grub_uint8_t type;
-+  struct grub_btrfs_key key;
-+
-+  err = find_path (data, path, &key, &tree, &type);
-+  if (err)
-+      return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path);
-+
-+  if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0)
-+    return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path);
-+
-+  data->fs_tree = tree;
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__ ((unused)))
-+{
-+  if (btrfs_default_subvol)
-+    return lookup_root_by_name(data, btrfs_default_subvol);
-+
-+  if (btrfs_default_subvolid)
-+    return lookup_root_by_id(data, btrfs_default_subvolid);
-+
-+  data->fs_tree = 0;
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+
- static struct grub_btrfs_data *
- grub_btrfs_mount (grub_device_t dev)
- {
-@@ -1208,6 +1286,13 @@ grub_btrfs_mount (grub_device_t dev)
-   data->devices_attached[0].dev = dev;
-   data->devices_attached[0].id = data->sblock.this_device.device_id;
- 
-+  err = btrfs_handle_subvol (data);
-+  if (err)
-+    {
-+      grub_free (data);
-+      return NULL;
-+    }
-+
-   return data;
- }
- 
-@@ -1673,6 +1758,91 @@ get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key,
-   return GRUB_ERR_NONE;
- }
- 
-+static grub_err_t
-+find_pathname(struct grub_btrfs_data *data, grub_uint64_t objectid,
-+              grub_uint64_t fs_root, const char *name, char **pathname)
-+{
-+  grub_err_t err;
-+  struct grub_btrfs_key key = {
-+    .object_id = objectid,
-+    .type = GRUB_BTRFS_ITEM_TYPE_INODE_REF,
-+    .offset = 0,
-+  };
-+  struct grub_btrfs_key key_out;
-+  struct grub_btrfs_leaf_descriptor desc;
-+  char *p = grub_strdup (name);
-+  grub_disk_addr_t elemaddr;
-+  grub_size_t elemsize;
-+  grub_size_t alloc = grub_strlen(name) + 1;
-+
-+  err = lower_bound(data, &key, &key_out, fs_root,
-+                    &elemaddr, &elemsize, &desc, 0);
-+  if (err)
-+    return grub_error(err, "lower_bound caught %d\n", err);
-+
-+  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF)
-+    next(data, &desc, &elemaddr, &elemsize, &key_out);
-+
-+  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF)
-+    {
-+      return grub_error(GRUB_ERR_FILE_NOT_FOUND,
-+                        "Can't find inode ref for {%"PRIuGRUB_UINT64_T
-+                        ", %u, %"PRIuGRUB_UINT64_T"} %"PRIuGRUB_UINT64_T
-+                        "/%"PRIuGRUB_SIZE"\n",
-+                        key_out.object_id, key_out.type,
-+                        key_out.offset, elemaddr, elemsize);
-+    }
-+
-+
-+  while (key_out.type == GRUB_BTRFS_ITEM_TYPE_INODE_REF &&
-+         key_out.object_id != key_out.offset) {
-+    struct grub_btrfs_inode_ref *inode_ref;
-+    char *new;
-+
-+    inode_ref = grub_malloc(elemsize + 1);
-+    if (!inode_ref)
-+      return grub_error(GRUB_ERR_OUT_OF_MEMORY,
-+                        "couldn't allocate memory for inode_ref (%"PRIuGRUB_SIZE")\n", elemsize);
-+
-+    err = grub_btrfs_read_logical(data, elemaddr, inode_ref, elemsize, 0);
-+    if (err)
-+      return grub_error(err, "read_logical caught %d\n", err);
-+
-+    alloc += grub_le_to_cpu16 (inode_ref->n) + 2;
-+    new = grub_malloc(alloc);
-+    if (!new)
-+      return grub_error(GRUB_ERR_OUT_OF_MEMORY,
-+                        "couldn't allocate memory for name (%"PRIuGRUB_SIZE")\n", alloc);
-+
-+    grub_memcpy(new, inode_ref->name, grub_le_to_cpu16 (inode_ref->n));
-+    if (p)
-+      {
-+        new[grub_le_to_cpu16 (inode_ref->n)] = '/';
-+        grub_strcpy (new + grub_le_to_cpu16 (inode_ref->n) + 1, p);
-+        grub_free(p);
-+      }
-+    else
-+      new[grub_le_to_cpu16 (inode_ref->n)] = 0;
-+    grub_free(inode_ref);
-+
-+    p = new;
-+
-+    key.object_id = key_out.offset;
-+
-+    err = lower_bound(data, &key, &key_out, fs_root, &elemaddr,
-+                      &elemsize, &desc, 0);
-+    if (err)
-+      return grub_error(err, "lower_bound caught %d\n", err);
-+
-+    if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF)
-+      next(data, &desc, &elemaddr, &elemsize, &key_out);
-+
-+  }
-+
-+  *pathname = p;
-+  return 0;
-+}
-+
- static grub_err_t
- find_path (struct grub_btrfs_data *data,
- 	   const char *path, struct grub_btrfs_key *key,
-@@ -1691,14 +1861,26 @@ find_path (struct grub_btrfs_data *data,
-   char *origpath = NULL;
-   unsigned symlinks_max = 32;
- 
--  err = get_root (data, key, tree, type);
--  if (err)
--    return err;
--
-   origpath = grub_strdup (path);
-   if (!origpath)
-     return grub_errno;
- 
-+  if (data->fs_tree)
-+    {
-+      *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
-+      *tree = data->fs_tree;
-+      /* This is a tree root, so everything starts at objectid 256 */
-+      key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
-+      key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
-+      key->offset = 0;
-+    }
-+  else
-+    {
-+      err = get_root (data, key, tree, type);
-+      if (err)
-+	return err;
-+    }
-+
-   while (1)
-     {
-       while (path[0] == '/')
-@@ -1871,9 +2053,21 @@ find_path (struct grub_btrfs_data *data,
- 	  path = path_alloc = tmp;
- 	  if (path[0] == '/')
- 	    {
--	      err = get_root (data, key, tree, type);
--	      if (err)
--		return err;
-+	      if (data->fs_tree)
-+		{
-+		  *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
-+		  *tree = data->fs_tree;
-+		  /* This is a tree root, so everything starts at objectid 256 */
-+		  key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
-+		  key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
-+		  key->offset = 0;
-+		}
-+	      else
-+		{
-+		  err = get_root (data, key, tree, type);
-+		  if (err)
-+		    return err;
-+		}
- 	    }
- 	  continue;
- 	}
-@@ -2114,18 +2308,10 @@ grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len)
- 				 data->tree, file->offset, buf, len);
- }
- 
--static grub_err_t
--grub_btrfs_uuid (grub_device_t device, char **uuid)
-+static char *
-+btrfs_unparse_uuid(struct grub_btrfs_data *data)
- {
--  struct grub_btrfs_data *data;
--
--  *uuid = NULL;
--
--  data = grub_btrfs_mount (device);
--  if (!data)
--    return grub_errno;
--
--  *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
-+  return  grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
- 			  grub_be_to_cpu16 (data->sblock.uuid[0]),
- 			  grub_be_to_cpu16 (data->sblock.uuid[1]),
- 			  grub_be_to_cpu16 (data->sblock.uuid[2]),
-@@ -2134,6 +2320,20 @@ grub_btrfs_uuid (grub_device_t device, char **uuid)
- 			  grub_be_to_cpu16 (data->sblock.uuid[5]),
- 			  grub_be_to_cpu16 (data->sblock.uuid[6]),
- 			  grub_be_to_cpu16 (data->sblock.uuid[7]));
-+}
-+
-+static grub_err_t
-+grub_btrfs_uuid (grub_device_t device, char **uuid)
-+{
-+  struct grub_btrfs_data *data;
-+
-+  *uuid = NULL;
-+
-+  data = grub_btrfs_mount (device);
-+  if (!data)
-+    return grub_errno;
-+
-+  *uuid = btrfs_unparse_uuid(data);
- 
-   grub_btrfs_unmount (data);
- 
-@@ -2190,6 +2390,242 @@ grub_btrfs_embed (grub_device_t device __attribute__ ((unused)),
- }
- #endif
- 
-+static grub_err_t
-+grub_cmd_btrfs_info (grub_command_t cmd __attribute__ ((unused)), int argc,
-+		     char **argv)
-+{
-+  grub_device_t dev;
-+  char *devname;
-+  struct grub_btrfs_data *data;
-+  char *uuid;
-+
-+  if (argc < 1)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
-+
-+  devname = grub_file_get_device_name(argv[0]);
-+
-+  if (!devname)
-+    return grub_errno;
-+
-+  dev = grub_device_open (devname);
-+  grub_free (devname);
-+  if (!dev)
-+    return grub_errno;
-+
-+  data = grub_btrfs_mount (dev);
-+  if (!data)
-+    {
-+      grub_device_close(dev);
-+      return grub_error (GRUB_ERR_BAD_ARGUMENT, "failed to open fs");
-+    }
-+
-+  if (data->sblock.label)
-+    grub_printf("Label: '%s' ", data->sblock.label);
-+  else
-+    grub_printf("Label: none ");
-+
-+  uuid = btrfs_unparse_uuid(data);
-+
-+  grub_printf(" uuid: %s\n\tTotal devices %" PRIuGRUB_UINT64_T
-+              " FS bytes used %" PRIuGRUB_UINT64_T "\n",
-+	      uuid, grub_cpu_to_le64(data->sblock.num_devices),
-+	      grub_cpu_to_le64(data->sblock.bytes_used));
-+
-+  grub_btrfs_unmount (data);
-+
-+  return 0;
-+}
-+
-+static grub_err_t
-+get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree,
-+            grub_uint64_t objectid, grub_uint64_t offset,
-+            grub_uint64_t *fs_root)
-+{
-+  grub_err_t err;
-+  struct grub_btrfs_key key_in = {
-+    .object_id = objectid,
-+    .type = GRUB_BTRFS_ROOT_ITEM_KEY,
-+    .offset = offset,
-+  }, key_out;
-+  struct grub_btrfs_leaf_descriptor desc;
-+  grub_disk_addr_t elemaddr;
-+  grub_size_t elemsize;
-+  struct grub_btrfs_root_item ri;
-+
-+  err = lower_bound(data, &key_in, &key_out, tree,
-+                    &elemaddr, &elemsize, &desc, 0);
-+
-+  if (err)
-+    return err;
-+
-+  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM || elemaddr == 0)
-+    return grub_error(GRUB_ERR_FILE_NOT_FOUND,
-+                    N_("can't find fs root for subvol %"PRIuGRUB_UINT64_T"\n"),
-+                    key_in.object_id);
-+
-+  err = grub_btrfs_read_logical (data, elemaddr, &ri, sizeof (ri), 0);
-+  if (err)
-+    return err;
-+
-+  *fs_root = ri.tree;
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static const struct grub_arg_option options[] = {
-+  {"output", 'o', 0, N_("Output to a variable instead of the console."),
-+   N_("VARNAME"), ARG_TYPE_STRING},
-+  {"path-only", 'p', 0, N_("Show only the path of the subvolume."), 0, 0},
-+  {"id-only", 'i', 0, N_("Show only the id of the subvolume."), 0, 0},
-+  {0, 0, 0, 0, 0, 0}
-+};
-+
-+static grub_err_t
-+grub_cmd_btrfs_list_subvols (struct grub_extcmd_context *ctxt,
-+			     int argc, char **argv)
-+{
-+  struct grub_btrfs_data *data;
-+  grub_device_t dev;
-+  char *devname;
-+  grub_uint64_t tree;
-+  struct grub_btrfs_key key_in = {
-+    .object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID),
-+    .type = GRUB_BTRFS_ROOT_REF_KEY,
-+    .offset = 0,
-+  }, key_out;
-+  struct grub_btrfs_leaf_descriptor desc;
-+  grub_disk_addr_t elemaddr;
-+  grub_uint64_t fs_root = 0;
-+  grub_size_t elemsize;
-+  grub_size_t allocated = 0;
-+  int r = 0;
-+  grub_err_t err;
-+  char *buf = NULL;
-+  int print = 1;
-+  int path_only = ctxt->state[1].set;
-+  int num_only = ctxt->state[2].set;
-+  char *varname = NULL;
-+  char *output = NULL;
-+
-+  if (ctxt->state[0].set) {
-+    varname = ctxt->state[0].arg;
-+    print = 0;
-+  }
-+
-+  if (argc < 1)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
-+
-+  devname = grub_file_get_device_name(argv[0]);
-+  if (!devname)
-+    return grub_errno;
-+
-+  dev = grub_device_open (devname);
-+  grub_free (devname);
-+  if (!dev)
-+    return grub_errno;
-+
-+  data = grub_btrfs_mount(dev);
-+  if (!data)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "could not open device");
-+
-+  tree = data->sblock.root_tree;
-+  err = get_fs_root(data, tree, grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID),
-+                    0, &fs_root);
-+  if (err)
-+    goto out;
-+
-+  err = lower_bound(data, &key_in, &key_out, tree,
-+                    &elemaddr, &elemsize, &desc, 0);
-+
-+  if (err)
-+    {
-+      grub_btrfs_unmount(data);
-+      return err;
-+    }
-+
-+  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF || elemaddr == 0)
-+    {
-+      r = next(data, &desc, &elemaddr, &elemsize, &key_out);
-+    }
-+
-+  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF) {
-+    err = GRUB_ERR_FILE_NOT_FOUND;
-+    grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root refs"));
-+    goto out;
-+  }
-+
-+  do
-+    {
-+      struct grub_btrfs_root_ref *ref;
-+      char *p = NULL;
-+
-+      if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF)
-+        {
-+          r = 0;
-+          break;
-+        }
-+
-+      if (elemsize > allocated)
-+        {
-+          grub_free(buf);
-+          allocated = 2 * elemsize;
-+          buf = grub_malloc(allocated + 1);
-+          if (!buf)
-+            {
-+              r = -grub_errno;
-+              break;
-+            }
-+        }
-+      ref = (struct grub_btrfs_root_ref *)buf;
-+
-+      err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0);
-+      if (err)
-+        {
-+          r = -err;
-+          break;
-+        }
-+        buf[elemsize] = 0;
-+
-+      find_pathname(data, ref->dirid, fs_root, ref->name, &p);
-+
-+      if (print)
-+        {
-+          if (num_only)
-+            grub_printf("ID %"PRIuGRUB_UINT64_T"\n", key_out.offset);
-+          else if (path_only)
-+            grub_printf("%s\n", p);
-+          else
-+            grub_printf("ID %"PRIuGRUB_UINT64_T" path %s\n", key_out.offset, p);
-+        } else {
-+          char *old = output;
-+          if (num_only)
-+            output = grub_xasprintf("%s%"PRIuGRUB_UINT64_T"\n",
-+                                    old ?: "", key_out.offset);
-+          else if (path_only)
-+            output = grub_xasprintf("%s%s\n", old ?: "", p);
-+          else
-+            output = grub_xasprintf("%sID %"PRIuGRUB_UINT64_T" path %s\n",
-+                                    old ?: "", key_out.offset, p);
-+
-+          if (old)
-+            grub_free(old);
-+        }
-+
-+      r = next(data, &desc, &elemaddr, &elemsize, &key_out);
-+  } while(r > 0);
-+
-+  if (output)
-+    grub_env_set(varname, output);
-+
-+out:
-+  free_iterator(&desc);
-+  grub_btrfs_unmount(data);
-+
-+  grub_device_close (dev);
-+
-+  return 0;
-+}
-+
- static struct grub_fs grub_btrfs_fs = {
-   .name = "btrfs",
-   .fs_dir = grub_btrfs_dir,
-@@ -2205,12 +2641,88 @@ static struct grub_fs grub_btrfs_fs = {
- #endif
- };
- 
-+static grub_command_t cmd_info;
-+static grub_extcmd_t cmd_list_subvols;
-+
-+static char *
-+subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)),
-+                  const char *val)
-+{
-+  unsigned long long result = 0;
-+
-+  grub_errno = GRUB_ERR_NONE;
-+  if (*val)
-+    {
-+      result = grub_strtoull(val, NULL, 10);
-+      if (grub_errno)
-+        return NULL;
-+    }
-+
-+  grub_free (btrfs_default_subvol);
-+  btrfs_default_subvol = NULL;
-+  btrfs_default_subvolid = result;
-+  return grub_strdup(val);
-+}
-+
-+static const char *
-+subvolid_get_env (struct grub_env_var *var __attribute__ ((unused)),
-+                  const char *val __attribute__ ((unused)))
-+{
-+  if (btrfs_default_subvol)
-+    return grub_xasprintf("subvol:%s", btrfs_default_subvol);
-+  else if (btrfs_default_subvolid)
-+    return grub_xasprintf("%"PRIuGRUB_UINT64_T, btrfs_default_subvolid);
-+  else
-+    return "";
-+}
-+
-+static char *
-+subvol_set_env (struct grub_env_var *var __attribute__ ((unused)),
-+                const char *val)
-+{
-+  grub_free (btrfs_default_subvol);
-+  btrfs_default_subvol = grub_strdup (val);
-+  btrfs_default_subvolid = 0;
-+  return grub_strdup(val);
-+}
-+
-+static const char *
-+subvol_get_env (struct grub_env_var *var __attribute__ ((unused)),
-+                const char *val __attribute__ ((unused)))
-+{
-+  if (btrfs_default_subvol)
-+    return btrfs_default_subvol;
-+  else if (btrfs_default_subvolid)
-+    return grub_xasprintf("subvolid:%" PRIuGRUB_UINT64_T,
-+                          btrfs_default_subvolid);
-+  else
-+    return "";
-+}
-+
- GRUB_MOD_INIT (btrfs)
- {
-   grub_fs_register (&grub_btrfs_fs);
-+  cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info,
-+				   "DEVICE",
-+				   "Print BtrFS info about DEVICE.");
-+  cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols",
-+					 grub_cmd_btrfs_list_subvols, 0,
-+					 "[-p|-n] [-o var] DEVICE",
-+					 "Print list of BtrFS subvolumes on "
-+					 "DEVICE.", options);
-+  grub_register_variable_hook ("btrfs_subvol", subvol_get_env,
-+                               subvol_set_env);
-+  grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env,
-+                               subvolid_set_env);
- }
- 
- GRUB_MOD_FINI (btrfs)
- {
-+  grub_register_variable_hook ("btrfs_subvol", NULL, NULL);
-+  grub_register_variable_hook ("btrfs_subvolid", NULL, NULL);
-+  grub_unregister_command (cmd_info);
-+  grub_unregister_extcmd (cmd_list_subvols);
-   grub_fs_unregister (&grub_btrfs_fs);
- }
-+
-+// vim: si et sw=2:
-diff --git a/include/grub/btrfs.h b/include/grub/btrfs.h
-index 9d93fb6c182..234ad976771 100644
---- a/include/grub/btrfs.h
-+++ b/include/grub/btrfs.h
-@@ -29,6 +29,7 @@ enum
-     GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM = 0x84,
-     GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF = 0x90,
-     GRUB_BTRFS_ITEM_TYPE_DEVICE = 0xd8,
-+    GRUB_BTRFS_ITEM_TYPE_ROOT_REF = 0x9c,
-     GRUB_BTRFS_ITEM_TYPE_CHUNK = 0xe4
-   };
- 
diff --git a/SOURCES/0058-Add-BLS-support-to-grub-mkconfig.patch b/SOURCES/0058-Add-BLS-support-to-grub-mkconfig.patch
new file mode 100644
index 0000000..3e5b230
--- /dev/null
+++ b/SOURCES/0058-Add-BLS-support-to-grub-mkconfig.patch
@@ -0,0 +1,382 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 9 Dec 2016 15:40:29 -0500
+Subject: [PATCH] Add BLS support to grub-mkconfig
+
+GRUB now has BootLoaderSpec support, the user can choose to use this by
+setting GRUB_ENABLE_BLSCFG to true in /etc/default/grub. On this setup,
+the boot menu entries are not added to the grub.cfg, instead BLS config
+files are parsed by blscfg command and the entries created dynamically.
+
+A 10_linux_bls grub.d snippet to generate menu entries from BLS files
+is also added that can be used on platforms where the bootloader doesn't
+have BLS support and only can parse a normal grub configuration file.
+
+Portions of the 10_linux_bls were taken from the ostree-grub-generator
+script that's included in the OSTree project.
+
+Fixes to support multi-devices and generate a BLS section even if no
+kernels are found in the boot directory were proposed by Yclept Nemo
+and Tom Gundersen respectively.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+[javierm: remove outdated URL for BLS document]
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+[iwienand@redhat.com: skip machine ID check when updating entries]
+Signed-off-by: Ian Wienand <iwienand@redhat.com>
+[rharwood: use sort(1), commit message composits, drop man pages]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ util/grub-mkconfig.in     |   9 +-
+ util/grub-mkconfig_lib.in |  22 ++++-
+ util/grub.d/10_linux.in   | 218 +++++++++++++++++++++++++++++++++++++++++++++-
+ 3 files changed, 243 insertions(+), 6 deletions(-)
+
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index 535c0f0249..f55339a3f6 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -50,6 +50,8 @@ grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@"
+ export TEXTDOMAIN=@PACKAGE@
+ export TEXTDOMAINDIR="@localedir@"
+ 
++export GRUB_GRUBENV_UPDATE="yes"
++
+ . "${pkgdatadir}/grub-mkconfig_lib"
+ 
+ # Usage: usage
+@@ -59,6 +61,7 @@ usage () {
+     gettext "Generate a grub config file"; echo
+     echo
+     print_option_help "-o, --output=$(gettext FILE)" "$(gettext "output generated config to FILE [default=stdout]")"
++    print_option_help "--no-grubenv-update" "$(gettext "do not update variables in the grubenv file")"
+     print_option_help "-h, --help" "$(gettext "print this message and exit")"
+     print_option_help "-V, --version" "$(gettext "print the version information and exit")"
+     echo
+@@ -94,6 +97,9 @@ do
+     --output=*)
+ 	grub_cfg=`echo "$option" | sed 's/--output=//'`
+ 	;;
++    --no-grubenv-update)
++	GRUB_GRUBENV_UPDATE="no"
++	;;
+     -*)
+ 	gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2
+ 	usage
+@@ -253,7 +259,8 @@ export GRUB_DEFAULT \
+   GRUB_OS_PROBER_SKIP_LIST \
+   GRUB_DISABLE_SUBMENU \
+   GRUB_DEFAULT_DTB \
+-  SUSE_BTRFS_SNAPSHOT_BOOTING
++  SUSE_BTRFS_SNAPSHOT_BOOTING \
++  GRUB_ENABLE_BLSCFG
+ 
+ if test "x${grub_cfg}" != "x"; then
+   rm -f "${grub_cfg}.new"
+diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
+index 5e96f6cc5d..301d8a8a1e 100644
+--- a/util/grub-mkconfig_lib.in
++++ b/util/grub-mkconfig_lib.in
+@@ -30,6 +30,9 @@ fi
+ if test "x$grub_file" = x; then
+   grub_file="${bindir}/@grub_file@"
+ fi
++if test "x$grub_editenv" = x; then
++  grub_editenv="${bindir}/@grub_editenv@"
++fi
+ if test "x$grub_mkrelpath" = x; then
+   grub_mkrelpath="${bindir}/@grub_mkrelpath@"
+ fi
+@@ -122,8 +125,19 @@ EOF
+   fi
+ }
+ 
++prepare_grub_to_access_device_with_variable ()
++{
++  device_variable="$1"
++  shift
++  prepare_grub_to_access_device "$@"
++  unset "device_variable"
++}
++
+ prepare_grub_to_access_device ()
+ {
++  if [ -z "$device_variable" ]; then
++    device_variable="root"
++  fi
+   old_ifs="$IFS"
+   IFS='
+ '
+@@ -158,18 +172,18 @@ prepare_grub_to_access_device ()
+   # otherwise set root as per value in device.map.
+   fs_hint="`"${grub_probe}" --device $@ --target=compatibility_hint`"
+   if [ "x$fs_hint" != x ]; then
+-    echo "set root='$fs_hint'"
++    echo "set ${device_variable}='$fs_hint'"
+   fi
+   if [ "x${GRUB_DISABLE_UUID}" != "xtrue" ] && fs_uuid="`"${grub_probe}" --device $@ --target=fs_uuid 2> /dev/null`" ; then
+     hints="`"${grub_probe}" --device $@ --target=hints_string 2> /dev/null`" || hints=
+     if [ "x$hints" != x ]; then
+       echo "if [ x\$feature_platform_search_hint = xy ]; then"
+-      echo "  search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}"
++      echo "  search --no-floppy --fs-uuid --set=${device_variable} ${hints} ${fs_uuid}"
+       echo "else"
+-      echo "  search --no-floppy --fs-uuid --set=root ${fs_uuid}"
++      echo "  search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}"
+       echo "fi"
+     else
+-      echo "search --no-floppy --fs-uuid --set=root ${fs_uuid}"
++      echo "search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}"
+     fi
+   fi
+   IFS="$old_ifs"
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 7bb3a211a7..2851952659 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -82,6 +82,218 @@ case x"$GRUB_FS" in
+ 	;;
+ esac
+ 
++populate_header_warn()
++{
++if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then
++  bls_parser="10_linux script"
++else
++  bls_parser="blscfg command"
++fi
++cat <<EOF
++
++# This section was generated by a script. Do not modify the generated file - all changes
++# will be lost the next time file is regenerated. Instead edit the BootLoaderSpec files.
++#
++# The $bls_parser parses the BootLoaderSpec files stored in /boot/loader/entries and
++# populates the boot menu. Please refer to the Boot Loader Specification documentation
++# for the files format: https://systemd.io/BOOT_LOADER_SPECIFICATION/.
++
++EOF
++}
++
++read_config()
++{
++    config_file=${1}
++    title=""
++    initrd=""
++    options=""
++    linux=""
++    grub_arg=""
++
++    while read -r line
++    do
++        record=$(echo ${line} | cut -f 1 -d ' ')
++        value=$(echo ${line} | cut -s -f2- -d ' ')
++        case "${record}" in
++            "title")
++                title=${value}
++                ;;
++            "initrd")
++                initrd=${value}
++                ;;
++            "linux")
++                linux=${value}
++                ;;
++            "options")
++                options=${value}
++                ;;
++            "grub_arg")
++                grub_arg=${value}
++                ;;
++        esac
++    done < ${config_file}
++}
++
++blsdir="/boot/loader/entries"
++
++get_sorted_bls()
++{
++    if ! [ -d "${blsdir}" ]; then
++        return
++    fi
++
++    local IFS=$'\n'
++
++    files=($(for bls in ${blsdir}/*.conf; do
++        if ! [[ -e "${bls}" ]] ; then
++            continue
++        fi
++        bls="${bls%.conf}"
++        bls="${bls##*/}"
++        echo "${bls}"
++    done | sort -Vr 2>/dev/null)) || :
++
++    echo "${files[@]}"
++}
++
++update_bls_cmdline()
++{
++    local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
++    local -a files=($(get_sorted_bls))
++
++    for bls in "${files[@]}"; do
++        local options="${cmdline}"
++        if [ -z "${bls##*debug*}" ]; then
++            options="${options} ${GRUB_CMDLINE_LINUX_DEBUG}"
++        fi
++        options="$(echo "${options}" | sed -e 's/\//\\\//g')"
++        sed -i -e "s/^options.*/options ${options}/" "${blsdir}/${bls}.conf"
++    done
++}
++
++populate_menu()
++{
++    local -a files=($(get_sorted_bls))
++
++    gettext_printf "Generating boot entries from BLS files...\n" >&2
++
++    for bls in "${files[@]}"; do
++        read_config "${blsdir}/${bls}.conf"
++
++        menu="${menu}menuentry '${title}' ${grub_arg} --id=${bls} {\n"
++        menu="${menu}\t linux ${linux} ${options}\n"
++        if [ -n "${initrd}" ] ; then
++            menu="${menu}\t initrd ${boot_prefix}${initrd}\n"
++        fi
++        menu="${menu}}\n\n"
++    done
++    # The printf command seems to be more reliable across shells for special character (\n, \t) evaluation
++    printf "$menu"
++}
++
++# Make BLS the default if GRUB_ENABLE_BLSCFG was not set and grubby is not installed.
++if [ -z "${GRUB_ENABLE_BLSCFG}" ] && ! command -v new-kernel-pkg >/dev/null; then
++	  GRUB_ENABLE_BLSCFG="true"
++fi
++
++if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]; then
++  if [ x$dirname = x/ ]; then
++    if [ -z "${prepare_root_cache}" ]; then
++      prepare_grub_to_access_device ${GRUB_DEVICE}
++    fi
++  else
++    if [ -z "${prepare_boot_cache}" ]; then
++      prepare_grub_to_access_device ${GRUB_DEVICE_BOOT}
++    fi
++  fi
++
++  if [ -d /sys/firmware/efi ]; then
++      bootefi_device="`${grub_probe} --target=device /boot/efi/`"
++      prepare_grub_to_access_device_with_variable boot ${bootefi_device}
++  else
++      boot_device="`${grub_probe} --target=device /boot/`"
++      prepare_grub_to_access_device_with_variable boot ${boot_device}
++  fi
++
++  arch="$(uname -m)"
++  if [ "x${arch}" = "xppc64le" ] && [ -d /sys/firmware/opal ]; then
++
++      BLS_POPULATE_MENU="true"
++      petitboot_path="/sys/firmware/devicetree/base/ibm,firmware-versions/petitboot"
++
++      if test -e ${petitboot_path}; then
++          read -r -d '' petitboot_version < ${petitboot_path}
++          petitboot_version="$(echo ${petitboot_version//v})"
++
++	  if test -n ${petitboot_version}; then
++              major_version="$(echo ${petitboot_version} | cut -d . -f1)"
++              minor_version="$(echo ${petitboot_version} | cut -d . -f2)"
++
++              re='^[0-9]+$'
++              if [[ $major_version =~ $re ]] && [[ $minor_version =~ $re ]] &&
++                 ([[ ${major_version} -gt 1 ]] ||
++                  [[ ${major_version} -eq 1 &&
++                     ${minor_version} -ge 8  ]]); then
++                  BLS_POPULATE_MENU="false"
++              fi
++          fi
++      fi
++  fi
++
++  populate_header_warn
++
++  cat << EOF
++# The kernelopts variable should be defined in the grubenv file. But to ensure that menu
++# entries populated from BootLoaderSpec files that use this variable work correctly even
++# without a grubenv file, define a fallback kernelopts variable if this has not been set.
++#
++# The kernelopts variable in the grubenv file can be modified using the grubby tool or by
++# executing the grub2-mkconfig tool. For the latter, the values of the GRUB_CMDLINE_LINUX
++# and GRUB_CMDLINE_LINUX_DEFAULT options from /etc/default/grub file are used to set both
++# the kernelopts variable in the grubenv file and the fallback kernelopts variable.
++if [ -z "\${kernelopts}" ]; then
++  set kernelopts="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
++fi
++EOF
++
++  update_bls_cmdline
++
++  if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then
++      populate_menu
++  else
++      cat << EOF
++
++insmod blscfg
++blscfg
++EOF
++  fi
++
++  if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then
++      blsdir="/boot/loader/entries"
++      [ -d "${blsdir}" ] && GRUB_BLS_FS="$(${grub_probe} --target=fs ${blsdir})"
++      if [ "x${GRUB_BLS_FS}" = "xbtrfs" ] || [ "x${GRUB_BLS_FS}" = "xzfs" ]; then
++          blsdir=$(make_system_path_relative_to_its_root "${blsdir}")
++          if [ "x${blsdir}" != "x/loader/entries" ] && [ "x${blsdir}" != "x/boot/loader/entries" ]; then
++              ${grub_editenv} - set blsdir="${blsdir}"
++          fi
++      fi
++
++      if [ -n "${GRUB_EARLY_INITRD_LINUX_CUSTOM}" ]; then
++          ${grub_editenv} - set early_initrd="${GRUB_EARLY_INITRD_LINUX_CUSTOM}"
++      fi
++
++      if [ -n "${GRUB_DEFAULT_DTB}" ]; then
++          ${grub_editenv} - set devicetree="${GRUB_DEFAULT_DTB}"
++      fi
++
++      if [ -n "${GRUB_SAVEDEFAULT}" ]; then
++           ${grub_editenv} - set save_default="${GRUB_SAVEDEFAULT}"
++      fi
++  fi
++
++  exit 0
++fi
++
+ mktitle ()
+ {
+   local title_type
+@@ -121,6 +333,7 @@ linux_entry ()
+   if [ -z "$boot_device_id" ]; then
+       boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+   fi
++
+   if [ x$type != xsimple ] ; then
+       title=$(mktitle "$type" "$version")
+       if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then
+@@ -231,6 +444,7 @@ is_top_level=true
+ while [ "x$list" != "x" ] ; do
+   linux=`version_find_latest $list`
+   gettext_printf "Found linux image: %s\n" "$linux" >&2
++
+   basename=`basename $linux`
+   dirname=`dirname $linux`
+   rel_dirname=`make_system_path_relative_to_its_root $dirname`
+@@ -269,7 +483,9 @@ while [ "x$list" != "x" ] ; do
+     for i in ${initrd}; do
+       initrd_display="${initrd_display} ${dirname}/${i}"
+     done
+-    gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2
++    if [ "x${GRUB_ENABLE_BLSCFG}" != "xtrue" ]; then
++      gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2
++    fi
+   fi
+ 
+   fdt=
diff --git a/SOURCES/0058-export-btrfs_subvol-and-btrfs_subvolid.patch b/SOURCES/0058-export-btrfs_subvol-and-btrfs_subvolid.patch
deleted file mode 100644
index d38a6b8..0000000
--- a/SOURCES/0058-export-btrfs_subvol-and-btrfs_subvolid.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Michael Chang <mchang@suse.com>
-Date: Wed, 18 Dec 2013 09:57:04 +0000
-Subject: [PATCH] export btrfs_subvol and btrfs_subvolid
-
-We should export btrfs_subvol and btrfs_subvolid to have both visible
-to subsidiary configuration files loaded using configfile.
-
-Signed-off-by: Michael Chang <mchang@suse.com>
----
- grub-core/fs/btrfs.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
-index f1fff7385b5..ad1b56b716d 100644
---- a/grub-core/fs/btrfs.c
-+++ b/grub-core/fs/btrfs.c
-@@ -2714,6 +2714,8 @@ GRUB_MOD_INIT (btrfs)
-                                subvol_set_env);
-   grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env,
-                                subvolid_set_env);
-+  grub_env_export ("btrfs_subvol");
-+  grub_env_export ("btrfs_subvolid");
- }
- 
- GRUB_MOD_FINI (btrfs)
diff --git a/SOURCES/0059-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch b/SOURCES/0059-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch
new file mode 100644
index 0000000..1ac900c
--- /dev/null
+++ b/SOURCES/0059-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch
@@ -0,0 +1,26 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 6 Feb 2018 11:16:28 +0100
+Subject: [PATCH] Don't attempt to backtrace on grub_abort() for grub-emu
+
+The emu platform doesn't have a grub_backtrace() implementation, so this
+causes a build error. Don't attempt to call this when building grub-emu.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/kern/misc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index a3e215155b..c60601b699 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -1201,7 +1201,7 @@ static void __attribute__ ((noreturn))
+ grub_abort (void)
+ {
+ #ifndef GRUB_UTIL
+-#if defined(__i386__) || defined(__x86_64__)
++#if (defined(__i386__) || defined(__x86_64__)) && !defined(GRUB_MACHINE_EMU)
+   grub_backtrace();
+ #endif
+ #endif
diff --git a/SOURCES/0059-grub2-btrfs-03-follow_default.patch b/SOURCES/0059-grub2-btrfs-03-follow_default.patch
deleted file mode 100644
index 2b9a136..0000000
--- a/SOURCES/0059-grub2-btrfs-03-follow_default.patch
+++ /dev/null
@@ -1,196 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Michael Chang <mchang@suse.com>
-Date: Thu, 21 Aug 2014 03:39:11 +0000
-Subject: [PATCH] grub2-btrfs-03-follow_default
-
----
- grub-core/fs/btrfs.c | 107 ++++++++++++++++++++++++++++++++++++---------------
- 1 file changed, 76 insertions(+), 31 deletions(-)
-
-diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
-index ad1b56b716d..113c1f746c9 100644
---- a/grub-core/fs/btrfs.c
-+++ b/grub-core/fs/btrfs.c
-@@ -1256,6 +1256,7 @@ grub_btrfs_mount (grub_device_t dev)
- {
-   struct grub_btrfs_data *data;
-   grub_err_t err;
-+  const char *relpath = grub_env_get ("btrfs_relative_path");
- 
-   if (!dev->disk)
-     {
-@@ -1286,11 +1287,14 @@ grub_btrfs_mount (grub_device_t dev)
-   data->devices_attached[0].dev = dev;
-   data->devices_attached[0].id = data->sblock.this_device.device_id;
- 
--  err = btrfs_handle_subvol (data);
--  if (err)
-+  if (relpath && (relpath[0] == '1' || relpath[0] == 'y'))
-     {
--      grub_free (data);
--      return NULL;
-+      err = btrfs_handle_subvol (data);
-+      if (err)
-+      {
-+        grub_free (data);
-+        return NULL;
-+      }
-     }
- 
-   return data;
-@@ -1855,24 +1859,39 @@ find_path (struct grub_btrfs_data *data,
-   grub_size_t allocated = 0;
-   struct grub_btrfs_dir_item *direl = NULL;
-   struct grub_btrfs_key key_out;
-+  int follow_default;
-   const char *ctoken;
-   grub_size_t ctokenlen;
-   char *path_alloc = NULL;
-   char *origpath = NULL;
-   unsigned symlinks_max = 32;
-+  const char *relpath = grub_env_get ("btrfs_relative_path");
- 
-+  follow_default = 0;
-   origpath = grub_strdup (path);
-   if (!origpath)
-     return grub_errno;
- 
--  if (data->fs_tree)
-+  if (relpath && (relpath[0] == '1' || relpath[0] == 'y'))
-     {
--      *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
--      *tree = data->fs_tree;
--      /* This is a tree root, so everything starts at objectid 256 */
--      key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
--      key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
--      key->offset = 0;
-+      if (data->fs_tree)
-+        {
-+          *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
-+          *tree = data->fs_tree;
-+          /* This is a tree root, so everything starts at objectid 256 */
-+          key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
-+          key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
-+          key->offset = 0;
-+        }
-+      else
-+        {
-+          *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
-+          *tree = data->sblock.root_tree;
-+          key->object_id = data->sblock.root_dir_objectid;
-+          key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
-+          key->offset = 0;
-+          follow_default = 1;
-+        }
-     }
-   else
-     {
-@@ -1883,15 +1902,23 @@ find_path (struct grub_btrfs_data *data,
- 
-   while (1)
-     {
--      while (path[0] == '/')
--	path++;
--      if (!path[0])
--	break;
--      slash = grub_strchr (path, '/');
--      if (!slash)
--	slash = path + grub_strlen (path);
--      ctoken = path;
--      ctokenlen = slash - path;
-+      if (!follow_default)
-+	{
-+	  while (path[0] == '/')
-+	    path++;
-+	  if (!path[0])
-+	    break;
-+	  slash = grub_strchr (path, '/');
-+	  if (!slash)
-+	    slash = path + grub_strlen (path);
-+	  ctoken = path;
-+	  ctokenlen = slash - path;
-+	}
-+      else
-+	{
-+	  ctoken = "default";
-+	  ctokenlen = sizeof ("default") - 1;
-+	}
- 
-       if (*type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY)
- 	{
-@@ -1902,7 +1929,9 @@ find_path (struct grub_btrfs_data *data,
- 
-       if (ctokenlen == 1 && ctoken[0] == '.')
- 	{
--	  path = slash;
-+	  if (!follow_default)
-+	    path = slash;
-+	  follow_default = 0;
- 	  continue;
- 	}
-       if (ctokenlen == 2 && ctoken[0] == '.' && ctoken[1] == '.')
-@@ -1933,8 +1962,9 @@ find_path (struct grub_btrfs_data *data,
- 	  *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
- 	  key->object_id = key_out.offset;
- 
--	  path = slash;
--
-+	  if (!follow_default)
-+	    path = slash;
-+	  follow_default = 0;
- 	  continue;
- 	}
- 
-@@ -2003,7 +2033,9 @@ find_path (struct grub_btrfs_data *data,
- 	  return err;
- 	}
- 
--      path = slash;
-+      if (!follow_default)
-+	path = slash;
-+      follow_default = 0;
-       if (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK)
- 	{
- 	  struct grub_btrfs_inode inode;
-@@ -2053,14 +2085,26 @@ find_path (struct grub_btrfs_data *data,
- 	  path = path_alloc = tmp;
- 	  if (path[0] == '/')
- 	    {
--	      if (data->fs_tree)
-+              if (relpath && (relpath[0] == '1' || relpath[0] == 'y'))
- 		{
--		  *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
--		  *tree = data->fs_tree;
--		  /* This is a tree root, so everything starts at objectid 256 */
--		  key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
--		  key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
--		  key->offset = 0;
-+	          if (data->fs_tree)
-+		    {
-+		      *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
-+		      *tree = data->fs_tree;
-+		      /* This is a tree root, so everything starts at objectid 256 */
-+		      key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
-+		      key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
-+		      key->offset = 0;
-+		    }
-+		  else
-+		    {
-+	              *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
-+	              *tree = data->sblock.root_tree;
-+	              key->object_id = data->sblock.root_dir_objectid;
-+	              key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
-+	              key->offset = 0;
-+	              follow_default = 1;
-+		    }
- 		}
- 	      else
- 		{
-@@ -2716,6 +2760,7 @@ GRUB_MOD_INIT (btrfs)
-                                subvolid_set_env);
-   grub_env_export ("btrfs_subvol");
-   grub_env_export ("btrfs_subvolid");
-+  grub_env_export ("btrfs_relative_path");
- }
- 
- GRUB_MOD_FINI (btrfs)
diff --git a/SOURCES/0060-Add-grub2-switch-to-blscfg.patch b/SOURCES/0060-Add-grub2-switch-to-blscfg.patch
new file mode 100644
index 0000000..e316116
--- /dev/null
+++ b/SOURCES/0060-Add-grub2-switch-to-blscfg.patch
@@ -0,0 +1,395 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 15 Mar 2018 14:12:40 -0400
+Subject: [PATCH] Add grub2-switch-to-blscfg
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+[jhlavac: Use ${etcdefaultgrub} instead of /etc/default/grub]
+Signed-off-by: Jan Hlavac <jhlavac@redhat.com>
+[rharwood: skip on ostree installations, migrate man to h2m]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ Makefile.util.def                  |   7 +
+ docs/man/grub-switch-to-blscfg.h2m |   2 +
+ util/grub-set-password.in          |   2 +-
+ util/grub-switch-to-blscfg.in      | 317 +++++++++++++++++++++++++++++++++++++
+ util/grub.d/10_linux.in            |   2 +-
+ 5 files changed, 328 insertions(+), 2 deletions(-)
+ create mode 100644 docs/man/grub-switch-to-blscfg.h2m
+ create mode 100644 util/grub-switch-to-blscfg.in
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 18a9242776..88f55e35c4 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -1348,6 +1348,13 @@ program = {
+   ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
+ };
+ 
++script = {
++  name = grub-switch-to-blscfg;
++  common = util/grub-switch-to-blscfg.in;
++  mansection = 8;
++  installdir = sbin;
++};
++
+ program = {
+   name = grub-glue-efi;
+   mansection = 1;
+diff --git a/docs/man/grub-switch-to-blscfg.h2m b/docs/man/grub-switch-to-blscfg.h2m
+new file mode 100644
+index 0000000000..fa341426a5
+--- /dev/null
++++ b/docs/man/grub-switch-to-blscfg.h2m
+@@ -0,0 +1,2 @@
++[NAME]
++grub-switch-to-blscfg \- switch to using BLS config files
+diff --git a/util/grub-set-password.in b/util/grub-set-password.in
+index 5ebf50576d..c0b5ebbfdc 100644
+--- a/util/grub-set-password.in
++++ b/util/grub-set-password.in
+@@ -1,6 +1,6 @@
+ #!/bin/sh -e
+ 
+-EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/')
++EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g')
+ if [ -d /sys/firmware/efi/efivars/ ]; then
+     grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'`
+ else
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+new file mode 100644
+index 0000000000..a851424beb
+--- /dev/null
++++ b/util/grub-switch-to-blscfg.in
+@@ -0,0 +1,317 @@
++#! /bin/sh
++#
++# Set a default boot entry for GRUB.
++# Copyright (C) 2004,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/>.
++
++#set -eu
++
++# Initialize some variables.
++prefix=@prefix@
++exec_prefix=@exec_prefix@
++sbindir=@sbindir@
++bindir=@bindir@
++sysconfdir="@sysconfdir@"
++PACKAGE_NAME=@PACKAGE_NAME@
++PACKAGE_VERSION=@PACKAGE_VERSION@
++datarootdir="@datarootdir@"
++datadir="@datadir@"
++if [ ! -v pkgdatadir ]; then
++    pkgdatadir="${datadir}/@PACKAGE@"
++fi
++
++self=`basename $0`
++
++grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@"
++grub_editenv=${bindir}/@grub_editenv@
++etcdefaultgrub=/etc/default/grub
++
++eval "$("${grub_get_kernel_settings}")" || true
++
++EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g')
++if [ -d /sys/firmware/efi/efivars/ ]; then
++    startlink=/etc/grub2-efi.cfg
++    grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'`
++else
++    startlink=/etc/grub2.cfg
++    grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`
++fi
++
++blsdir=`echo "/@bootdirname@/loader/entries" | sed 's,//*,/,g'`
++
++backupsuffix=.bak
++
++arch="$(uname -m)"
++
++export TEXTDOMAIN=@PACKAGE@
++export TEXTDOMAINDIR="@localedir@"
++
++. "${pkgdatadir}/grub-mkconfig_lib"
++
++# Usage: usage
++# Print the usage.
++usage () {
++    gettext_printf "Usage: %s\n" "$self"
++    gettext "Switch to BLS config files.\n"; echo
++    echo
++    print_option_help "-h, --help" "$(gettext "print this message and exit")"
++    print_option_help "-V, --version" "$(gettext "print the version information and exit")"
++    echo
++    print_option_help "--backup-suffix=$(gettext "SUFFIX")" "$backupsuffix"
++    print_option_help "--bls-directory=$(gettext "DIR")" "$blsdir"
++    print_option_help "--config-file=$(gettext "FILE")" "$startlink"
++    print_option_help "--grub-defaults=$(gettext "FILE")" "$etcdefaultgrub"
++    print_option_help "--grub-directory=$(gettext "DIR")" "$grubdir"
++    # echo
++    # gettext "Report bugs to <bug-grub@gnu.org>."; echo
++}
++
++argument () {
++    opt=$1
++    shift
++
++    if test $# -eq 0; then
++        gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$opt" 1>&2
++        exit 1
++    fi
++    echo $1
++}
++
++# Check the arguments.
++while test $# -gt 0
++do
++    option=$1
++    shift
++
++    case "$option" in
++    -h | --help)
++        usage
++        exit 0 ;;
++    -V | --version)
++        echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}"
++        exit 0 ;;
++
++    --backup-suffix)
++        backupsuffix=`argument $option "$@"`
++        shift
++        ;;
++    --backup-suffix=*)
++        backupsuffix=`echo "$option" | sed 's/--backup-suffix=//'`
++        ;;
++
++    --bls-directory)
++        blsdir=`argument $option "$@"`
++        shift
++        ;;
++    --bls-directory=*)
++        blsdir=`echo "$option" | sed 's/--bls-directory=//'`
++        ;;
++
++    --config-file)
++        startlink=`argument $option "$@"`
++        shift
++        ;;
++    --config-file=*)
++        startlink=`echo "$option" | sed 's/--config-file=//'`
++        ;;
++
++    --grub-defaults)
++        etcdefaultgrub=`argument $option "$@"`
++        shift
++        ;;
++    --grub-defaults=*)
++        etcdefaultgrub=`echo "$option" | sed 's/--grub-defaults=//'`
++        ;;
++
++    --grub-directory)
++        grubdir=`argument $option "$@"`
++        shift
++        ;;
++    --grub-directory=*)
++        grubdir=`echo "$option" | sed 's/--grub-directory=//'`
++        ;;
++
++    *)
++        gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2
++        usage
++        exit 1
++        ;;
++    esac
++done
++
++find_grub_cfg() {
++    local candidate=""
++    while [ -e "${candidate}" -o $# -gt 0 ]
++    do
++        if [ ! -e "${candidate}" ] ; then
++            candidate="$1"
++            shift
++        fi
++
++        if [ -L "${candidate}" ]; then
++            candidate="$(realpath "${candidate}")"
++        fi
++
++        if [ -f "${candidate}" ]; then
++            export GRUB_CONFIG_FILE="${candidate}"
++            return 0
++        fi
++    done
++    return 1
++}
++
++if ! find_grub_cfg ${startlink} ${grubdir}/grub.cfg ; then
++  gettext_printf "Couldn't find config file\n" 1>&2
++  exit 1
++fi
++
++if [ ! -d "${blsdir}" ]; then
++    install -m 700 -d "${blsdir}"
++fi
++
++if [ -f /etc/machine-id ]; then
++    MACHINE_ID=$(cat /etc/machine-id)
++else
++    MACHINE_ID=$(dmesg | sha256sum)
++fi
++
++mkbls() {
++    local kernelver=$1 && shift
++    local datetime=$1 && shift
++    local kernelopts=$1 && shift
++
++    local debugname=""
++    local debugid=""
++    local flavor=""
++
++    if [ "$kernelver" == *\+* ] ; then
++        local flavor=-"${kernelver##*+}"
++        if [ "${flavor}" == "-debug" ]; then
++            local debugname=" with debugging"
++            local debugid="-debug"
++        fi
++    fi
++    (
++        source /etc/os-release
++
++        cat <<EOF
++title ${NAME} (${kernelver}) ${VERSION}${debugname}
++version ${kernelver}${debugid}
++linux /vmlinuz-${kernelver}
++initrd /initramfs-${kernelver}.img
++options ${kernelopts}
++grub_users \$grub_users
++grub_arg --unrestricted
++grub_class kernel${flavor}
++EOF
++    ) | cat
++}
++
++copy_bls() {
++    for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
++	bls_target="${blsdir}/${MACHINE_ID}-${kernelver}.conf"
++	linux="/vmlinuz-${kernelver}"
++	linux_path="/boot${linux}"
++	kernel_dir="/lib/modules/${kernelver}"
++
++	if [ ! -d "${kernel_dir}" ] ; then
++            continue
++	fi
++	if [ ! -f "${linux_path}" ]; then
++            continue
++	fi
++
++	linux_relpath="$("${grub_mkrelpath}" "${linux_path}")"
++	bootprefix="${linux_relpath%%"${linux}"}"
++	cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
++
++	mkbls "${kernelver}" \
++	      "$(date -u +%Y%m%d%H%M%S -d "$(stat -c '%y' "${kernel_dir}")")" \
++	      "${bootprefix}" "${cmdline}" >"${bls_target}"
++
++	if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
++            bls_debug="$(echo ${bls_target} | sed -e "s/${kernelver}/${kernelver}~debug/")"
++            cp -aT  "${bls_target}" "${bls_debug}"
++            title="$(grep '^title[ \t]' "${bls_debug}" | sed -e 's/^title[ \t]*//')"
++            options="$(echo "${cmdline} ${GRUB_CMDLINE_LINUX_DEBUG}" | sed -e 's/\//\\\//g')"
++            sed -i -e "s/^title.*/title ${title}${GRUB_LINUX_DEBUG_TITLE_POSTFIX}/" "${bls_debug}"
++            sed -i -e "s/^options.*/options ${options}/" "${bls_debug}"
++	fi
++    done
++
++    if [ -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]; then
++	mkbls "0-rescue-${MACHINE_ID}" "0" "${bootprefix}" >"${blsdir}/${MACHINE_ID}-0-rescue.conf"
++    fi
++}
++
++# The grub2 EFI binary is not copied to the ESP as a part of an ostree
++# transaction. Make sure a grub2 version with BLS support is installed
++# but only do this if the blsdir is not set, to make sure that the BLS
++# parsing module will search for the BLS snippets in the default path.
++if test -f /run/ostree-booted && test -d /sys/firmware/efi/efivars && \
++   ! ${grub_editenv} - list | grep -q blsdir && \
++   mountpoint -q /boot; then
++    grub_binary="$(find /usr/lib/ostree-boot/efi/EFI/${EFIDIR}/ -name grub*.efi)"
++    install -m 700 ${grub_binary} ${grubdir} || exit 1
++    # Create a hidden file to indicate that grub2 now has BLS support.
++    touch /boot/grub2/.grub2-blscfg-supported
++fi
++
++GENERATE=0
++if grep '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" \
++        | grep -vq '^GRUB_ENABLE_BLSCFG="*true"*\s*$' ; then
++    if ! sed -i"${backupsuffix}" \
++            -e 's,^GRUB_ENABLE_BLSCFG=.*,GRUB_ENABLE_BLSCFG=true,' \
++            "${etcdefaultgrub}" ; then
++        gettext_printf "Updating %s failed\n" "${etcdefaultgrub}"
++        exit 1
++    fi
++    GENERATE=1
++elif ! grep -q '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" ; then
++    if ! echo 'GRUB_ENABLE_BLSCFG=true' >> "${etcdefaultgrub}" ; then
++        gettext_printf "Updating %s failed\n" "${etcdefaultgrub}"
++        exit 1
++    fi
++    GENERATE=1
++fi
++
++if [ "${GENERATE}" -eq 1 ] ; then
++    copy_bls
++
++    if [ $arch = "x86_64" ] && [ ! -d /sys/firmware/efi ]; then
++	mod_dir="i386-pc"
++    elif [ $arch = "ppc64" -o $arch = "ppc64le" ] && [ ! -d /sys/firmware/opal ]; then
++	mod_dir="powerpc-ieee1275"
++    fi
++
++    if [ -n "${mod_dir}" ]; then
++	for mod in blscfg increment; do
++	    install -m 700 ${prefix}/lib/grub/${mod_dir}/${mod}.mod ${grubdir}/$mod_dir/ || exit 1
++	done
++    fi
++
++    cp -af "${GRUB_CONFIG_FILE}" "${GRUB_CONFIG_FILE}${backupsuffix}"
++    if ! grub2-mkconfig -o "${GRUB_CONFIG_FILE}" ; then
++        install -m 700 "${GRUB_CONFIG_FILE}${backupsuffix}" "${GRUB_CONFIG_FILE}"
++        sed -i"${backupsuffix}" \
++            -e 's,^GRUB_ENABLE_BLSCFG=.*,GRUB_ENABLE_BLSCFG=false,' \
++            "${etcdefaultgrub}"
++        gettext_printf "Updating %s failed\n" "${GRUB_CONFIG_FILE}"
++        exit 1
++    fi
++fi
++
++# Bye.
++exit 0
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 2851952659..e490e1a43a 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -138,7 +138,7 @@ blsdir="/boot/loader/entries"
+ 
+ get_sorted_bls()
+ {
+-    if ! [ -d "${blsdir}" ]; then
++    if ! [ -d "${blsdir}" ] || [ -f /run/ostree-booted ] || [ -d /ostree/repo ]; then
+         return
+     fi
+ 
diff --git a/SOURCES/0060-grub2-btrfs-04-grub2-install.patch b/SOURCES/0060-grub2-btrfs-04-grub2-install.patch
deleted file mode 100644
index f91c31a..0000000
--- a/SOURCES/0060-grub2-btrfs-04-grub2-install.patch
+++ /dev/null
@@ -1,174 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Michael Chang <mchang@suse.com>
-Date: Thu, 21 Aug 2014 03:39:11 +0000
-Subject: [PATCH] grub2-btrfs-04-grub2-install
-
----
- grub-core/osdep/linux/getroot.c |  7 +++++++
- grub-core/osdep/unix/config.c   | 17 +++++++++++++++--
- util/config.c                   | 10 ++++++++++
- util/grub-install.c             | 15 +++++++++++++++
- util/grub-mkrelpath.c           |  6 ++++++
- include/grub/emu/config.h       |  1 +
- 6 files changed, 54 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
-index 001b818fe58..caf9b1ccd3f 100644
---- a/grub-core/osdep/linux/getroot.c
-+++ b/grub-core/osdep/linux/getroot.c
-@@ -376,6 +376,7 @@ get_btrfs_fs_prefix (const char *mount_path)
-   return NULL;
- }
- 
-+int use_relative_path_on_btrfs = 0;
- 
- char **
- grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
-@@ -519,6 +520,12 @@ again:
- 	{
- 	  ret = grub_find_root_devices_from_btrfs (dir);
- 	  fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
-+	  if (use_relative_path_on_btrfs)
-+	    {
-+	      if (fs_prefix)
-+	        free (fs_prefix);
-+	      fs_prefix = xstrdup ("/");
-+	    }
- 	}
-       else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0)
- 	{
-diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c
-index 7d6325138ce..46a881530c0 100644
---- a/grub-core/osdep/unix/config.c
-+++ b/grub-core/osdep/unix/config.c
-@@ -82,6 +82,19 @@ grub_util_load_config (struct grub_util_config *cfg)
-   if (v)
-     cfg->grub_distributor = xstrdup (v);
- 
-+  v = getenv ("SUSE_BTRFS_SNAPSHOT_BOOTING");
-+  if (v)
-+    {
-+      if (grub_strncmp(v, "true", sizeof ("true") - 1) == 0)
-+        {
-+          cfg->is_suse_btrfs_snapshot_enabled = 1;
-+        }
-+      else
-+        {
-+          cfg->is_suse_btrfs_snapshot_enabled = 0;
-+        }
-+    }
-+
-   cfgfile = grub_util_get_config_filename ();
-   if (!grub_util_is_regular (cfgfile))
-     return;
-@@ -105,8 +118,8 @@ grub_util_load_config (struct grub_util_config *cfg)
-       *ptr++ = *iptr;
-     }
- 
--  strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" "
--	  "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\"");
-+  strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\nSUSE_BTRFS_SNAPSHOT_BOOTING=%s\\n\" "
-+	  "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\" \"$SUSE_BTRFS_SNAPSHOT_BOOTING\"");
- 
-   argv[2] = script;
-   argv[3] = '\0';
-diff --git a/util/config.c b/util/config.c
-index ebcdd8f5e22..f044a880a76 100644
---- a/util/config.c
-+++ b/util/config.c
-@@ -42,6 +42,16 @@ grub_util_parse_config (FILE *f, struct grub_util_config *cfg, int simple)
- 	    cfg->is_cryptodisk_enabled = 1;
- 	  continue;
- 	}
-+      if (grub_strncmp (ptr, "SUSE_BTRFS_SNAPSHOT_BOOTING=",
-+			sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1) == 0)
-+	{
-+	  ptr += sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1;
-+	  if (*ptr == '"' || *ptr == '\'')
-+	    ptr++;
-+	  if (grub_strncmp(ptr, "true", sizeof ("true") - 1) == 0)
-+	    cfg->is_suse_btrfs_snapshot_enabled = 1;
-+	  continue;
-+	}
-       if (grub_strncmp (ptr, "GRUB_DISTRIBUTOR=",
- 			sizeof ("GRUB_DISTRIBUTOR=") - 1) == 0)
- 	{
-diff --git a/util/grub-install.c b/util/grub-install.c
-index 0fbe7f78c6d..0f66f36d23a 100644
---- a/util/grub-install.c
-+++ b/util/grub-install.c
-@@ -827,6 +827,8 @@ fill_core_services (const char *core_services)
-   free (sysv_plist);
- }
- 
-+extern int use_relative_path_on_btrfs;
-+
- int
- main (int argc, char *argv[])
- {
-@@ -860,6 +862,9 @@ main (int argc, char *argv[])
- 
-   grub_util_load_config (&config);
- 
-+  if (config.is_suse_btrfs_snapshot_enabled)
-+    use_relative_path_on_btrfs = 1;
-+
-   if (!bootloader_id && config.grub_distributor)
-     {
-       char *ptr;
-@@ -1352,6 +1357,16 @@ main (int argc, char *argv[])
-       fprintf (load_cfg_f, "set debug='%s'\n",
- 	      debug_image);
-     }
-+
-+  if (config.is_suse_btrfs_snapshot_enabled
-+      && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0)
-+    {
-+      if (!load_cfg_f)
-+        load_cfg_f = grub_util_fopen (load_cfg, "wb");
-+      have_load_cfg = 1;
-+      fprintf (load_cfg_f, "set btrfs_relative_path='y'\n");
-+    }
-+
-   char *prefix_drive = NULL;
-   char *install_drive = NULL;
- 
-diff --git a/util/grub-mkrelpath.c b/util/grub-mkrelpath.c
-index 47a241a391b..5db7a9a7d97 100644
---- a/util/grub-mkrelpath.c
-+++ b/util/grub-mkrelpath.c
-@@ -40,9 +40,12 @@ struct arguments
- };
- 
- static struct argp_option options[] = {
-+  {"relative",  'r', 0, 0, "use relative path on btrfs", 0},
-   { 0, 0, 0, 0, 0, 0 }
- };
- 
-+extern int use_relative_path_on_btrfs;
-+
- static error_t
- argp_parser (int key, char *arg, struct argp_state *state)
- {
-@@ -52,6 +55,9 @@ argp_parser (int key, char *arg, struct argp_state *state)
- 
-   switch (key)
-     {
-+    case 'r':
-+      use_relative_path_on_btrfs = 1;
-+      break;
-     case ARGP_KEY_ARG:
-       if (state->arg_num == 0)
- 	arguments->pathname = xstrdup (arg);
-diff --git a/include/grub/emu/config.h b/include/grub/emu/config.h
-index 875d5896ce1..c9a7e5f4ade 100644
---- a/include/grub/emu/config.h
-+++ b/include/grub/emu/config.h
-@@ -37,6 +37,7 @@ struct grub_util_config
- {
-   int is_cryptodisk_enabled;
-   char *grub_distributor;
-+  int is_suse_btrfs_snapshot_enabled;
- };
- 
- void
diff --git a/SOURCES/0061-grub2-btrfs-05-grub2-mkconfig.patch b/SOURCES/0061-grub2-btrfs-05-grub2-mkconfig.patch
deleted file mode 100644
index 8270505..0000000
--- a/SOURCES/0061-grub2-btrfs-05-grub2-mkconfig.patch
+++ /dev/null
@@ -1,129 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Michael Chang <mchang@suse.com>
-Date: Thu, 21 Aug 2014 03:39:11 +0000
-Subject: [PATCH] grub2-btrfs-05-grub2-mkconfig
-
-Signed-off-by: Michael Chang <mchang@suse.com>
----
- util/grub-mkconfig.in       |  3 ++-
- util/grub-mkconfig_lib.in   |  4 ++++
- util/grub.d/00_header.in    | 25 ++++++++++++++++++++++++-
- util/grub.d/10_linux.in     |  4 ++++
- util/grub.d/20_linux_xen.in |  4 ++++
- 5 files changed, 38 insertions(+), 2 deletions(-)
-
-diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
-index 005f093809b..535c0f02499 100644
---- a/util/grub-mkconfig.in
-+++ b/util/grub-mkconfig.in
-@@ -252,7 +252,8 @@ export GRUB_DEFAULT \
-   GRUB_BADRAM \
-   GRUB_OS_PROBER_SKIP_LIST \
-   GRUB_DISABLE_SUBMENU \
--  GRUB_DEFAULT_DTB
-+  GRUB_DEFAULT_DTB \
-+  SUSE_BTRFS_SNAPSHOT_BOOTING
- 
- if test "x${grub_cfg}" != "x"; then
-   rm -f "${grub_cfg}.new"
-diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
-index 42c2ea9ba50..fafeac95061 100644
---- a/util/grub-mkconfig_lib.in
-+++ b/util/grub-mkconfig_lib.in
-@@ -52,7 +52,11 @@ grub_warn ()
- 
- make_system_path_relative_to_its_root ()
- {
-+  if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] ; then
-+  "${grub_mkrelpath}" -r "$1"
-+  else
-   "${grub_mkrelpath}" "$1"
-+  fi
- }
- 
- is_path_readable_by_grub ()
-diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
-index 858b526c925..de727e6ee6b 100644
---- a/util/grub.d/00_header.in
-+++ b/util/grub.d/00_header.in
-@@ -27,6 +27,14 @@ export TEXTDOMAINDIR="@localedir@"
- 
- . "$pkgdatadir/grub-mkconfig_lib"
- 
-+if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] &&
-+   [ "x${GRUB_FS}" = "xbtrfs" ] ; then
-+    cat <<EOF
-+set btrfs_relative_path="y"
-+export btrfs_relative_path
-+EOF
-+fi
-+
- # Do this as early as possible, since other commands might depend on it.
- # (e.g. the `loadfont' command might need lvm or raid modules)
- for i in ${GRUB_PRELOAD_MODULES} ; do
-@@ -45,7 +53,9 @@ if [ "x${GRUB_TIMEOUT_BUTTON}" = "x" ] ; then GRUB_TIMEOUT_BUTTON="$GRUB_TIMEOUT
- cat << EOF
- set pager=1
- 
--if [ -s \$prefix/grubenv ]; then
-+if [ -f \${config_directory}/grubenv ]; then
-+  load_env -f \${config_directory}/grubenv
-+elif [ -s \$prefix/grubenv ]; then
-   load_env
- fi
- EOF
-@@ -356,3 +366,16 @@ fi
- if [ "x${GRUB_BADRAM}" != "x" ] ; then
-   echo "badram ${GRUB_BADRAM}"
- fi
-+
-+if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] &&
-+   [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ] &&
-+   [ "x${GRUB_FS}" = "xbtrfs" ] ; then
-+    # Note: No $snapshot_num on *read-only* rollback!  (bsc#901487)
-+    cat <<EOF
-+if [ -n "\$extra_cmdline" ]; then
-+  submenu "Bootable snapshot #\$snapshot_num" {
-+    menuentry "If OK, run 'snapper rollback' and reboot." { true; }
-+  }
-+fi
-+EOF
-+fi
-diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
-index 0f3c19e30cc..cbfaca34cc7 100644
---- a/util/grub.d/10_linux.in
-+++ b/util/grub.d/10_linux.in
-@@ -66,10 +66,14 @@ fi
- 
- case x"$GRUB_FS" in
-     xbtrfs)
-+	if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ]; then
-+	GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX} \${extra_cmdline}"
-+	else
- 	rootsubvol="`make_system_path_relative_to_its_root /`"
- 	rootsubvol="${rootsubvol#/}"
- 	if [ "x${rootsubvol}" != x ]; then
- 	    GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}"
-+	fi
- 	fi;;
-     xzfs)
- 	rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true`
-diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in
-index ada20775a14..e9e73b815fb 100644
---- a/util/grub.d/20_linux_xen.in
-+++ b/util/grub.d/20_linux_xen.in
-@@ -73,10 +73,14 @@ fi
- 
- case x"$GRUB_FS" in
-     xbtrfs)
-+	if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ]; then
-+	GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX} \${extra_cmdline}"
-+	else
- 	rootsubvol="`make_system_path_relative_to_its_root /`"
- 	rootsubvol="${rootsubvol#/}"
- 	if [ "x${rootsubvol}" != x ]; then
- 	    GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}"
-+	fi
- 	fi;;
-     xzfs)
- 	rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true`
diff --git a/SOURCES/0061-make-better-backtraces.patch b/SOURCES/0061-make-better-backtraces.patch
new file mode 100644
index 0000000..7fdcaf7
--- /dev/null
+++ b/SOURCES/0061-make-better-backtraces.patch
@@ -0,0 +1,910 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 9 Jul 2019 17:05:03 +0200
+Subject: [PATCH] make better backtraces
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ Makefile.util.def                       |   6 ++
+ grub-core/Makefile.core.def             |  16 ++--
+ grub-core/{lib => commands}/backtrace.c |   2 +-
+ grub-core/gdb/cstub.c                   |   1 -
+ grub-core/kern/arm64/backtrace.c        |  94 ++++++++++++++++++++++++
+ grub-core/kern/backtrace.c              |  97 +++++++++++++++++++++++++
+ grub-core/kern/dl.c                     |  45 ++++++++++++
+ grub-core/kern/i386/backtrace.c         | 125 ++++++++++++++++++++++++++++++++
+ grub-core/kern/i386/pc/init.c           |   4 +-
+ grub-core/kern/ieee1275/init.c          |   1 -
+ grub-core/kern/misc.c                   |  13 ++--
+ grub-core/kern/mm.c                     |   6 +-
+ grub-core/lib/arm64/backtrace.c         |  62 ----------------
+ grub-core/lib/i386/backtrace.c          |  78 --------------------
+ include/grub/backtrace.h                |  10 ++-
+ include/grub/dl.h                       |   2 +
+ include/grub/kernel.h                   |   3 +
+ grub-core/kern/arm/efi/startup.S        |   2 +
+ grub-core/kern/arm/startup.S            |   2 +
+ grub-core/kern/arm64/efi/startup.S      |   2 +
+ grub-core/kern/i386/qemu/startup.S      |   3 +-
+ grub-core/kern/ia64/efi/startup.S       |   3 +-
+ grub-core/kern/sparc64/ieee1275/crt0.S  |   3 +-
+ grub-core/Makefile.am                   |   1 +
+ 24 files changed, 414 insertions(+), 167 deletions(-)
+ rename grub-core/{lib => commands}/backtrace.c (98%)
+ create mode 100644 grub-core/kern/arm64/backtrace.c
+ create mode 100644 grub-core/kern/backtrace.c
+ create mode 100644 grub-core/kern/i386/backtrace.c
+ delete mode 100644 grub-core/lib/arm64/backtrace.c
+ delete mode 100644 grub-core/lib/i386/backtrace.c
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 88f55e35c4..bda9fd1211 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -51,6 +51,12 @@ library = {
+   common = grub-core/partmap/msdos.c;
+   common = grub-core/fs/proc.c;
+   common = grub-core/fs/archelp.c;
++  common = grub-core/kern/backtrace.c;
++
++  x86 = grub-core/kern/i386/backtrace.c;
++  i386_xen = grub-core/kern/i386/backtrace.c;
++  x86_64_xen = grub-core/kern/i386/backtrace.c;
++  arm64 = grub-core/kern/arm64/backtrace.c;
+ };
+ 
+ library = {
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 058c88ac3a..52ec0fafcd 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -142,6 +142,12 @@ kernel = {
+   common = kern/rescue_reader.c;
+   common = kern/term.c;
+   common = kern/verifiers.c;
++  common = kern/backtrace.c;
++
++  x86 = kern/i386/backtrace.c;
++  i386_xen = kern/i386/backtrace.c;
++  x86_64_xen = kern/i386/backtrace.c;
++  arm64 = kern/arm64/backtrace.c;
+ 
+   noemu = kern/compiler-rt.c;
+   noemu = kern/mm.c;
+@@ -188,9 +194,6 @@ kernel = {
+ 
+   softdiv = lib/division.c;
+ 
+-  x86 = lib/i386/backtrace.c;
+-  x86 = lib/backtrace.c;
+-
+   i386 = kern/i386/dl.c;
+   i386_xen = kern/i386/dl.c;
+   i386_xen_pvh = kern/i386/dl.c;
+@@ -2399,15 +2402,12 @@ module = {
+ 
+ module = {
+   name = backtrace;
+-  x86 = lib/i386/backtrace.c;
+-  i386_xen_pvh = lib/i386/backtrace.c;
+-  i386_xen = lib/i386/backtrace.c;
+-  x86_64_xen = lib/i386/backtrace.c;
+-  common = lib/backtrace.c;
++  common = commands/backtrace.c;
+   enable = x86;
+   enable = i386_xen_pvh;
+   enable = i386_xen;
+   enable = x86_64_xen;
++  enable = arm64;
+ };
+ 
+ module = {
+diff --git a/grub-core/lib/backtrace.c b/grub-core/commands/backtrace.c
+similarity index 98%
+rename from grub-core/lib/backtrace.c
+rename to grub-core/commands/backtrace.c
+index c0ad6ab8be..8b5ec3913b 100644
+--- a/grub-core/lib/backtrace.c
++++ b/grub-core/commands/backtrace.c
+@@ -54,7 +54,7 @@ grub_cmd_backtrace (grub_command_t cmd __attribute__ ((unused)),
+ 		    int argc __attribute__ ((unused)),
+ 		    char **args __attribute__ ((unused)))
+ {
+-  grub_backtrace ();
++  grub_backtrace (1);
+   return 0;
+ }
+ 
+diff --git a/grub-core/gdb/cstub.c b/grub-core/gdb/cstub.c
+index b64acd70fe..99281472d3 100644
+--- a/grub-core/gdb/cstub.c
++++ b/grub-core/gdb/cstub.c
+@@ -215,7 +215,6 @@ grub_gdb_trap (int trap_no)
+       grub_printf ("Unhandled exception 0x%x at ", trap_no);
+       grub_backtrace_print_address ((void *) grub_gdb_regs[PC]);
+       grub_printf ("\n");
+-      grub_backtrace_pointer ((void *) grub_gdb_regs[EBP]);
+       grub_fatal ("Unhandled exception");
+     }
+ 
+diff --git a/grub-core/kern/arm64/backtrace.c b/grub-core/kern/arm64/backtrace.c
+new file mode 100644
+index 0000000000..019c6fdfef
+--- /dev/null
++++ b/grub-core/kern/arm64/backtrace.c
+@@ -0,0 +1,94 @@
++/*
++ *  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/misc.h>
++#include <grub/command.h>
++#include <grub/err.h>
++#include <grub/dl.h>
++#include <grub/mm.h>
++#include <grub/term.h>
++#include <grub/backtrace.h>
++
++#define MAX_STACK_FRAME 102400
++
++struct fplr
++{
++  void *lr;
++  struct fplr *fp;
++};
++
++void
++grub_backtrace_pointer (void *frame, unsigned int skip)
++{
++  unsigned int x = 0;
++  struct fplr *fplr = (struct fplr *)frame;
++
++  while (fplr)
++    {
++      const char *name = NULL;
++      char *addr = NULL;
++
++      grub_dprintf("backtrace", "fp is %p next_fp is %p\n",
++		   fplr, fplr->fp);
++
++      if (x >= skip)
++	{
++	  name = grub_get_symbol_by_addr (fplr->lr, 1);
++	  if (name)
++	    addr = grub_resolve_symbol (name);
++	  grub_backtrace_print_address (fplr->lr);
++
++	  if (addr && addr != fplr->lr)
++	    grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr,
++			 (void *)((grub_uint64_t)fplr->lr - (grub_uint64_t)addr));
++	  else
++	    grub_printf(" %s() %p \n", name ? name : "unknown", addr);
++
++	}
++
++      x += 1;
++
++      if (fplr->fp < fplr ||
++	  (grub_uint64_t)fplr->fp - (grub_uint64_t)fplr > MAX_STACK_FRAME ||
++	  fplr->fp == fplr)
++	{
++	  break;
++	}
++      fplr = fplr->fp;
++    }
++}
++
++asm ("\t.global \"_text\"\n"
++     "_text:\n"
++     "\t.quad .text\n"
++     "\t.global \"_data\"\n"
++     "_data:\n"
++     "\t.quad .data\n"
++     );
++
++extern grub_uint64_t _text;
++extern grub_uint64_t _data;
++
++void
++grub_backtrace_arch (unsigned int skip)
++{
++  grub_printf ("Backtrace (.text %p .data %p):\n",
++	       (void *)_text, (void *)_data);
++  skip += 1;
++  grub_backtrace_pointer(__builtin_frame_address(0), skip);
++}
+diff --git a/grub-core/kern/backtrace.c b/grub-core/kern/backtrace.c
+new file mode 100644
+index 0000000000..4a82e865cc
+--- /dev/null
++++ b/grub-core/kern/backtrace.c
+@@ -0,0 +1,97 @@
++/*
++ *  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/misc.h>
++#include <grub/command.h>
++#include <grub/err.h>
++#include <grub/dl.h>
++#include <grub/mm.h>
++#include <grub/term.h>
++#include <grub/backtrace.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++static void
++grub_backtrace_print_address_default (void *addr)
++{
++#ifndef GRUB_UTIL
++  grub_dl_t mod;
++  void *start_addr;
++
++  FOR_DL_MODULES (mod)
++  {
++    grub_dl_segment_t segment;
++    for (segment = mod->segment; segment; segment = segment->next)
++      if (segment->addr <= addr && (grub_uint8_t *) segment->addr
++	  + segment->size > (grub_uint8_t *) addr)
++	{
++	  grub_printf ("%s.%x+%" PRIxGRUB_SIZE, mod->name,
++		       segment->section,
++		       (grub_size_t)
++		       ((grub_uint8_t *)addr - (grub_uint8_t *)segment->addr));
++	  return;
++	}
++  }
++
++  start_addr = grub_resolve_symbol ("_start");
++  if (start_addr && start_addr < addr)
++    grub_printf ("kernel+%" PRIxGRUB_SIZE,
++		 (grub_size_t)
++		  ((grub_uint8_t *)addr - (grub_uint8_t *)start_addr));
++  else
++#endif
++    grub_printf ("%p", addr);
++}
++
++static void
++grub_backtrace_pointer_default (void *frame __attribute__((__unused__)),
++				unsigned int skip __attribute__((__unused__)))
++{
++  return;
++}
++
++void
++grub_backtrace_pointer (void *frame, unsigned int skip)
++     __attribute__((__weak__,
++		    __alias__(("grub_backtrace_pointer_default"))));
++
++void
++grub_backtrace_print_address (void *addr)
++     __attribute__((__weak__,
++		    __alias__(("grub_backtrace_print_address_default"))));
++
++static void
++grub_backtrace_arch_default(unsigned int skip)
++{
++  grub_backtrace_pointer(__builtin_frame_address(0), skip + 1);
++}
++
++void grub_backtrace_arch (unsigned int skip)
++     __attribute__((__weak__, __alias__(("grub_backtrace_arch_default"))));
++
++void grub_backtrace (unsigned int skip)
++{
++  grub_backtrace_arch(skip + 1);
++}
++
++void grub_debug_backtrace (const char * const debug,
++			   unsigned int skip)
++{
++  if (grub_debug_enabled (debug))
++    grub_backtrace (skip + 1);
++}
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index 7afb9e6f72..88d2077709 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -124,6 +124,50 @@ grub_dl_resolve_symbol (const char *name)
+   return 0;
+ }
+ 
++void *
++grub_resolve_symbol (const char *name)
++{
++	grub_symbol_t sym;
++
++	sym = grub_dl_resolve_symbol (name);
++	if (sym)
++		return sym->addr;
++	return NULL;
++}
++
++const char *
++grub_get_symbol_by_addr(const void *addr, int isfunc)
++{
++  unsigned int i;
++  grub_symbol_t before = NULL, after = NULL;
++  for (i = 0; i < GRUB_SYMTAB_SIZE; i++)
++    {
++      grub_symbol_t sym;
++      for (sym = grub_symtab[i]; sym; sym = sym->next)
++	{
++	  //grub_printf ("addr 0x%08llx symbol %s\n", (unsigned long long)sym->addr, sym->name);
++	  if (sym->addr > addr)
++	    {
++	      if (!after || sym->addr > after->addr)
++		after = sym;
++	    }
++
++	  if (isfunc != sym->isfunc)
++	    continue;
++	  if (sym->addr > addr)
++	    continue;
++
++	  if ((!before && sym->addr <= addr) || (before && before->addr <= sym->addr))
++	    before = sym;
++	}
++    }
++
++  if (before && addr < after->addr)
++    return before->name;
++
++  return NULL;
++}
++
+ /* Register a symbol with the name NAME and the address ADDR.  */
+ grub_err_t
+ grub_dl_register_symbol (const char *name, void *addr, int isfunc,
+@@ -336,6 +380,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
+   const char *str;
+   Elf_Word size, entsize;
+ 
++  grub_dprintf ("modules", "Resolving symbols for \"%s\"\n", mod->name);
+   for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
+        i < e->e_shnum;
+        i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
+diff --git a/grub-core/kern/i386/backtrace.c b/grub-core/kern/i386/backtrace.c
+new file mode 100644
+index 0000000000..2413f9a57d
+--- /dev/null
++++ b/grub-core/kern/i386/backtrace.c
+@@ -0,0 +1,125 @@
++/*
++ *  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/misc.h>
++#include <grub/command.h>
++#include <grub/err.h>
++#include <grub/dl.h>
++#include <grub/mm.h>
++#include <grub/term.h>
++#include <grub/backtrace.h>
++
++#define MAX_STACK_FRAME 102400
++
++void
++grub_backtrace_pointer (void *frame, unsigned int skip)
++{
++  void **ebp = (void **)frame;
++  unsigned long x = 0;
++
++  while (ebp)
++    {
++      void **next_ebp = (void **)ebp[0];
++      const char *name = NULL;
++      char *addr = NULL;
++
++      grub_dprintf("backtrace", "ebp is %p next_ebp is %p\n", ebp, next_ebp);
++
++      if (x >= skip)
++	{
++	  name = grub_get_symbol_by_addr (ebp[1], 1);
++	  if (name)
++	    addr = grub_resolve_symbol (name);
++	  grub_backtrace_print_address (ebp[1]);
++
++	  if (addr && addr != ebp[1])
++	    grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr,
++			 (char *)((char *)ebp[1] - addr));
++	  else
++	    grub_printf(" %s() %p \n", name ? name : "unknown", addr);
++
++#if 0
++	  grub_printf ("(");
++	  for (i = 0, arg = ebp[2]; arg != next_ebp && i < 12; arg++, i++)
++	    grub_printf ("%p,", arg);
++	  grub_printf (")\n");
++#endif
++	}
++
++      x += 1;
++
++      if (next_ebp < ebp || next_ebp - ebp > MAX_STACK_FRAME || next_ebp == ebp)
++	{
++	  //grub_printf ("Invalid stack frame at %p (%p)\n", ebp, next_ebp);
++	  break;
++	}
++      ebp = next_ebp;
++    }
++}
++
++#if defined (__x86_64__)
++asm ("\t.global \"_text\"\n"
++     "_text:\n"
++     "\t.quad .text\n"
++     "\t.global \"_data\"\n"
++     "_data:\n"
++     "\t.quad .data\n"
++     );
++#elif defined(__i386__)
++asm ("\t.global \"_text\"\n"
++     "_text:\n"
++     "\t.long .text\n"
++     "\t.global \"_data\"\n"
++     "_data:\n"
++     "\t.long .data\n"
++     );
++#else
++#warning I dunno...
++#endif
++
++extern unsigned long _text;
++extern unsigned long _data;
++
++#ifdef GRUB_UTIL
++#define EXT_C(x) x
++#endif
++
++void
++grub_backtrace_arch (unsigned int skip)
++{
++  grub_printf ("Backtrace (.text %p .data %p):\n",
++	       (void *)_text, (void *)_data);
++  skip += 1;
++#if defined (__x86_64__)
++  asm volatile ("movq %%rbp, %%rdi\n"
++		"movq 0, %%rsi\n"
++		"movl %0, %%esi\n"
++		"call " EXT_C("grub_backtrace_pointer")
++		:
++		: "r" (skip));
++#elif defined(__i386__)
++  asm volatile ("addl $8, %%esp\n"
++		"pushl %0\n"
++		"pushl %%ebp\n"
++		"call " EXT_C("grub_backtrace_pointer")
++		:
++		: "r" (skip));
++#else
++  grub_backtrace_pointer(__builtin_frame_address(0), skip);
++#endif
++}
+diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c
+index 27bc68b8a5..b51d0abfa6 100644
+--- a/grub-core/kern/i386/pc/init.c
++++ b/grub-core/kern/i386/pc/init.c
+@@ -153,7 +153,7 @@ compact_mem_regions (void)
+ }
+ 
+ grub_addr_t grub_modbase;
+-extern grub_uint8_t _start[], _edata[];
++extern grub_uint8_t _edata[];
+ 
+ /* Helper for grub_machine_init.  */
+ static int
+@@ -217,7 +217,7 @@ grub_machine_init (void)
+   /* This has to happen before any BIOS calls. */
+   grub_via_workaround_init ();
+ 
+-  grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - _start);
++  grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - (grub_uint8_t *)_start);
+ 
+   /* Initialize the console as early as possible.  */
+   grub_console_init ();
+diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
+index 0cd2a62723..937c1bc44c 100644
+--- a/grub-core/kern/ieee1275/init.c
++++ b/grub-core/kern/ieee1275/init.c
+@@ -63,7 +63,6 @@
+ #define HEAP_MAX_ADDR		(unsigned long) (32 * 1024 * 1024)
+ #endif
+ 
+-extern char _start[];
+ extern char _end[];
+ 
+ #ifdef __sparc__
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index c60601b699..a432a6be54 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -1197,15 +1197,15 @@ grub_printf_fmt_check (const char *fmt, const char *fmt_expected)
+ 
+ 
+ /* Abort GRUB. This function does not return.  */
+-static void __attribute__ ((noreturn))
++static inline void __attribute__ ((noreturn))
+ grub_abort (void)
+ {
+-#ifndef GRUB_UTIL
+-#if (defined(__i386__) || defined(__x86_64__)) && !defined(GRUB_MACHINE_EMU)
+-  grub_backtrace();
++#if !defined(GRUB_MACHINE_EMU) && !defined(GRUB_UTIL)
++  grub_backtrace (1);
++#else
++  grub_printf ("\n");
+ #endif
+-#endif
+-  grub_printf ("\nAborted.");
++  grub_printf ("Aborted.");
+ 
+ #ifndef GRUB_UTIL
+   if (grub_term_inputs)
+@@ -1232,6 +1232,7 @@ grub_fatal (const char *fmt, ...)
+ {
+   va_list ap;
+ 
++  grub_printf ("\n");
+   va_start (ap, fmt);
+   grub_vprintf (_(fmt), ap);
+   va_end (ap);
+diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
+index c070afc621..d8c8377578 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -97,13 +97,13 @@ get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r)
+       break;
+ 
+   if (! *r)
+-    grub_fatal ("out of range pointer %p", ptr);
++    grub_fatal ("out of range pointer %p\n", ptr);
+ 
+   *p = (grub_mm_header_t) ptr - 1;
+   if ((*p)->magic == GRUB_MM_FREE_MAGIC)
+-    grub_fatal ("double free at %p", *p);
++    grub_fatal ("double free at %p\n", *p);
+   if ((*p)->magic != GRUB_MM_ALLOC_MAGIC)
+-    grub_fatal ("alloc magic is broken at %p: %lx", *p,
++    grub_fatal ("alloc magic is broken at %p: %lx\n", *p,
+ 		(unsigned long) (*p)->magic);
+ }
+ 
+diff --git a/grub-core/lib/arm64/backtrace.c b/grub-core/lib/arm64/backtrace.c
+deleted file mode 100644
+index 1079b5380e..0000000000
+--- a/grub-core/lib/arm64/backtrace.c
++++ /dev/null
+@@ -1,62 +0,0 @@
+-/*
+- *  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/misc.h>
+-#include <grub/command.h>
+-#include <grub/err.h>
+-#include <grub/dl.h>
+-#include <grub/mm.h>
+-#include <grub/term.h>
+-#include <grub/backtrace.h>
+-
+-#define MAX_STACK_FRAME 102400
+-
+-void
+-grub_backtrace_pointer (int frame)
+-{
+-  while (1)
+-    {
+-      void *lp = __builtin_return_address (frame);
+-      if (!lp)
+-	break;
+-
+-      lp = __builtin_extract_return_addr (lp);
+-
+-      grub_printf ("%p: ", lp);
+-      grub_backtrace_print_address (lp);
+-      grub_printf (" (");
+-      for (i = 0; i < 2; i++)
+-	grub_printf ("%p,", ((void **)ptr) [i + 2]);
+-      grub_printf ("%p)\n", ((void **)ptr) [i + 2]);
+-      nptr = *(void **)ptr;
+-      if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME
+-	  || nptr == ptr)
+-	{
+-	  grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr);
+-	  break;
+-	}
+-      ptr = nptr;
+-    }
+-}
+-
+-void
+-grub_backtrace (void)
+-{
+-  grub_backtrace_pointer (1);
+-}
+-
+diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c
+deleted file mode 100644
+index c67273db3a..0000000000
+--- a/grub-core/lib/i386/backtrace.c
++++ /dev/null
+@@ -1,78 +0,0 @@
+-/*
+- *  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 <config.h>
+-#ifdef GRUB_UTIL
+-#define REALLY_GRUB_UTIL GRUB_UTIL
+-#undef GRUB_UTIL
+-#endif
+-
+-#include <grub/symbol.h>
+-#include <grub/dl.h>
+-
+-#ifdef REALLY_GRUB_UTIL
+-#define GRUB_UTIL REALLY_GRUB_UTIL
+-#undef REALLY_GRUB_UTIL
+-#endif
+-
+-#include <grub/misc.h>
+-#include <grub/command.h>
+-#include <grub/err.h>
+-#include <grub/mm.h>
+-#include <grub/term.h>
+-#include <grub/backtrace.h>
+-
+-#define MAX_STACK_FRAME 102400
+-
+-void
+-grub_backtrace_pointer (void *ebp)
+-{
+-  void *ptr, *nptr;
+-  unsigned i;
+-
+-  ptr = ebp;
+-  while (1)
+-    {
+-      grub_printf ("%p: ", ptr);
+-      grub_backtrace_print_address (((void **) ptr)[1]);
+-      grub_printf (" (");
+-      for (i = 0; i < 2; i++)
+-	grub_printf ("%p,", ((void **)ptr) [i + 2]);
+-      grub_printf ("%p)\n", ((void **)ptr) [i + 2]);
+-      nptr = *(void **)ptr;
+-      if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME
+-	  || nptr == ptr)
+-	{
+-	  grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr);
+-	  break;
+-	}
+-      ptr = nptr;
+-    }
+-}
+-
+-void
+-grub_backtrace (void)
+-{
+-#ifdef __x86_64__
+-  asm volatile ("movq %%rbp, %%rdi\n"
+-		"callq *%%rax": :"a"(grub_backtrace_pointer));
+-#else
+-  asm volatile ("movl %%ebp, %%eax\n"
+-		"calll *%%ecx": :"c"(grub_backtrace_pointer));
+-#endif
+-}
+-
+diff --git a/include/grub/backtrace.h b/include/grub/backtrace.h
+index 395519762f..275cf85e2d 100644
+--- a/include/grub/backtrace.h
++++ b/include/grub/backtrace.h
+@@ -19,8 +19,14 @@
+ #ifndef GRUB_BACKTRACE_HEADER
+ #define GRUB_BACKTRACE_HEADER	1
+ 
+-void grub_backtrace (void);
+-void grub_backtrace_pointer (void *ptr);
++#include <grub/symbol.h>
++#include <grub/types.h>
++
++void EXPORT_FUNC(grub_debug_backtrace) (const char * const debug,
++					unsigned int skip);
++void EXPORT_FUNC(grub_backtrace) (unsigned int skip);
++void grub_backtrace_arch (unsigned int skip);
++void grub_backtrace_pointer (void *ptr, unsigned int skip);
+ void grub_backtrace_print_address (void *addr);
+ 
+ #endif
+diff --git a/include/grub/dl.h b/include/grub/dl.h
+index 91933b85f2..2f76e6b043 100644
+--- a/include/grub/dl.h
++++ b/include/grub/dl.h
+@@ -259,6 +259,8 @@ grub_dl_is_persistent (grub_dl_t mod)
+ 
+ #endif
+ 
++void * EXPORT_FUNC(grub_resolve_symbol) (const char *name);
++const char * EXPORT_FUNC(grub_get_symbol_by_addr) (const void *addr, int isfunc);
+ grub_err_t grub_dl_register_symbol (const char *name, void *addr,
+ 				    int isfunc, grub_dl_t mod);
+ 
+diff --git a/include/grub/kernel.h b/include/grub/kernel.h
+index abbca5ea33..300a9766cd 100644
+--- a/include/grub/kernel.h
++++ b/include/grub/kernel.h
+@@ -111,6 +111,9 @@ grub_addr_t grub_modules_get_end (void);
+ 
+ #endif
+ 
++void EXPORT_FUNC(start) (void);
++void EXPORT_FUNC(_start) (void);
++
+ /* The start point of the C code.  */
+ void grub_main (void) __attribute__ ((noreturn));
+ 
+diff --git a/grub-core/kern/arm/efi/startup.S b/grub-core/kern/arm/efi/startup.S
+index 9f8265315a..f3bc41f9d0 100644
+--- a/grub-core/kern/arm/efi/startup.S
++++ b/grub-core/kern/arm/efi/startup.S
+@@ -23,6 +23,8 @@
+ 	.file 	"startup.S"
+ 	.text
+ 	.arm
++	.globl	start, _start
++FUNCTION(start)
+ FUNCTION(_start)
+ 	/*
+ 	 *  EFI_SYSTEM_TABLE and EFI_HANDLE are passed in r1/r0.
+diff --git a/grub-core/kern/arm/startup.S b/grub-core/kern/arm/startup.S
+index 3946fe8e18..5679a1d00a 100644
+--- a/grub-core/kern/arm/startup.S
++++ b/grub-core/kern/arm/startup.S
+@@ -48,6 +48,8 @@
+ 	
+ 	.text
+ 	.arm
++	.globl	start, _start
++FUNCTION(start)
+ FUNCTION(_start)
+ 	b	codestart
+ 	
+diff --git a/grub-core/kern/arm64/efi/startup.S b/grub-core/kern/arm64/efi/startup.S
+index 666a7ee3c9..41676bdb2b 100644
+--- a/grub-core/kern/arm64/efi/startup.S
++++ b/grub-core/kern/arm64/efi/startup.S
+@@ -19,7 +19,9 @@
+ #include <grub/symbol.h>
+ 
+ 	.file 	"startup.S"
++	.globl start, _start
+ 	.text
++FUNCTION(start)
+ FUNCTION(_start)
+ 	/*
+ 	 *  EFI_SYSTEM_TABLE and EFI_HANDLE are passed in x1/x0.
+diff --git a/grub-core/kern/i386/qemu/startup.S b/grub-core/kern/i386/qemu/startup.S
+index 0d89858d9b..939f182fc7 100644
+--- a/grub-core/kern/i386/qemu/startup.S
++++ b/grub-core/kern/i386/qemu/startup.S
+@@ -24,7 +24,8 @@
+ 
+ 	.text
+ 	.code32
+-	.globl _start
++	.globl start, _start
++start:
+ _start:
+ 	jmp	codestart
+ 
+diff --git a/grub-core/kern/ia64/efi/startup.S b/grub-core/kern/ia64/efi/startup.S
+index d75c6d7cc7..8f2a593e52 100644
+--- a/grub-core/kern/ia64/efi/startup.S
++++ b/grub-core/kern/ia64/efi/startup.S
+@@ -24,8 +24,9 @@
+ 	.psr lsb
+ 	.lsb
+ 
+-	.global _start
++	.global start, _start
+ 	.proc _start
++start:
+ _start:
+ 	alloc loc0=ar.pfs,2,4,0,0
+ 	mov loc1=rp
+diff --git a/grub-core/kern/sparc64/ieee1275/crt0.S b/grub-core/kern/sparc64/ieee1275/crt0.S
+index 03b916f053..701bf63abc 100644
+--- a/grub-core/kern/sparc64/ieee1275/crt0.S
++++ b/grub-core/kern/sparc64/ieee1275/crt0.S
+@@ -22,7 +22,8 @@
+ 
+ 	.text
+ 	.align	4
+-	.globl	_start
++	.globl	start, _start
++start:
+ _start:
+ 	ba	codestart
+ 	 mov  %o4, %o0
+diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
+index ee88e44e97..bfd29a3bf0 100644
+--- a/grub-core/Makefile.am
++++ b/grub-core/Makefile.am
+@@ -66,6 +66,7 @@ CLEANFILES += grub_script.yy.c grub_script.yy.h
+ 
+ include $(srcdir)/Makefile.core.am
+ 
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/backtrace.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cache.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/command.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/device.h
diff --git a/SOURCES/0062-grub2-btrfs-06-subvol-mount.patch b/SOURCES/0062-grub2-btrfs-06-subvol-mount.patch
deleted file mode 100644
index 9a51175..0000000
--- a/SOURCES/0062-grub2-btrfs-06-subvol-mount.patch
+++ /dev/null
@@ -1,537 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Michael Chang <mchang@suse.com>
-Date: Tue, 9 Jul 2019 13:56:16 +0200
-Subject: [PATCH] grub2-btrfs-06-subvol-mount
-
----
- grub-core/fs/btrfs.c            | 195 +++++++++++++++++++++++++++++++++++++++-
- grub-core/osdep/linux/getroot.c | 148 +++++++++++++++++++++++++++++-
- util/grub-install.c             |  49 ++++++++++
- include/grub/emu/getroot.h      |   5 ++
- 4 files changed, 392 insertions(+), 5 deletions(-)
-
-diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
-index 113c1f746c9..d323746ecfa 100644
---- a/grub-core/fs/btrfs.c
-+++ b/grub-core/fs/btrfs.c
-@@ -41,6 +41,7 @@
- #include <grub/command.h>
- #include <grub/env.h>
- #include <grub/extcmd.h>
-+#include <grub/list.h>
- #include <grub/crypto.h>
- #include <grub/diskfilter.h>
- #include <grub/safemath.h>
-@@ -266,6 +267,12 @@ static grub_err_t
- grub_btrfs_read_logical (struct grub_btrfs_data *data,
- 			 grub_disk_addr_t addr, void *buf, grub_size_t size,
- 			 int recursion_depth);
-+static grub_err_t
-+get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key,
-+	  grub_uint64_t *tree, grub_uint8_t *type);
-+
-+grub_uint64_t
-+find_mtab_subvol_tree (const char *path, char **path_in_subvol);
- 
- static grub_err_t
- read_sblock (grub_disk_t disk, struct grub_btrfs_superblock *sb)
-@@ -1223,9 +1230,26 @@ lookup_root_by_name(struct grub_btrfs_data *data, const char *path)
-   grub_err_t err;
-   grub_uint64_t tree = 0;
-   grub_uint8_t type;
-+  grub_uint64_t saved_tree;
-   struct grub_btrfs_key key;
- 
-+  if (path[0] == '\0')
-+    {
-+      data->fs_tree = 0;
-+      return GRUB_ERR_NONE;
-+    }
-+
-+  err = get_root (data, &key, &tree, &type);
-+  if (err)
-+    return err;
-+
-+  saved_tree = data->fs_tree;
-+  data->fs_tree = tree;
-+
-   err = find_path (data, path, &key, &tree, &type);
-+
-+  data->fs_tree = saved_tree;
-+
-   if (err)
-       return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path);
- 
-@@ -2199,11 +2223,20 @@ grub_btrfs_dir (grub_device_t device, const char *path,
-   int r = 0;
-   grub_uint64_t tree;
-   grub_uint8_t type;
-+  char *new_path = NULL;
- 
-   if (!data)
-     return grub_errno;
- 
--  err = find_path (data, path, &key_in, &tree, &type);
-+  tree = find_mtab_subvol_tree (path, &new_path);
-+
-+  if (tree)
-+    data->fs_tree = tree;
-+
-+  err = find_path (data, new_path ? new_path : path, &key_in, &tree, &type);
-+  if (new_path)
-+    grub_free (new_path);
-+
-   if (err)
-     {
-       grub_btrfs_unmount (data);
-@@ -2305,11 +2338,21 @@ grub_btrfs_open (struct grub_file *file, const char *name)
-   struct grub_btrfs_inode inode;
-   grub_uint8_t type;
-   struct grub_btrfs_key key_in;
-+  grub_uint64_t tree;
-+  char *new_path = NULL;
- 
-   if (!data)
-     return grub_errno;
- 
--  err = find_path (data, name, &key_in, &data->tree, &type);
-+  tree = find_mtab_subvol_tree (name, &new_path);
-+
-+  if (tree)
-+    data->fs_tree = tree;
-+
-+  err = find_path (data, new_path ? new_path : name, &key_in, &data->tree, &type);
-+  if (new_path)
-+    grub_free (new_path);
-+
-   if (err)
-     {
-       grub_btrfs_unmount (data);
-@@ -2480,6 +2523,150 @@ grub_cmd_btrfs_info (grub_command_t cmd __attribute__ ((unused)), int argc,
-   return 0;
- }
- 
-+struct grub_btrfs_mtab
-+{
-+  struct grub_btrfs_mtab *next;
-+  struct grub_btrfs_mtab **prev;
-+  char *path;
-+  char *subvol;
-+  grub_uint64_t tree;
-+};
-+
-+typedef struct grub_btrfs_mtab* grub_btrfs_mtab_t;
-+
-+static struct grub_btrfs_mtab *btrfs_mtab;
-+
-+#define FOR_GRUB_MTAB(var) FOR_LIST_ELEMENTS (var, btrfs_mtab)
-+#define FOR_GRUB_MTAB_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE((var), (next), btrfs_mtab)
-+
-+static void
-+add_mountpoint (const char *path, const char *subvol, grub_uint64_t tree)
-+{
-+  grub_btrfs_mtab_t m = grub_malloc (sizeof (*m));
-+
-+  m->path = grub_strdup (path);
-+  m->subvol = grub_strdup (subvol);
-+  m->tree = tree;
-+  grub_list_push (GRUB_AS_LIST_P (&btrfs_mtab), GRUB_AS_LIST (m));
-+}
-+
-+static grub_err_t
-+grub_cmd_btrfs_mount_subvol (grub_command_t cmd __attribute__ ((unused)), int argc,
-+		     char **argv)
-+{
-+  char *devname, *dirname, *subvol;
-+  struct grub_btrfs_key key_in;
-+  grub_uint8_t type;
-+  grub_uint64_t tree;
-+  grub_uint64_t saved_tree;
-+  grub_err_t err;
-+  struct grub_btrfs_data *data = NULL;
-+  grub_device_t dev = NULL;
-+
-+  if (argc < 3)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "required <dev> <dir> and <subvol>");
-+
-+  devname = grub_file_get_device_name(argv[0]);
-+  dev = grub_device_open (devname);
-+  grub_free (devname);
-+
-+  if (!dev)
-+    {
-+      err = grub_errno;
-+      goto err_out;
-+    }
-+
-+  dirname = argv[1];
-+  subvol = argv[2];
-+
-+  data = grub_btrfs_mount (dev);
-+  if (!data)
-+    {
-+      err = grub_errno;
-+      goto err_out;
-+    }
-+
-+  err = find_path (data, dirname, &key_in, &tree, &type);
-+  if (err)
-+    goto err_out;
-+
-+  if (type !=  GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY)
-+    {
-+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
-+      goto err_out;
-+    }
-+
-+  err = get_root (data, &key_in, &tree, &type);
-+
-+  if (err)
-+    goto err_out;
-+
-+  saved_tree = data->fs_tree;
-+  data->fs_tree = tree;
-+  err = find_path (data, subvol, &key_in, &tree, &type);
-+  data->fs_tree = saved_tree;
-+
-+  if (err)
-+    goto err_out;
-+
-+  if (key_in.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0)
-+    {
-+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", subvol);
-+      goto err_out;
-+    }
-+
-+  grub_btrfs_unmount (data);
-+  grub_device_close (dev);
-+  add_mountpoint (dirname, subvol, tree);
-+
-+  return GRUB_ERR_NONE;
-+
-+err_out:
-+
-+  if (data)
-+    grub_btrfs_unmount (data);
-+
-+  if (dev)
-+    grub_device_close (dev);
-+
-+  return err;
-+}
-+
-+grub_uint64_t
-+find_mtab_subvol_tree (const char *path, char **path_in_subvol)
-+{
-+  grub_btrfs_mtab_t m, cm;
-+  grub_uint64_t tree;
-+
-+  if (!path || !path_in_subvol)
-+    return 0;
-+
-+  *path_in_subvol = NULL;
-+  tree = 0;
-+  cm = NULL;
-+
-+  FOR_GRUB_MTAB (m)
-+    {
-+      if (grub_strncmp (path, m->path, grub_strlen (m->path)) == 0)
-+	{
-+	  if (!cm)
-+	    cm = m;
-+	  else
-+	    if (grub_strcmp (m->path, cm->path) > 0)
-+	      cm = m;
-+	}
-+    }
-+
-+  if (cm)
-+    {
-+      const char *s = path + grub_strlen (cm->path);
-+      *path_in_subvol = (s[0] == '\0') ? grub_strdup ("/") : grub_strdup (s);
-+      tree = cm->tree;
-+    }
-+
-+  return tree;
-+}
-+
- static grub_err_t
- get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree,
-             grub_uint64_t objectid, grub_uint64_t offset,
-@@ -2686,6 +2873,7 @@ static struct grub_fs grub_btrfs_fs = {
- };
- 
- static grub_command_t cmd_info;
-+static grub_command_t cmd_mount_subvol;
- static grub_extcmd_t cmd_list_subvols;
- 
- static char *
-@@ -2749,6 +2937,9 @@ GRUB_MOD_INIT (btrfs)
-   cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info,
- 				   "DEVICE",
- 				   "Print BtrFS info about DEVICE.");
-+  cmd_mount_subvol = grub_register_command("btrfs-mount-subvol", grub_cmd_btrfs_mount_subvol,
-+				   "DEVICE DIRECTORY SUBVOL",
-+				   "Set btrfs DEVICE the DIRECTORY a mountpoint of SUBVOL.");
-   cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols",
- 					 grub_cmd_btrfs_list_subvols, 0,
- 					 "[-p|-n] [-o var] DEVICE",
-diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
-index caf9b1ccd3f..28790307e00 100644
---- a/grub-core/osdep/linux/getroot.c
-+++ b/grub-core/osdep/linux/getroot.c
-@@ -107,6 +107,14 @@ struct btrfs_ioctl_search_key
-   grub_uint32_t unused[9];
- };
- 
-+struct btrfs_ioctl_search_header {
-+  grub_uint64_t transid;
-+  grub_uint64_t objectid;
-+  grub_uint64_t offset;
-+  grub_uint32_t type;
-+  grub_uint32_t len;
-+};
-+
- struct btrfs_ioctl_search_args {
-   struct btrfs_ioctl_search_key key;
-   grub_uint64_t buf[(4096 - sizeof(struct btrfs_ioctl_search_key))
-@@ -378,6 +386,109 @@ get_btrfs_fs_prefix (const char *mount_path)
- 
- int use_relative_path_on_btrfs = 0;
- 
-+static char *
-+get_btrfs_subvol (const char *path)
-+{
-+  struct btrfs_ioctl_ino_lookup_args args;
-+  grub_uint64_t tree_id;
-+  int fd = -1;
-+  char *ret = NULL;
-+
-+  fd = open (path, O_RDONLY);
-+
-+  if (fd < 0)
-+    return NULL;
-+
-+  memset (&args, 0, sizeof(args));
-+  args.objectid = GRUB_BTRFS_TREE_ROOT_OBJECTID;
-+
-+  if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
-+    goto error;
-+
-+  tree_id = args.treeid;
-+
-+  while (tree_id != GRUB_BTRFS_ROOT_VOL_OBJECTID)
-+    {
-+      struct btrfs_ioctl_search_args sargs;
-+      struct grub_btrfs_root_backref *br;
-+      struct btrfs_ioctl_search_header *search_header;
-+      char *old;
-+      grub_uint16_t len;
-+      grub_uint64_t inode_id;
-+
-+      memset (&sargs, 0, sizeof(sargs));
-+
-+      sargs.key.tree_id = 1;
-+      sargs.key.min_objectid = tree_id;
-+      sargs.key.max_objectid = tree_id;
-+
-+      sargs.key.min_offset = 0;
-+      sargs.key.max_offset = ~0ULL;
-+      sargs.key.min_transid = 0;
-+      sargs.key.max_transid = ~0ULL;
-+      sargs.key.min_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF;
-+      sargs.key.max_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF;
-+
-+      sargs.key.nr_items = 1;
-+
-+      if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0)
-+	goto error;
-+
-+      if (sargs.key.nr_items == 0)
-+	goto error;
-+
-+      search_header = (struct btrfs_ioctl_search_header *)sargs.buf;
-+      br = (struct grub_btrfs_root_backref *) (search_header + 1);
-+
-+      len = grub_le_to_cpu16 (br->n);
-+      inode_id = grub_le_to_cpu64 (br->inode_id);
-+      tree_id = search_header->offset;
-+
-+      old = ret;
-+      ret = malloc (len + 1);
-+      memcpy (ret, br->name, len);
-+      ret[len] = '\0';
-+
-+      if (inode_id != GRUB_BTRFS_TREE_ROOT_OBJECTID)
-+	{
-+	  char *s;
-+
-+	  memset(&args, 0, sizeof(args));
-+	  args.treeid = search_header->offset;
-+	  args.objectid = inode_id;
-+
-+	  if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
-+	    goto error;
-+
-+	  s = xasprintf ("%s%s", args.name, ret);
-+	  free (ret);
-+	  ret = s;
-+	}
-+
-+      if (old)
-+	{
-+	  char *s = xasprintf ("%s/%s", ret, old);
-+	  free (ret);
-+	  free (old);
-+	  ret = s;
-+	}
-+    }
-+
-+  close (fd);
-+  return ret;
-+
-+error:
-+
-+  if (fd >= 0)
-+    close (fd);
-+  if (ret)
-+    free (ret);
-+
-+  return NULL;
-+}
-+
-+void (*grub_find_root_btrfs_mount_path_hook)(const char *mount_path);
-+
- char **
- grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
- {
-@@ -519,12 +630,15 @@ again:
-       else if (grub_strcmp (entries[i].fstype, "btrfs") == 0)
- 	{
- 	  ret = grub_find_root_devices_from_btrfs (dir);
--	  fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
- 	  if (use_relative_path_on_btrfs)
- 	    {
--	      if (fs_prefix)
--	        free (fs_prefix);
- 	      fs_prefix = xstrdup ("/");
-+	      if (grub_find_root_btrfs_mount_path_hook)
-+		grub_find_root_btrfs_mount_path_hook (entries[i].enc_path);
-+	    }
-+	  else
-+	    {
-+	      fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
- 	    }
- 	}
-       else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0)
-@@ -1150,6 +1264,34 @@ grub_util_get_grub_dev_os (const char *os_dev)
-   return grub_dev;
- }
- 
-+
-+char *
-+grub_util_get_btrfs_subvol (const char *path, char **mount_path)
-+{
-+  char *mp = NULL;
-+
-+  if (mount_path)
-+    *mount_path = NULL;
-+
-+  auto void
-+  mount_path_hook (const char *m)
-+  {
-+    mp = strdup (m);
-+  }
-+
-+  grub_find_root_btrfs_mount_path_hook = mount_path_hook;
-+  grub_free (grub_find_root_devices_from_mountinfo (path, NULL));
-+  grub_find_root_btrfs_mount_path_hook = NULL;
-+
-+  if (!mp)
-+    return NULL;
-+
-+  if (mount_path)
-+    *mount_path = mp;
-+
-+  return get_btrfs_subvol (mp);
-+}
-+
- char *
- grub_make_system_path_relative_to_its_root_os (const char *path)
- {
-diff --git a/util/grub-install.c b/util/grub-install.c
-index 0f66f36d23a..84ed6e88ecb 100644
---- a/util/grub-install.c
-+++ b/util/grub-install.c
-@@ -1569,6 +1569,55 @@ main (int argc, char *argv[])
-       prefix_drive = xasprintf ("(%s)", grub_drives[0]);
-     }
- 
-+#ifdef __linux__
-+
-+  if (config.is_suse_btrfs_snapshot_enabled
-+      && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0)
-+    {
-+      char *subvol = NULL;
-+      char *mount_path = NULL;
-+      char **rootdir_devices = NULL;
-+      char *rootdir_path = grub_util_path_concat (2, "/", rootdir);
-+
-+      if (grub_util_is_directory (rootdir_path))
-+	rootdir_devices = grub_guess_root_devices (rootdir_path);
-+
-+      free (rootdir_path);
-+
-+      if (rootdir_devices && rootdir_devices[0])
-+	if (grub_strcmp (rootdir_devices[0], grub_devices[0]) == 0)
-+	  subvol = grub_util_get_btrfs_subvol (platdir, &mount_path);
-+
-+      if (subvol && mount_path)
-+	{
-+	  char *def_subvol;
-+
-+	  def_subvol = grub_util_get_btrfs_subvol ("/", NULL);
-+
-+	  if (def_subvol)
-+	    {
-+	      if (!load_cfg_f)
-+		load_cfg_f = grub_util_fopen (load_cfg, "wb");
-+	      have_load_cfg = 1;
-+
-+	      if (grub_strcmp (subvol, def_subvol) != 0)
-+		fprintf (load_cfg_f, "btrfs-mount-subvol ($root) %s %s\n", mount_path, subvol);
-+	      free (def_subvol);
-+	    }
-+	}
-+
-+      for (curdev = rootdir_devices; *curdev; curdev++)
-+	free (*curdev);
-+      if (rootdir_devices)
-+	free (rootdir_devices);
-+      if (subvol)
-+	free (subvol);
-+      if (mount_path)
-+	free (mount_path);
-+    }
-+
-+#endif
-+
-   char mkimage_target[200];
-   const char *core_name = NULL;
- 
-diff --git a/include/grub/emu/getroot.h b/include/grub/emu/getroot.h
-index 73fa2d34abb..9c642ae3fe3 100644
---- a/include/grub/emu/getroot.h
-+++ b/include/grub/emu/getroot.h
-@@ -53,6 +53,11 @@ char **
- grub_find_root_devices_from_mountinfo (const char *dir, char **relroot);
- #endif
- 
-+#ifdef __linux__
-+char *
-+grub_util_get_btrfs_subvol (const char *path, char **mount_path);
-+#endif
-+
- /* Devmapper functions provided by getroot_devmapper.c.  */
- void
- grub_util_pull_devmapper (const char *os_dev);
diff --git a/SOURCES/0062-normal-don-t-draw-our-startup-message-if-debug-is-se.patch b/SOURCES/0062-normal-don-t-draw-our-startup-message-if-debug-is-se.patch
new file mode 100644
index 0000000..a916299
--- /dev/null
+++ b/SOURCES/0062-normal-don-t-draw-our-startup-message-if-debug-is-se.patch
@@ -0,0 +1,23 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 9 Nov 2017 15:58:52 -0500
+Subject: [PATCH] normal: don't draw our startup message if debug is set
+
+---
+ grub-core/normal/main.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index 55558cc0b9..af9792c963 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -430,6 +430,9 @@ grub_normal_reader_init (int nested)
+   const char *msg_esc = _("ESC at any time exits.");
+   char *msg_formatted;
+ 
++  if (grub_env_get ("debug") != NULL)
++    return 0;
++
+   msg_formatted = grub_xasprintf (_("Minimal BASH-like line editing is supported. For "
+ 				    "the first word, TAB lists possible command completions. Anywhere "
+ 				    "else TAB lists possible device or file completions. %s"),
diff --git a/SOURCES/0063-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch b/SOURCES/0063-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch
deleted file mode 100644
index b02ab53..0000000
--- a/SOURCES/0063-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Andrei Borzenkov <arvidjaar@gmail.com>
-Date: Tue, 21 Jun 2016 16:44:17 +0000
-Subject: [PATCH] Fallback to old subvol name scheme to support old snapshot
- config
-
-Ref: bsc#953538
----
- grub-core/fs/btrfs.c | 32 +++++++++++++++++++++++++++++++-
- 1 file changed, 31 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
-index d323746ecfa..673ded03522 100644
---- a/grub-core/fs/btrfs.c
-+++ b/grub-core/fs/btrfs.c
-@@ -1260,11 +1260,41 @@ lookup_root_by_name(struct grub_btrfs_data *data, const char *path)
-   return GRUB_ERR_NONE;
- }
- 
-+static grub_err_t
-+lookup_root_by_name_fallback(struct grub_btrfs_data *data, const char *path)
-+{
-+  grub_err_t err;
-+  grub_uint64_t tree = 0;
-+  grub_uint8_t type;
-+  struct grub_btrfs_key key;
-+
-+  err = find_path (data, path, &key, &tree, &type);
-+  if (err)
-+      return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path);
-+
-+  if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0)
-+    return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path);
-+
-+  data->fs_tree = tree;
-+  return GRUB_ERR_NONE;
-+}
-+
- static grub_err_t
- btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__ ((unused)))
- {
-   if (btrfs_default_subvol)
--    return lookup_root_by_name(data, btrfs_default_subvol);
-+    {
-+      grub_err_t err;
-+      err = lookup_root_by_name(data, btrfs_default_subvol);
-+
-+      /* Fallback to old schemes */
-+      if (err == GRUB_ERR_FILE_NOT_FOUND)
-+	{
-+	  err = GRUB_ERR_NONE;
-+	  return lookup_root_by_name_fallback(data, btrfs_default_subvol);
-+	}
-+      return err;
-+    }
- 
-   if (btrfs_default_subvolid)
-     return lookup_root_by_id(data, btrfs_default_subvolid);
diff --git a/SOURCES/0063-Work-around-some-minor-include-path-weirdnesses.patch b/SOURCES/0063-Work-around-some-minor-include-path-weirdnesses.patch
new file mode 100644
index 0000000..c7ae8d0
--- /dev/null
+++ b/SOURCES/0063-Work-around-some-minor-include-path-weirdnesses.patch
@@ -0,0 +1,137 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 16 Mar 2018 13:28:57 -0400
+Subject: [PATCH] Work around some minor include path weirdnesses
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ include/grub/arm/efi/console.h    | 24 ++++++++++++++++++++++++
+ include/grub/arm64/efi/console.h  | 24 ++++++++++++++++++++++++
+ include/grub/i386/efi/console.h   | 24 ++++++++++++++++++++++++
+ include/grub/x86_64/efi/console.h | 24 ++++++++++++++++++++++++
+ 4 files changed, 96 insertions(+)
+ create mode 100644 include/grub/arm/efi/console.h
+ create mode 100644 include/grub/arm64/efi/console.h
+ create mode 100644 include/grub/i386/efi/console.h
+ create mode 100644 include/grub/x86_64/efi/console.h
+
+diff --git a/include/grub/arm/efi/console.h b/include/grub/arm/efi/console.h
+new file mode 100644
+index 0000000000..1592f6f76b
+--- /dev/null
++++ b/include/grub/arm/efi/console.h
+@@ -0,0 +1,24 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2002,2005,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/>.
++ */
++
++#ifndef GRUB_ARM_EFI_CONSOLE_H
++#define GRUB_ARM_EFI_CONSOLE_H
++
++#include <efi/console.h>
++
++#endif /* ! GRUB_ARM_EFI_CONSOLE_H */
+diff --git a/include/grub/arm64/efi/console.h b/include/grub/arm64/efi/console.h
+new file mode 100644
+index 0000000000..9568933938
+--- /dev/null
++++ b/include/grub/arm64/efi/console.h
+@@ -0,0 +1,24 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2002,2005,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/>.
++ */
++
++#ifndef GRUB_ARM64_EFI_CONSOLE_H
++#define GRUB_ARM64_EFI_CONSOLE_H
++
++#include <efi/console.h>
++
++#endif /* ! GRUB_ARM64_EFI_CONSOLE_H */
+diff --git a/include/grub/i386/efi/console.h b/include/grub/i386/efi/console.h
+new file mode 100644
+index 0000000000..9231375cb0
+--- /dev/null
++++ b/include/grub/i386/efi/console.h
+@@ -0,0 +1,24 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2002,2005,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/>.
++ */
++
++#ifndef GRUB_I386_EFI_CONSOLE_H
++#define GRUB_I386_EFI_CONSOLE_H
++
++#include <efi/console.h>
++
++#endif /* ! GRUB_I386_EFI_CONSOLE_H */
+diff --git a/include/grub/x86_64/efi/console.h b/include/grub/x86_64/efi/console.h
+new file mode 100644
+index 0000000000..dba9d8678d
+--- /dev/null
++++ b/include/grub/x86_64/efi/console.h
+@@ -0,0 +1,24 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2002,2005,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/>.
++ */
++
++#ifndef GRUB_X86_64_EFI_CONSOLE_H
++#define GRUB_X86_64_EFI_CONSOLE_H
++
++#include <efi/console.h>
++
++#endif /* ! GRUB_X86_64_EFI_CONSOLE_H */
diff --git a/SOURCES/0064-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch b/SOURCES/0064-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch
deleted file mode 100644
index d4e20cd..0000000
--- a/SOURCES/0064-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch
+++ /dev/null
@@ -1,272 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Michael Chang <mchang@suse.com>
-Date: Thu, 11 May 2017 08:56:57 +0000
-Subject: [PATCH] Grub not working correctly with btrfs snapshots (bsc#1026511)
-
----
- grub-core/fs/btrfs.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 238 insertions(+)
-
-diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
-index 673ded03522..2b21cbaa67e 100644
---- a/grub-core/fs/btrfs.c
-+++ b/grub-core/fs/btrfs.c
-@@ -2887,6 +2887,238 @@ out:
-   return 0;
- }
- 
-+static grub_err_t
-+grub_btrfs_get_parent_subvol_path (struct grub_btrfs_data *data,
-+		grub_uint64_t child_id,
-+		const char *child_path,
-+		grub_uint64_t *parent_id,
-+		char **path_out)
-+{
-+  grub_uint64_t fs_root = 0;
-+  struct grub_btrfs_key key_in = {
-+    .object_id = child_id,
-+    .type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF,
-+    .offset = 0,
-+  }, key_out;
-+  struct grub_btrfs_root_ref *ref;
-+  char *buf;
-+  struct grub_btrfs_leaf_descriptor desc;
-+  grub_size_t elemsize;
-+  grub_disk_addr_t elemaddr;
-+  grub_err_t err;
-+  char *parent_path;
-+
-+  *parent_id = 0;
-+  *path_out = 0;
-+
-+  err = lower_bound(data, &key_in, &key_out, data->sblock.root_tree,
-+                    &elemaddr, &elemsize, &desc, 0);
-+  if (err)
-+    return err;
-+
-+  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF || elemaddr == 0)
-+    next(data, &desc, &elemaddr, &elemsize, &key_out);
-+
-+  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF)
-+    {
-+      free_iterator(&desc);
-+      return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root backrefs"));
-+    }
-+
-+  buf = grub_malloc(elemsize + 1);
-+  if (!buf)
-+    {
-+      free_iterator(&desc);
-+      return grub_errno;
-+    }
-+
-+  err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0);
-+  if (err)
-+    {
-+      grub_free(buf);
-+      free_iterator(&desc);
-+      return err;
-+    }
-+
-+  buf[elemsize] = 0;
-+  ref = (struct grub_btrfs_root_ref *)buf;
-+
-+  err = get_fs_root(data, data->sblock.root_tree, grub_le_to_cpu64 (key_out.offset),
-+                    0, &fs_root);
-+  if (err)
-+    {
-+      grub_free(buf);
-+      free_iterator(&desc);
-+      return err;
-+    }
-+
-+  find_pathname(data, grub_le_to_cpu64 (ref->dirid), fs_root, ref->name, &parent_path);
-+
-+  if (child_path)
-+    {
-+      *path_out = grub_xasprintf ("%s/%s", parent_path, child_path);
-+      grub_free (parent_path);
-+    }
-+  else
-+    *path_out = parent_path;
-+
-+  *parent_id = grub_le_to_cpu64 (key_out.offset);
-+
-+  grub_free(buf);
-+  free_iterator(&desc);
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+grub_btrfs_get_default_subvolume_id (struct grub_btrfs_data *data, grub_uint64_t *id)
-+{
-+  grub_err_t err;
-+  grub_disk_addr_t elemaddr;
-+  grub_size_t elemsize;
-+  struct grub_btrfs_key key, key_out;
-+  struct grub_btrfs_dir_item *direl = NULL;
-+  const char *ctoken = "default";
-+  grub_size_t ctokenlen = sizeof ("default") - 1;
-+
-+  *id = 0;
-+  key.object_id = data->sblock.root_dir_objectid;
-+  key.type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
-+  key.offset = grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken, ctokenlen));
-+  err = lower_bound (data, &key, &key_out, data->sblock.root_tree, &elemaddr, &elemsize,
-+			 NULL, 0);
-+  if (err)
-+    return err;
-+
-+  if (key_cmp (&key, &key_out) != 0)
-+    return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found"));
-+
-+  struct grub_btrfs_dir_item *cdirel;
-+  direl = grub_malloc (elemsize + 1);
-+  err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize, 0);
-+  if (err)
-+    {
-+      grub_free (direl);
-+      return err;
-+    }
-+  for (cdirel = direl;
-+       (grub_uint8_t *) cdirel - (grub_uint8_t *) direl
-+       < (grub_ssize_t) elemsize;
-+       cdirel = (void *) ((grub_uint8_t *) (direl + 1)
-+       + grub_le_to_cpu16 (cdirel->n)
-+       + grub_le_to_cpu16 (cdirel->m)))
-+    {
-+      if (ctokenlen == grub_le_to_cpu16 (cdirel->n)
-+        && grub_memcmp (cdirel->name, ctoken, ctokenlen) == 0)
-+      break;
-+    }
-+  if ((grub_uint8_t *) cdirel - (grub_uint8_t *) direl
-+      >= (grub_ssize_t) elemsize)
-+    {
-+      grub_free (direl);
-+      err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found"));
-+      return err;
-+    }
-+
-+  if (cdirel->key.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM)
-+    {
-+      grub_free (direl);
-+      err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found"));
-+      return err;
-+    }
-+
-+  *id = grub_le_to_cpu64 (cdirel->key.object_id);
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+grub_cmd_btrfs_get_default_subvol (struct grub_extcmd_context *ctxt,
-+			     int argc, char **argv)
-+{
-+  char *devname;
-+  grub_device_t dev;
-+  struct grub_btrfs_data *data;
-+  grub_err_t err;
-+  grub_uint64_t id;
-+  char *subvol = NULL;
-+  grub_uint64_t subvolid = 0;
-+  char *varname = NULL;
-+  char *output = NULL;
-+  int path_only = ctxt->state[1].set;
-+  int num_only = ctxt->state[2].set;
-+
-+  if (ctxt->state[0].set)
-+    varname = ctxt->state[0].arg;
-+
-+  if (argc < 1)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
-+
-+  devname = grub_file_get_device_name(argv[0]);
-+  if (!devname)
-+    return grub_errno;
-+
-+  dev = grub_device_open (devname);
-+  grub_free (devname);
-+  if (!dev)
-+    return grub_errno;
-+
-+  data = grub_btrfs_mount(dev);
-+  if (!data)
-+    {
-+      grub_device_close (dev);
-+      grub_dprintf ("btrfs", "failed to open fs\n");
-+      grub_errno = GRUB_ERR_NONE;
-+      return 0;
-+    }
-+
-+  err = grub_btrfs_get_default_subvolume_id (data, &subvolid);
-+  if (err)
-+    {
-+      grub_btrfs_unmount (data);
-+      grub_device_close (dev);
-+      return err;
-+    }
-+
-+  id = subvolid;
-+  while (id != GRUB_BTRFS_ROOT_VOL_OBJECTID)
-+    {
-+      grub_uint64_t parent_id;
-+      char *path_out;
-+
-+      err = grub_btrfs_get_parent_subvol_path (data, grub_cpu_to_le64 (id), subvol, &parent_id, &path_out);
-+      if (err)
-+	{
-+	  grub_btrfs_unmount (data);
-+	  grub_device_close (dev);
-+	  return err;
-+	}
-+
-+      if (subvol)
-+        grub_free (subvol);
-+      subvol = path_out;
-+      id = parent_id;
-+    }
-+
-+  if (num_only && path_only)
-+      output = grub_xasprintf ("%"PRIuGRUB_UINT64_T" /%s", subvolid, subvol);
-+  else if (num_only)
-+      output = grub_xasprintf ("%"PRIuGRUB_UINT64_T, subvolid);
-+  else
-+      output = grub_xasprintf ("/%s", subvol);
-+
-+  if (varname)
-+    grub_env_set(varname, output);
-+  else
-+    grub_printf ("%s\n", output);
-+
-+  grub_free (output);
-+  grub_free (subvol);
-+
-+  grub_btrfs_unmount (data);
-+  grub_device_close (dev);
-+
-+  return GRUB_ERR_NONE;
-+}
-+
- static struct grub_fs grub_btrfs_fs = {
-   .name = "btrfs",
-   .fs_dir = grub_btrfs_dir,
-@@ -2905,6 +3137,7 @@ static struct grub_fs grub_btrfs_fs = {
- static grub_command_t cmd_info;
- static grub_command_t cmd_mount_subvol;
- static grub_extcmd_t cmd_list_subvols;
-+static grub_extcmd_t cmd_get_default_subvol;
- 
- static char *
- subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)),
-@@ -2975,6 +3208,11 @@ GRUB_MOD_INIT (btrfs)
- 					 "[-p|-n] [-o var] DEVICE",
- 					 "Print list of BtrFS subvolumes on "
- 					 "DEVICE.", options);
-+  cmd_get_default_subvol = grub_register_extcmd("btrfs-get-default-subvol",
-+					 grub_cmd_btrfs_get_default_subvol, 0,
-+					 "[-p|-n] [-o var] DEVICE",
-+					 "Print default BtrFS subvolume on "
-+					 "DEVICE.", options);
-   grub_register_variable_hook ("btrfs_subvol", subvol_get_env,
-                                subvol_set_env);
-   grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env,
diff --git a/SOURCES/0064-Make-it-possible-to-enabled-build-id-sha1.patch b/SOURCES/0064-Make-it-possible-to-enabled-build-id-sha1.patch
new file mode 100644
index 0000000..99d8055
--- /dev/null
+++ b/SOURCES/0064-Make-it-possible-to-enabled-build-id-sha1.patch
@@ -0,0 +1,61 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 25 Jun 2015 15:41:06 -0400
+Subject: [PATCH] Make it possible to enabled --build-id=sha1
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ configure.ac |  8 ++++++++
+ acinclude.m4 | 19 +++++++++++++++++++
+ 2 files changed, 27 insertions(+)
+
+diff --git a/configure.ac b/configure.ac
+index 0d0e6782a1..302300711f 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1442,7 +1442,15 @@ grub_PROG_TARGET_CC
+ if test "x$TARGET_APPLE_LINKER" != x1 ; then
+ grub_PROG_OBJCOPY_ABSOLUTE
+ fi
++
++AC_ARG_ENABLE([build-id],
++	      [AS_HELP_STRING([--enable-build-id],
++                             [ask the linker to supply build-id notes (default=no)])])
++if test x$enable_build_id = xyes; then
++grub_PROG_LD_BUILD_ID_SHA1
++else
+ grub_PROG_LD_BUILD_ID_NONE
++fi
+ if test "x$target_cpu" = xi386; then
+   if test "$platform" != emu && test "x$TARGET_APPLE_LINKER" != x1 ; then
+     if test ! -z "$TARGET_IMG_LDSCRIPT"; then
+diff --git a/acinclude.m4 b/acinclude.m4
+index 6e14bb553c..21238fcfd0 100644
+--- a/acinclude.m4
++++ b/acinclude.m4
+@@ -136,6 +136,25 @@ if test "x$grub_cv_prog_ld_build_id_none" = xyes; then
+ fi
+ ])
+ 
++dnl Supply --build-id=sha1 to ld if building modules.
++dnl This suppresses warnings from ld on some systems
++AC_DEFUN([grub_PROG_LD_BUILD_ID_SHA1],
++[AC_MSG_CHECKING([whether linker accepts --build-id=sha1])
++AC_CACHE_VAL(grub_cv_prog_ld_build_id_sha1,
++[save_LDFLAGS="$LDFLAGS"
++LDFLAGS="$LDFLAGS -Wl,--build-id=sha1"
++AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
++	       [grub_cv_prog_ld_build_id_sha1=yes],
++	       [grub_cv_prog_ld_build_id_sha1=no])
++LDFLAGS="$save_LDFLAGS"
++])
++AC_MSG_RESULT([$grub_cv_prog_ld_build_id_sha1])
++
++if test "x$grub_cv_prog_ld_build_id_sha1" = xyes; then
++  TARGET_LDFLAGS="$TARGET_LDFLAGS -Wl,--build-id=sha1"
++fi
++])
++
+ dnl Check nm
+ AC_DEFUN([grub_PROG_NM_WORKS],
+ [AC_MSG_CHECKING([whether nm works])
diff --git a/SOURCES/0065-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch b/SOURCES/0065-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch
deleted file mode 100644
index bde7096..0000000
--- a/SOURCES/0065-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 1 Jun 2017 09:59:56 -0400
-Subject: [PATCH] Add grub_efi_allocate_pool() and grub_efi_free_pool()
- wrappers.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- include/grub/efi/efi.h | 36 ++++++++++++++++++++++++++++++++----
- 1 file changed, 32 insertions(+), 4 deletions(-)
-
-diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
-index 585fa6662b6..03f9a9d0118 100644
---- a/include/grub/efi/efi.h
-+++ b/include/grub/efi/efi.h
-@@ -24,6 +24,10 @@
- #include <grub/dl.h>
- #include <grub/efi/api.h>
- 
-+/* Variables.  */
-+extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table);
-+extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle);
-+
- /* Functions.  */
- void *EXPORT_FUNC(grub_efi_locate_protocol) (grub_efi_guid_t *protocol,
- 					     void *registration);
-@@ -60,6 +64,33 @@ EXPORT_FUNC(grub_efi_get_memory_map) (grub_efi_uintn_t *memory_map_size,
- 				      grub_efi_uintn_t *descriptor_size,
- 				      grub_efi_uint32_t *descriptor_version);
- void grub_efi_memory_fini (void);
-+
-+static inline grub_efi_status_t
-+__attribute__((__unused__))
-+grub_efi_allocate_pool (grub_efi_memory_type_t pool_type,
-+			grub_efi_uintn_t buffer_size,
-+			void **buffer)
-+{
-+  grub_efi_boot_services_t *b;
-+  grub_efi_status_t status;
-+
-+  b = grub_efi_system_table->boot_services;
-+  status = efi_call_3 (b->allocate_pool, pool_type, buffer_size, buffer);
-+  return status;
-+}
-+
-+static inline grub_efi_status_t
-+__attribute__((__unused__))
-+grub_efi_free_pool (void *buffer)
-+{
-+  grub_efi_boot_services_t *b;
-+  grub_efi_status_t status;
-+
-+  b = grub_efi_system_table->boot_services;
-+  status = efi_call_1 (b->free_pool, buffer);
-+  return status;
-+}
-+
- grub_efi_loaded_image_t *EXPORT_FUNC(grub_efi_get_loaded_image) (grub_efi_handle_t image_handle);
- void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp);
- char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp);
-@@ -115,10 +146,7 @@ void grub_efi_init (void);
- void grub_efi_fini (void);
- void grub_efi_set_prefix (void);
- 
--/* Variables.  */
--extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table);
--extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle);
--
-+/* More variables.  */
- extern int EXPORT_VAR(grub_efi_is_finished);
- 
- struct grub_net_card;
diff --git a/SOURCES/0065-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch b/SOURCES/0065-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch
new file mode 100644
index 0000000..7658e9b
--- /dev/null
+++ b/SOURCES/0065-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch
@@ -0,0 +1,56 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Sun, 28 Jun 2015 13:09:58 -0400
+Subject: [PATCH] Add grub_qdprintf() - grub_dprintf() without the file+line
+ number.
+
+This just makes copy+paste of our debug loading info easier.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/misc.c | 18 ++++++++++++++++++
+ include/grub/misc.h   |  2 ++
+ 2 files changed, 20 insertions(+)
+
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index a432a6be54..9a2fae6398 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -191,6 +191,24 @@ grub_real_dprintf (const char *file, const int line, const char *condition,
+     }
+ }
+ 
++void
++grub_qdprintf (const char *condition, const char *fmt, ...)
++{
++  va_list args;
++  const char *debug = grub_env_get ("debug");
++
++  if (! debug)
++    return;
++
++  if (grub_strword (debug, "all") || grub_strword (debug, condition))
++    {
++      va_start (args, fmt);
++      grub_vprintf (fmt, args);
++      va_end (args);
++      grub_refresh ();
++    }
++}
++
+ #define PREALLOC_SIZE 255
+ 
+ int
+diff --git a/include/grub/misc.h b/include/grub/misc.h
+index fd18e6320b..3adc4036e3 100644
+--- a/include/grub/misc.h
++++ b/include/grub/misc.h
+@@ -345,6 +345,8 @@ void EXPORT_FUNC(grub_real_dprintf) (const char *file,
+                                      const int line,
+                                      const char *condition,
+                                      const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 4, 5)));
++void EXPORT_FUNC(grub_qdprintf) (const char *condition,
++				 const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 2, 3)));
+ int EXPORT_FUNC(grub_vprintf) (const char *fmt, va_list args);
+ int EXPORT_FUNC(grub_snprintf) (char *str, grub_size_t n, const char *fmt, ...)
+      __attribute__ ((format (GNU_PRINTF, 3, 4)));
diff --git a/SOURCES/0066-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch b/SOURCES/0066-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch
new file mode 100644
index 0000000..ccf34a5
--- /dev/null
+++ b/SOURCES/0066-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch
@@ -0,0 +1,178 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 25 Jun 2015 15:11:36 -0400
+Subject: [PATCH] Make a "gdb" dprintf that tells us load addresses.
+
+This makes a grub_dprintf() call during platform init and during module
+loading that tells us the virtual addresses of the .text and .data
+sections of grub-core/kernel.exec and any modules it loads.
+
+Specifically, it displays them in the gdb "add-symbol-file" syntax, with
+the presumption that there's a variable $grubdir that reflects the path
+to any such binaries.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/dl.c       | 50 +++++++++++++++++++++++++++++++++++++++++++++++
+ grub-core/kern/efi/efi.c  |  4 ++--
+ grub-core/kern/efi/init.c | 26 +++++++++++++++++++++++-
+ include/grub/efi/efi.h    |  2 +-
+ 4 files changed, 78 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index 88d2077709..9557254035 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -501,6 +501,23 @@ grub_dl_find_section (Elf_Ehdr *e, const char *name)
+       return s;
+   return NULL;
+ }
++static long
++grub_dl_find_section_index (Elf_Ehdr *e, const char *name)
++{
++  Elf_Shdr *s;
++  const char *str;
++  unsigned i;
++
++  s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
++  str = (char *) e + s->sh_offset;
++
++  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
++       i < e->e_shnum;
++       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
++    if (grub_strcmp (str + s->sh_name, name) == 0)
++      return (long)i;
++  return -1;
++}
+ 
+ /* Me, Vladimir Serbinenko, hereby I add this module check as per new
+    GNU module policy. Note that this license check is informative only.
+@@ -653,6 +670,37 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
+ 
+   return GRUB_ERR_NONE;
+ }
++static void
++grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e)
++{
++  void *text, *data = NULL;
++  long idx;
++
++  idx = grub_dl_find_section_index (e, ".text");
++  if (idx < 0)
++    return;
++
++  text = grub_dl_get_section_addr (mod, idx);
++  if (!text)
++    return;
++
++  idx = grub_dl_find_section_index (e, ".data");
++  if (idx >= 0)
++    data = grub_dl_get_section_addr (mod, idx);
++
++  if (data)
++    grub_qdprintf ("gdb", "add-symbol-file \\\n"
++		          "/usr/lib/debug/usr/lib/grub/%s-%s/%s.debug "
++			  "\\\n %p -s .data %p\n",
++		  GRUB_TARGET_CPU, GRUB_PLATFORM,
++		  mod->name, text, data);
++  else
++    grub_qdprintf ("gdb", "add-symbol-file \\\n"
++			   "/usr/lib/debug/usr/lib/grub/%s-%s/%s.debug "
++			   "\\\n%p\n",
++		  GRUB_TARGET_CPU, GRUB_PLATFORM,
++		  mod->name, text);
++}
+ 
+ /* Load a module from core memory.  */
+ grub_dl_t
+@@ -712,6 +760,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
+   grub_dprintf ("modules", "module name: %s\n", mod->name);
+   grub_dprintf ("modules", "init function: %p\n", mod->init);
+ 
++  grub_dl_print_gdb_info (mod, e);
++
+   if (grub_dl_add (mod))
+     {
+       grub_dl_unload (mod);
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index ae9885edb8..d6a2fb5778 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -296,7 +296,7 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
+ /* Search the mods section from the PE32/PE32+ image. This code uses
+    a PE32 header, but should work with PE32+ as well.  */
+ grub_addr_t
+-grub_efi_modules_addr (void)
++grub_efi_section_addr (const char *section_name)
+ {
+   grub_efi_loaded_image_t *image;
+   struct grub_pe32_header *header;
+@@ -321,7 +321,7 @@ grub_efi_modules_addr (void)
+        i < coff_header->num_sections;
+        i++, section++)
+     {
+-      if (grub_strcmp (section->name, "mods") == 0)
++      if (grub_strcmp (section->name, section_name) == 0)
+ 	break;
+     }
+ 
+diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
+index 6d39bd3ad2..2d12e6188f 100644
+--- a/grub-core/kern/efi/init.c
++++ b/grub-core/kern/efi/init.c
+@@ -115,10 +115,33 @@ grub_efi_env_init (void)
+   grub_free (envblk_s.buf);
+ }
+ 
++static void
++grub_efi_print_gdb_info (void)
++{
++  grub_addr_t text;
++  grub_addr_t data;
++
++  text = grub_efi_section_addr (".text");
++  if (!text)
++    return;
++
++  data = grub_efi_section_addr (".data");
++  if (data)
++    grub_qdprintf ("gdb",
++		  "add-symbol-file /usr/lib/debug/usr/lib/grub/%s-%s/"
++		  "kernel.exec %p -s .data %p\n",
++		  GRUB_TARGET_CPU, GRUB_PLATFORM, (void *)text, (void *)data);
++  else
++    grub_qdprintf ("gdb",
++		  "add-symbol-file /usr/lib/debug/usr/lib/grub/%s-%s/"
++		  "kernel.exec %p\n",
++		  GRUB_TARGET_CPU, GRUB_PLATFORM, (void *)text);
++}
++
+ void
+ grub_efi_init (void)
+ {
+-  grub_modbase = grub_efi_modules_addr ();
++  grub_modbase = grub_efi_section_addr ("mods");
+   /* First of all, initialize the console so that GRUB can display
+      messages.  */
+   grub_console_init ();
+@@ -142,6 +165,7 @@ grub_efi_init (void)
+ 	      0, 0, 0, NULL);
+ 
+   grub_efi_env_init ();
++  grub_efi_print_gdb_info ();
+   grub_efidisk_init ();
+ }
+ 
+diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
+index 03f9a9d011..2e0691454b 100644
+--- a/include/grub/efi/efi.h
++++ b/include/grub/efi/efi.h
+@@ -138,7 +138,7 @@ grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh);
+ grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, char *args);
+ #endif
+ 
+-grub_addr_t grub_efi_modules_addr (void);
++grub_addr_t grub_efi_section_addr (const char *section);
+ 
+ void grub_efi_mm_init (void);
+ void grub_efi_mm_fini (void);
diff --git a/SOURCES/0066-Use-grub_efi_.-memory-helpers-where-reasonable.patch b/SOURCES/0066-Use-grub_efi_.-memory-helpers-where-reasonable.patch
deleted file mode 100644
index 4fa92c0..0000000
--- a/SOURCES/0066-Use-grub_efi_.-memory-helpers-where-reasonable.patch
+++ /dev/null
@@ -1,106 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 1 Jun 2017 10:06:38 -0400
-Subject: [PATCH] Use grub_efi_...() memory helpers where reasonable.
-
-This uses grub_efi_allocate_pool(), grub_efi_free_pool(), and
-grub_efi_free_pages() instead of open-coded efi_call_N() calls, so we
-get more reasonable type checking.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/loader/efi/chainloader.c | 24 +++++++++---------------
- 1 file changed, 9 insertions(+), 15 deletions(-)
-
-diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
-index 3ff305b1d32..ba3d2930197 100644
---- a/grub-core/loader/efi/chainloader.c
-+++ b/grub-core/loader/efi/chainloader.c
-@@ -65,7 +65,7 @@ grub_chainloader_unload (void)
- 
-   b = grub_efi_system_table->boot_services;
-   efi_call_1 (b->unload_image, image_handle);
--  efi_call_2 (b->free_pages, address, pages);
-+  grub_efi_free_pages (address, pages);
- 
-   grub_free (file_path);
-   grub_free (cmdline);
-@@ -108,7 +108,7 @@ grub_chainloader_boot (void)
-     }
- 
-   if (exit_data)
--    efi_call_1 (b->free_pool, exit_data);
-+    grub_efi_free_pool (exit_data);
- 
-   grub_loader_unset ();
- 
-@@ -523,10 +523,9 @@ grub_efi_get_media_file_path (grub_efi_device_path_t *dp)
- static grub_efi_boolean_t
- handle_image (void *data, grub_efi_uint32_t datasize)
- {
--  grub_efi_boot_services_t *b;
-   grub_efi_loaded_image_t *li, li_bak;
-   grub_efi_status_t efi_status;
--  char *buffer = NULL;
-+  void *buffer = NULL;
-   char *buffer_aligned = NULL;
-   grub_efi_uint32_t i;
-   struct grub_pe32_section_table *section;
-@@ -537,8 +536,6 @@ handle_image (void *data, grub_efi_uint32_t datasize)
-   int found_entry_point = 0;
-   int rc;
- 
--  b = grub_efi_system_table->boot_services;
--
-   rc = read_header (data, datasize, &context);
-   if (rc < 0)
-     {
-@@ -578,8 +575,8 @@ handle_image (void *data, grub_efi_uint32_t datasize)
-   grub_dprintf ("chain", "image size is %08"PRIxGRUB_UINT64_T", datasize is %08x\n",
- 	       context.image_size, datasize);
- 
--  efi_status = efi_call_3 (b->allocate_pool, GRUB_EFI_LOADER_DATA,
--			   buffer_size, &buffer);
-+  efi_status = grub_efi_allocate_pool (GRUB_EFI_LOADER_DATA, buffer_size,
-+				       &buffer);
- 
-   if (efi_status != GRUB_EFI_SUCCESS)
-     {
-@@ -811,14 +808,14 @@ handle_image (void *data, grub_efi_uint32_t datasize)
- 
-   grub_dprintf ("chain", "entry_point returned %ld\n", efi_status);
-   grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t));
--  efi_status = efi_call_1 (b->free_pool, buffer);
-+  efi_status = grub_efi_free_pool (buffer);
- 
-   return 1;
- 
- error_exit:
-   grub_dprintf ("chain", "error_exit: grub_errno: %d\n", grub_errno);
-   if (buffer)
--      efi_call_1 (b->free_pool, buffer);
-+    grub_efi_free_pool (buffer);
- 
-   return 0;
- }
-@@ -826,10 +823,7 @@ error_exit:
- static grub_err_t
- grub_secureboot_chainloader_unload (void)
- {
--  grub_efi_boot_services_t *b;
--
--  b = grub_efi_system_table->boot_services;
--  efi_call_2 (b->free_pages, address, pages);
-+  grub_efi_free_pages (address, pages);
-   grub_free (file_path);
-   grub_free (cmdline);
-   cmdline = 0;
-@@ -1096,7 +1090,7 @@ fail:
-   grub_free (file_path);
- 
-   if (address)
--    efi_call_2 (b->free_pages, address, pages);
-+    grub_efi_free_pages (address, pages);
- 
-   if (cmdline)
-     grub_free (cmdline);
diff --git a/SOURCES/0067-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch b/SOURCES/0067-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch
deleted file mode 100644
index 1a96b43..0000000
--- a/SOURCES/0067-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 1 Jun 2017 10:07:50 -0400
-Subject: [PATCH] Add PRIxGRUB_EFI_STATUS and use it.
-
-This avoids syntax checkers getting confused about if it's llx or lx.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/loader/efi/chainloader.c | 3 ++-
- include/grub/efi/api.h             | 9 +++++++++
- 2 files changed, 11 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
-index ba3d2930197..47f5aa14817 100644
---- a/grub-core/loader/efi/chainloader.c
-+++ b/grub-core/loader/efi/chainloader.c
-@@ -806,7 +806,8 @@ handle_image (void *data, grub_efi_uint32_t datasize)
-   efi_status = efi_call_2 (entry_point, grub_efi_image_handle,
- 			   grub_efi_system_table);
- 
--  grub_dprintf ("chain", "entry_point returned %ld\n", efi_status);
-+  grub_dprintf ("chain", "entry_point returned 0x%"PRIxGRUB_EFI_STATUS"\n",
-+		efi_status);
-   grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t));
-   efi_status = grub_efi_free_pool (buffer);
- 
-diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
-index 117469450d3..99628801478 100644
---- a/include/grub/efi/api.h
-+++ b/include/grub/efi/api.h
-@@ -546,7 +546,16 @@ typedef grub_uint64_t grub_efi_uint64_t;
- typedef grub_uint8_t grub_efi_char8_t;
- typedef grub_uint16_t grub_efi_char16_t;
- 
-+
- typedef grub_efi_uintn_t grub_efi_status_t;
-+/* Make grub_efi_status_t reasonably printable. */
-+#if GRUB_CPU_SIZEOF_VOID_P == 8
-+#define PRIxGRUB_EFI_STATUS "lx"
-+#define PRIdGRUB_EFI_STATUS "ld"
-+#else
-+#define PRIxGRUB_EFI_STATUS "llx"
-+#define PRIdGRUB_EFI_STATUS "lld"
-+#endif
- 
- #define GRUB_EFI_ERROR_CODE(value)	\
-   ((((grub_efi_status_t) 1) << (sizeof (grub_efi_status_t) * 8 - 1)) | (value))
diff --git a/SOURCES/0067-Fixup-for-newer-compiler.patch b/SOURCES/0067-Fixup-for-newer-compiler.patch
new file mode 100644
index 0000000..ed23271
--- /dev/null
+++ b/SOURCES/0067-Fixup-for-newer-compiler.patch
@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 10 May 2018 13:40:19 -0400
+Subject: [PATCH] Fixup for newer compiler
+
+---
+ grub-core/fs/btrfs.c         | 2 +-
+ include/grub/gpt_partition.h | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index 2b21cbaa67..4cc86e9b79 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -218,7 +218,7 @@ struct grub_btrfs_inode
+   grub_uint64_t size;
+   grub_uint8_t dummy2[0x70];
+   struct grub_btrfs_time mtime;
+-} GRUB_PACKED;
++} GRUB_PACKED  __attribute__ ((aligned(8)));
+ 
+ struct grub_btrfs_extent_data
+ {
+diff --git a/include/grub/gpt_partition.h b/include/grub/gpt_partition.h
+index 7a93f43291..8212697bf6 100644
+--- a/include/grub/gpt_partition.h
++++ b/include/grub/gpt_partition.h
+@@ -76,7 +76,7 @@ struct grub_gpt_partentry
+   grub_uint64_t end;
+   grub_uint64_t attrib;
+   char name[72];
+-} GRUB_PACKED;
++} GRUB_PACKED  __attribute__ ((aligned(8)));
+ 
+ grub_err_t
+ grub_gpt_partition_map_iterate (grub_disk_t disk,
diff --git a/SOURCES/0068-Don-t-attempt-to-export-the-start-and-_start-symbols.patch b/SOURCES/0068-Don-t-attempt-to-export-the-start-and-_start-symbols.patch
new file mode 100644
index 0000000..9b78c00
--- /dev/null
+++ b/SOURCES/0068-Don-t-attempt-to-export-the-start-and-_start-symbols.patch
@@ -0,0 +1,42 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Sat, 12 May 2018 11:29:07 +0200
+Subject: [PATCH] Don't attempt to export the start and _start symbols for
+ grub-emu
+
+Commit 318ee04aadc ("make better backtraces") reworked the backtrace logic
+but the changes lead to the following build error on the grub-emu platform:
+
+grub_emu_lite-symlist.o:(.data+0xf08): undefined reference to `start'
+collect2: error: ld returned 1 exit status
+make[3]: *** [Makefile:25959: grub-emu-lite] Error 1
+make[3]: *** Waiting for unfinished jobs....
+cat kernel_syms.input | grep -v '^#' | sed -n \
+  -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/defined kernel '""'\1/;p;}' \
+  -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/defined kernel '""'\1/;p;}' \
+  | sort -u >kernel_syms.lst
+
+The problem is that start and _start symbols are exported unconditionally,
+but these aren't defined for grub-emu since is an emultaed platform so it
+doesn't have a startup logic. Don't attempt to export those for grub-emu.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ include/grub/kernel.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/include/grub/kernel.h b/include/grub/kernel.h
+index 300a9766cd..55849777ea 100644
+--- a/include/grub/kernel.h
++++ b/include/grub/kernel.h
+@@ -111,8 +111,10 @@ grub_addr_t grub_modules_get_end (void);
+ 
+ #endif
+ 
++#if !defined(GRUB_MACHINE_EMU)
+ void EXPORT_FUNC(start) (void);
+ void EXPORT_FUNC(_start) (void);
++#endif
+ 
+ /* The start point of the C code.  */
+ void grub_main (void) __attribute__ ((noreturn));
diff --git a/SOURCES/0068-don-t-use-int-for-efi-status.patch b/SOURCES/0068-don-t-use-int-for-efi-status.patch
deleted file mode 100644
index 44d3555..0000000
--- a/SOURCES/0068-don-t-use-int-for-efi-status.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 26 Jun 2017 12:44:59 -0400
-Subject: [PATCH] don't use int for efi status
-
----
- grub-core/kern/efi/efi.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
-index 05d8237a9b2..ae9885edb84 100644
---- a/grub-core/kern/efi/efi.c
-+++ b/grub-core/kern/efi/efi.c
-@@ -167,7 +167,7 @@ grub_reboot (void)
- void
- grub_exit (int retval)
- {
--  int rc = GRUB_EFI_LOAD_ERROR;
-+  grub_efi_status_t rc = GRUB_EFI_LOAD_ERROR;
- 
-   if (retval == 0)
-     rc = GRUB_EFI_SUCCESS;
diff --git a/SOURCES/0069-Fixup-for-newer-compiler.patch b/SOURCES/0069-Fixup-for-newer-compiler.patch
new file mode 100644
index 0000000..167dca1
--- /dev/null
+++ b/SOURCES/0069-Fixup-for-newer-compiler.patch
@@ -0,0 +1,22 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 10 May 2018 13:40:19 -0400
+Subject: [PATCH] Fixup for newer compiler
+
+---
+ conf/Makefile.common | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/conf/Makefile.common b/conf/Makefile.common
+index 191b1a70c6..5f0ef96985 100644
+--- a/conf/Makefile.common
++++ b/conf/Makefile.common
+@@ -38,7 +38,7 @@ CFLAGS_KERNEL = $(CFLAGS_PLATFORM) -ffreestanding
+ LDFLAGS_KERNEL = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC)
+ CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1
+ CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
+-STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx
++STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx -R .note.gnu.property -R .gnu.build.attributes
+ 
+ CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding
+ LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d
diff --git a/SOURCES/0069-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch b/SOURCES/0069-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch
deleted file mode 100644
index 1014900..0000000
--- a/SOURCES/0069-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 26 Jun 2017 12:46:23 -0400
-Subject: [PATCH] make GRUB_MOD_INIT() declare its function prototypes.
-
----
- include/grub/dl.h | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/include/grub/dl.h b/include/grub/dl.h
-index b3753c9ca26..91933b85f2c 100644
---- a/include/grub/dl.h
-+++ b/include/grub/dl.h
-@@ -54,6 +54,7 @@ grub_mod_fini (void)
- 
- #define GRUB_MOD_INIT(name)	\
- static void grub_mod_init (grub_dl_t mod __attribute__ ((unused))) __attribute__ ((used)); \
-+extern void grub_##name##_init (void); \
- void \
- grub_##name##_init (void) { grub_mod_init (0); } \
- static void \
-@@ -61,6 +62,7 @@ grub_mod_init (grub_dl_t mod __attribute__ ((unused)))
- 
- #define GRUB_MOD_FINI(name)	\
- static void grub_mod_fini (void) __attribute__ ((used)); \
-+extern void grub_##name##_fini (void); \
- void \
- grub_##name##_fini (void) { grub_mod_fini (); } \
- static void \
diff --git a/SOURCES/0070-Add-support-for-non-Ethernet-network-cards.patch b/SOURCES/0070-Add-support-for-non-Ethernet-network-cards.patch
new file mode 100644
index 0000000..fb44628
--- /dev/null
+++ b/SOURCES/0070-Add-support-for-non-Ethernet-network-cards.patch
@@ -0,0 +1,766 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Andrzej Kacprowski <andrzej.kacprowski@intel.com>
+Date: Wed, 10 Jul 2019 15:22:29 +0200
+Subject: [PATCH] Add support for non-Ethernet network cards
+
+This patch replaces fixed 6-byte link layer address with
+up to 32-byte variable sized address.
+This allows supporting Infiniband and Omni-Path fabric
+which use 20-byte address, but other network card types
+can also take advantage of this change.
+The network card driver is responsible for replacing L2
+header provided by grub2 if needed.
+This approach is compatible with UEFI network stack which
+also allows up to 32-byte variable size link address.
+
+The BOOTP/DHCP packet format is limited to 16 byte client
+hardware address, if link address is more that 16-bytes
+then chaddr field in BOOTP it will be set to 0 as per rfc4390.
+
+Resolves: rhbz#1370642
+
+Signed-off-by: Andrzej Kacprowski <andrzej.kacprowski@intel.com>
+[msalter: Fix max string calculation in grub_net_hwaddr_to_str]
+Signed-off-by: Mark Salter <msalter@redhat.com>
+---
+ grub-core/net/arp.c                    | 155 ++++++++++++++++++++++-----------
+ grub-core/net/bootp.c                  |  15 ++--
+ grub-core/net/drivers/efi/efinet.c     |   8 +-
+ grub-core/net/drivers/emu/emunet.c     |   1 +
+ grub-core/net/drivers/i386/pc/pxe.c    |  13 +--
+ grub-core/net/drivers/ieee1275/ofnet.c |   2 +
+ grub-core/net/drivers/uboot/ubootnet.c |   1 +
+ grub-core/net/ethernet.c               |  88 +++++++++----------
+ grub-core/net/icmp6.c                  |  15 ++--
+ grub-core/net/ip.c                     |   4 +-
+ grub-core/net/net.c                    |  50 ++++++-----
+ include/grub/net.h                     |  19 ++--
+ 12 files changed, 219 insertions(+), 152 deletions(-)
+
+diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c
+index 54306e3b16..67b409a8ac 100644
+--- a/grub-core/net/arp.c
++++ b/grub-core/net/arp.c
+@@ -31,22 +31,12 @@ enum
+     ARP_REPLY = 2
+   };
+ 
+-enum
+-  {
+-    /* IANA ARP constant to define hardware type as ethernet. */
+-    GRUB_NET_ARPHRD_ETHERNET = 1
+-  };
+-
+-struct arppkt {
++struct arphdr {
+   grub_uint16_t hrd;
+   grub_uint16_t pro;
+   grub_uint8_t hln;
+   grub_uint8_t pln;
+   grub_uint16_t op;
+-  grub_uint8_t sender_mac[6];
+-  grub_uint32_t sender_ip;
+-  grub_uint8_t recv_mac[6];
+-  grub_uint32_t recv_ip;
+ } GRUB_PACKED;
+ 
+ static int have_pending;
+@@ -57,12 +47,16 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
+ 			   const grub_net_network_level_address_t *proto_addr)
+ {
+   struct grub_net_buff nb;
+-  struct arppkt *arp_packet;
++  struct arphdr *arp_header;
+   grub_net_link_level_address_t target_mac_addr;
+   grub_err_t err;
+   int i;
+   grub_uint8_t *nbd;
+   grub_uint8_t arp_data[128];
++  grub_uint8_t hln;
++  grub_uint8_t pln;
++  grub_uint8_t arp_packet_len;
++  grub_uint8_t *tmp_ptr;
+ 
+   if (proto_addr->type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
+     return grub_error (GRUB_ERR_BUG, "unsupported address family");
+@@ -73,23 +67,39 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
+   grub_netbuff_clear (&nb);
+   grub_netbuff_reserve (&nb, 128);
+ 
+-  err = grub_netbuff_push (&nb, sizeof (*arp_packet));
++  hln = inf->card->default_address.len;
++  pln = sizeof (proto_addr->ipv4);
++  arp_packet_len = sizeof (*arp_header) + 2 * (hln + pln);
++
++  err = grub_netbuff_push (&nb, arp_packet_len);
+   if (err)
+     return err;
+ 
+-  arp_packet = (struct arppkt *) nb.data;
+-  arp_packet->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET);
+-  arp_packet->hln = 6;
+-  arp_packet->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP);
+-  arp_packet->pln = 4;
+-  arp_packet->op = grub_cpu_to_be16_compile_time (ARP_REQUEST);
+-  /* Sender hardware address.  */
+-  grub_memcpy (arp_packet->sender_mac, &inf->hwaddress.mac, 6);
+-  arp_packet->sender_ip = inf->address.ipv4;
+-  grub_memset (arp_packet->recv_mac, 0, 6);
+-  arp_packet->recv_ip = proto_addr->ipv4;
+-  /* Target protocol address */
+-  grub_memset (&target_mac_addr.mac, 0xff, 6);
++  arp_header = (struct arphdr *) nb.data;
++  arp_header->hrd = grub_cpu_to_be16 (inf->card->default_address.type);
++  arp_header->hln = hln;
++  arp_header->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP);
++  arp_header->pln = pln;
++  arp_header->op = grub_cpu_to_be16_compile_time (ARP_REQUEST);
++  tmp_ptr = nb.data + sizeof (*arp_header);
++
++  /* The source hardware address. */
++  grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln);
++  tmp_ptr += hln;
++
++  /* The source protocol address. */
++  grub_memcpy (tmp_ptr, &inf->address.ipv4, pln);
++  tmp_ptr += pln;
++
++  /* The target hardware address. */
++  grub_memset (tmp_ptr, 0, hln);
++  tmp_ptr += hln;
++
++  /* The target protocol address */
++  grub_memcpy (tmp_ptr, &proto_addr->ipv4, pln);
++  tmp_ptr += pln;
++
++  grub_memset (&target_mac_addr.mac, 0xff, hln);
+ 
+   nbd = nb.data;
+   send_ethernet_packet (inf, &nb, target_mac_addr, GRUB_NET_ETHERTYPE_ARP);
+@@ -114,28 +124,53 @@ grub_err_t
+ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card,
+                       grub_uint16_t *vlantag)
+ {
+-  struct arppkt *arp_packet = (struct arppkt *) nb->data;
++  struct arphdr *arp_header = (struct arphdr *) nb->data;
+   grub_net_network_level_address_t sender_addr, target_addr;
+   grub_net_link_level_address_t sender_mac_addr;
+   struct grub_net_network_level_interface *inf;
++  grub_uint16_t hw_type;
++  grub_uint8_t hln;
++  grub_uint8_t pln;
++  grub_uint8_t arp_packet_len;
++  grub_uint8_t *tmp_ptr;
+ 
+-  if (arp_packet->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP)
+-      || arp_packet->pln != 4 || arp_packet->hln != 6
+-      || nb->tail - nb->data < (int) sizeof (*arp_packet))
++  hw_type = card->default_address.type;
++  hln = card->default_address.len;
++  pln = sizeof(sender_addr.ipv4);
++  arp_packet_len = sizeof (*arp_header) + 2 * (pln + hln);
++
++  if (arp_header->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP)
++      || arp_header->hrd != grub_cpu_to_be16 (hw_type)
++      || arp_header->hln != hln || arp_header->pln != pln
++      || nb->tail - nb->data < (int) arp_packet_len) {
+     return GRUB_ERR_NONE;
++  }
+ 
++  tmp_ptr =  nb->data + sizeof (*arp_header);
++
++  /* The source hardware address. */
++  sender_mac_addr.type = hw_type;
++  sender_mac_addr.len = hln;
++  grub_memcpy (sender_mac_addr.mac, tmp_ptr, hln);
++  tmp_ptr += hln;
++
++  /* The source protocol address. */
+   sender_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
++  grub_memcpy(&sender_addr.ipv4, tmp_ptr, pln);
++  tmp_ptr += pln;
++
++  grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1);
++
++  /* The target hardware address. */
++  tmp_ptr += hln;
++
++  /* The target protocol address. */
+   target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
+-  sender_addr.ipv4 = arp_packet->sender_ip;
+-  target_addr.ipv4 = arp_packet->recv_ip;
+-  if (arp_packet->sender_ip == pending_req)
++  grub_memcpy(&target_addr.ipv4, tmp_ptr, pln);
++
++  if (sender_addr.ipv4 == pending_req)
+     have_pending = 1;
+ 
+-  sender_mac_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-  grub_memcpy (sender_mac_addr.mac, arp_packet->sender_mac,
+-	       sizeof (sender_mac_addr.mac));
+-  grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1);
+-
+   FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
+   {
+     /* Verify vlantag id */
+@@ -148,11 +183,11 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card,
+ 
+     /* Am I the protocol address target? */
+     if (grub_net_addr_cmp (&inf->address, &target_addr) == 0
+-	&& arp_packet->op == grub_cpu_to_be16_compile_time (ARP_REQUEST))
++	&& arp_header->op == grub_cpu_to_be16_compile_time (ARP_REQUEST))
+       {
+ 	grub_net_link_level_address_t target;
+ 	struct grub_net_buff nb_reply;
+-	struct arppkt *arp_reply;
++	struct arphdr *arp_reply;
+ 	grub_uint8_t arp_data[128];
+ 	grub_err_t err;
+ 
+@@ -161,25 +196,39 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card,
+ 	grub_netbuff_clear (&nb_reply);
+ 	grub_netbuff_reserve (&nb_reply, 128);
+ 
+-	err = grub_netbuff_push (&nb_reply, sizeof (*arp_packet));
++	err = grub_netbuff_push (&nb_reply, arp_packet_len);
+ 	if (err)
+ 	  return err;
+ 
+-	arp_reply = (struct arppkt *) nb_reply.data;
++	arp_reply = (struct arphdr *) nb_reply.data;
+ 
+-	arp_reply->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET);
++	arp_reply->hrd = grub_cpu_to_be16 (hw_type);
+ 	arp_reply->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP);
+-	arp_reply->pln = 4;
+-	arp_reply->hln = 6;
++	arp_reply->pln = pln;
++	arp_reply->hln = hln;
+ 	arp_reply->op = grub_cpu_to_be16_compile_time (ARP_REPLY);
+-	arp_reply->sender_ip = arp_packet->recv_ip;
+-	arp_reply->recv_ip = arp_packet->sender_ip;
+-	arp_reply->hln = 6;
+-
+-	target.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-	grub_memcpy (target.mac, arp_packet->sender_mac, 6);
+-	grub_memcpy (arp_reply->sender_mac, inf->hwaddress.mac, 6);
+-	grub_memcpy (arp_reply->recv_mac, arp_packet->sender_mac, 6);
++
++	tmp_ptr = nb_reply.data + sizeof (*arp_reply);
++
++	/* The source hardware address. */
++	grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln);
++	tmp_ptr += hln;
++
++	/* The source protocol address. */
++	grub_memcpy (tmp_ptr, &target_addr.ipv4, pln);
++	tmp_ptr += pln;
++
++	/* The target hardware address. */
++	grub_memcpy (tmp_ptr, sender_mac_addr.mac, hln);
++	tmp_ptr += hln;
++
++	/* The target protocol address */
++	grub_memcpy (tmp_ptr, &sender_addr.ipv4, pln);
++	tmp_ptr += pln;
++
++	target.type = hw_type;
++	target.len = hln;
++	grub_memcpy (target.mac, sender_mac_addr.mac, hln);
+ 
+ 	/* Change operation to REPLY and send packet */
+ 	send_ethernet_packet (inf, &nb_reply, target, GRUB_NET_ETHERTYPE_ARP);
+diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
+index e28fb6a09f..08b6b2b5d6 100644
+--- a/grub-core/net/bootp.c
++++ b/grub-core/net/bootp.c
+@@ -233,7 +233,6 @@ grub_net_configure_by_dhcp_ack (const char *name,
+ 				int is_def, char **device, char **path)
+ {
+   grub_net_network_level_address_t addr;
+-  grub_net_link_level_address_t hwaddr;
+   struct grub_net_network_level_interface *inter;
+   int mask = -1;
+   char server_ip[sizeof ("xxx.xxx.xxx.xxx")];
+@@ -250,12 +249,8 @@ grub_net_configure_by_dhcp_ack (const char *name,
+   if (path)
+     *path = 0;
+ 
+-  grub_memcpy (hwaddr.mac, bp->mac_addr,
+-	       bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len
+-	       : sizeof (hwaddr.mac));
+-  hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-
+-  inter = grub_net_add_addr (name, card, &addr, &hwaddr, flags);
++  grub_dprintf("dhcp", "configuring dhcp for %s\n", name);
++  inter = grub_net_add_addr (name, card, &addr, &card->default_address, flags);
+   if (!inter)
+     return 0;
+ 
+@@ -567,7 +562,9 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface)
+   grub_memset (pack, 0, sizeof (*pack));
+   pack->opcode = 1;
+   pack->hw_type = 1;
+-  pack->hw_len = 6;
++  pack->hw_len = iface->hwaddress.len > 16 ? 0
++                                              : iface->hwaddress.len;
++
+   err = grub_get_datetime (&date);
+   if (err || !grub_datetime2unixtime (&date, &t))
+     {
+@@ -580,7 +577,7 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface)
+   else
+     pack->ident = iface->xid;
+ 
+-  grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, 6);
++  grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, pack->hw_len);
+ 
+   grub_netbuff_push (nb, sizeof (*udph));
+ 
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index 173fb63153..a673bea807 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -279,6 +279,9 @@ grub_efinet_findcards (void)
+ 	/* This should not happen... Why?  */
+ 	continue;
+ 
++      if (net->mode->hwaddr_size > GRUB_NET_MAX_LINK_ADDRESS_SIZE)
++	continue;
++
+       if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
+ 	  && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
+ 	continue;
+@@ -315,10 +318,11 @@ grub_efinet_findcards (void)
+       card->name = grub_xasprintf ("efinet%d", i++);
+       card->driver = &efidriver;
+       card->flags = 0;
+-      card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
++      card->default_address.type = net->mode->if_type;
++      card->default_address.len = net->mode->hwaddr_size;
+       grub_memcpy (card->default_address.mac,
+ 		   net->mode->current_address,
+-		   sizeof (card->default_address.mac));
++		   net->mode->hwaddr_size);
+       card->efi_net = net;
+       card->efi_handle = *handle;
+ 
+diff --git a/grub-core/net/drivers/emu/emunet.c b/grub-core/net/drivers/emu/emunet.c
+index b194920861..5b6c5e16a6 100644
+--- a/grub-core/net/drivers/emu/emunet.c
++++ b/grub-core/net/drivers/emu/emunet.c
+@@ -46,6 +46,7 @@ static struct grub_net_card emucard =
+     .mtu = 1500,
+     .default_address = {
+ 			 .type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET,
++			 . len = 6,
+ 			 {.mac = {0, 1, 2, 3, 4, 5}}
+ 		       },
+     .flags = 0
+diff --git a/grub-core/net/drivers/i386/pc/pxe.c b/grub-core/net/drivers/i386/pc/pxe.c
+index 3f4152d036..9f8fb4b6d2 100644
+--- a/grub-core/net/drivers/i386/pc/pxe.c
++++ b/grub-core/net/drivers/i386/pc/pxe.c
+@@ -386,20 +386,21 @@ GRUB_MOD_INIT(pxe)
+   grub_memset (ui, 0, sizeof (*ui));
+   grub_pxe_call (GRUB_PXENV_UNDI_GET_INFORMATION, ui, pxe_rm_entry);
+ 
++  grub_pxe_card.default_address.len = 6;
+   grub_memcpy (grub_pxe_card.default_address.mac, ui->current_addr,
+-	       sizeof (grub_pxe_card.default_address.mac));
+-  for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++)
++	       grub_pxe_card.default_address.len);
++  for (i = 0; i < grub_pxe_card.default_address.len; i++)
+     if (grub_pxe_card.default_address.mac[i] != 0)
+       break;
+-  if (i != sizeof (grub_pxe_card.default_address.mac))
++  if (i != grub_pxe_card.default_address.len)
+     {
+-      for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++)
++      for (i = 0; i < grub_pxe_card.default_address.len; i++)
+ 	if (grub_pxe_card.default_address.mac[i] != 0xff)
+ 	  break;
+     }
+-  if (i == sizeof (grub_pxe_card.default_address.mac))
++  if (i == grub_pxe_card.default_address.len)
+     grub_memcpy (grub_pxe_card.default_address.mac, ui->permanent_addr,
+-		 sizeof (grub_pxe_card.default_address.mac));
++		 grub_pxe_card.default_address.len);
+   grub_pxe_card.mtu = ui->mtu;
+ 
+   grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c
+index 3860b6f78d..bcb3f9ea02 100644
+--- a/grub-core/net/drivers/ieee1275/ofnet.c
++++ b/grub-core/net/drivers/ieee1275/ofnet.c
+@@ -160,6 +160,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath,
+   grub_uint16_t vlantag = 0;
+ 
+   hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
++  hw_addr.len = 6;
+ 
+   args = bootpath + grub_strlen (devpath) + 1;
+   do
+@@ -503,6 +504,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias)
+     grub_memcpy (&lla.mac, pprop, 6);
+ 
+   lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
++  lla.len = 6;
+   card->default_address = lla;
+ 
+   card->txbufsize = ALIGN_UP (card->mtu, 64) + 256;
+diff --git a/grub-core/net/drivers/uboot/ubootnet.c b/grub-core/net/drivers/uboot/ubootnet.c
+index 056052e40d..22ebcbf211 100644
+--- a/grub-core/net/drivers/uboot/ubootnet.c
++++ b/grub-core/net/drivers/uboot/ubootnet.c
+@@ -131,6 +131,7 @@ GRUB_MOD_INIT (ubootnet)
+ 
+       grub_memcpy (&(card->default_address.mac), &devinfo->di_net.hwaddr, 6);
+       card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
++      card->default_address.len = 6;
+ 
+       card->txbufsize = ALIGN_UP (card->mtu, 64) + 256;
+       card->txbuf = grub_zalloc (card->txbufsize);
+diff --git a/grub-core/net/ethernet.c b/grub-core/net/ethernet.c
+index 4d7ceed6f9..9aae83a5eb 100644
+--- a/grub-core/net/ethernet.c
++++ b/grub-core/net/ethernet.c
+@@ -29,13 +29,6 @@
+ 
+ #define LLCADDRMASK 0x7f
+ 
+-struct etherhdr
+-{
+-  grub_uint8_t dst[6];
+-  grub_uint8_t src[6];
+-  grub_uint16_t type;
+-} GRUB_PACKED;
+-
+ struct llchdr
+ {
+   grub_uint8_t dsap;
+@@ -55,13 +48,15 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
+ 		      grub_net_link_level_address_t target_addr,
+ 		      grub_net_ethertype_t ethertype)
+ {
+-  struct etherhdr *eth;
++  grub_uint8_t *eth;
+   grub_err_t err;
+-  grub_uint8_t etherhdr_size;
+-  grub_uint16_t vlantag_id = VLANTAG_IDENTIFIER;
++  grub_uint32_t vlantag = 0;
++  grub_uint8_t hw_addr_len = inf->card->default_address.len;
++  grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2;
+ 
+-  etherhdr_size = sizeof (*eth);
+-  COMPILE_TIME_ASSERT (sizeof (*eth) + 4 < GRUB_NET_MAX_LINK_HEADER_SIZE);
++  /* Source and destination link addresses + ethertype + vlan tag */
++  COMPILE_TIME_ASSERT ((GRUB_NET_MAX_LINK_ADDRESS_SIZE * 2 + 2 + 4) <
++		       GRUB_NET_MAX_LINK_HEADER_SIZE);
+ 
+   /* Increase ethernet header in case of vlantag */
+   if (inf->vlantag != 0)
+@@ -70,11 +65,22 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
+   err = grub_netbuff_push (nb, etherhdr_size);
+   if (err)
+     return err;
+-  eth = (struct etherhdr *) nb->data;
+-  grub_memcpy (eth->dst, target_addr.mac, 6);
+-  grub_memcpy (eth->src, inf->hwaddress.mac, 6);
++  eth = nb->data;
++  grub_memcpy (eth, target_addr.mac, hw_addr_len);
++  eth += hw_addr_len;
++  grub_memcpy (eth, inf->hwaddress.mac, hw_addr_len);
++  eth += hw_addr_len;
++
++  /* Check if a vlan-tag is present. */
++  if (vlantag != 0)
++    {
++      *((grub_uint32_t *)eth) = grub_cpu_to_be32 (vlantag);
++      eth += sizeof (vlantag);
++    }
++
++  /* Write ethertype */
++  *((grub_uint16_t*) eth) = grub_cpu_to_be16 (ethertype);
+ 
+-  eth->type = grub_cpu_to_be16 (ethertype);
+   if (!inf->card->opened)
+     {
+       err = GRUB_ERR_NONE;
+@@ -85,18 +91,6 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
+       inf->card->opened = 1;
+     }
+ 
+-  /* Check and add a vlan-tag if needed. */
+-  if (inf->vlantag != 0)
+-    {
+-      /* Move eth type to the right */
+-      grub_memcpy ((char *) nb->data + etherhdr_size - 2,
+-                   (char *) nb->data + etherhdr_size - 6, 2);
+-
+-      /* Add the tag in the middle */
+-      grub_memcpy ((char *) nb->data + etherhdr_size - 6, &vlantag_id, 2);
+-      grub_memcpy ((char *) nb->data + etherhdr_size - 4, (char *) &(inf->vlantag), 2);
+-    }
+-
+   return inf->card->driver->send (inf->card, nb);
+ }
+ 
+@@ -104,31 +98,40 @@ grub_err_t
+ grub_net_recv_ethernet_packet (struct grub_net_buff *nb,
+ 			       struct grub_net_card *card)
+ {
+-  struct etherhdr *eth;
++  grub_uint8_t *eth;
+   struct llchdr *llch;
+   struct snaphdr *snaph;
+   grub_net_ethertype_t type;
+   grub_net_link_level_address_t hwaddress;
+   grub_net_link_level_address_t src_hwaddress;
+   grub_err_t err;
+-  grub_uint8_t etherhdr_size = sizeof (*eth);
++  grub_uint8_t hw_addr_len = card->default_address.len;
++  grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2;
+   grub_uint16_t vlantag = 0;
+ 
++  eth = nb->data;
+ 
+-  /* Check if a vlan-tag is present. If so, the ethernet header is 4 bytes */
+-  /* longer than the original one. The vlantag id is extracted and the header */
+-  /* is reseted to the original size. */
+-  if (grub_get_unaligned16 (nb->data + etherhdr_size - 2) == VLANTAG_IDENTIFIER)
++  hwaddress.type = card->default_address.type;
++  hwaddress.len = hw_addr_len;
++  grub_memcpy (hwaddress.mac, eth, hw_addr_len);
++  eth += hw_addr_len;
++
++  src_hwaddress.type = card->default_address.type;
++  src_hwaddress.len = hw_addr_len;
++  grub_memcpy (src_hwaddress.mac, eth, hw_addr_len);
++  eth += hw_addr_len;
++
++  type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth));
++  if (type == VLANTAG_IDENTIFIER)
+     {
+-      vlantag = grub_get_unaligned16 (nb->data + etherhdr_size);
++      /* Skip vlan tag */
++      eth += 2;
++      vlantag = grub_be_to_cpu16 (*(grub_uint16_t*)(eth));
+       etherhdr_size += 4;
+-      /* Move eth type to the original position */
+-      grub_memcpy((char *) nb->data + etherhdr_size - 6,
+-                  (char *) nb->data + etherhdr_size - 2, 2);
++      eth += 2;
++      type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth));
+     }
+ 
+-  eth = (struct etherhdr *) nb->data;
+-  type = grub_be_to_cpu16 (eth->type);
+   err = grub_netbuff_pull (nb, etherhdr_size);
+   if (err)
+     return err;
+@@ -148,11 +151,6 @@ grub_net_recv_ethernet_packet (struct grub_net_buff *nb,
+ 	}
+     }
+ 
+-  hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-  grub_memcpy (hwaddress.mac, eth->dst, sizeof (hwaddress.mac));
+-  src_hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-  grub_memcpy (src_hwaddress.mac, eth->src, sizeof (src_hwaddress.mac));
+-
+   switch (type)
+     {
+       /* ARP packet. */
+diff --git a/grub-core/net/icmp6.c b/grub-core/net/icmp6.c
+index 2cbd95dce2..56a3ec5c8e 100644
+--- a/grub-core/net/icmp6.c
++++ b/grub-core/net/icmp6.c
+@@ -231,8 +231,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
+ 		&& ohdr->len == 1)
+ 	      {
+ 		grub_net_link_level_address_t ll_address;
+-		ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-		grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
++		ll_address.type = card->default_address.type;
++		ll_address.len = card->default_address.len;
++		grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len);
+ 		grub_net_link_layer_add_address (card, source, &ll_address, 0);
+ 	      }
+ 	  }
+@@ -335,8 +336,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
+ 		&& ohdr->len == 1)
+ 	      {
+ 		grub_net_link_level_address_t ll_address;
+-		ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-		grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
++		ll_address.type = card->default_address.type;
++		ll_address.len = card->default_address.len;
++		grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len);
+ 		grub_net_link_layer_add_address (card, source, &ll_address, 0);
+ 	      }
+ 	  }
+@@ -384,8 +386,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
+ 		&& ohdr->len == 1)
+ 	      {
+ 		grub_net_link_level_address_t ll_address;
+-		ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-		grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
++		ll_address.type = card->default_address.type;
++		ll_address.len = card->default_address.len;
++		grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len);
+ 		grub_net_link_layer_add_address (card, source, &ll_address, 0);
+ 	      }
+ 	    if (ohdr->type == OPTION_PREFIX && ohdr->len == 4)
+diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
+index ea5edf8f1f..a5896f6dc2 100644
+--- a/grub-core/net/ip.c
++++ b/grub-core/net/ip.c
+@@ -276,8 +276,8 @@ handle_dgram (struct grub_net_buff *nb,
+ 	  if (inf->card == card
+ 	      && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV
+ 	      && inf->hwaddress.type == GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
+-	      && grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr,
+-			      sizeof (inf->hwaddress.mac)) == 0)
++	      && (grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr,
++			       bootp->hw_len) == 0 || bootp->hw_len == 0))
+ 	    {
+ 	      grub_net_process_dhcp (nb, inf);
+ 	      grub_netbuff_free (nb);
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index 22f2689aae..a46f82362e 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -133,8 +133,9 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf,
+ 								   << 48)
+ 	  && proto_addr->ipv6[1] == (grub_be_to_cpu64_compile_time (1))))
+     {
+-      hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-      grub_memset (hw_addr->mac, -1, 6);
++      hw_addr->type = inf->card->default_address.type;
++      hw_addr->len = inf->card->default_address.len;
++      grub_memset (hw_addr->mac, -1, hw_addr->len);
+       return GRUB_ERR_NONE;
+     }
+ 
+@@ -142,6 +143,7 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf,
+       && ((grub_be_to_cpu64 (proto_addr->ipv6[0]) >> 56) == 0xff))
+     {
+       hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
++      hw_addr->len = inf->card->default_address.len;
+       hw_addr->mac[0] = 0x33;
+       hw_addr->mac[1] = 0x33;
+       hw_addr->mac[2] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 24) & 0xff);
+@@ -762,23 +764,23 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf)
+ void
+ grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str)
+ {
+-  str[0] = 0;
+-  switch (addr->type)
++  char *ptr;
++  unsigned i;
++  int maxstr;
++
++  if (addr->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE)
+     {
+-    case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET:
+-      {
+-	char *ptr;
+-	unsigned i;
+-	for (ptr = str, i = 0; i < ARRAY_SIZE (addr->mac); i++)
+-	  {
+-	    grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str),
+-			   "%02x:", addr->mac[i] & 0xff);
+-	    ptr += (sizeof ("XX:") - 1);
+-	  }
+-      return;
+-      }
++       str[0] = 0;
++       grub_printf (_("Unsupported hw address type %d len %d\n"),
++		    addr->type, addr->len);
++       return;
++    }
++  maxstr = addr->len * grub_strlen ("XX:");
++  for (ptr = str, i = 0; i < addr->len; i++)
++    {
++      ptr += grub_snprintf (ptr, maxstr - (ptr - str),
++		     "%02x:", addr->mac[i] & 0xff);
+     }
+-  grub_printf (_("Unsupported hw address type %d\n"), addr->type);
+ }
+ 
+ int
+@@ -789,13 +791,17 @@ grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a,
+     return -1;
+   if (a->type > b->type)
+     return +1;
+-  switch (a->type)
++  if (a->len < b->len)
++    return -1;
++  if (a->len > b->len)
++    return +1;
++  if (a->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE)
+     {
+-    case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET:
+-      return grub_memcmp (a->mac, b->mac, sizeof (a->mac));
++      grub_printf (_("Unsupported hw address type %d len %d\n"),
++		   a->type, a->len);
++      return + 1;
+     }
+-  grub_printf (_("Unsupported hw address type %d\n"), a->type);
+-  return 1;
++  return grub_memcmp (a->mac, b->mac, a->len);
+ }
+ 
+ int
+diff --git a/include/grub/net.h b/include/grub/net.h
+index 8a05ec4fe7..af0404db7e 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -29,7 +29,8 @@
+ 
+ enum
+   {
+-    GRUB_NET_MAX_LINK_HEADER_SIZE = 64,
++    GRUB_NET_MAX_LINK_HEADER_SIZE = 96,
++    GRUB_NET_MAX_LINK_ADDRESS_SIZE = 32,
+     GRUB_NET_UDP_HEADER_SIZE = 8,
+     GRUB_NET_TCP_HEADER_SIZE = 20,
+     GRUB_NET_OUR_IPV4_HEADER_SIZE = 20,
+@@ -42,15 +43,17 @@ enum
+ 
+ typedef enum grub_link_level_protocol_id 
+ {
+-  GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
++  /* IANA ARP constant to define hardware type. */
++  GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET = 1,
+ } grub_link_level_protocol_id_t;
+ 
+ typedef struct grub_net_link_level_address
+ {
+   grub_link_level_protocol_id_t type;
++  grub_uint8_t len;
+   union
+   {
+-    grub_uint8_t mac[6];
++    grub_uint8_t mac[GRUB_NET_MAX_LINK_ADDRESS_SIZE];
+   };
+ } grub_net_link_level_address_t;
+ 
+@@ -566,11 +569,13 @@ grub_net_addr_cmp (const grub_net_network_level_address_t *a,
+ #define GRUB_NET_MAX_STR_ADDR_LEN sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX")
+ 
+ /*
+-  Currently suppoerted adresses:
+-  ethernet:   XX:XX:XX:XX:XX:XX
++  Up to 32 byte hardware address supported, see GRUB_NET_MAX_LINK_ADDRESS_SIZE
+  */
+-
+-#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof ("XX:XX:XX:XX:XX:XX"))
++#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof (\
++	"XX:XX:XX:XX:XX:XX:XX:XX:"\
++	"XX:XX:XX:XX:XX:XX:XX:XX:"\
++	"XX:XX:XX:XX:XX:XX:XX:XX:"\
++	"XX:XX:XX:XX:XX:XX:XX:XX"))
+ 
+ void
+ grub_net_addr_to_str (const grub_net_network_level_address_t *target,
diff --git a/SOURCES/0070-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch b/SOURCES/0070-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch
deleted file mode 100644
index 890aa34..0000000
--- a/SOURCES/0070-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 20 Apr 2017 13:29:06 -0400
-Subject: [PATCH] Don't guess /boot/efi/ as HFS+ on ppc machines in
- grub-install
-
-This should never be trying this, and since we've consolidated the
-grubenv to always be on /boot/efi/EFI/fedora/, this code causes it to
-always make the wrong decision.
-
-Resolves: rhbz#1484474
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- util/grub-install.c | 12 +-----------
- 1 file changed, 1 insertion(+), 11 deletions(-)
-
-diff --git a/util/grub-install.c b/util/grub-install.c
-index 84ed6e88ecb..a2bec7446cb 100644
---- a/util/grub-install.c
-+++ b/util/grub-install.c
-@@ -1190,18 +1190,8 @@ main (int argc, char *argv[])
- 	  char *d;
- 
- 	  is_guess = 1;
--	  d = grub_util_path_concat (2, bootdir, "macppc");
--	  if (!grub_util_is_directory (d))
--	    {
--	      free (d);
--	      d = grub_util_path_concat (2, bootdir, "efi");
--	    }
- 	  /* Find the Mac HFS(+) System Partition.  */
--	  if (!grub_util_is_directory (d))
--	    {
--	      free (d);
--	      d = grub_util_path_concat (2, bootdir, "EFI");
--	    }
-+	  d = grub_util_path_concat (2, bootdir, "macppc");
- 	  if (!grub_util_is_directory (d))
- 	    {
- 	      free (d);
diff --git a/SOURCES/0071-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch b/SOURCES/0071-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch
deleted file mode 100644
index 3fd779f..0000000
--- a/SOURCES/0071-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 9 Jul 2019 14:31:19 +0200
-Subject: [PATCH] 20_linux_xen: load xen or multiboot{,2} modules as needed.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- util/grub.d/20_linux_xen.in | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in
-index e9e73b815fb..c23b064be6c 100644
---- a/util/grub.d/20_linux_xen.in
-+++ b/util/grub.d/20_linux_xen.in
-@@ -153,6 +153,7 @@ linux_entry_xsm ()
-         else
-             xen_rm_opts="no-real-mode edd=off"
-         fi
-+	insmod ${xen_module}
- 	${xen_loader}	${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} \${xen_rm_opts}
- 	echo	'$(echo "$lmessage" | grub_quote)'
- 	${module_loader}	${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args}
-@@ -166,6 +167,7 @@ EOF
-     done
-     sed "s/^/$submenu_indentation/" << EOF
- 	echo	'$(echo "$message" | grub_quote)'
-+	insmod ${xen_module}
- 	${module_loader}	--nounzip   $(echo $initrd_path)
- EOF
-   fi
-@@ -253,13 +255,16 @@ while [ "x${xen_list}" != "x" ] ; do
- 	echo "	submenu '$(gettext_printf "Xen hypervisor, version %s" "${xen_version}" | grub_quote)' \$menuentry_id_option 'xen-hypervisor-$xen_version-$boot_device_id' {"
-     fi
-     if ($grub_file --is-arm64-efi $current_xen); then
-+	xen_module="xen_boot"
- 	xen_loader="xen_hypervisor"
- 	module_loader="xen_module"
-     else
- 	if ($grub_file --is-x86-multiboot2 $current_xen); then
-+	    xen_module="multiboot2"
- 	    xen_loader="multiboot2"
- 	    module_loader="module2"
- 	else
-+	    xen_module="multiboot"
- 	    xen_loader="multiboot"
- 	    module_loader="module"
-         fi
diff --git a/SOURCES/0071-net-read-bracketed-ipv6-addrs-and-port-numbers.patch b/SOURCES/0071-net-read-bracketed-ipv6-addrs-and-port-numbers.patch
new file mode 100644
index 0000000..307e33c
--- /dev/null
+++ b/SOURCES/0071-net-read-bracketed-ipv6-addrs-and-port-numbers.patch
@@ -0,0 +1,270 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Aaron Miller <aaronmiller@fb.com>
+Date: Fri, 29 Jul 2016 17:41:38 +0800
+Subject: [PATCH] net: read bracketed ipv6 addrs and port numbers
+
+Allow specifying port numbers for http and tftp paths, and allow ipv6 addresses
+to be recognized with brackets around them, which is required to specify a port
+number
+
+Signed-off-by: Aaron Miller <aaronmiller@fb.com>
+[pjones: various bug fixes]
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/http.c | 25 ++++++++++++---
+ grub-core/net/net.c  | 87 +++++++++++++++++++++++++++++++++++++++++++++++++---
+ grub-core/net/tftp.c |  8 +++--
+ include/grub/net.h   |  1 +
+ 4 files changed, 109 insertions(+), 12 deletions(-)
+
+diff --git a/grub-core/net/http.c b/grub-core/net/http.c
+index b616cf40b1..12a2632ea5 100644
+--- a/grub-core/net/http.c
++++ b/grub-core/net/http.c
+@@ -289,7 +289,9 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)),
+ 	  nb2 = grub_netbuff_alloc (data->chunk_rem);
+ 	  if (!nb2)
+ 	    return grub_errno;
+-	  grub_netbuff_put (nb2, data->chunk_rem);
++	  err = grub_netbuff_put (nb2, data->chunk_rem);
++	  if (err)
++	    return grub_errno;
+ 	  grub_memcpy (nb2->data, nb->data, data->chunk_rem);
+ 	  if (file->device->net->packs.count >= 20)
+ 	    {
+@@ -312,12 +314,14 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
+   int i;
+   struct grub_net_buff *nb;
+   grub_err_t err;
++  char* server = file->device->net->server;
++  int port = file->device->net->port;
+ 
+   nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE
+ 			   + sizeof ("GET ") - 1
+ 			   + grub_strlen (data->filename)
+ 			   + sizeof (" HTTP/1.1\r\nHost: ") - 1
+-			   + grub_strlen (file->device->net->server)
++			   + grub_strlen (server) + sizeof (":XXXXXXXXXX")
+ 			   + sizeof ("\r\nUser-Agent: " PACKAGE_STRING
+ 				     "\r\n") - 1
+ 			   + sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX"
+@@ -356,7 +360,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
+ 	       sizeof (" HTTP/1.1\r\nHost: ") - 1);
+ 
+   ptr = nb->tail;
+-  err = grub_netbuff_put (nb, grub_strlen (file->device->net->server));
++  err = grub_netbuff_put (nb, grub_strlen (server));
+   if (err)
+     {
+       grub_netbuff_free (nb);
+@@ -365,6 +369,15 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
+   grub_memcpy (ptr, file->device->net->server,
+ 	       grub_strlen (file->device->net->server));
+ 
++  if (port)
++    {
++      ptr = nb->tail;
++      grub_snprintf ((char *) ptr,
++	  sizeof (":XXXXXXXXXX"),
++	  ":%d",
++	  port);
++    }
++
+   ptr = nb->tail;
+   err = grub_netbuff_put (nb, 
+ 			  sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n")
+@@ -390,8 +403,10 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
+   grub_netbuff_put (nb, 2);
+   grub_memcpy (ptr, "\r\n", 2);
+ 
+-  data->sock = grub_net_tcp_open (file->device->net->server,
+-				  HTTP_PORT, http_receive,
++  grub_dprintf ("http", "opening path %s on host %s TCP port %d\n",
++		data->filename, server, port ? port : HTTP_PORT);
++  data->sock = grub_net_tcp_open (server,
++				  port ? port : HTTP_PORT, http_receive,
+ 				  http_err, NULL,
+ 				  file);
+   if (!data->sock)
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index a46f82362e..0ce5e675ed 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -444,6 +444,13 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
+   grub_uint16_t newip[8];
+   const char *ptr = val;
+   int word, quaddot = -1;
++  int bracketed = 0;
++
++  if (ptr[0] == '[')
++    {
++      bracketed = 1;
++      ptr++;
++    }
+ 
+   if (ptr[0] == ':' && ptr[1] != ':')
+     return 0;
+@@ -482,6 +489,8 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
+       grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
+     }
+   grub_memcpy (ip, newip, 16);
++  if (bracketed && *ptr == ']')
++    ptr++;
+   if (rest)
+     *rest = ptr;
+   return 1;
+@@ -1343,8 +1352,10 @@ grub_net_open_real (const char *name)
+ {
+   grub_net_app_level_t proto;
+   const char *protname, *server;
++  char *host;
+   grub_size_t protnamelen;
+   int try;
++  int port = 0;
+ 
+   if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
+     {
+@@ -1382,6 +1393,72 @@ grub_net_open_real (const char *name)
+       return NULL;
+     }  
+ 
++  char* port_start;
++  /* ipv6 or port specified? */
++  if ((port_start = grub_strchr (server, ':')))
++    {
++      char* ipv6_begin;
++      if((ipv6_begin = grub_strchr (server, '[')))
++	{
++	  char* ipv6_end = grub_strchr (server, ']');
++	  if(!ipv6_end)
++	    {
++	      grub_error (GRUB_ERR_NET_BAD_ADDRESS,
++		      N_("mismatched [ in address"));
++	      return NULL;
++	    }
++	  /* port number after bracketed ipv6 addr */
++	  if(ipv6_end[1] == ':')
++	    {
++	      port = grub_strtoul (ipv6_end + 2, NULL, 10);
++	      if(port > 65535)
++		{
++		  grub_error (GRUB_ERR_NET_BAD_ADDRESS,
++			  N_("bad port number"));
++		  return NULL;
++		}
++	    }
++	  host = grub_strndup (ipv6_begin, (ipv6_end - ipv6_begin) + 1);
++	}
++      else
++	{
++	  if (grub_strchr (port_start + 1, ':'))
++	    {
++	      int iplen = grub_strlen (server);
++	      /* bracket bare ipv6 addrs */
++	      host = grub_malloc (iplen + 3);
++	      if(!host)
++		{
++		  return NULL;
++		}
++	      host[0] = '[';
++	      grub_memcpy (host + 1, server, iplen);
++	      host[iplen + 1] = ']';
++	      host[iplen + 2] = '\0';
++	    }
++	  else
++	    {
++	      /* hostname:port or ipv4:port */
++	      port = grub_strtol (port_start + 1, NULL, 10);
++	      if(port > 65535)
++		{
++		  grub_error (GRUB_ERR_NET_BAD_ADDRESS,
++			  N_("bad port number"));
++		  return NULL;
++		}
++	      host = grub_strndup (server, port_start - server);
++	    }
++	}
++    }
++  else
++    {
++      host = grub_strdup (server);
++    }
++  if (!host)
++    {
++      return NULL;
++    }
++
+   for (try = 0; try < 2; try++)
+     {
+       FOR_NET_APP_LEVEL (proto)
+@@ -1391,14 +1468,13 @@ grub_net_open_real (const char *name)
+ 	  {
+ 	    grub_net_t ret = grub_zalloc (sizeof (*ret));
+ 	    if (!ret)
+-	      return NULL;
+-	    ret->protocol = proto;
+-	    ret->server = grub_strdup (server);
+-	    if (!ret->server)
+ 	      {
+-		grub_free (ret);
++		grub_free (host);
+ 		return NULL;
+ 	      }
++	    ret->protocol = proto;
++	    ret->port = port;
++	    ret->server = host;
+ 	    ret->fs = &grub_net_fs;
+ 	    return ret;
+ 	  }
+@@ -1473,6 +1549,7 @@ grub_net_open_real (const char *name)
+   grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"),
+ 	      name);
+ 
++  grub_free (host);
+   return NULL;
+ }
+ 
+diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
+index 4ab2f5c735..d54b13f09f 100644
+--- a/grub-core/net/tftp.c
++++ b/grub-core/net/tftp.c
+@@ -295,6 +295,7 @@ tftp_open (struct grub_file *file, const char *filename)
+   grub_err_t err;
+   grub_uint8_t *nbd;
+   grub_net_network_level_address_t addr;
++  int port = file->device->net->port;
+ 
+   data = grub_zalloc (sizeof (*data));
+   if (!data)
+@@ -362,14 +363,17 @@ tftp_open (struct grub_file *file, const char *filename)
+   err = grub_net_resolve_address (file->device->net->server, &addr);
+   if (err)
+     {
+-      grub_dprintf("tftp", "Address resolution failed: %d\n", err);
++      grub_dprintf ("tftp", "Address resolution failed: %d\n", err);
++      grub_dprintf ("tftp", "file_size is %llu, block_size is %llu\n",
++		    (unsigned long long)data->file_size,
++		    (unsigned long long)data->block_size);
+       grub_free (data);
+       return err;
+     }
+ 
+   grub_dprintf("tftp", "opening connection\n");
+   data->sock = grub_net_udp_open (addr,
+-				  TFTP_SERVER_PORT, tftp_receive,
++				  port ? port : TFTP_SERVER_PORT, tftp_receive,
+ 				  file);
+   if (!data->sock)
+     {
+diff --git a/include/grub/net.h b/include/grub/net.h
+index af0404db7e..d55d505a03 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -273,6 +273,7 @@ typedef struct grub_net
+ {
+   char *server;
+   char *name;
++  int port;
+   grub_net_app_level_t protocol;
+   grub_net_packets_t packs;
+   grub_off_t offset;
diff --git a/SOURCES/0072-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch b/SOURCES/0072-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch
deleted file mode 100644
index acfb116..0000000
--- a/SOURCES/0072-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch
+++ /dev/null
@@ -1,211 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 7 Nov 2017 17:12:17 -0500
-Subject: [PATCH] Make pmtimer tsc calibration not take 51 seconds to fail.
-
-On my laptop running at 2.4GHz, if I run a VM where tsc calibration
-using pmtimer will fail presuming a broken pmtimer, it takes ~51 seconds
-to do so (as measured with the stopwatch on my phone), with a tsc delta
-of 0x1cd1c85300, or around 125 billion cycles.
-
-If instead of trying to wait for 5-200ms to show up on the pmtimer, we try
-to wait for 5-200us, it decides it's broken in ~0x2626aa0 TSCs, aka ~2.4
-million cycles, or more or less instantly.
-
-Additionally, this reading the pmtimer was returning 0xffffffff anyway,
-and that's obviously an invalid return.  I've added a check for that and
-0 so we don't bother waiting for the test if what we're seeing is dead
-pins with no response at all.
-
-If "debug" is includes "pmtimer", you will see one of the following
-three outcomes.  If pmtimer gives all 0 or all 1 bits, you will see:
-
-kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 1
-kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 2
-kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 3
-kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 4
-kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 5
-kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 6
-kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 7
-kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 8
-kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 9
-kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 10
-kern/i386/tsc_pmtimer.c:78: timer is broken; giving up.
-
-This outcome was tested using qemu+kvm with UEFI (OVMF) firmware and
-these options: -machine pc-q35-2.10 -cpu Broadwell-noTSX
-
-If pmtimer gives any other bit patterns but is not actually marching
-forward fast enough to use for clock calibration, you will see:
-
-kern/i386/tsc_pmtimer.c:121: pmtimer delta is 0x0 (1904 iterations)
-kern/i386/tsc_pmtimer.c:124: tsc delta is implausible: 0x2626aa0
-
-This outcome was tested using grub compiled with GRUB_PMTIMER_IGNORE_BAD_READS
-defined (so as not to trip the bad read test) using qemu+kvm with UEFI
-(OVMF) firmware, and these options: -machine pc-q35-2.10 -cpu Broadwell-noTSX
-
-If pmtimer actually works, you'll see something like:
-
-kern/i386/tsc_pmtimer.c:121: pmtimer delta is 0x0 (1904 iterations)
-kern/i386/tsc_pmtimer.c:124: tsc delta is implausible: 0x2626aa0
-
-This outcome was tested using qemu+kvm with UEFI (OVMF) firmware, and
-these options: -machine pc-i440fx-2.4 -cpu Broadwell-noTSX
-
-I've also tested this outcome on a real Intel Xeon E3-1275v3 on an Intel
-Server Board S1200V3RPS using the SDV.RP.B8 "Release" build here:
-https://firmware.intel.com/sites/default/files/UEFIDevKit_S1200RP_vB8.zip
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/kern/i386/tsc_pmtimer.c | 109 +++++++++++++++++++++++++++++++-------
- 1 file changed, 89 insertions(+), 20 deletions(-)
-
-diff --git a/grub-core/kern/i386/tsc_pmtimer.c b/grub-core/kern/i386/tsc_pmtimer.c
-index c9c36169978..ca15c3aacd7 100644
---- a/grub-core/kern/i386/tsc_pmtimer.c
-+++ b/grub-core/kern/i386/tsc_pmtimer.c
-@@ -28,40 +28,101 @@
- #include <grub/acpi.h>
- #include <grub/cpu/io.h>
- 
-+/*
-+ * Define GRUB_PMTIMER_IGNORE_BAD_READS if you're trying to test a timer that's
-+ * present but doesn't keep time well.
-+ */
-+// #define GRUB_PMTIMER_IGNORE_BAD_READS
-+
- grub_uint64_t
- grub_pmtimer_wait_count_tsc (grub_port_t pmtimer,
- 			     grub_uint16_t num_pm_ticks)
- {
-   grub_uint32_t start;
--  grub_uint32_t last;
--  grub_uint32_t cur, end;
-+  grub_uint64_t cur, end;
-   grub_uint64_t start_tsc;
-   grub_uint64_t end_tsc;
--  int num_iter = 0;
-+  unsigned int num_iter = 0;
-+#ifndef GRUB_PMTIMER_IGNORE_BAD_READS
-+  int bad_reads = 0;
-+#endif
- 
--  start = grub_inl (pmtimer) & 0xffffff;
--  last = start;
-+  /*
-+   * Some timers are 24-bit and some are 32-bit, but it doesn't make much
-+   * difference to us.  Caring which one we have isn't really worth it since
-+   * the low-order digits will give us enough data to calibrate TSC.  So just
-+   * mask the top-order byte off.
-+   */
-+  cur = start = grub_inl (pmtimer) & 0xffffffUL;
-   end = start + num_pm_ticks;
-   start_tsc = grub_get_tsc ();
-   while (1)
-     {
--      cur = grub_inl (pmtimer) & 0xffffff;
--      if (cur < last)
--	cur |= 0x1000000;
--      num_iter++;
-+      cur &= 0xffffffffff000000ULL;
-+      cur |= grub_inl (pmtimer) & 0xffffffUL;
-+
-+      end_tsc = grub_get_tsc();
-+
-+#ifndef GRUB_PMTIMER_IGNORE_BAD_READS
-+      /*
-+       * If we get 10 reads in a row that are obviously dead pins, there's no
-+       * reason to do this thousands of times.
-+       */
-+      if (cur == 0xffffffUL || cur == 0)
-+	{
-+	  bad_reads++;
-+	  grub_dprintf ("pmtimer",
-+			"pmtimer: 0x%"PRIxGRUB_UINT64_T" bad_reads: %d\n",
-+			cur, bad_reads);
-+	  grub_dprintf ("pmtimer", "timer is broken; giving up.\n");
-+
-+	  if (bad_reads == 10)
-+	    return 0;
-+	}
-+#endif
-+
-+      if (cur < start)
-+	cur += 0x1000000;
-+
-       if (cur >= end)
- 	{
--	  end_tsc = grub_get_tsc ();
-+	  grub_dprintf ("pmtimer", "pmtimer delta is 0x%"PRIxGRUB_UINT64_T"\n",
-+			cur - start);
-+	  grub_dprintf ("pmtimer", "tsc delta is 0x%"PRIxGRUB_UINT64_T"\n",
-+			end_tsc - start_tsc);
- 	  return end_tsc - start_tsc;
- 	}
--      /* Check for broken PM timer.
--	 50000000 TSCs is between 5 ms (10GHz) and 200 ms (250 MHz)
--	 if after this time we still don't have 1 ms on pmtimer, then
--	 pmtimer is broken.
-+
-+      /*
-+       * Check for broken PM timer.  1ms at 10GHz should be 1E+7 TSCs; at
-+       * 250MHz it should be 2.5E6.  So if after 4E+7 TSCs on a 10GHz machine,
-+       * we should have seen pmtimer show 4ms of change (i.e. cur =~
-+       * start+14320); on a 250MHz machine that should be 16ms (start+57280).
-+       * If after this a time we still don't have 1ms on pmtimer, then pmtimer
-+       * is broken.
-+       *
-+       * Likewise, if our code is perfectly efficient and introduces no delays
-+       * whatsoever, on a 10GHz system we should see a TSC delta of 3580 in
-+       * ~3580 iterations.  On a 250MHz machine that should be ~900 iterations.
-+       *
-+       * With those factors in mind, there are two limits here.  There's a hard
-+       * limit here at 8x our desired pm timer delta, picked as an arbitrarily
-+       * large value that's still not a lot of time to humans, because if we
-+       * get that far this is either an implausibly fast machine or the pmtimer
-+       * is not running.  And there's another limit on 4x our 10GHz tsc delta
-+       * without seeing cur converge on our target value.
-        */
--      if ((num_iter & 0xffffff) == 0 && grub_get_tsc () - start_tsc > 5000000) {
--	return 0;
--      }
-+      if ((++num_iter > (grub_uint32_t)num_pm_ticks << 3UL) ||
-+	  end_tsc - start_tsc > 40000000)
-+	{
-+	  grub_dprintf ("pmtimer",
-+			"pmtimer delta is 0x%"PRIxGRUB_UINT64_T" (%u iterations)\n",
-+			cur - start, num_iter);
-+	  grub_dprintf ("pmtimer",
-+			"tsc delta is implausible: 0x%"PRIxGRUB_UINT64_T"\n",
-+			end_tsc - start_tsc);
-+	  return 0;
-+	}
-     }
- }
- 
-@@ -74,12 +135,20 @@ grub_tsc_calibrate_from_pmtimer (void)
- 
-   fadt = grub_acpi_find_fadt ();
-   if (!fadt)
--    return 0;
-+    {
-+      grub_dprintf ("pmtimer", "No FADT found; not using pmtimer.\n");
-+      return 0;
-+    }
-   pmtimer = fadt->pmtimer;
-   if (!pmtimer)
--    return 0;
-+    {
-+      grub_dprintf ("pmtimer", "FADT does not specify pmtimer; skipping.\n");
-+      return 0;
-+    }
- 
--  /* It's 3.579545 MHz clock. Wait 1 ms.  */
-+  /*
-+   * It's 3.579545 MHz clock. Wait 1 ms.
-+   */
-   tsc_diff = grub_pmtimer_wait_count_tsc (pmtimer, 3580);
-   if (tsc_diff == 0)
-     return 0;
diff --git a/SOURCES/0072-bootp-New-net_bootp6-command.patch b/SOURCES/0072-bootp-New-net_bootp6-command.patch
new file mode 100644
index 0000000..bef3acd
--- /dev/null
+++ b/SOURCES/0072-bootp-New-net_bootp6-command.patch
@@ -0,0 +1,1368 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Wed, 10 Jul 2019 15:42:36 +0200
+Subject: [PATCH] bootp: New net_bootp6 command
+
+Implement new net_bootp6 command for IPv6 network auto configuration via the
+DHCPv6 protocol (RFC3315).
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+[pjones: Put back our code to add a local route]
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/bootp.c              | 1059 ++++++++++++++++++++++++++++++------
+ grub-core/net/drivers/efi/efinet.c |   20 +-
+ grub-core/net/ip.c                 |   39 ++
+ include/grub/efi/api.h             |    2 +-
+ include/grub/net.h                 |   91 ++--
+ 5 files changed, 1002 insertions(+), 209 deletions(-)
+
+diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
+index 08b6b2b5d6..fe93b80f1c 100644
+--- a/grub-core/net/bootp.c
++++ b/grub-core/net/bootp.c
+@@ -24,6 +24,98 @@
+ #include <grub/net/netbuff.h>
+ #include <grub/net/udp.h>
+ #include <grub/datetime.h>
++#include <grub/time.h>
++#include <grub/list.h>
++
++static int
++dissect_url (const char *url, char **proto, char **host, char **path)
++{
++  const char *p, *ps;
++  grub_size_t l;
++
++  *proto = *host = *path = NULL;
++  ps = p = url;
++
++  while ((p = grub_strchr (p, ':')))
++    {
++      if (grub_strlen (p) < sizeof ("://") - 1)
++	break;
++      if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0)
++	{
++	  l = p - ps;
++	  *proto = grub_malloc (l + 1);
++	  if (!*proto)
++	    {
++	      grub_print_error ();
++	      return 0;
++	    }
++
++	  grub_memcpy (*proto, ps, l);
++	  (*proto)[l] = '\0';
++	  p +=  sizeof ("://") - 1;
++	  break;
++	}
++      ++p;
++    }
++
++  if (!*proto)
++    {
++      grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url);
++      return 0;
++    }
++
++  ps = p;
++  p = grub_strchr (p, '/');
++
++  if (!p)
++    {
++      grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url);
++      grub_free (*proto);
++      *proto = NULL;
++      return 0;
++    }
++
++  l = p - ps;
++
++  if (l > 2 && ps[0] == '[' && ps[l - 1] == ']')
++    {
++      *host = grub_malloc (l - 1);
++      if (!*host)
++	{
++	  grub_print_error ();
++	  grub_free (*proto);
++	  *proto = NULL;
++	  return 0;
++	}
++      grub_memcpy (*host, ps + 1, l - 2);
++      (*host)[l - 2] = 0;
++    }
++  else
++    {
++      *host = grub_malloc (l + 1);
++      if (!*host)
++	{
++	  grub_print_error ();
++	  grub_free (*proto);
++	  *proto = NULL;
++	  return 0;
++	}
++      grub_memcpy (*host, ps, l);
++      (*host)[l] = 0;
++    }
++
++  *path = grub_strdup (p);
++  if (!*path)
++    {
++      grub_print_error ();
++      grub_free (*host);
++      grub_free (*proto);
++      *host = NULL;
++      *proto = NULL;
++      return 0;
++    }
++  return 1;
++}
+ 
+ struct grub_dhcp_discover_options
+ {
+@@ -604,6 +696,584 @@ out:
+   return err;
+ }
+ 
++/* The default netbuff size for sending DHCPv6 packets which should be
++   large enough to hold the information */
++#define GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE 512
++
++struct grub_dhcp6_options
++{
++  grub_uint8_t *client_duid;
++  grub_uint16_t client_duid_len;
++  grub_uint8_t *server_duid;
++  grub_uint16_t server_duid_len;
++  grub_uint32_t iaid;
++  grub_uint32_t t1;
++  grub_uint32_t t2;
++  grub_net_network_level_address_t *ia_addr;
++  grub_uint32_t preferred_lifetime;
++  grub_uint32_t valid_lifetime;
++  grub_net_network_level_address_t *dns_server_addrs;
++  grub_uint16_t num_dns_server;
++  char *boot_file_proto;
++  char *boot_file_server_ip;
++  char *boot_file_path;
++};
++
++typedef struct grub_dhcp6_options *grub_dhcp6_options_t;
++
++struct grub_dhcp6_session
++{
++  struct grub_dhcp6_session *next;
++  struct grub_dhcp6_session **prev;
++  grub_uint32_t iaid;
++  grub_uint32_t transaction_id:24;
++  grub_uint64_t start_time;
++  struct grub_net_dhcp6_option_duid_ll duid;
++  struct grub_net_network_level_interface *iface;
++
++  /* The associated dhcpv6 options */
++  grub_dhcp6_options_t adv;
++  grub_dhcp6_options_t reply;
++};
++
++typedef struct grub_dhcp6_session *grub_dhcp6_session_t;
++
++typedef void (*dhcp6_option_hook_fn) (const struct grub_net_dhcp6_option *opt, void *data);
++
++static void
++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size,
++		      dhcp6_option_hook_fn hook, void *hook_data);
++
++static void
++parse_dhcp6_iaaddr (const struct grub_net_dhcp6_option *opt, void *data)
++{
++  grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t )data;
++
++  grub_uint16_t code = grub_be_to_cpu16 (opt->code);
++  grub_uint16_t len = grub_be_to_cpu16 (opt->len);
++
++  if (code == GRUB_NET_DHCP6_OPTION_IAADDR)
++    {
++      const struct grub_net_dhcp6_option_iaaddr *iaaddr;
++      iaaddr = (const struct grub_net_dhcp6_option_iaaddr *)opt->data;
++
++      if (len < sizeof (*iaaddr))
++	{
++	  grub_dprintf ("bootp", "DHCPv6: code %u with insufficient length %u\n", code, len);
++	  return;
++	}
++      if (!dhcp6->ia_addr)
++	{
++	  dhcp6->ia_addr = grub_malloc (sizeof(*dhcp6->ia_addr));
++	  dhcp6->ia_addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++	  dhcp6->ia_addr->ipv6[0] = grub_get_unaligned64 (iaaddr->addr);
++	  dhcp6->ia_addr->ipv6[1] = grub_get_unaligned64 (iaaddr->addr + 8);
++	  dhcp6->preferred_lifetime = grub_be_to_cpu32 (iaaddr->preferred_lifetime);
++	  dhcp6->valid_lifetime = grub_be_to_cpu32 (iaaddr->valid_lifetime);
++	}
++    }
++}
++
++static void
++parse_dhcp6_option (const struct grub_net_dhcp6_option *opt, void *data)
++{
++  grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t)data;
++  grub_uint16_t code = grub_be_to_cpu16 (opt->code);
++  grub_uint16_t len = grub_be_to_cpu16 (opt->len);
++
++  switch (code)
++    {
++      case GRUB_NET_DHCP6_OPTION_CLIENTID:
++
++	if (dhcp6->client_duid || !len)
++	  {
++	    grub_dprintf ("bootp", "Skipped DHCPv6 CLIENTID with length %u\n", len);
++	    break;
++	  }
++	dhcp6->client_duid = grub_malloc (len);
++	grub_memcpy (dhcp6->client_duid, opt->data, len);
++	dhcp6->client_duid_len = len;
++	break;
++
++      case GRUB_NET_DHCP6_OPTION_SERVERID:
++
++	if (dhcp6->server_duid || !len)
++	  {
++	    grub_dprintf ("bootp", "Skipped DHCPv6 SERVERID with length %u\n", len);
++	    break;
++	  }
++	dhcp6->server_duid = grub_malloc (len);
++	grub_memcpy (dhcp6->server_duid, opt->data, len);
++	dhcp6->server_duid_len = len;
++	break;
++
++      case GRUB_NET_DHCP6_OPTION_IA_NA:
++	{
++	  const struct grub_net_dhcp6_option_iana *ia_na;
++	  grub_uint16_t data_len;
++
++	  if (dhcp6->iaid || len < sizeof (*ia_na))
++	    {
++	      grub_dprintf ("bootp", "Skipped DHCPv6 IA_NA with length %u\n", len);
++	      break;
++	    }
++	  ia_na = (const struct grub_net_dhcp6_option_iana *)opt->data;
++	  dhcp6->iaid = grub_be_to_cpu32 (ia_na->iaid);
++	  dhcp6->t1 = grub_be_to_cpu32 (ia_na->t1);
++	  dhcp6->t2 = grub_be_to_cpu32 (ia_na->t2);
++
++	  data_len = len - sizeof (*ia_na);
++	  if (data_len)
++	    foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)ia_na->data, data_len, parse_dhcp6_iaaddr, dhcp6);
++	}
++	break;
++
++      case GRUB_NET_DHCP6_OPTION_DNS_SERVERS:
++	{
++	  const grub_uint8_t *po;
++	  grub_uint16_t ln;
++	  grub_net_network_level_address_t *la;
++
++	  if (!len || len & 0xf)
++	    {
++	      grub_dprintf ("bootp", "Skip invalid length DHCPv6 DNS_SERVERS \n");
++	      break;
++	    }
++	  dhcp6->num_dns_server = ln = len >> 4;
++	  dhcp6->dns_server_addrs = la = grub_zalloc (ln * sizeof (*la));
++
++	  for (po = opt->data; ln > 0; po += 0x10, la++, ln--)
++	    {
++	      la->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++	      la->ipv6[0] = grub_get_unaligned64 (po);
++	      la->ipv6[1] = grub_get_unaligned64 (po + 8);
++	      la->option = DNS_OPTION_PREFER_IPV6;
++	    }
++	}
++	break;
++
++      case GRUB_NET_DHCP6_OPTION_BOOTFILE_URL:
++	dissect_url ((const char *)opt->data,
++		      &dhcp6->boot_file_proto,
++		      &dhcp6->boot_file_server_ip,
++		      &dhcp6->boot_file_path);
++	break;
++
++      default:
++	break;
++    }
++}
++
++static void
++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, dhcp6_option_hook_fn hook, void *hook_data)
++{
++  while (size)
++    {
++      grub_uint16_t code, len;
++
++      if (size < sizeof (*opt))
++	{
++	  grub_dprintf ("bootp", "DHCPv6: Options stopped with remaining size %" PRIxGRUB_SIZE "\n", size);
++	  break;
++	}
++      size -= sizeof (*opt);
++      len = grub_be_to_cpu16 (opt->len);
++      code = grub_be_to_cpu16 (opt->code);
++      if (size < len)
++	{
++	  grub_dprintf ("bootp", "DHCPv6: Options stopped at out of bound length %u for option %u\n", len, code);
++	  break;
++	}
++      if (!len)
++	{
++	  grub_dprintf ("bootp", "DHCPv6: Options stopped at zero length option %u\n", code);
++	  break;
++	}
++      else
++	{
++	  if (hook)
++	    hook (opt, hook_data);
++	  size -= len;
++	  opt = (const struct grub_net_dhcp6_option *)((grub_uint8_t *)opt + len + sizeof (*opt));
++	}
++    }
++}
++
++static grub_dhcp6_options_t
++grub_dhcp6_options_get (const struct grub_net_dhcp6_packet *v6h,
++			grub_size_t size)
++{
++  grub_dhcp6_options_t options;
++
++  if (size < sizeof (*v6h))
++    {
++      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small"));
++      return NULL;
++    }
++
++  options = grub_zalloc (sizeof(*options));
++  if (!options)
++    return NULL;
++
++  foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)v6h->dhcp_options,
++		       size - sizeof (*v6h), parse_dhcp6_option, options);
++
++  return options;
++}
++
++static void
++grub_dhcp6_options_free (grub_dhcp6_options_t options)
++{
++  if (options->client_duid)
++    grub_free (options->client_duid);
++  if (options->server_duid)
++    grub_free (options->server_duid);
++  if (options->ia_addr)
++    grub_free (options->ia_addr);
++  if (options->dns_server_addrs)
++    grub_free (options->dns_server_addrs);
++  if (options->boot_file_proto)
++    grub_free (options->boot_file_proto);
++  if (options->boot_file_server_ip)
++    grub_free (options->boot_file_server_ip);
++  if (options->boot_file_path)
++    grub_free (options->boot_file_path);
++
++  grub_free (options);
++}
++
++static grub_dhcp6_session_t grub_dhcp6_sessions;
++#define FOR_DHCP6_SESSIONS_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE (var, next, grub_dhcp6_sessions)
++#define FOR_DHCP6_SESSIONS(var) FOR_LIST_ELEMENTS (var, grub_dhcp6_sessions)
++
++static void
++grub_net_configure_by_dhcp6_info (const char *name,
++	  struct grub_net_card *card,
++	  grub_dhcp6_options_t dhcp6,
++	  int is_def,
++	  int flags,
++	  struct grub_net_network_level_interface **ret_inf)
++{
++  grub_net_network_level_netaddress_t netaddr;
++  struct grub_net_network_level_interface *inf;
++
++  if (dhcp6->ia_addr)
++    {
++      inf = grub_net_add_addr (name, card, dhcp6->ia_addr, &card->default_address, flags);
++
++      netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++      netaddr.ipv6.base[0] = dhcp6->ia_addr->ipv6[0];
++      netaddr.ipv6.base[1] = 0;
++      netaddr.ipv6.masksize = 64;
++      grub_net_add_route (name, netaddr, inf);
++
++      if (ret_inf)
++	*ret_inf = inf;
++    }
++
++  if (dhcp6->dns_server_addrs)
++    {
++      grub_uint16_t i;
++
++      for (i = 0; i < dhcp6->num_dns_server; ++i)
++	grub_net_add_dns_server (dhcp6->dns_server_addrs + i);
++    }
++
++  if (dhcp6->boot_file_path)
++    grub_env_set_net_property (name, "boot_file", dhcp6->boot_file_path,
++			  grub_strlen (dhcp6->boot_file_path));
++
++  if (is_def && dhcp6->boot_file_server_ip)
++    {
++      grub_net_default_server = grub_strdup (dhcp6->boot_file_server_ip);
++      grub_env_set ("net_default_interface", name);
++      grub_env_export ("net_default_interface");
++    }
++}
++
++static void
++grub_dhcp6_session_add (struct grub_net_network_level_interface *iface,
++			grub_uint32_t iaid)
++{
++  grub_dhcp6_session_t se;
++  struct grub_datetime date;
++  grub_err_t err;
++  grub_int32_t t = 0;
++
++  se = grub_malloc (sizeof (*se));
++
++  err = grub_get_datetime (&date);
++  if (err || !grub_datetime2unixtime (&date, &t))
++    {
++      grub_errno = GRUB_ERR_NONE;
++      t = 0;
++    }
++
++  se->iface = iface;
++  se->iaid = iaid;
++  se->transaction_id = t;
++  se->start_time = grub_get_time_ms ();
++  se->duid.type = grub_cpu_to_be16_compile_time (3) ;
++  se->duid.hw_type = grub_cpu_to_be16_compile_time (1);
++  grub_memcpy (&se->duid.hwaddr, &iface->hwaddress.mac, sizeof (se->duid.hwaddr));
++  se->adv = NULL;
++  se->reply = NULL;
++  grub_list_push (GRUB_AS_LIST_P (&grub_dhcp6_sessions), GRUB_AS_LIST (se));
++}
++
++static void
++grub_dhcp6_session_remove (grub_dhcp6_session_t se)
++{
++  grub_list_remove (GRUB_AS_LIST (se));
++  if (se->adv)
++    grub_dhcp6_options_free (se->adv);
++  if (se->reply)
++    grub_dhcp6_options_free (se->reply);
++  grub_free (se);
++}
++
++static void
++grub_dhcp6_session_remove_all (void)
++{
++  grub_dhcp6_session_t se, next;
++
++  FOR_DHCP6_SESSIONS_SAFE (se, next)
++    {
++      grub_dhcp6_session_remove (se);
++    }
++  grub_dhcp6_sessions = NULL;
++}
++
++static grub_err_t
++grub_dhcp6_session_configure_network (grub_dhcp6_session_t se)
++{
++  char *name;
++
++  name = grub_xasprintf ("%s:dhcp6", se->iface->card->name);
++  if (!name)
++    return grub_errno;
++
++  grub_net_configure_by_dhcp6_info (name, se->iface->card, se->reply, 1, 0, 0);
++  grub_free (name);
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_dhcp6_session_send_request (grub_dhcp6_session_t se)
++{
++  struct grub_net_buff *nb;
++  struct grub_net_dhcp6_option *opt;
++  struct grub_net_dhcp6_packet *v6h;
++  struct grub_net_dhcp6_option_iana *ia_na;
++  struct grub_net_dhcp6_option_iaaddr *iaaddr;
++  struct udphdr *udph;
++  grub_net_network_level_address_t multicast;
++  grub_net_link_level_address_t ll_multicast;
++  grub_uint64_t elapsed;
++  struct grub_net_network_level_interface *inf = se->iface;
++  grub_dhcp6_options_t dhcp6 = se->adv;
++  grub_err_t err = GRUB_ERR_NONE;
++
++  multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++  multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48);
++  multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL);
++
++  err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast);
++  if (err)
++    return err;
++
++  nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
++
++  if (!nb)
++    return grub_errno;
++
++  err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++
++  err = grub_netbuff_push (nb, dhcp6->client_duid_len + sizeof (*opt));
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++  opt = (struct grub_net_dhcp6_option *)nb->data;
++  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID);
++  opt->len = grub_cpu_to_be16 (dhcp6->client_duid_len);
++  grub_memcpy (opt->data, dhcp6->client_duid , dhcp6->client_duid_len);
++
++  err = grub_netbuff_push (nb, dhcp6->server_duid_len + sizeof (*opt));
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++  opt = (struct grub_net_dhcp6_option *)nb->data;
++  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_SERVERID);
++  opt->len = grub_cpu_to_be16 (dhcp6->server_duid_len);
++  grub_memcpy (opt->data, dhcp6->server_duid , dhcp6->server_duid_len);
++
++  err = grub_netbuff_push (nb, sizeof (*ia_na) + sizeof (*opt));
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++
++  if (dhcp6->ia_addr)
++    {
++      err = grub_netbuff_push (nb, sizeof(*iaaddr) + sizeof (*opt));
++      if (err)
++	{
++	  grub_netbuff_free (nb);
++	  return err;
++	}
++    }
++  opt = (struct grub_net_dhcp6_option *)nb->data;
++  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
++  opt->len = grub_cpu_to_be16 (sizeof (*ia_na));
++  if (dhcp6->ia_addr)
++    opt->len += grub_cpu_to_be16 (sizeof(*iaaddr) + sizeof (*opt));
++
++  ia_na = (struct grub_net_dhcp6_option_iana *)opt->data;
++  ia_na->iaid = grub_cpu_to_be32 (dhcp6->iaid);
++
++  ia_na->t1 = grub_cpu_to_be32 (dhcp6->t1);
++  ia_na->t2 = grub_cpu_to_be32 (dhcp6->t2);
++
++  if (dhcp6->ia_addr)
++    {
++      opt = (struct grub_net_dhcp6_option *)ia_na->data;
++      opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR);
++      opt->len = grub_cpu_to_be16 (sizeof (*iaaddr));
++      iaaddr = (struct grub_net_dhcp6_option_iaaddr *)opt->data;
++      grub_set_unaligned64 (iaaddr->addr, dhcp6->ia_addr->ipv6[0]);
++      grub_set_unaligned64 (iaaddr->addr + 8, dhcp6->ia_addr->ipv6[1]);
++
++      iaaddr->preferred_lifetime = grub_cpu_to_be32 (dhcp6->preferred_lifetime);
++      iaaddr->valid_lifetime = grub_cpu_to_be32 (dhcp6->valid_lifetime);
++    }
++
++  err = grub_netbuff_push (nb, sizeof (*opt) + 2 * sizeof (grub_uint16_t));
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++
++  opt = (struct grub_net_dhcp6_option*) nb->data;
++  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ORO);
++  opt->len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_uint16_t));
++  grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL));
++  grub_set_unaligned16 (opt->data + 2, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS));
++
++  err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t));
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++  opt = (struct grub_net_dhcp6_option*) nb->data;
++  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME);
++  opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t));
++
++  /* the time is expressed in hundredths of a second */
++  elapsed = grub_divmod64 (grub_get_time_ms () - se->start_time, 10, 0);
++
++  if (elapsed > 0xffff)
++    elapsed = 0xffff;
++
++  grub_set_unaligned16 (opt->data,  grub_cpu_to_be16 ((grub_uint16_t)elapsed));
++
++  err = grub_netbuff_push (nb, sizeof (*v6h));
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++
++  v6h = (struct grub_net_dhcp6_packet *) nb->data;
++  v6h->message_type = GRUB_NET_DHCP6_REQUEST;
++  v6h->transaction_id = se->transaction_id;
++
++  err = grub_netbuff_push (nb, sizeof (*udph));
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++
++  udph = (struct udphdr *) nb->data;
++  udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT);
++  udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT);
++  udph->chksum = 0;
++  udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
++
++  udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP,
++						 &inf->address,
++						 &multicast);
++  err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb,
++				 GRUB_NET_IP_UDP);
++
++  grub_netbuff_free (nb);
++
++  return err;
++}
++
++struct grub_net_network_level_interface *
++grub_net_configure_by_dhcpv6_reply (const char *name,
++	struct grub_net_card *card,
++	grub_net_interface_flags_t flags,
++	const struct grub_net_dhcp6_packet *v6h,
++	grub_size_t size,
++	int is_def,
++	char **device, char **path)
++{
++  struct grub_net_network_level_interface *inf;
++  grub_dhcp6_options_t dhcp6;
++  int mask = -1;
++
++  dhcp6 = grub_dhcp6_options_get (v6h, size);
++  if (!dhcp6)
++    {
++      grub_print_error ();
++      return NULL;
++    }
++
++  grub_net_configure_by_dhcp6_info (name, card, dhcp6, is_def, flags, &inf);
++
++  if (device && dhcp6->boot_file_proto && dhcp6->boot_file_server_ip)
++    {
++      *device = grub_xasprintf ("%s,%s", dhcp6->boot_file_proto, dhcp6->boot_file_server_ip);
++      grub_print_error ();
++    }
++  if (path && dhcp6->boot_file_path)
++    {
++      *path = grub_strdup (dhcp6->boot_file_path);
++      grub_print_error ();
++      if (*path)
++	{
++	  char *slash;
++	  slash = grub_strrchr (*path, '/');
++	  if (slash)
++	    *slash = 0;
++	  else
++	    **path = 0;
++	}
++    }
++
++  grub_dhcp6_options_free (dhcp6);
++
++  if (inf)
++    grub_net_add_ipv6_local (inf, mask);
++
++  return inf;
++}
++
+ /*
+  * This is called directly from net/ip.c:handle_dgram(), because those
+  * BOOTP/DHCP packets are a bit special due to their improper
+@@ -672,6 +1342,77 @@ grub_net_process_dhcp (struct grub_net_buff *nb,
+     }
+ }
+ 
++grub_err_t
++grub_net_process_dhcp6 (struct grub_net_buff *nb,
++                       struct grub_net_card *card __attribute__ ((unused)))
++{
++  const struct grub_net_dhcp6_packet *v6h;
++  grub_dhcp6_session_t se;
++  grub_size_t size;
++  grub_dhcp6_options_t options;
++
++  v6h = (const struct grub_net_dhcp6_packet *) nb->data;
++  size = nb->tail - nb->data;
++
++  options = grub_dhcp6_options_get (v6h, size);
++  if (!options)
++    return grub_errno;
++
++  if (!options->client_duid || !options->server_duid || !options->ia_addr)
++    {
++      grub_dhcp6_options_free (options);
++      return grub_error (GRUB_ERR_BAD_ARGUMENT, "Bad DHCPv6 Packet");
++    }
++
++  FOR_DHCP6_SESSIONS (se)
++    {
++      if (se->transaction_id == v6h->transaction_id &&
++         grub_memcmp (options->client_duid, &se->duid, sizeof (se->duid)) == 0 &&
++         se->iaid == options->iaid)
++       break;
++    }
++
++  if (!se)
++    {
++      grub_dprintf ("bootp", "DHCPv6 session not found\n");
++      grub_dhcp6_options_free (options);
++      return GRUB_ERR_NONE;
++    }
++
++  if (v6h->message_type == GRUB_NET_DHCP6_ADVERTISE)
++    {
++      if (se->adv)
++       {
++         grub_dprintf ("bootp", "Skipped DHCPv6 Advertised .. \n");
++         grub_dhcp6_options_free (options);
++         return GRUB_ERR_NONE;
++       }
++
++      se->adv = options;
++      return grub_dhcp6_session_send_request (se);
++    }
++  else if (v6h->message_type == GRUB_NET_DHCP6_REPLY)
++    {
++      if (!se->adv)
++       {
++         grub_dprintf ("bootp", "Skipped DHCPv6 Reply .. \n");
++         grub_dhcp6_options_free (options);
++         return GRUB_ERR_NONE;
++       }
++
++      se->reply = options;
++      grub_dhcp6_session_configure_network (se);
++      grub_dhcp6_session_remove (se);
++      return GRUB_ERR_NONE;
++    }
++  else
++    {
++      grub_dhcp6_options_free (options);
++    }
++
++  return GRUB_ERR_NONE;
++}
++
+ static grub_err_t
+ grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)),
+ 		  int argc, char **args)
+@@ -897,180 +1638,174 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
+   return err;
+ }
+ 
+-static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp;
+-
+-struct grub_net_network_level_interface *
+-grub_net_configure_by_dhcpv6_ack (const char *name,
+-				  struct grub_net_card *card,
+-				  grub_net_interface_flags_t flags
+-				    __attribute__((__unused__)),
+-				  const grub_net_link_level_address_t *hwaddr,
+-				  const struct grub_net_dhcpv6_packet *packet,
+-				  int is_def, char **device, char **path)
++static grub_err_t
++grub_cmd_bootp6 (struct grub_command *cmd __attribute__ ((unused)),
++                 int argc, char **args)
+ {
+-  struct grub_net_network_level_interface *inter = NULL;
+-  struct grub_net_network_level_address addr;
+-  int mask = -1;
++  struct grub_net_card *card;
++  grub_uint32_t iaid = 0;
++  int interval;
++  grub_err_t err;
++  grub_dhcp6_session_t se;
+ 
+-  if (!device || !path)
+-    return NULL;
++  err = GRUB_ERR_NONE;
+ 
+-  *device = 0;
+-  *path = 0;
++  FOR_NET_CARDS (card)
++  {
++    struct grub_net_network_level_interface *iface;
+ 
+-  grub_dprintf ("net", "mac address is %02x:%02x:%02x:%02x:%02x:%02x\n",
+-		hwaddr->mac[0], hwaddr->mac[1], hwaddr->mac[2],
+-		hwaddr->mac[3], hwaddr->mac[4], hwaddr->mac[5]);
++    if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
++      continue;
+ 
+-  if (is_def)
+-    grub_net_default_server = 0;
++    iface = grub_net_ipv6_get_link_local (card, &card->default_address);
++    if (!iface)
++      {
++       grub_dhcp6_session_remove_all ();
++       return grub_errno;
++      }
+ 
+-  if (is_def && !grub_net_default_server && packet)
++    grub_dhcp6_session_add (iface, iaid++);
++  }
++
++  for (interval = 200; interval < 10000; interval *= 2)
+     {
+-      const grub_uint8_t *options = packet->dhcp_options;
+-      unsigned int option_max = 1024 - OFFSET_OF (dhcp_options, packet);
+-      unsigned int i;
+-
+-      for (i = 0; i < option_max - sizeof (grub_net_dhcpv6_option_t); )
+-	{
+-	  grub_uint16_t num, len;
+-	  grub_net_dhcpv6_option_t *opt =
+-	    (grub_net_dhcpv6_option_t *)(options + i);
+-
+-	  num = grub_be_to_cpu16(opt->option_num);
+-	  len = grub_be_to_cpu16(opt->option_len);
+-
+-	  grub_dprintf ("net", "got dhcpv6 option %d len %d\n", num, len);
+-
+-	  if (len == 0)
+-	    break;
+-
+-	  if (len + i > 1024)
+-	    break;
+-
+-	  if (num == GRUB_NET_DHCP6_BOOTFILE_URL)
+-	    {
+-	      char *scheme, *userinfo, *host, *file;
+-	      char *tmp;
+-	      int hostlen;
+-	      int port;
+-	      int rc = extract_url_info ((const char *)opt->option_data,
+-					 (grub_size_t)len,
+-					 &scheme, &userinfo, &host, &port,
+-					 &file);
+-	      if (rc < 0)
+-		continue;
+-
+-	      /* right now this only handles tftp. */
+-	      if (grub_strcmp("tftp", scheme))
+-		{
+-		  grub_free (scheme);
+-		  grub_free (userinfo);
+-		  grub_free (host);
+-		  grub_free (file);
+-		  continue;
+-		}
+-	      grub_free (userinfo);
+-
+-	      hostlen = grub_strlen (host);
+-	      if (hostlen > 2 && host[0] == '[' && host[hostlen-1] == ']')
+-		{
+-		  tmp = host+1;
+-		  host[hostlen-1] = '\0';
+-		}
+-	      else
+-		tmp = host;
+-
+-	      *device = grub_xasprintf ("%s,%s", scheme, tmp);
+-	      grub_free (scheme);
+-	      grub_free (host);
+-
+-	      if (file && *file)
+-		{
+-		  tmp = grub_strrchr (file, '/');
+-		  if (tmp)
+-		    *(tmp+1) = '\0';
+-		  else
+-		    file[0] = '\0';
+-		}
+-	      else if (!file)
+-		file = grub_strdup ("");
+-
+-	      if (file[0] == '/')
+-		{
+-		  *path = grub_strdup (file+1);
+-		  grub_free (file);
+-		}
+-	      else
+-		*path = file;
+-	    }
+-	  else if (num == GRUB_NET_DHCP6_IA_NA)
+-	    {
+-	      const grub_net_dhcpv6_option_t *ia_na_opt;
+-	      const grub_net_dhcpv6_opt_ia_na_t *ia_na =
+-		(const grub_net_dhcpv6_opt_ia_na_t *)opt;
+-	      unsigned int left = len - OFFSET_OF (options, ia_na);
+-	      unsigned int j;
+-
+-	      if ((grub_uint8_t *)ia_na + left >
+-		  (grub_uint8_t *)options + option_max)
+-		left -= ((grub_uint8_t *)ia_na + left)
+-		        - ((grub_uint8_t *)options + option_max);
+-
+-	      if (len < OFFSET_OF (option_data, opt)
+-			+ sizeof (grub_net_dhcpv6_option_t))
+-		{
+-		  grub_dprintf ("net",
+-				"found dhcpv6 ia_na option with no address\n");
+-		  continue;
+-		}
+-
+-	      for (j = 0; left > sizeof (grub_net_dhcpv6_option_t); )
+-		{
+-		  ia_na_opt = (const grub_net_dhcpv6_option_t *)
+-			       (ia_na->options + j);
+-		  grub_uint16_t ia_na_opt_num, ia_na_opt_len;
+-
+-		  ia_na_opt_num = grub_be_to_cpu16 (ia_na_opt->option_num);
+-		  ia_na_opt_len = grub_be_to_cpu16 (ia_na_opt->option_len);
+-		  if (ia_na_opt_len == 0)
+-		    break;
+-		  if (j + ia_na_opt_len > left)
+-		    break;
+-		  if (ia_na_opt_num == GRUB_NET_DHCP6_IA_ADDRESS)
+-		    {
+-		      const grub_net_dhcpv6_opt_ia_address_t *ia_addr;
+-
+-		      ia_addr = (const grub_net_dhcpv6_opt_ia_address_t *)
+-				 ia_na_opt;
+-		      addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
+-		      grub_memcpy(addr.ipv6, ia_addr->ipv6_address,
+-				  sizeof (ia_addr->ipv6_address));
+-		      inter = grub_net_add_addr (name, card, &addr, hwaddr, 0);
+-		    }
+-
+-		  j += ia_na_opt_len;
+-		  left -= ia_na_opt_len;
+-		}
+-	    }
+-
+-	  i += len + 4;
+-	}
+-
+-      grub_print_error ();
++      int done = 1;
++
++      FOR_DHCP6_SESSIONS (se)
++       {
++         struct grub_net_buff *nb;
++         struct grub_net_dhcp6_option *opt;
++         struct grub_net_dhcp6_packet *v6h;
++         struct grub_net_dhcp6_option_duid_ll *duid;
++         struct grub_net_dhcp6_option_iana *ia_na;
++         grub_net_network_level_address_t multicast;
++         grub_net_link_level_address_t ll_multicast;
++         struct udphdr *udph;
++
++         multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++         multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48);
++         multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL);
++
++         err = grub_net_link_layer_resolve (se->iface,
++                   &multicast, &ll_multicast);
++         if (err)
++           {
++             grub_dhcp6_session_remove_all ();
++             return err;
++           }
++
++         nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
++
++         if (!nb)
++           {
++             grub_dhcp6_session_remove_all ();
++             return grub_errno;
++           }
++
++         err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
++         if (err)
++           {
++             grub_dhcp6_session_remove_all ();
++             grub_netbuff_free (nb);
++             return err;
++           }
++
++         err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t));
++         if (err)
++           {
++             grub_dhcp6_session_remove_all ();
++             grub_netbuff_free (nb);
++             return err;
++           }
++
++         opt = (struct grub_net_dhcp6_option *)nb->data;
++         opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME);
++         opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t));
++         grub_set_unaligned16 (opt->data, 0);
++
++         err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*duid));
++         if (err)
++           {
++             grub_dhcp6_session_remove_all ();
++             grub_netbuff_free (nb);
++             return err;
++           }
++
++         opt = (struct grub_net_dhcp6_option *)nb->data;
++         opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID);
++         opt->len = grub_cpu_to_be16 (sizeof (*duid));
++
++         duid = (struct grub_net_dhcp6_option_duid_ll *) opt->data;
++         grub_memcpy (duid, &se->duid, sizeof (*duid));
++
++         err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*ia_na));
++         if (err)
++           {
++             grub_dhcp6_session_remove_all ();
++             grub_netbuff_free (nb);
++             return err;
++           }
++
++         opt = (struct grub_net_dhcp6_option *)nb->data;
++         opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
++         opt->len = grub_cpu_to_be16 (sizeof (*ia_na));
++         ia_na = (struct grub_net_dhcp6_option_iana *)opt->data;
++         ia_na->iaid = grub_cpu_to_be32 (se->iaid);
++         ia_na->t1 = 0;
++         ia_na->t2 = 0;
++
++         err = grub_netbuff_push (nb, sizeof (*v6h));
++         if (err)
++           {
++             grub_dhcp6_session_remove_all ();
++             grub_netbuff_free (nb);
++             return err;
++           }
++
++         v6h = (struct grub_net_dhcp6_packet *)nb->data;
++         v6h->message_type = GRUB_NET_DHCP6_SOLICIT;
++         v6h->transaction_id = se->transaction_id;
++
++         grub_netbuff_push (nb, sizeof (*udph));
++
++         udph = (struct udphdr *) nb->data;
++         udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT);
++         udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT);
++         udph->chksum = 0;
++         udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
++
++         udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP,
++                           &se->iface->address, &multicast);
++
++         err = grub_net_send_ip_packet (se->iface, &multicast,
++                   &ll_multicast, nb, GRUB_NET_IP_UDP);
++         done = 0;
++         grub_netbuff_free (nb);
++
++         if (err)
++           {
++             grub_dhcp6_session_remove_all ();
++             return err;
++           }
++       }
++      if (!done)
++       grub_net_poll_cards (interval, 0);
+     }
+ 
+-  if (is_def)
++  FOR_DHCP6_SESSIONS (se)
+     {
+-      grub_env_set ("net_default_interface", name);
+-      grub_env_export ("net_default_interface");
++      grub_error_push ();
++      err = grub_error (GRUB_ERR_FILE_NOT_FOUND,
++                       N_("couldn't autoconfigure %s"),
++                       se->iface->card->name);
+     }
+ 
+-    if (inter)
+-      grub_net_add_ipv6_local (inter, mask);
+-    return inter;
++  grub_dhcp6_session_remove_all ();
++
++  return err;
+ }
+ 
++static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp, cmd_bootp6;
+ 
+ void
+ grub_bootp_init (void)
+@@ -1084,11 +1819,15 @@ grub_bootp_init (void)
+   cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt,
+ 				       N_("VAR INTERFACE NUMBER DESCRIPTION"),
+ 				       N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value."));
++  cmd_bootp6 = grub_register_command ("net_bootp6", grub_cmd_bootp6,
++				     N_("[CARD]"),
++				     N_("perform a DHCPv6 autoconfiguration"));
+ }
+ 
+ void
+ grub_bootp_fini (void)
+ {
++  grub_unregister_command (cmd_bootp6);
+   grub_unregister_command (cmd_getdhcp);
+   grub_unregister_command (cmd_bootp);
+   grub_unregister_command (cmd_dhcp);
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index a673bea807..8e25680db0 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -393,9 +393,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+     pxe_mode = pxe->mode;
+     if (pxe_mode->using_ipv6)
+       {
+-	grub_net_link_level_address_t hwaddr;
+-	struct grub_net_network_level_interface *intf;
+-
+ 	grub_dprintf ("efinet", "using ipv6 and dhcpv6\n");
+ 	grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n",
+ 		      pxe_mode->dhcp_ack_received ? "yes" : "no",
+@@ -403,15 +400,14 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 	if (!pxe_mode->dhcp_ack_received)
+ 	  continue;
+ 
+-	hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-	grub_memcpy (hwaddr.mac,
+-		     card->efi_net->mode->current_address,
+-		     sizeof (hwaddr.mac));
+-
+-	intf = grub_net_configure_by_dhcpv6_ack (card->name, card, 0, &hwaddr,
+-	      (const struct grub_net_dhcpv6_packet *)&pxe_mode->dhcp_ack.dhcpv6,
+-	      1, device, path);
+-	if (intf && device && path)
++	grub_net_configure_by_dhcpv6_reply (card->name, card, 0,
++					    (struct grub_net_dhcp6_packet *)
++					    &pxe_mode->dhcp_ack,
++					    sizeof (pxe_mode->dhcp_ack),
++					    1, device, path);
++	if (grub_errno)
++	  grub_print_error ();
++	if (device && path)
+ 	  grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
+       }
+     else
+diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
+index a5896f6dc2..ce6bdc75c6 100644
+--- a/grub-core/net/ip.c
++++ b/grub-core/net/ip.c
+@@ -239,6 +239,45 @@ handle_dgram (struct grub_net_buff *nb,
+   {
+     struct udphdr *udph;
+     udph = (struct udphdr *) nb->data;
++
++    if (proto == GRUB_NET_IP_UDP && udph->dst == grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT))
++      {
++	if (udph->chksum)
++	  {
++	    grub_uint16_t chk, expected;
++	    chk = udph->chksum;
++	    udph->chksum = 0;
++	    expected = grub_net_ip_transport_checksum (nb,
++						       GRUB_NET_IP_UDP,
++						       source,
++						       dest);
++	    if (expected != chk)
++	      {
++		grub_dprintf ("net", "Invalid UDP checksum. "
++			      "Expected %x, got %x\n",
++			      grub_be_to_cpu16 (expected),
++			      grub_be_to_cpu16 (chk));
++		grub_netbuff_free (nb);
++		return GRUB_ERR_NONE;
++	      }
++	    udph->chksum = chk;
++	  }
++
++	err = grub_netbuff_pull (nb, sizeof (*udph));
++	if (err)
++	  {
++	    grub_netbuff_free (nb);
++	    return err;
++	  }
++
++	err = grub_net_process_dhcp6 (nb, card);
++	if (err)
++	  grub_print_error ();
++
++	grub_netbuff_free (nb);
++	return GRUB_ERR_NONE;
++      }
++
+     if (proto == GRUB_NET_IP_UDP && grub_be_to_cpu16 (udph->dst) == 68)
+       {
+ 	const struct grub_net_bootp_packet *bootp;
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index 9962880147..7614b58dca 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -1532,7 +1532,7 @@ typedef struct grub_efi_pxe_ip_filter
+ {
+   grub_efi_uint8_t filters;
+   grub_efi_uint8_t ip_count;
+-  grub_efi_uint8_t reserved;
++  grub_efi_uint16_t reserved;
+   grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT];
+ } grub_efi_pxe_ip_filter_t;
+ 
+diff --git a/include/grub/net.h b/include/grub/net.h
+index d55d505a03..543251f727 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -451,50 +451,65 @@ struct grub_net_bootp_packet
+   grub_uint8_t vendor[0];
+ } GRUB_PACKED;
+ 
+-enum
+-  {
+-    GRUB_NET_DHCP6_IA_NA = 3,
+-    GRUB_NET_DHCP6_IA_ADDRESS = 5,
+-    GRUB_NET_DHCP6_BOOTFILE_URL = 59,
+-  };
+-
+-struct grub_net_dhcpv6_option
++struct grub_net_dhcp6_packet
+ {
+-  grub_uint16_t option_num;
+-  grub_uint16_t option_len;
+-  grub_uint8_t option_data[];
++  grub_uint32_t message_type:8;
++  grub_uint32_t transaction_id:24;
++  grub_uint8_t dhcp_options[0];
+ } GRUB_PACKED;
+-typedef struct grub_net_dhcpv6_option grub_net_dhcpv6_option_t;
+ 
+-struct grub_net_dhcpv6_opt_ia_na
+-{
+-  grub_uint16_t option_num;
+-  grub_uint16_t option_len;
++struct grub_net_dhcp6_option {
++  grub_uint16_t code;
++  grub_uint16_t len;
++  grub_uint8_t data[0];
++} GRUB_PACKED;
++
++struct grub_net_dhcp6_option_iana {
+   grub_uint32_t iaid;
+   grub_uint32_t t1;
+   grub_uint32_t t2;
+-  grub_uint8_t options[];
++  grub_uint8_t data[0];
+ } GRUB_PACKED;
+-typedef struct grub_net_dhcpv6_opt_ia_na grub_net_dhcpv6_opt_ia_na_t;
+ 
+-struct grub_net_dhcpv6_opt_ia_address
+-{
+-  grub_uint16_t option_num;
+-  grub_uint16_t option_len;
+-  grub_uint64_t ipv6_address[2];
++struct grub_net_dhcp6_option_iaaddr {
++  grub_uint8_t addr[16];
+   grub_uint32_t preferred_lifetime;
+   grub_uint32_t valid_lifetime;
+-  grub_uint8_t options[];
++  grub_uint8_t data[0];
+ } GRUB_PACKED;
+-typedef struct grub_net_dhcpv6_opt_ia_address grub_net_dhcpv6_opt_ia_address_t;
+ 
+-struct grub_net_dhcpv6_packet
++struct grub_net_dhcp6_option_duid_ll
+ {
+-  grub_uint32_t message_type:8;
+-  grub_uint32_t transaction_id:24;
+-  grub_uint8_t dhcp_options[1024];
++  grub_uint16_t type;
++  grub_uint16_t hw_type;
++  grub_uint8_t hwaddr[6];
+ } GRUB_PACKED;
+-typedef struct grub_net_dhcpv6_packet grub_net_dhcpv6_packet_t;
++
++enum
++  {
++    GRUB_NET_DHCP6_SOLICIT = 1,
++    GRUB_NET_DHCP6_ADVERTISE = 2,
++    GRUB_NET_DHCP6_REQUEST = 3,
++    GRUB_NET_DHCP6_REPLY = 7
++  };
++
++enum
++  {
++    DHCP6_CLIENT_PORT = 546,
++    DHCP6_SERVER_PORT = 547
++  };
++
++enum
++  {
++    GRUB_NET_DHCP6_OPTION_CLIENTID = 1,
++    GRUB_NET_DHCP6_OPTION_SERVERID = 2,
++    GRUB_NET_DHCP6_OPTION_IA_NA = 3,
++    GRUB_NET_DHCP6_OPTION_IAADDR = 5,
++    GRUB_NET_DHCP6_OPTION_ORO = 6,
++    GRUB_NET_DHCP6_OPTION_ELAPSED_TIME = 8,
++    GRUB_NET_DHCP6_OPTION_DNS_SERVERS = 23,
++    GRUB_NET_DHCP6_OPTION_BOOTFILE_URL = 59
++  };
+ 
+ #define	GRUB_NET_BOOTP_RFC1048_MAGIC_0	0x63
+ #define	GRUB_NET_BOOTP_RFC1048_MAGIC_1	0x82
+@@ -532,12 +547,12 @@ grub_net_configure_by_dhcp_ack (const char *name,
+ 				int is_def, char **device, char **path);
+ 
+ struct grub_net_network_level_interface *
+-grub_net_configure_by_dhcpv6_ack (const char *name,
+-				 struct grub_net_card *card,
+-				 grub_net_interface_flags_t flags,
+-				 const grub_net_link_level_address_t *hwaddr,
+-				 const struct grub_net_dhcpv6_packet *packet,
+-				 int is_def, char **device, char **path);
++grub_net_configure_by_dhcpv6_reply (const char *name,
++				    struct grub_net_card *card,
++				    grub_net_interface_flags_t flags,
++				    const struct grub_net_dhcp6_packet *v6,
++				    grub_size_t size,
++				    int is_def, char **device, char **path);
+ 
+ int
+ grub_ipv6_get_masksize(grub_uint16_t *mask);
+@@ -554,6 +569,10 @@ void
+ grub_net_process_dhcp (struct grub_net_buff *nb,
+ 		       struct grub_net_network_level_interface *iface);
+ 
++grub_err_t
++grub_net_process_dhcp6 (struct grub_net_buff *nb,
++			struct grub_net_card *card);
++
+ int
+ grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a,
+ 		     const grub_net_link_level_address_t *b);
diff --git a/SOURCES/0073-align-struct-efi_variable-better.patch b/SOURCES/0073-align-struct-efi_variable-better.patch
deleted file mode 100644
index ec26def..0000000
--- a/SOURCES/0073-align-struct-efi_variable-better.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 27 Feb 2018 13:55:35 -0500
-Subject: [PATCH] align struct efi_variable better...
-
----
- include/grub/efiemu/runtime.h | 2 +-
- include/grub/types.h          | 1 +
- 2 files changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/include/grub/efiemu/runtime.h b/include/grub/efiemu/runtime.h
-index 36d2dedf47e..9d93ba88bac 100644
---- a/include/grub/efiemu/runtime.h
-+++ b/include/grub/efiemu/runtime.h
-@@ -33,5 +33,5 @@ struct efi_variable
-   grub_uint32_t namelen;
-   grub_uint32_t size;
-   grub_efi_uint32_t attributes;
--} GRUB_PACKED;
-+} GRUB_PACKED GRUB_ALIGNED(8);
- #endif /* ! GRUB_EFI_EMU_RUNTIME_HEADER */
-diff --git a/include/grub/types.h b/include/grub/types.h
-index 0a3ff159136..ba446d99040 100644
---- a/include/grub/types.h
-+++ b/include/grub/types.h
-@@ -29,6 +29,7 @@
- #else
- #define GRUB_PACKED __attribute__ ((packed))
- #endif
-+#define GRUB_ALIGNED(x) __attribute__((aligned (x)))
- 
- #ifdef GRUB_BUILD
- # define GRUB_CPU_SIZEOF_VOID_P	BUILD_SIZEOF_VOID_P
diff --git a/SOURCES/0073-efinet-UEFI-IPv6-PXE-support.patch b/SOURCES/0073-efinet-UEFI-IPv6-PXE-support.patch
new file mode 100644
index 0000000..988c178
--- /dev/null
+++ b/SOURCES/0073-efinet-UEFI-IPv6-PXE-support.patch
@@ -0,0 +1,126 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Wed, 15 Apr 2015 14:48:30 +0800
+Subject: [PATCH] efinet: UEFI IPv6 PXE support
+
+When grub2 image is booted from UEFI IPv6 PXE, the DHCPv6 Reply packet is
+cached in firmware buffer which can be obtained by PXE Base Code protocol. The
+network interface can be setup through the parameters in that obtained packet.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+---
+ grub-core/net/drivers/efi/efinet.c |  2 ++
+ include/grub/efi/api.h             | 71 +++++++++++++++++++++++---------------
+ 2 files changed, 46 insertions(+), 27 deletions(-)
+
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index 8e25680db0..014e5bf980 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -409,6 +409,8 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 	  grub_print_error ();
+ 	if (device && path)
+ 	  grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
++	if (grub_errno)
++	  grub_print_error ();
+       }
+     else
+       {
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index 7614b58dca..91ab528e4d 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -1524,31 +1524,6 @@ typedef union
+   grub_efi_pxe_dhcpv6_packet_t dhcpv6;
+ } grub_efi_pxe_packet_t;
+ 
+-#define GRUB_EFI_PXE_MAX_IPCNT 8
+-#define GRUB_EFI_PXE_MAX_ARP_ENTRIES 8
+-#define GRUB_EFI_PXE_MAX_ROUTE_ENTRIES 8
+-
+-typedef struct grub_efi_pxe_ip_filter
+-{
+-  grub_efi_uint8_t filters;
+-  grub_efi_uint8_t ip_count;
+-  grub_efi_uint16_t reserved;
+-  grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT];
+-} grub_efi_pxe_ip_filter_t;
+-
+-typedef struct grub_efi_pxe_arp_entry
+-{
+-  grub_efi_ip_address_t ip_addr;
+-  grub_efi_mac_address_t mac_addr;
+-} grub_efi_pxe_arp_entry_t;
+-
+-typedef struct grub_efi_pxe_route_entry
+-{
+-  grub_efi_ip_address_t ip_addr;
+-  grub_efi_ip_address_t subnet_mask;
+-  grub_efi_ip_address_t gateway_addr;
+-} grub_efi_pxe_route_entry_t;
+-
+ typedef struct grub_efi_pxe_icmp_error
+ {
+   grub_efi_uint8_t type;
+@@ -1574,6 +1549,48 @@ typedef struct grub_efi_pxe_tftp_error
+   grub_efi_char8_t error_string[127];
+ } grub_efi_pxe_tftp_error_t;
+ 
++typedef struct {
++  grub_uint8_t addr[4];
++} grub_efi_pxe_ipv4_address_t;
++
++typedef struct {
++  grub_uint8_t addr[16];
++} grub_efi_pxe_ipv6_address_t;
++
++typedef struct {
++  grub_uint8_t addr[32];
++} grub_efi_pxe_mac_address_t;
++
++typedef union {
++  grub_uint32_t addr[4];
++  grub_efi_pxe_ipv4_address_t v4;
++  grub_efi_pxe_ipv6_address_t v6;
++} grub_efi_pxe_ip_address_t;
++
++#define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8
++typedef struct grub_efi_pxe_ip_filter
++{
++  grub_efi_uint8_t filters;
++  grub_efi_uint8_t ip_count;
++  grub_efi_uint16_t reserved;
++  grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT];
++} grub_efi_pxe_ip_filter_t;
++
++typedef struct {
++  grub_efi_pxe_ip_address_t ip_addr;
++  grub_efi_pxe_mac_address_t mac_addr;
++} grub_efi_pxe_arp_entry_t;
++
++typedef struct {
++  grub_efi_pxe_ip_address_t ip_addr;
++  grub_efi_pxe_ip_address_t subnet_mask;
++  grub_efi_pxe_ip_address_t gw_addr;
++} grub_efi_pxe_route_entry_t;
++
++
++#define GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8
++#define GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8
++
+ typedef struct grub_efi_pxe_mode
+ {
+   grub_efi_boolean_t started;
+@@ -1605,9 +1622,9 @@ typedef struct grub_efi_pxe_mode
+   grub_efi_pxe_packet_t pxe_bis_reply;
+   grub_efi_pxe_ip_filter_t ip_filter;
+   grub_efi_uint32_t arp_cache_entries;
+-  grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_MAX_ARP_ENTRIES];
++  grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES];
+   grub_efi_uint32_t route_table_entries;
+-  grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_MAX_ROUTE_ENTRIES];
++  grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES];
+   grub_efi_pxe_icmp_error_t icmp_error;
+   grub_efi_pxe_tftp_error_t tftp_error;
+ } grub_efi_pxe_mode_t;
diff --git a/SOURCES/0074-Add-BLS-support-to-grub-mkconfig.patch b/SOURCES/0074-Add-BLS-support-to-grub-mkconfig.patch
deleted file mode 100644
index 6c65440..0000000
--- a/SOURCES/0074-Add-BLS-support-to-grub-mkconfig.patch
+++ /dev/null
@@ -1,397 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Fri, 9 Dec 2016 15:40:29 -0500
-Subject: [PATCH] Add BLS support to grub-mkconfig
-
-GRUB now has BootLoaderSpec support, the user can choose to use this by
-setting GRUB_ENABLE_BLSCFG to true in /etc/default/grub. On this setup,
-the boot menu entries are not added to the grub.cfg, instead BLS config
-files are parsed by blscfg command and the entries created dynamically.
-
-A 10_linux_bls grub.d snippet to generate menu entries from BLS files
-is also added that can be used on platforms where the bootloader doesn't
-have BLS support and only can parse a normal grub configuration file.
-
-Portions of the 10_linux_bls were taken from the ostree-grub-generator
-script that's included in the OSTree project.
-
-Fixes to support multi-devices and generate a BLS section even if no
-kernels are found in the boot directory were proposed by Yclept Nemo
-and Tom Gundersen respectively.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- util/grub-mkconfig.8      |   4 +
- util/grub-mkconfig.in     |   9 +-
- util/grub-mkconfig_lib.in |  22 ++++-
- util/grub.d/10_linux.in   | 223 +++++++++++++++++++++++++++++++++++++++++++++-
- 4 files changed, 252 insertions(+), 6 deletions(-)
-
-diff --git a/util/grub-mkconfig.8 b/util/grub-mkconfig.8
-index a2d1f577b9b..434fa4deda4 100644
---- a/util/grub-mkconfig.8
-+++ b/util/grub-mkconfig.8
-@@ -13,5 +13,9 @@
- \fB--output\fR=\fIFILE\fR
- Write generated output to \fIFILE\fR.
- 
-+.TP
-+\fB--no-grubenv-update\fR
-+Do not update variables in the grubenv file.
-+
- .SH SEE ALSO
- .BR "info grub"
-diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
-index 535c0f02499..f55339a3f64 100644
---- a/util/grub-mkconfig.in
-+++ b/util/grub-mkconfig.in
-@@ -50,6 +50,8 @@ grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@"
- export TEXTDOMAIN=@PACKAGE@
- export TEXTDOMAINDIR="@localedir@"
- 
-+export GRUB_GRUBENV_UPDATE="yes"
-+
- . "${pkgdatadir}/grub-mkconfig_lib"
- 
- # Usage: usage
-@@ -59,6 +61,7 @@ usage () {
-     gettext "Generate a grub config file"; echo
-     echo
-     print_option_help "-o, --output=$(gettext FILE)" "$(gettext "output generated config to FILE [default=stdout]")"
-+    print_option_help "--no-grubenv-update" "$(gettext "do not update variables in the grubenv file")"
-     print_option_help "-h, --help" "$(gettext "print this message and exit")"
-     print_option_help "-V, --version" "$(gettext "print the version information and exit")"
-     echo
-@@ -94,6 +97,9 @@ do
-     --output=*)
- 	grub_cfg=`echo "$option" | sed 's/--output=//'`
- 	;;
-+    --no-grubenv-update)
-+	GRUB_GRUBENV_UPDATE="no"
-+	;;
-     -*)
- 	gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2
- 	usage
-@@ -253,7 +259,8 @@ export GRUB_DEFAULT \
-   GRUB_OS_PROBER_SKIP_LIST \
-   GRUB_DISABLE_SUBMENU \
-   GRUB_DEFAULT_DTB \
--  SUSE_BTRFS_SNAPSHOT_BOOTING
-+  SUSE_BTRFS_SNAPSHOT_BOOTING \
-+  GRUB_ENABLE_BLSCFG
- 
- if test "x${grub_cfg}" != "x"; then
-   rm -f "${grub_cfg}.new"
-diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
-index fafeac95061..d8bb4069360 100644
---- a/util/grub-mkconfig_lib.in
-+++ b/util/grub-mkconfig_lib.in
-@@ -30,6 +30,9 @@ fi
- if test "x$grub_file" = x; then
-   grub_file="${bindir}/@grub_file@"
- fi
-+if test "x$grub_editenv" = x; then
-+  grub_editenv="${bindir}/@grub_editenv@"
-+fi
- if test "x$grub_mkrelpath" = x; then
-   grub_mkrelpath="${bindir}/@grub_mkrelpath@"
- fi
-@@ -125,8 +128,19 @@ EOF
-   fi
- }
- 
-+prepare_grub_to_access_device_with_variable ()
-+{
-+  device_variable="$1"
-+  shift
-+  prepare_grub_to_access_device "$@"
-+  unset "device_variable"
-+}
-+
- prepare_grub_to_access_device ()
- {
-+  if [ -z "$device_variable" ]; then
-+    device_variable="root"
-+  fi
-   old_ifs="$IFS"
-   IFS='
- '
-@@ -161,18 +175,18 @@ prepare_grub_to_access_device ()
-   # otherwise set root as per value in device.map.
-   fs_hint="`"${grub_probe}" --device $@ --target=compatibility_hint`"
-   if [ "x$fs_hint" != x ]; then
--    echo "set root='$fs_hint'"
-+    echo "set ${device_variable}='$fs_hint'"
-   fi
-   if [ "x${GRUB_DISABLE_UUID}" != "xtrue" ] && fs_uuid="`"${grub_probe}" --device $@ --target=fs_uuid 2> /dev/null`" ; then
-     hints="`"${grub_probe}" --device $@ --target=hints_string 2> /dev/null`" || hints=
-     if [ "x$hints" != x ]; then
-       echo "if [ x\$feature_platform_search_hint = xy ]; then"
--      echo "  search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}"
-+      echo "  search --no-floppy --fs-uuid --set=${device_variable} ${hints} ${fs_uuid}"
-       echo "else"
--      echo "  search --no-floppy --fs-uuid --set=root ${fs_uuid}"
-+      echo "  search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}"
-       echo "fi"
-     else
--      echo "search --no-floppy --fs-uuid --set=root ${fs_uuid}"
-+      echo "search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}"
-     fi
-   fi
-   IFS="$old_ifs"
-diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
-index cbfaca34cc7..68adb55d893 100644
---- a/util/grub.d/10_linux.in
-+++ b/util/grub.d/10_linux.in
-@@ -82,6 +82,223 @@ case x"$GRUB_FS" in
- 	;;
- esac
- 
-+populate_header_warn()
-+{
-+if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then
-+  bls_parser="10_linux script"
-+else
-+  bls_parser="blscfg command"
-+fi
-+cat <<EOF
-+
-+# This section was generated by a script. Do not modify the generated file - all changes
-+# will be lost the next time file is regenerated. Instead edit the BootLoaderSpec files.
-+#
-+# The $bls_parser parses the BootLoaderSpec files stored in /boot/loader/entries and
-+# populates the boot menu. Please refer to the Boot Loader Specification documentation
-+# for the files format: https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/.
-+
-+EOF
-+}
-+
-+read_config()
-+{
-+    config_file=${1}
-+    title=""
-+    initrd=""
-+    options=""
-+    linux=""
-+    grub_arg=""
-+
-+    while read -r line
-+    do
-+        record=$(echo ${line} | cut -f 1 -d ' ')
-+        value=$(echo ${line} | cut -s -f2- -d ' ')
-+        case "${record}" in
-+            "title")
-+                title=${value}
-+                ;;
-+            "initrd")
-+                initrd=${value}
-+                ;;
-+            "linux")
-+                linux=${value}
-+                ;;
-+            "options")
-+                options=${value}
-+                ;;
-+            "grub_arg")
-+                grub_arg=${value}
-+                ;;
-+        esac
-+    done < ${config_file}
-+}
-+
-+blsdir="/boot/loader/entries"
-+
-+get_sorted_bls()
-+{
-+    if ! [ -d "${blsdir}" ] || ! [ -e /etc/machine-id ]; then
-+        return
-+    fi
-+
-+    read machine_id < /etc/machine-id
-+    if [ -z "${machine_id}" ]; then
-+        return
-+    fi
-+
-+    local IFS=$'\n'
-+
-+    files=($(for bls in ${blsdir}/${machine_id}-*.conf; do
-+        if ! [[ -e "${bls}" ]] ; then
-+            continue
-+        fi
-+        bls="${bls%.conf}"
-+        bls="${bls##*/}"
-+        echo "${bls}"
-+    done | ${kernel_sort} 2>/dev/null | tac)) || :
-+
-+    echo "${files[@]}"
-+}
-+
-+update_bls_cmdline()
-+{
-+    local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
-+    local -a files=($(get_sorted_bls))
-+
-+    for bls in "${files[@]}"; do
-+        local options="${cmdline}"
-+        if [ -z "${bls##*debug*}" ]; then
-+            options="${options} ${GRUB_CMDLINE_LINUX_DEBUG}"
-+        fi
-+        options="$(echo "${options}" | sed -e 's/\//\\\//g')"
-+        sed -i -e "s/^options.*/options ${options}/" "${blsdir}/${bls}.conf"
-+    done
-+}
-+
-+populate_menu()
-+{
-+    local -a files=($(get_sorted_bls))
-+
-+    gettext_printf "Generating boot entries from BLS files...\n" >&2
-+
-+    for bls in "${files[@]}"; do
-+        read_config "${blsdir}/${bls}.conf"
-+
-+        menu="${menu}menuentry '${title}' ${grub_arg} --id=${bls} {\n"
-+        menu="${menu}\t linux ${linux} ${options}\n"
-+        if [ -n "${initrd}" ] ; then
-+            menu="${menu}\t initrd ${boot_prefix}${initrd}\n"
-+        fi
-+        menu="${menu}}\n\n"
-+    done
-+    # The printf command seems to be more reliable across shells for special character (\n, \t) evaluation
-+    printf "$menu"
-+}
-+
-+# Make BLS the default if GRUB_ENABLE_BLSCFG was not set and grubby is not installed.
-+if [ -z "${GRUB_ENABLE_BLSCFG}" ] && [ -z "$(which new-kernel-pkg 2> /dev/null)" ]; then
-+	  GRUB_ENABLE_BLSCFG="true"
-+fi
-+
-+if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]; then
-+  if [ x$dirname = x/ ]; then
-+    if [ -z "${prepare_root_cache}" ]; then
-+      prepare_grub_to_access_device ${GRUB_DEVICE}
-+    fi
-+  else
-+    if [ -z "${prepare_boot_cache}" ]; then
-+      prepare_grub_to_access_device ${GRUB_DEVICE_BOOT}
-+    fi
-+  fi
-+
-+  if [ -d /sys/firmware/efi ]; then
-+      bootefi_device="`${grub_probe} --target=device /boot/efi/`"
-+      prepare_grub_to_access_device_with_variable boot ${bootefi_device}
-+  else
-+      boot_device="`${grub_probe} --target=device /boot/`"
-+      prepare_grub_to_access_device_with_variable boot ${boot_device}
-+  fi
-+
-+  arch="$(uname -m)"
-+  if [ "x${arch}" = "xppc64le" ] && [ -d /sys/firmware/opal ]; then
-+
-+      BLS_POPULATE_MENU="true"
-+      petitboot_path="/sys/firmware/devicetree/base/ibm,firmware-versions/petitboot"
-+
-+      if test -e ${petitboot_path}; then
-+          read -r -d '' petitboot_version < ${petitboot_path}
-+          petitboot_version="$(echo ${petitboot_version//v})"
-+
-+	  if test -n ${petitboot_version}; then
-+              major_version="$(echo ${petitboot_version} | cut -d . -f1)"
-+              minor_version="$(echo ${petitboot_version} | cut -d . -f2)"
-+
-+              re='^[0-9]+$'
-+              if [[ $major_version =~ $re ]] && [[ $minor_version =~ $re ]] &&
-+                 ([[ ${major_version} -gt 1 ]] ||
-+                  [[ ${major_version} -eq 1 &&
-+                     ${minor_version} -ge 8  ]]); then
-+                  BLS_POPULATE_MENU="false"
-+              fi
-+          fi
-+      fi
-+  fi
-+
-+  populate_header_warn
-+
-+  cat << EOF
-+# The kernelopts variable should be defined in the grubenv file. But to ensure that menu
-+# entries populated from BootLoaderSpec files that use this variable work correctly even
-+# without a grubenv file, define a fallback kernelopts variable if this has not been set.
-+#
-+# The kernelopts variable in the grubenv file can be modified using the grubby tool or by
-+# executing the grub2-mkconfig tool. For the latter, the values of the GRUB_CMDLINE_LINUX
-+# and GRUB_CMDLINE_LINUX_DEFAULT options from /etc/default/grub file are used to set both
-+# the kernelopts variable in the grubenv file and the fallback kernelopts variable.
-+if [ -z "\${kernelopts}" ]; then
-+  set kernelopts="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
-+fi
-+EOF
-+
-+  update_bls_cmdline
-+
-+  if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then
-+      populate_menu
-+  else
-+      cat << EOF
-+
-+insmod blscfg
-+blscfg
-+EOF
-+  fi
-+
-+  if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then
-+      blsdir="/boot/loader/entries"
-+      [ -d "${blsdir}" ] && GRUB_BLS_FS="$(${grub_probe} --target=fs ${blsdir})"
-+      if [ "x${GRUB_BLS_FS}" = "xbtrfs" ] || [ "x${GRUB_BLS_FS}" = "xzfs" ]; then
-+          blsdir=$(make_system_path_relative_to_its_root "${blsdir}")
-+          if [ "x${blsdir}" != "x/loader/entries" ] && [ "x${blsdir}" != "x/boot/loader/entries" ]; then
-+              ${grub_editenv} - set blsdir="${blsdir}"
-+          fi
-+      fi
-+
-+      if [ -n "${GRUB_EARLY_INITRD_LINUX_CUSTOM}" ]; then
-+          ${grub_editenv} - set early_initrd="${GRUB_EARLY_INITRD_LINUX_CUSTOM}"
-+      fi
-+
-+      if [ -n "${GRUB_DEFAULT_DTB}" ]; then
-+          ${grub_editenv} - set devicetree="${GRUB_DEFAULT_DTB}"
-+      fi
-+
-+      if [ -n "${GRUB_SAVEDEFAULT}" ]; then
-+           ${grub_editenv} - set save_default="${GRUB_SAVEDEFAULT}"
-+      fi
-+  fi
-+
-+  exit 0
-+fi
-+
- mktitle ()
- {
-   local title_type
-@@ -121,6 +338,7 @@ linux_entry ()
-   if [ -z "$boot_device_id" ]; then
-       boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
-   fi
-+
-   if [ x$type != xsimple ] ; then
-       title=$(mktitle "$type" "$version")
-       if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then
-@@ -224,6 +442,7 @@ is_top_level=true
- while [ "x$list" != "x" ] ; do
-   linux=`version_find_latest $list`
-   gettext_printf "Found linux image: %s\n" "$linux" >&2
-+
-   basename=`basename $linux`
-   dirname=`dirname $linux`
-   rel_dirname=`make_system_path_relative_to_its_root $dirname`
-@@ -262,7 +481,9 @@ while [ "x$list" != "x" ] ; do
-     for i in ${initrd}; do
-       initrd_display="${initrd_display} ${dirname}/${i}"
-     done
--    gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2
-+    if [ "x${GRUB_ENABLE_BLSCFG}" != "xtrue" ]; then
-+      gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2
-+    fi
-   fi
- 
-   fdt=
diff --git a/SOURCES/0074-grub.texi-Add-net_bootp6-doument.patch b/SOURCES/0074-grub.texi-Add-net_bootp6-doument.patch
new file mode 100644
index 0000000..b42e09b
--- /dev/null
+++ b/SOURCES/0074-grub.texi-Add-net_bootp6-doument.patch
@@ -0,0 +1,48 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Tue, 5 May 2015 14:19:24 +0800
+Subject: [PATCH] grub.texi: Add net_bootp6 doument
+
+Update grub documentation for net_bootp6 command.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+---
+ docs/grub.texi | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/docs/grub.texi b/docs/grub.texi
+index 0615d0ed97..04ed6ac1f0 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -5487,6 +5487,7 @@ This command is only available on AArch64 systems.
+ * net_add_dns::                 Add a DNS server
+ * net_add_route::               Add routing entry
+ * net_bootp::                   Perform a bootp/DHCP autoconfiguration
++* net_bootp6::                  Perform a DHCPv6 autoconfiguration
+ * net_del_addr::                Remove IP address from interface
+ * net_del_dns::                 Remove a DNS server
+ * net_del_route::               Remove a route entry
+@@ -5611,6 +5612,22 @@ Sets environment variable @samp{net_}@var{<card>}@samp{_boot_file}
+ 
+ @end deffn
+ 
++@node net_bootp6
++@subsection net_bootp6
++
++@deffn Command net_bootp6 [@var{card}]
++Perform configuration of @var{card} using DHCPv6 protocol. If no card name is
++specified, try to configure all existing cards. If configuration was
++successful, interface with name @var{card}@samp{:dhcp6} and configured address
++is added to @var{card}.
++
++@table @samp
++@item 1 (Domain Name Server)
++Adds all servers from option value to the list of servers used during name
++resolution.
++@end table
++
++@end deffn
+ 
+ @node net_get_dhcp_option
+ @subsection net_get_dhcp_option
diff --git a/SOURCES/0075-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch b/SOURCES/0075-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch
deleted file mode 100644
index 9ff4c8b..0000000
--- a/SOURCES/0075-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Tue, 6 Feb 2018 11:16:28 +0100
-Subject: [PATCH] Don't attempt to backtrace on grub_abort() for grub-emu
-
-The emu platform doesn't have a grub_backtrace() implementation, so this
-causes a build error. Don't attempt to call this when building grub-emu.
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/kern/misc.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
-index a3e215155bd..c60601b699d 100644
---- a/grub-core/kern/misc.c
-+++ b/grub-core/kern/misc.c
-@@ -1201,7 +1201,7 @@ static void __attribute__ ((noreturn))
- grub_abort (void)
- {
- #ifndef GRUB_UTIL
--#if defined(__i386__) || defined(__x86_64__)
-+#if (defined(__i386__) || defined(__x86_64__)) && !defined(GRUB_MACHINE_EMU)
-   grub_backtrace();
- #endif
- #endif
diff --git a/SOURCES/0075-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch b/SOURCES/0075-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch
new file mode 100644
index 0000000..abff9eb
--- /dev/null
+++ b/SOURCES/0075-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch
@@ -0,0 +1,108 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Wed, 10 Jul 2019 23:58:28 +0200
+Subject: [PATCH] bootp: Add processing DHCPACK packet from HTTP Boot
+
+The vendor class identifier with the string "HTTPClient" is used to denote the
+packet as responding to HTTP boot request. In DHCP4 config, the filename for
+HTTP boot is the URL of the boot file while for PXE boot it is the path to the
+boot file. As a consequence, the next-server becomes obseleted because the HTTP
+URL already contains the server address for the boot file. For DHCP6 config,
+there's no difference definition in existing config as dhcp6.bootfile-url can
+be used to specify URL for both HTTP and PXE boot file.
+
+This patch adds processing for "HTTPClient" vendor class identifier in DHCPACK
+packet by treating it as HTTP format, not as the PXE format.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+---
+ grub-core/net/bootp.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ include/grub/net.h    |  1 +
+ 2 files changed, 56 insertions(+)
+
+diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
+index fe93b80f1c..8fb8918ae7 100644
+--- a/grub-core/net/bootp.c
++++ b/grub-core/net/bootp.c
+@@ -20,6 +20,7 @@
+ #include <grub/env.h>
+ #include <grub/i18n.h>
+ #include <grub/command.h>
++#include <grub/net.h>
+ #include <grub/net/ip.h>
+ #include <grub/net/netbuff.h>
+ #include <grub/net/udp.h>
+@@ -500,6 +501,60 @@ grub_net_configure_by_dhcp_ack (const char *name,
+   if (opt && opt_len)
+     grub_env_set_net_property (name, "rootpath", (const char *) opt, opt_len);
+ 
++  opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER, &opt_len);
++  if (opt && opt_len)
++    {
++      grub_env_set_net_property (name, "vendor_class_identifier", (const char *) opt, opt_len);
++      if (opt && grub_strcmp (opt, "HTTPClient") == 0)
++        {
++          char *proto, *ip, *pa;
++
++          if (!dissect_url (bp->boot_file, &proto, &ip, &pa))
++            return inter;
++
++          grub_env_set_net_property (name, "boot_file", pa, grub_strlen (pa));
++          if (is_def)
++            {
++              grub_net_default_server = grub_strdup (ip);
++              grub_env_set ("net_default_interface", name);
++             grub_env_export ("net_default_interface");
++            }
++          if (device && !*device)
++            {
++              *device = grub_xasprintf ("%s,%s", proto, ip);
++              grub_print_error ();
++            }
++          if (path)
++            {
++              *path = grub_strdup (pa);
++              grub_print_error ();
++              if (*path)
++                {
++                  char *slash;
++                  slash = grub_strrchr (*path, '/');
++                  if (slash)
++                    *slash = 0;
++                  else
++                    **path = 0;
++                }
++            }
++          grub_net_add_ipv4_local (inter, mask);
++          inter->dhcp_ack = grub_malloc (size);
++          if (inter->dhcp_ack)
++            {
++              grub_memcpy (inter->dhcp_ack, bp, size);
++              inter->dhcp_acklen = size;
++            }
++          else
++            grub_errno = GRUB_ERR_NONE;
++
++          grub_free (proto);
++          grub_free (ip);
++          grub_free (pa);
++          return inter;
++        }
++    }
++
+   opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_EXTENSIONS_PATH, &opt_len);
+   if (opt && opt_len)
+     grub_env_set_net_property (name, "extensionspath", (const char *) opt, opt_len);
+diff --git a/include/grub/net.h b/include/grub/net.h
+index 543251f727..42af7de250 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -531,6 +531,7 @@ enum
+     GRUB_NET_DHCP_MESSAGE_TYPE = 53,
+     GRUB_NET_DHCP_SERVER_IDENTIFIER = 54,
+     GRUB_NET_DHCP_PARAMETER_REQUEST_LIST = 55,
++    GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER = 60,
+     GRUB_NET_BOOTP_CLIENT_ID = 61,
+     GRUB_NET_DHCP_TFTP_SERVER_NAME = 66,
+     GRUB_NET_DHCP_BOOTFILE_NAME = 67,
diff --git a/SOURCES/0076-Add-linux-and-initrd-commands-for-grub-emu.patch b/SOURCES/0076-Add-linux-and-initrd-commands-for-grub-emu.patch
deleted file mode 100644
index dd69b13..0000000
--- a/SOURCES/0076-Add-linux-and-initrd-commands-for-grub-emu.patch
+++ /dev/null
@@ -1,347 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Michael Chang <mchang@suse.com>
-Date: Tue, 6 Feb 2018 09:09:00 +0100
-Subject: [PATCH] Add linux and initrd commands for grub-emu
-
-When using grub-emu, the linux and initrd commands are used as arguments
-to the kexec command line tool, to allow booting the selected menu entry.
----
- grub-core/Makefile.core.def  |   1 -
- grub-core/kern/emu/main.c    |   4 +
- grub-core/kern/emu/misc.c    |  18 ++++-
- grub-core/loader/emu/linux.c | 172 +++++++++++++++++++++++++++++++++++++++++++
- include/grub/emu/exec.h      |   4 +-
- include/grub/emu/hostfile.h  |   3 +-
- include/grub/emu/misc.h      |   3 +
- grub-core/Makefile.am        |   1 +
- 8 files changed, 202 insertions(+), 4 deletions(-)
- create mode 100644 grub-core/loader/emu/linux.c
-
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 058c88ac3af..5354f9613d3 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -1826,7 +1826,6 @@ module = {
- 
-   common = loader/linux.c;
-   common = lib/cmdline.c;
--  enable = noemu;
- 
-   efi = loader/efi/linux.c;
- };
-diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c
-index 55ea5a11ccd..846fe9715ec 100644
---- a/grub-core/kern/emu/main.c
-+++ b/grub-core/kern/emu/main.c
-@@ -107,6 +107,7 @@ static struct argp_option options[] = {
-    N_("use GRUB files in the directory DIR [default=%s]"), 0},
-   {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
-   {"hold",     'H', N_("SECS"),      OPTION_ARG_OPTIONAL, N_("wait until a debugger will attach"), 0},
-+  {"kexec",       'X', 0,      0, N_("try the untryable."), 0},
-   { 0, 0, 0, 0, 0, 0 }
- };
- 
-@@ -164,6 +165,9 @@ argp_parser (int key, char *arg, struct argp_state *state)
-     case 'v':
-       verbosity++;
-       break;
-+    case 'X':
-+      grub_util_set_kexecute();
-+      break;
- 
-     case ARGP_KEY_ARG:
-       {
-diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c
-index 0ff13bcaf8c..eeea092752d 100644
---- a/grub-core/kern/emu/misc.c
-+++ b/grub-core/kern/emu/misc.c
-@@ -39,6 +39,7 @@
- #include <grub/emu/misc.h>
- 
- int verbosity;
-+int kexecute;
- 
- void
- grub_util_warn (const char *fmt, ...)
-@@ -82,7 +83,7 @@ grub_util_error (const char *fmt, ...)
-   vfprintf (stderr, fmt, ap);
-   va_end (ap);
-   fprintf (stderr, ".\n");
--  exit (1);
-+  grub_exit (1);
- }
- 
- void *
-@@ -154,6 +155,9 @@ void
- __attribute__ ((noreturn))
- grub_exit (int rc)
- {
-+#if defined (GRUB_KERNEL)
-+  grub_reboot();
-+#endif
-   exit (rc < 0 ? 1 : rc);
- }
- #endif
-@@ -215,3 +219,15 @@ grub_util_load_image (const char *path, char *buf)
- 
-   fclose (fp);
- }
-+
-+void
-+grub_util_set_kexecute(void)
-+{
-+  kexecute++;
-+}
-+
-+int
-+grub_util_get_kexecute(void)
-+{
-+  return kexecute;
-+}
-diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c
-new file mode 100644
-index 00000000000..fda9e00d24c
---- /dev/null
-+++ b/grub-core/loader/emu/linux.c
-@@ -0,0 +1,172 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2006,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/loader.h>
-+#include <grub/dl.h>
-+#include <grub/command.h>
-+#include <grub/time.h>
-+
-+#include <grub/emu/exec.h>
-+#include <grub/emu/hostfile.h>
-+#include <grub/emu/misc.h>
-+
-+GRUB_MOD_LICENSE ("GPLv3+");
-+
-+static grub_dl_t my_mod;
-+
-+static char *kernel_path;
-+static char *initrd_path;
-+static char *boot_cmdline;
-+
-+static grub_err_t
-+grub_linux_boot (void)
-+{
-+  grub_err_t rc = GRUB_ERR_NONE;
-+  char *initrd_param;
-+  const char *kexec[] = { "kexec", "-l", kernel_path, boot_cmdline, NULL, NULL };
-+  const char *systemctl[] = { "systemctl", "kexec", NULL };
-+  int kexecute = grub_util_get_kexecute();
-+
-+  if (initrd_path) {
-+    initrd_param = grub_xasprintf("--initrd=%s", initrd_path);
-+    kexec[3] = initrd_param;
-+    kexec[4] = boot_cmdline;
-+  } else {
-+    initrd_param = grub_xasprintf("%s", "");
-+  }
-+
-+  grub_printf("%serforming 'kexec -l %s %s %s'\n",
-+	(kexecute) ? "P" : "Not p",
-+	kernel_path, initrd_param, boot_cmdline);
-+
-+  if (kexecute)
-+    rc = grub_util_exec(kexec);
-+
-+  grub_free(initrd_param);
-+
-+  if (rc != GRUB_ERR_NONE) {
-+    grub_error (rc, N_("Error trying to perform kexec load operation."));
-+    grub_sleep (3);
-+    return rc;
-+  }
-+  if (kexecute < 1)
-+    grub_fatal (N_("Use '"PACKAGE"-emu --kexec' to force a system restart."));
-+
-+  grub_printf("Performing 'systemctl kexec' (%s) ",
-+		(kexecute==1) ? "do-or-die" : "just-in-case");
-+  rc = grub_util_exec (systemctl);
-+
-+  if (kexecute == 1)
-+    grub_fatal (N_("Error trying to perform 'systemctl kexec'"));
-+
-+  /* need to check read-only root before resetting hard!? */
-+  grub_printf("Performing 'kexec -e'");
-+  kexec[1] = "-e";
-+  kexec[2] = NULL;
-+  rc = grub_util_exec(kexec);
-+  if ( rc != GRUB_ERR_NONE )
-+    grub_fatal (N_("Error trying to directly perform 'kexec -e'."));
-+
-+  return rc;
-+}
-+
-+static grub_err_t
-+grub_linux_unload (void)
-+{
-+  grub_dl_unref (my_mod);
-+  if ( boot_cmdline != NULL )
-+    grub_free (boot_cmdline);
-+  boot_cmdline = NULL;
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[])
-+{
-+  int i;
-+  char *tempstr;
-+
-+  grub_dl_ref (my_mod);
-+
-+  if (argc == 0)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
-+
-+  if ( !grub_util_is_regular(argv[0]) )
-+    return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("Cannot find kernel file %s"), argv[0]);
-+
-+  if ( kernel_path != NULL )
-+    grub_free(kernel_path);
-+
-+  kernel_path = grub_xasprintf("%s", argv[0]);
-+
-+  if ( boot_cmdline != NULL ) {
-+    grub_free(boot_cmdline);
-+    boot_cmdline = NULL;
-+  }
-+
-+  if ( argc > 1 )
-+  {
-+    boot_cmdline = grub_xasprintf("--command-line=%s", argv[1]);
-+    for ( i = 2; i < argc; i++ ) {
-+      tempstr = grub_xasprintf("%s %s", boot_cmdline, argv[i]);
-+      grub_free(boot_cmdline);
-+      boot_cmdline = tempstr;
-+    }
-+  }
-+
-+  grub_loader_set (grub_linux_boot, grub_linux_unload, 0);
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[])
-+{
-+  if (argc == 0)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
-+
-+  if ( !grub_util_is_regular(argv[0]) )
-+    return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("Cannot find initrd file %s"), argv[0]);
-+
-+  if ( initrd_path != NULL )
-+    grub_free(initrd_path);
-+
-+  initrd_path = grub_xasprintf("%s", argv[0]);
-+
-+  grub_dl_unref (my_mod);
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_command_t cmd_linux, cmd_initrd;
-+
-+GRUB_MOD_INIT(linux)
-+{
-+  cmd_linux = grub_register_command ("linux", grub_cmd_linux, 0, N_("Load Linux."));
-+  cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, 0, N_("Load initrd."));
-+  my_mod = mod;
-+  kernel_path = NULL;
-+  initrd_path = NULL;
-+  boot_cmdline = NULL;
-+}
-+
-+GRUB_MOD_FINI(linux)
-+{
-+  grub_unregister_command (cmd_linux);
-+  grub_unregister_command (cmd_initrd);
-+}
-diff --git a/include/grub/emu/exec.h b/include/grub/emu/exec.h
-index d1073ef86af..1b61b4a2e5d 100644
---- a/include/grub/emu/exec.h
-+++ b/include/grub/emu/exec.h
-@@ -23,6 +23,8 @@
- #include <stdarg.h>
- 
- #include <sys/types.h>
-+#include <grub/symbol.h>
-+
- pid_t
- grub_util_exec_pipe (const char *const *argv, int *fd);
- pid_t
-@@ -32,7 +34,7 @@ int
- grub_util_exec_redirect_all (const char *const *argv, const char *stdin_file,
- 			     const char *stdout_file, const char *stderr_file);
- int
--grub_util_exec (const char *const *argv);
-+EXPORT_FUNC(grub_util_exec) (const char *const *argv);
- int
- grub_util_exec_redirect (const char *const *argv, const char *stdin_file,
- 			 const char *stdout_file);
-diff --git a/include/grub/emu/hostfile.h b/include/grub/emu/hostfile.h
-index cfb1e2b5661..a61568e36e9 100644
---- a/include/grub/emu/hostfile.h
-+++ b/include/grub/emu/hostfile.h
-@@ -22,6 +22,7 @@
- #include <grub/disk.h>
- #include <grub/partition.h>
- #include <sys/types.h>
-+#include <grub/symbol.h>
- #include <grub/osdep/hostfile.h>
- 
- int
-@@ -29,7 +30,7 @@ grub_util_is_directory (const char *path);
- int
- grub_util_is_special_file (const char *path);
- int
--grub_util_is_regular (const char *path);
-+EXPORT_FUNC(grub_util_is_regular) (const char *path);
- 
- char *
- grub_util_path_concat (size_t n, ...);
-diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h
-index ff9c48a6490..01056954b96 100644
---- a/include/grub/emu/misc.h
-+++ b/include/grub/emu/misc.h
-@@ -57,6 +57,9 @@ void EXPORT_FUNC(grub_util_warn) (const char *fmt, ...) __attribute__ ((format (
- void EXPORT_FUNC(grub_util_info) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2)));
- void EXPORT_FUNC(grub_util_error) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2), noreturn));
- 
-+void EXPORT_FUNC(grub_util_set_kexecute) (void);
-+int EXPORT_FUNC(grub_util_get_kexecute) (void) WARN_UNUSED_RESULT;
-+
- grub_uint64_t EXPORT_FUNC (grub_util_get_cpu_time_ms) (void);
- 
- #ifdef HAVE_DEVICE_MAPPER
-diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
-index ee88e44e97a..80e7a83edf9 100644
---- a/grub-core/Makefile.am
-+++ b/grub-core/Makefile.am
-@@ -307,6 +307,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/net.h
- KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostdisk.h
- KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostfile.h
- KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
-+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/exec.h
- if COND_GRUB_EMU_SDL
- KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sdl.h
- endif
diff --git a/SOURCES/0076-efinet-Setting-network-from-UEFI-device-path.patch b/SOURCES/0076-efinet-Setting-network-from-UEFI-device-path.patch
new file mode 100644
index 0000000..f4faf27
--- /dev/null
+++ b/SOURCES/0076-efinet-Setting-network-from-UEFI-device-path.patch
@@ -0,0 +1,405 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Sun, 10 Jul 2016 23:46:31 +0800
+Subject: [PATCH] efinet: Setting network from UEFI device path
+
+The PXE Base Code protocol used to obtain cached PXE DHCPACK packet is no
+longer provided for HTTP Boot. Instead, we have to get the HTTP boot
+information from the device path nodes defined in following UEFI Specification
+sections.
+
+ 9.3.5.12 IPv4 Device Path
+ 9.3.5.13 IPv6 Device Path
+ 9.3.5.23 Uniform Resource Identifiers (URI) Device Path
+
+This patch basically does:
+
+include/grub/efi/api.h:
+Add new structure of Uniform Resource Identifiers (URI) Device Path
+
+grub-core/net/drivers/efi/efinet.c:
+Check if PXE Base Code is available, if not it will try to obtain the netboot
+information from the device path where the image booted from. The DHCPACK
+packet is recoverd from the information in device patch and feed into the same
+DHCP packet processing functions to ensure the network interface is setting up
+the same way it used to be.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+---
+ grub-core/net/drivers/efi/efinet.c | 284 +++++++++++++++++++++++++++++++++++--
+ include/grub/efi/api.h             |  11 ++
+ 2 files changed, 280 insertions(+), 15 deletions(-)
+
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index 014e5bf980..8171ecaa5e 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -26,6 +26,7 @@
+ #include <grub/i18n.h>
+ #include <grub/lib/hexdump.h>
+ #include <grub/types.h>
++#include <grub/net/netbuff.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -331,6 +332,227 @@ grub_efinet_findcards (void)
+   grub_free (handles);
+ }
+ 
++static struct grub_net_buff *
++grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6)
++{
++  grub_efi_uint16_t uri_len;
++  grub_efi_device_path_t *ldp, *ddp;
++  grub_efi_uri_device_path_t *uri_dp;
++  struct grub_net_buff *nb;
++  grub_err_t err;
++
++  ddp = grub_efi_duplicate_device_path (dp);
++  if (!ddp)
++    return NULL;
++
++  ldp = grub_efi_find_last_device_path (ddp);
++
++  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
++      || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
++    {
++      grub_free (ddp);
++      return NULL;
++    }
++
++  uri_len = GRUB_EFI_DEVICE_PATH_LENGTH (ldp) > 4 ? GRUB_EFI_DEVICE_PATH_LENGTH (ldp) - 4  : 0;
++
++  if (!uri_len)
++    {
++      grub_free (ddp);
++      return NULL;
++    }
++
++  uri_dp = (grub_efi_uri_device_path_t *) ldp;
++
++  ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++  ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++  ldp->length = sizeof (*ldp);
++
++  ldp = grub_efi_find_last_device_path (ddp);
++
++  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
++      || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
++          && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
++    {
++      grub_free (ddp);
++      return NULL;
++    }
++
++  nb = grub_netbuff_alloc (512);
++  if (!nb)
++    {
++      grub_free (ddp);
++      return NULL;
++    }
++
++  if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE)
++    {
++      grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp;
++      struct grub_net_bootp_packet *bp;
++      grub_uint8_t *ptr;
++
++      bp = (struct grub_net_bootp_packet *) nb->tail;
++      err = grub_netbuff_put (nb, sizeof (*bp) + 4);
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++
++      if (sizeof(bp->boot_file) < uri_len)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      grub_memcpy (bp->boot_file, uri_dp->uri, uri_len);
++      grub_memcpy (&bp->your_ip, ipv4->local_ip_address, sizeof (bp->your_ip));
++      grub_memcpy (&bp->server_ip, ipv4->remote_ip_address, sizeof (bp->server_ip));
++
++      bp->vendor[0] = GRUB_NET_BOOTP_RFC1048_MAGIC_0;
++      bp->vendor[1] = GRUB_NET_BOOTP_RFC1048_MAGIC_1;
++      bp->vendor[2] = GRUB_NET_BOOTP_RFC1048_MAGIC_2;
++      bp->vendor[3] = GRUB_NET_BOOTP_RFC1048_MAGIC_3;
++
++      ptr = nb->tail;
++      err = grub_netbuff_put (nb, sizeof (ipv4->subnet_mask) + 2);
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      *ptr++ = GRUB_NET_BOOTP_NETMASK;
++      *ptr++ = sizeof (ipv4->subnet_mask);
++      grub_memcpy (ptr, ipv4->subnet_mask, sizeof (ipv4->subnet_mask));
++
++      ptr = nb->tail;
++      err = grub_netbuff_put (nb, sizeof (ipv4->gateway_ip_address) + 2);
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      *ptr++ = GRUB_NET_BOOTP_ROUTER;
++      *ptr++ = sizeof (ipv4->gateway_ip_address);
++      grub_memcpy (ptr, ipv4->gateway_ip_address, sizeof (ipv4->gateway_ip_address));
++
++      ptr = nb->tail;
++      err = grub_netbuff_put (nb, sizeof ("HTTPClient") + 1);
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      *ptr++ = GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER;
++      *ptr++ = sizeof ("HTTPClient") - 1;
++      grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1);
++
++      ptr = nb->tail;
++      err = grub_netbuff_put (nb, 1);
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      *ptr = GRUB_NET_BOOTP_END;
++      *use_ipv6 = 0;
++
++      ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++      ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++      ldp->length = sizeof (*ldp);
++      ldp = grub_efi_find_last_device_path (ddp);
++
++      if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) ==  GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)
++	{
++	  grub_efi_mac_address_device_path_t *mac = (grub_efi_mac_address_device_path_t *) ldp;
++	  bp->hw_type = mac->if_type;
++	  bp->hw_len = sizeof (bp->mac_addr);
++	  grub_memcpy (bp->mac_addr, mac->mac_address, bp->hw_len);
++	}
++    }
++  else
++    {
++      grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) ldp;
++
++      struct grub_net_dhcp6_packet *d6p;
++      struct grub_net_dhcp6_option *opt;
++      struct grub_net_dhcp6_option_iana *iana;
++      struct grub_net_dhcp6_option_iaaddr *iaaddr;
++
++      d6p = (struct grub_net_dhcp6_packet *)nb->tail;
++      err = grub_netbuff_put (nb, sizeof(*d6p));
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      d6p->message_type = GRUB_NET_DHCP6_REPLY;
++
++      opt = (struct grub_net_dhcp6_option *)nb->tail;
++      err = grub_netbuff_put (nb, sizeof(*opt));
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
++      opt->len = grub_cpu_to_be16_compile_time (sizeof(*iana) + sizeof(*opt) + sizeof(*iaaddr));
++
++      err = grub_netbuff_put (nb, sizeof(*iana));
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++
++      opt = (struct grub_net_dhcp6_option *)nb->tail;
++      err = grub_netbuff_put (nb, sizeof(*opt));
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR);
++      opt->len = grub_cpu_to_be16_compile_time (sizeof (*iaaddr));
++
++      iaaddr = (struct grub_net_dhcp6_option_iaaddr *)nb->tail;
++      err = grub_netbuff_put (nb, sizeof(*iaaddr));
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      grub_memcpy (iaaddr->addr, ipv6->local_ip_address, sizeof(ipv6->local_ip_address));
++
++      opt = (struct grub_net_dhcp6_option *)nb->tail;
++      err = grub_netbuff_put (nb, sizeof(*opt) + uri_len);
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL);
++      opt->len = grub_cpu_to_be16 (uri_len);
++      grub_memcpy (opt->data, uri_dp->uri, uri_len);
++
++      *use_ipv6 = 1;
++    }
++
++  grub_free (ddp);
++  return nb;
++}
++
+ static void
+ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 			  char **path)
+@@ -346,7 +568,11 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+   {
+     grub_efi_device_path_t *cdp;
+     struct grub_efi_pxe *pxe;
+-    struct grub_efi_pxe_mode *pxe_mode;
++    struct grub_efi_pxe_mode *pxe_mode = NULL;
++    grub_uint8_t *packet_buf;
++    grub_size_t packet_bufsz ;
++    int ipv6;
++    struct grub_net_buff *nb = NULL;
+ 
+     if (card->driver != &efidriver)
+       continue;
+@@ -370,11 +596,21 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+          */
+ 	if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+ 	    || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
+-		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
++		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE
++		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
+ 	  continue;
+ 	dup_dp = grub_efi_duplicate_device_path (dp);
+ 	if (!dup_dp)
+ 	  continue;
++
++	if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
++	  {
++	    dup_ldp = grub_efi_find_last_device_path (dup_dp);
++	    dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++	    dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++	    dup_ldp->length = sizeof (*dup_ldp);
++	  }
++
+ 	dup_ldp = grub_efi_find_last_device_path (dup_dp);
+ 	dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ 	dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+@@ -387,23 +623,37 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 
+     pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
+ 				  GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+-    if (! pxe)
+-      continue;
++    if (!pxe)
++      {
++	nb = grub_efinet_create_dhcp_ack_from_device_path (dp, &ipv6);
++	if (!nb)
++	  {
++	    grub_print_error ();
++	    continue;
++	  }
++	packet_buf = nb->head;
++	packet_bufsz = nb->tail - nb->head;
++      }
++    else
++      {
++	pxe_mode = pxe->mode;
++	packet_buf = (grub_uint8_t *) &pxe_mode->dhcp_ack;
++	packet_bufsz = sizeof (pxe_mode->dhcp_ack);
++	ipv6 = pxe_mode->using_ipv6;
++      }
+ 
+-    pxe_mode = pxe->mode;
+-    if (pxe_mode->using_ipv6)
++    if (ipv6)
+       {
+ 	grub_dprintf ("efinet", "using ipv6 and dhcpv6\n");
+-	grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n",
+-		      pxe_mode->dhcp_ack_received ? "yes" : "no",
+-		      pxe_mode->dhcp_ack_received ? "" : " cannot continue");
+-	if (!pxe_mode->dhcp_ack_received)
+-	  continue;
++	if (pxe_mode)
++	  grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n",
++			pxe_mode->dhcp_ack_received ? "yes" : "no",
++			pxe_mode->dhcp_ack_received ? "" : " cannot continue");
+ 
+ 	grub_net_configure_by_dhcpv6_reply (card->name, card, 0,
+ 					    (struct grub_net_dhcp6_packet *)
+-					    &pxe_mode->dhcp_ack,
+-					    sizeof (pxe_mode->dhcp_ack),
++					    packet_buf,
++					    packet_bufsz,
+ 					    1, device, path);
+ 	if (grub_errno)
+ 	  grub_print_error ();
+@@ -417,11 +667,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 	grub_dprintf ("efinet", "using ipv4 and dhcp\n");
+ 	grub_net_configure_by_dhcp_ack (card->name, card, 0,
+ 					(struct grub_net_bootp_packet *)
+-					&pxe_mode->dhcp_ack,
+-					sizeof (pxe_mode->dhcp_ack),
++					packet_buf,
++					packet_bufsz,
+ 					1, device, path);
+ 	grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
+       }
++
++    if (nb)
++      grub_netbuff_free (nb);
++
+     return;
+   }
+ }
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index 91ab528e4d..4a51667adb 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -864,6 +864,8 @@ struct grub_efi_ipv4_device_path
+   grub_efi_uint16_t remote_port;
+   grub_efi_uint16_t protocol;
+   grub_efi_uint8_t static_ip_address;
++  grub_efi_ipv4_address_t gateway_ip_address;
++  grub_efi_ipv4_address_t subnet_mask;
+ } GRUB_PACKED;
+ typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t;
+ 
+@@ -918,6 +920,15 @@ struct grub_efi_sata_device_path
+ } GRUB_PACKED;
+ typedef struct grub_efi_sata_device_path grub_efi_sata_device_path_t;
+ 
++#define GRUB_EFI_URI_DEVICE_PATH_SUBTYPE		24
++
++struct grub_efi_uri_device_path
++{
++  grub_efi_device_path_t header;
++  grub_efi_uint8_t uri[0];
++} GRUB_PACKED;
++typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t;
++
+ #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE	10
+ 
+ /* Media Device Path.  */
diff --git a/SOURCES/0077-Add-grub2-switch-to-blscfg.patch b/SOURCES/0077-Add-grub2-switch-to-blscfg.patch
deleted file mode 100644
index ce40e90..0000000
--- a/SOURCES/0077-Add-grub2-switch-to-blscfg.patch
+++ /dev/null
@@ -1,410 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 15 Mar 2018 14:12:40 -0400
-Subject: [PATCH] Add grub2-switch-to-blscfg
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
-[jhlavac: Use ${etcdefaultgrub} instead of /etc/default/grub]
-Signed-off-by: Jan Hlavac <jhlavac@redhat.com>
----
- Makefile.util.def             |   7 +
- util/grub-set-password.in     |   2 +-
- util/grub-switch-to-blscfg.8  |  33 +++++
- util/grub-switch-to-blscfg.in | 317 ++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 358 insertions(+), 1 deletion(-)
- create mode 100644 util/grub-switch-to-blscfg.8
- create mode 100644 util/grub-switch-to-blscfg.in
-
-diff --git a/Makefile.util.def b/Makefile.util.def
-index cdd2f51fe4b..afc4d7b0c3e 100644
---- a/Makefile.util.def
-+++ b/Makefile.util.def
-@@ -1364,6 +1364,13 @@ program = {
-   ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
- };
- 
-+script = {
-+  name = grub-switch-to-blscfg;
-+  common = util/grub-switch-to-blscfg.in;
-+  mansection = 8;
-+  installdir = sbin;
-+};
-+
- program = {
-   name = grub-glue-efi;
-   mansection = 1;
-diff --git a/util/grub-set-password.in b/util/grub-set-password.in
-index 5ebf50576d6..c0b5ebbfdc5 100644
---- a/util/grub-set-password.in
-+++ b/util/grub-set-password.in
-@@ -1,6 +1,6 @@
- #!/bin/sh -e
- 
--EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/')
-+EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g')
- if [ -d /sys/firmware/efi/efivars/ ]; then
-     grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'`
- else
-diff --git a/util/grub-switch-to-blscfg.8 b/util/grub-switch-to-blscfg.8
-new file mode 100644
-index 00000000000..9a886282976
---- /dev/null
-+++ b/util/grub-switch-to-blscfg.8
-@@ -0,0 +1,33 @@
-+.TH GRUB-SWITCH-TO-BLSCFG 1 "Wed Feb 26 2014"
-+.SH NAME
-+\fBgrub-switch-to-blscfg\fR \(em Switch to using BLS config files.
-+
-+.SH SYNOPSIS
-+\fBgrub-switch-to-blscfg\fR [--grub-directory=\fIDIR\fR] [--config-file=\fIFILE\fR] [--grub-defaults=\fIFILE\fR]
-+
-+.SH DESCRIPTION
-+\fBgrub-switch-to-blscfg\fR reconfigures grub-mkconfig to use BLS-style config files, and then regenerates the GRUB configuration.
-+
-+.SH OPTIONS
-+.TP
-+--grub-directory=\fIDIR\fR
-+Search for grub.cfg under \fIDIR\fR.  The default value is \fI/boot/efi/EFI/\fBVENDOR\fR on UEFI machines and \fI/boot/grub2\fR elsewhere.
-+
-+.TP
-+--config-file=\fIFILE\fR
-+The grub config file to use.  The default value is \fI/etc/grub2-efi.cfg\fR on UEFI machines and \fI/etc/grub2.cfg\fR elsewhere.  Symbolic links will be followed.
-+
-+.TP
-+--grub-defaults=\fIFILE\fR
-+The defaults file for grub-mkconfig.  The default value is \fI/etc/default/grub\fR.
-+
-+.TP
-+--bls-directory=\fIDIR\fR
-+Create BootLoaderSpec fragments in \fIDIR\fR.  The default value is \fI/boot/loader/entries\fR.
-+
-+.TP
-+--backup-suffix=\fSUFFIX\fR
-+The suffix to use for saved backup files.  The default value is \fI.bak\fR.
-+
-+.SH SEE ALSO
-+.BR "info grub"
-diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
-new file mode 100644
-index 00000000000..a851424beb2
---- /dev/null
-+++ b/util/grub-switch-to-blscfg.in
-@@ -0,0 +1,317 @@
-+#! /bin/sh
-+#
-+# Set a default boot entry for GRUB.
-+# Copyright (C) 2004,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/>.
-+
-+#set -eu
-+
-+# Initialize some variables.
-+prefix=@prefix@
-+exec_prefix=@exec_prefix@
-+sbindir=@sbindir@
-+bindir=@bindir@
-+sysconfdir="@sysconfdir@"
-+PACKAGE_NAME=@PACKAGE_NAME@
-+PACKAGE_VERSION=@PACKAGE_VERSION@
-+datarootdir="@datarootdir@"
-+datadir="@datadir@"
-+if [ ! -v pkgdatadir ]; then
-+    pkgdatadir="${datadir}/@PACKAGE@"
-+fi
-+
-+self=`basename $0`
-+
-+grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@"
-+grub_editenv=${bindir}/@grub_editenv@
-+etcdefaultgrub=/etc/default/grub
-+
-+eval "$("${grub_get_kernel_settings}")" || true
-+
-+EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g')
-+if [ -d /sys/firmware/efi/efivars/ ]; then
-+    startlink=/etc/grub2-efi.cfg
-+    grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'`
-+else
-+    startlink=/etc/grub2.cfg
-+    grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`
-+fi
-+
-+blsdir=`echo "/@bootdirname@/loader/entries" | sed 's,//*,/,g'`
-+
-+backupsuffix=.bak
-+
-+arch="$(uname -m)"
-+
-+export TEXTDOMAIN=@PACKAGE@
-+export TEXTDOMAINDIR="@localedir@"
-+
-+. "${pkgdatadir}/grub-mkconfig_lib"
-+
-+# Usage: usage
-+# Print the usage.
-+usage () {
-+    gettext_printf "Usage: %s\n" "$self"
-+    gettext "Switch to BLS config files.\n"; echo
-+    echo
-+    print_option_help "-h, --help" "$(gettext "print this message and exit")"
-+    print_option_help "-V, --version" "$(gettext "print the version information and exit")"
-+    echo
-+    print_option_help "--backup-suffix=$(gettext "SUFFIX")" "$backupsuffix"
-+    print_option_help "--bls-directory=$(gettext "DIR")" "$blsdir"
-+    print_option_help "--config-file=$(gettext "FILE")" "$startlink"
-+    print_option_help "--grub-defaults=$(gettext "FILE")" "$etcdefaultgrub"
-+    print_option_help "--grub-directory=$(gettext "DIR")" "$grubdir"
-+    # echo
-+    # gettext "Report bugs to <bug-grub@gnu.org>."; echo
-+}
-+
-+argument () {
-+    opt=$1
-+    shift
-+
-+    if test $# -eq 0; then
-+        gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$opt" 1>&2
-+        exit 1
-+    fi
-+    echo $1
-+}
-+
-+# Check the arguments.
-+while test $# -gt 0
-+do
-+    option=$1
-+    shift
-+
-+    case "$option" in
-+    -h | --help)
-+        usage
-+        exit 0 ;;
-+    -V | --version)
-+        echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}"
-+        exit 0 ;;
-+
-+    --backup-suffix)
-+        backupsuffix=`argument $option "$@"`
-+        shift
-+        ;;
-+    --backup-suffix=*)
-+        backupsuffix=`echo "$option" | sed 's/--backup-suffix=//'`
-+        ;;
-+
-+    --bls-directory)
-+        blsdir=`argument $option "$@"`
-+        shift
-+        ;;
-+    --bls-directory=*)
-+        blsdir=`echo "$option" | sed 's/--bls-directory=//'`
-+        ;;
-+
-+    --config-file)
-+        startlink=`argument $option "$@"`
-+        shift
-+        ;;
-+    --config-file=*)
-+        startlink=`echo "$option" | sed 's/--config-file=//'`
-+        ;;
-+
-+    --grub-defaults)
-+        etcdefaultgrub=`argument $option "$@"`
-+        shift
-+        ;;
-+    --grub-defaults=*)
-+        etcdefaultgrub=`echo "$option" | sed 's/--grub-defaults=//'`
-+        ;;
-+
-+    --grub-directory)
-+        grubdir=`argument $option "$@"`
-+        shift
-+        ;;
-+    --grub-directory=*)
-+        grubdir=`echo "$option" | sed 's/--grub-directory=//'`
-+        ;;
-+
-+    *)
-+        gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2
-+        usage
-+        exit 1
-+        ;;
-+    esac
-+done
-+
-+find_grub_cfg() {
-+    local candidate=""
-+    while [ -e "${candidate}" -o $# -gt 0 ]
-+    do
-+        if [ ! -e "${candidate}" ] ; then
-+            candidate="$1"
-+            shift
-+        fi
-+
-+        if [ -L "${candidate}" ]; then
-+            candidate="$(realpath "${candidate}")"
-+        fi
-+
-+        if [ -f "${candidate}" ]; then
-+            export GRUB_CONFIG_FILE="${candidate}"
-+            return 0
-+        fi
-+    done
-+    return 1
-+}
-+
-+if ! find_grub_cfg ${startlink} ${grubdir}/grub.cfg ; then
-+  gettext_printf "Couldn't find config file\n" 1>&2
-+  exit 1
-+fi
-+
-+if [ ! -d "${blsdir}" ]; then
-+    install -m 700 -d "${blsdir}"
-+fi
-+
-+if [ -f /etc/machine-id ]; then
-+    MACHINE_ID=$(cat /etc/machine-id)
-+else
-+    MACHINE_ID=$(dmesg | sha256sum)
-+fi
-+
-+mkbls() {
-+    local kernelver=$1 && shift
-+    local datetime=$1 && shift
-+    local kernelopts=$1 && shift
-+
-+    local debugname=""
-+    local debugid=""
-+    local flavor=""
-+
-+    if [ "$kernelver" == *\+* ] ; then
-+        local flavor=-"${kernelver##*+}"
-+        if [ "${flavor}" == "-debug" ]; then
-+            local debugname=" with debugging"
-+            local debugid="-debug"
-+        fi
-+    fi
-+    (
-+        source /etc/os-release
-+
-+        cat <<EOF
-+title ${NAME} (${kernelver}) ${VERSION}${debugname}
-+version ${kernelver}${debugid}
-+linux /vmlinuz-${kernelver}
-+initrd /initramfs-${kernelver}.img
-+options ${kernelopts}
-+grub_users \$grub_users
-+grub_arg --unrestricted
-+grub_class kernel${flavor}
-+EOF
-+    ) | cat
-+}
-+
-+copy_bls() {
-+    for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
-+	bls_target="${blsdir}/${MACHINE_ID}-${kernelver}.conf"
-+	linux="/vmlinuz-${kernelver}"
-+	linux_path="/boot${linux}"
-+	kernel_dir="/lib/modules/${kernelver}"
-+
-+	if [ ! -d "${kernel_dir}" ] ; then
-+            continue
-+	fi
-+	if [ ! -f "${linux_path}" ]; then
-+            continue
-+	fi
-+
-+	linux_relpath="$("${grub_mkrelpath}" "${linux_path}")"
-+	bootprefix="${linux_relpath%%"${linux}"}"
-+	cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
-+
-+	mkbls "${kernelver}" \
-+	      "$(date -u +%Y%m%d%H%M%S -d "$(stat -c '%y' "${kernel_dir}")")" \
-+	      "${bootprefix}" "${cmdline}" >"${bls_target}"
-+
-+	if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
-+            bls_debug="$(echo ${bls_target} | sed -e "s/${kernelver}/${kernelver}~debug/")"
-+            cp -aT  "${bls_target}" "${bls_debug}"
-+            title="$(grep '^title[ \t]' "${bls_debug}" | sed -e 's/^title[ \t]*//')"
-+            options="$(echo "${cmdline} ${GRUB_CMDLINE_LINUX_DEBUG}" | sed -e 's/\//\\\//g')"
-+            sed -i -e "s/^title.*/title ${title}${GRUB_LINUX_DEBUG_TITLE_POSTFIX}/" "${bls_debug}"
-+            sed -i -e "s/^options.*/options ${options}/" "${bls_debug}"
-+	fi
-+    done
-+
-+    if [ -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]; then
-+	mkbls "0-rescue-${MACHINE_ID}" "0" "${bootprefix}" >"${blsdir}/${MACHINE_ID}-0-rescue.conf"
-+    fi
-+}
-+
-+# The grub2 EFI binary is not copied to the ESP as a part of an ostree
-+# transaction. Make sure a grub2 version with BLS support is installed
-+# but only do this if the blsdir is not set, to make sure that the BLS
-+# parsing module will search for the BLS snippets in the default path.
-+if test -f /run/ostree-booted && test -d /sys/firmware/efi/efivars && \
-+   ! ${grub_editenv} - list | grep -q blsdir && \
-+   mountpoint -q /boot; then
-+    grub_binary="$(find /usr/lib/ostree-boot/efi/EFI/${EFIDIR}/ -name grub*.efi)"
-+    install -m 700 ${grub_binary} ${grubdir} || exit 1
-+    # Create a hidden file to indicate that grub2 now has BLS support.
-+    touch /boot/grub2/.grub2-blscfg-supported
-+fi
-+
-+GENERATE=0
-+if grep '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" \
-+        | grep -vq '^GRUB_ENABLE_BLSCFG="*true"*\s*$' ; then
-+    if ! sed -i"${backupsuffix}" \
-+            -e 's,^GRUB_ENABLE_BLSCFG=.*,GRUB_ENABLE_BLSCFG=true,' \
-+            "${etcdefaultgrub}" ; then
-+        gettext_printf "Updating %s failed\n" "${etcdefaultgrub}"
-+        exit 1
-+    fi
-+    GENERATE=1
-+elif ! grep -q '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" ; then
-+    if ! echo 'GRUB_ENABLE_BLSCFG=true' >> "${etcdefaultgrub}" ; then
-+        gettext_printf "Updating %s failed\n" "${etcdefaultgrub}"
-+        exit 1
-+    fi
-+    GENERATE=1
-+fi
-+
-+if [ "${GENERATE}" -eq 1 ] ; then
-+    copy_bls
-+
-+    if [ $arch = "x86_64" ] && [ ! -d /sys/firmware/efi ]; then
-+	mod_dir="i386-pc"
-+    elif [ $arch = "ppc64" -o $arch = "ppc64le" ] && [ ! -d /sys/firmware/opal ]; then
-+	mod_dir="powerpc-ieee1275"
-+    fi
-+
-+    if [ -n "${mod_dir}" ]; then
-+	for mod in blscfg increment; do
-+	    install -m 700 ${prefix}/lib/grub/${mod_dir}/${mod}.mod ${grubdir}/$mod_dir/ || exit 1
-+	done
-+    fi
-+
-+    cp -af "${GRUB_CONFIG_FILE}" "${GRUB_CONFIG_FILE}${backupsuffix}"
-+    if ! grub2-mkconfig -o "${GRUB_CONFIG_FILE}" ; then
-+        install -m 700 "${GRUB_CONFIG_FILE}${backupsuffix}" "${GRUB_CONFIG_FILE}"
-+        sed -i"${backupsuffix}" \
-+            -e 's,^GRUB_ENABLE_BLSCFG=.*,GRUB_ENABLE_BLSCFG=false,' \
-+            "${etcdefaultgrub}"
-+        gettext_printf "Updating %s failed\n" "${GRUB_CONFIG_FILE}"
-+        exit 1
-+    fi
-+fi
-+
-+# Bye.
-+exit 0
diff --git a/SOURCES/0077-efinet-Setting-DNS-server-from-UEFI-protocol.patch b/SOURCES/0077-efinet-Setting-DNS-server-from-UEFI-protocol.patch
new file mode 100644
index 0000000..2d92ff0
--- /dev/null
+++ b/SOURCES/0077-efinet-Setting-DNS-server-from-UEFI-protocol.patch
@@ -0,0 +1,336 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 14 Jul 2016 17:48:45 +0800
+Subject: [PATCH] efinet: Setting DNS server from UEFI protocol
+
+In the URI device path node, any name rahter than address can be used for
+looking up the resources so that DNS service become needed to get answer of the
+name's address. Unfortunately the DNS is not defined in any of the device path
+nodes so that we use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL
+to obtain it.
+
+These two protcols are defined the sections of UEFI specification.
+
+ 27.5 EFI IPv4 Configuration II Protocol
+ 27.7 EFI IPv6 Configuration Protocol
+
+include/grub/efi/api.h:
+Add new structure and protocol UUID of EFI_IP4_CONFIG2_PROTOCOL and
+EFI_IP6_CONFIG_PROTOCOL.
+
+grub-core/net/drivers/efi/efinet.c:
+Use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL to obtain the list
+of DNS server address for IPv4 and IPv6 respectively. The address of DNS
+servers is structured into DHCPACK packet and feed into the same DHCP packet
+processing functions to ensure the network interface is setting up the same way
+it used to be.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+---
+ grub-core/net/drivers/efi/efinet.c | 163 +++++++++++++++++++++++++++++++++++++
+ include/grub/efi/api.h             |  75 +++++++++++++++++
+ 2 files changed, 238 insertions(+)
+
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index 8171ecaa5e..715a6168d7 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -33,6 +33,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ /* GUID.  */
+ static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID;
+ static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID;
++static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID;
++static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID;
+ 
+ static grub_err_t
+ send_card_buffer (struct grub_net_card *dev,
+@@ -332,6 +334,125 @@ grub_efinet_findcards (void)
+   grub_free (handles);
+ }
+ 
++static grub_efi_handle_t
++grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path,
++			    grub_efi_device_path_t **r_device_path)
++{
++  grub_efi_handle_t handle;
++  grub_efi_status_t status;
++
++  status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path,
++		      protocol, &device_path, &handle);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++
++  if (r_device_path)
++    *r_device_path = device_path;
++
++  return handle;
++}
++
++static grub_efi_ipv4_address_t *
++grub_dns_server_ip4_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns)
++{
++  grub_efi_handle_t hnd;
++  grub_efi_status_t status;
++  grub_efi_ip4_config2_protocol_t *conf;
++  grub_efi_ipv4_address_t *addrs;
++  grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv4_address_t);
++
++  hnd = grub_efi_locate_device_path (&ip4_config_guid, dp, NULL);
++
++  if (!hnd)
++    return 0;
++
++  conf = grub_efi_open_protocol (hnd, &ip4_config_guid,
++				GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++
++  if (!conf)
++    return 0;
++
++  addrs  = grub_malloc (data_size);
++  if (!addrs)
++    return 0;
++
++  status = efi_call_4 (conf->get_data, conf,
++		      GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
++		      &data_size, addrs);
++
++  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
++    {
++      grub_free (addrs);
++      addrs  = grub_malloc (data_size);
++      if (!addrs)
++	return 0;
++
++      status = efi_call_4 (conf->get_data,  conf,
++			  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
++			  &data_size, addrs);
++    }
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (addrs);
++      return 0;
++    }
++
++  *num_dns = data_size / sizeof (grub_efi_ipv4_address_t);
++  return addrs;
++}
++
++static grub_efi_ipv6_address_t *
++grub_dns_server_ip6_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns)
++{
++  grub_efi_handle_t hnd;
++  grub_efi_status_t status;
++  grub_efi_ip6_config_protocol_t *conf;
++  grub_efi_ipv6_address_t *addrs;
++  grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv6_address_t);
++
++  hnd = grub_efi_locate_device_path (&ip6_config_guid, dp, NULL);
++
++  if (!hnd)
++    return 0;
++
++  conf = grub_efi_open_protocol (hnd, &ip6_config_guid,
++				GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++
++  if (!conf)
++    return 0;
++
++  addrs  = grub_malloc (data_size);
++  if (!addrs)
++    return 0;
++
++  status = efi_call_4 (conf->get_data, conf,
++		      GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
++		      &data_size, addrs);
++
++  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
++    {
++      grub_free (addrs);
++      addrs  = grub_malloc (data_size);
++      if (!addrs)
++	return 0;
++
++      status = efi_call_4 (conf->get_data,  conf,
++			  GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
++			  &data_size, addrs);
++    }
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (addrs);
++      return 0;
++    }
++
++  *num_dns = data_size / sizeof (grub_efi_ipv6_address_t);
++  return addrs;
++}
++
+ static struct grub_net_buff *
+ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6)
+ {
+@@ -390,6 +511,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
+       grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp;
+       struct grub_net_bootp_packet *bp;
+       grub_uint8_t *ptr;
++      grub_efi_ipv4_address_t *dns;
++      grub_efi_uintn_t num_dns;
+ 
+       bp = (struct grub_net_bootp_packet *) nb->tail;
+       err = grub_netbuff_put (nb, sizeof (*bp) + 4);
+@@ -451,6 +574,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
+       *ptr++ = sizeof ("HTTPClient") - 1;
+       grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1);
+ 
++      dns = grub_dns_server_ip4_address (dp, &num_dns);
++      if (dns)
++	{
++	  grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns;
++
++	  ptr = nb->tail;
++	  err = grub_netbuff_put (nb, size_dns + 2);
++	  if (err)
++	    {
++	      grub_free (ddp);
++	      grub_netbuff_free (nb);
++	      return NULL;
++	    }
++	  *ptr++ = GRUB_NET_BOOTP_DNS;
++	  *ptr++ = size_dns;
++	  grub_memcpy (ptr, dns, size_dns);
++	  grub_free (dns);
++	}
++
+       ptr = nb->tail;
+       err = grub_netbuff_put (nb, 1);
+       if (err)
+@@ -483,6 +625,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
+       struct grub_net_dhcp6_option *opt;
+       struct grub_net_dhcp6_option_iana *iana;
+       struct grub_net_dhcp6_option_iaaddr *iaaddr;
++      grub_efi_ipv6_address_t *dns;
++      grub_efi_uintn_t num_dns;
+ 
+       d6p = (struct grub_net_dhcp6_packet *)nb->tail;
+       err = grub_netbuff_put (nb, sizeof(*d6p));
+@@ -546,6 +690,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
+       opt->len = grub_cpu_to_be16 (uri_len);
+       grub_memcpy (opt->data, uri_dp->uri, uri_len);
+ 
++      dns = grub_dns_server_ip6_address (dp, &num_dns);
++      if (dns)
++	{
++	  grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns;
++
++	  opt = (struct grub_net_dhcp6_option *)nb->tail;
++	  err = grub_netbuff_put (nb, sizeof(*opt) + size_dns);
++	  if (err)
++	  {
++	    grub_free (ddp);
++	    grub_netbuff_free (nb);
++	    return NULL;
++	  }
++	  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS);
++	  opt->len = grub_cpu_to_be16 (size_dns);
++	  grub_memcpy (opt->data, dns, size_dns);
++	  grub_free (dns);
++	}
++
+       *use_ipv6 = 1;
+     }
+ 
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index 4a51667adb..0b490195ad 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -352,6 +352,15 @@
+ #define GRUB_EFI_RNG_PROTOCOL_GUID \
+   { 0x3152bca5, 0xeade, 0x433d, \
+     { 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \
++
++#define GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID \
++  { 0x5b446ed1, 0xe30b, 0x4faa, \
++      { 0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \
++  }
++
++#define GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID \
++  { 0x937fe521, 0x95ae, 0x4d1a, \
++      { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \
+   }
+ 
+ struct grub_efi_sal_system_table
+@@ -1883,6 +1892,72 @@ struct grub_efi_rng_protocol
+ };
+ typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t;
+ 
++enum grub_efi_ip4_config2_data_type {
++  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
++  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
++  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
++  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY,
++  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
++  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MAXIMUM
++};
++typedef enum grub_efi_ip4_config2_data_type grub_efi_ip4_config2_data_type_t;
++
++struct grub_efi_ip4_config2_protocol
++{
++  grub_efi_status_t (*set_data) (struct grub_efi_ip4_config2_protocol *this,
++				 grub_efi_ip4_config2_data_type_t data_type,
++				 grub_efi_uintn_t data_size,
++				 void *data);
++
++  grub_efi_status_t (*get_data) (struct grub_efi_ip4_config2_protocol *this,
++				 grub_efi_ip4_config2_data_type_t data_type,
++				 grub_efi_uintn_t *data_size,
++				 void *data);
++
++  grub_efi_status_t (*register_data_notify) (struct grub_efi_ip4_config2_protocol *this,
++					     grub_efi_ip4_config2_data_type_t data_type,
++					     grub_efi_event_t event);
++
++  grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip4_config2_protocol *this,
++					     grub_efi_ip4_config2_data_type_t data_type,
++					     grub_efi_event_t event);
++};
++typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t;
++
++enum grub_efi_ip6_config_data_type {
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID,
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY,
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_DUP_ADDR_DETECT_TRANSMITS,
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY,
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_MAXIMUM
++};
++typedef enum grub_efi_ip6_config_data_type grub_efi_ip6_config_data_type_t;
++
++struct grub_efi_ip6_config_protocol
++{
++  grub_efi_status_t (*set_data) (struct grub_efi_ip6_config_protocol *this,
++				 grub_efi_ip6_config_data_type_t data_type,
++				 grub_efi_uintn_t data_size,
++				 void *data);
++
++  grub_efi_status_t (*get_data) (struct grub_efi_ip6_config_protocol *this,
++				 grub_efi_ip6_config_data_type_t data_type,
++				 grub_efi_uintn_t *data_size,
++				 void *data);
++
++  grub_efi_status_t (*register_data_notify) (struct grub_efi_ip6_config_protocol *this,
++					     grub_efi_ip6_config_data_type_t data_type,
++					     grub_efi_event_t event);
++
++  grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip6_config_protocol *this,
++					     grub_efi_ip6_config_data_type_t data_type,
++					     grub_efi_event_t event);
++};
++typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t;
++
+ #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
+   || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \
+   || defined(__riscv)
diff --git a/SOURCES/0078-Support-UEFI-networking-protocols.patch b/SOURCES/0078-Support-UEFI-networking-protocols.patch
new file mode 100644
index 0000000..145becf
--- /dev/null
+++ b/SOURCES/0078-Support-UEFI-networking-protocols.patch
@@ -0,0 +1,5053 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Wed, 22 Feb 2017 14:27:50 +0800
+Subject: [PATCH] Support UEFI networking protocols
+
+References: fate#320130, bsc#1015589, bsc#1076132
+Patch-Mainline: no
+
+V1:
+  * Add preliminary support of UEFI networking protocols
+  * Support UEFI HTTPS Boot
+
+V2:
+  * Workaround http data access in firmware
+  * Fix DNS device path parsing for efinet device
+  * Relaxed UEFI Protocol requirement
+  * Support Intel OPA (Omni-Path Architecture) PXE Boot
+
+V3:
+  * Fix bufio in calculating address of next_buf
+  * Check HTTP respond code
+  * Use HEAD request method to test before GET
+  * Finish HTTP transaction in one go
+  * Fix bsc#1076132
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+[pjones: make efi_netfs not duplicate symbols from efinet]
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/Makefile.core.def        |   12 +
+ grub-core/io/bufio.c               |    2 +-
+ grub-core/kern/efi/efi.c           |   96 ++-
+ grub-core/net/drivers/efi/efinet.c |   27 +
+ grub-core/net/efi/dhcp.c           |  397 ++++++++++
+ grub-core/net/efi/efi_netfs.c      |   57 ++
+ grub-core/net/efi/http.c           |  419 +++++++++++
+ grub-core/net/efi/ip4_config.c     |  398 ++++++++++
+ grub-core/net/efi/ip6_config.c     |  422 +++++++++++
+ grub-core/net/efi/net.c            | 1428 ++++++++++++++++++++++++++++++++++++
+ grub-core/net/efi/pxe.c            |  424 +++++++++++
+ grub-core/net/net.c                |   74 ++
+ util/grub-mknetdir.c               |   23 +-
+ include/grub/efi/api.h             |  180 ++++-
+ include/grub/efi/dhcp.h            |  343 +++++++++
+ include/grub/efi/http.h            |  215 ++++++
+ include/grub/net/efi.h             |  144 ++++
+ 17 files changed, 4620 insertions(+), 41 deletions(-)
+ create mode 100644 grub-core/net/efi/dhcp.c
+ create mode 100644 grub-core/net/efi/efi_netfs.c
+ create mode 100644 grub-core/net/efi/http.c
+ create mode 100644 grub-core/net/efi/ip4_config.c
+ create mode 100644 grub-core/net/efi/ip6_config.c
+ create mode 100644 grub-core/net/efi/net.c
+ create mode 100644 grub-core/net/efi/pxe.c
+ create mode 100644 include/grub/efi/dhcp.h
+ create mode 100644 include/grub/efi/http.h
+ create mode 100644 include/grub/net/efi.h
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 52ec0fafcd..12797336c9 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -2300,6 +2300,12 @@ module = {
+   common = hook/datehook.c;
+ };
+ 
++module = {
++  name = efi_netfs;
++  common = net/efi/efi_netfs.c;
++  enable = efi;
++};
++
+ module = {
+   name = net;
+   common = net/net.c;
+@@ -2313,6 +2319,12 @@ module = {
+   common = net/ethernet.c;
+   common = net/arp.c;
+   common = net/netbuff.c;
++  efi = net/efi/net.c;
++  efi = net/efi/http.c;
++  efi = net/efi/pxe.c;
++  efi = net/efi/ip4_config.c;
++  efi = net/efi/ip6_config.c;
++  efi = net/efi/dhcp.c;
+ };
+ 
+ module = {
+diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c
+index a458c3aca7..1637731535 100644
+--- a/grub-core/io/bufio.c
++++ b/grub-core/io/bufio.c
+@@ -139,7 +139,7 @@ grub_bufio_read (grub_file_t file, char *buf, grub_size_t len)
+     return res;
+ 
+   /* Need to read some more.  */
+-  next_buf = (file->offset + res + len - 1) & ~((grub_off_t) bufio->block_size - 1);
++  next_buf = (grub_divmod64 (file->offset + res + len - 1, bufio->block_size, NULL)) * bufio->block_size;
+   /* Now read between file->offset + res and bufio->buffer_at.  */
+   if (file->offset + res < next_buf)
+     {
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index d6a2fb5778..2a446f5031 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -755,7 +755,7 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
+ 	      {
+ 		grub_efi_ipv4_device_path_t *ipv4
+ 		  = (grub_efi_ipv4_device_path_t *) dp;
+-		grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x)",
++		grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x",
+ 			     (unsigned) ipv4->local_ip_address[0],
+ 			     (unsigned) ipv4->local_ip_address[1],
+ 			     (unsigned) ipv4->local_ip_address[2],
+@@ -768,33 +768,60 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
+ 			     (unsigned) ipv4->remote_port,
+ 			     (unsigned) ipv4->protocol,
+ 			     (unsigned) ipv4->static_ip_address);
++		if (len == sizeof (*ipv4))
++		  {
++		    grub_printf (",%u.%u.%u.%u,%u.%u.%u.%u",
++			(unsigned) ipv4->gateway_ip_address[0],
++			(unsigned) ipv4->gateway_ip_address[1],
++			(unsigned) ipv4->gateway_ip_address[2],
++			(unsigned) ipv4->gateway_ip_address[3],
++			(unsigned) ipv4->subnet_mask[0],
++			(unsigned) ipv4->subnet_mask[1],
++			(unsigned) ipv4->subnet_mask[2],
++			(unsigned) ipv4->subnet_mask[3]);
++		  }
++		grub_printf (")");
+ 	      }
+ 	      break;
+ 	    case GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE:
+ 	      {
+ 		grub_efi_ipv6_device_path_t *ipv6
+ 		  = (grub_efi_ipv6_device_path_t *) dp;
+-		grub_printf ("/IPv6(%x:%x:%x:%x:%x:%x:%x:%x,%x:%x:%x:%x:%x:%x:%x:%x,%u,%u,%x,%x)",
+-			     (unsigned) ipv6->local_ip_address[0],
+-			     (unsigned) ipv6->local_ip_address[1],
+-			     (unsigned) ipv6->local_ip_address[2],
+-			     (unsigned) ipv6->local_ip_address[3],
+-			     (unsigned) ipv6->local_ip_address[4],
+-			     (unsigned) ipv6->local_ip_address[5],
+-			     (unsigned) ipv6->local_ip_address[6],
+-			     (unsigned) ipv6->local_ip_address[7],
+-			     (unsigned) ipv6->remote_ip_address[0],
+-			     (unsigned) ipv6->remote_ip_address[1],
+-			     (unsigned) ipv6->remote_ip_address[2],
+-			     (unsigned) ipv6->remote_ip_address[3],
+-			     (unsigned) ipv6->remote_ip_address[4],
+-			     (unsigned) ipv6->remote_ip_address[5],
+-			     (unsigned) ipv6->remote_ip_address[6],
+-			     (unsigned) ipv6->remote_ip_address[7],
++		grub_printf ("/IPv6(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%u,%u,%x,%x",
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[0]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[1]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[2]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[3]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[4]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[5]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[6]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[7]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[0]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[1]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[2]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[3]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[4]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[5]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[6]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[7]),
+ 			     (unsigned) ipv6->local_port,
+ 			     (unsigned) ipv6->remote_port,
+ 			     (unsigned) ipv6->protocol,
+ 			     (unsigned) ipv6->static_ip_address);
++		if (len == sizeof (*ipv6))
++		  {
++		    grub_printf (",%u,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
++			(unsigned) ipv6->prefix_length,
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[0]),
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[1]),
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[2]),
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[3]),
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[4]),
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[5]),
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[6]),
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[7]));
++		  }
++		grub_printf (")");
+ 	      }
+ 	      break;
+ 	    case GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE:
+@@ -834,6 +861,39 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
+ 	      dump_vendor_path ("Messaging",
+ 				(grub_efi_vendor_device_path_t *) dp);
+ 	      break;
++	    case GRUB_EFI_URI_DEVICE_PATH_SUBTYPE:
++	      {
++		grub_efi_uri_device_path_t *uri
++		  = (grub_efi_uri_device_path_t *) dp;
++		grub_printf ("/URI(%s)", uri->uri);
++	      }
++	      break;
++	    case GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE:
++	      {
++		grub_efi_dns_device_path_t *dns
++		  = (grub_efi_dns_device_path_t *) dp;
++		if (dns->is_ipv6)
++		  {
++		    grub_printf ("/DNS(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x)",
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0]) >> 16),
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0])),
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1]) >> 16),
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1])),
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2]) >> 16),
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2])),
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]) >> 16),
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3])));
++		  }
++		else
++		  {
++		    grub_printf ("/DNS(%d.%d.%d.%d)",
++			  dns->dns_server_ip[0].v4.addr[0],
++			  dns->dns_server_ip[0].v4.addr[1],
++			  dns->dns_server_ip[0].v4.addr[2],
++			  dns->dns_server_ip[0].v4.addr[3]);
++		  }
++	      }
++	      break;
+ 	    default:
+ 	      grub_printf ("/UnknownMessaging(%x)", (unsigned) subtype);
+ 	      break;
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index 715a6168d7..e11d759f19 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -27,6 +27,7 @@
+ #include <grub/lib/hexdump.h>
+ #include <grub/types.h>
+ #include <grub/net/netbuff.h>
++#include <grub/env.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -491,6 +492,17 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
+ 
+   ldp = grub_efi_find_last_device_path (ddp);
+ 
++  /* Skip the DNS Device */
++  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
++      && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE)
++    {
++      ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++      ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++      ldp->length = sizeof (*ldp);
++
++      ldp = grub_efi_find_last_device_path (ddp);
++    }
++
+   if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+       || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
+           && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
+@@ -760,6 +772,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 	if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+ 	    || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
+ 		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE
++		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE
+ 		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
+ 	  continue;
+ 	dup_dp = grub_efi_duplicate_device_path (dp);
+@@ -774,6 +787,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 	    dup_ldp->length = sizeof (*dup_ldp);
+ 	  }
+ 
++	dup_ldp = grub_efi_find_last_device_path (dup_dp);
++	if (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE)
++	  {
++	    dup_ldp = grub_efi_find_last_device_path (dup_dp);
++	    dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++	    dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++	    dup_ldp->length = sizeof (*dup_ldp);
++	  }
++
+ 	dup_ldp = grub_efi_find_last_device_path (dup_dp);
+ 	dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ 	dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+@@ -845,6 +867,9 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 
+ GRUB_MOD_INIT(efinet)
+ {
++  if (grub_efi_net_config)
++    return;
++
+   grub_efinet_findcards ();
+   grub_efi_net_config = grub_efi_net_config_real;
+ }
+@@ -856,5 +881,7 @@ GRUB_MOD_FINI(efinet)
+   FOR_NET_CARDS_SAFE (card, next) 
+     if (card->driver == &efidriver)
+       grub_net_card_unregister (card);
++
++  grub_efi_net_config = NULL;
+ }
+ 
+diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c
+new file mode 100644
+index 0000000000..dbef63d8c0
+--- /dev/null
++++ b/grub-core/net/efi/dhcp.c
+@@ -0,0 +1,397 @@
++#include <grub/mm.h>
++#include <grub/command.h>
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/misc.h>
++#include <grub/net/efi.h>
++#include <grub/charset.h>
++
++#ifdef GRUB_EFI_NET_DEBUG
++static void
++dhcp4_mode_print (grub_efi_dhcp4_mode_data_t *mode)
++{
++    switch (mode->state)
++      {
++	case GRUB_EFI_DHCP4_STOPPED:
++	  grub_printf ("STATE: STOPPED\n");
++	  break;
++	case GRUB_EFI_DHCP4_INIT:
++	  grub_printf ("STATE: INIT\n");
++	  break;
++	case GRUB_EFI_DHCP4_SELECTING:
++	  grub_printf ("STATE: SELECTING\n");
++	  break;
++	case GRUB_EFI_DHCP4_REQUESTING:
++	  grub_printf ("STATE: REQUESTING\n");
++	  break;
++	case GRUB_EFI_DHCP4_BOUND:
++	  grub_printf ("STATE: BOUND\n");
++	  break;
++	case GRUB_EFI_DHCP4_RENEWING:
++	  grub_printf ("STATE: RENEWING\n");
++	  break;
++	case GRUB_EFI_DHCP4_REBINDING:
++	  grub_printf ("STATE: REBINDING\n");
++	  break;
++	case GRUB_EFI_DHCP4_INIT_REBOOT:
++	  grub_printf ("STATE: INIT_REBOOT\n");
++	  break;
++	case GRUB_EFI_DHCP4_REBOOTING:
++	  grub_printf ("STATE: REBOOTING\n");
++	  break;
++	default:
++	  grub_printf ("STATE: UNKNOWN\n");
++	  break;
++      }
++
++    grub_printf ("CLIENT_ADDRESS: %u.%u.%u.%u\n",
++      mode->client_address[0],
++      mode->client_address[1],
++      mode->client_address[2],
++      mode->client_address[3]);
++    grub_printf ("SERVER_ADDRESS: %u.%u.%u.%u\n",
++      mode->server_address[0],
++      mode->server_address[1],
++      mode->server_address[2],
++      mode->server_address[3]);
++    grub_printf ("SUBNET_MASK: %u.%u.%u.%u\n",
++      mode->subnet_mask[0],
++      mode->subnet_mask[1],
++      mode->subnet_mask[2],
++      mode->subnet_mask[3]);
++    grub_printf ("ROUTER_ADDRESS: %u.%u.%u.%u\n",
++      mode->router_address[0],
++      mode->router_address[1],
++      mode->router_address[2],
++      mode->router_address[3]);
++}
++#endif
++
++static grub_efi_ipv4_address_t *
++grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packet_t *reply_packet)
++{
++  grub_efi_dhcp4_packet_option_t **option_list;
++  grub_efi_status_t status;
++  grub_efi_uint32_t option_count = 0;
++  grub_efi_uint32_t i;
++
++  status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, NULL);
++
++  if (status != GRUB_EFI_BUFFER_TOO_SMALL)
++    return NULL;
++
++  option_list = grub_malloc (option_count * sizeof(*option_list));
++  if (!option_list)
++    return NULL;
++
++  status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, option_list);
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (option_list);
++      return NULL;
++    }
++
++  for (i = 0; i < option_count; ++i)
++    {
++      if (option_list[i]->op_code == 6)
++	{
++	  grub_efi_ipv4_address_t *dns_address;
++
++	  if (((option_list[i]->length & 0x3) != 0) || (option_list[i]->length == 0))
++	    continue;
++
++	  /* We only contact primary dns */
++	  dns_address = grub_malloc (sizeof (*dns_address));
++	  if (!dns_address)
++	    {
++	      grub_free (option_list);
++	      return NULL;
++	    }
++	  grub_memcpy (dns_address, option_list[i]->data, sizeof (dns_address));
++	  grub_free (option_list);
++	  return dns_address;
++	}
++    }
++
++  grub_free (option_list);
++  return NULL;
++}
++
++#if 0
++/* Somehow this doesn't work ... */
++static grub_err_t
++grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)),
++		    int argc __attribute__ ((unused)),
++		    char **args __attribute__ ((unused)))
++{
++  struct grub_efi_net_device *dev;
++  for (dev = net_devices; dev; dev = dev->next)
++    {
++      grub_efi_pxe_t *pxe = dev->ip4_pxe;
++      grub_efi_pxe_mode_t *mode = pxe->mode;
++      grub_efi_status_t status;
++
++      if (!mode->started)
++	{
++	  status = efi_call_2 (pxe->start, pxe, 0);
++
++	  if (status != GRUB_EFI_SUCCESS)
++	      grub_printf ("Couldn't start PXE\n");
++	}
++
++      status = efi_call_2 (pxe->dhcp, pxe, 0);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("dhcp4 configure failed, %d\n", (int)status);
++	  continue;
++	}
++
++      dev->prefer_ip6 = 0;
++    }
++
++  return GRUB_ERR_NONE;
++}
++#endif
++
++static grub_err_t
++grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)),
++		    int argc,
++		    char **args)
++{
++  struct grub_efi_net_device *netdev;
++
++  for (netdev = net_devices; netdev; netdev = netdev->next)
++    {
++      grub_efi_status_t status;
++      grub_efi_dhcp4_mode_data_t mode;
++      grub_efi_dhcp4_config_data_t config;
++      grub_efi_dhcp4_packet_option_t *options;
++      grub_efi_ipv4_address_t *dns_address;
++      grub_efi_net_ip_manual_address_t net_ip;
++      grub_efi_net_ip_address_t ip_addr;
++      grub_efi_net_interface_t *inf = NULL;
++
++      if (argc > 0 && grub_strcmp (netdev->card_name, args[0]) != 0)
++	continue;
++
++      grub_memset (&config, 0, sizeof(config));
++
++      config.option_count = 1;
++      options = grub_malloc (sizeof(*options) + 2);
++      /* Parameter request list */
++      options->op_code = 55;
++      options->length = 3;
++      /* subnet mask */
++      options->data[0] = 1;
++      /* router */
++      options->data[1] = 3;
++      /* DNS */
++      options->data[2] = 6;
++      config.option_list = &options;
++
++      /* FIXME: What if the dhcp has bounded */
++      status = efi_call_2 (netdev->dhcp4->configure, netdev->dhcp4, &config);
++      grub_free (options);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("dhcp4 configure failed, %d\n", (int)status);
++	  continue;
++	}
++
++      status = efi_call_2 (netdev->dhcp4->start, netdev->dhcp4, NULL);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("dhcp4 start failed, %d\n", (int)status);
++	  continue;
++	}
++
++      status = efi_call_2 (netdev->dhcp4->get_mode_data, netdev->dhcp4, &mode);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("dhcp4 get mode failed, %d\n", (int)status);
++	  continue;
++	}
++
++#ifdef GRUB_EFI_NET_DEBUG
++      dhcp4_mode_print (&mode);
++#endif
++
++      for (inf = netdev->net_interfaces; inf; inf = inf->next)
++	if (inf->prefer_ip6 == 0)
++	  break;
++
++      grub_memcpy (net_ip.ip4.address, mode.client_address, sizeof (net_ip.ip4.address));
++      grub_memcpy (net_ip.ip4.subnet_mask, mode.subnet_mask, sizeof (net_ip.ip4.subnet_mask));
++
++      if (!inf)
++	{
++	  char *name = grub_xasprintf ("%s:dhcp", netdev->card_name);
++
++	  net_ip.is_ip6 = 0;
++	  inf = grub_efi_net_create_interface (netdev,
++		    name,
++		    &net_ip,
++		    1);
++	  grub_free (name);
++	}
++      else
++	{
++	  efi_net_interface_set_address (inf, &net_ip, 1);
++	}
++
++      grub_memcpy (ip_addr.ip4, mode.router_address, sizeof (ip_addr.ip4));
++      efi_net_interface_set_gateway (inf, &ip_addr);
++
++      dns_address = grub_efi_dhcp4_parse_dns (netdev->dhcp4, mode.reply_packet);
++      if (dns_address)
++	efi_net_interface_set_dns (inf, (grub_efi_net_ip_address_t *)&dns_address);
++
++    }
++
++  return GRUB_ERR_NONE;
++}
++
++
++static grub_err_t
++grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)),
++		    int argc,
++		    char **args)
++{
++  struct grub_efi_net_device *dev;
++  grub_efi_uint32_t ia_id;
++
++  for (dev = net_devices, ia_id = 0; dev; dev = dev->next, ia_id++)
++    {
++      grub_efi_dhcp6_config_data_t config;
++      grub_efi_dhcp6_packet_option_t *option_list[1];
++      grub_efi_dhcp6_packet_option_t *opt;
++      grub_efi_status_t status;
++      grub_efi_dhcp6_mode_data_t mode;
++      grub_efi_dhcp6_retransmission_t retrans;
++      grub_efi_net_ip_manual_address_t net_ip;
++      grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
++      grub_efi_net_interface_t *inf = NULL;
++
++      if (argc > 0 && grub_strcmp (dev->card_name, args[0]) != 0)
++	continue;
++
++      opt = grub_malloc (sizeof(*opt) + 2 * sizeof (grub_efi_uint16_t));
++
++#define GRUB_EFI_DHCP6_OPT_ORO 6
++
++      opt->op_code = grub_cpu_to_be16_compile_time (GRUB_EFI_DHCP6_OPT_ORO);
++      opt->op_len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_efi_uint16_t));
++
++#define GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL 59
++#define GRUB_EFI_DHCP6_OPT_DNS_SERVERS 23
++
++      grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL));
++      grub_set_unaligned16 (opt->data + 1 * sizeof (grub_efi_uint16_t),
++	      grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS));
++
++      option_list[0] = opt;
++      retrans.irt = 4;
++      retrans.mrc = 4;
++      retrans.mrt = 32;
++      retrans.mrd = 60;
++
++      config.dhcp6_callback = NULL;
++      config.callback_context = NULL;
++      config.option_count = 1;
++      config.option_list = option_list;
++      config.ia_descriptor.ia_id = ia_id;
++      config.ia_descriptor.type = GRUB_EFI_DHCP6_IA_TYPE_NA;
++      config.ia_info_event = NULL;
++      config.reconfigure_accept = 0;
++      config.rapid_commit = 0;
++      config.solicit_retransmission = &retrans;
++
++      status = efi_call_2 (dev->dhcp6->configure, dev->dhcp6, &config);
++      grub_free (opt);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("dhcp6 configure failed, %d\n", (int)status);
++	  continue;
++	}
++      status = efi_call_1 (dev->dhcp6->start, dev->dhcp6);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("dhcp6 start failed, %d\n", (int)status);
++	  continue;
++	}
++
++      status = efi_call_3 (dev->dhcp6->get_mode_data, dev->dhcp6, &mode, NULL);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("dhcp4 get mode failed, %d\n", (int)status);
++	  continue;
++	}
++
++      for (inf = dev->net_interfaces; inf; inf = inf->next)
++	if (inf->prefer_ip6 == 1)
++	  break;
++
++      grub_memcpy (net_ip.ip6.address, mode.ia->ia_address[0].ip_address, sizeof (net_ip.ip6.address));
++      net_ip.ip6.prefix_length = 64;
++      net_ip.ip6.is_anycast = 0;
++      net_ip.is_ip6 = 1;
++
++      if (!inf)
++	{
++	  char *name = grub_xasprintf ("%s:dhcp", dev->card_name);
++
++	  inf = grub_efi_net_create_interface (dev,
++		    name,
++		    &net_ip,
++		    1);
++	  grub_free (name);
++	}
++      else
++	{
++	  efi_net_interface_set_address (inf, &net_ip, 1);
++	}
++
++      {
++	grub_efi_uint32_t count = 0;
++	grub_efi_dhcp6_packet_option_t **options = NULL;
++	grub_efi_uint32_t i;
++
++	status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, NULL);
++
++	if (status == GRUB_EFI_BUFFER_TOO_SMALL && count)
++	  {
++	    options = grub_malloc (count * sizeof(*options));
++	    status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options);
++	  }
++
++	if (status != GRUB_EFI_SUCCESS)
++	  {
++	    if (options)
++	      grub_free (options);
++	    continue;
++	  }
++
++	for (i = 0; i < count; ++i)
++	  {
++	    if (options[i]->op_code == grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS))
++	      {
++		grub_efi_net_ip_address_t dns;
++		grub_memcpy (dns.ip6, options[i]->data, sizeof(net_ip.ip6));
++		efi_net_interface_set_dns (inf, &dns);
++		break;
++	      }
++	  }
++
++	if (options)
++	  grub_free (options);
++      }
++
++      efi_call_1 (b->free_pool, mode.client_id);
++      efi_call_1 (b->free_pool, mode.ia);
++    }
++
++  return GRUB_ERR_NONE;
++}
++
++grub_command_func_t grub_efi_net_bootp = grub_cmd_efi_bootp;
++grub_command_func_t grub_efi_net_bootp6 = grub_cmd_efi_bootp6;
+diff --git a/grub-core/net/efi/efi_netfs.c b/grub-core/net/efi/efi_netfs.c
+new file mode 100644
+index 0000000000..ef371d885e
+--- /dev/null
++++ b/grub-core/net/efi/efi_netfs.c
+@@ -0,0 +1,57 @@
++#include <grub/dl.h>
++#include <grub/env.h>
++#define EFI_NET_CMD_PREFIX "net_efi"
++#include <grub/net/efi.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++static grub_command_t cmd_efi_lsroutes;
++static grub_command_t cmd_efi_lscards;
++static grub_command_t cmd_efi_lsaddrs;
++static grub_command_t cmd_efi_addaddr;
++static grub_command_t cmd_efi_bootp;
++static grub_command_t cmd_efi_bootp6;
++
++static int initialized;
++
++GRUB_MOD_INIT(efi_netfs)
++{
++  if (grub_net_open)
++    return;
++
++  if (grub_efi_net_fs_init ())
++    {
++      cmd_efi_lsroutes = grub_register_command ("net_efi_ls_routes", grub_efi_net_list_routes,
++					    "", N_("list network routes"));
++      cmd_efi_lscards = grub_register_command ("net_efi_ls_cards", grub_efi_net_list_cards,
++					   "", N_("list network cards"));
++      cmd_efi_lsaddrs = grub_register_command ("net_efi_ls_addr", grub_efi_net_list_addrs,
++					  "", N_("list network addresses"));
++      cmd_efi_addaddr = grub_register_command ("net_efi_add_addr", grub_efi_net_add_addr,
++					  N_("SHORTNAME CARD ADDRESS [HWADDRESS]"),
++					  N_("Add a network address."));
++      cmd_efi_bootp = grub_register_command ("net_efi_bootp", grub_efi_net_bootp,
++					 N_("[CARD]"),
++					 N_("perform a bootp autoconfiguration"));
++      cmd_efi_bootp6 = grub_register_command ("net_efi_bootp6", grub_efi_net_bootp6,
++					 N_("[CARD]"),
++					 N_("perform a bootp autoconfiguration"));
++      initialized = 1;
++    }
++}
++
++GRUB_MOD_FINI(efi_netfs)
++{
++  if (initialized)
++    {
++      grub_unregister_command (cmd_efi_lsroutes);
++      grub_unregister_command (cmd_efi_lscards);
++      grub_unregister_command (cmd_efi_lsaddrs);
++      grub_unregister_command (cmd_efi_addaddr);
++      grub_unregister_command (cmd_efi_bootp);
++      grub_unregister_command (cmd_efi_bootp6);
++      grub_efi_net_fs_fini ();
++      initialized = 0;
++      return;
++    }
++}
+diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
+new file mode 100644
+index 0000000000..3f61fd2fa5
+--- /dev/null
++++ b/grub-core/net/efi/http.c
+@@ -0,0 +1,419 @@
++
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/misc.h>
++#include <grub/net/efi.h>
++#include <grub/charset.h>
++
++static void
++http_configure (struct grub_efi_net_device *dev, int prefer_ip6)
++{
++  grub_efi_http_config_data_t http_config;
++  grub_efi_httpv4_access_point_t httpv4_node;
++  grub_efi_httpv6_access_point_t httpv6_node;
++  grub_efi_status_t status;
++
++  grub_efi_http_t *http = dev->http;
++
++  grub_memset (&http_config, 0, sizeof(http_config));
++  http_config.http_version = GRUB_EFI_HTTPVERSION11;
++  http_config.timeout_millisec = 5000;
++
++  if (prefer_ip6)
++    {
++      grub_efi_uintn_t sz;
++      grub_efi_ip6_config_manual_address_t manual_address;
++
++      http_config.local_address_is_ipv6 = 1;
++      sz = sizeof (manual_address);
++      status = efi_call_4 (dev->ip6_config->get_data, dev->ip6_config,
++			GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
++			&sz, &manual_address);
++
++      if (status == GRUB_EFI_NOT_FOUND)
++	{
++	  grub_printf ("The MANUAL ADDRESS is not found\n");
++	}
++
++      /* FIXME: The manual interface would return BUFFER TOO SMALL !!! */
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("??? %d\n",(int) status);
++	  return;
++	}
++
++      grub_memcpy (httpv6_node.local_address, manual_address.address, sizeof (httpv6_node.local_address));
++      httpv6_node.local_port = 0;
++      http_config.access_point.ipv6_node = &httpv6_node;
++    }
++  else
++    {
++      http_config.local_address_is_ipv6 = 0;
++      grub_memset (&httpv4_node, 0, sizeof(httpv4_node));
++      httpv4_node.use_default_address = 1;
++
++      /* Use random port here */
++      /* See TcpBind() in edk2/NetworkPkg/TcpDxe/TcpDispatcher.c */
++      httpv4_node.local_port = 0;
++      http_config.access_point.ipv4_node = &httpv4_node;
++    }
++
++  status = efi_call_2 (http->configure, http, &http_config);
++
++  if (status == GRUB_EFI_ALREADY_STARTED)
++    {
++      /* XXX: This hangs HTTPS boot */
++#if 0
++      if (efi_call_2 (http->configure, http, NULL) != GRUB_EFI_SUCCESS)
++	{
++	  grub_error (GRUB_ERR_IO, N_("couldn't reset http instance"));
++	  grub_print_error ();
++	  return;
++	}
++      status = efi_call_2 (http->configure, http, &http_config);
++#endif
++      return;
++    }
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_error (GRUB_ERR_IO, N_("couldn't configure http protocol, reason: %d"), (int)status);
++      grub_print_error ();
++      return ;
++    }
++}
++
++static grub_efi_boolean_t request_callback_done;
++static grub_efi_boolean_t response_callback_done;
++
++static void
++grub_efi_http_request_callback (grub_efi_event_t event __attribute__ ((unused)),
++				void *context __attribute__ ((unused)))
++{
++  request_callback_done = 1;
++}
++
++static void
++grub_efi_http_response_callback (grub_efi_event_t event __attribute__ ((unused)),
++				void *context __attribute__ ((unused)))
++{
++  response_callback_done = 1;
++}
++
++static grub_err_t
++efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, int headeronly, grub_off_t *file_size)
++{
++  grub_efi_http_request_data_t request_data;
++  grub_efi_http_message_t request_message;
++  grub_efi_http_token_t request_token;
++  grub_efi_http_response_data_t response_data;
++  grub_efi_http_message_t response_message;
++  grub_efi_http_token_t response_token;
++  grub_efi_http_header_t request_headers[3];
++
++  grub_efi_status_t status;
++  grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
++  char *url = NULL;
++
++  request_headers[0].field_name = (grub_efi_char8_t *)"Host";
++  request_headers[0].field_value = (grub_efi_char8_t *)server;
++  request_headers[1].field_name = (grub_efi_char8_t *)"Accept";
++  request_headers[1].field_value = (grub_efi_char8_t *)"*/*";
++  request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent";
++  request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0";
++
++  {
++    grub_efi_ipv6_address_t address;
++    const char *rest;
++    grub_efi_char16_t *ucs2_url;
++    grub_size_t url_len, ucs2_url_len;
++    const char *protocol = (use_https == 1) ? "https" : "http";
++
++    if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0)
++      url = grub_xasprintf ("%s://[%s]%s", protocol, server, name);
++    else
++      url = grub_xasprintf ("%s://%s%s", protocol, server, name);
++
++    if (!url)
++      {
++	return grub_errno;
++      }
++
++    url_len = grub_strlen (url);
++    ucs2_url_len = url_len * GRUB_MAX_UTF16_PER_UTF8;
++    ucs2_url = grub_malloc ((ucs2_url_len + 1) * sizeof (ucs2_url[0]));
++
++    if (!ucs2_url)
++      {
++	grub_free (url);
++	return grub_errno;
++      }
++
++    ucs2_url_len = grub_utf8_to_utf16 (ucs2_url, ucs2_url_len, (grub_uint8_t *)url, url_len, NULL); /* convert string format from ascii to usc2 */
++    ucs2_url[ucs2_url_len] = 0;
++    grub_free (url);
++    request_data.url = ucs2_url;
++  }
++
++  request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET;
++
++  request_message.data.request = &request_data;
++  request_message.header_count = 3;
++  request_message.headers = request_headers;
++  request_message.body_length = 0;
++  request_message.body = NULL;
++
++  /* request token */
++  request_token.event = NULL;
++  request_token.status = GRUB_EFI_NOT_READY;
++  request_token.message = &request_message;
++
++  request_callback_done = 0;
++  status = efi_call_5 (b->create_event,
++                       GRUB_EFI_EVT_NOTIFY_SIGNAL,
++                       GRUB_EFI_TPL_CALLBACK,
++                       grub_efi_http_request_callback,
++                       NULL,
++                       &request_token.event);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (request_data.url);
++      return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status);
++    }
++
++  status = efi_call_2 (http->request, http, &request_token);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      efi_call_1 (b->close_event, request_token.event);
++      grub_free (request_data.url);
++      return grub_error (GRUB_ERR_IO, "Fail to send a request! status=0x%x\n", status);
++    }
++  /* TODO: Add Timeout */
++  while (!request_callback_done)
++    efi_call_1(http->poll, http);
++
++  response_data.status_code = GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS;
++  response_message.data.response = &response_data;
++  /* herader_count will be updated by the HTTP driver on response */
++  response_message.header_count = 0;
++  /* headers will be populated by the driver on response */
++  response_message.headers = NULL;
++  /* use zero BodyLength to only receive the response headers */
++  response_message.body_length = 0;
++  response_message.body = NULL;
++  response_token.event = NULL;
++
++  status = efi_call_5 (b->create_event,
++              GRUB_EFI_EVT_NOTIFY_SIGNAL,
++              GRUB_EFI_TPL_CALLBACK,
++              grub_efi_http_response_callback,
++              NULL,
++              &response_token.event);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      efi_call_1 (b->close_event, request_token.event);
++      grub_free (request_data.url);
++      return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status);
++    }
++
++  response_token.status = GRUB_EFI_SUCCESS;
++  response_token.message = &response_message;
++
++  /* wait for HTTP response */
++  response_callback_done = 0;
++  status = efi_call_2 (http->response, http, &response_token);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      efi_call_1 (b->close_event, response_token.event);
++      efi_call_1 (b->close_event, request_token.event);
++      grub_free (request_data.url);
++      return grub_error (GRUB_ERR_IO, "Fail to receive a response! status=%d\n", (int)status);
++    }
++
++  /* TODO: Add Timeout */
++  while (!response_callback_done)
++    efi_call_1 (http->poll, http);
++
++  if (response_message.data.response->status_code != GRUB_EFI_HTTP_STATUS_200_OK)
++    {
++      grub_efi_http_status_code_t status_code = response_message.data.response->status_code;
++
++      if (response_message.headers)
++	efi_call_1 (b->free_pool, response_message.headers);
++      efi_call_1 (b->close_event, response_token.event);
++      efi_call_1 (b->close_event, request_token.event);
++      grub_free (request_data.url);
++      if (status_code == GRUB_EFI_HTTP_STATUS_404_NOT_FOUND)
++	{
++	  return grub_error (GRUB_ERR_FILE_NOT_FOUND, _("file `%s' not found"), name);
++	}
++      else
++	{
++	  return grub_error (GRUB_ERR_NET_UNKNOWN_ERROR,
++		  _("unsupported uefi http status code 0x%x"), status_code);
++	}
++    }
++
++  if (file_size)
++    {
++      int i;
++      /* parse the length of the file from the ContentLength header */
++      for (*file_size = 0, i = 0; i < (int)response_message.header_count; ++i)
++	{
++	  if (!grub_strcmp((const char*)response_message.headers[i].field_name, "Content-Length"))
++	    {
++	      *file_size = grub_strtoul((const char*)response_message.headers[i].field_value, 0, 10);
++	      break;
++	    }
++	}
++    }
++
++  if (response_message.headers)
++    efi_call_1 (b->free_pool, response_message.headers);
++  efi_call_1 (b->close_event, response_token.event);
++  efi_call_1 (b->close_event, request_token.event);
++  grub_free (request_data.url);
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_ssize_t
++efihttp_read (struct grub_efi_net_device *dev,
++		  char *buf,
++		  grub_size_t len)
++{
++  grub_efi_http_message_t response_message;
++  grub_efi_http_token_t response_token;
++
++  grub_efi_status_t status;
++  grub_size_t sum = 0;
++  grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
++  grub_efi_http_t *http = dev->http;
++
++  if (!len)
++    {
++      grub_error (GRUB_ERR_BUG, "Invalid arguments to EFI HTTP Read");
++      return -1;
++    }
++
++  efi_call_5 (b->create_event,
++              GRUB_EFI_EVT_NOTIFY_SIGNAL,
++              GRUB_EFI_TPL_CALLBACK,
++              grub_efi_http_response_callback,
++              NULL,
++              &response_token.event);
++
++  while (len)
++    {
++      response_message.data.response = NULL;
++      response_message.header_count = 0;
++      response_message.headers = NULL;
++      response_message.body_length = len;
++      response_message.body = buf;
++
++      response_token.message = &response_message;
++      response_token.status = GRUB_EFI_NOT_READY;
++
++      response_callback_done = 0;
++
++      status = efi_call_2 (http->response, http, &response_token);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  efi_call_1 (b->close_event, response_token.event);
++	  grub_error (GRUB_ERR_IO, "Error! status=%d\n", (int)status);
++	  return -1;
++	}
++
++      while (!response_callback_done)
++	efi_call_1(http->poll, http);
++
++      sum += response_message.body_length;
++      buf += response_message.body_length;
++      len -= response_message.body_length;
++    }
++
++  efi_call_1 (b->close_event, response_token.event);
++
++  return sum;
++}
++
++static grub_err_t
++grub_efihttp_open (struct grub_efi_net_device *dev,
++		  int prefer_ip6 __attribute__ ((unused)),
++		  grub_file_t file,
++		  const char *filename __attribute__ ((unused)),
++		  int type)
++{
++  grub_err_t err;
++  grub_off_t size;
++  char *buf;
++
++  err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0);
++  if (err != GRUB_ERR_NONE)
++    return err;
++
++  err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size);
++  if (err != GRUB_ERR_NONE)
++    return err;
++
++  buf = grub_malloc (size);
++  efihttp_read (dev, buf, size);
++
++  file->size = size;
++  file->data = buf;
++  file->not_easily_seekable = 0;
++  file->device->net->offset = 0;
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_efihttp_close (struct grub_efi_net_device *dev __attribute__ ((unused)),
++		    int prefer_ip6 __attribute__ ((unused)),
++		    grub_file_t file)
++{
++  if (file->data)
++    grub_free (file->data);
++
++  file->data = 0;
++  file->offset = 0;
++  file->size = 0;
++  file->device->net->offset = 0;
++  return GRUB_ERR_NONE;
++}
++
++static grub_ssize_t
++grub_efihttp_read (struct grub_efi_net_device *dev __attribute__((unused)),
++		  int prefer_ip6 __attribute__((unused)),
++		  grub_file_t file,
++		  char *buf,
++		  grub_size_t len)
++{
++  grub_size_t r = len;
++
++  if (!file->data || !buf || !len)
++    return 0;
++
++  if ((file->device->net->offset + len) > file->size)
++    r = file->size - file->device->net->offset;
++
++  if (r)
++    {
++      grub_memcpy (buf, (char *)file->data + file->device->net->offset, r);
++      file->device->net->offset += r;
++    }
++
++  return r;
++}
++
++struct grub_efi_net_io io_http =
++  {
++    .configure = http_configure,
++    .open = grub_efihttp_open,
++    .read = grub_efihttp_read,
++    .close = grub_efihttp_close
++  };
+diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c
+new file mode 100644
+index 0000000000..b711a5d945
+--- /dev/null
++++ b/grub-core/net/efi/ip4_config.c
+@@ -0,0 +1,398 @@
++
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/misc.h>
++#include <grub/net/efi.h>
++#include <grub/charset.h>
++
++char *
++grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address)
++{
++  char *hw_addr, *p;
++  int sz, s;
++  int i;
++
++  sz = (int)hw_address_size * (sizeof ("XX:") - 1) + 1;
++
++  hw_addr = grub_malloc (sz);
++  if (!hw_addr)
++    return NULL;
++
++  p = hw_addr;
++  s = sz;
++  for (i = 0; i < (int)hw_address_size; i++)
++    {
++      grub_snprintf (p, sz, "%02x:", hw_address[i]);
++      p +=  sizeof ("XX:") - 1;
++      s -=  sizeof ("XX:") - 1;
++    }
++
++  hw_addr[sz - 2] = '\0';
++  return hw_addr;
++}
++
++char *
++grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address)
++{
++  char *addr;
++
++  addr = grub_malloc (sizeof ("XXX.XXX.XXX.XXX"));
++  if (!addr)
++      return NULL;
++
++  /* FIXME: Use grub_xasprintf ? */
++  grub_snprintf (addr,
++	  sizeof ("XXX.XXX.XXX.XXX"),
++	  "%u.%u.%u.%u",
++	  (*address)[0],
++	  (*address)[1],
++	  (*address)[2],
++	  (*address)[3]);
++
++  return addr;
++}
++
++int
++grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest)
++{
++  grub_uint32_t newip = 0;
++  int i;
++  const char *ptr = val;
++
++  for (i = 0; i < 4; i++)
++    {
++      unsigned long t;
++      t = grub_strtoul (ptr, (char **) &ptr, 0);
++      if (grub_errno)
++	{
++	  grub_errno = GRUB_ERR_NONE;
++	  return 0;
++	}
++      if (*ptr != '.' && i == 0)
++	{
++	  /* XXX: t is in host byte order */
++	  newip = t;
++	  break;
++	}
++      if (t & ~0xff)
++	return 0;
++      newip <<= 8;
++      newip |= t;
++      if (i != 3 && *ptr != '.')
++	return 0;
++      ptr++;
++    }
++
++  newip =  grub_cpu_to_be32 (newip);
++
++  grub_memcpy (address, &newip, sizeof(*address));
++
++  if (rest)
++    *rest = (ptr - 1);
++  return 1;
++}
++
++static grub_efi_ip4_config2_interface_info_t *
++efi_ip4_config_interface_info (grub_efi_ip4_config2_protocol_t *ip4_config)
++{
++  grub_efi_uintn_t sz;
++  grub_efi_status_t status;
++  grub_efi_ip4_config2_interface_info_t *interface_info;
++
++  sz = sizeof (*interface_info) + sizeof (*interface_info->route_table);
++  interface_info = grub_malloc (sz);
++  if (!interface_info)
++    return NULL;
++
++  status = efi_call_4 (ip4_config->get_data, ip4_config,
++		GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
++		&sz, interface_info);
++
++  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
++    {
++      grub_free (interface_info);
++      interface_info = grub_malloc (sz);
++      status = efi_call_4 (ip4_config->get_data, ip4_config,
++		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
++		    &sz, interface_info);
++    }
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (interface_info);
++      return NULL;
++    }
++
++  return interface_info;
++}
++
++static grub_efi_ip4_config2_manual_address_t *
++efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config)
++{
++  grub_efi_uintn_t sz;
++  grub_efi_status_t status;
++  grub_efi_ip4_config2_manual_address_t *manual_address;
++
++  sz = sizeof (*manual_address);
++  manual_address = grub_malloc (sz);
++  if (!manual_address)
++    return NULL;
++
++  status = efi_call_4 (ip4_config->get_data, ip4_config,
++		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
++		    &sz, manual_address);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (manual_address);
++      return NULL;
++    }
++
++  return manual_address;
++}
++
++char *
++grub_efi_ip4_interface_name (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip4_config2_interface_info_t *interface_info;
++  char *name;
++
++  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
++
++  if (!interface_info)
++    return NULL;
++
++  name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE
++		      * GRUB_MAX_UTF8_PER_UTF16 + 1);
++  *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name,
++		      GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0;
++  grub_free (interface_info);
++  return name;
++}
++
++static char *
++grub_efi_ip4_interface_hw_address (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip4_config2_interface_info_t *interface_info;
++  char *hw_addr;
++
++  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
++
++  if (!interface_info)
++    return NULL;
++
++  hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address);
++  grub_free (interface_info);
++
++  return hw_addr;
++}
++
++static char *
++grub_efi_ip4_interface_address (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip4_config2_manual_address_t *manual_address;
++  char *addr;
++
++  manual_address = efi_ip4_config_manual_address (dev->ip4_config);
++
++  if (!manual_address)
++    return NULL;
++
++  addr = grub_efi_ip4_address_to_string (&manual_address->address);
++  grub_free (manual_address);
++  return addr;
++}
++
++
++static int
++address_mask_size (grub_efi_ipv4_address_t *address)
++{
++  grub_uint8_t i;
++  grub_uint32_t u32_addr = grub_be_to_cpu32 (grub_get_unaligned32 (address));
++
++  if (u32_addr == 0)
++    return 0;
++
++  for (i = 0; i < 32 ; ++i)
++    {
++      if (u32_addr == ((0xffffffff >> i) << i))
++	return (32 - i);
++    }
++
++  return -1;
++}
++
++static char **
++grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip4_config2_interface_info_t *interface_info;
++  char **ret;
++  int i, id;
++
++  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
++  if (!interface_info)
++    return NULL;
++
++  ret = grub_malloc (sizeof (*ret) * (interface_info->route_table_size + 1));
++
++  if (!ret)
++    {
++      grub_free (interface_info);
++      return NULL;
++    }
++
++  id = 0;
++  for (i = 0; i < (int)interface_info->route_table_size; i++)
++    {
++      char *subnet, *gateway, *mask;
++      grub_uint32_t u32_subnet, u32_gateway;
++      int mask_size;
++      grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i;
++      grub_efi_net_interface_t *inf;
++      char *interface_name = NULL;
++
++      for (inf = dev->net_interfaces; inf; inf = inf->next)
++	if (!inf->prefer_ip6)
++	  interface_name = inf->name;
++
++      u32_gateway = grub_get_unaligned32 (&route_table->gateway_address);
++      gateway = grub_efi_ip4_address_to_string (&route_table->gateway_address);
++      u32_subnet = grub_get_unaligned32 (&route_table->subnet_address);
++      subnet = grub_efi_ip4_address_to_string (&route_table->subnet_address);
++      mask_size = address_mask_size (&route_table->subnet_mask);
++      mask = grub_efi_ip4_address_to_string (&route_table->subnet_mask);
++      if (u32_subnet && !u32_gateway && interface_name)
++	ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, subnet, mask_size, interface_name);
++      else if (u32_subnet && u32_gateway)
++	ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, subnet, mask_size, gateway);
++      else if (!u32_subnet && u32_gateway)
++	ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, subnet, mask_size, gateway);
++      grub_free (subnet);
++      grub_free (gateway);
++      grub_free (mask);
++    }
++
++  ret[id] = NULL;
++  grub_free (interface_info);
++  return ret;
++}
++
++static grub_efi_net_interface_t *
++grub_efi_ip4_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address)
++{
++  grub_efi_ip4_config2_interface_info_t *interface_info;
++  grub_efi_net_interface_t *inf;
++  int i;
++  grub_efi_ipv4_address_t *address = &ip_address->ip4;
++
++  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
++  if (!interface_info)
++    return NULL;
++
++  for (i = 0; i < (int)interface_info->route_table_size; i++)
++    {
++      grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i;
++      grub_uint32_t u32_address, u32_mask, u32_subnet;
++
++      u32_address = grub_get_unaligned32 (address);
++      u32_subnet = grub_get_unaligned32 (route_table->subnet_address);
++      u32_mask = grub_get_unaligned32 (route_table->subnet_mask);
++
++      /* SKIP Default GATEWAY */
++      if (!u32_subnet && !u32_mask)
++	continue;
++
++      if ((u32_address & u32_mask) == u32_subnet)
++	{
++	  for (inf = dev->net_interfaces; inf; inf = inf->next)
++	    if (!inf->prefer_ip6)
++	      {
++		grub_free (interface_info);
++		return inf;
++	      }
++	}
++    }
++
++  grub_free (interface_info);
++  return NULL;
++}
++
++static int
++grub_efi_ip4_interface_set_manual_address (struct grub_efi_net_device *dev,
++	    grub_efi_net_ip_manual_address_t *net_ip,
++	    int with_subnet)
++{
++  grub_efi_status_t status;
++  grub_efi_ip4_config2_manual_address_t *address = &net_ip->ip4;
++
++  if (!with_subnet)
++    {
++      grub_efi_ip4_config2_manual_address_t *manual_address =
++      efi_ip4_config_manual_address (dev->ip4_config);
++
++      if (manual_address)
++	{
++	  grub_memcpy (address->subnet_mask, manual_address->subnet_mask, sizeof(address->subnet_mask));
++	  grub_free (manual_address);
++	}
++      else
++	{
++	  /* XXX: */
++	  address->subnet_mask[0] = 0xff;
++	  address->subnet_mask[1] = 0xff;
++	  address->subnet_mask[2] = 0xff;
++	  address->subnet_mask[3] = 0;
++	}
++    }
++
++  status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
++		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
++		    sizeof(*address), address);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++
++  return 1;
++}
++
++static int
++grub_efi_ip4_interface_set_gateway (struct grub_efi_net_device *dev,
++	      grub_efi_net_ip_address_t *address)
++{
++  grub_efi_status_t status;
++
++  status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
++		GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY,
++		sizeof (address->ip4), &address->ip4);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++  return 1;
++}
++
++/* FIXME: Multiple DNS */
++static int
++grub_efi_ip4_interface_set_dns (struct grub_efi_net_device *dev,
++	      grub_efi_net_ip_address_t *address)
++{
++  grub_efi_status_t status;
++
++  status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
++		GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
++		sizeof (address->ip4), &address->ip4);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++  return 1;
++}
++
++grub_efi_net_ip_config_t *efi_net_ip4_config = &(grub_efi_net_ip_config_t)
++  {
++    .get_hw_address = grub_efi_ip4_interface_hw_address,
++    .get_address = grub_efi_ip4_interface_address,
++    .get_route_table = grub_efi_ip4_interface_route_table,
++    .best_interface = grub_efi_ip4_interface_match,
++    .set_address = grub_efi_ip4_interface_set_manual_address,
++    .set_gateway = grub_efi_ip4_interface_set_gateway,
++    .set_dns = grub_efi_ip4_interface_set_dns
++  };
+diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c
+new file mode 100644
+index 0000000000..017c4d05bc
+--- /dev/null
++++ b/grub-core/net/efi/ip6_config.c
+@@ -0,0 +1,422 @@
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/misc.h>
++#include <grub/net/efi.h>
++#include <grub/charset.h>
++
++char *
++grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address)
++{
++  char *str = grub_malloc (sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX"));
++  char *p;
++  int i;
++  int squash;
++
++  if (!str)
++    return NULL;
++
++  p = str;
++  squash = 0;
++  for (i = 0; i < 8; ++i)
++    {
++      grub_uint16_t addr;
++
++      if (i == 7)
++	squash = 2;
++
++      addr = grub_get_unaligned16 (address->addr + i * 2);
++
++      if (grub_be_to_cpu16 (addr))
++	{
++	  char buf[sizeof ("XXXX")];
++	  if (i > 0)
++	    *p++ = ':';
++	  grub_snprintf (buf, sizeof (buf), "%x", grub_be_to_cpu16 (addr));
++	  grub_strcpy (p, buf);
++	  p += grub_strlen (buf);
++
++	  if (squash == 1)
++	    squash = 2;
++	}
++      else
++	{
++	  if (squash == 0)
++	    {
++	      *p++ = ':';
++	      squash = 1;
++	    }
++	  else if (squash == 2)
++	    {
++	      *p++ = ':';
++	      *p++ = '0';
++	    }
++	}
++    }
++  *p = '\0';
++  return str;
++}
++
++int
++grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest)
++{
++  grub_uint16_t newip[8];
++  const char *ptr = val;
++  int word, quaddot = -1;
++  int bracketed = 0;
++
++  if (ptr[0] == '[') {
++    bracketed = 1;
++    ptr++;
++  }
++
++  if (ptr[0] == ':' && ptr[1] != ':')
++    return 0;
++  if (ptr[0] == ':')
++    ptr++;
++
++  for (word = 0; word < 8; word++)
++    {
++      unsigned long t;
++      if (*ptr == ':')
++	{
++	  quaddot = word;
++	  word--;
++	  ptr++;
++	  continue;
++	}
++      t = grub_strtoul (ptr, (char **) &ptr, 16);
++      if (grub_errno)
++	{
++	  grub_errno = GRUB_ERR_NONE;
++	  break;
++	}
++      if (t & ~0xffff)
++	return 0;
++      newip[word] = grub_cpu_to_be16 (t);
++      if (*ptr != ':')
++	break;
++      ptr++;
++    }
++  if (quaddot == -1 && word < 7)
++    return 0;
++  if (quaddot != -1)
++    {
++      grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot],
++		    (word - quaddot + 1) * sizeof (newip[0]));
++      grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
++    }
++  grub_memcpy (address, newip, 16);
++  if (bracketed && *ptr == ']') {
++    ptr++;
++  }
++  if (rest)
++    *rest = ptr;
++  return 1;
++}
++
++static grub_efi_ip6_config_interface_info_t *
++efi_ip6_config_interface_info (grub_efi_ip6_config_protocol_t *ip6_config)
++{
++  grub_efi_uintn_t sz;
++  grub_efi_status_t status;
++  grub_efi_ip6_config_interface_info_t *interface_info;
++
++  sz = sizeof (*interface_info) + sizeof (*interface_info->route_table);
++  interface_info = grub_malloc (sz);
++
++  status = efi_call_4 (ip6_config->get_data, ip6_config,
++		GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
++		&sz, interface_info);
++
++  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
++    {
++      grub_free (interface_info);
++      interface_info = grub_malloc (sz);
++      status = efi_call_4 (ip6_config->get_data, ip6_config,
++		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
++		    &sz, interface_info);
++    }
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (interface_info);
++      return NULL;
++    }
++
++  return interface_info;
++}
++
++static grub_efi_ip6_config_manual_address_t *
++efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config)
++{
++  grub_efi_uintn_t sz;
++  grub_efi_status_t status;
++  grub_efi_ip6_config_manual_address_t *manual_address;
++
++  sz = sizeof (*manual_address);
++  manual_address = grub_malloc (sz);
++  if (!manual_address)
++    return NULL;
++
++  status = efi_call_4 (ip6_config->get_data, ip6_config,
++		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
++		    &sz, manual_address);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (manual_address);
++      return NULL;
++    }
++
++  return manual_address;
++}
++
++char *
++grub_efi_ip6_interface_name (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip6_config_interface_info_t *interface_info;
++  char *name;
++
++  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
++
++  if (!interface_info)
++    return NULL;
++
++  name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE
++		      * GRUB_MAX_UTF8_PER_UTF16 + 1);
++  *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name,
++		      GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0;
++  grub_free (interface_info);
++  return name;
++}
++
++static char *
++grub_efi_ip6_interface_hw_address (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip6_config_interface_info_t *interface_info;
++  char *hw_addr;
++
++  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
++
++  if (!interface_info)
++    return NULL;
++
++  hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address);
++  grub_free (interface_info);
++
++  return hw_addr;
++}
++
++static char *
++grub_efi_ip6_interface_address (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip6_config_manual_address_t *manual_address;
++  char *addr;
++
++  manual_address = efi_ip6_config_manual_address (dev->ip6_config);
++
++  if (!manual_address)
++    return NULL;
++
++  addr = grub_efi_ip6_address_to_string ((grub_efi_pxe_ipv6_address_t *)&manual_address->address);
++  grub_free (manual_address);
++  return addr;
++}
++
++static char **
++grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip6_config_interface_info_t *interface_info;
++  char **ret;
++  int i, id;
++
++  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
++  if (!interface_info)
++    return NULL;
++
++  ret = grub_malloc (sizeof (*ret) * (interface_info->route_count + 1));
++
++  if (!ret)
++    {
++      grub_free (interface_info);
++      return NULL;
++    }
++
++  id = 0;
++  for (i = 0; i < (int)interface_info->route_count ; i++)
++    {
++      char *gateway, *destination;
++      grub_uint64_t u64_gateway[2];
++      grub_uint64_t u64_destination[2];
++      grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i;
++      grub_efi_net_interface_t *inf;
++      char *interface_name = NULL;
++
++      gateway = grub_efi_ip6_address_to_string (&route_table->gateway);
++      destination = grub_efi_ip6_address_to_string (&route_table->destination);
++
++      u64_gateway[0] = grub_get_unaligned64 (route_table->gateway.addr);
++      u64_gateway[1] = grub_get_unaligned64 (route_table->gateway.addr + 8);
++      u64_destination[0] = grub_get_unaligned64 (route_table->destination.addr);
++      u64_destination[1] = grub_get_unaligned64 (route_table->destination.addr + 8);
++
++      for (inf = dev->net_interfaces; inf; inf = inf->next)
++	if (inf->prefer_ip6)
++	  interface_name = inf->name;
++
++      if ((!u64_gateway[0] && !u64_gateway[1])
++	  && (u64_destination[0] || u64_destination[1]))
++	{
++	  if (interface_name)
++	    {
++	      if ((grub_be_to_cpu64 (u64_destination[0]) == 0xfe80000000000000ULL)
++	      && (!u64_destination[1])
++	      && (route_table->prefix_length == 64))
++		ret[id++] = grub_xasprintf ("%s:link %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name);
++	      else
++		ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name);
++	    }
++	}
++      else if ((u64_gateway[0] || u64_gateway[1])
++	  && (u64_destination[0] || u64_destination[1]))
++	ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway);
++      else if ((u64_gateway[0] || u64_gateway[1])
++	  && (!u64_destination[0] && !u64_destination[1]))
++	ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway);
++
++      grub_free (gateway);
++      grub_free (destination);
++    }
++
++  ret[id] = NULL;
++  grub_free (interface_info);
++  return ret;
++}
++
++static grub_efi_net_interface_t *
++grub_efi_ip6_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address)
++{
++  grub_efi_ip6_config_interface_info_t *interface_info;
++  grub_efi_net_interface_t *inf;
++  int i;
++  grub_efi_ipv6_address_t *address = &ip_address->ip6;
++
++  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
++  if (!interface_info)
++    return NULL;
++
++  for (i = 0; i < (int)interface_info->route_count ; i++)
++    {
++      grub_uint64_t u64_addr[2];
++      grub_uint64_t u64_subnet[2];
++      grub_uint64_t u64_mask[2];
++
++      grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i;
++
++      /* SKIP Default GATEWAY */
++      if (route_table->prefix_length == 0)
++	continue;
++
++      u64_addr[0] = grub_get_unaligned64 (address);
++      u64_addr[1] = grub_get_unaligned64 (address + 4);
++      u64_subnet[0] = grub_get_unaligned64 (route_table->destination.addr);
++      u64_subnet[1] = grub_get_unaligned64 (route_table->destination.addr + 8);
++      u64_mask[0] = (route_table->prefix_length <= 64) ?
++	    0xffffffffffffffffULL << (64 - route_table->prefix_length) :
++	    0xffffffffffffffffULL;
++      u64_mask[1] = (route_table->prefix_length <= 64) ?
++	    0 :
++	    0xffffffffffffffffULL << (128 - route_table->prefix_length);
++
++      if (((u64_addr[0] & u64_mask[0]) == u64_subnet[0])
++	  && ((u64_addr[1] & u64_mask[1]) == u64_subnet[1]))
++	{
++	  for (inf = dev->net_interfaces; inf; inf = inf->next)
++	    if (inf->prefer_ip6)
++	      {
++		grub_free (interface_info);
++		return inf;
++	      }
++	}
++    }
++
++  grub_free (interface_info);
++  return NULL;
++}
++
++static int
++grub_efi_ip6_interface_set_manual_address (struct grub_efi_net_device *dev,
++	    grub_efi_net_ip_manual_address_t *net_ip,
++	    int with_subnet)
++{
++  grub_efi_status_t status;
++  grub_efi_ip6_config_manual_address_t *address = &net_ip->ip6;
++
++  if (!with_subnet)
++    {
++      grub_efi_ip6_config_manual_address_t *manual_address =
++      efi_ip6_config_manual_address (dev->ip6_config);
++
++      if (manual_address)
++	{
++	  address->prefix_length = manual_address->prefix_length;
++	  grub_free (manual_address);
++	}
++      else
++	{
++	  /* XXX: */
++	  address->prefix_length = 64;
++	}
++    }
++
++  status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
++		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
++		    sizeof(*address), address);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++
++  return 1;
++}
++
++static int
++grub_efi_ip6_interface_set_gateway (struct grub_efi_net_device *dev,
++	      grub_efi_net_ip_address_t *address)
++{
++  grub_efi_status_t status;
++
++  status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
++		GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY,
++		sizeof (address->ip6), &address->ip6);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++  return 1;
++}
++
++static int
++grub_efi_ip6_interface_set_dns (struct grub_efi_net_device *dev,
++	      grub_efi_net_ip_address_t *address)
++{
++
++  grub_efi_status_t status;
++
++  status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
++		GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
++		sizeof (address->ip6), &address->ip6);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++  return 1;
++}
++
++grub_efi_net_ip_config_t *efi_net_ip6_config = &(grub_efi_net_ip_config_t)
++  {
++    .get_hw_address = grub_efi_ip6_interface_hw_address,
++    .get_address = grub_efi_ip6_interface_address,
++    .get_route_table = grub_efi_ip6_interface_route_table,
++    .best_interface = grub_efi_ip6_interface_match,
++    .set_address = grub_efi_ip6_interface_set_manual_address,
++    .set_gateway = grub_efi_ip6_interface_set_gateway,
++    .set_dns = grub_efi_ip6_interface_set_dns
++  };
+diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
+new file mode 100644
+index 0000000000..86bce6535d
+--- /dev/null
++++ b/grub-core/net/efi/net.c
+@@ -0,0 +1,1428 @@
++#include <grub/net.h>
++#include <grub/env.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/dl.h>
++#include <grub/command.h>
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/i18n.h>
++#include <grub/bufio.h>
++#include <grub/efi/http.h>
++#include <grub/efi/dhcp.h>
++#include <grub/net/efi.h>
++#include <grub/charset.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++#define GRUB_EFI_IP6_PREFIX_LENGTH 64
++
++static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID;
++static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID;
++static grub_efi_guid_t http_service_binding_guid = GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID;
++static grub_efi_guid_t http_guid = GRUB_EFI_HTTP_PROTOCOL_GUID;
++static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID;
++static grub_efi_guid_t dhcp4_service_binding_guid = GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID;
++static grub_efi_guid_t dhcp4_guid = GRUB_EFI_DHCP4_PROTOCOL_GUID;
++static grub_efi_guid_t dhcp6_service_binding_guid = GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID;
++static grub_efi_guid_t dhcp6_guid = GRUB_EFI_DHCP6_PROTOCOL_GUID;
++
++struct grub_efi_net_device *net_devices;
++
++static char *default_server;
++static grub_efi_net_interface_t *net_interface;
++static grub_efi_net_interface_t *net_default_interface;
++
++#define efi_net_interface_configure(inf) inf->io->configure (inf->dev, inf->prefer_ip6)
++#define efi_net_interface_open(inf, file, name) inf->io->open (inf->dev, inf->prefer_ip6, file, name, inf->io_type)
++#define efi_net_interface_read(inf, file, buf, sz) inf->io->read (inf->dev, inf->prefer_ip6, file, buf, sz)
++#define efi_net_interface_close(inf, file) inf->io->close (inf->dev, inf->prefer_ip6, file)
++#define efi_net_interface(m,...) efi_net_interface_ ## m (net_interface, ## __VA_ARGS__)
++
++static grub_efi_handle_t
++grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path,
++                            grub_efi_device_path_t **r_device_path)
++{
++  grub_efi_handle_t handle;
++  grub_efi_status_t status;
++
++  status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path,
++                      protocol, &device_path, &handle);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++
++  if (r_device_path)
++    *r_device_path = device_path;
++
++  return handle;
++}
++
++static int
++url_parse_fields (const char *url, char **proto, char **host, char **path)
++{
++  const char *p, *ps;
++  grub_size_t l;
++
++  *proto = *host = *path = NULL;
++  ps = p = url;
++
++  while ((p = grub_strchr (p, ':')))
++    {
++      if (grub_strlen (p) < sizeof ("://") - 1)
++	break;
++      if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0)
++	{
++	  l = p - ps;
++	  *proto = grub_malloc (l + 1);
++	  if (!*proto)
++	    {
++	      grub_print_error ();
++	      return 0;
++	    }
++
++	  grub_memcpy (*proto, ps, l);
++	  (*proto)[l] = '\0';
++	  p +=  sizeof ("://") - 1;
++	  break;
++	}
++      ++p;
++    }
++
++  if (!*proto)
++    {
++      grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url);
++      return 0;
++    }
++
++  ps = p;
++  p = grub_strchr (p, '/');
++
++  if (!p)
++    {
++      grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url);
++      grub_free (*proto);
++      *proto = NULL;
++      return 0;
++    }
++
++  l = p - ps;
++
++  if (l > 2 && ps[0] == '[' && ps[l - 1] == ']')
++    {
++      *host = grub_malloc (l - 1);
++      if (!*host)
++	{
++	  grub_print_error ();
++	  grub_free (*proto);
++	  *proto = NULL;
++	  return 0;
++	}
++      grub_memcpy (*host, ps + 1, l - 2);
++      (*host)[l - 2] = 0;
++    }
++  else
++    {
++      *host = grub_malloc (l + 1);
++      if (!*host)
++	{
++	  grub_print_error ();
++	  grub_free (*proto);
++	  *proto = NULL;
++	  return 0;
++	}
++      grub_memcpy (*host, ps, l);
++      (*host)[l] = 0;
++    }
++
++  *path = grub_strdup (p);
++  if (!*path)
++    {
++      grub_print_error ();
++      grub_free (*host);
++      grub_free (*proto);
++      *host = NULL;
++      *proto = NULL;
++      return 0;
++    }
++  return 1;
++}
++
++static void
++url_get_boot_location (const char *url, char **device, char **path, int is_default)
++{
++  char *protocol, *server, *file;
++  char *slash;
++
++  if (!url_parse_fields (url, &protocol, &server, &file))
++    return;
++
++  if ((slash = grub_strrchr (file, '/')))
++    *slash = 0;
++  else
++    *file = 0;
++
++  *device = grub_xasprintf ("%s,%s", protocol, server);
++  *path = grub_strdup(file);
++
++  if (is_default)
++    default_server = server;
++  else
++    grub_free (server);
++
++  grub_free (protocol);
++  grub_free (file);
++}
++
++static void
++pxe_get_boot_location (const struct grub_net_bootp_packet *bp,
++		  char **device,
++		  char **path,
++		  int is_default)
++{
++  char *server = grub_xasprintf ("%d.%d.%d.%d",
++	     ((grub_uint8_t *) &bp->server_ip)[0],
++	     ((grub_uint8_t *) &bp->server_ip)[1],
++	     ((grub_uint8_t *) &bp->server_ip)[2],
++	     ((grub_uint8_t *) &bp->server_ip)[3]);
++
++  *device = grub_xasprintf ("tftp,%s", server);
++
++  *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file));
++
++  if (*path)
++    {
++      char *slash;
++      slash = grub_strrchr (*path, '/');
++      if (slash)
++	*slash = 0;
++      else
++	**path = 0;
++    }
++
++  if (is_default)
++    default_server = server;
++  else
++    grub_free (server);
++}
++
++static void
++pxe_get_boot_location_v6 (const struct grub_net_dhcp6_packet *dp,
++		  grub_size_t dhcp_size,
++		  char **device,
++		  char **path)
++{
++
++  struct grub_net_dhcp6_option *dhcp_opt;
++  grub_size_t dhcp_remain_size;
++  *device = *path = 0;
++
++  if (dhcp_size < sizeof (*dp))
++    {
++      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small"));
++      return;
++    }
++
++  dhcp_remain_size = dhcp_size - sizeof (*dp);
++  dhcp_opt = (struct grub_net_dhcp6_option *)dp->dhcp_options;
++
++  while (dhcp_remain_size)
++    {
++      grub_uint16_t code = grub_be_to_cpu16 (dhcp_opt->code);
++      grub_uint16_t len = grub_be_to_cpu16 (dhcp_opt->len);
++      grub_uint16_t option_size = sizeof (*dhcp_opt) + len;
++
++      if (dhcp_remain_size < option_size || code == 0)
++	break;
++
++      if (code == GRUB_NET_DHCP6_OPTION_BOOTFILE_URL)
++	{
++	  char *url = grub_malloc (len + 1);
++
++	  grub_memcpy (url, dhcp_opt->data, len);
++	  url[len] = 0;
++
++	  url_get_boot_location ((const char *)url, device, path, 1);
++	  grub_free (url);
++	  break;
++	}
++
++      dhcp_remain_size -= option_size;
++      dhcp_opt = (struct grub_net_dhcp6_option *)((grub_uint8_t *)dhcp_opt + option_size);
++    }
++}
++
++static grub_efi_net_interface_t *
++grub_efi_net_config_from_device_path (grub_efi_device_path_t *dp,
++		  struct grub_efi_net_device *netdev,
++		  char **device,
++		  char **path)
++{
++  grub_efi_net_interface_t *inf = NULL;
++
++  while (1)
++    {
++      grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
++      grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
++      grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp);
++
++      if (type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE)
++	{
++	  if (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
++	    {
++	      grub_efi_uri_device_path_t *uri_dp;
++	      uri_dp = (grub_efi_uri_device_path_t *) dp;
++	      /* Beware that uri_dp->uri may not be null terminated */
++	      url_get_boot_location ((const char *)uri_dp->uri, device, path, 1);
++	    }
++	  else if (subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE)
++	    {
++	      grub_efi_net_ip_manual_address_t net_ip;
++	      grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) dp;
++
++	      if (inf)
++		continue;
++	      grub_memcpy (net_ip.ip4.address, ipv4->local_ip_address, sizeof (net_ip.ip4.address));
++	      grub_memcpy (net_ip.ip4.subnet_mask, ipv4->subnet_mask, sizeof (net_ip.ip4.subnet_mask));
++	      net_ip.is_ip6 = 0;
++	      inf = grub_efi_net_create_interface (netdev,
++			    netdev->card_name,
++			    &net_ip,
++			    1);
++	    }
++	  else if (subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)
++	    {
++	      grub_efi_net_ip_manual_address_t net_ip;
++	      grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) dp;
++
++	      if (inf)
++		continue;
++	      grub_memcpy (net_ip.ip6.address, ipv6->local_ip_address, sizeof (net_ip.ip6.address));
++	      net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH;
++	      net_ip.ip6.is_anycast = 0;
++	      net_ip.is_ip6 = 1;
++	      inf = grub_efi_net_create_interface (netdev,
++			    netdev->card_name,
++			    &net_ip,
++			    1);
++	    }
++	}
++
++      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
++        break;
++      dp = (grub_efi_device_path_t *) ((char *) dp + len);
++    }
++
++  return inf;
++}
++
++static grub_efi_net_interface_t *
++grub_efi_net_config_from_handle (grub_efi_handle_t *hnd,
++		  struct grub_efi_net_device *netdev,
++		  char **device,
++		  char **path)
++{
++  grub_efi_pxe_t *pxe = NULL;
++
++  if (hnd == netdev->ip4_pxe_handle)
++    pxe = netdev->ip4_pxe;
++  else if (hnd == netdev->ip6_pxe_handle)
++    pxe = netdev->ip6_pxe;
++
++  if (!pxe)
++    return (grub_efi_net_config_from_device_path (
++		grub_efi_get_device_path (hnd),
++		netdev,
++		device,
++		path));
++
++  if (pxe->mode->using_ipv6)
++    {
++      grub_efi_net_ip_manual_address_t net_ip;
++
++      pxe_get_boot_location_v6 (
++	    (const struct grub_net_dhcp6_packet *) &pxe->mode->dhcp_ack,
++	    sizeof (pxe->mode->dhcp_ack),
++	    device,
++	    path);
++
++      grub_memcpy (net_ip.ip6.address, pxe->mode->station_ip.v6, sizeof(net_ip.ip6.address));
++      net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH;
++      net_ip.ip6.is_anycast = 0;
++      net_ip.is_ip6 = 1;
++      return (grub_efi_net_create_interface (netdev,
++		    netdev->card_name,
++		    &net_ip,
++		    1));
++    }
++  else
++    {
++      grub_efi_net_ip_manual_address_t net_ip;
++
++      pxe_get_boot_location (
++		(const struct grub_net_bootp_packet *) &pxe->mode->dhcp_ack,
++		device,
++		path,
++		1);
++
++      grub_memcpy (net_ip.ip4.address, pxe->mode->station_ip.v4, sizeof (net_ip.ip4.address));
++      grub_memcpy (net_ip.ip4.subnet_mask, pxe->mode->subnet_mask.v4, sizeof (net_ip.ip4.subnet_mask));
++      net_ip.is_ip6 = 0;
++      return (grub_efi_net_create_interface (netdev,
++		    netdev->card_name,
++		    &net_ip,
++		    1));
++    }
++}
++
++static const char *
++grub_efi_net_var_get_address (struct grub_env_var *var,
++                   const char *val __attribute__ ((unused)))
++{
++  struct grub_efi_net_device *dev;
++
++  for (dev = net_devices; dev; dev = dev->next)
++    {
++      grub_efi_net_interface_t *inf;
++
++      for (inf = dev->net_interfaces; inf; inf = inf->next)
++	{
++	  char *var_name;
++
++	  var_name = grub_xasprintf ("net_%s_ip", inf->name);
++	  if (grub_strcmp (var_name, var->name) == 0)
++	    return efi_net_interface_get_address (inf);
++	  grub_free (var_name);
++	  var_name = grub_xasprintf ("net_%s_mac", inf->name);
++	  if (grub_strcmp (var_name, var->name) == 0)
++	    return efi_net_interface_get_hw_address (inf);
++	  grub_free (var_name);
++	}
++    }
++
++  return NULL;
++}
++
++static char *
++grub_efi_net_var_set_interface (struct grub_env_var *var __attribute__ ((unused)),
++		   const char *val)
++{
++  struct grub_efi_net_device *dev;
++  grub_efi_net_interface_t *inf;
++
++  for (dev = net_devices; dev; dev = dev->next)
++    for (inf = dev->net_interfaces; inf; inf = inf->next)
++      if (grub_strcmp (inf->name, val) == 0)
++	{
++	  net_default_interface = inf;
++	  return grub_strdup (val);
++	}
++
++  return NULL;
++}
++
++static char *
++grub_efi_net_var_set_server (struct grub_env_var *var __attribute__ ((unused)),
++		   const char *val)
++{
++  grub_free (default_server);
++  default_server = grub_strdup (val);
++  return grub_strdup (val);
++}
++
++static const char *
++grub_efi_net_var_get_server (struct grub_env_var *var __attribute__ ((unused)),
++		   const char *val __attribute__ ((unused)))
++{
++  return default_server ? : "";
++}
++
++static const char *
++grub_efi_net_var_get_ip (struct grub_env_var *var __attribute__ ((unused)),
++	       const char *val __attribute__ ((unused)))
++{
++  const char *intf = grub_env_get ("net_default_interface");
++  const char *ret = NULL;
++  if (intf)
++    {
++      char *buf = grub_xasprintf ("net_%s_ip", intf);
++      if (buf)
++	ret = grub_env_get (buf);
++      grub_free (buf);
++    }
++  return ret;
++}
++
++static const char *
++grub_efi_net_var_get_mac (struct grub_env_var *var __attribute__ ((unused)),
++	       const char *val __attribute__ ((unused)))
++{
++  const char *intf = grub_env_get ("net_default_interface");
++  const char *ret = NULL;
++  if (intf)
++    {
++      char *buf = grub_xasprintf ("net_%s_mac", intf);
++      if (buf)
++	ret = grub_env_get (buf);
++      grub_free (buf);
++    }
++  return ret;
++}
++
++static void
++grub_efi_net_export_interface_vars (void)
++{
++  struct grub_efi_net_device *dev;
++
++  for (dev = net_devices; dev; dev = dev->next)
++    {
++      grub_efi_net_interface_t *inf;
++
++      for (inf = dev->net_interfaces; inf; inf = inf->next)
++	{
++	  char *var;
++
++	  var = grub_xasprintf ("net_%s_ip", inf->name);
++	  grub_register_variable_hook (var, grub_efi_net_var_get_address, 0);
++	  grub_env_export (var);
++	  grub_free (var);
++	  var = grub_xasprintf ("net_%s_mac", inf->name);
++	  grub_register_variable_hook (var, grub_efi_net_var_get_address, 0);
++	  grub_env_export (var);
++	  grub_free (var);
++	}
++    }
++}
++
++static void
++grub_efi_net_unset_interface_vars (void)
++{
++  struct grub_efi_net_device *dev;
++
++  for (dev = net_devices; dev; dev = dev->next)
++    {
++      grub_efi_net_interface_t *inf;
++
++      for (inf = dev->net_interfaces; inf; inf = inf->next)
++	{
++	  char *var;
++
++	  var = grub_xasprintf ("net_%s_ip", inf->name);
++	  grub_register_variable_hook (var, 0, 0);
++	  grub_env_unset (var);
++	  grub_free (var);
++	  var = grub_xasprintf ("net_%s_mac", inf->name);
++	  grub_register_variable_hook (var, 0, 0);
++	  grub_env_unset (var);
++	  grub_free (var);
++	}
++    }
++}
++
++grub_efi_net_interface_t *
++grub_efi_net_create_interface (struct grub_efi_net_device *dev,
++		const char *interface_name,
++		grub_efi_net_ip_manual_address_t *net_ip,
++		int has_subnet)
++{
++  grub_efi_net_interface_t *inf;
++
++  for (inf = dev->net_interfaces; inf; inf = inf->next)
++    {
++      if (inf->prefer_ip6 == net_ip->is_ip6)
++	break;
++    }
++
++  if (!inf)
++    {
++      inf = grub_malloc (sizeof(*inf));
++      inf->name = grub_strdup (interface_name);
++      inf->prefer_ip6 = net_ip->is_ip6;
++      inf->dev = dev;
++      inf->next = dev->net_interfaces;
++      inf->ip_config = (net_ip->is_ip6) ? efi_net_ip6_config : efi_net_ip4_config ;
++      dev->net_interfaces = inf;
++    }
++  else
++    {
++      grub_free (inf->name);
++      inf->name = grub_strdup (interface_name);
++    }
++
++  if (!efi_net_interface_set_address (inf, net_ip, has_subnet))
++    {
++      grub_error (GRUB_ERR_BUG, N_("Set Address Failed"));
++      return NULL;
++    }
++
++  return inf;
++}
++
++static void
++grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
++			  char **path)
++{
++  grub_efi_handle_t config_hnd;
++
++  struct grub_efi_net_device *netdev;
++  grub_efi_net_interface_t *inf;
++
++  config_hnd = grub_efi_locate_device_path (&ip4_config_guid, grub_efi_get_device_path (hnd), NULL);
++
++  if (!config_hnd)
++    return;
++
++  for (netdev = net_devices; netdev; netdev = netdev->next)
++    if (netdev->handle == config_hnd)
++      break;
++
++  if (!netdev)
++    return;
++
++  if (!(inf = grub_efi_net_config_from_handle (hnd, netdev, device, path)))
++    return;
++
++  grub_env_set ("net_default_interface", inf->name);
++  grub_efi_net_export_interface_vars ();
++}
++
++static grub_err_t
++grub_efi_netfs_dir (grub_device_t device, const char *path __attribute__ ((unused)),
++		 grub_fs_dir_hook_t hook __attribute__ ((unused)),
++		 void *hook_data __attribute__ ((unused)))
++{
++  if (!device->net)
++    return grub_error (GRUB_ERR_BUG, "invalid net device");
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_efi_netfs_open (struct grub_file *file_out __attribute__ ((unused)),
++		  const char *name __attribute__ ((unused)))
++{
++  struct grub_file *file, *bufio;
++
++  file = grub_malloc (sizeof (*file));
++  if (!file)
++    return grub_errno;
++
++  grub_memcpy (file, file_out, sizeof (struct grub_file));
++  file->device->net->name = grub_strdup (name);
++
++  if (!file->device->net->name)
++    {
++      grub_free (file);
++      return grub_errno;
++    }
++
++  efi_net_interface(open, file, name);
++  grub_print_error ();
++
++  bufio = grub_bufio_open (file, 32768);
++  if (!bufio)
++    {
++      grub_free (file->device->net->name);
++      grub_free (file);
++      return grub_errno;
++    }
++  grub_memcpy (file_out, bufio, sizeof (struct grub_file));
++  grub_free (bufio);
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_ssize_t
++grub_efihttp_chunk_read (grub_file_t file, char *buf,
++			grub_size_t len, grub_size_t chunk_size)
++{
++  char *chunk = grub_malloc (chunk_size);
++  grub_size_t sum = 0;
++
++  while (len)
++    {
++      grub_ssize_t rd;
++      grub_size_t sz = (len > chunk_size) ? chunk_size : len;
++
++      rd = efi_net_interface (read, file, chunk, sz);
++
++      if (rd <= 0)
++	return rd;
++
++      if (buf)
++	{
++	  grub_memcpy (buf, chunk, rd);
++	  buf += rd;
++	}
++      sum += rd;
++      len -= rd;
++    }
++
++  grub_free (chunk);
++  return sum;
++}
++
++static grub_ssize_t
++grub_efi_netfs_read (grub_file_t file __attribute__ ((unused)),
++		  char *buf __attribute__ ((unused)), grub_size_t len __attribute__ ((unused)))
++{
++  if (file->offset > file->device->net->offset)
++    {
++      grub_efihttp_chunk_read (file, NULL, file->offset - file->device->net->offset, 10240);
++    }
++  else if (file->offset < file->device->net->offset)
++    {
++      efi_net_interface (close, file);
++      efi_net_interface (open, file, file->device->net->name);
++      if (file->offset)
++	grub_efihttp_chunk_read (file, NULL, file->offset, 10240);
++    }
++
++  return efi_net_interface (read, file, buf, len);
++}
++
++static grub_err_t
++grub_efi_netfs_close (grub_file_t file)
++{
++  efi_net_interface (close, file);
++  return GRUB_ERR_NONE;
++}
++
++static grub_efi_handle_t
++grub_efi_service_binding (grub_efi_handle_t dev, grub_efi_guid_t *service_binding_guid)
++{
++  grub_efi_service_binding_t *service;
++  grub_efi_status_t status;
++  grub_efi_handle_t child_dev = NULL;
++
++  service = grub_efi_open_protocol (dev, service_binding_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++  if (!service)
++    {
++      grub_error (GRUB_ERR_IO, N_("couldn't open efi service binding protocol"));
++      return NULL;
++    }
++
++  status = efi_call_2 (service->create_child, service, &child_dev);
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_error (GRUB_ERR_IO, N_("Failed to create child device of http service %x"), status);
++      return NULL;
++    }
++
++  return child_dev;
++}
++
++static grub_err_t
++grub_efi_net_parse_address (const char *address,
++    grub_efi_ip4_config2_manual_address_t *ip4,
++    grub_efi_ip6_config_manual_address_t *ip6,
++    int *is_ip6,
++    int *has_cidr)
++{
++  const char *rest;
++
++  if (grub_efi_string_to_ip4_address (address, &ip4->address, &rest))
++    {
++      *is_ip6 = 0;
++      if (*rest == '/')
++	{
++	  grub_uint32_t subnet_mask_size;
++
++	  subnet_mask_size = grub_strtoul (rest + 1, (char **) &rest, 0);
++
++	  if (!grub_errno && subnet_mask_size <= 32 && *rest == 0)
++	    {
++	      grub_uint32_t subnet_mask;
++
++	      subnet_mask = grub_cpu_to_be32 ((0xffffffffU << (32 - subnet_mask_size)));
++	      grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask));
++	      if (has_cidr)
++		*has_cidr = 1;
++	      return GRUB_ERR_NONE;
++	    }
++	}
++      else if (*rest == 0)
++	{
++	  grub_uint32_t subnet_mask = 0xffffffffU;
++	  grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask));
++	  if (has_cidr)
++	    *has_cidr = 0;
++	  return GRUB_ERR_NONE;
++	}
++    }
++  else if (grub_efi_string_to_ip6_address (address, &ip6->address, &rest))
++    {
++      *is_ip6 = 1;
++      if (*rest == '/')
++	{
++	  grub_efi_uint8_t prefix_length;
++
++	  prefix_length = grub_strtoul (rest + 1, (char **) &rest, 0);
++	  if (!grub_errno && prefix_length <= 128 && *rest == 0)
++	    {
++	      ip6->prefix_length = prefix_length;
++	      ip6->is_anycast = 0;
++	      if (has_cidr)
++		*has_cidr = 1;
++	      return GRUB_ERR_NONE;
++	    }
++	}
++      else if (*rest == 0)
++	{
++	  ip6->prefix_length = 128;
++	  ip6->is_anycast = 0;
++	  if (has_cidr)
++	    *has_cidr = 0;
++	  return GRUB_ERR_NONE;
++	}
++    }
++
++  return grub_error (GRUB_ERR_NET_BAD_ADDRESS,
++		   N_("unrecognised network address `%s'"),
++		   address);
++}
++
++static grub_efi_net_interface_t *
++match_route (const char *server)
++{
++  grub_err_t err;
++  grub_efi_ip4_config2_manual_address_t ip4;
++  grub_efi_ip6_config_manual_address_t ip6;
++  grub_efi_net_interface_t *inf;
++  int is_ip6 = 0;
++
++  err = grub_efi_net_parse_address (server, &ip4, &ip6, &is_ip6, 0);
++
++  if (err)
++    {
++      grub_print_error ();
++      return NULL;
++    }
++
++  if (is_ip6)
++    {
++      struct grub_efi_net_device *dev;
++      grub_efi_net_ip_address_t addr;
++
++      grub_memcpy (addr.ip6, ip6.address, sizeof(ip6.address));
++
++      for (dev = net_devices; dev; dev = dev->next)
++	  if ((inf = efi_net_ip6_config->best_interface (dev, &addr)))
++	    return inf;
++    }
++  else
++    {
++      struct grub_efi_net_device *dev;
++      grub_efi_net_ip_address_t addr;
++
++      grub_memcpy (addr.ip4, ip4.address, sizeof(ip4.address));
++
++      for (dev = net_devices; dev; dev = dev->next)
++	  if ((inf = efi_net_ip4_config->best_interface (dev, &addr)))
++	    return inf;
++    }
++
++  return 0;
++}
++
++static void
++grub_efi_net_add_pxebc_to_cards (void)
++{
++  grub_efi_uintn_t num_handles;
++  grub_efi_handle_t *handles;
++  grub_efi_handle_t *handle;
++
++  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &pxe_io_guid,
++				    0, &num_handles);
++  if (!handles)
++    return;
++
++  for (handle = handles; num_handles--; handle++)
++    {
++      grub_efi_device_path_t *dp, *ddp, *ldp;
++      grub_efi_pxe_t *pxe;
++      struct grub_efi_net_device *d;
++      int is_ip6 = 0;
++
++      dp = grub_efi_get_device_path (*handle);
++      if (!dp)
++	continue;
++
++      ddp = grub_efi_duplicate_device_path (dp);
++      ldp = grub_efi_find_last_device_path (ddp);
++
++      if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
++	  && ldp->subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE)
++	{
++	  ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++	  ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++	  ldp->length = sizeof (*ldp);
++	}
++      else if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
++	  && ldp->subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)
++	{
++	  is_ip6 = 1;
++	  ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++	  ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++	  ldp->length = sizeof (*ldp);
++	}
++
++      for (d = net_devices; d; d = d->next)
++	if (grub_efi_compare_device_paths (ddp, grub_efi_get_device_path (d->handle)) == 0)
++	  break;
++
++      if (!d)
++	{
++	  grub_free (ddp);
++	  continue;
++	}
++
++      pxe = grub_efi_open_protocol (*handle, &pxe_io_guid,
++				GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++
++      if (!pxe)
++	{
++	  grub_free (ddp);
++	  continue;
++	}
++
++      if (is_ip6)
++	{
++	  d->ip6_pxe_handle = *handle;
++	  d->ip6_pxe = pxe;
++	}
++      else
++	{
++	  d->ip4_pxe_handle = *handle;
++	  d->ip4_pxe = pxe;
++	}
++
++      grub_free (ddp);
++    }
++
++  grub_free (handles);
++}
++
++static void
++set_ip_policy_to_static (void)
++{
++  struct grub_efi_net_device *dev;
++
++  for (dev = net_devices; dev; dev = dev->next)
++    {
++      grub_efi_ip4_config2_policy_t ip4_policy = GRUB_EFI_IP4_CONFIG2_POLICY_STATIC;
++
++      if (efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
++		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
++		    sizeof (ip4_policy), &ip4_policy) != GRUB_EFI_SUCCESS)
++	grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP4_CONFIG2_POLICY_STATIC on dev `%s'", dev->card_name);
++
++      if (dev->ip6_config)
++	{
++	  grub_efi_ip6_config_policy_t ip6_policy = GRUB_EFI_IP6_CONFIG_POLICY_MANUAL;
++
++	  if (efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
++		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY,
++		    sizeof (ip6_policy), &ip6_policy) != GRUB_EFI_SUCCESS)
++	    grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP6_CONFIG_POLICY_MANUAL on dev `%s'", dev->card_name);
++	}
++    }
++}
++
++/* FIXME: Do not fail if the card did not support any of the protocol (Eg http) */
++static void
++grub_efi_net_find_cards (void)
++{
++  grub_efi_uintn_t num_handles;
++  grub_efi_handle_t *handles;
++  grub_efi_handle_t *handle;
++  int id;
++
++  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &ip4_config_guid,
++				    0, &num_handles);
++  if (!handles)
++    return;
++
++  for (id = 0, handle = handles; num_handles--; handle++, id++)
++    {
++      grub_efi_device_path_t *dp;
++      grub_efi_ip4_config2_protocol_t *ip4_config;
++      grub_efi_ip6_config_protocol_t *ip6_config;
++      grub_efi_handle_t http_handle;
++      grub_efi_http_t *http;
++      grub_efi_handle_t dhcp4_handle;
++      grub_efi_dhcp4_protocol_t *dhcp4;
++      grub_efi_handle_t dhcp6_handle;
++      grub_efi_dhcp6_protocol_t *dhcp6;
++
++      struct grub_efi_net_device *d;
++
++      dp = grub_efi_get_device_path (*handle);
++      if (!dp)
++	continue;
++
++      ip4_config = grub_efi_open_protocol (*handle, &ip4_config_guid,
++				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++      if (!ip4_config)
++	continue;
++
++      ip6_config = grub_efi_open_protocol (*handle, &ip6_config_guid,
++				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++
++      http_handle = grub_efi_service_binding (*handle, &http_service_binding_guid);
++      grub_errno = GRUB_ERR_NONE;
++      http = (http_handle)
++	? grub_efi_open_protocol (http_handle, &http_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL)
++	: NULL;
++
++      dhcp4_handle = grub_efi_service_binding (*handle, &dhcp4_service_binding_guid);
++      grub_errno = GRUB_ERR_NONE;
++      dhcp4 = (dhcp4_handle)
++	? grub_efi_open_protocol (dhcp4_handle, &dhcp4_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL)
++	: NULL;
++
++
++      dhcp6_handle = grub_efi_service_binding (*handle, &dhcp6_service_binding_guid);
++      grub_errno = GRUB_ERR_NONE;
++      dhcp6 = (dhcp6_handle)
++	? grub_efi_open_protocol (dhcp6_handle, &dhcp6_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL)
++	: NULL;
++
++      d = grub_malloc (sizeof (*d));
++      if (!d)
++	{
++	  grub_free (handles);
++	  while (net_devices)
++	    {
++	      d = net_devices->next;
++	      grub_free (net_devices);
++	      net_devices = d;
++	    }
++	  return;
++	}
++      d->handle = *handle;
++      d->ip4_config = ip4_config;
++      d->ip6_config = ip6_config;
++      d->http_handle = http_handle;
++      d->http = http;
++      d->dhcp4_handle = dhcp4_handle;
++      d->dhcp4 = dhcp4;
++      d->dhcp6_handle = dhcp6_handle;
++      d->dhcp6 = dhcp6;
++      d->next = net_devices;
++      d->card_name = grub_xasprintf ("efinet%d", id);
++      d->net_interfaces = NULL;
++      net_devices = d;
++    }
++
++  grub_efi_net_add_pxebc_to_cards ();
++  grub_free (handles);
++  set_ip_policy_to_static ();
++}
++
++static void
++listroutes_ip4 (struct grub_efi_net_device *netdev)
++{
++  char **routes;
++
++  routes = NULL;
++
++  if ((routes = efi_net_ip4_config->get_route_table (netdev)))
++    {
++      char **r;
++
++      for (r = routes; *r; ++r)
++	grub_printf ("%s\n", *r);
++    }
++
++  if (routes)
++    {
++      char **r;
++
++      for (r = routes; *r; ++r)
++	grub_free (*r);
++      grub_free (routes);
++    }
++}
++
++static void
++listroutes_ip6 (struct grub_efi_net_device *netdev)
++{
++  char **routes;
++
++  routes = NULL;
++
++  if ((routes = efi_net_ip6_config->get_route_table (netdev)))
++    {
++      char **r;
++
++      for (r = routes; *r; ++r)
++	grub_printf ("%s\n", *r);
++    }
++
++  if (routes)
++    {
++      char **r;
++
++      for (r = routes; *r; ++r)
++	grub_free (*r);
++      grub_free (routes);
++    }
++}
++
++static grub_err_t
++grub_cmd_efi_listroutes (struct grub_command *cmd __attribute__ ((unused)),
++		     int argc __attribute__ ((unused)),
++		     char **args __attribute__ ((unused)))
++{
++  struct grub_efi_net_device *netdev;
++
++  for (netdev = net_devices; netdev; netdev = netdev->next)
++    {
++      listroutes_ip4 (netdev);
++      listroutes_ip6 (netdev);
++    }
++
++  return GRUB_ERR_NONE;
++}
++static grub_err_t
++grub_cmd_efi_listcards (struct grub_command *cmd __attribute__ ((unused)),
++		    int argc __attribute__ ((unused)),
++		    char **args __attribute__ ((unused)))
++{
++  struct grub_efi_net_device *dev;
++
++  for (dev = net_devices; dev; dev = dev->next)
++    {
++      char *hw_addr;
++
++      hw_addr = efi_net_ip4_config->get_hw_address (dev);
++
++      if (hw_addr)
++	{
++	  grub_printf ("%s %s\n", dev->card_name, hw_addr);
++	  grub_free (hw_addr);
++	}
++    }
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_cmd_efi_listaddrs (struct grub_command *cmd __attribute__ ((unused)),
++		    int argc __attribute__ ((unused)),
++		    char **args __attribute__ ((unused)))
++{
++  struct grub_efi_net_device *dev;
++  grub_efi_net_interface_t *inf;
++
++  for (dev = net_devices; dev; dev = dev->next)
++    for (inf = dev->net_interfaces; inf; inf = inf->next)
++      {
++	char *hw_addr = NULL;
++	char *addr = NULL;
++
++	if ((hw_addr = efi_net_interface_get_hw_address (inf))
++	    && (addr = efi_net_interface_get_address (inf)))
++	  grub_printf ("%s %s %s\n", inf->name, hw_addr, addr);
++
++	if (hw_addr)
++	  grub_free (hw_addr);
++	if (addr)
++	  grub_free (addr);
++      }
++
++  return GRUB_ERR_NONE;
++}
++
++/* FIXME: support MAC specifying.  */
++static grub_err_t
++grub_cmd_efi_addaddr (struct grub_command *cmd __attribute__ ((unused)),
++                  int argc, char **args)
++{
++  struct grub_efi_net_device *dev;
++  grub_err_t err;
++  grub_efi_ip4_config2_manual_address_t ip4;
++  grub_efi_ip6_config_manual_address_t ip6;
++  grub_efi_net_ip_manual_address_t net_ip;
++  int is_ip6 = 0;
++  int cidr = 0;
++
++  if (argc != 3)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("three arguments expected"));
++
++  for (dev = net_devices; dev; dev = dev->next)
++    {
++      if (grub_strcmp (dev->card_name, args[1]) == 0)
++	break;
++    }
++
++  if (!dev)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("card not found"));
++
++  err = grub_efi_net_parse_address (args[2], &ip4, &ip6, &is_ip6, &cidr);
++
++  if (err)
++    return err;
++
++  net_ip.is_ip6 = is_ip6;
++  if (is_ip6)
++    grub_memcpy (&net_ip.ip6, &ip6, sizeof(net_ip.ip6));
++  else
++    grub_memcpy (&net_ip.ip4, &ip4, sizeof(net_ip.ip4));
++
++  if (!grub_efi_net_create_interface (dev,
++		args[0],
++		&net_ip,
++		cidr))
++    return grub_errno;
++
++  return GRUB_ERR_NONE;
++}
++
++static struct grub_fs grub_efi_netfs;
++
++static grub_net_t
++grub_net_open_real (const char *name __attribute__ ((unused)))
++{
++  grub_size_t protnamelen;
++  const char *protname, *server;
++  grub_net_t ret;
++
++  net_interface = NULL;
++
++  if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
++    {
++      protname = "tftp";
++      protnamelen = sizeof ("tftp") - 1;
++      server = name + sizeof ("pxe:") - 1;
++    }
++  else if (grub_strcmp (name, "pxe") == 0)
++    {
++      protname = "tftp";
++      protnamelen = sizeof ("tftp") - 1;
++      server = default_server;
++    }
++  else
++    {
++      const char *comma;
++
++      comma = grub_strchr (name, ',');
++      if (comma)
++	{
++	  protnamelen = comma - name;
++	  server = comma + 1;
++	  protname = name;
++	}
++      else
++	{
++	  protnamelen = grub_strlen (name);
++	  server = default_server;
++	  protname = name;
++	}
++    }
++
++  if (!server)
++    {
++      grub_error (GRUB_ERR_NET_BAD_ADDRESS,
++		  N_("no server is specified"));
++      return NULL;
++    }
++
++  /*FIXME: Use DNS translate name to address */
++  net_interface = match_route (server);
++
++  /*XXX: should we check device with default gateway ? */
++  if (!net_interface && !(net_interface = net_default_interface))
++    {
++      grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' no route found"),
++		  name);
++      return NULL;
++    }
++
++  if ((protnamelen == (sizeof ("https") - 1)
++	&& grub_memcmp ("https", protname, protnamelen) == 0))
++    {
++      net_interface->io = &io_http;
++      net_interface->io_type = 1;
++    }
++  else if ((protnamelen == (sizeof ("http") - 1)
++	&& grub_memcmp ("http", protname, protnamelen) == 0))
++    {
++      net_interface->io = &io_http;
++      net_interface->io_type = 0;
++    }
++  else if (protnamelen == (sizeof ("tftp") - 1)
++	&& grub_memcmp ("tftp", protname, protnamelen) == 0)
++    {
++      net_interface->io = &io_pxe;
++      net_interface->io_type = 0;
++    }
++  else
++    {
++      grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"),
++		  name);
++      return NULL;
++    }
++
++  /*XXX: Should we try to avoid doing excess "reconfigure" here ??? */
++  efi_net_interface (configure);
++
++  ret = grub_zalloc (sizeof (*ret));
++  if (!ret)
++    return NULL;
++
++  ret->server = grub_strdup (server);
++  if (!ret->server)
++    {
++      grub_free (ret);
++      return NULL;
++    }
++
++  ret->fs = &grub_efi_netfs;
++  return ret;
++}
++#if 0
++static grub_command_t cmd_efi_lsaddr;
++static grub_command_t cmd_efi_lscards;
++static grub_command_t cmd_efi_lsroutes;
++static grub_command_t cmd_efi_addaddr;
++#endif
++
++static struct grub_fs grub_efi_netfs =
++  {
++    .name = "efi netfs",
++    .fs_dir = grub_efi_netfs_dir,
++    .fs_open = grub_efi_netfs_open,
++    .fs_read = grub_efi_netfs_read,
++    .fs_close = grub_efi_netfs_close,
++    .fs_label = NULL,
++    .fs_uuid = NULL,
++    .fs_mtime = NULL,
++  };
++
++int
++grub_efi_net_boot_from_https (void)
++{
++  grub_efi_loaded_image_t *image = NULL;
++  grub_efi_device_path_t *dp;
++
++  image = grub_efi_get_loaded_image (grub_efi_image_handle);
++  if (!image)
++    return 0;
++
++  dp = grub_efi_get_device_path (image->device_handle);
++
++  while (1)
++    {
++      grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
++      grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
++      grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp);
++
++      if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE)
++	  && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
++	{
++	  grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp;
++	  return (grub_strncmp ((const char*)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0) ? 1 : 0;
++	}
++
++      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
++        break;
++      dp = (grub_efi_device_path_t *) ((char *) dp + len);
++    }
++
++  return 0;
++}
++
++int
++grub_efi_net_boot_from_opa (void)
++{
++  grub_efi_loaded_image_t *image = NULL;
++  grub_efi_device_path_t *dp;
++
++  image = grub_efi_get_loaded_image (grub_efi_image_handle);
++  if (!image)
++    return 0;
++
++  dp = grub_efi_get_device_path (image->device_handle);
++
++  while (1)
++    {
++      grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
++      grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
++      grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp);
++
++      if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE)
++	  && (subtype == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE))
++	{
++	  grub_efi_mac_address_device_path_t *mac_dp  = (grub_efi_mac_address_device_path_t *)dp;
++	  return (mac_dp->if_type == 0xC7) ? 1 : 0;
++	}
++
++      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
++        break;
++      dp = (grub_efi_device_path_t *) ((char *) dp + len);
++    }
++
++  return 0;
++}
++
++static char *
++grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
++			 const char *val __attribute__ ((unused)))
++{
++  return NULL;
++}
++
++grub_command_func_t grub_efi_net_list_routes = grub_cmd_efi_listroutes;
++grub_command_func_t grub_efi_net_list_cards = grub_cmd_efi_listcards;
++grub_command_func_t grub_efi_net_list_addrs = grub_cmd_efi_listaddrs;
++grub_command_func_t grub_efi_net_add_addr = grub_cmd_efi_addaddr;
++
++int
++grub_efi_net_fs_init ()
++{
++  grub_efi_net_find_cards ();
++  grub_efi_net_config = grub_efi_net_config_real;
++  grub_net_open = grub_net_open_real;
++  grub_register_variable_hook ("net_default_server", grub_efi_net_var_get_server,
++			       grub_efi_net_var_set_server);
++  grub_env_export ("net_default_server");
++  grub_register_variable_hook ("pxe_default_server", grub_efi_net_var_get_server,
++			       grub_efi_net_var_set_server);
++  grub_env_export ("pxe_default_server");
++  grub_register_variable_hook ("net_default_interface", 0,
++			       grub_efi_net_var_set_interface);
++  grub_env_export ("net_default_interface");
++  grub_register_variable_hook ("net_default_ip", grub_efi_net_var_get_ip,
++			       0);
++  grub_env_export ("net_default_ip");
++  grub_register_variable_hook ("net_default_mac", grub_efi_net_var_get_mac,
++			       0);
++  grub_env_export ("net_default_mac");
++
++  grub_env_set ("grub_netfs_type", "efi");
++  grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly);
++  grub_env_export ("grub_netfs_type");
++
++  return 1;
++}
++
++void
++grub_efi_net_fs_fini (void)
++{
++  grub_env_unset ("grub_netfs_type");
++  grub_efi_net_unset_interface_vars ();
++  grub_register_variable_hook ("net_default_server", 0, 0);
++  grub_env_unset ("net_default_server");
++  grub_register_variable_hook ("net_default_interface", 0, 0);
++  grub_env_unset ("net_default_interface");
++  grub_register_variable_hook ("pxe_default_server", 0, 0);
++  grub_env_unset ("pxe_default_server");
++  grub_register_variable_hook ("net_default_ip", 0, 0);
++  grub_env_unset ("net_default_ip");
++  grub_register_variable_hook ("net_default_mac", 0, 0);
++  grub_env_unset ("net_default_mac");
++  grub_efi_net_config = NULL;
++  grub_net_open = NULL;
++  grub_fs_unregister (&grub_efi_netfs);
++}
+diff --git a/grub-core/net/efi/pxe.c b/grub-core/net/efi/pxe.c
+new file mode 100644
+index 0000000000..531949cba5
+--- /dev/null
++++ b/grub-core/net/efi/pxe.c
+@@ -0,0 +1,424 @@
++
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/misc.h>
++#include <grub/net/efi.h>
++#include <grub/charset.h>
++
++static grub_efi_ip6_config_manual_address_t *
++efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config)
++{
++  grub_efi_uintn_t sz;
++  grub_efi_status_t status;
++  grub_efi_ip6_config_manual_address_t *manual_address;
++
++  sz = sizeof (*manual_address);
++  manual_address = grub_malloc (sz);
++  if (!manual_address)
++    return NULL;
++
++  status = efi_call_4 (ip6_config->get_data, ip6_config,
++		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
++		    &sz, manual_address);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (manual_address);
++      return NULL;
++    }
++
++  return manual_address;
++}
++
++static grub_efi_ip4_config2_manual_address_t *
++efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config)
++{
++  grub_efi_uintn_t sz;
++  grub_efi_status_t status;
++  grub_efi_ip4_config2_manual_address_t *manual_address;
++
++  sz = sizeof (*manual_address);
++  manual_address = grub_malloc (sz);
++  if (!manual_address)
++    return NULL;
++
++  status = efi_call_4 (ip4_config->get_data, ip4_config,
++		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
++		    &sz, manual_address);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (manual_address);
++      return NULL;
++    }
++
++  return manual_address;
++}
++
++static void
++pxe_configure (struct grub_efi_net_device *dev, int prefer_ip6)
++{
++  grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe;
++
++  grub_efi_pxe_mode_t *mode = pxe->mode;
++
++  if (!mode->started)
++    {
++      grub_efi_status_t status;
++      status = efi_call_2 (pxe->start, pxe, prefer_ip6);
++
++      if (status != GRUB_EFI_SUCCESS)
++	  grub_printf ("Couldn't start PXE\n");
++    }
++
++#if 0
++  grub_printf ("PXE STARTED: %u\n", mode->started);
++  grub_printf ("PXE USING IPV6: %u\n", mode->using_ipv6);
++#endif
++
++  if (mode->using_ipv6)
++    {
++      grub_efi_ip6_config_manual_address_t *manual_address;
++      manual_address = efi_ip6_config_manual_address (dev->ip6_config);
++
++      if (manual_address &&
++	  grub_memcmp (manual_address->address, mode->station_ip.v6, sizeof (manual_address->address)) != 0)
++	{
++	  grub_efi_status_t status;
++	  grub_efi_pxe_ip_address_t station_ip;
++
++	  grub_memcpy (station_ip.v6.addr, manual_address->address, sizeof (station_ip.v6.addr));
++	  status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, NULL);
++
++	  if (status != GRUB_EFI_SUCCESS)
++	      grub_printf ("Couldn't set station ip\n");
++
++	  grub_free (manual_address);
++	}
++    }
++  else
++    {
++      grub_efi_ip4_config2_manual_address_t *manual_address;
++      manual_address = efi_ip4_config_manual_address (dev->ip4_config);
++
++      if (manual_address &&
++	  grub_memcmp (manual_address->address, mode->station_ip.v4, sizeof (manual_address->address)) != 0)
++	{
++	  grub_efi_status_t status;
++	  grub_efi_pxe_ip_address_t station_ip;
++	  grub_efi_pxe_ip_address_t subnet_mask;
++
++	  grub_memcpy (station_ip.v4.addr, manual_address->address, sizeof (station_ip.v4.addr));
++	  grub_memcpy (subnet_mask.v4.addr, manual_address->subnet_mask, sizeof (subnet_mask.v4.addr));
++
++	  status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, &subnet_mask);
++
++	  if (status != GRUB_EFI_SUCCESS)
++	      grub_printf ("Couldn't set station ip\n");
++
++	  grub_free (manual_address);
++	}
++    }
++
++#if 0
++  if (mode->using_ipv6)
++    {
++      grub_printf ("PXE STATION IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
++	mode->station_ip.v6.addr[0],
++	mode->station_ip.v6.addr[1],
++	mode->station_ip.v6.addr[2],
++	mode->station_ip.v6.addr[3],
++	mode->station_ip.v6.addr[4],
++	mode->station_ip.v6.addr[5],
++	mode->station_ip.v6.addr[6],
++	mode->station_ip.v6.addr[7],
++	mode->station_ip.v6.addr[8],
++	mode->station_ip.v6.addr[9],
++	mode->station_ip.v6.addr[10],
++	mode->station_ip.v6.addr[11],
++	mode->station_ip.v6.addr[12],
++	mode->station_ip.v6.addr[13],
++	mode->station_ip.v6.addr[14],
++	mode->station_ip.v6.addr[15]);
++    }
++  else
++    {
++      grub_printf ("PXE STATION IP: %d.%d.%d.%d\n",
++	mode->station_ip.v4.addr[0],
++	mode->station_ip.v4.addr[1],
++	mode->station_ip.v4.addr[2],
++	mode->station_ip.v4.addr[3]);
++      grub_printf ("PXE SUBNET MASK: %d.%d.%d.%d\n",
++	mode->subnet_mask.v4.addr[0],
++	mode->subnet_mask.v4.addr[1],
++	mode->subnet_mask.v4.addr[2],
++	mode->subnet_mask.v4.addr[3]);
++    }
++#endif
++
++  /* TODO: Set The Station IP to the IP2 Config */
++}
++
++static int
++parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
++{
++  grub_uint16_t newip[8];
++  const char *ptr = val;
++  int word, quaddot = -1;
++  int bracketed = 0;
++
++  if (ptr[0] == '[') {
++    bracketed = 1;
++    ptr++;
++  }
++
++  if (ptr[0] == ':' && ptr[1] != ':')
++    return 0;
++  if (ptr[0] == ':')
++    ptr++;
++
++  for (word = 0; word < 8; word++)
++    {
++      unsigned long t;
++      if (*ptr == ':')
++	{
++	  quaddot = word;
++	  word--;
++	  ptr++;
++	  continue;
++	}
++      t = grub_strtoul (ptr, (char **) &ptr, 16);
++      if (grub_errno)
++	{
++	  grub_errno = GRUB_ERR_NONE;
++	  break;
++	}
++      if (t & ~0xffff)
++	return 0;
++      newip[word] = grub_cpu_to_be16 (t);
++      if (*ptr != ':')
++	break;
++      ptr++;
++    }
++  if (quaddot == -1 && word < 7)
++    return 0;
++  if (quaddot != -1)
++    {
++      grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot],
++		    (word - quaddot + 1) * sizeof (newip[0]));
++      grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
++    }
++  grub_memcpy (ip, newip, 16);
++  if (bracketed && *ptr == ']') {
++    ptr++;
++  }
++  if (rest)
++    *rest = ptr;
++  return 1;
++}
++
++static grub_err_t
++pxe_open (struct grub_efi_net_device *dev,
++	  int prefer_ip6,
++	  grub_file_t file,
++	  const char *filename,
++	  int type __attribute__((unused)))
++{
++  int i;
++  char *p;
++  grub_efi_status_t status;
++  grub_efi_pxe_ip_address_t server_ip;
++  grub_efi_uint64_t file_size = 0;
++  grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe;
++
++  if (pxe->mode->using_ipv6)
++    {
++      const char *rest;
++      grub_uint64_t ip6[2];
++      if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0)
++	grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr));
++      /* TODO: ERROR Handling Here */
++#if 0
++      grub_printf ("PXE SERVER IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
++	server_ip.v6.addr[0],
++	server_ip.v6.addr[1],
++	server_ip.v6.addr[2],
++	server_ip.v6.addr[3],
++	server_ip.v6.addr[4],
++	server_ip.v6.addr[5],
++	server_ip.v6.addr[6],
++	server_ip.v6.addr[7],
++	server_ip.v6.addr[8],
++	server_ip.v6.addr[9],
++	server_ip.v6.addr[10],
++	server_ip.v6.addr[11],
++	server_ip.v6.addr[12],
++	server_ip.v6.addr[13],
++	server_ip.v6.addr[14],
++	server_ip.v6.addr[15]);
++#endif
++    }
++  else
++    {
++      for (i = 0, p = file->device->net->server; i < 4; ++i, ++p)
++	server_ip.v4.addr[i] = grub_strtoul (p, &p, 10);
++    }
++
++  status = efi_call_10 (pxe->mtftp,
++	    pxe,
++	    GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
++	    NULL,
++	    0,
++	    &file_size,
++	    NULL,
++	    &server_ip,
++	    (grub_efi_char8_t *)filename,
++	    NULL,
++	    0);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return grub_error (GRUB_ERR_IO, "Couldn't get file size");
++
++  file->size = (grub_off_t)file_size;
++  file->not_easily_seekable = 0;
++  file->data = 0;
++  file->device->net->offset = 0;
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++pxe_close (struct grub_efi_net_device *dev __attribute__((unused)),
++	  int prefer_ip6 __attribute__((unused)),
++	  grub_file_t file __attribute__((unused)))
++{
++  file->offset = 0;
++  file->size = 0;
++  file->device->net->offset = 0;
++
++  if (file->data)
++    {
++      grub_free (file->data);
++      file->data = NULL;
++    }
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_ssize_t
++pxe_read (struct grub_efi_net_device *dev,
++	  int prefer_ip6,
++	  grub_file_t file,
++	  char *buf,
++	  grub_size_t len)
++{
++  int i;
++  char *p;
++  grub_efi_status_t status;
++  grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe;
++  grub_efi_uint64_t bufsz = len;
++  grub_efi_pxe_ip_address_t server_ip;
++  char *buf2 = NULL;
++
++  if (file->data)
++    {
++      /* TODO: RANGE Check for offset and file size */
++      grub_memcpy (buf, (char*)file->data + file->device->net->offset, len);
++      file->device->net->offset += len;
++      return len;
++    }
++
++  if (file->device->net->offset)
++    {
++      grub_error (GRUB_ERR_BUG, "No Offet Read Possible");
++      grub_print_error ();
++      return 0;
++    }
++
++  if (pxe->mode->using_ipv6)
++    {
++      const char *rest;
++      grub_uint64_t ip6[2];
++      if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0)
++	grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr));
++      /* TODO: ERROR Handling Here */
++    }
++  else
++    {
++      for (i = 0, p = file->device->net->server; i < 4; ++i, ++p)
++	server_ip.v4.addr[i] = grub_strtoul (p, &p, 10);
++    }
++
++  status = efi_call_10 (pxe->mtftp,
++	    pxe,
++	    GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE,
++	    buf,
++	    0,
++	    &bufsz,
++	    NULL,
++	    &server_ip,
++	    (grub_efi_char8_t *)file->device->net->name,
++	    NULL,
++	    0);
++
++  if (bufsz != file->size)
++    {
++      grub_error (GRUB_ERR_BUG, "Short read should not happen here");
++      grub_print_error ();
++      return 0;
++    }
++
++  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
++    {
++
++      buf2 = grub_malloc (bufsz);
++
++      if (!buf2)
++	{
++	  grub_error (GRUB_ERR_OUT_OF_MEMORY, "ERROR OUT OF MEMORY");
++	  grub_print_error ();
++	  return 0;
++	}
++
++      status = efi_call_10 (pxe->mtftp,
++		pxe,
++		GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE,
++		buf2,
++		0,
++		&bufsz,
++		NULL,
++		&server_ip,
++		(grub_efi_char8_t *)file->device->net->name,
++		NULL,
++		0);
++    }
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      if (buf2)
++	grub_free (buf2);
++
++      grub_error (GRUB_ERR_IO, "Failed to Read File");
++      grub_print_error ();
++      return 0;
++    }
++
++  if (buf2)
++    grub_memcpy (buf, buf2, len);
++
++  file->device->net->offset = len;
++
++  if (buf2)
++    file->data = buf2;
++
++  return len;
++}
++
++struct grub_efi_net_io io_pxe =
++  {
++    .configure = pxe_configure,
++    .open = pxe_open,
++    .read = pxe_read,
++    .close = pxe_close
++  };
++
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index 0ce5e675ed..55aed92722 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -32,6 +32,9 @@
+ #include <grub/loader.h>
+ #include <grub/bufio.h>
+ #include <grub/kernel.h>
++#ifdef GRUB_MACHINE_EFI
++#include <grub/net/efi.h>
++#endif
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -2033,8 +2036,49 @@ static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute;
+ static grub_command_t cmd_lsroutes, cmd_lscards;
+ static grub_command_t cmd_lsaddr, cmd_slaac;
+ 
++#ifdef GRUB_MACHINE_EFI
++
++static enum {
++  INIT_MODE_NONE,
++  INIT_MODE_GRUB,
++  INIT_MODE_EFI
++} init_mode;
++
++static grub_command_t cmd_bootp, cmd_bootp6;
++
++#endif
++
+ GRUB_MOD_INIT(net)
+ {
++#ifdef GRUB_MACHINE_EFI
++  if (grub_net_open)
++    return;
++
++  if ((grub_efi_net_boot_from_https () || grub_efi_net_boot_from_opa ())
++      && grub_efi_net_fs_init ())
++    {
++      cmd_lsroutes = grub_register_command ("net_ls_routes", grub_efi_net_list_routes,
++					    "", N_("list network routes"));
++      cmd_lscards = grub_register_command ("net_ls_cards", grub_efi_net_list_cards,
++					   "", N_("list network cards"));
++      cmd_lsaddr = grub_register_command ("net_ls_addr", grub_efi_net_list_addrs,
++					  "", N_("list network addresses"));
++      cmd_addaddr = grub_register_command ("net_add_addr", grub_efi_net_add_addr,
++					    /* TRANSLATORS: HWADDRESS stands for
++					       "hardware address".  */
++					  N_("SHORTNAME CARD ADDRESS [HWADDRESS]"),
++					  N_("Add a network address."));
++      cmd_bootp = grub_register_command ("net_bootp", grub_efi_net_bootp,
++					 N_("[CARD]"),
++					 N_("perform a bootp autoconfiguration"));
++      cmd_bootp6 = grub_register_command ("net_bootp6", grub_efi_net_bootp6,
++					 N_("[CARD]"),
++					 N_("perform a bootp autoconfiguration"));
++      init_mode = INIT_MODE_EFI;
++      return;
++    }
++#endif
++
+   grub_register_variable_hook ("net_default_server", defserver_get_env,
+ 			       defserver_set_env);
+   grub_env_export ("net_default_server");
+@@ -2082,10 +2126,37 @@ GRUB_MOD_INIT(net)
+ 						grub_net_restore_hw,
+ 						GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK);
+   grub_net_poll_cards_idle = grub_net_poll_cards_idle_real;
++
++#ifdef GRUB_MACHINE_EFI
++  grub_env_set ("grub_netfs_type", "grub");
++  grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly);
++  grub_env_export ("grub_netfs_type");
++  init_mode = INIT_MODE_GRUB;
++#endif
++
+ }
+ 
+ GRUB_MOD_FINI(net)
+ {
++
++#ifdef GRUB_MACHINE_EFI
++  if (init_mode == INIT_MODE_NONE)
++    return;
++
++  if (init_mode == INIT_MODE_EFI)
++    {
++      grub_unregister_command (cmd_lsroutes);
++      grub_unregister_command (cmd_lscards);
++      grub_unregister_command (cmd_lsaddr);
++      grub_unregister_command (cmd_addaddr);
++      grub_unregister_command (cmd_bootp);
++      grub_unregister_command (cmd_bootp6);
++      grub_efi_net_fs_fini ();
++      init_mode = INIT_MODE_NONE;
++      return;
++    }
++#endif
++
+   grub_register_variable_hook ("net_default_server", 0, 0);
+   grub_register_variable_hook ("pxe_default_server", 0, 0);
+ 
+@@ -2104,4 +2175,7 @@ GRUB_MOD_FINI(net)
+   grub_net_fini_hw (0);
+   grub_loader_unregister_preboot_hook (fini_hnd);
+   grub_net_poll_cards_idle = grub_net_poll_cards_idle_real;
++#ifdef GRUB_MACHINE_EFI
++  init_mode = INIT_MODE_NONE;
++#endif
+ }
+diff --git a/util/grub-mknetdir.c b/util/grub-mknetdir.c
+index a2461cda1c..77958dd9dd 100644
+--- a/util/grub-mknetdir.c
++++ b/util/grub-mknetdir.c
+@@ -32,13 +32,15 @@
+ 
+ static char *rootdir = NULL, *subdir = NULL;
+ static char *debug_image = NULL;
++static char efi_netfs = 0;
+ 
+ enum
+   {
+     OPTION_NET_DIRECTORY = 0x301,
+     OPTION_SUBDIR,
+     OPTION_DEBUG,
+-    OPTION_DEBUG_IMAGE
++    OPTION_DEBUG_IMAGE,
++    OPTION_DEBUG_EFI_NETFS
+   };
+ 
+ static struct argp_option options[] = {
+@@ -49,6 +51,7 @@ static struct argp_option options[] = {
+    0, N_("relative subdirectory on network server"), 2},
+   {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2},
+   {"debug-image", OPTION_DEBUG_IMAGE, N_("STRING"), OPTION_HIDDEN, 0, 2},
++  {"debug-efi-netfs", OPTION_DEBUG_EFI_NETFS, 0, OPTION_HIDDEN, 0, 2},
+   {0, 0, 0, 0, 0, 0}
+ };
+ 
+@@ -67,6 +70,9 @@ argp_parser (int key, char *arg, struct argp_state *state)
+       free (subdir);
+       subdir = xstrdup (arg);
+       return 0;
++    case OPTION_DEBUG_EFI_NETFS:
++      efi_netfs = 1;
++      return 0;
+       /* This is an undocumented feature...  */
+     case OPTION_DEBUG:
+       verbosity++;
+@@ -82,7 +88,6 @@ argp_parser (int key, char *arg, struct argp_state *state)
+     }
+ }
+ 
+-
+ struct argp argp = {
+   options, argp_parser, NULL,
+   "\v"N_("Prepares GRUB network boot images at net_directory/subdir "
+@@ -92,7 +97,7 @@ struct argp argp = {
+ 
+ static char *base;
+ 
+-static const struct
++static struct
+ {
+   const char *mkimage_target;
+   const char *netmodule;
+@@ -156,6 +161,7 @@ process_input_dir (const char *input_dir, enum grub_install_plat platform)
+   grub_install_push_module (targets[platform].netmodule);
+ 
+   output = grub_util_path_concat_ext (2, grubdir, "core", targets[platform].ext);
++
+   grub_install_make_image_wrap (input_dir, prefix, output,
+ 				0, load_cfg,
+ 				targets[platform].mkimage_target, 0);
+@@ -195,7 +201,16 @@ main (int argc, char *argv[])
+ 
+   grub_install_mkdir_p (base);
+ 
+-  grub_install_push_module ("tftp");
++  if (!efi_netfs)
++    {
++      grub_install_push_module ("tftp");
++      grub_install_push_module ("http");
++    }
++  else
++    {
++      targets[GRUB_INSTALL_PLATFORM_I386_EFI].netmodule = "efi_netfs";
++      targets[GRUB_INSTALL_PLATFORM_X86_64_EFI].netmodule = "efi_netfs";
++    }
+ 
+   if (!grub_install_source_directory)
+     {
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index 0b490195ad..f431f49973 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -622,6 +622,23 @@ typedef union
+ 
+ typedef grub_efi_uint64_t grub_efi_physical_address_t;
+ typedef grub_efi_uint64_t grub_efi_virtual_address_t;
++typedef struct {
++  grub_uint8_t addr[4];
++} grub_efi_pxe_ipv4_address_t;
++
++typedef struct {
++  grub_uint8_t addr[16];
++} grub_efi_pxe_ipv6_address_t;
++
++typedef struct {
++  grub_uint8_t addr[32];
++} grub_efi_pxe_mac_address_t;
++
++typedef union {
++    grub_uint32_t addr[4];
++    grub_efi_pxe_ipv4_address_t v4;
++    grub_efi_pxe_ipv6_address_t v6;
++} grub_efi_pxe_ip_address_t;
+ 
+ struct grub_efi_guid
+ {
+@@ -889,6 +906,8 @@ struct grub_efi_ipv6_device_path
+   grub_efi_uint16_t remote_port;
+   grub_efi_uint16_t protocol;
+   grub_efi_uint8_t static_ip_address;
++  grub_efi_uint8_t prefix_length;
++  grub_efi_ipv6_address_t gateway_ip_address;
+ } GRUB_PACKED;
+ typedef struct grub_efi_ipv6_device_path grub_efi_ipv6_device_path_t;
+ 
+@@ -938,6 +957,15 @@ struct grub_efi_uri_device_path
+ } GRUB_PACKED;
+ typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t;
+ 
++#define GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE                31
++struct grub_efi_dns_device_path
++{
++  grub_efi_device_path_t header;
++  grub_efi_uint8_t is_ipv6;
++  grub_efi_pxe_ip_address_t dns_server_ip[0];
++} GRUB_PACKED;
++typedef struct grub_efi_dns_device_path grub_efi_dns_device_path_t;
++
+ #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE	10
+ 
+ /* Media Device Path.  */
+@@ -1020,6 +1048,23 @@ struct grub_efi_bios_device_path
+ } GRUB_PACKED;
+ typedef struct grub_efi_bios_device_path grub_efi_bios_device_path_t;
+ 
++/* Service Binding definitions */
++struct grub_efi_service_binding;
++
++typedef grub_efi_status_t
++(*grub_efi_service_binding_create_child) (struct grub_efi_service_binding *this,
++                                          grub_efi_handle_t *child_handle);
++
++typedef grub_efi_status_t
++(*grub_efi_service_binding_destroy_child) (struct grub_efi_service_binding *this,
++                                           grub_efi_handle_t *child_handle);
++
++typedef struct grub_efi_service_binding
++{
++  grub_efi_service_binding_create_child create_child;
++  grub_efi_service_binding_destroy_child destroy_child;
++} grub_efi_service_binding_t;
++
+ struct grub_efi_open_protocol_information_entry
+ {
+   grub_efi_handle_t agent_handle;
+@@ -1569,23 +1614,27 @@ typedef struct grub_efi_pxe_tftp_error
+   grub_efi_char8_t error_string[127];
+ } grub_efi_pxe_tftp_error_t;
+ 
+-typedef struct {
+-  grub_uint8_t addr[4];
+-} grub_efi_pxe_ipv4_address_t;
++typedef grub_efi_uint16_t grub_efi_pxe_base_code_udp_port_t;
+ 
+-typedef struct {
+-  grub_uint8_t addr[16];
+-} grub_efi_pxe_ipv6_address_t;
++typedef enum {
++  GRUB_EFI_PXE_BASE_CODE_TFTP_FIRST,
++  GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
++  GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE,
++  GRUB_EFI_PXE_BASE_CODE_TFTP_WRITE_FILE,
++  GRUB_EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY,
++  GRUB_EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE,
++  GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_FILE,
++  GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY,
++  GRUB_EFI_PXE_BASE_CODE_MTFTP_LAST
++} grub_efi_pxe_base_code_tftp_opcode_t;
+ 
+ typedef struct {
+-  grub_uint8_t addr[32];
+-} grub_efi_pxe_mac_address_t;
+-
+-typedef union {
+-  grub_uint32_t addr[4];
+-  grub_efi_pxe_ipv4_address_t v4;
+-  grub_efi_pxe_ipv6_address_t v6;
+-} grub_efi_pxe_ip_address_t;
++  grub_efi_ip_address_t mcast_ip;
++  grub_efi_pxe_base_code_udp_port_t c_port;
++  grub_efi_pxe_base_code_udp_port_t s_port;
++  grub_efi_uint16_t listen_timeout;
++  grub_efi_uint16_t transmit_timeout;
++} grub_efi_pxe_base_code_mtftp_info_t;
+ 
+ #define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8
+ typedef struct grub_efi_pxe_ip_filter
+@@ -1652,17 +1701,31 @@ typedef struct grub_efi_pxe_mode
+ typedef struct grub_efi_pxe
+ {
+   grub_uint64_t rev;
+-  void (*start) (void);
++  grub_efi_status_t (*start) (struct grub_efi_pxe *this, grub_efi_boolean_t use_ipv6);
+   void (*stop) (void);
+-  void (*dhcp) (void);
++  grub_efi_status_t (*dhcp) (struct grub_efi_pxe *this,
++			    grub_efi_boolean_t sort_offers);
+   void (*discover) (void);
+-  void (*mftp) (void);
++  grub_efi_status_t (*mtftp) (struct grub_efi_pxe *this,
++			    grub_efi_pxe_base_code_tftp_opcode_t operation,
++			    void *buffer_ptr,
++			    grub_efi_boolean_t overwrite,
++			    grub_efi_uint64_t *buffer_size,
++			    grub_efi_uintn_t *block_size,
++			    grub_efi_pxe_ip_address_t *server_ip,
++			    //grub_efi_ip_address_t *server_ip,
++			    grub_efi_char8_t *filename,
++			    grub_efi_pxe_base_code_mtftp_info_t *info,
++			    grub_efi_boolean_t dont_use_buffer);
+   void (*udpwrite) (void);
+   void (*udpread) (void);
+   void (*setipfilter) (void);
+   void (*arp) (void);
+   void (*setparams) (void);
+-  void (*setstationip) (void);
++  grub_efi_status_t (*set_station_ip) (struct grub_efi_pxe *this,
++			    grub_efi_pxe_ip_address_t *new_station_ip,
++			    grub_efi_pxe_ip_address_t *new_subnet_mask);
++  //void (*setstationip) (void);
+   void (*setpackets) (void);
+   struct grub_efi_pxe_mode *mode;
+ } grub_efi_pxe_t;
+@@ -1924,6 +1987,44 @@ struct grub_efi_ip4_config2_protocol
+ };
+ typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t;
+ 
++struct grub_efi_ip4_route_table {
++  grub_efi_ipv4_address_t subnet_address;
++  grub_efi_ipv4_address_t subnet_mask;
++  grub_efi_ipv4_address_t gateway_address;
++};
++
++typedef struct grub_efi_ip4_route_table grub_efi_ip4_route_table_t;
++
++#define GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32
++
++struct grub_efi_ip4_config2_interface_info {
++  grub_efi_char16_t name[GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE];
++  grub_efi_uint8_t if_type;
++  grub_efi_uint32_t hw_address_size;
++  grub_efi_mac_address_t hw_address;
++  grub_efi_ipv4_address_t station_address;
++  grub_efi_ipv4_address_t subnet_mask;
++  grub_efi_uint32_t route_table_size;
++  grub_efi_ip4_route_table_t *route_table;
++};
++
++typedef struct grub_efi_ip4_config2_interface_info grub_efi_ip4_config2_interface_info_t;
++
++enum grub_efi_ip4_config2_policy {
++  GRUB_EFI_IP4_CONFIG2_POLICY_STATIC,
++  GRUB_EFI_IP4_CONFIG2_POLICY_DHCP,
++  GRUB_EFI_IP4_CONFIG2_POLICY_MAX
++};
++
++typedef enum grub_efi_ip4_config2_policy grub_efi_ip4_config2_policy_t;
++
++struct grub_efi_ip4_config2_manual_address {
++  grub_efi_ipv4_address_t address;
++  grub_efi_ipv4_address_t subnet_mask;
++};
++
++typedef struct grub_efi_ip4_config2_manual_address grub_efi_ip4_config2_manual_address_t;
++
+ enum grub_efi_ip6_config_data_type {
+   GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
+   GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID,
+@@ -1958,6 +2059,49 @@ struct grub_efi_ip6_config_protocol
+ };
+ typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t;
+ 
++enum grub_efi_ip6_config_policy {
++  GRUB_EFI_IP6_CONFIG_POLICY_MANUAL,
++  GRUB_EFI_IP6_CONFIG_POLICY_AUTOMATIC
++};
++typedef enum grub_efi_ip6_config_policy grub_efi_ip6_config_policy_t;
++
++struct grub_efi_ip6_address_info {
++  grub_efi_ipv6_address_t address;
++  grub_efi_uint8_t prefix_length;
++};
++typedef struct grub_efi_ip6_address_info grub_efi_ip6_address_info_t;
++
++struct grub_efi_ip6_route_table {
++  grub_efi_pxe_ipv6_address_t gateway;
++  grub_efi_pxe_ipv6_address_t destination;
++  grub_efi_uint8_t prefix_length;
++};
++typedef struct grub_efi_ip6_route_table grub_efi_ip6_route_table_t;
++
++struct grub_efi_ip6_config_interface_info {
++  grub_efi_char16_t name[32];
++  grub_efi_uint8_t if_type;
++  grub_efi_uint32_t hw_address_size;
++  grub_efi_mac_address_t hw_address;
++  grub_efi_uint32_t address_info_count;
++  grub_efi_ip6_address_info_t *address_info;
++  grub_efi_uint32_t route_count;
++  grub_efi_ip6_route_table_t *route_table;
++};
++typedef struct grub_efi_ip6_config_interface_info grub_efi_ip6_config_interface_info_t;
++
++struct grub_efi_ip6_config_dup_addr_detect_transmits {
++  grub_efi_uint32_t dup_addr_detect_transmits;
++};
++typedef struct grub_efi_ip6_config_dup_addr_detect_transmits grub_efi_ip6_config_dup_addr_detect_transmits_t;
++
++struct grub_efi_ip6_config_manual_address {
++  grub_efi_ipv6_address_t address;
++  grub_efi_boolean_t is_anycast;
++  grub_efi_uint8_t prefix_length;
++};
++typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t;
++
+ #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
+   || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \
+   || defined(__riscv)
+diff --git a/include/grub/efi/dhcp.h b/include/grub/efi/dhcp.h
+new file mode 100644
+index 0000000000..fdb88eb810
+--- /dev/null
++++ b/include/grub/efi/dhcp.h
+@@ -0,0 +1,343 @@
++#ifndef GRUB_EFI_DHCP_HEADER
++#define GRUB_EFI_DHCP_HEADER	1
++
++#define GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID \
++  { 0x9d9a39d8, 0xbd42, 0x4a73, \
++    { 0xa4, 0xd5, 0x8e, 0xe9, 0x4b, 0xe1, 0x13, 0x80 } \
++  }
++
++#define GRUB_EFI_DHCP4_PROTOCOL_GUID \
++  { 0x8a219718, 0x4ef5, 0x4761, \
++    { 0x91, 0xc8, 0xc0, 0xf0, 0x4b, 0xda, 0x9e, 0x56 } \
++  }
++
++#define GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID \
++  { 0x9fb9a8a1, 0x2f4a, 0x43a6, \
++    { 0x88, 0x9c, 0xd0, 0xf7, 0xb6, 0xc4 ,0x7a, 0xd5 } \
++  }
++
++#define GRUB_EFI_DHCP6_PROTOCOL_GUID \
++  { 0x87c8bad7, 0x595, 0x4053, \
++    { 0x82, 0x97, 0xde, 0xde, 0x39, 0x5f, 0x5d, 0x5b } \
++  }
++
++typedef struct grub_efi_dhcp4_protocol grub_efi_dhcp4_protocol_t;
++
++enum grub_efi_dhcp4_state {
++  GRUB_EFI_DHCP4_STOPPED,
++  GRUB_EFI_DHCP4_INIT,
++  GRUB_EFI_DHCP4_SELECTING,
++  GRUB_EFI_DHCP4_REQUESTING,
++  GRUB_EFI_DHCP4_BOUND,
++  GRUB_EFI_DHCP4_RENEWING,
++  GRUB_EFI_DHCP4_REBINDING,
++  GRUB_EFI_DHCP4_INIT_REBOOT,
++  GRUB_EFI_DHCP4_REBOOTING
++};
++
++typedef enum grub_efi_dhcp4_state grub_efi_dhcp4_state_t;
++
++struct grub_efi_dhcp4_header {
++  grub_efi_uint8_t op_code;
++  grub_efi_uint8_t hw_type;
++  grub_efi_uint8_t hw_addr_len;
++  grub_efi_uint8_t hops;
++  grub_efi_uint32_t xid;
++  grub_efi_uint16_t seconds;
++  grub_efi_uint16_t reserved;
++  grub_efi_ipv4_address_t client_addr;
++  grub_efi_ipv4_address_t your_addr;
++  grub_efi_ipv4_address_t server_addr;
++  grub_efi_ipv4_address_t gateway_addr;
++  grub_efi_uint8_t client_hw_addr[16];
++  grub_efi_char8_t server_name[64];
++  grub_efi_char8_t boot_file_name[128];
++} GRUB_PACKED;
++
++typedef struct grub_efi_dhcp4_header grub_efi_dhcp4_header_t;
++
++struct grub_efi_dhcp4_packet {
++  grub_efi_uint32_t size;
++  grub_efi_uint32_t length;
++  struct {
++    grub_efi_dhcp4_header_t header;
++    grub_efi_uint32_t magik;
++    grub_efi_uint8_t option[1];
++  } dhcp4;
++} GRUB_PACKED;
++
++typedef struct grub_efi_dhcp4_packet grub_efi_dhcp4_packet_t;
++
++struct grub_efi_dhcp4_listen_point {
++  grub_efi_ipv4_address_t listen_address;
++  grub_efi_ipv4_address_t subnet_mask;
++  grub_efi_uint16_t listen_port;
++};
++
++typedef struct grub_efi_dhcp4_listen_point grub_efi_dhcp4_listen_point_t;
++
++struct grub_efi_dhcp4_transmit_receive_token {
++  grub_efi_status_t status;
++  grub_efi_event_t completion_event;
++  grub_efi_ipv4_address_t remote_address;
++  grub_efi_uint16_t remote_port;
++  grub_efi_ipv4_address_t gateway_address;
++  grub_efi_uint32_t listen_point_count;
++  grub_efi_dhcp4_listen_point_t *listen_points;
++  grub_efi_uint32_t timeout_value;
++  grub_efi_dhcp4_packet_t *packet;
++  grub_efi_uint32_t response_count;
++  grub_efi_dhcp4_packet_t *response_list;
++};
++
++typedef struct grub_efi_dhcp4_transmit_receive_token grub_efi_dhcp4_transmit_receive_token_t;
++
++enum grub_efi_dhcp4_event {
++  GRUB_EFI_DHCP4_SEND_DISCOVER = 0X01,
++  GRUB_EFI_DHCP4_RCVD_OFFER,
++  GRUB_EFI_DHCP4_SELECT_OFFER,
++  GRUB_EFI_DHCP4_SEND_REQUEST,
++  GRUB_EFI_DHCP4_RCVD_ACK,
++  GRUB_EFI_DHCP4_RCVD_NAK,
++  GRUB_EFI_DHCP4_SEND_DECLINE,
++  GRUB_EFI_DHCP4_BOUND_COMPLETED,
++  GRUB_EFI_DHCP4_ENTER_RENEWING,
++  GRUB_EFI_DHCP4_ENTER_REBINDING,
++  GRUB_EFI_DHCP4_ADDRESS_LOST,
++  GRUB_EFI_DHCP4_FAIL
++};
++
++typedef enum grub_efi_dhcp4_event grub_efi_dhcp4_event_t;
++
++struct grub_efi_dhcp4_packet_option {
++  grub_efi_uint8_t op_code;
++  grub_efi_uint8_t length;
++  grub_efi_uint8_t data[1];
++} GRUB_PACKED;
++
++typedef struct grub_efi_dhcp4_packet_option grub_efi_dhcp4_packet_option_t;
++
++struct grub_efi_dhcp4_config_data {
++  grub_efi_uint32_t discover_try_count;
++  grub_efi_uint32_t *discover_timeout;
++  grub_efi_uint32_t request_try_count;
++  grub_efi_uint32_t *request_timeout;
++  grub_efi_ipv4_address_t client_address;
++  grub_efi_status_t (*dhcp4_callback) (
++    grub_efi_dhcp4_protocol_t *this,
++    void *context,
++    grub_efi_dhcp4_state_t current_state,
++    grub_efi_dhcp4_event_t dhcp4_event,
++    grub_efi_dhcp4_packet_t *packet,
++    grub_efi_dhcp4_packet_t **new_packet
++  );
++  void *callback_context;
++  grub_efi_uint32_t option_count;
++  grub_efi_dhcp4_packet_option_t **option_list;
++};
++
++typedef struct grub_efi_dhcp4_config_data grub_efi_dhcp4_config_data_t;
++
++struct grub_efi_dhcp4_mode_data {
++  grub_efi_dhcp4_state_t state;
++  grub_efi_dhcp4_config_data_t config_data;
++  grub_efi_ipv4_address_t client_address;
++  grub_efi_mac_address_t client_mac_address;
++  grub_efi_ipv4_address_t server_address;
++  grub_efi_ipv4_address_t router_address;
++  grub_efi_ipv4_address_t subnet_mask;
++  grub_efi_uint32_t lease_time;
++  grub_efi_dhcp4_packet_t *reply_packet;
++};
++
++typedef struct grub_efi_dhcp4_mode_data grub_efi_dhcp4_mode_data_t;
++
++struct grub_efi_dhcp4_protocol {
++  grub_efi_status_t (*get_mode_data) (grub_efi_dhcp4_protocol_t *this,
++	      grub_efi_dhcp4_mode_data_t *dhcp4_mode_data);
++  grub_efi_status_t (*configure) (grub_efi_dhcp4_protocol_t *this,
++	      grub_efi_dhcp4_config_data_t *dhcp4_cfg_data);
++  grub_efi_status_t (*start) (grub_efi_dhcp4_protocol_t *this,
++	      grub_efi_event_t completion_event);
++  grub_efi_status_t (*renew_rebind) (grub_efi_dhcp4_protocol_t *this,
++	      grub_efi_boolean_t rebind_request,
++	      grub_efi_event_t completion_event);
++  grub_efi_status_t (*release) (grub_efi_dhcp4_protocol_t *this);
++  grub_efi_status_t (*stop) (grub_efi_dhcp4_protocol_t *this);
++  grub_efi_status_t (*build) (grub_efi_dhcp4_protocol_t *this,
++	      grub_efi_dhcp4_packet_t *seed_packet,
++	      grub_efi_uint32_t delete_count,
++	      grub_efi_uint8_t *delete_list,
++	      grub_efi_uint32_t append_count,
++	      grub_efi_dhcp4_packet_option_t *append_list[],
++	      grub_efi_dhcp4_packet_t **new_packet);
++  grub_efi_status_t (*transmit_receive) (grub_efi_dhcp4_protocol_t *this,
++	      grub_efi_dhcp4_transmit_receive_token_t *token);
++  grub_efi_status_t (*parse) (grub_efi_dhcp4_protocol_t *this,
++	      grub_efi_dhcp4_packet_t *packet,
++	      grub_efi_uint32_t *option_count,
++	      grub_efi_dhcp4_packet_option_t *packet_option_list[]);
++};
++
++typedef struct grub_efi_dhcp6_protocol grub_efi_dhcp6_protocol_t;
++
++struct grub_efi_dhcp6_retransmission {
++  grub_efi_uint32_t irt;
++  grub_efi_uint32_t mrc;
++  grub_efi_uint32_t mrt;
++  grub_efi_uint32_t mrd;
++};
++
++typedef struct grub_efi_dhcp6_retransmission grub_efi_dhcp6_retransmission_t;
++
++enum grub_efi_dhcp6_event {
++  GRUB_EFI_DHCP6_SEND_SOLICIT,
++  GRUB_EFI_DHCP6_RCVD_ADVERTISE,
++  GRUB_EFI_DHCP6_SELECT_ADVERTISE,
++  GRUB_EFI_DHCP6_SEND_REQUEST,
++  GRUB_EFI_DHCP6_RCVD_REPLY,
++  GRUB_EFI_DHCP6_RCVD_RECONFIGURE,
++  GRUB_EFI_DHCP6_SEND_DECLINE,
++  GRUB_EFI_DHCP6_SEND_CONFIRM,
++  GRUB_EFI_DHCP6_SEND_RELEASE,
++  GRUB_EFI_DHCP6_SEND_RENEW,
++  GRUB_EFI_DHCP6_SEND_REBIND
++};
++
++typedef enum grub_efi_dhcp6_event grub_efi_dhcp6_event_t;
++
++struct grub_efi_dhcp6_packet_option {
++  grub_efi_uint16_t op_code;
++  grub_efi_uint16_t op_len;
++  grub_efi_uint8_t data[1];
++} GRUB_PACKED;
++
++typedef struct grub_efi_dhcp6_packet_option grub_efi_dhcp6_packet_option_t;
++
++struct grub_efi_dhcp6_header {
++  grub_efi_uint32_t transaction_id:24;
++  grub_efi_uint32_t message_type:8;
++} GRUB_PACKED;
++
++typedef struct grub_efi_dhcp6_header grub_efi_dhcp6_header_t;
++
++struct grub_efi_dhcp6_packet {
++  grub_efi_uint32_t size;
++  grub_efi_uint32_t length;
++  struct {
++    grub_efi_dhcp6_header_t header;
++    grub_efi_uint8_t option[1];
++  } dhcp6;
++} GRUB_PACKED;
++
++typedef struct grub_efi_dhcp6_packet grub_efi_dhcp6_packet_t;
++
++struct grub_efi_dhcp6_ia_address {
++  grub_efi_ipv6_address_t ip_address;
++  grub_efi_uint32_t preferred_lifetime;
++  grub_efi_uint32_t valid_lifetime;
++};
++
++typedef struct grub_efi_dhcp6_ia_address grub_efi_dhcp6_ia_address_t;
++
++enum grub_efi_dhcp6_state {
++  GRUB_EFI_DHCP6_INIT,
++  GRUB_EFI_DHCP6_SELECTING,
++  GRUB_EFI_DHCP6_REQUESTING,
++  GRUB_EFI_DHCP6_DECLINING,
++  GRUB_EFI_DHCP6_CONFIRMING,
++  GRUB_EFI_DHCP6_RELEASING,
++  GRUB_EFI_DHCP6_BOUND,
++  GRUB_EFI_DHCP6_RENEWING,
++  GRUB_EFI_DHCP6_REBINDING
++};
++
++typedef enum grub_efi_dhcp6_state grub_efi_dhcp6_state_t;
++
++#define GRUB_EFI_DHCP6_IA_TYPE_NA 3
++#define GRUB_EFI_DHCP6_IA_TYPE_TA 4
++
++struct grub_efi_dhcp6_ia_descriptor {
++  grub_efi_uint16_t type;
++  grub_efi_uint32_t ia_id;
++};
++
++typedef struct grub_efi_dhcp6_ia_descriptor grub_efi_dhcp6_ia_descriptor_t;
++
++struct grub_efi_dhcp6_ia {
++  grub_efi_dhcp6_ia_descriptor_t descriptor;
++  grub_efi_dhcp6_state_t state;
++  grub_efi_dhcp6_packet_t *reply_packet;
++  grub_efi_uint32_t ia_address_count;
++  grub_efi_dhcp6_ia_address_t ia_address[1];
++};
++
++typedef struct grub_efi_dhcp6_ia grub_efi_dhcp6_ia_t;
++
++struct grub_efi_dhcp6_duid {
++  grub_efi_uint16_t length;
++  grub_efi_uint8_t duid[1];
++};
++
++typedef struct grub_efi_dhcp6_duid grub_efi_dhcp6_duid_t;
++
++struct grub_efi_dhcp6_mode_data {
++  grub_efi_dhcp6_duid_t *client_id;
++  grub_efi_dhcp6_ia_t *ia;
++};
++
++typedef struct grub_efi_dhcp6_mode_data grub_efi_dhcp6_mode_data_t;
++
++struct grub_efi_dhcp6_config_data {
++  grub_efi_status_t (*dhcp6_callback) (grub_efi_dhcp6_protocol_t this,
++		void *context,
++		grub_efi_dhcp6_state_t current_state,
++		grub_efi_dhcp6_event_t dhcp6_event,
++		grub_efi_dhcp6_packet_t *packet,
++		grub_efi_dhcp6_packet_t **new_packet);
++  void *callback_context;
++  grub_efi_uint32_t option_count;
++  grub_efi_dhcp6_packet_option_t **option_list;
++  grub_efi_dhcp6_ia_descriptor_t ia_descriptor;
++  grub_efi_event_t ia_info_event;
++  grub_efi_boolean_t reconfigure_accept;
++  grub_efi_boolean_t rapid_commit;
++  grub_efi_dhcp6_retransmission_t *solicit_retransmission;
++};
++
++typedef struct grub_efi_dhcp6_config_data grub_efi_dhcp6_config_data_t;
++
++struct grub_efi_dhcp6_protocol {
++  grub_efi_status_t (*get_mode_data) (grub_efi_dhcp6_protocol_t *this,
++	    grub_efi_dhcp6_mode_data_t *dhcp6_mode_data,
++	    grub_efi_dhcp6_config_data_t *dhcp6_config_data);
++  grub_efi_status_t (*configure) (grub_efi_dhcp6_protocol_t *this,
++	    grub_efi_dhcp6_config_data_t *dhcp6_cfg_data);
++  grub_efi_status_t (*start) (grub_efi_dhcp6_protocol_t *this);
++  grub_efi_status_t (*info_request) (grub_efi_dhcp6_protocol_t *this,
++	    grub_efi_boolean_t send_client_id,
++	    grub_efi_dhcp6_packet_option_t *option_request,
++	    grub_efi_uint32_t option_count,
++	    grub_efi_dhcp6_packet_option_t *option_list[],
++	    grub_efi_dhcp6_retransmission_t *retransmission,
++	    grub_efi_event_t timeout_event,
++	    grub_efi_status_t (*reply_callback) (grub_efi_dhcp6_protocol_t *this,
++		    void *context,
++		    grub_efi_dhcp6_packet_t *packet),
++	    void *callback_context);
++  grub_efi_status_t (*renew_rebind) (grub_efi_dhcp6_protocol_t *this,
++	    grub_efi_boolean_t rebind_request);
++  grub_efi_status_t (*decline) (grub_efi_dhcp6_protocol_t *this,
++	    grub_efi_uint32_t address_count,
++	    grub_efi_ipv6_address_t *addresses);
++  grub_efi_status_t (*release) (grub_efi_dhcp6_protocol_t *this,
++	    grub_efi_uint32_t address_count,
++	    grub_efi_ipv6_address_t *addresses);
++  grub_efi_status_t (*stop) (grub_efi_dhcp6_protocol_t *this);
++  grub_efi_status_t (*parse) (grub_efi_dhcp6_protocol_t *this,
++	    grub_efi_dhcp6_packet_t *packet,
++	    grub_efi_uint32_t *option_count,
++	    grub_efi_dhcp6_packet_option_t *packet_option_list[]);
++};
++
++#endif /* ! GRUB_EFI_DHCP_HEADER */
+diff --git a/include/grub/efi/http.h b/include/grub/efi/http.h
+new file mode 100644
+index 0000000000..c5e9a89f50
+--- /dev/null
++++ b/include/grub/efi/http.h
+@@ -0,0 +1,215 @@
++/*
++ *  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/>.
++ */
++
++#ifndef GRUB_EFI_HTTP_HEADER
++#define GRUB_EFI_HTTP_HEADER	1
++
++#include <grub/symbol.h>
++#include <grub/net.h>
++#include <grub/efi/api.h>
++
++#define GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \
++  { 0xbdc8e6af, 0xd9bc, 0x4379, \
++      { 0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c } \
++  }
++
++#define GRUB_EFI_HTTP_PROTOCOL_GUID \
++  { 0x7A59B29B, 0x910B, 0x4171, \
++      { 0x82, 0x42, 0xA8, 0x5A, 0x0D, 0xF2, 0x5B, 0x5B } \
++  }
++
++#define EFIHTTP_WAIT_TIME 10000 // 10000ms = 10s
++#define EFIHTTP_RX_BUF_LEN 10240
++
++//******************************************
++// Protocol Interface Structure
++//******************************************
++struct grub_efi_http;
++
++//******************************************
++// EFI_HTTP_VERSION
++//******************************************
++typedef enum {
++  GRUB_EFI_HTTPVERSION10,
++  GRUB_EFI_HTTPVERSION11,
++  GRUB_EFI_HTTPVERSIONUNSUPPORTED
++} grub_efi_http_version_t;
++
++//******************************************
++// EFI_HTTPv4_ACCESS_POINT
++//******************************************
++typedef struct {
++  grub_efi_boolean_t use_default_address;
++  grub_efi_ipv4_address_t local_address;
++  grub_efi_ipv4_address_t local_subnet;
++  grub_efi_uint16_t local_port;
++} grub_efi_httpv4_access_point_t;
++
++//******************************************
++// EFI_HTTPv6_ACCESS_POINT
++//******************************************
++typedef struct {
++  grub_efi_ipv6_address_t local_address;
++  grub_efi_uint16_t local_port;
++} grub_efi_httpv6_access_point_t;
++
++//******************************************
++// EFI_HTTP_CONFIG_DATA
++//******************************************
++typedef struct {
++  grub_efi_http_version_t http_version;
++  grub_efi_uint32_t timeout_millisec;
++  grub_efi_boolean_t local_address_is_ipv6;
++  union {
++    grub_efi_httpv4_access_point_t *ipv4_node;
++    grub_efi_httpv6_access_point_t *ipv6_node;
++  } access_point;
++} grub_efi_http_config_data_t;
++
++//******************************************
++// EFI_HTTP_METHOD
++//******************************************
++typedef enum {
++  GRUB_EFI_HTTPMETHODGET,
++  GRUB_EFI_HTTPMETHODPOST,
++  GRUB_EFI_HTTPMETHODPATCH,
++  GRUB_EFI_HTTPMETHODOPTIONS,
++  GRUB_EFI_HTTPMETHODCONNECT,
++  GRUB_EFI_HTTPMETHODHEAD,
++  GRUB_EFI_HTTPMETHODPUT,
++  GRUB_EFI_HTTPMETHODDELETE,
++  GRUB_EFI_HTTPMETHODTRACE,
++} grub_efi_http_method_t;
++
++//******************************************
++// EFI_HTTP_REQUEST_DATA
++//******************************************
++typedef struct {
++  grub_efi_http_method_t method;
++  grub_efi_char16_t *url;
++} grub_efi_http_request_data_t;
++
++typedef enum {
++  GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS = 0,
++  GRUB_EFI_HTTP_STATUS_100_CONTINUE,
++  GRUB_EFI_HTTP_STATUS_101_SWITCHING_PROTOCOLS,
++  GRUB_EFI_HTTP_STATUS_200_OK,
++  GRUB_EFI_HTTP_STATUS_201_CREATED,
++  GRUB_EFI_HTTP_STATUS_202_ACCEPTED,
++  GRUB_EFI_HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION,
++  GRUB_EFI_HTTP_STATUS_204_NO_CONTENT,
++  GRUB_EFI_HTTP_STATUS_205_RESET_CONTENT,
++  GRUB_EFI_HTTP_STATUS_206_PARTIAL_CONTENT,
++  GRUB_EFI_HTTP_STATUS_300_MULTIPLE_CHIOCES,
++  GRUB_EFI_HTTP_STATUS_301_MOVED_PERMANENTLY,
++  GRUB_EFI_HTTP_STATUS_302_FOUND,
++  GRUB_EFI_HTTP_STATUS_303_SEE_OTHER,
++  GRUB_EFI_HTTP_STATUS_304_NOT_MODIFIED,
++  GRUB_EFI_HTTP_STATUS_305_USE_PROXY,
++  GRUB_EFI_HTTP_STATUS_307_TEMPORARY_REDIRECT,
++  GRUB_EFI_HTTP_STATUS_400_BAD_REQUEST,
++  GRUB_EFI_HTTP_STATUS_401_UNAUTHORIZED,
++  GRUB_EFI_HTTP_STATUS_402_PAYMENT_REQUIRED,
++  GRUB_EFI_HTTP_STATUS_403_FORBIDDEN,
++  GRUB_EFI_HTTP_STATUS_404_NOT_FOUND,
++  GRUB_EFI_HTTP_STATUS_405_METHOD_NOT_ALLOWED,
++  GRUB_EFI_HTTP_STATUS_406_NOT_ACCEPTABLE,
++  GRUB_EFI_HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED,
++  GRUB_EFI_HTTP_STATUS_408_REQUEST_TIME_OUT,
++  GRUB_EFI_HTTP_STATUS_409_CONFLICT,
++  GRUB_EFI_HTTP_STATUS_410_GONE,
++  GRUB_EFI_HTTP_STATUS_411_LENGTH_REQUIRED,
++  GRUB_EFI_HTTP_STATUS_412_PRECONDITION_FAILED,
++  GRUB_EFI_HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE,
++  GRUB_EFI_HTTP_STATUS_414_REQUEST_URI_TOO_LARGE,
++  GRUB_EFI_HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE,
++  GRUB_EFI_HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED,
++  GRUB_EFI_HTTP_STATUS_417_EXPECTATION_FAILED,
++  GRUB_EFI_HTTP_STATUS_500_INTERNAL_SERVER_ERROR,
++  GRUB_EFI_HTTP_STATUS_501_NOT_IMPLEMENTED,
++  GRUB_EFI_HTTP_STATUS_502_BAD_GATEWAY,
++  GRUB_EFI_HTTP_STATUS_503_SERVICE_UNAVAILABLE,
++  GRUB_EFI_HTTP_STATUS_504_GATEWAY_TIME_OUT,
++  GRUB_EFI_HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED
++} grub_efi_http_status_code_t;
++
++//******************************************
++// EFI_HTTP_RESPONSE_DATA
++//******************************************
++typedef struct {
++  grub_efi_http_status_code_t status_code;
++} grub_efi_http_response_data_t;
++
++//******************************************
++// EFI_HTTP_HEADER
++//******************************************
++typedef struct {
++  grub_efi_char8_t *field_name;
++  grub_efi_char8_t *field_value;
++} grub_efi_http_header_t;
++
++//******************************************
++// EFI_HTTP_MESSAGE
++//******************************************
++typedef struct {
++  union {
++    grub_efi_http_request_data_t *request;
++    grub_efi_http_response_data_t *response;
++  } data;
++  grub_efi_uint32_t header_count;
++  grub_efi_http_header_t *headers;
++  grub_efi_uint32_t body_length;
++  void *body;
++} grub_efi_http_message_t;
++
++//******************************************
++// EFI_HTTP_TOKEN
++//******************************************
++typedef struct {
++  grub_efi_event_t event;
++  grub_efi_status_t status;
++  grub_efi_http_message_t *message;
++} grub_efi_http_token_t;
++
++struct grub_efi_http {
++  grub_efi_status_t
++  (*get_mode_data) (struct grub_efi_http *this,
++                    grub_efi_http_config_data_t *http_config_data);
++
++  grub_efi_status_t
++  (*configure) (struct grub_efi_http *this,
++                grub_efi_http_config_data_t *http_config_data);
++
++  grub_efi_status_t
++  (*request) (struct grub_efi_http *this,
++              grub_efi_http_token_t *token);
++
++  grub_efi_status_t
++  (*cancel) (struct grub_efi_http *this,
++             grub_efi_http_token_t *token);
++
++  grub_efi_status_t
++  (*response) (struct grub_efi_http *this,
++               grub_efi_http_token_t *token);
++
++  grub_efi_status_t
++  (*poll) (struct grub_efi_http *this);
++};
++typedef struct grub_efi_http grub_efi_http_t;
++
++#endif /* !GRUB_EFI_HTTP_HEADER */
+diff --git a/include/grub/net/efi.h b/include/grub/net/efi.h
+new file mode 100644
+index 0000000000..de90d223e8
+--- /dev/null
++++ b/include/grub/net/efi.h
+@@ -0,0 +1,144 @@
++#ifndef GRUB_NET_EFI_HEADER
++#define GRUB_NET_EFI_HEADER	1
++
++#include <grub/efi/api.h>
++#include <grub/efi/http.h>
++#include <grub/efi/dhcp.h>
++#include <grub/command.h>
++
++typedef struct grub_efi_net_interface grub_efi_net_interface_t;
++typedef struct grub_efi_net_ip_config grub_efi_net_ip_config_t;
++typedef union grub_efi_net_ip_address grub_efi_net_ip_address_t;
++typedef struct grub_efi_net_ip_manual_address grub_efi_net_ip_manual_address_t;
++
++struct grub_efi_net_interface
++{
++  char *name;
++  int prefer_ip6;
++  struct grub_efi_net_device *dev;
++  struct grub_efi_net_io *io;
++  grub_efi_net_ip_config_t *ip_config;
++  int io_type;
++  struct grub_efi_net_interface *next;
++};
++
++#define efi_net_interface_get_hw_address(inf) inf->ip_config->get_hw_address (inf->dev)
++#define efi_net_interface_get_address(inf) inf->ip_config->get_address (inf->dev)
++#define efi_net_interface_get_route_table(inf) inf->ip_config->get_route_table (inf->dev)
++#define efi_net_interface_set_address(inf, addr, with_subnet) inf->ip_config->set_address (inf->dev, addr, with_subnet)
++#define efi_net_interface_set_gateway(inf, addr) inf->ip_config->set_gateway (inf->dev, addr)
++#define efi_net_interface_set_dns(inf, addr) inf->ip_config->set_dns (inf->dev, addr)
++
++struct grub_efi_net_ip_config
++{
++  char * (*get_hw_address) (struct grub_efi_net_device *dev);
++  char * (*get_address) (struct grub_efi_net_device *dev);
++  char ** (*get_route_table) (struct grub_efi_net_device *dev);
++  grub_efi_net_interface_t * (*best_interface) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address);
++  int (*set_address) (struct grub_efi_net_device *dev, grub_efi_net_ip_manual_address_t *net_ip, int with_subnet);
++  int (*set_gateway) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address);
++  int (*set_dns) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *dns);
++};
++
++union grub_efi_net_ip_address
++{
++  grub_efi_ipv4_address_t ip4;
++  grub_efi_ipv6_address_t ip6;
++};
++
++struct grub_efi_net_ip_manual_address
++{
++  int is_ip6;
++  union
++  {
++    grub_efi_ip4_config2_manual_address_t ip4;
++    grub_efi_ip6_config_manual_address_t ip6;
++  };
++};
++
++struct grub_efi_net_device
++{
++  grub_efi_handle_t handle;
++  grub_efi_ip4_config2_protocol_t *ip4_config;
++  grub_efi_ip6_config_protocol_t *ip6_config;
++  grub_efi_handle_t http_handle;
++  grub_efi_http_t *http;
++  grub_efi_handle_t ip4_pxe_handle;
++  grub_efi_pxe_t *ip4_pxe;
++  grub_efi_handle_t ip6_pxe_handle;
++  grub_efi_pxe_t *ip6_pxe;
++  grub_efi_handle_t dhcp4_handle;
++  grub_efi_dhcp4_protocol_t *dhcp4;
++  grub_efi_handle_t dhcp6_handle;
++  grub_efi_dhcp6_protocol_t *dhcp6;
++  char *card_name;
++  grub_efi_net_interface_t *net_interfaces;
++  struct grub_efi_net_device *next;
++};
++
++struct grub_efi_net_io
++{
++  void (*configure) (struct grub_efi_net_device *dev, int prefer_ip6);
++  grub_err_t (*open) (struct grub_efi_net_device *dev,
++		    int prefer_ip6,
++		    grub_file_t file,
++		    const char *filename,
++		    int type);
++  grub_ssize_t (*read) (struct grub_efi_net_device *dev,
++			int prefer_ip6,
++			grub_file_t file,
++			char *buf,
++			grub_size_t len);
++  grub_err_t (*close) (struct grub_efi_net_device *dev,
++		      int prefer_ip6,
++		      grub_file_t file);
++};
++
++extern struct grub_efi_net_device *net_devices;
++
++extern struct grub_efi_net_io io_http;
++extern struct grub_efi_net_io io_pxe;
++
++extern grub_efi_net_ip_config_t *efi_net_ip4_config;
++extern grub_efi_net_ip_config_t *efi_net_ip6_config;
++
++char *
++grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address);
++
++char *
++grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address);
++
++char *
++grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address);
++
++int
++grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest);
++
++int
++grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest);
++
++char *
++grub_efi_ip6_interface_name (struct grub_efi_net_device *dev);
++
++char *
++grub_efi_ip4_interface_name (struct grub_efi_net_device *dev);
++
++grub_efi_net_interface_t *
++grub_efi_net_create_interface (struct grub_efi_net_device *dev,
++		const char *interface_name,
++		grub_efi_net_ip_manual_address_t *net_ip,
++		int has_subnet);
++
++int grub_efi_net_fs_init (void);
++void grub_efi_net_fs_fini (void);
++int grub_efi_net_boot_from_https (void);
++int grub_efi_net_boot_from_opa (void);
++
++extern grub_command_func_t grub_efi_net_list_routes;
++extern grub_command_func_t grub_efi_net_list_cards;
++extern grub_command_func_t grub_efi_net_list_addrs;
++extern grub_command_func_t grub_efi_net_add_addr;
++extern grub_command_func_t grub_efi_net_bootp;
++extern grub_command_func_t grub_efi_net_bootp6;
++
++#endif /* ! GRUB_NET_EFI_HEADER */
diff --git a/SOURCES/0078-make-better-backtraces.patch b/SOURCES/0078-make-better-backtraces.patch
deleted file mode 100644
index a65af3d..0000000
--- a/SOURCES/0078-make-better-backtraces.patch
+++ /dev/null
@@ -1,910 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 9 Jul 2019 17:05:03 +0200
-Subject: [PATCH] make better backtraces
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- Makefile.util.def                       |   6 ++
- grub-core/Makefile.core.def             |  16 ++--
- grub-core/{lib => commands}/backtrace.c |   2 +-
- grub-core/gdb/cstub.c                   |   1 -
- grub-core/kern/arm64/backtrace.c        |  94 ++++++++++++++++++++++++
- grub-core/kern/backtrace.c              |  97 +++++++++++++++++++++++++
- grub-core/kern/dl.c                     |  45 ++++++++++++
- grub-core/kern/i386/backtrace.c         | 125 ++++++++++++++++++++++++++++++++
- grub-core/kern/i386/pc/init.c           |   4 +-
- grub-core/kern/ieee1275/init.c          |   1 -
- grub-core/kern/misc.c                   |  13 ++--
- grub-core/kern/mm.c                     |   6 +-
- grub-core/lib/arm64/backtrace.c         |  62 ----------------
- grub-core/lib/i386/backtrace.c          |  78 --------------------
- include/grub/backtrace.h                |  10 ++-
- include/grub/dl.h                       |   2 +
- include/grub/kernel.h                   |   3 +
- grub-core/kern/arm/efi/startup.S        |   2 +
- grub-core/kern/arm/startup.S            |   2 +
- grub-core/kern/arm64/efi/startup.S      |   2 +
- grub-core/kern/i386/qemu/startup.S      |   3 +-
- grub-core/kern/ia64/efi/startup.S       |   3 +-
- grub-core/kern/sparc64/ieee1275/crt0.S  |   3 +-
- grub-core/Makefile.am                   |   1 +
- 24 files changed, 414 insertions(+), 167 deletions(-)
- rename grub-core/{lib => commands}/backtrace.c (98%)
- create mode 100644 grub-core/kern/arm64/backtrace.c
- create mode 100644 grub-core/kern/backtrace.c
- create mode 100644 grub-core/kern/i386/backtrace.c
- delete mode 100644 grub-core/lib/arm64/backtrace.c
- delete mode 100644 grub-core/lib/i386/backtrace.c
-
-diff --git a/Makefile.util.def b/Makefile.util.def
-index afc4d7b0c3e..41906486a71 100644
---- a/Makefile.util.def
-+++ b/Makefile.util.def
-@@ -51,6 +51,12 @@ library = {
-   common = grub-core/partmap/msdos.c;
-   common = grub-core/fs/proc.c;
-   common = grub-core/fs/archelp.c;
-+  common = grub-core/kern/backtrace.c;
-+
-+  x86 = grub-core/kern/i386/backtrace.c;
-+  i386_xen = grub-core/kern/i386/backtrace.c;
-+  x86_64_xen = grub-core/kern/i386/backtrace.c;
-+  arm64 = grub-core/kern/arm64/backtrace.c;
- };
- 
- library = {
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 5354f9613d3..4b7c45a7b06 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -142,6 +142,12 @@ kernel = {
-   common = kern/rescue_reader.c;
-   common = kern/term.c;
-   common = kern/verifiers.c;
-+  common = kern/backtrace.c;
-+
-+  x86 = kern/i386/backtrace.c;
-+  i386_xen = kern/i386/backtrace.c;
-+  x86_64_xen = kern/i386/backtrace.c;
-+  arm64 = kern/arm64/backtrace.c;
- 
-   noemu = kern/compiler-rt.c;
-   noemu = kern/mm.c;
-@@ -188,9 +194,6 @@ kernel = {
- 
-   softdiv = lib/division.c;
- 
--  x86 = lib/i386/backtrace.c;
--  x86 = lib/backtrace.c;
--
-   i386 = kern/i386/dl.c;
-   i386_xen = kern/i386/dl.c;
-   i386_xen_pvh = kern/i386/dl.c;
-@@ -2398,15 +2401,12 @@ module = {
- 
- module = {
-   name = backtrace;
--  x86 = lib/i386/backtrace.c;
--  i386_xen_pvh = lib/i386/backtrace.c;
--  i386_xen = lib/i386/backtrace.c;
--  x86_64_xen = lib/i386/backtrace.c;
--  common = lib/backtrace.c;
-+  common = commands/backtrace.c;
-   enable = x86;
-   enable = i386_xen_pvh;
-   enable = i386_xen;
-   enable = x86_64_xen;
-+  enable = arm64;
- };
- 
- module = {
-diff --git a/grub-core/lib/backtrace.c b/grub-core/commands/backtrace.c
-similarity index 98%
-rename from grub-core/lib/backtrace.c
-rename to grub-core/commands/backtrace.c
-index c0ad6ab8be1..8b5ec3913b5 100644
---- a/grub-core/lib/backtrace.c
-+++ b/grub-core/commands/backtrace.c
-@@ -54,7 +54,7 @@ grub_cmd_backtrace (grub_command_t cmd __attribute__ ((unused)),
- 		    int argc __attribute__ ((unused)),
- 		    char **args __attribute__ ((unused)))
- {
--  grub_backtrace ();
-+  grub_backtrace (1);
-   return 0;
- }
- 
-diff --git a/grub-core/gdb/cstub.c b/grub-core/gdb/cstub.c
-index b64acd70fee..99281472d36 100644
---- a/grub-core/gdb/cstub.c
-+++ b/grub-core/gdb/cstub.c
-@@ -215,7 +215,6 @@ grub_gdb_trap (int trap_no)
-       grub_printf ("Unhandled exception 0x%x at ", trap_no);
-       grub_backtrace_print_address ((void *) grub_gdb_regs[PC]);
-       grub_printf ("\n");
--      grub_backtrace_pointer ((void *) grub_gdb_regs[EBP]);
-       grub_fatal ("Unhandled exception");
-     }
- 
-diff --git a/grub-core/kern/arm64/backtrace.c b/grub-core/kern/arm64/backtrace.c
-new file mode 100644
-index 00000000000..019c6fdfef2
---- /dev/null
-+++ b/grub-core/kern/arm64/backtrace.c
-@@ -0,0 +1,94 @@
-+/*
-+ *  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/misc.h>
-+#include <grub/command.h>
-+#include <grub/err.h>
-+#include <grub/dl.h>
-+#include <grub/mm.h>
-+#include <grub/term.h>
-+#include <grub/backtrace.h>
-+
-+#define MAX_STACK_FRAME 102400
-+
-+struct fplr
-+{
-+  void *lr;
-+  struct fplr *fp;
-+};
-+
-+void
-+grub_backtrace_pointer (void *frame, unsigned int skip)
-+{
-+  unsigned int x = 0;
-+  struct fplr *fplr = (struct fplr *)frame;
-+
-+  while (fplr)
-+    {
-+      const char *name = NULL;
-+      char *addr = NULL;
-+
-+      grub_dprintf("backtrace", "fp is %p next_fp is %p\n",
-+		   fplr, fplr->fp);
-+
-+      if (x >= skip)
-+	{
-+	  name = grub_get_symbol_by_addr (fplr->lr, 1);
-+	  if (name)
-+	    addr = grub_resolve_symbol (name);
-+	  grub_backtrace_print_address (fplr->lr);
-+
-+	  if (addr && addr != fplr->lr)
-+	    grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr,
-+			 (void *)((grub_uint64_t)fplr->lr - (grub_uint64_t)addr));
-+	  else
-+	    grub_printf(" %s() %p \n", name ? name : "unknown", addr);
-+
-+	}
-+
-+      x += 1;
-+
-+      if (fplr->fp < fplr ||
-+	  (grub_uint64_t)fplr->fp - (grub_uint64_t)fplr > MAX_STACK_FRAME ||
-+	  fplr->fp == fplr)
-+	{
-+	  break;
-+	}
-+      fplr = fplr->fp;
-+    }
-+}
-+
-+asm ("\t.global \"_text\"\n"
-+     "_text:\n"
-+     "\t.quad .text\n"
-+     "\t.global \"_data\"\n"
-+     "_data:\n"
-+     "\t.quad .data\n"
-+     );
-+
-+extern grub_uint64_t _text;
-+extern grub_uint64_t _data;
-+
-+void
-+grub_backtrace_arch (unsigned int skip)
-+{
-+  grub_printf ("Backtrace (.text %p .data %p):\n",
-+	       (void *)_text, (void *)_data);
-+  skip += 1;
-+  grub_backtrace_pointer(__builtin_frame_address(0), skip);
-+}
-diff --git a/grub-core/kern/backtrace.c b/grub-core/kern/backtrace.c
-new file mode 100644
-index 00000000000..4a82e865cc6
---- /dev/null
-+++ b/grub-core/kern/backtrace.c
-@@ -0,0 +1,97 @@
-+/*
-+ *  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/misc.h>
-+#include <grub/command.h>
-+#include <grub/err.h>
-+#include <grub/dl.h>
-+#include <grub/mm.h>
-+#include <grub/term.h>
-+#include <grub/backtrace.h>
-+
-+GRUB_MOD_LICENSE ("GPLv3+");
-+
-+static void
-+grub_backtrace_print_address_default (void *addr)
-+{
-+#ifndef GRUB_UTIL
-+  grub_dl_t mod;
-+  void *start_addr;
-+
-+  FOR_DL_MODULES (mod)
-+  {
-+    grub_dl_segment_t segment;
-+    for (segment = mod->segment; segment; segment = segment->next)
-+      if (segment->addr <= addr && (grub_uint8_t *) segment->addr
-+	  + segment->size > (grub_uint8_t *) addr)
-+	{
-+	  grub_printf ("%s.%x+%" PRIxGRUB_SIZE, mod->name,
-+		       segment->section,
-+		       (grub_size_t)
-+		       ((grub_uint8_t *)addr - (grub_uint8_t *)segment->addr));
-+	  return;
-+	}
-+  }
-+
-+  start_addr = grub_resolve_symbol ("_start");
-+  if (start_addr && start_addr < addr)
-+    grub_printf ("kernel+%" PRIxGRUB_SIZE,
-+		 (grub_size_t)
-+		  ((grub_uint8_t *)addr - (grub_uint8_t *)start_addr));
-+  else
-+#endif
-+    grub_printf ("%p", addr);
-+}
-+
-+static void
-+grub_backtrace_pointer_default (void *frame __attribute__((__unused__)),
-+				unsigned int skip __attribute__((__unused__)))
-+{
-+  return;
-+}
-+
-+void
-+grub_backtrace_pointer (void *frame, unsigned int skip)
-+     __attribute__((__weak__,
-+		    __alias__(("grub_backtrace_pointer_default"))));
-+
-+void
-+grub_backtrace_print_address (void *addr)
-+     __attribute__((__weak__,
-+		    __alias__(("grub_backtrace_print_address_default"))));
-+
-+static void
-+grub_backtrace_arch_default(unsigned int skip)
-+{
-+  grub_backtrace_pointer(__builtin_frame_address(0), skip + 1);
-+}
-+
-+void grub_backtrace_arch (unsigned int skip)
-+     __attribute__((__weak__, __alias__(("grub_backtrace_arch_default"))));
-+
-+void grub_backtrace (unsigned int skip)
-+{
-+  grub_backtrace_arch(skip + 1);
-+}
-+
-+void grub_debug_backtrace (const char * const debug,
-+			   unsigned int skip)
-+{
-+  if (grub_debug_enabled (debug))
-+    grub_backtrace (skip + 1);
-+}
-diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
-index 7afb9e6f724..88d2077709e 100644
---- a/grub-core/kern/dl.c
-+++ b/grub-core/kern/dl.c
-@@ -124,6 +124,50 @@ grub_dl_resolve_symbol (const char *name)
-   return 0;
- }
- 
-+void *
-+grub_resolve_symbol (const char *name)
-+{
-+	grub_symbol_t sym;
-+
-+	sym = grub_dl_resolve_symbol (name);
-+	if (sym)
-+		return sym->addr;
-+	return NULL;
-+}
-+
-+const char *
-+grub_get_symbol_by_addr(const void *addr, int isfunc)
-+{
-+  unsigned int i;
-+  grub_symbol_t before = NULL, after = NULL;
-+  for (i = 0; i < GRUB_SYMTAB_SIZE; i++)
-+    {
-+      grub_symbol_t sym;
-+      for (sym = grub_symtab[i]; sym; sym = sym->next)
-+	{
-+	  //grub_printf ("addr 0x%08llx symbol %s\n", (unsigned long long)sym->addr, sym->name);
-+	  if (sym->addr > addr)
-+	    {
-+	      if (!after || sym->addr > after->addr)
-+		after = sym;
-+	    }
-+
-+	  if (isfunc != sym->isfunc)
-+	    continue;
-+	  if (sym->addr > addr)
-+	    continue;
-+
-+	  if ((!before && sym->addr <= addr) || (before && before->addr <= sym->addr))
-+	    before = sym;
-+	}
-+    }
-+
-+  if (before && addr < after->addr)
-+    return before->name;
-+
-+  return NULL;
-+}
-+
- /* Register a symbol with the name NAME and the address ADDR.  */
- grub_err_t
- grub_dl_register_symbol (const char *name, void *addr, int isfunc,
-@@ -336,6 +380,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
-   const char *str;
-   Elf_Word size, entsize;
- 
-+  grub_dprintf ("modules", "Resolving symbols for \"%s\"\n", mod->name);
-   for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
-        i < e->e_shnum;
-        i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
-diff --git a/grub-core/kern/i386/backtrace.c b/grub-core/kern/i386/backtrace.c
-new file mode 100644
-index 00000000000..2413f9a57db
---- /dev/null
-+++ b/grub-core/kern/i386/backtrace.c
-@@ -0,0 +1,125 @@
-+/*
-+ *  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/misc.h>
-+#include <grub/command.h>
-+#include <grub/err.h>
-+#include <grub/dl.h>
-+#include <grub/mm.h>
-+#include <grub/term.h>
-+#include <grub/backtrace.h>
-+
-+#define MAX_STACK_FRAME 102400
-+
-+void
-+grub_backtrace_pointer (void *frame, unsigned int skip)
-+{
-+  void **ebp = (void **)frame;
-+  unsigned long x = 0;
-+
-+  while (ebp)
-+    {
-+      void **next_ebp = (void **)ebp[0];
-+      const char *name = NULL;
-+      char *addr = NULL;
-+
-+      grub_dprintf("backtrace", "ebp is %p next_ebp is %p\n", ebp, next_ebp);
-+
-+      if (x >= skip)
-+	{
-+	  name = grub_get_symbol_by_addr (ebp[1], 1);
-+	  if (name)
-+	    addr = grub_resolve_symbol (name);
-+	  grub_backtrace_print_address (ebp[1]);
-+
-+	  if (addr && addr != ebp[1])
-+	    grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr,
-+			 (char *)((char *)ebp[1] - addr));
-+	  else
-+	    grub_printf(" %s() %p \n", name ? name : "unknown", addr);
-+
-+#if 0
-+	  grub_printf ("(");
-+	  for (i = 0, arg = ebp[2]; arg != next_ebp && i < 12; arg++, i++)
-+	    grub_printf ("%p,", arg);
-+	  grub_printf (")\n");
-+#endif
-+	}
-+
-+      x += 1;
-+
-+      if (next_ebp < ebp || next_ebp - ebp > MAX_STACK_FRAME || next_ebp == ebp)
-+	{
-+	  //grub_printf ("Invalid stack frame at %p (%p)\n", ebp, next_ebp);
-+	  break;
-+	}
-+      ebp = next_ebp;
-+    }
-+}
-+
-+#if defined (__x86_64__)
-+asm ("\t.global \"_text\"\n"
-+     "_text:\n"
-+     "\t.quad .text\n"
-+     "\t.global \"_data\"\n"
-+     "_data:\n"
-+     "\t.quad .data\n"
-+     );
-+#elif defined(__i386__)
-+asm ("\t.global \"_text\"\n"
-+     "_text:\n"
-+     "\t.long .text\n"
-+     "\t.global \"_data\"\n"
-+     "_data:\n"
-+     "\t.long .data\n"
-+     );
-+#else
-+#warning I dunno...
-+#endif
-+
-+extern unsigned long _text;
-+extern unsigned long _data;
-+
-+#ifdef GRUB_UTIL
-+#define EXT_C(x) x
-+#endif
-+
-+void
-+grub_backtrace_arch (unsigned int skip)
-+{
-+  grub_printf ("Backtrace (.text %p .data %p):\n",
-+	       (void *)_text, (void *)_data);
-+  skip += 1;
-+#if defined (__x86_64__)
-+  asm volatile ("movq %%rbp, %%rdi\n"
-+		"movq 0, %%rsi\n"
-+		"movl %0, %%esi\n"
-+		"call " EXT_C("grub_backtrace_pointer")
-+		:
-+		: "r" (skip));
-+#elif defined(__i386__)
-+  asm volatile ("addl $8, %%esp\n"
-+		"pushl %0\n"
-+		"pushl %%ebp\n"
-+		"call " EXT_C("grub_backtrace_pointer")
-+		:
-+		: "r" (skip));
-+#else
-+  grub_backtrace_pointer(__builtin_frame_address(0), skip);
-+#endif
-+}
-diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c
-index 27bc68b8a53..b51d0abfa6e 100644
---- a/grub-core/kern/i386/pc/init.c
-+++ b/grub-core/kern/i386/pc/init.c
-@@ -153,7 +153,7 @@ compact_mem_regions (void)
- }
- 
- grub_addr_t grub_modbase;
--extern grub_uint8_t _start[], _edata[];
-+extern grub_uint8_t _edata[];
- 
- /* Helper for grub_machine_init.  */
- static int
-@@ -217,7 +217,7 @@ grub_machine_init (void)
-   /* This has to happen before any BIOS calls. */
-   grub_via_workaround_init ();
- 
--  grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - _start);
-+  grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - (grub_uint8_t *)_start);
- 
-   /* Initialize the console as early as possible.  */
-   grub_console_init ();
-diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
-index 0cd2a627231..937c1bc44cb 100644
---- a/grub-core/kern/ieee1275/init.c
-+++ b/grub-core/kern/ieee1275/init.c
-@@ -63,7 +63,6 @@
- #define HEAP_MAX_ADDR		(unsigned long) (32 * 1024 * 1024)
- #endif
- 
--extern char _start[];
- extern char _end[];
- 
- #ifdef __sparc__
-diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
-index c60601b699d..a432a6be54a 100644
---- a/grub-core/kern/misc.c
-+++ b/grub-core/kern/misc.c
-@@ -1197,15 +1197,15 @@ grub_printf_fmt_check (const char *fmt, const char *fmt_expected)
- 
- 
- /* Abort GRUB. This function does not return.  */
--static void __attribute__ ((noreturn))
-+static inline void __attribute__ ((noreturn))
- grub_abort (void)
- {
--#ifndef GRUB_UTIL
--#if (defined(__i386__) || defined(__x86_64__)) && !defined(GRUB_MACHINE_EMU)
--  grub_backtrace();
-+#if !defined(GRUB_MACHINE_EMU) && !defined(GRUB_UTIL)
-+  grub_backtrace (1);
-+#else
-+  grub_printf ("\n");
- #endif
--#endif
--  grub_printf ("\nAborted.");
-+  grub_printf ("Aborted.");
- 
- #ifndef GRUB_UTIL
-   if (grub_term_inputs)
-@@ -1232,6 +1232,7 @@ grub_fatal (const char *fmt, ...)
- {
-   va_list ap;
- 
-+  grub_printf ("\n");
-   va_start (ap, fmt);
-   grub_vprintf (_(fmt), ap);
-   va_end (ap);
-diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
-index c070afc621f..d8c8377578b 100644
---- a/grub-core/kern/mm.c
-+++ b/grub-core/kern/mm.c
-@@ -97,13 +97,13 @@ get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r)
-       break;
- 
-   if (! *r)
--    grub_fatal ("out of range pointer %p", ptr);
-+    grub_fatal ("out of range pointer %p\n", ptr);
- 
-   *p = (grub_mm_header_t) ptr - 1;
-   if ((*p)->magic == GRUB_MM_FREE_MAGIC)
--    grub_fatal ("double free at %p", *p);
-+    grub_fatal ("double free at %p\n", *p);
-   if ((*p)->magic != GRUB_MM_ALLOC_MAGIC)
--    grub_fatal ("alloc magic is broken at %p: %lx", *p,
-+    grub_fatal ("alloc magic is broken at %p: %lx\n", *p,
- 		(unsigned long) (*p)->magic);
- }
- 
-diff --git a/grub-core/lib/arm64/backtrace.c b/grub-core/lib/arm64/backtrace.c
-deleted file mode 100644
-index 1079b5380e1..00000000000
---- a/grub-core/lib/arm64/backtrace.c
-+++ /dev/null
-@@ -1,62 +0,0 @@
--/*
-- *  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/misc.h>
--#include <grub/command.h>
--#include <grub/err.h>
--#include <grub/dl.h>
--#include <grub/mm.h>
--#include <grub/term.h>
--#include <grub/backtrace.h>
--
--#define MAX_STACK_FRAME 102400
--
--void
--grub_backtrace_pointer (int frame)
--{
--  while (1)
--    {
--      void *lp = __builtin_return_address (frame);
--      if (!lp)
--	break;
--
--      lp = __builtin_extract_return_addr (lp);
--
--      grub_printf ("%p: ", lp);
--      grub_backtrace_print_address (lp);
--      grub_printf (" (");
--      for (i = 0; i < 2; i++)
--	grub_printf ("%p,", ((void **)ptr) [i + 2]);
--      grub_printf ("%p)\n", ((void **)ptr) [i + 2]);
--      nptr = *(void **)ptr;
--      if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME
--	  || nptr == ptr)
--	{
--	  grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr);
--	  break;
--	}
--      ptr = nptr;
--    }
--}
--
--void
--grub_backtrace (void)
--{
--  grub_backtrace_pointer (1);
--}
--
-diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c
-deleted file mode 100644
-index c67273db3ae..00000000000
---- a/grub-core/lib/i386/backtrace.c
-+++ /dev/null
-@@ -1,78 +0,0 @@
--/*
-- *  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 <config.h>
--#ifdef GRUB_UTIL
--#define REALLY_GRUB_UTIL GRUB_UTIL
--#undef GRUB_UTIL
--#endif
--
--#include <grub/symbol.h>
--#include <grub/dl.h>
--
--#ifdef REALLY_GRUB_UTIL
--#define GRUB_UTIL REALLY_GRUB_UTIL
--#undef REALLY_GRUB_UTIL
--#endif
--
--#include <grub/misc.h>
--#include <grub/command.h>
--#include <grub/err.h>
--#include <grub/mm.h>
--#include <grub/term.h>
--#include <grub/backtrace.h>
--
--#define MAX_STACK_FRAME 102400
--
--void
--grub_backtrace_pointer (void *ebp)
--{
--  void *ptr, *nptr;
--  unsigned i;
--
--  ptr = ebp;
--  while (1)
--    {
--      grub_printf ("%p: ", ptr);
--      grub_backtrace_print_address (((void **) ptr)[1]);
--      grub_printf (" (");
--      for (i = 0; i < 2; i++)
--	grub_printf ("%p,", ((void **)ptr) [i + 2]);
--      grub_printf ("%p)\n", ((void **)ptr) [i + 2]);
--      nptr = *(void **)ptr;
--      if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME
--	  || nptr == ptr)
--	{
--	  grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr);
--	  break;
--	}
--      ptr = nptr;
--    }
--}
--
--void
--grub_backtrace (void)
--{
--#ifdef __x86_64__
--  asm volatile ("movq %%rbp, %%rdi\n"
--		"callq *%%rax": :"a"(grub_backtrace_pointer));
--#else
--  asm volatile ("movl %%ebp, %%eax\n"
--		"calll *%%ecx": :"c"(grub_backtrace_pointer));
--#endif
--}
--
-diff --git a/include/grub/backtrace.h b/include/grub/backtrace.h
-index 395519762f0..275cf85e2d3 100644
---- a/include/grub/backtrace.h
-+++ b/include/grub/backtrace.h
-@@ -19,8 +19,14 @@
- #ifndef GRUB_BACKTRACE_HEADER
- #define GRUB_BACKTRACE_HEADER	1
- 
--void grub_backtrace (void);
--void grub_backtrace_pointer (void *ptr);
-+#include <grub/symbol.h>
-+#include <grub/types.h>
-+
-+void EXPORT_FUNC(grub_debug_backtrace) (const char * const debug,
-+					unsigned int skip);
-+void EXPORT_FUNC(grub_backtrace) (unsigned int skip);
-+void grub_backtrace_arch (unsigned int skip);
-+void grub_backtrace_pointer (void *ptr, unsigned int skip);
- void grub_backtrace_print_address (void *addr);
- 
- #endif
-diff --git a/include/grub/dl.h b/include/grub/dl.h
-index 91933b85f2c..2f76e6b0437 100644
---- a/include/grub/dl.h
-+++ b/include/grub/dl.h
-@@ -259,6 +259,8 @@ grub_dl_is_persistent (grub_dl_t mod)
- 
- #endif
- 
-+void * EXPORT_FUNC(grub_resolve_symbol) (const char *name);
-+const char * EXPORT_FUNC(grub_get_symbol_by_addr) (const void *addr, int isfunc);
- grub_err_t grub_dl_register_symbol (const char *name, void *addr,
- 				    int isfunc, grub_dl_t mod);
- 
-diff --git a/include/grub/kernel.h b/include/grub/kernel.h
-index abbca5ea335..300a9766cda 100644
---- a/include/grub/kernel.h
-+++ b/include/grub/kernel.h
-@@ -111,6 +111,9 @@ grub_addr_t grub_modules_get_end (void);
- 
- #endif
- 
-+void EXPORT_FUNC(start) (void);
-+void EXPORT_FUNC(_start) (void);
-+
- /* The start point of the C code.  */
- void grub_main (void) __attribute__ ((noreturn));
- 
-diff --git a/grub-core/kern/arm/efi/startup.S b/grub-core/kern/arm/efi/startup.S
-index 9f8265315a9..f3bc41f9d0f 100644
---- a/grub-core/kern/arm/efi/startup.S
-+++ b/grub-core/kern/arm/efi/startup.S
-@@ -23,6 +23,8 @@
- 	.file 	"startup.S"
- 	.text
- 	.arm
-+	.globl	start, _start
-+FUNCTION(start)
- FUNCTION(_start)
- 	/*
- 	 *  EFI_SYSTEM_TABLE and EFI_HANDLE are passed in r1/r0.
-diff --git a/grub-core/kern/arm/startup.S b/grub-core/kern/arm/startup.S
-index 3946fe8e183..5679a1d00ad 100644
---- a/grub-core/kern/arm/startup.S
-+++ b/grub-core/kern/arm/startup.S
-@@ -48,6 +48,8 @@
- 	
- 	.text
- 	.arm
-+	.globl	start, _start
-+FUNCTION(start)
- FUNCTION(_start)
- 	b	codestart
- 	
-diff --git a/grub-core/kern/arm64/efi/startup.S b/grub-core/kern/arm64/efi/startup.S
-index 666a7ee3c92..41676bdb2b8 100644
---- a/grub-core/kern/arm64/efi/startup.S
-+++ b/grub-core/kern/arm64/efi/startup.S
-@@ -19,7 +19,9 @@
- #include <grub/symbol.h>
- 
- 	.file 	"startup.S"
-+	.globl start, _start
- 	.text
-+FUNCTION(start)
- FUNCTION(_start)
- 	/*
- 	 *  EFI_SYSTEM_TABLE and EFI_HANDLE are passed in x1/x0.
-diff --git a/grub-core/kern/i386/qemu/startup.S b/grub-core/kern/i386/qemu/startup.S
-index 0d89858d9b3..939f182fc74 100644
---- a/grub-core/kern/i386/qemu/startup.S
-+++ b/grub-core/kern/i386/qemu/startup.S
-@@ -24,7 +24,8 @@
- 
- 	.text
- 	.code32
--	.globl _start
-+	.globl start, _start
-+start:
- _start:
- 	jmp	codestart
- 
-diff --git a/grub-core/kern/ia64/efi/startup.S b/grub-core/kern/ia64/efi/startup.S
-index d75c6d7cc74..8f2a593e529 100644
---- a/grub-core/kern/ia64/efi/startup.S
-+++ b/grub-core/kern/ia64/efi/startup.S
-@@ -24,8 +24,9 @@
- 	.psr lsb
- 	.lsb
- 
--	.global _start
-+	.global start, _start
- 	.proc _start
-+start:
- _start:
- 	alloc loc0=ar.pfs,2,4,0,0
- 	mov loc1=rp
-diff --git a/grub-core/kern/sparc64/ieee1275/crt0.S b/grub-core/kern/sparc64/ieee1275/crt0.S
-index 03b916f0534..701bf63abcf 100644
---- a/grub-core/kern/sparc64/ieee1275/crt0.S
-+++ b/grub-core/kern/sparc64/ieee1275/crt0.S
-@@ -22,7 +22,8 @@
- 
- 	.text
- 	.align	4
--	.globl	_start
-+	.globl	start, _start
-+start:
- _start:
- 	ba	codestart
- 	 mov  %o4, %o0
-diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
-index 80e7a83edf9..f512573c0da 100644
---- a/grub-core/Makefile.am
-+++ b/grub-core/Makefile.am
-@@ -66,6 +66,7 @@ CLEANFILES += grub_script.yy.c grub_script.yy.h
- 
- include $(srcdir)/Makefile.core.am
- 
-+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/backtrace.h
- KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cache.h
- KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/command.h
- KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/device.h
diff --git a/SOURCES/0079-AUDIT-0-http-boot-tracker-bug.patch b/SOURCES/0079-AUDIT-0-http-boot-tracker-bug.patch
new file mode 100644
index 0000000..b487271
--- /dev/null
+++ b/SOURCES/0079-AUDIT-0-http-boot-tracker-bug.patch
@@ -0,0 +1,62 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Sebastian Krahmer <krahmer@suse.com>
+Date: Tue, 28 Nov 2017 17:24:38 +0800
+Subject: [PATCH] AUDIT-0: http boot tracker bug
+
+Fixing a memory leak in case of error, and a integer overflow, leading to a
+heap overflow due to overly large chunk sizes.
+
+We need to check against some maximum value, otherwise values like 0xffffffff
+will eventually lead in the allocation functions to small sized buffers, since
+the len is rounded up to the next reasonable alignment. The following memcpy
+will then smash the heap, leading to RCE.
+
+This is no big issue for pure http boot, since its going to execute an
+untrusted kernel anyway, but it will break trusted boot scenarios, where only
+signed code is allowed to be executed.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+---
+ grub-core/net/efi/net.c | 4 +++-
+ grub-core/net/http.c    | 5 ++++-
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
+index 86bce6535d..4bb308026c 100644
+--- a/grub-core/net/efi/net.c
++++ b/grub-core/net/efi/net.c
+@@ -645,8 +645,10 @@ grub_efihttp_chunk_read (grub_file_t file, char *buf,
+ 
+       rd = efi_net_interface (read, file, chunk, sz);
+ 
+-      if (rd <= 0)
++      if (rd <= 0) {
++	grub_free (chunk);
+ 	return rd;
++      }
+ 
+       if (buf)
+ 	{
+diff --git a/grub-core/net/http.c b/grub-core/net/http.c
+index 12a2632ea5..b52b558d63 100644
+--- a/grub-core/net/http.c
++++ b/grub-core/net/http.c
+@@ -31,7 +31,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+ enum
+   {
+-    HTTP_PORT = 80
++    HTTP_PORT = 80,
++    HTTP_MAX_CHUNK_SIZE = 0x80000000
+   };
+ 
+ 
+@@ -78,6 +79,8 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len)
+   if (data->in_chunk_len == 2)
+     {
+       data->chunk_rem = grub_strtoul (ptr, 0, 16);
++      if (data->chunk_rem > HTTP_MAX_CHUNK_SIZE)
++	  return GRUB_ERR_NET_PACKET_TOO_BIG;
+       grub_errno = GRUB_ERR_NONE;
+       if (data->chunk_rem == 0)
+ 	{
diff --git a/SOURCES/0079-normal-don-t-draw-our-startup-message-if-debug-is-se.patch b/SOURCES/0079-normal-don-t-draw-our-startup-message-if-debug-is-se.patch
deleted file mode 100644
index 9922f2b..0000000
--- a/SOURCES/0079-normal-don-t-draw-our-startup-message-if-debug-is-se.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 9 Nov 2017 15:58:52 -0500
-Subject: [PATCH] normal: don't draw our startup message if debug is set
-
----
- grub-core/normal/main.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
-index d5968797f4f..e349303c29b 100644
---- a/grub-core/normal/main.c
-+++ b/grub-core/normal/main.c
-@@ -432,6 +432,9 @@ grub_normal_reader_init (int nested)
-   const char *msg_esc = _("ESC at any time exits.");
-   char *msg_formatted;
- 
-+  if (grub_env_get ("debug") != NULL)
-+    return 0;
-+
-   msg_formatted = grub_xasprintf (_("Minimal BASH-like line editing is supported. For "
- 				    "the first word, TAB lists possible command completions. Anywhere "
- 				    "else TAB lists possible device or file completions. %s"),
diff --git a/SOURCES/0080-Work-around-some-minor-include-path-weirdnesses.patch b/SOURCES/0080-Work-around-some-minor-include-path-weirdnesses.patch
deleted file mode 100644
index 460d792..0000000
--- a/SOURCES/0080-Work-around-some-minor-include-path-weirdnesses.patch
+++ /dev/null
@@ -1,137 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Fri, 16 Mar 2018 13:28:57 -0400
-Subject: [PATCH] Work around some minor include path weirdnesses
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- include/grub/arm/efi/console.h    | 24 ++++++++++++++++++++++++
- include/grub/arm64/efi/console.h  | 24 ++++++++++++++++++++++++
- include/grub/i386/efi/console.h   | 24 ++++++++++++++++++++++++
- include/grub/x86_64/efi/console.h | 24 ++++++++++++++++++++++++
- 4 files changed, 96 insertions(+)
- create mode 100644 include/grub/arm/efi/console.h
- create mode 100644 include/grub/arm64/efi/console.h
- create mode 100644 include/grub/i386/efi/console.h
- create mode 100644 include/grub/x86_64/efi/console.h
-
-diff --git a/include/grub/arm/efi/console.h b/include/grub/arm/efi/console.h
-new file mode 100644
-index 00000000000..1592f6f76b5
---- /dev/null
-+++ b/include/grub/arm/efi/console.h
-@@ -0,0 +1,24 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2002,2005,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/>.
-+ */
-+
-+#ifndef GRUB_ARM_EFI_CONSOLE_H
-+#define GRUB_ARM_EFI_CONSOLE_H
-+
-+#include <efi/console.h>
-+
-+#endif /* ! GRUB_ARM_EFI_CONSOLE_H */
-diff --git a/include/grub/arm64/efi/console.h b/include/grub/arm64/efi/console.h
-new file mode 100644
-index 00000000000..95689339384
---- /dev/null
-+++ b/include/grub/arm64/efi/console.h
-@@ -0,0 +1,24 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2002,2005,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/>.
-+ */
-+
-+#ifndef GRUB_ARM64_EFI_CONSOLE_H
-+#define GRUB_ARM64_EFI_CONSOLE_H
-+
-+#include <efi/console.h>
-+
-+#endif /* ! GRUB_ARM64_EFI_CONSOLE_H */
-diff --git a/include/grub/i386/efi/console.h b/include/grub/i386/efi/console.h
-new file mode 100644
-index 00000000000..9231375cb07
---- /dev/null
-+++ b/include/grub/i386/efi/console.h
-@@ -0,0 +1,24 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2002,2005,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/>.
-+ */
-+
-+#ifndef GRUB_I386_EFI_CONSOLE_H
-+#define GRUB_I386_EFI_CONSOLE_H
-+
-+#include <efi/console.h>
-+
-+#endif /* ! GRUB_I386_EFI_CONSOLE_H */
-diff --git a/include/grub/x86_64/efi/console.h b/include/grub/x86_64/efi/console.h
-new file mode 100644
-index 00000000000..dba9d8678d0
---- /dev/null
-+++ b/include/grub/x86_64/efi/console.h
-@@ -0,0 +1,24 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2002,2005,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/>.
-+ */
-+
-+#ifndef GRUB_X86_64_EFI_CONSOLE_H
-+#define GRUB_X86_64_EFI_CONSOLE_H
-+
-+#include <efi/console.h>
-+
-+#endif /* ! GRUB_X86_64_EFI_CONSOLE_H */
diff --git a/SOURCES/0080-grub-editenv-Add-incr-command-to-increment-integer-v.patch b/SOURCES/0080-grub-editenv-Add-incr-command-to-increment-integer-v.patch
new file mode 100644
index 0000000..6e2e4e2
--- /dev/null
+++ b/SOURCES/0080-grub-editenv-Add-incr-command-to-increment-integer-v.patch
@@ -0,0 +1,93 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 4 Jun 2018 19:49:47 +0200
+Subject: [PATCH] grub-editenv: Add "incr" command to increment integer value
+ env. variables
+
+To be able to automatically detect if the last boot was successful,
+We want to keep count of succesful / failed boots in some integer
+environment variable.
+
+This commit adds a grub-editenvt "incr" command to increment such
+integer value env. variables by 1 for use from various boot scripts.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ util/grub-editenv.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 50 insertions(+)
+
+diff --git a/util/grub-editenv.c b/util/grub-editenv.c
+index db6f187cc6..948eec8a11 100644
+--- a/util/grub-editenv.c
++++ b/util/grub-editenv.c
+@@ -53,6 +53,9 @@ static struct argp_option options[] = {
+   /* TRANSLATORS: "unset" is a keyword. It's a summary of "unset" subcommand.  */
+   {N_("unset [NAME ...]"),    0, 0, OPTION_DOC|OPTION_NO_USAGE,
+    N_("Delete variables."), 0},
++  /* TRANSLATORS: "incr" is a keyword. It's a summary of "incr" subcommand.  */
++  {N_("incr [NAME ...]"),     0, 0, OPTION_DOC|OPTION_NO_USAGE,
++   N_("Increase value of integer variables."), 0},
+ 
+   {0,         0, 0, OPTION_DOC, N_("Options:"), -1},
+   {"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
+@@ -253,6 +256,51 @@ unset_variables (const char *name, int argc, char *argv[])
+   grub_envblk_close (envblk);
+ }
+ 
++struct get_int_value_params {
++  char *varname;
++  int value;
++};
++
++static int
++get_int_value (const char *varname, const char *value, void *hook_data)
++{
++  struct get_int_value_params *params = hook_data;
++
++  if (strcmp (varname, params->varname) == 0) {
++    params->value = strtol (value, NULL, 10);
++    return 1;
++  }
++  return 0;
++}
++
++static void
++incr_variables (const char *name, int argc, char *argv[])
++{
++  grub_envblk_t envblk;
++  char buf[16];
++
++  envblk = open_envblk_file (name);
++  while (argc)
++    {
++      struct get_int_value_params params = {
++        .varname = argv[0],
++        .value = 0, /* Consider unset variables 0 */
++      };
++
++      grub_envblk_iterate (envblk, &params, get_int_value);
++      snprintf(buf, sizeof(buf), "%d", params.value + 1);
++
++      if (! grub_envblk_set (envblk, argv[0], buf))
++        grub_util_error ("%s", _("environment block too small"));
++
++      argc--;
++      argv++;
++    }
++
++  write_envblk (name, envblk);
++  grub_envblk_close (envblk);
++}
++
+ int
+ main (int argc, char *argv[])
+ {
+@@ -292,6 +340,8 @@ main (int argc, char *argv[])
+     set_variables (filename, argc - curindex, argv + curindex);
+   else if (strcmp (command, "unset") == 0)
+     unset_variables (filename, argc - curindex, argv + curindex);
++  else if (strcmp (command, "incr") == 0)
++    incr_variables (filename, argc - curindex, argv + curindex);
+   else
+     {
+       char *program = xstrdup(program_name);
diff --git a/SOURCES/0081-Add-auto-hide-menu-support.patch b/SOURCES/0081-Add-auto-hide-menu-support.patch
new file mode 100644
index 0000000..a4fbe4a
--- /dev/null
+++ b/SOURCES/0081-Add-auto-hide-menu-support.patch
@@ -0,0 +1,183 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 6 Jun 2018 08:44:11 +0200
+Subject: [PATCH] Add auto-hide menu support
+
+On single-os systems we do not want to show the menu, unless something
+went wrong with the previous boot, in which case the user may need the
+menu to debug/fix the problem.
+
+This commit adds a new grub.d/00_menu_auto_hide file which emits a
+config snippet implementing this. I've chosen to do this in a separate
+grub.d file because chances of this going upstream are small and this way
+it will be easier to rebase.
+
+Since auto-hiding the menu requires detecting the previous boot was ok,
+we get fastboot support (where we don't check for a key at all) for free
+so this commit also adds support for this.
+
+The new config-file code uses the following variables:
+
+menu_auto_hide     Set this to "1" to activate the new auto-hide feature
+                   Set this to "2" to auto-hide the menu even when multiple
+                   operating systems are installed. Note the menu will still
+                   auto show after booting an other os as that won't set
+                   boot_success.
+menu_show_once     Set this to "1" to force showing the menu once.
+boot_success       The OS sets this to "1" to indicate a successful boot.
+boot_indeterminate The OS increments this integer when rebooting after e.g.
+                   installing updates or a selinux relabel.
+fastboot           If set to "1" and the conditions for auto-hiding the menu
+                   are met, the menu is not shown and all checks for keypresses
+                   are skipped, booting the default immediately.
+
+30_os-prober.in changes somewhat inspired by:
+https://git.launchpad.net/~ubuntu-core-dev/grub/+git/ubuntu/tree/debian/patches/quick_boot.patch
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ Makefile.util.def                |  6 +++++
+ util/grub.d/01_menu_auto_hide.in | 48 ++++++++++++++++++++++++++++++++++++++++
+ util/grub.d/30_os-prober.in      | 18 +++++++++++++++
+ 3 files changed, 72 insertions(+)
+ create mode 100644 util/grub.d/01_menu_auto_hide.in
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index bda9fd1211..cb8e3c3270 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -458,6 +458,12 @@ script = {
+   installdir = grubconf;
+ };
+ 
++script = {
++  name = '01_menu_auto_hide';
++  common = util/grub.d/01_menu_auto_hide.in;
++  installdir = grubconf;
++};
++
+ script = {
+   name = '01_users';
+   common = util/grub.d/01_users.in;
+diff --git a/util/grub.d/01_menu_auto_hide.in b/util/grub.d/01_menu_auto_hide.in
+new file mode 100644
+index 0000000000..ad175870a5
+--- /dev/null
++++ b/util/grub.d/01_menu_auto_hide.in
+@@ -0,0 +1,48 @@
++#! /bin/sh
++
++# Disable / skip generating menu-auto-hide config parts on serial terminals
++for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do
++  case "$x" in
++    serial*)
++      exit 0
++      ;;
++  esac
++done
++
++cat << EOF
++if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then
++  set last_boot_ok=1
++else
++  set last_boot_ok=0
++fi
++
++# Reset boot_indeterminate after a successful boot
++if [ "\${boot_success}" = "1" ] ; then
++  set boot_indeterminate=0
++# Avoid boot_indeterminate causing the menu to be hidden more then once
++elif [ "\${boot_indeterminate}" = "1" ]; then
++  set boot_indeterminate=2
++fi
++set boot_success=0
++save_env boot_success boot_indeterminate
++
++if [ x\$feature_timeout_style = xy ] ; then
++  if [ "\${menu_show_once}" ]; then
++    unset menu_show_once
++    save_env menu_show_once
++    set timeout_style=menu
++    set timeout=60
++  elif [ "\${menu_auto_hide}" -a "\${last_boot_ok}" = "1" ]; then
++    set orig_timeout_style=\${timeout_style}
++    set orig_timeout=\${timeout}
++    if [ "\${fastboot}" = "1" ]; then
++      # timeout_style=menu + timeout=0 avoids the countdown code keypress check
++      set timeout_style=menu
++      set timeout=0
++    else
++      set timeout_style=hidden
++      set timeout=1
++    fi
++  fi
++fi
++EOF
+diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in
+index 4b27bd2015..3c9431cfcf 100644
+--- a/util/grub.d/30_os-prober.in
++++ b/util/grub.d/30_os-prober.in
+@@ -42,6 +42,7 @@ if [ -z "${OSPROBED}" ] ; then
+ fi
+ 
+ osx_entry() {
++    found_other_os=1
+     # TRANSLATORS: it refers on the OS residing on device %s
+     onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+     hints=""
+@@ -102,6 +103,7 @@ for OS in ${OSPROBED} ; do
+ 
+   case ${BOOT} in
+     chain)
++      found_other_os=1
+ 
+ 	  onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+       cat << EOF
+@@ -132,6 +134,7 @@ EOF
+ EOF
+     ;;
+     efi)
++      found_other_os=1
+ 
+ 	EFIPATH=${DEVICE#*@}
+ 	DEVICE=${DEVICE%@*}
+@@ -176,6 +179,7 @@ EOF
+ 	  LINITRD="${LINITRD#/boot}"
+ 	fi
+ 
++        found_other_os=1
+ 	onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+ 	recovery_params="$(echo "${LPARAMS}" | grep single)" || true
+ 	counter=1
+@@ -257,6 +261,7 @@ EOF
+       done
+     ;;
+     hurd)
++      found_other_os=1
+       onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+       cat << EOF
+ menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' {
+@@ -283,6 +288,7 @@ EOF
+ EOF
+     ;;
+     minix)
++      found_other_os=1
+ 	  cat << EOF
+ menuentry "${LONGNAME} (on ${DEVICE}, Multiboot)" {
+ EOF
+@@ -299,3 +305,15 @@ EOF
+     ;;
+   esac
+ done
++
++# We override the results of the menu_auto_hide code here, this is a bit ugly,
++# but grub-mkconfig writes out the file linearly, so this is the only way
++if [ "${found_other_os}" = "1" ]; then
++  cat << EOF
++# Other OS found, undo autohiding of menu unless menu_auto_hide=2
++if [ "\${orig_timeout_style}" -a "\${menu_auto_hide}" != "2" ]; then
++  set timeout_style=\${orig_timeout_style}
++  set timeout=\${orig_timeout}
++fi
++EOF
++fi
diff --git a/SOURCES/0081-Make-it-possible-to-enabled-build-id-sha1.patch b/SOURCES/0081-Make-it-possible-to-enabled-build-id-sha1.patch
deleted file mode 100644
index 356a4d8..0000000
--- a/SOURCES/0081-Make-it-possible-to-enabled-build-id-sha1.patch
+++ /dev/null
@@ -1,61 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 25 Jun 2015 15:41:06 -0400
-Subject: [PATCH] Make it possible to enabled --build-id=sha1
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- configure.ac |  8 ++++++++
- acinclude.m4 | 19 +++++++++++++++++++
- 2 files changed, 27 insertions(+)
-
-diff --git a/configure.ac b/configure.ac
-index 537ed411469..b4455e4732d 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1470,7 +1470,15 @@ grub_PROG_TARGET_CC
- if test "x$TARGET_APPLE_LINKER" != x1 ; then
- grub_PROG_OBJCOPY_ABSOLUTE
- fi
-+
-+AC_ARG_ENABLE([build-id],
-+	      [AS_HELP_STRING([--enable-build-id],
-+                             [ask the linker to supply build-id notes (default=no)])])
-+if test x$enable_build_id = xyes; then
-+grub_PROG_LD_BUILD_ID_SHA1
-+else
- grub_PROG_LD_BUILD_ID_NONE
-+fi
- if test "x$target_cpu" = xi386; then
-   if test "$platform" != emu && test "x$TARGET_APPLE_LINKER" != x1 ; then
-     if test ! -z "$TARGET_IMG_LDSCRIPT"; then
-diff --git a/acinclude.m4 b/acinclude.m4
-index 6e14bb553c6..21238fcfd03 100644
---- a/acinclude.m4
-+++ b/acinclude.m4
-@@ -136,6 +136,25 @@ if test "x$grub_cv_prog_ld_build_id_none" = xyes; then
- fi
- ])
- 
-+dnl Supply --build-id=sha1 to ld if building modules.
-+dnl This suppresses warnings from ld on some systems
-+AC_DEFUN([grub_PROG_LD_BUILD_ID_SHA1],
-+[AC_MSG_CHECKING([whether linker accepts --build-id=sha1])
-+AC_CACHE_VAL(grub_cv_prog_ld_build_id_sha1,
-+[save_LDFLAGS="$LDFLAGS"
-+LDFLAGS="$LDFLAGS -Wl,--build-id=sha1"
-+AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
-+	       [grub_cv_prog_ld_build_id_sha1=yes],
-+	       [grub_cv_prog_ld_build_id_sha1=no])
-+LDFLAGS="$save_LDFLAGS"
-+])
-+AC_MSG_RESULT([$grub_cv_prog_ld_build_id_sha1])
-+
-+if test "x$grub_cv_prog_ld_build_id_sha1" = xyes; then
-+  TARGET_LDFLAGS="$TARGET_LDFLAGS -Wl,--build-id=sha1"
-+fi
-+])
-+
- dnl Check nm
- AC_DEFUN([grub_PROG_NM_WORKS],
- [AC_MSG_CHECKING([whether nm works])
diff --git a/SOURCES/0082-Add-grub-set-bootflag-utility.patch b/SOURCES/0082-Add-grub-set-bootflag-utility.patch
new file mode 100644
index 0000000..495bb13
--- /dev/null
+++ b/SOURCES/0082-Add-grub-set-bootflag-utility.patch
@@ -0,0 +1,290 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 12 Jun 2018 13:25:16 +0200
+Subject: [PATCH] Add grub-set-bootflag utility
+
+This commit adds a new grub-set-bootflag utility, which can be used
+to set known bootflags in the grubenv: boot_success or menu_show_once.
+
+grub-set-bootflag is different from grub-editenv in 2 ways:
+
+1) It is intended to be executed by regular users so must be installed
+as suid root. As such it is written to not use any existing grubenv
+related code for easy auditing.
+
+It can't be executed through pkexec because we want to call it under gdm
+and pkexec does not work under gdm due the gdm user having /sbin/nologin
+as shell.
+
+2) Since it can be executed by regular users it only allows setting
+(assigning a value of 1 to) bootflags which it knows about. Currently
+those are just boot_success and menu_show_once.
+
+This commit also adds a couple of example systemd and files which show
+how this can be used to set boot_success from a user-session:
+
+docs/grub-boot-success.service
+docs/grub-boot-success.timer
+
+The 2 grub-boot-success.systemd files should be placed in /lib/systemd/user
+and a symlink to grub-boot-success.timer should be added to
+/lib/systemd/user/timers.target.wants.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+[makhomed: grub-boot-success.timer: Only run if not in a container]
+Signed-off-by: Gena Makhomed <makhomed@gmail.com>
+[rharwood: migrate to h2m]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ Makefile.util.def              |   7 ++
+ util/grub-set-bootflag.c       | 172 +++++++++++++++++++++++++++++++++++++++++
+ conf/Makefile.extra-dist       |   3 +
+ docs/grub-boot-success.service |   6 ++
+ docs/grub-boot-success.timer   |   7 ++
+ docs/man/grub-set-bootflag.h2m |   2 +
+ 6 files changed, 197 insertions(+)
+ create mode 100644 util/grub-set-bootflag.c
+ create mode 100644 docs/grub-boot-success.service
+ create mode 100644 docs/grub-boot-success.timer
+ create mode 100644 docs/man/grub-set-bootflag.h2m
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index cb8e3c3270..d066652e9b 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -1429,3 +1429,10 @@ program = {
+   ldadd = grub-core/lib/gnulib/libgnu.a;
+   ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
+ };
++
++program = {
++  name = grub-set-bootflag;
++  installdir = sbin;
++  mansection = 1;
++  common = util/grub-set-bootflag.c;
++};
+diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c
+new file mode 100644
+index 0000000000..d506f7e75b
+--- /dev/null
++++ b/util/grub-set-bootflag.c
+@@ -0,0 +1,172 @@
++/* grub-set-bootflag.c - tool to set boot-flags in the grubenv. */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2018 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/>.
++ */
++
++/*
++ * NOTE this gets run by users as root (through pkexec), so this does not
++ * use any grub library / util functions to allow for easy auditing.
++ * The grub headers are only included to get certain defines.
++ */
++
++#include <config-util.h>     /* For *_DIR_NAME defines */
++#include <grub/types.h>
++#include <grub/lib/envblk.h> /* For GRUB_ENVBLK_DEFCFG define */
++#include <errno.h>
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++
++#include "progname.h"
++
++#define GRUBENV "/" GRUB_BOOT_DIR_NAME "/" GRUB_DIR_NAME "/" GRUB_ENVBLK_DEFCFG
++#define GRUBENV_SIZE 1024
++
++const char *bootflags[] = {
++  "boot_success",
++  "menu_show_once",
++  NULL
++};
++
++static void usage(FILE *out)
++{
++  int i;
++
++  fprintf (out, "Usage: 'grub-set-bootflag <bootflag>', where <bootflag> is one of:\n");
++  for (i = 0; bootflags[i]; i++)
++    fprintf (out, "  %s\n", bootflags[i]);
++}
++
++int main(int argc, char *argv[])
++{
++  /* NOTE buf must be at least the longest bootflag length + 4 bytes */
++  char env[GRUBENV_SIZE + 1], buf[64], *s;
++  const char *bootflag;
++  int i, len, ret;
++  FILE *f;
++
++  if (argc != 2)
++    {
++      usage (stderr);
++      return 1;
++    }
++  else if (!strcmp (argv[1], "--help"))
++    {
++      usage (stdout);
++      return 0;
++    }
++  else if (!strcmp (argv[1], "--version"))
++    {
++      printf ("grub-set-bootflag (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
++      return 0;
++    }
++
++  for (i = 0; bootflags[i]; i++)
++    if (!strcmp (argv[1], bootflags[i]))
++      break;
++  if (!bootflags[i])
++    {
++      fprintf (stderr, "Invalid bootflag: '%s'\n", argv[1]);
++      usage (stderr);
++      return 1;
++    }
++
++  bootflag = bootflags[i];
++  len = strlen (bootflag);
++
++  f = fopen (GRUBENV, "r");
++  if (!f)
++    {
++      perror ("Error opening " GRUBENV " for reading");
++      return 1;     
++    }
++
++  ret = fread (env, 1, GRUBENV_SIZE, f);
++  fclose (f);
++  if (ret != GRUBENV_SIZE)
++    {
++      errno = EINVAL;
++      perror ("Error reading from " GRUBENV);
++      return 1;     
++    }
++
++  /* 0 terminate env */
++  env[GRUBENV_SIZE] = 0;
++
++  if (strncmp (env, GRUB_ENVBLK_SIGNATURE, strlen (GRUB_ENVBLK_SIGNATURE)))
++    {
++      fprintf (stderr, "Error invalid environment block\n");
++      return 1;
++    }
++
++  /* Find a pre-existing definition of the bootflag */
++  s = strstr (env, bootflag);
++  while (s && s[len] != '=')
++    s = strstr (s + len, bootflag);
++
++  if (s && ((s[len + 1] != '0' && s[len + 1] != '1') || s[len + 2] != '\n'))
++    {
++      fprintf (stderr, "Pre-existing bootflag '%s' has unexpected value\n", bootflag);
++      return 1;     
++    }
++
++  /* No pre-existing bootflag? -> find free space */
++  if (!s)
++    {
++      for (i = 0; i < (len + 3); i++)
++        buf[i] = '#';
++      buf[i] = 0;
++      s = strstr (env, buf);
++    }
++
++  if (!s)
++    {
++      fprintf (stderr, "No space in grubenv to store bootflag '%s'\n", bootflag);
++      return 1;     
++    }
++
++  /* The grubenv is not 0 terminated, so memcpy the name + '=' , '1', '\n' */
++  snprintf(buf, sizeof(buf), "%s=1\n", bootflag);
++  memcpy(s, buf, len + 3);
++
++  /* "r+", don't truncate so that the diskspace stays reserved */
++  f = fopen (GRUBENV, "r+");
++  if (!f)
++    {
++      perror ("Error opening " GRUBENV " for writing");
++      return 1;     
++    }
++
++  ret = fwrite (env, 1, GRUBENV_SIZE, f);
++  if (ret != GRUBENV_SIZE)
++    {
++      perror ("Error writing to " GRUBENV);
++      return 1;     
++    }
++
++  ret = fflush (f);
++  if (ret)
++    {
++      perror ("Error flushing " GRUBENV);
++      return 1;     
++    }
++
++  fsync (fileno (f));
++  fclose (f);
++
++  return 0;
++}
+diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist
+index 8f1485d52a..ad235de7fc 100644
+--- a/conf/Makefile.extra-dist
++++ b/conf/Makefile.extra-dist
+@@ -15,6 +15,9 @@ EXTRA_DIST += docs/man
+ EXTRA_DIST += docs/autoiso.cfg
+ EXTRA_DIST += docs/grub.cfg
+ EXTRA_DIST += docs/osdetect.cfg
++EXTRA_DIST += docs/org.gnu.grub.policy
++EXTRA_DIST += docs/grub-boot-success.service
++EXTRA_DIST += docs/grub-boot-success.timer
+ 
+ EXTRA_DIST += conf/i386-cygwin-img-ld.sc
+ 
+diff --git a/docs/grub-boot-success.service b/docs/grub-boot-success.service
+new file mode 100644
+index 0000000000..80e79584c9
+--- /dev/null
++++ b/docs/grub-boot-success.service
+@@ -0,0 +1,6 @@
++[Unit]
++Description=Mark boot as successful
++
++[Service]
++Type=oneshot
++ExecStart=/usr/sbin/grub2-set-bootflag boot_success
+diff --git a/docs/grub-boot-success.timer b/docs/grub-boot-success.timer
+new file mode 100644
+index 0000000000..406f172005
+--- /dev/null
++++ b/docs/grub-boot-success.timer
+@@ -0,0 +1,7 @@
++[Unit]
++Description=Mark boot as successful after the user session has run 2 minutes
++ConditionUser=!@system
++ConditionVirtualization=!container
++
++[Timer]
++OnActiveSec=2min
+diff --git a/docs/man/grub-set-bootflag.h2m b/docs/man/grub-set-bootflag.h2m
+new file mode 100644
+index 0000000000..94ec0b92ed
+--- /dev/null
++++ b/docs/man/grub-set-bootflag.h2m
+@@ -0,0 +1,2 @@
++[NAME]
++grub-set-bootflag \- set a bootflag in the GRUB environment block
diff --git a/SOURCES/0082-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch b/SOURCES/0082-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch
deleted file mode 100644
index a8a757e..0000000
--- a/SOURCES/0082-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch
+++ /dev/null
@@ -1,56 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Sun, 28 Jun 2015 13:09:58 -0400
-Subject: [PATCH] Add grub_qdprintf() - grub_dprintf() without the file+line
- number.
-
-This just makes copy+paste of our debug loading info easier.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/kern/misc.c | 18 ++++++++++++++++++
- include/grub/misc.h   |  2 ++
- 2 files changed, 20 insertions(+)
-
-diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
-index a432a6be54a..9a2fae6398e 100644
---- a/grub-core/kern/misc.c
-+++ b/grub-core/kern/misc.c
-@@ -191,6 +191,24 @@ grub_real_dprintf (const char *file, const int line, const char *condition,
-     }
- }
- 
-+void
-+grub_qdprintf (const char *condition, const char *fmt, ...)
-+{
-+  va_list args;
-+  const char *debug = grub_env_get ("debug");
-+
-+  if (! debug)
-+    return;
-+
-+  if (grub_strword (debug, "all") || grub_strword (debug, condition))
-+    {
-+      va_start (args, fmt);
-+      grub_vprintf (fmt, args);
-+      va_end (args);
-+      grub_refresh ();
-+    }
-+}
-+
- #define PREALLOC_SIZE 255
- 
- int
-diff --git a/include/grub/misc.h b/include/grub/misc.h
-index fd18e6320b8..3adc4036e3b 100644
---- a/include/grub/misc.h
-+++ b/include/grub/misc.h
-@@ -345,6 +345,8 @@ void EXPORT_FUNC(grub_real_dprintf) (const char *file,
-                                      const int line,
-                                      const char *condition,
-                                      const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 4, 5)));
-+void EXPORT_FUNC(grub_qdprintf) (const char *condition,
-+				 const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 2, 3)));
- int EXPORT_FUNC(grub_vprintf) (const char *fmt, va_list args);
- int EXPORT_FUNC(grub_snprintf) (char *str, grub_size_t n, const char *fmt, ...)
-      __attribute__ ((format (GNU_PRINTF, 3, 4)));
diff --git a/SOURCES/0083-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch b/SOURCES/0083-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch
deleted file mode 100644
index 75de764..0000000
--- a/SOURCES/0083-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch
+++ /dev/null
@@ -1,178 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 25 Jun 2015 15:11:36 -0400
-Subject: [PATCH] Make a "gdb" dprintf that tells us load addresses.
-
-This makes a grub_dprintf() call during platform init and during module
-loading that tells us the virtual addresses of the .text and .data
-sections of grub-core/kernel.exec and any modules it loads.
-
-Specifically, it displays them in the gdb "add-symbol-file" syntax, with
-the presumption that there's a variable $grubdir that reflects the path
-to any such binaries.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/kern/dl.c       | 50 +++++++++++++++++++++++++++++++++++++++++++++++
- grub-core/kern/efi/efi.c  |  4 ++--
- grub-core/kern/efi/init.c | 26 +++++++++++++++++++++++-
- include/grub/efi/efi.h    |  2 +-
- 4 files changed, 78 insertions(+), 4 deletions(-)
-
-diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
-index 88d2077709e..9557254035e 100644
---- a/grub-core/kern/dl.c
-+++ b/grub-core/kern/dl.c
-@@ -501,6 +501,23 @@ grub_dl_find_section (Elf_Ehdr *e, const char *name)
-       return s;
-   return NULL;
- }
-+static long
-+grub_dl_find_section_index (Elf_Ehdr *e, const char *name)
-+{
-+  Elf_Shdr *s;
-+  const char *str;
-+  unsigned i;
-+
-+  s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
-+  str = (char *) e + s->sh_offset;
-+
-+  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
-+       i < e->e_shnum;
-+       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
-+    if (grub_strcmp (str + s->sh_name, name) == 0)
-+      return (long)i;
-+  return -1;
-+}
- 
- /* Me, Vladimir Serbinenko, hereby I add this module check as per new
-    GNU module policy. Note that this license check is informative only.
-@@ -653,6 +670,37 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
- 
-   return GRUB_ERR_NONE;
- }
-+static void
-+grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e)
-+{
-+  void *text, *data = NULL;
-+  long idx;
-+
-+  idx = grub_dl_find_section_index (e, ".text");
-+  if (idx < 0)
-+    return;
-+
-+  text = grub_dl_get_section_addr (mod, idx);
-+  if (!text)
-+    return;
-+
-+  idx = grub_dl_find_section_index (e, ".data");
-+  if (idx >= 0)
-+    data = grub_dl_get_section_addr (mod, idx);
-+
-+  if (data)
-+    grub_qdprintf ("gdb", "add-symbol-file \\\n"
-+		          "/usr/lib/debug/usr/lib/grub/%s-%s/%s.debug "
-+			  "\\\n %p -s .data %p\n",
-+		  GRUB_TARGET_CPU, GRUB_PLATFORM,
-+		  mod->name, text, data);
-+  else
-+    grub_qdprintf ("gdb", "add-symbol-file \\\n"
-+			   "/usr/lib/debug/usr/lib/grub/%s-%s/%s.debug "
-+			   "\\\n%p\n",
-+		  GRUB_TARGET_CPU, GRUB_PLATFORM,
-+		  mod->name, text);
-+}
- 
- /* Load a module from core memory.  */
- grub_dl_t
-@@ -712,6 +760,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
-   grub_dprintf ("modules", "module name: %s\n", mod->name);
-   grub_dprintf ("modules", "init function: %p\n", mod->init);
- 
-+  grub_dl_print_gdb_info (mod, e);
-+
-   if (grub_dl_add (mod))
-     {
-       grub_dl_unload (mod);
-diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
-index ae9885edb84..d6a2fb57789 100644
---- a/grub-core/kern/efi/efi.c
-+++ b/grub-core/kern/efi/efi.c
-@@ -296,7 +296,7 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
- /* Search the mods section from the PE32/PE32+ image. This code uses
-    a PE32 header, but should work with PE32+ as well.  */
- grub_addr_t
--grub_efi_modules_addr (void)
-+grub_efi_section_addr (const char *section_name)
- {
-   grub_efi_loaded_image_t *image;
-   struct grub_pe32_header *header;
-@@ -321,7 +321,7 @@ grub_efi_modules_addr (void)
-        i < coff_header->num_sections;
-        i++, section++)
-     {
--      if (grub_strcmp (section->name, "mods") == 0)
-+      if (grub_strcmp (section->name, section_name) == 0)
- 	break;
-     }
- 
-diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
-index 6d39bd3ad29..2d12e6188fd 100644
---- a/grub-core/kern/efi/init.c
-+++ b/grub-core/kern/efi/init.c
-@@ -115,10 +115,33 @@ grub_efi_env_init (void)
-   grub_free (envblk_s.buf);
- }
- 
-+static void
-+grub_efi_print_gdb_info (void)
-+{
-+  grub_addr_t text;
-+  grub_addr_t data;
-+
-+  text = grub_efi_section_addr (".text");
-+  if (!text)
-+    return;
-+
-+  data = grub_efi_section_addr (".data");
-+  if (data)
-+    grub_qdprintf ("gdb",
-+		  "add-symbol-file /usr/lib/debug/usr/lib/grub/%s-%s/"
-+		  "kernel.exec %p -s .data %p\n",
-+		  GRUB_TARGET_CPU, GRUB_PLATFORM, (void *)text, (void *)data);
-+  else
-+    grub_qdprintf ("gdb",
-+		  "add-symbol-file /usr/lib/debug/usr/lib/grub/%s-%s/"
-+		  "kernel.exec %p\n",
-+		  GRUB_TARGET_CPU, GRUB_PLATFORM, (void *)text);
-+}
-+
- void
- grub_efi_init (void)
- {
--  grub_modbase = grub_efi_modules_addr ();
-+  grub_modbase = grub_efi_section_addr ("mods");
-   /* First of all, initialize the console so that GRUB can display
-      messages.  */
-   grub_console_init ();
-@@ -142,6 +165,7 @@ grub_efi_init (void)
- 	      0, 0, 0, NULL);
- 
-   grub_efi_env_init ();
-+  grub_efi_print_gdb_info ();
-   grub_efidisk_init ();
- }
- 
-diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
-index 03f9a9d0118..2e0691454b1 100644
---- a/include/grub/efi/efi.h
-+++ b/include/grub/efi/efi.h
-@@ -138,7 +138,7 @@ grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh);
- grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, char *args);
- #endif
- 
--grub_addr_t grub_efi_modules_addr (void);
-+grub_addr_t grub_efi_section_addr (const char *section);
- 
- void grub_efi_mm_init (void);
- void grub_efi_mm_fini (void);
diff --git a/SOURCES/0083-docs-Add-grub-boot-indeterminate.service-example.patch b/SOURCES/0083-docs-Add-grub-boot-indeterminate.service-example.patch
new file mode 100644
index 0000000..96eff36
--- /dev/null
+++ b/SOURCES/0083-docs-Add-grub-boot-indeterminate.service-example.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 19 Jun 2018 15:20:54 +0200
+Subject: [PATCH] docs: Add grub-boot-indeterminate.service example
+
+This is an example service file, for use from
+/lib/systemd/system/system-update.target.wants
+to increment the boot_indeterminate variable when
+doing offline updates.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ docs/grub-boot-indeterminate.service | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+ create mode 100644 docs/grub-boot-indeterminate.service
+
+diff --git a/docs/grub-boot-indeterminate.service b/docs/grub-boot-indeterminate.service
+new file mode 100644
+index 0000000000..6c8dcb186b
+--- /dev/null
++++ b/docs/grub-boot-indeterminate.service
+@@ -0,0 +1,11 @@
++[Unit]
++Description=Mark boot as indeterminate
++DefaultDependencies=false
++Requires=sysinit.target
++After=sysinit.target
++Wants=system-update-pre.target
++Before=system-update-pre.target
++
++[Service]
++Type=oneshot
++ExecStart=/usr/bin/grub2-editenv - incr boot_indeterminate
diff --git a/SOURCES/0084-Fixup-for-newer-compiler.patch b/SOURCES/0084-Fixup-for-newer-compiler.patch
deleted file mode 100644
index 12dd193..0000000
--- a/SOURCES/0084-Fixup-for-newer-compiler.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 10 May 2018 13:40:19 -0400
-Subject: [PATCH] Fixup for newer compiler
-
----
- grub-core/fs/btrfs.c         | 2 +-
- include/grub/gpt_partition.h | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
-index 2b21cbaa67e..4cc86e9b79e 100644
---- a/grub-core/fs/btrfs.c
-+++ b/grub-core/fs/btrfs.c
-@@ -218,7 +218,7 @@ struct grub_btrfs_inode
-   grub_uint64_t size;
-   grub_uint8_t dummy2[0x70];
-   struct grub_btrfs_time mtime;
--} GRUB_PACKED;
-+} GRUB_PACKED  __attribute__ ((aligned(8)));
- 
- struct grub_btrfs_extent_data
- {
-diff --git a/include/grub/gpt_partition.h b/include/grub/gpt_partition.h
-index 7a93f43291c..8212697bf6b 100644
---- a/include/grub/gpt_partition.h
-+++ b/include/grub/gpt_partition.h
-@@ -76,7 +76,7 @@ struct grub_gpt_partentry
-   grub_uint64_t end;
-   grub_uint64_t attrib;
-   char name[72];
--} GRUB_PACKED;
-+} GRUB_PACKED  __attribute__ ((aligned(8)));
- 
- grub_err_t
- grub_gpt_partition_map_iterate (grub_disk_t disk,
diff --git a/SOURCES/0084-gentpl-add-disable-support.patch b/SOURCES/0084-gentpl-add-disable-support.patch
new file mode 100644
index 0000000..3b305e6
--- /dev/null
+++ b/SOURCES/0084-gentpl-add-disable-support.patch
@@ -0,0 +1,46 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 11 Jul 2018 13:43:15 -0400
+Subject: [PATCH] gentpl: add 'disable = ' support
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ gentpl.py | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/gentpl.py b/gentpl.py
+index c86550d4f9..f3c5f84f85 100644
+--- a/gentpl.py
++++ b/gentpl.py
+@@ -592,11 +592,21 @@ def platform_conditional(platform, closure):
+ #  };
+ #
+ def foreach_enabled_platform(defn, closure):
++    enabled = False
++    disabled = False
+     if 'enable' in defn:
++        enabled = True
+         for platform in GRUB_PLATFORMS:
+             if platform_tagged(defn, platform, "enable"):
+                platform_conditional(platform, closure)
+-    else:
++
++    if 'disable' in defn:
++        disabled = True
++        for platform in GRUB_PLATFORMS:
++            if not platform_tagged(defn, platform, "disable"):
++                platform_conditional(platform, closure)
++
++    if not enabled and not disabled:
+         for platform in GRUB_PLATFORMS:
+             platform_conditional(platform, closure)
+ 
+@@ -655,6 +665,8 @@ def first_time(defn, snippet):
+ def is_platform_independent(defn):
+     if 'enable' in defn:
+         return False
++    if 'disable' in defn:
++        return False
+     for suffix in [ "", "_nodist" ]:
+         template = platform_values(defn, GRUB_PLATFORMS[0], suffix)
+         for platform in GRUB_PLATFORMS[1:]:
diff --git a/SOURCES/0085-Don-t-attempt-to-export-the-start-and-_start-symbols.patch b/SOURCES/0085-Don-t-attempt-to-export-the-start-and-_start-symbols.patch
deleted file mode 100644
index 0e925ee..0000000
--- a/SOURCES/0085-Don-t-attempt-to-export-the-start-and-_start-symbols.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Sat, 12 May 2018 11:29:07 +0200
-Subject: [PATCH] Don't attempt to export the start and _start symbols for
- grub-emu
-
-Commit 318ee04aadc ("make better backtraces") reworked the backtrace logic
-but the changes lead to the following build error on the grub-emu platform:
-
-grub_emu_lite-symlist.o:(.data+0xf08): undefined reference to `start'
-collect2: error: ld returned 1 exit status
-make[3]: *** [Makefile:25959: grub-emu-lite] Error 1
-make[3]: *** Waiting for unfinished jobs....
-cat kernel_syms.input | grep -v '^#' | sed -n \
-  -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/defined kernel '""'\1/;p;}' \
-  -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/defined kernel '""'\1/;p;}' \
-  | sort -u >kernel_syms.lst
-
-The problem is that start and _start symbols are exported unconditionally,
-but these aren't defined for grub-emu since is an emultaed platform so it
-doesn't have a startup logic. Don't attempt to export those for grub-emu.
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- include/grub/kernel.h | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/include/grub/kernel.h b/include/grub/kernel.h
-index 300a9766cda..55849777eaa 100644
---- a/include/grub/kernel.h
-+++ b/include/grub/kernel.h
-@@ -111,8 +111,10 @@ grub_addr_t grub_modules_get_end (void);
- 
- #endif
- 
-+#if !defined(GRUB_MACHINE_EMU)
- void EXPORT_FUNC(start) (void);
- void EXPORT_FUNC(_start) (void);
-+#endif
- 
- /* The start point of the C code.  */
- void grub_main (void) __attribute__ ((noreturn));
diff --git a/SOURCES/0085-gentpl-add-pc-firmware-type.patch b/SOURCES/0085-gentpl-add-pc-firmware-type.patch
new file mode 100644
index 0000000..0bfd2ea
--- /dev/null
+++ b/SOURCES/0085-gentpl-add-pc-firmware-type.patch
@@ -0,0 +1,22 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 11 Jul 2019 11:04:24 +0200
+Subject: [PATCH] gentpl: add 'pc' firmware type
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ gentpl.py | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/gentpl.py b/gentpl.py
+index f3c5f84f85..f09b336869 100644
+--- a/gentpl.py
++++ b/gentpl.py
+@@ -51,6 +51,7 @@ GROUPS["riscv32"]  = [ "riscv32_efi" ]
+ GROUPS["riscv64"]  = [ "riscv64_efi" ]
+ 
+ # Groups based on firmware
++GROUPS["pc"] = [ "i386_pc" ]
+ GROUPS["efi"]  = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi",
+ 		   "riscv32_efi", "riscv64_efi" ]
+ GROUPS["ieee1275"]   = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ]
diff --git a/SOURCES/0086-Fixup-for-newer-compiler.patch b/SOURCES/0086-Fixup-for-newer-compiler.patch
deleted file mode 100644
index 11ed6e5..0000000
--- a/SOURCES/0086-Fixup-for-newer-compiler.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 10 May 2018 13:40:19 -0400
-Subject: [PATCH] Fixup for newer compiler
-
----
- conf/Makefile.common | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/conf/Makefile.common b/conf/Makefile.common
-index 191b1a70c6b..5f0ef969857 100644
---- a/conf/Makefile.common
-+++ b/conf/Makefile.common
-@@ -38,7 +38,7 @@ CFLAGS_KERNEL = $(CFLAGS_PLATFORM) -ffreestanding
- LDFLAGS_KERNEL = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC)
- CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1
- CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
--STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx
-+STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx -R .note.gnu.property -R .gnu.build.attributes
- 
- CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding
- LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d
diff --git a/SOURCES/0086-efinet-also-use-the-firmware-acceleration-for-http.patch b/SOURCES/0086-efinet-also-use-the-firmware-acceleration-for-http.patch
new file mode 100644
index 0000000..a3a9400
--- /dev/null
+++ b/SOURCES/0086-efinet-also-use-the-firmware-acceleration-for-http.patch
@@ -0,0 +1,25 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 30 Jul 2018 14:06:42 -0400
+Subject: [PATCH] efinet: also use the firmware acceleration for http
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/efi/net.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
+index 4bb308026c..6603cd83ed 100644
+--- a/grub-core/net/efi/net.c
++++ b/grub-core/net/efi/net.c
+@@ -1324,7 +1324,9 @@ grub_efi_net_boot_from_https (void)
+ 	  && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
+ 	{
+ 	  grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp;
+-	  return (grub_strncmp ((const char*)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0) ? 1 : 0;
++	  grub_dprintf ("efinet", "url:%s\n", (const char *)uri_dp->uri);
++	  return (grub_strncmp ((const char *)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0 ||
++	          grub_strncmp ((const char *)uri_dp->uri, "http://", sizeof ("http://") - 1) == 0);
+ 	}
+ 
+       if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
diff --git a/SOURCES/0087-Add-support-for-non-Ethernet-network-cards.patch b/SOURCES/0087-Add-support-for-non-Ethernet-network-cards.patch
deleted file mode 100644
index 02fb951..0000000
--- a/SOURCES/0087-Add-support-for-non-Ethernet-network-cards.patch
+++ /dev/null
@@ -1,766 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Andrzej Kacprowski <andrzej.kacprowski@intel.com>
-Date: Wed, 10 Jul 2019 15:22:29 +0200
-Subject: [PATCH] Add support for non-Ethernet network cards
-
-This patch replaces fixed 6-byte link layer address with
-up to 32-byte variable sized address.
-This allows supporting Infiniband and Omni-Path fabric
-which use 20-byte address, but other network card types
-can also take advantage of this change.
-The network card driver is responsible for replacing L2
-header provided by grub2 if needed.
-This approach is compatible with UEFI network stack which
-also allows up to 32-byte variable size link address.
-
-The BOOTP/DHCP packet format is limited to 16 byte client
-hardware address, if link address is more that 16-bytes
-then chaddr field in BOOTP it will be set to 0 as per rfc4390.
-
-Resolves: rhbz#1370642
-
-Signed-off-by: Andrzej Kacprowski <andrzej.kacprowski@intel.com>
-[msalter: Fix max string calculation in grub_net_hwaddr_to_str]
-Signed-off-by: Mark Salter <msalter@redhat.com>
----
- grub-core/net/arp.c                    | 155 ++++++++++++++++++++++-----------
- grub-core/net/bootp.c                  |  15 ++--
- grub-core/net/drivers/efi/efinet.c     |   8 +-
- grub-core/net/drivers/emu/emunet.c     |   1 +
- grub-core/net/drivers/i386/pc/pxe.c    |  13 +--
- grub-core/net/drivers/ieee1275/ofnet.c |   2 +
- grub-core/net/drivers/uboot/ubootnet.c |   1 +
- grub-core/net/ethernet.c               |  88 +++++++++----------
- grub-core/net/icmp6.c                  |  15 ++--
- grub-core/net/ip.c                     |   4 +-
- grub-core/net/net.c                    |  50 ++++++-----
- include/grub/net.h                     |  19 ++--
- 12 files changed, 219 insertions(+), 152 deletions(-)
-
-diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c
-index 54306e3b16d..67b409a8acc 100644
---- a/grub-core/net/arp.c
-+++ b/grub-core/net/arp.c
-@@ -31,22 +31,12 @@ enum
-     ARP_REPLY = 2
-   };
- 
--enum
--  {
--    /* IANA ARP constant to define hardware type as ethernet. */
--    GRUB_NET_ARPHRD_ETHERNET = 1
--  };
--
--struct arppkt {
-+struct arphdr {
-   grub_uint16_t hrd;
-   grub_uint16_t pro;
-   grub_uint8_t hln;
-   grub_uint8_t pln;
-   grub_uint16_t op;
--  grub_uint8_t sender_mac[6];
--  grub_uint32_t sender_ip;
--  grub_uint8_t recv_mac[6];
--  grub_uint32_t recv_ip;
- } GRUB_PACKED;
- 
- static int have_pending;
-@@ -57,12 +47,16 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
- 			   const grub_net_network_level_address_t *proto_addr)
- {
-   struct grub_net_buff nb;
--  struct arppkt *arp_packet;
-+  struct arphdr *arp_header;
-   grub_net_link_level_address_t target_mac_addr;
-   grub_err_t err;
-   int i;
-   grub_uint8_t *nbd;
-   grub_uint8_t arp_data[128];
-+  grub_uint8_t hln;
-+  grub_uint8_t pln;
-+  grub_uint8_t arp_packet_len;
-+  grub_uint8_t *tmp_ptr;
- 
-   if (proto_addr->type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
-     return grub_error (GRUB_ERR_BUG, "unsupported address family");
-@@ -73,23 +67,39 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
-   grub_netbuff_clear (&nb);
-   grub_netbuff_reserve (&nb, 128);
- 
--  err = grub_netbuff_push (&nb, sizeof (*arp_packet));
-+  hln = inf->card->default_address.len;
-+  pln = sizeof (proto_addr->ipv4);
-+  arp_packet_len = sizeof (*arp_header) + 2 * (hln + pln);
-+
-+  err = grub_netbuff_push (&nb, arp_packet_len);
-   if (err)
-     return err;
- 
--  arp_packet = (struct arppkt *) nb.data;
--  arp_packet->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET);
--  arp_packet->hln = 6;
--  arp_packet->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP);
--  arp_packet->pln = 4;
--  arp_packet->op = grub_cpu_to_be16_compile_time (ARP_REQUEST);
--  /* Sender hardware address.  */
--  grub_memcpy (arp_packet->sender_mac, &inf->hwaddress.mac, 6);
--  arp_packet->sender_ip = inf->address.ipv4;
--  grub_memset (arp_packet->recv_mac, 0, 6);
--  arp_packet->recv_ip = proto_addr->ipv4;
--  /* Target protocol address */
--  grub_memset (&target_mac_addr.mac, 0xff, 6);
-+  arp_header = (struct arphdr *) nb.data;
-+  arp_header->hrd = grub_cpu_to_be16 (inf->card->default_address.type);
-+  arp_header->hln = hln;
-+  arp_header->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP);
-+  arp_header->pln = pln;
-+  arp_header->op = grub_cpu_to_be16_compile_time (ARP_REQUEST);
-+  tmp_ptr = nb.data + sizeof (*arp_header);
-+
-+  /* The source hardware address. */
-+  grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln);
-+  tmp_ptr += hln;
-+
-+  /* The source protocol address. */
-+  grub_memcpy (tmp_ptr, &inf->address.ipv4, pln);
-+  tmp_ptr += pln;
-+
-+  /* The target hardware address. */
-+  grub_memset (tmp_ptr, 0, hln);
-+  tmp_ptr += hln;
-+
-+  /* The target protocol address */
-+  grub_memcpy (tmp_ptr, &proto_addr->ipv4, pln);
-+  tmp_ptr += pln;
-+
-+  grub_memset (&target_mac_addr.mac, 0xff, hln);
- 
-   nbd = nb.data;
-   send_ethernet_packet (inf, &nb, target_mac_addr, GRUB_NET_ETHERTYPE_ARP);
-@@ -114,28 +124,53 @@ grub_err_t
- grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card,
-                       grub_uint16_t *vlantag)
- {
--  struct arppkt *arp_packet = (struct arppkt *) nb->data;
-+  struct arphdr *arp_header = (struct arphdr *) nb->data;
-   grub_net_network_level_address_t sender_addr, target_addr;
-   grub_net_link_level_address_t sender_mac_addr;
-   struct grub_net_network_level_interface *inf;
-+  grub_uint16_t hw_type;
-+  grub_uint8_t hln;
-+  grub_uint8_t pln;
-+  grub_uint8_t arp_packet_len;
-+  grub_uint8_t *tmp_ptr;
- 
--  if (arp_packet->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP)
--      || arp_packet->pln != 4 || arp_packet->hln != 6
--      || nb->tail - nb->data < (int) sizeof (*arp_packet))
-+  hw_type = card->default_address.type;
-+  hln = card->default_address.len;
-+  pln = sizeof(sender_addr.ipv4);
-+  arp_packet_len = sizeof (*arp_header) + 2 * (pln + hln);
-+
-+  if (arp_header->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP)
-+      || arp_header->hrd != grub_cpu_to_be16 (hw_type)
-+      || arp_header->hln != hln || arp_header->pln != pln
-+      || nb->tail - nb->data < (int) arp_packet_len) {
-     return GRUB_ERR_NONE;
-+  }
- 
-+  tmp_ptr =  nb->data + sizeof (*arp_header);
-+
-+  /* The source hardware address. */
-+  sender_mac_addr.type = hw_type;
-+  sender_mac_addr.len = hln;
-+  grub_memcpy (sender_mac_addr.mac, tmp_ptr, hln);
-+  tmp_ptr += hln;
-+
-+  /* The source protocol address. */
-   sender_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
-+  grub_memcpy(&sender_addr.ipv4, tmp_ptr, pln);
-+  tmp_ptr += pln;
-+
-+  grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1);
-+
-+  /* The target hardware address. */
-+  tmp_ptr += hln;
-+
-+  /* The target protocol address. */
-   target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
--  sender_addr.ipv4 = arp_packet->sender_ip;
--  target_addr.ipv4 = arp_packet->recv_ip;
--  if (arp_packet->sender_ip == pending_req)
-+  grub_memcpy(&target_addr.ipv4, tmp_ptr, pln);
-+
-+  if (sender_addr.ipv4 == pending_req)
-     have_pending = 1;
- 
--  sender_mac_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
--  grub_memcpy (sender_mac_addr.mac, arp_packet->sender_mac,
--	       sizeof (sender_mac_addr.mac));
--  grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1);
--
-   FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
-   {
-     /* Verify vlantag id */
-@@ -148,11 +183,11 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card,
- 
-     /* Am I the protocol address target? */
-     if (grub_net_addr_cmp (&inf->address, &target_addr) == 0
--	&& arp_packet->op == grub_cpu_to_be16_compile_time (ARP_REQUEST))
-+	&& arp_header->op == grub_cpu_to_be16_compile_time (ARP_REQUEST))
-       {
- 	grub_net_link_level_address_t target;
- 	struct grub_net_buff nb_reply;
--	struct arppkt *arp_reply;
-+	struct arphdr *arp_reply;
- 	grub_uint8_t arp_data[128];
- 	grub_err_t err;
- 
-@@ -161,25 +196,39 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card,
- 	grub_netbuff_clear (&nb_reply);
- 	grub_netbuff_reserve (&nb_reply, 128);
- 
--	err = grub_netbuff_push (&nb_reply, sizeof (*arp_packet));
-+	err = grub_netbuff_push (&nb_reply, arp_packet_len);
- 	if (err)
- 	  return err;
- 
--	arp_reply = (struct arppkt *) nb_reply.data;
-+	arp_reply = (struct arphdr *) nb_reply.data;
- 
--	arp_reply->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET);
-+	arp_reply->hrd = grub_cpu_to_be16 (hw_type);
- 	arp_reply->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP);
--	arp_reply->pln = 4;
--	arp_reply->hln = 6;
-+	arp_reply->pln = pln;
-+	arp_reply->hln = hln;
- 	arp_reply->op = grub_cpu_to_be16_compile_time (ARP_REPLY);
--	arp_reply->sender_ip = arp_packet->recv_ip;
--	arp_reply->recv_ip = arp_packet->sender_ip;
--	arp_reply->hln = 6;
--
--	target.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
--	grub_memcpy (target.mac, arp_packet->sender_mac, 6);
--	grub_memcpy (arp_reply->sender_mac, inf->hwaddress.mac, 6);
--	grub_memcpy (arp_reply->recv_mac, arp_packet->sender_mac, 6);
-+
-+	tmp_ptr = nb_reply.data + sizeof (*arp_reply);
-+
-+	/* The source hardware address. */
-+	grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln);
-+	tmp_ptr += hln;
-+
-+	/* The source protocol address. */
-+	grub_memcpy (tmp_ptr, &target_addr.ipv4, pln);
-+	tmp_ptr += pln;
-+
-+	/* The target hardware address. */
-+	grub_memcpy (tmp_ptr, sender_mac_addr.mac, hln);
-+	tmp_ptr += hln;
-+
-+	/* The target protocol address */
-+	grub_memcpy (tmp_ptr, &sender_addr.ipv4, pln);
-+	tmp_ptr += pln;
-+
-+	target.type = hw_type;
-+	target.len = hln;
-+	grub_memcpy (target.mac, sender_mac_addr.mac, hln);
- 
- 	/* Change operation to REPLY and send packet */
- 	send_ethernet_packet (inf, &nb_reply, target, GRUB_NET_ETHERTYPE_ARP);
-diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
-index e28fb6a09f9..08b6b2b5d6c 100644
---- a/grub-core/net/bootp.c
-+++ b/grub-core/net/bootp.c
-@@ -233,7 +233,6 @@ grub_net_configure_by_dhcp_ack (const char *name,
- 				int is_def, char **device, char **path)
- {
-   grub_net_network_level_address_t addr;
--  grub_net_link_level_address_t hwaddr;
-   struct grub_net_network_level_interface *inter;
-   int mask = -1;
-   char server_ip[sizeof ("xxx.xxx.xxx.xxx")];
-@@ -250,12 +249,8 @@ grub_net_configure_by_dhcp_ack (const char *name,
-   if (path)
-     *path = 0;
- 
--  grub_memcpy (hwaddr.mac, bp->mac_addr,
--	       bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len
--	       : sizeof (hwaddr.mac));
--  hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
--
--  inter = grub_net_add_addr (name, card, &addr, &hwaddr, flags);
-+  grub_dprintf("dhcp", "configuring dhcp for %s\n", name);
-+  inter = grub_net_add_addr (name, card, &addr, &card->default_address, flags);
-   if (!inter)
-     return 0;
- 
-@@ -567,7 +562,9 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface)
-   grub_memset (pack, 0, sizeof (*pack));
-   pack->opcode = 1;
-   pack->hw_type = 1;
--  pack->hw_len = 6;
-+  pack->hw_len = iface->hwaddress.len > 16 ? 0
-+                                              : iface->hwaddress.len;
-+
-   err = grub_get_datetime (&date);
-   if (err || !grub_datetime2unixtime (&date, &t))
-     {
-@@ -580,7 +577,7 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface)
-   else
-     pack->ident = iface->xid;
- 
--  grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, 6);
-+  grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, pack->hw_len);
- 
-   grub_netbuff_push (nb, sizeof (*udph));
- 
-diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
-index 173fb63153c..a673bea807a 100644
---- a/grub-core/net/drivers/efi/efinet.c
-+++ b/grub-core/net/drivers/efi/efinet.c
-@@ -279,6 +279,9 @@ grub_efinet_findcards (void)
- 	/* This should not happen... Why?  */
- 	continue;
- 
-+      if (net->mode->hwaddr_size > GRUB_NET_MAX_LINK_ADDRESS_SIZE)
-+	continue;
-+
-       if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
- 	  && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
- 	continue;
-@@ -315,10 +318,11 @@ grub_efinet_findcards (void)
-       card->name = grub_xasprintf ("efinet%d", i++);
-       card->driver = &efidriver;
-       card->flags = 0;
--      card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
-+      card->default_address.type = net->mode->if_type;
-+      card->default_address.len = net->mode->hwaddr_size;
-       grub_memcpy (card->default_address.mac,
- 		   net->mode->current_address,
--		   sizeof (card->default_address.mac));
-+		   net->mode->hwaddr_size);
-       card->efi_net = net;
-       card->efi_handle = *handle;
- 
-diff --git a/grub-core/net/drivers/emu/emunet.c b/grub-core/net/drivers/emu/emunet.c
-index b194920861f..5b6c5e16a6d 100644
---- a/grub-core/net/drivers/emu/emunet.c
-+++ b/grub-core/net/drivers/emu/emunet.c
-@@ -46,6 +46,7 @@ static struct grub_net_card emucard =
-     .mtu = 1500,
-     .default_address = {
- 			 .type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET,
-+			 . len = 6,
- 			 {.mac = {0, 1, 2, 3, 4, 5}}
- 		       },
-     .flags = 0
-diff --git a/grub-core/net/drivers/i386/pc/pxe.c b/grub-core/net/drivers/i386/pc/pxe.c
-index 3f4152d036c..9f8fb4b6d2b 100644
---- a/grub-core/net/drivers/i386/pc/pxe.c
-+++ b/grub-core/net/drivers/i386/pc/pxe.c
-@@ -386,20 +386,21 @@ GRUB_MOD_INIT(pxe)
-   grub_memset (ui, 0, sizeof (*ui));
-   grub_pxe_call (GRUB_PXENV_UNDI_GET_INFORMATION, ui, pxe_rm_entry);
- 
-+  grub_pxe_card.default_address.len = 6;
-   grub_memcpy (grub_pxe_card.default_address.mac, ui->current_addr,
--	       sizeof (grub_pxe_card.default_address.mac));
--  for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++)
-+	       grub_pxe_card.default_address.len);
-+  for (i = 0; i < grub_pxe_card.default_address.len; i++)
-     if (grub_pxe_card.default_address.mac[i] != 0)
-       break;
--  if (i != sizeof (grub_pxe_card.default_address.mac))
-+  if (i != grub_pxe_card.default_address.len)
-     {
--      for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++)
-+      for (i = 0; i < grub_pxe_card.default_address.len; i++)
- 	if (grub_pxe_card.default_address.mac[i] != 0xff)
- 	  break;
-     }
--  if (i == sizeof (grub_pxe_card.default_address.mac))
-+  if (i == grub_pxe_card.default_address.len)
-     grub_memcpy (grub_pxe_card.default_address.mac, ui->permanent_addr,
--		 sizeof (grub_pxe_card.default_address.mac));
-+		 grub_pxe_card.default_address.len);
-   grub_pxe_card.mtu = ui->mtu;
- 
-   grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
-diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c
-index 3860b6f78d8..bcb3f9ea02d 100644
---- a/grub-core/net/drivers/ieee1275/ofnet.c
-+++ b/grub-core/net/drivers/ieee1275/ofnet.c
-@@ -160,6 +160,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath,
-   grub_uint16_t vlantag = 0;
- 
-   hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
-+  hw_addr.len = 6;
- 
-   args = bootpath + grub_strlen (devpath) + 1;
-   do
-@@ -503,6 +504,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias)
-     grub_memcpy (&lla.mac, pprop, 6);
- 
-   lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
-+  lla.len = 6;
-   card->default_address = lla;
- 
-   card->txbufsize = ALIGN_UP (card->mtu, 64) + 256;
-diff --git a/grub-core/net/drivers/uboot/ubootnet.c b/grub-core/net/drivers/uboot/ubootnet.c
-index 056052e40d5..22ebcbf211e 100644
---- a/grub-core/net/drivers/uboot/ubootnet.c
-+++ b/grub-core/net/drivers/uboot/ubootnet.c
-@@ -131,6 +131,7 @@ GRUB_MOD_INIT (ubootnet)
- 
-       grub_memcpy (&(card->default_address.mac), &devinfo->di_net.hwaddr, 6);
-       card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
-+      card->default_address.len = 6;
- 
-       card->txbufsize = ALIGN_UP (card->mtu, 64) + 256;
-       card->txbuf = grub_zalloc (card->txbufsize);
-diff --git a/grub-core/net/ethernet.c b/grub-core/net/ethernet.c
-index 4d7ceed6f93..9aae83a5eb4 100644
---- a/grub-core/net/ethernet.c
-+++ b/grub-core/net/ethernet.c
-@@ -29,13 +29,6 @@
- 
- #define LLCADDRMASK 0x7f
- 
--struct etherhdr
--{
--  grub_uint8_t dst[6];
--  grub_uint8_t src[6];
--  grub_uint16_t type;
--} GRUB_PACKED;
--
- struct llchdr
- {
-   grub_uint8_t dsap;
-@@ -55,13 +48,15 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
- 		      grub_net_link_level_address_t target_addr,
- 		      grub_net_ethertype_t ethertype)
- {
--  struct etherhdr *eth;
-+  grub_uint8_t *eth;
-   grub_err_t err;
--  grub_uint8_t etherhdr_size;
--  grub_uint16_t vlantag_id = VLANTAG_IDENTIFIER;
-+  grub_uint32_t vlantag = 0;
-+  grub_uint8_t hw_addr_len = inf->card->default_address.len;
-+  grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2;
- 
--  etherhdr_size = sizeof (*eth);
--  COMPILE_TIME_ASSERT (sizeof (*eth) + 4 < GRUB_NET_MAX_LINK_HEADER_SIZE);
-+  /* Source and destination link addresses + ethertype + vlan tag */
-+  COMPILE_TIME_ASSERT ((GRUB_NET_MAX_LINK_ADDRESS_SIZE * 2 + 2 + 4) <
-+		       GRUB_NET_MAX_LINK_HEADER_SIZE);
- 
-   /* Increase ethernet header in case of vlantag */
-   if (inf->vlantag != 0)
-@@ -70,11 +65,22 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
-   err = grub_netbuff_push (nb, etherhdr_size);
-   if (err)
-     return err;
--  eth = (struct etherhdr *) nb->data;
--  grub_memcpy (eth->dst, target_addr.mac, 6);
--  grub_memcpy (eth->src, inf->hwaddress.mac, 6);
-+  eth = nb->data;
-+  grub_memcpy (eth, target_addr.mac, hw_addr_len);
-+  eth += hw_addr_len;
-+  grub_memcpy (eth, inf->hwaddress.mac, hw_addr_len);
-+  eth += hw_addr_len;
-+
-+  /* Check if a vlan-tag is present. */
-+  if (vlantag != 0)
-+    {
-+      *((grub_uint32_t *)eth) = grub_cpu_to_be32 (vlantag);
-+      eth += sizeof (vlantag);
-+    }
-+
-+  /* Write ethertype */
-+  *((grub_uint16_t*) eth) = grub_cpu_to_be16 (ethertype);
- 
--  eth->type = grub_cpu_to_be16 (ethertype);
-   if (!inf->card->opened)
-     {
-       err = GRUB_ERR_NONE;
-@@ -85,18 +91,6 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
-       inf->card->opened = 1;
-     }
- 
--  /* Check and add a vlan-tag if needed. */
--  if (inf->vlantag != 0)
--    {
--      /* Move eth type to the right */
--      grub_memcpy ((char *) nb->data + etherhdr_size - 2,
--                   (char *) nb->data + etherhdr_size - 6, 2);
--
--      /* Add the tag in the middle */
--      grub_memcpy ((char *) nb->data + etherhdr_size - 6, &vlantag_id, 2);
--      grub_memcpy ((char *) nb->data + etherhdr_size - 4, (char *) &(inf->vlantag), 2);
--    }
--
-   return inf->card->driver->send (inf->card, nb);
- }
- 
-@@ -104,31 +98,40 @@ grub_err_t
- grub_net_recv_ethernet_packet (struct grub_net_buff *nb,
- 			       struct grub_net_card *card)
- {
--  struct etherhdr *eth;
-+  grub_uint8_t *eth;
-   struct llchdr *llch;
-   struct snaphdr *snaph;
-   grub_net_ethertype_t type;
-   grub_net_link_level_address_t hwaddress;
-   grub_net_link_level_address_t src_hwaddress;
-   grub_err_t err;
--  grub_uint8_t etherhdr_size = sizeof (*eth);
-+  grub_uint8_t hw_addr_len = card->default_address.len;
-+  grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2;
-   grub_uint16_t vlantag = 0;
- 
-+  eth = nb->data;
- 
--  /* Check if a vlan-tag is present. If so, the ethernet header is 4 bytes */
--  /* longer than the original one. The vlantag id is extracted and the header */
--  /* is reseted to the original size. */
--  if (grub_get_unaligned16 (nb->data + etherhdr_size - 2) == VLANTAG_IDENTIFIER)
-+  hwaddress.type = card->default_address.type;
-+  hwaddress.len = hw_addr_len;
-+  grub_memcpy (hwaddress.mac, eth, hw_addr_len);
-+  eth += hw_addr_len;
-+
-+  src_hwaddress.type = card->default_address.type;
-+  src_hwaddress.len = hw_addr_len;
-+  grub_memcpy (src_hwaddress.mac, eth, hw_addr_len);
-+  eth += hw_addr_len;
-+
-+  type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth));
-+  if (type == VLANTAG_IDENTIFIER)
-     {
--      vlantag = grub_get_unaligned16 (nb->data + etherhdr_size);
-+      /* Skip vlan tag */
-+      eth += 2;
-+      vlantag = grub_be_to_cpu16 (*(grub_uint16_t*)(eth));
-       etherhdr_size += 4;
--      /* Move eth type to the original position */
--      grub_memcpy((char *) nb->data + etherhdr_size - 6,
--                  (char *) nb->data + etherhdr_size - 2, 2);
-+      eth += 2;
-+      type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth));
-     }
- 
--  eth = (struct etherhdr *) nb->data;
--  type = grub_be_to_cpu16 (eth->type);
-   err = grub_netbuff_pull (nb, etherhdr_size);
-   if (err)
-     return err;
-@@ -148,11 +151,6 @@ grub_net_recv_ethernet_packet (struct grub_net_buff *nb,
- 	}
-     }
- 
--  hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
--  grub_memcpy (hwaddress.mac, eth->dst, sizeof (hwaddress.mac));
--  src_hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
--  grub_memcpy (src_hwaddress.mac, eth->src, sizeof (src_hwaddress.mac));
--
-   switch (type)
-     {
-       /* ARP packet. */
-diff --git a/grub-core/net/icmp6.c b/grub-core/net/icmp6.c
-index 2cbd95dce25..56a3ec5c8e8 100644
---- a/grub-core/net/icmp6.c
-+++ b/grub-core/net/icmp6.c
-@@ -231,8 +231,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
- 		&& ohdr->len == 1)
- 	      {
- 		grub_net_link_level_address_t ll_address;
--		ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
--		grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
-+		ll_address.type = card->default_address.type;
-+		ll_address.len = card->default_address.len;
-+		grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len);
- 		grub_net_link_layer_add_address (card, source, &ll_address, 0);
- 	      }
- 	  }
-@@ -335,8 +336,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
- 		&& ohdr->len == 1)
- 	      {
- 		grub_net_link_level_address_t ll_address;
--		ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
--		grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
-+		ll_address.type = card->default_address.type;
-+		ll_address.len = card->default_address.len;
-+		grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len);
- 		grub_net_link_layer_add_address (card, source, &ll_address, 0);
- 	      }
- 	  }
-@@ -384,8 +386,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
- 		&& ohdr->len == 1)
- 	      {
- 		grub_net_link_level_address_t ll_address;
--		ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
--		grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
-+		ll_address.type = card->default_address.type;
-+		ll_address.len = card->default_address.len;
-+		grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len);
- 		grub_net_link_layer_add_address (card, source, &ll_address, 0);
- 	      }
- 	    if (ohdr->type == OPTION_PREFIX && ohdr->len == 4)
-diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
-index ea5edf8f1f6..a5896f6dc26 100644
---- a/grub-core/net/ip.c
-+++ b/grub-core/net/ip.c
-@@ -276,8 +276,8 @@ handle_dgram (struct grub_net_buff *nb,
- 	  if (inf->card == card
- 	      && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV
- 	      && inf->hwaddress.type == GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
--	      && grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr,
--			      sizeof (inf->hwaddress.mac)) == 0)
-+	      && (grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr,
-+			       bootp->hw_len) == 0 || bootp->hw_len == 0))
- 	    {
- 	      grub_net_process_dhcp (nb, inf);
- 	      grub_netbuff_free (nb);
-diff --git a/grub-core/net/net.c b/grub-core/net/net.c
-index 22f2689aaeb..a46f82362ed 100644
---- a/grub-core/net/net.c
-+++ b/grub-core/net/net.c
-@@ -133,8 +133,9 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf,
- 								   << 48)
- 	  && proto_addr->ipv6[1] == (grub_be_to_cpu64_compile_time (1))))
-     {
--      hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
--      grub_memset (hw_addr->mac, -1, 6);
-+      hw_addr->type = inf->card->default_address.type;
-+      hw_addr->len = inf->card->default_address.len;
-+      grub_memset (hw_addr->mac, -1, hw_addr->len);
-       return GRUB_ERR_NONE;
-     }
- 
-@@ -142,6 +143,7 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf,
-       && ((grub_be_to_cpu64 (proto_addr->ipv6[0]) >> 56) == 0xff))
-     {
-       hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
-+      hw_addr->len = inf->card->default_address.len;
-       hw_addr->mac[0] = 0x33;
-       hw_addr->mac[1] = 0x33;
-       hw_addr->mac[2] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 24) & 0xff);
-@@ -762,23 +764,23 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf)
- void
- grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str)
- {
--  str[0] = 0;
--  switch (addr->type)
-+  char *ptr;
-+  unsigned i;
-+  int maxstr;
-+
-+  if (addr->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE)
-     {
--    case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET:
--      {
--	char *ptr;
--	unsigned i;
--	for (ptr = str, i = 0; i < ARRAY_SIZE (addr->mac); i++)
--	  {
--	    grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str),
--			   "%02x:", addr->mac[i] & 0xff);
--	    ptr += (sizeof ("XX:") - 1);
--	  }
--      return;
--      }
-+       str[0] = 0;
-+       grub_printf (_("Unsupported hw address type %d len %d\n"),
-+		    addr->type, addr->len);
-+       return;
-+    }
-+  maxstr = addr->len * grub_strlen ("XX:");
-+  for (ptr = str, i = 0; i < addr->len; i++)
-+    {
-+      ptr += grub_snprintf (ptr, maxstr - (ptr - str),
-+		     "%02x:", addr->mac[i] & 0xff);
-     }
--  grub_printf (_("Unsupported hw address type %d\n"), addr->type);
- }
- 
- int
-@@ -789,13 +791,17 @@ grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a,
-     return -1;
-   if (a->type > b->type)
-     return +1;
--  switch (a->type)
-+  if (a->len < b->len)
-+    return -1;
-+  if (a->len > b->len)
-+    return +1;
-+  if (a->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE)
-     {
--    case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET:
--      return grub_memcmp (a->mac, b->mac, sizeof (a->mac));
-+      grub_printf (_("Unsupported hw address type %d len %d\n"),
-+		   a->type, a->len);
-+      return + 1;
-     }
--  grub_printf (_("Unsupported hw address type %d\n"), a->type);
--  return 1;
-+  return grub_memcmp (a->mac, b->mac, a->len);
- }
- 
- int
-diff --git a/include/grub/net.h b/include/grub/net.h
-index 8a05ec4fe7a..af0404db7e3 100644
---- a/include/grub/net.h
-+++ b/include/grub/net.h
-@@ -29,7 +29,8 @@
- 
- enum
-   {
--    GRUB_NET_MAX_LINK_HEADER_SIZE = 64,
-+    GRUB_NET_MAX_LINK_HEADER_SIZE = 96,
-+    GRUB_NET_MAX_LINK_ADDRESS_SIZE = 32,
-     GRUB_NET_UDP_HEADER_SIZE = 8,
-     GRUB_NET_TCP_HEADER_SIZE = 20,
-     GRUB_NET_OUR_IPV4_HEADER_SIZE = 20,
-@@ -42,15 +43,17 @@ enum
- 
- typedef enum grub_link_level_protocol_id 
- {
--  GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
-+  /* IANA ARP constant to define hardware type. */
-+  GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET = 1,
- } grub_link_level_protocol_id_t;
- 
- typedef struct grub_net_link_level_address
- {
-   grub_link_level_protocol_id_t type;
-+  grub_uint8_t len;
-   union
-   {
--    grub_uint8_t mac[6];
-+    grub_uint8_t mac[GRUB_NET_MAX_LINK_ADDRESS_SIZE];
-   };
- } grub_net_link_level_address_t;
- 
-@@ -566,11 +569,13 @@ grub_net_addr_cmp (const grub_net_network_level_address_t *a,
- #define GRUB_NET_MAX_STR_ADDR_LEN sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX")
- 
- /*
--  Currently suppoerted adresses:
--  ethernet:   XX:XX:XX:XX:XX:XX
-+  Up to 32 byte hardware address supported, see GRUB_NET_MAX_LINK_ADDRESS_SIZE
-  */
--
--#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof ("XX:XX:XX:XX:XX:XX"))
-+#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof (\
-+	"XX:XX:XX:XX:XX:XX:XX:XX:"\
-+	"XX:XX:XX:XX:XX:XX:XX:XX:"\
-+	"XX:XX:XX:XX:XX:XX:XX:XX:"\
-+	"XX:XX:XX:XX:XX:XX:XX:XX"))
- 
- void
- grub_net_addr_to_str (const grub_net_network_level_address_t *target,
diff --git a/SOURCES/0087-efi-http-Make-root_url-reflect-the-protocol-hostname.patch b/SOURCES/0087-efi-http-Make-root_url-reflect-the-protocol-hostname.patch
new file mode 100644
index 0000000..90d9777
--- /dev/null
+++ b/SOURCES/0087-efi-http-Make-root_url-reflect-the-protocol-hostname.patch
@@ -0,0 +1,50 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 30 Jul 2018 16:39:57 -0400
+Subject: [PATCH] efi/http: Make root_url reflect the protocol+hostname of our
+ boot url.
+
+This lets you write config files that don't know urls.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/efi/http.c | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
+index 3f61fd2fa5..243acbaa35 100644
+--- a/grub-core/net/efi/http.c
++++ b/grub-core/net/efi/http.c
+@@ -4,6 +4,7 @@
+ #include <grub/misc.h>
+ #include <grub/net/efi.h>
+ #include <grub/charset.h>
++#include <grub/env.h>
+ 
+ static void
+ http_configure (struct grub_efi_net_device *dev, int prefer_ip6)
+@@ -351,6 +352,24 @@ grub_efihttp_open (struct grub_efi_net_device *dev,
+   grub_err_t err;
+   grub_off_t size;
+   char *buf;
++  char *root_url;
++  grub_efi_ipv6_address_t address;
++  const char *rest;
++
++  if (grub_efi_string_to_ip6_address (file->device->net->server, &address, &rest) && *rest == 0)
++    root_url = grub_xasprintf ("%s://[%s]", type ? "https" : "http", file->device->net->server);
++  else
++    root_url = grub_xasprintf ("%s://%s", type ? "https" : "http", file->device->net->server);
++  if (root_url)
++    {
++      grub_env_unset ("root_url");
++      grub_env_set ("root_url", root_url);
++      grub_free (root_url);
++    }
++  else
++    {
++      return grub_errno;
++    }
+ 
+   err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0);
+   if (err != GRUB_ERR_NONE)
diff --git a/SOURCES/0088-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch b/SOURCES/0088-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch
new file mode 100644
index 0000000..6d2974f
--- /dev/null
+++ b/SOURCES/0088-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch
@@ -0,0 +1,149 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 26 Jun 2018 17:16:06 -0400
+Subject: [PATCH] Make it so we can tell configure which cflags utils are built
+ with
+
+This lets us have kernel.img be built with TARGET_CFLAGS but grub-mkimage and
+friends built with HOST_CFLAGS.  That in turn lets us build with an ARM compiler
+that only has hard-float ABI versions of crt*.o and libgcc*, but still use soft
+float for grub.efi.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ configure.ac         | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ conf/Makefile.common | 23 ++++++++++++-----------
+ gentpl.py            |  8 ++++----
+ 3 files changed, 64 insertions(+), 16 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 302300711f..008f6c273b 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -849,11 +849,23 @@ if ( test "x$target_cpu" = xi386 || test "x$target_cpu" = xx86_64 ) && test "x$p
+   TARGET_CFLAGS="$TARGET_CFLAGS -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow"
+ fi
+ 
++# Should grub utils get the host CFLAGS, or the target CFLAGS?
++AC_ARG_WITH([utils],
++            AS_HELP_STRING([--with-utils=host|target|build],
++                           [choose which flags to build utilities with. (default=target)]),
++	    [have_with_utils=y],
++	    [have_with_utils=n])
++if test x"$have_with_utils" = xy ; then
++  with_utils="$withval"
++else
++  with_utils=target
++fi
++
+ # GRUB doesn't use float or doubles at all. Yet some toolchains may decide
+ # that floats are a good fit to run instead of what's written in the code.
+ # Given that floating point unit is disabled (if present to begin with)
+ # when GRUB is running which may result in various hard crashes.
+-if test x"$platform" != xemu ; then
++if test x"$platform" != xemu -a x"$with_utils" == xtarget ; then
+   AC_CACHE_CHECK([for options to get soft-float], grub_cv_target_cc_soft_float, [
+     grub_cv_target_cc_soft_float=no
+     if test "x$target_cpu" = xarm64; then
+@@ -1954,6 +1966,41 @@ HOST_CPPFLAGS="$HOST_CPPFLAGS -I\$(top_builddir)/include"
+ TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_srcdir)/include"
+ TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_builddir)/include"
+ 
++case "$with_utils" in
++  host)
++    UTILS_CFLAGS=$HOST_CFLAGS
++    UTILS_CPPFLAGS=$HOST_CPPFLAGS
++    UTILS_CCASFLAGS=$HOST_CCASFLAGS
++    UTILS_LDFLAGS=$HOST_LDFLAGS
++    ;;
++  target)
++    UTILS_CFLAGS=$TARGET_CFLAGS
++    UTILS_CPPFLAGS=$TARGET_CPPFLAGS
++    UTILS_CCASFLAGS=$TARGET_CCASFLAGS
++    UTILS_LDFLAGS=$TARGET_LDFLAGS
++    ;;
++  build)
++    UTILS_CFLAGS=$BUILD_CFLAGS
++    UTILS_CPPFLAGS=$BUILD_CPPFLAGS
++    UTILS_CCASFLAGS=$BUILD_CCASFLAGS
++    UTILS_LDFLAGS=$BUILD_LDFLAGS
++    ;;
++  *)
++    AC_MSG_ERROR([--with-utils must be either host, target, or build])
++    ;;
++esac
++AC_MSG_NOTICE([Using $with_utils flags for utilities.])
++
++unset CFLAGS
++unset CPPFLAGS
++unset CCASFLAGS
++unset LDFLAGS
++
++AC_SUBST(UTILS_CFLAGS)
++AC_SUBST(UTILS_CPPFLAGS)
++AC_SUBST(UTILS_CCASFLAGS)
++AC_SUBST(UTILS_LDFLAGS)
++
+ GRUB_TARGET_CPU="${target_cpu}"
+ GRUB_PLATFORM="${platform}"
+ 
+diff --git a/conf/Makefile.common b/conf/Makefile.common
+index 5f0ef96985..2ff9b39357 100644
+--- a/conf/Makefile.common
++++ b/conf/Makefile.common
+@@ -40,24 +40,25 @@ CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1
+ CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
+ STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx -R .note.gnu.property -R .gnu.build.attributes
+ 
+-CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding
+-LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d
+-CPPFLAGS_MODULE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM)
+-CCASFLAGS_MODULE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
++CFLAGS_MODULE = $(TARGET_CFLAGS) $(CFLAGS_PLATFORM) -ffreestanding
++LDFLAGS_MODULE = $(TARGET_LDFLAGS) $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d
++CPPFLAGS_MODULE = $(TARGET_CPPFLAGS) $(CPPFLAGS_DEFAULT) $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM)
++CCASFLAGS_MODULE = $(TARGET_CCASFLAGS) $(CCASFLAGS_DEFAULT) $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
+ 
+ CFLAGS_IMAGE = $(CFLAGS_PLATFORM) -fno-builtin
+ LDFLAGS_IMAGE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-S
+ CPPFLAGS_IMAGE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM)
+ CCASFLAGS_IMAGE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
+ 
+-CFLAGS_PROGRAM =
+-LDFLAGS_PROGRAM =
+-CPPFLAGS_PROGRAM =
+-CCASFLAGS_PROGRAM =
++CFLAGS_PROGRAM = $(UTILS_CFLAGS)
++LDFLAGS_PROGRAM = $(UTILS_LDFLAGS)
++CPPFLAGS_PROGRAM = $(UTILS_CPPFLAGS)
++CCASFLAGS_PROGRAM = $(UTILS_CCASFLAGS)
+ 
+-CFLAGS_LIBRARY =
+-CPPFLAGS_LIBRARY =
+-CCASFLAGS_LIBRARY =
++CFLAGS_LIBRARY = $(UTILS_CFLAGS)
++LDFLAGS_LIBRARY = $(UTILS_LDFLAGS)
++CPPFLAGS_LIBRARY = $(UTILS_CPPFLAGS)
++CCASFLAGS_LIBRARY = $(UTILS_CCASFLAGS)
+ 
+ # Other variables
+ 
+diff --git a/gentpl.py b/gentpl.py
+index f09b336869..0e62e14666 100644
+--- a/gentpl.py
++++ b/gentpl.py
+@@ -697,10 +697,10 @@ def module(defn, platform):
+     var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform) + " ## platform sources")
+     var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + " ## platform nodist sources")
+     var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform))
+-    var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_MODULE) " + platform_cflags(defn, platform))
+-    var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_MODULE) " + platform_ldflags(defn, platform))
+-    var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform))
+-    var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform))
++    var_set(cname(defn) + "_CFLAGS", "$(CFLAGS_MODULE) " + platform_cflags(defn, platform))
++    var_set(cname(defn) + "_LDFLAGS", "$(LDFLAGS_MODULE) " + platform_ldflags(defn, platform))
++    var_set(cname(defn) + "_CPPFLAGS", "$(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform))
++    var_set(cname(defn) + "_CCASFLAGS", "$(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform))
+     var_set(cname(defn) + "_DEPENDENCIES", "$(TARGET_OBJ2ELF) " + platform_dependencies(defn, platform))
+ 
+     gvar_add("dist_noinst_DATA", extra_dist(defn))
diff --git a/SOURCES/0088-net-read-bracketed-ipv6-addrs-and-port-numbers.patch b/SOURCES/0088-net-read-bracketed-ipv6-addrs-and-port-numbers.patch
deleted file mode 100644
index 834b96e..0000000
--- a/SOURCES/0088-net-read-bracketed-ipv6-addrs-and-port-numbers.patch
+++ /dev/null
@@ -1,270 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Aaron Miller <aaronmiller@fb.com>
-Date: Fri, 29 Jul 2016 17:41:38 +0800
-Subject: [PATCH] net: read bracketed ipv6 addrs and port numbers
-
-Allow specifying port numbers for http and tftp paths, and allow ipv6 addresses
-to be recognized with brackets around them, which is required to specify a port
-number
-
-Signed-off-by: Aaron Miller <aaronmiller@fb.com>
-[pjones: various bug fixes]
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/net/http.c | 25 ++++++++++++---
- grub-core/net/net.c  | 87 +++++++++++++++++++++++++++++++++++++++++++++++++---
- grub-core/net/tftp.c |  8 +++--
- include/grub/net.h   |  1 +
- 4 files changed, 109 insertions(+), 12 deletions(-)
-
-diff --git a/grub-core/net/http.c b/grub-core/net/http.c
-index b616cf40b1e..12a2632ea55 100644
---- a/grub-core/net/http.c
-+++ b/grub-core/net/http.c
-@@ -289,7 +289,9 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)),
- 	  nb2 = grub_netbuff_alloc (data->chunk_rem);
- 	  if (!nb2)
- 	    return grub_errno;
--	  grub_netbuff_put (nb2, data->chunk_rem);
-+	  err = grub_netbuff_put (nb2, data->chunk_rem);
-+	  if (err)
-+	    return grub_errno;
- 	  grub_memcpy (nb2->data, nb->data, data->chunk_rem);
- 	  if (file->device->net->packs.count >= 20)
- 	    {
-@@ -312,12 +314,14 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
-   int i;
-   struct grub_net_buff *nb;
-   grub_err_t err;
-+  char* server = file->device->net->server;
-+  int port = file->device->net->port;
- 
-   nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE
- 			   + sizeof ("GET ") - 1
- 			   + grub_strlen (data->filename)
- 			   + sizeof (" HTTP/1.1\r\nHost: ") - 1
--			   + grub_strlen (file->device->net->server)
-+			   + grub_strlen (server) + sizeof (":XXXXXXXXXX")
- 			   + sizeof ("\r\nUser-Agent: " PACKAGE_STRING
- 				     "\r\n") - 1
- 			   + sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX"
-@@ -356,7 +360,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
- 	       sizeof (" HTTP/1.1\r\nHost: ") - 1);
- 
-   ptr = nb->tail;
--  err = grub_netbuff_put (nb, grub_strlen (file->device->net->server));
-+  err = grub_netbuff_put (nb, grub_strlen (server));
-   if (err)
-     {
-       grub_netbuff_free (nb);
-@@ -365,6 +369,15 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
-   grub_memcpy (ptr, file->device->net->server,
- 	       grub_strlen (file->device->net->server));
- 
-+  if (port)
-+    {
-+      ptr = nb->tail;
-+      grub_snprintf ((char *) ptr,
-+	  sizeof (":XXXXXXXXXX"),
-+	  ":%d",
-+	  port);
-+    }
-+
-   ptr = nb->tail;
-   err = grub_netbuff_put (nb, 
- 			  sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n")
-@@ -390,8 +403,10 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
-   grub_netbuff_put (nb, 2);
-   grub_memcpy (ptr, "\r\n", 2);
- 
--  data->sock = grub_net_tcp_open (file->device->net->server,
--				  HTTP_PORT, http_receive,
-+  grub_dprintf ("http", "opening path %s on host %s TCP port %d\n",
-+		data->filename, server, port ? port : HTTP_PORT);
-+  data->sock = grub_net_tcp_open (server,
-+				  port ? port : HTTP_PORT, http_receive,
- 				  http_err, NULL,
- 				  file);
-   if (!data->sock)
-diff --git a/grub-core/net/net.c b/grub-core/net/net.c
-index a46f82362ed..0ce5e675ed7 100644
---- a/grub-core/net/net.c
-+++ b/grub-core/net/net.c
-@@ -444,6 +444,13 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
-   grub_uint16_t newip[8];
-   const char *ptr = val;
-   int word, quaddot = -1;
-+  int bracketed = 0;
-+
-+  if (ptr[0] == '[')
-+    {
-+      bracketed = 1;
-+      ptr++;
-+    }
- 
-   if (ptr[0] == ':' && ptr[1] != ':')
-     return 0;
-@@ -482,6 +489,8 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
-       grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
-     }
-   grub_memcpy (ip, newip, 16);
-+  if (bracketed && *ptr == ']')
-+    ptr++;
-   if (rest)
-     *rest = ptr;
-   return 1;
-@@ -1343,8 +1352,10 @@ grub_net_open_real (const char *name)
- {
-   grub_net_app_level_t proto;
-   const char *protname, *server;
-+  char *host;
-   grub_size_t protnamelen;
-   int try;
-+  int port = 0;
- 
-   if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
-     {
-@@ -1382,6 +1393,72 @@ grub_net_open_real (const char *name)
-       return NULL;
-     }  
- 
-+  char* port_start;
-+  /* ipv6 or port specified? */
-+  if ((port_start = grub_strchr (server, ':')))
-+    {
-+      char* ipv6_begin;
-+      if((ipv6_begin = grub_strchr (server, '[')))
-+	{
-+	  char* ipv6_end = grub_strchr (server, ']');
-+	  if(!ipv6_end)
-+	    {
-+	      grub_error (GRUB_ERR_NET_BAD_ADDRESS,
-+		      N_("mismatched [ in address"));
-+	      return NULL;
-+	    }
-+	  /* port number after bracketed ipv6 addr */
-+	  if(ipv6_end[1] == ':')
-+	    {
-+	      port = grub_strtoul (ipv6_end + 2, NULL, 10);
-+	      if(port > 65535)
-+		{
-+		  grub_error (GRUB_ERR_NET_BAD_ADDRESS,
-+			  N_("bad port number"));
-+		  return NULL;
-+		}
-+	    }
-+	  host = grub_strndup (ipv6_begin, (ipv6_end - ipv6_begin) + 1);
-+	}
-+      else
-+	{
-+	  if (grub_strchr (port_start + 1, ':'))
-+	    {
-+	      int iplen = grub_strlen (server);
-+	      /* bracket bare ipv6 addrs */
-+	      host = grub_malloc (iplen + 3);
-+	      if(!host)
-+		{
-+		  return NULL;
-+		}
-+	      host[0] = '[';
-+	      grub_memcpy (host + 1, server, iplen);
-+	      host[iplen + 1] = ']';
-+	      host[iplen + 2] = '\0';
-+	    }
-+	  else
-+	    {
-+	      /* hostname:port or ipv4:port */
-+	      port = grub_strtol (port_start + 1, NULL, 10);
-+	      if(port > 65535)
-+		{
-+		  grub_error (GRUB_ERR_NET_BAD_ADDRESS,
-+			  N_("bad port number"));
-+		  return NULL;
-+		}
-+	      host = grub_strndup (server, port_start - server);
-+	    }
-+	}
-+    }
-+  else
-+    {
-+      host = grub_strdup (server);
-+    }
-+  if (!host)
-+    {
-+      return NULL;
-+    }
-+
-   for (try = 0; try < 2; try++)
-     {
-       FOR_NET_APP_LEVEL (proto)
-@@ -1391,14 +1468,13 @@ grub_net_open_real (const char *name)
- 	  {
- 	    grub_net_t ret = grub_zalloc (sizeof (*ret));
- 	    if (!ret)
--	      return NULL;
--	    ret->protocol = proto;
--	    ret->server = grub_strdup (server);
--	    if (!ret->server)
- 	      {
--		grub_free (ret);
-+		grub_free (host);
- 		return NULL;
- 	      }
-+	    ret->protocol = proto;
-+	    ret->port = port;
-+	    ret->server = host;
- 	    ret->fs = &grub_net_fs;
- 	    return ret;
- 	  }
-@@ -1473,6 +1549,7 @@ grub_net_open_real (const char *name)
-   grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"),
- 	      name);
- 
-+  grub_free (host);
-   return NULL;
- }
- 
-diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
-index 4ab2f5c7357..d54b13f09ff 100644
---- a/grub-core/net/tftp.c
-+++ b/grub-core/net/tftp.c
-@@ -295,6 +295,7 @@ tftp_open (struct grub_file *file, const char *filename)
-   grub_err_t err;
-   grub_uint8_t *nbd;
-   grub_net_network_level_address_t addr;
-+  int port = file->device->net->port;
- 
-   data = grub_zalloc (sizeof (*data));
-   if (!data)
-@@ -362,14 +363,17 @@ tftp_open (struct grub_file *file, const char *filename)
-   err = grub_net_resolve_address (file->device->net->server, &addr);
-   if (err)
-     {
--      grub_dprintf("tftp", "Address resolution failed: %d\n", err);
-+      grub_dprintf ("tftp", "Address resolution failed: %d\n", err);
-+      grub_dprintf ("tftp", "file_size is %llu, block_size is %llu\n",
-+		    (unsigned long long)data->file_size,
-+		    (unsigned long long)data->block_size);
-       grub_free (data);
-       return err;
-     }
- 
-   grub_dprintf("tftp", "opening connection\n");
-   data->sock = grub_net_udp_open (addr,
--				  TFTP_SERVER_PORT, tftp_receive,
-+				  port ? port : TFTP_SERVER_PORT, tftp_receive,
- 				  file);
-   if (!data->sock)
-     {
-diff --git a/include/grub/net.h b/include/grub/net.h
-index af0404db7e3..d55d505a03a 100644
---- a/include/grub/net.h
-+++ b/include/grub/net.h
-@@ -273,6 +273,7 @@ typedef struct grub_net
- {
-   char *server;
-   char *name;
-+  int port;
-   grub_net_app_level_t protocol;
-   grub_net_packets_t packs;
-   grub_off_t offset;
diff --git a/SOURCES/0089-bootp-New-net_bootp6-command.patch b/SOURCES/0089-bootp-New-net_bootp6-command.patch
deleted file mode 100644
index 21b3871..0000000
--- a/SOURCES/0089-bootp-New-net_bootp6-command.patch
+++ /dev/null
@@ -1,1368 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Michael Chang <mchang@suse.com>
-Date: Wed, 10 Jul 2019 15:42:36 +0200
-Subject: [PATCH] bootp: New net_bootp6 command
-
-Implement new net_bootp6 command for IPv6 network auto configuration via the
-DHCPv6 protocol (RFC3315).
-
-Signed-off-by: Michael Chang <mchang@suse.com>
-Signed-off-by: Ken Lin <ken.lin@hpe.com>
-[pjones: Put back our code to add a local route]
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/net/bootp.c              | 1059 ++++++++++++++++++++++++++++++------
- grub-core/net/drivers/efi/efinet.c |   20 +-
- grub-core/net/ip.c                 |   39 ++
- include/grub/efi/api.h             |    2 +-
- include/grub/net.h                 |   91 ++--
- 5 files changed, 1002 insertions(+), 209 deletions(-)
-
-diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
-index 08b6b2b5d6c..fe93b80f1cf 100644
---- a/grub-core/net/bootp.c
-+++ b/grub-core/net/bootp.c
-@@ -24,6 +24,98 @@
- #include <grub/net/netbuff.h>
- #include <grub/net/udp.h>
- #include <grub/datetime.h>
-+#include <grub/time.h>
-+#include <grub/list.h>
-+
-+static int
-+dissect_url (const char *url, char **proto, char **host, char **path)
-+{
-+  const char *p, *ps;
-+  grub_size_t l;
-+
-+  *proto = *host = *path = NULL;
-+  ps = p = url;
-+
-+  while ((p = grub_strchr (p, ':')))
-+    {
-+      if (grub_strlen (p) < sizeof ("://") - 1)
-+	break;
-+      if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0)
-+	{
-+	  l = p - ps;
-+	  *proto = grub_malloc (l + 1);
-+	  if (!*proto)
-+	    {
-+	      grub_print_error ();
-+	      return 0;
-+	    }
-+
-+	  grub_memcpy (*proto, ps, l);
-+	  (*proto)[l] = '\0';
-+	  p +=  sizeof ("://") - 1;
-+	  break;
-+	}
-+      ++p;
-+    }
-+
-+  if (!*proto)
-+    {
-+      grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url);
-+      return 0;
-+    }
-+
-+  ps = p;
-+  p = grub_strchr (p, '/');
-+
-+  if (!p)
-+    {
-+      grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url);
-+      grub_free (*proto);
-+      *proto = NULL;
-+      return 0;
-+    }
-+
-+  l = p - ps;
-+
-+  if (l > 2 && ps[0] == '[' && ps[l - 1] == ']')
-+    {
-+      *host = grub_malloc (l - 1);
-+      if (!*host)
-+	{
-+	  grub_print_error ();
-+	  grub_free (*proto);
-+	  *proto = NULL;
-+	  return 0;
-+	}
-+      grub_memcpy (*host, ps + 1, l - 2);
-+      (*host)[l - 2] = 0;
-+    }
-+  else
-+    {
-+      *host = grub_malloc (l + 1);
-+      if (!*host)
-+	{
-+	  grub_print_error ();
-+	  grub_free (*proto);
-+	  *proto = NULL;
-+	  return 0;
-+	}
-+      grub_memcpy (*host, ps, l);
-+      (*host)[l] = 0;
-+    }
-+
-+  *path = grub_strdup (p);
-+  if (!*path)
-+    {
-+      grub_print_error ();
-+      grub_free (*host);
-+      grub_free (*proto);
-+      *host = NULL;
-+      *proto = NULL;
-+      return 0;
-+    }
-+  return 1;
-+}
- 
- struct grub_dhcp_discover_options
- {
-@@ -604,6 +696,584 @@ out:
-   return err;
- }
- 
-+/* The default netbuff size for sending DHCPv6 packets which should be
-+   large enough to hold the information */
-+#define GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE 512
-+
-+struct grub_dhcp6_options
-+{
-+  grub_uint8_t *client_duid;
-+  grub_uint16_t client_duid_len;
-+  grub_uint8_t *server_duid;
-+  grub_uint16_t server_duid_len;
-+  grub_uint32_t iaid;
-+  grub_uint32_t t1;
-+  grub_uint32_t t2;
-+  grub_net_network_level_address_t *ia_addr;
-+  grub_uint32_t preferred_lifetime;
-+  grub_uint32_t valid_lifetime;
-+  grub_net_network_level_address_t *dns_server_addrs;
-+  grub_uint16_t num_dns_server;
-+  char *boot_file_proto;
-+  char *boot_file_server_ip;
-+  char *boot_file_path;
-+};
-+
-+typedef struct grub_dhcp6_options *grub_dhcp6_options_t;
-+
-+struct grub_dhcp6_session
-+{
-+  struct grub_dhcp6_session *next;
-+  struct grub_dhcp6_session **prev;
-+  grub_uint32_t iaid;
-+  grub_uint32_t transaction_id:24;
-+  grub_uint64_t start_time;
-+  struct grub_net_dhcp6_option_duid_ll duid;
-+  struct grub_net_network_level_interface *iface;
-+
-+  /* The associated dhcpv6 options */
-+  grub_dhcp6_options_t adv;
-+  grub_dhcp6_options_t reply;
-+};
-+
-+typedef struct grub_dhcp6_session *grub_dhcp6_session_t;
-+
-+typedef void (*dhcp6_option_hook_fn) (const struct grub_net_dhcp6_option *opt, void *data);
-+
-+static void
-+foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size,
-+		      dhcp6_option_hook_fn hook, void *hook_data);
-+
-+static void
-+parse_dhcp6_iaaddr (const struct grub_net_dhcp6_option *opt, void *data)
-+{
-+  grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t )data;
-+
-+  grub_uint16_t code = grub_be_to_cpu16 (opt->code);
-+  grub_uint16_t len = grub_be_to_cpu16 (opt->len);
-+
-+  if (code == GRUB_NET_DHCP6_OPTION_IAADDR)
-+    {
-+      const struct grub_net_dhcp6_option_iaaddr *iaaddr;
-+      iaaddr = (const struct grub_net_dhcp6_option_iaaddr *)opt->data;
-+
-+      if (len < sizeof (*iaaddr))
-+	{
-+	  grub_dprintf ("bootp", "DHCPv6: code %u with insufficient length %u\n", code, len);
-+	  return;
-+	}
-+      if (!dhcp6->ia_addr)
-+	{
-+	  dhcp6->ia_addr = grub_malloc (sizeof(*dhcp6->ia_addr));
-+	  dhcp6->ia_addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
-+	  dhcp6->ia_addr->ipv6[0] = grub_get_unaligned64 (iaaddr->addr);
-+	  dhcp6->ia_addr->ipv6[1] = grub_get_unaligned64 (iaaddr->addr + 8);
-+	  dhcp6->preferred_lifetime = grub_be_to_cpu32 (iaaddr->preferred_lifetime);
-+	  dhcp6->valid_lifetime = grub_be_to_cpu32 (iaaddr->valid_lifetime);
-+	}
-+    }
-+}
-+
-+static void
-+parse_dhcp6_option (const struct grub_net_dhcp6_option *opt, void *data)
-+{
-+  grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t)data;
-+  grub_uint16_t code = grub_be_to_cpu16 (opt->code);
-+  grub_uint16_t len = grub_be_to_cpu16 (opt->len);
-+
-+  switch (code)
-+    {
-+      case GRUB_NET_DHCP6_OPTION_CLIENTID:
-+
-+	if (dhcp6->client_duid || !len)
-+	  {
-+	    grub_dprintf ("bootp", "Skipped DHCPv6 CLIENTID with length %u\n", len);
-+	    break;
-+	  }
-+	dhcp6->client_duid = grub_malloc (len);
-+	grub_memcpy (dhcp6->client_duid, opt->data, len);
-+	dhcp6->client_duid_len = len;
-+	break;
-+
-+      case GRUB_NET_DHCP6_OPTION_SERVERID:
-+
-+	if (dhcp6->server_duid || !len)
-+	  {
-+	    grub_dprintf ("bootp", "Skipped DHCPv6 SERVERID with length %u\n", len);
-+	    break;
-+	  }
-+	dhcp6->server_duid = grub_malloc (len);
-+	grub_memcpy (dhcp6->server_duid, opt->data, len);
-+	dhcp6->server_duid_len = len;
-+	break;
-+
-+      case GRUB_NET_DHCP6_OPTION_IA_NA:
-+	{
-+	  const struct grub_net_dhcp6_option_iana *ia_na;
-+	  grub_uint16_t data_len;
-+
-+	  if (dhcp6->iaid || len < sizeof (*ia_na))
-+	    {
-+	      grub_dprintf ("bootp", "Skipped DHCPv6 IA_NA with length %u\n", len);
-+	      break;
-+	    }
-+	  ia_na = (const struct grub_net_dhcp6_option_iana *)opt->data;
-+	  dhcp6->iaid = grub_be_to_cpu32 (ia_na->iaid);
-+	  dhcp6->t1 = grub_be_to_cpu32 (ia_na->t1);
-+	  dhcp6->t2 = grub_be_to_cpu32 (ia_na->t2);
-+
-+	  data_len = len - sizeof (*ia_na);
-+	  if (data_len)
-+	    foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)ia_na->data, data_len, parse_dhcp6_iaaddr, dhcp6);
-+	}
-+	break;
-+
-+      case GRUB_NET_DHCP6_OPTION_DNS_SERVERS:
-+	{
-+	  const grub_uint8_t *po;
-+	  grub_uint16_t ln;
-+	  grub_net_network_level_address_t *la;
-+
-+	  if (!len || len & 0xf)
-+	    {
-+	      grub_dprintf ("bootp", "Skip invalid length DHCPv6 DNS_SERVERS \n");
-+	      break;
-+	    }
-+	  dhcp6->num_dns_server = ln = len >> 4;
-+	  dhcp6->dns_server_addrs = la = grub_zalloc (ln * sizeof (*la));
-+
-+	  for (po = opt->data; ln > 0; po += 0x10, la++, ln--)
-+	    {
-+	      la->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
-+	      la->ipv6[0] = grub_get_unaligned64 (po);
-+	      la->ipv6[1] = grub_get_unaligned64 (po + 8);
-+	      la->option = DNS_OPTION_PREFER_IPV6;
-+	    }
-+	}
-+	break;
-+
-+      case GRUB_NET_DHCP6_OPTION_BOOTFILE_URL:
-+	dissect_url ((const char *)opt->data,
-+		      &dhcp6->boot_file_proto,
-+		      &dhcp6->boot_file_server_ip,
-+		      &dhcp6->boot_file_path);
-+	break;
-+
-+      default:
-+	break;
-+    }
-+}
-+
-+static void
-+foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, dhcp6_option_hook_fn hook, void *hook_data)
-+{
-+  while (size)
-+    {
-+      grub_uint16_t code, len;
-+
-+      if (size < sizeof (*opt))
-+	{
-+	  grub_dprintf ("bootp", "DHCPv6: Options stopped with remaining size %" PRIxGRUB_SIZE "\n", size);
-+	  break;
-+	}
-+      size -= sizeof (*opt);
-+      len = grub_be_to_cpu16 (opt->len);
-+      code = grub_be_to_cpu16 (opt->code);
-+      if (size < len)
-+	{
-+	  grub_dprintf ("bootp", "DHCPv6: Options stopped at out of bound length %u for option %u\n", len, code);
-+	  break;
-+	}
-+      if (!len)
-+	{
-+	  grub_dprintf ("bootp", "DHCPv6: Options stopped at zero length option %u\n", code);
-+	  break;
-+	}
-+      else
-+	{
-+	  if (hook)
-+	    hook (opt, hook_data);
-+	  size -= len;
-+	  opt = (const struct grub_net_dhcp6_option *)((grub_uint8_t *)opt + len + sizeof (*opt));
-+	}
-+    }
-+}
-+
-+static grub_dhcp6_options_t
-+grub_dhcp6_options_get (const struct grub_net_dhcp6_packet *v6h,
-+			grub_size_t size)
-+{
-+  grub_dhcp6_options_t options;
-+
-+  if (size < sizeof (*v6h))
-+    {
-+      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small"));
-+      return NULL;
-+    }
-+
-+  options = grub_zalloc (sizeof(*options));
-+  if (!options)
-+    return NULL;
-+
-+  foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)v6h->dhcp_options,
-+		       size - sizeof (*v6h), parse_dhcp6_option, options);
-+
-+  return options;
-+}
-+
-+static void
-+grub_dhcp6_options_free (grub_dhcp6_options_t options)
-+{
-+  if (options->client_duid)
-+    grub_free (options->client_duid);
-+  if (options->server_duid)
-+    grub_free (options->server_duid);
-+  if (options->ia_addr)
-+    grub_free (options->ia_addr);
-+  if (options->dns_server_addrs)
-+    grub_free (options->dns_server_addrs);
-+  if (options->boot_file_proto)
-+    grub_free (options->boot_file_proto);
-+  if (options->boot_file_server_ip)
-+    grub_free (options->boot_file_server_ip);
-+  if (options->boot_file_path)
-+    grub_free (options->boot_file_path);
-+
-+  grub_free (options);
-+}
-+
-+static grub_dhcp6_session_t grub_dhcp6_sessions;
-+#define FOR_DHCP6_SESSIONS_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE (var, next, grub_dhcp6_sessions)
-+#define FOR_DHCP6_SESSIONS(var) FOR_LIST_ELEMENTS (var, grub_dhcp6_sessions)
-+
-+static void
-+grub_net_configure_by_dhcp6_info (const char *name,
-+	  struct grub_net_card *card,
-+	  grub_dhcp6_options_t dhcp6,
-+	  int is_def,
-+	  int flags,
-+	  struct grub_net_network_level_interface **ret_inf)
-+{
-+  grub_net_network_level_netaddress_t netaddr;
-+  struct grub_net_network_level_interface *inf;
-+
-+  if (dhcp6->ia_addr)
-+    {
-+      inf = grub_net_add_addr (name, card, dhcp6->ia_addr, &card->default_address, flags);
-+
-+      netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
-+      netaddr.ipv6.base[0] = dhcp6->ia_addr->ipv6[0];
-+      netaddr.ipv6.base[1] = 0;
-+      netaddr.ipv6.masksize = 64;
-+      grub_net_add_route (name, netaddr, inf);
-+
-+      if (ret_inf)
-+	*ret_inf = inf;
-+    }
-+
-+  if (dhcp6->dns_server_addrs)
-+    {
-+      grub_uint16_t i;
-+
-+      for (i = 0; i < dhcp6->num_dns_server; ++i)
-+	grub_net_add_dns_server (dhcp6->dns_server_addrs + i);
-+    }
-+
-+  if (dhcp6->boot_file_path)
-+    grub_env_set_net_property (name, "boot_file", dhcp6->boot_file_path,
-+			  grub_strlen (dhcp6->boot_file_path));
-+
-+  if (is_def && dhcp6->boot_file_server_ip)
-+    {
-+      grub_net_default_server = grub_strdup (dhcp6->boot_file_server_ip);
-+      grub_env_set ("net_default_interface", name);
-+      grub_env_export ("net_default_interface");
-+    }
-+}
-+
-+static void
-+grub_dhcp6_session_add (struct grub_net_network_level_interface *iface,
-+			grub_uint32_t iaid)
-+{
-+  grub_dhcp6_session_t se;
-+  struct grub_datetime date;
-+  grub_err_t err;
-+  grub_int32_t t = 0;
-+
-+  se = grub_malloc (sizeof (*se));
-+
-+  err = grub_get_datetime (&date);
-+  if (err || !grub_datetime2unixtime (&date, &t))
-+    {
-+      grub_errno = GRUB_ERR_NONE;
-+      t = 0;
-+    }
-+
-+  se->iface = iface;
-+  se->iaid = iaid;
-+  se->transaction_id = t;
-+  se->start_time = grub_get_time_ms ();
-+  se->duid.type = grub_cpu_to_be16_compile_time (3) ;
-+  se->duid.hw_type = grub_cpu_to_be16_compile_time (1);
-+  grub_memcpy (&se->duid.hwaddr, &iface->hwaddress.mac, sizeof (se->duid.hwaddr));
-+  se->adv = NULL;
-+  se->reply = NULL;
-+  grub_list_push (GRUB_AS_LIST_P (&grub_dhcp6_sessions), GRUB_AS_LIST (se));
-+}
-+
-+static void
-+grub_dhcp6_session_remove (grub_dhcp6_session_t se)
-+{
-+  grub_list_remove (GRUB_AS_LIST (se));
-+  if (se->adv)
-+    grub_dhcp6_options_free (se->adv);
-+  if (se->reply)
-+    grub_dhcp6_options_free (se->reply);
-+  grub_free (se);
-+}
-+
-+static void
-+grub_dhcp6_session_remove_all (void)
-+{
-+  grub_dhcp6_session_t se, next;
-+
-+  FOR_DHCP6_SESSIONS_SAFE (se, next)
-+    {
-+      grub_dhcp6_session_remove (se);
-+    }
-+  grub_dhcp6_sessions = NULL;
-+}
-+
-+static grub_err_t
-+grub_dhcp6_session_configure_network (grub_dhcp6_session_t se)
-+{
-+  char *name;
-+
-+  name = grub_xasprintf ("%s:dhcp6", se->iface->card->name);
-+  if (!name)
-+    return grub_errno;
-+
-+  grub_net_configure_by_dhcp6_info (name, se->iface->card, se->reply, 1, 0, 0);
-+  grub_free (name);
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+grub_dhcp6_session_send_request (grub_dhcp6_session_t se)
-+{
-+  struct grub_net_buff *nb;
-+  struct grub_net_dhcp6_option *opt;
-+  struct grub_net_dhcp6_packet *v6h;
-+  struct grub_net_dhcp6_option_iana *ia_na;
-+  struct grub_net_dhcp6_option_iaaddr *iaaddr;
-+  struct udphdr *udph;
-+  grub_net_network_level_address_t multicast;
-+  grub_net_link_level_address_t ll_multicast;
-+  grub_uint64_t elapsed;
-+  struct grub_net_network_level_interface *inf = se->iface;
-+  grub_dhcp6_options_t dhcp6 = se->adv;
-+  grub_err_t err = GRUB_ERR_NONE;
-+
-+  multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
-+  multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48);
-+  multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL);
-+
-+  err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast);
-+  if (err)
-+    return err;
-+
-+  nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
-+
-+  if (!nb)
-+    return grub_errno;
-+
-+  err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
-+  if (err)
-+    {
-+      grub_netbuff_free (nb);
-+      return err;
-+    }
-+
-+  err = grub_netbuff_push (nb, dhcp6->client_duid_len + sizeof (*opt));
-+  if (err)
-+    {
-+      grub_netbuff_free (nb);
-+      return err;
-+    }
-+  opt = (struct grub_net_dhcp6_option *)nb->data;
-+  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID);
-+  opt->len = grub_cpu_to_be16 (dhcp6->client_duid_len);
-+  grub_memcpy (opt->data, dhcp6->client_duid , dhcp6->client_duid_len);
-+
-+  err = grub_netbuff_push (nb, dhcp6->server_duid_len + sizeof (*opt));
-+  if (err)
-+    {
-+      grub_netbuff_free (nb);
-+      return err;
-+    }
-+  opt = (struct grub_net_dhcp6_option *)nb->data;
-+  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_SERVERID);
-+  opt->len = grub_cpu_to_be16 (dhcp6->server_duid_len);
-+  grub_memcpy (opt->data, dhcp6->server_duid , dhcp6->server_duid_len);
-+
-+  err = grub_netbuff_push (nb, sizeof (*ia_na) + sizeof (*opt));
-+  if (err)
-+    {
-+      grub_netbuff_free (nb);
-+      return err;
-+    }
-+
-+  if (dhcp6->ia_addr)
-+    {
-+      err = grub_netbuff_push (nb, sizeof(*iaaddr) + sizeof (*opt));
-+      if (err)
-+	{
-+	  grub_netbuff_free (nb);
-+	  return err;
-+	}
-+    }
-+  opt = (struct grub_net_dhcp6_option *)nb->data;
-+  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
-+  opt->len = grub_cpu_to_be16 (sizeof (*ia_na));
-+  if (dhcp6->ia_addr)
-+    opt->len += grub_cpu_to_be16 (sizeof(*iaaddr) + sizeof (*opt));
-+
-+  ia_na = (struct grub_net_dhcp6_option_iana *)opt->data;
-+  ia_na->iaid = grub_cpu_to_be32 (dhcp6->iaid);
-+
-+  ia_na->t1 = grub_cpu_to_be32 (dhcp6->t1);
-+  ia_na->t2 = grub_cpu_to_be32 (dhcp6->t2);
-+
-+  if (dhcp6->ia_addr)
-+    {
-+      opt = (struct grub_net_dhcp6_option *)ia_na->data;
-+      opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR);
-+      opt->len = grub_cpu_to_be16 (sizeof (*iaaddr));
-+      iaaddr = (struct grub_net_dhcp6_option_iaaddr *)opt->data;
-+      grub_set_unaligned64 (iaaddr->addr, dhcp6->ia_addr->ipv6[0]);
-+      grub_set_unaligned64 (iaaddr->addr + 8, dhcp6->ia_addr->ipv6[1]);
-+
-+      iaaddr->preferred_lifetime = grub_cpu_to_be32 (dhcp6->preferred_lifetime);
-+      iaaddr->valid_lifetime = grub_cpu_to_be32 (dhcp6->valid_lifetime);
-+    }
-+
-+  err = grub_netbuff_push (nb, sizeof (*opt) + 2 * sizeof (grub_uint16_t));
-+  if (err)
-+    {
-+      grub_netbuff_free (nb);
-+      return err;
-+    }
-+
-+  opt = (struct grub_net_dhcp6_option*) nb->data;
-+  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ORO);
-+  opt->len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_uint16_t));
-+  grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL));
-+  grub_set_unaligned16 (opt->data + 2, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS));
-+
-+  err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t));
-+  if (err)
-+    {
-+      grub_netbuff_free (nb);
-+      return err;
-+    }
-+  opt = (struct grub_net_dhcp6_option*) nb->data;
-+  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME);
-+  opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t));
-+
-+  /* the time is expressed in hundredths of a second */
-+  elapsed = grub_divmod64 (grub_get_time_ms () - se->start_time, 10, 0);
-+
-+  if (elapsed > 0xffff)
-+    elapsed = 0xffff;
-+
-+  grub_set_unaligned16 (opt->data,  grub_cpu_to_be16 ((grub_uint16_t)elapsed));
-+
-+  err = grub_netbuff_push (nb, sizeof (*v6h));
-+  if (err)
-+    {
-+      grub_netbuff_free (nb);
-+      return err;
-+    }
-+
-+  v6h = (struct grub_net_dhcp6_packet *) nb->data;
-+  v6h->message_type = GRUB_NET_DHCP6_REQUEST;
-+  v6h->transaction_id = se->transaction_id;
-+
-+  err = grub_netbuff_push (nb, sizeof (*udph));
-+  if (err)
-+    {
-+      grub_netbuff_free (nb);
-+      return err;
-+    }
-+
-+  udph = (struct udphdr *) nb->data;
-+  udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT);
-+  udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT);
-+  udph->chksum = 0;
-+  udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
-+
-+  udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP,
-+						 &inf->address,
-+						 &multicast);
-+  err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb,
-+				 GRUB_NET_IP_UDP);
-+
-+  grub_netbuff_free (nb);
-+
-+  return err;
-+}
-+
-+struct grub_net_network_level_interface *
-+grub_net_configure_by_dhcpv6_reply (const char *name,
-+	struct grub_net_card *card,
-+	grub_net_interface_flags_t flags,
-+	const struct grub_net_dhcp6_packet *v6h,
-+	grub_size_t size,
-+	int is_def,
-+	char **device, char **path)
-+{
-+  struct grub_net_network_level_interface *inf;
-+  grub_dhcp6_options_t dhcp6;
-+  int mask = -1;
-+
-+  dhcp6 = grub_dhcp6_options_get (v6h, size);
-+  if (!dhcp6)
-+    {
-+      grub_print_error ();
-+      return NULL;
-+    }
-+
-+  grub_net_configure_by_dhcp6_info (name, card, dhcp6, is_def, flags, &inf);
-+
-+  if (device && dhcp6->boot_file_proto && dhcp6->boot_file_server_ip)
-+    {
-+      *device = grub_xasprintf ("%s,%s", dhcp6->boot_file_proto, dhcp6->boot_file_server_ip);
-+      grub_print_error ();
-+    }
-+  if (path && dhcp6->boot_file_path)
-+    {
-+      *path = grub_strdup (dhcp6->boot_file_path);
-+      grub_print_error ();
-+      if (*path)
-+	{
-+	  char *slash;
-+	  slash = grub_strrchr (*path, '/');
-+	  if (slash)
-+	    *slash = 0;
-+	  else
-+	    **path = 0;
-+	}
-+    }
-+
-+  grub_dhcp6_options_free (dhcp6);
-+
-+  if (inf)
-+    grub_net_add_ipv6_local (inf, mask);
-+
-+  return inf;
-+}
-+
- /*
-  * This is called directly from net/ip.c:handle_dgram(), because those
-  * BOOTP/DHCP packets are a bit special due to their improper
-@@ -672,6 +1342,77 @@ grub_net_process_dhcp (struct grub_net_buff *nb,
-     }
- }
- 
-+grub_err_t
-+grub_net_process_dhcp6 (struct grub_net_buff *nb,
-+                       struct grub_net_card *card __attribute__ ((unused)))
-+{
-+  const struct grub_net_dhcp6_packet *v6h;
-+  grub_dhcp6_session_t se;
-+  grub_size_t size;
-+  grub_dhcp6_options_t options;
-+
-+  v6h = (const struct grub_net_dhcp6_packet *) nb->data;
-+  size = nb->tail - nb->data;
-+
-+  options = grub_dhcp6_options_get (v6h, size);
-+  if (!options)
-+    return grub_errno;
-+
-+  if (!options->client_duid || !options->server_duid || !options->ia_addr)
-+    {
-+      grub_dhcp6_options_free (options);
-+      return grub_error (GRUB_ERR_BAD_ARGUMENT, "Bad DHCPv6 Packet");
-+    }
-+
-+  FOR_DHCP6_SESSIONS (se)
-+    {
-+      if (se->transaction_id == v6h->transaction_id &&
-+         grub_memcmp (options->client_duid, &se->duid, sizeof (se->duid)) == 0 &&
-+         se->iaid == options->iaid)
-+       break;
-+    }
-+
-+  if (!se)
-+    {
-+      grub_dprintf ("bootp", "DHCPv6 session not found\n");
-+      grub_dhcp6_options_free (options);
-+      return GRUB_ERR_NONE;
-+    }
-+
-+  if (v6h->message_type == GRUB_NET_DHCP6_ADVERTISE)
-+    {
-+      if (se->adv)
-+       {
-+         grub_dprintf ("bootp", "Skipped DHCPv6 Advertised .. \n");
-+         grub_dhcp6_options_free (options);
-+         return GRUB_ERR_NONE;
-+       }
-+
-+      se->adv = options;
-+      return grub_dhcp6_session_send_request (se);
-+    }
-+  else if (v6h->message_type == GRUB_NET_DHCP6_REPLY)
-+    {
-+      if (!se->adv)
-+       {
-+         grub_dprintf ("bootp", "Skipped DHCPv6 Reply .. \n");
-+         grub_dhcp6_options_free (options);
-+         return GRUB_ERR_NONE;
-+       }
-+
-+      se->reply = options;
-+      grub_dhcp6_session_configure_network (se);
-+      grub_dhcp6_session_remove (se);
-+      return GRUB_ERR_NONE;
-+    }
-+  else
-+    {
-+      grub_dhcp6_options_free (options);
-+    }
-+
-+  return GRUB_ERR_NONE;
-+}
-+
- static grub_err_t
- grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)),
- 		  int argc, char **args)
-@@ -897,180 +1638,174 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
-   return err;
- }
- 
--static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp;
--
--struct grub_net_network_level_interface *
--grub_net_configure_by_dhcpv6_ack (const char *name,
--				  struct grub_net_card *card,
--				  grub_net_interface_flags_t flags
--				    __attribute__((__unused__)),
--				  const grub_net_link_level_address_t *hwaddr,
--				  const struct grub_net_dhcpv6_packet *packet,
--				  int is_def, char **device, char **path)
-+static grub_err_t
-+grub_cmd_bootp6 (struct grub_command *cmd __attribute__ ((unused)),
-+                 int argc, char **args)
- {
--  struct grub_net_network_level_interface *inter = NULL;
--  struct grub_net_network_level_address addr;
--  int mask = -1;
-+  struct grub_net_card *card;
-+  grub_uint32_t iaid = 0;
-+  int interval;
-+  grub_err_t err;
-+  grub_dhcp6_session_t se;
- 
--  if (!device || !path)
--    return NULL;
-+  err = GRUB_ERR_NONE;
- 
--  *device = 0;
--  *path = 0;
-+  FOR_NET_CARDS (card)
-+  {
-+    struct grub_net_network_level_interface *iface;
- 
--  grub_dprintf ("net", "mac address is %02x:%02x:%02x:%02x:%02x:%02x\n",
--		hwaddr->mac[0], hwaddr->mac[1], hwaddr->mac[2],
--		hwaddr->mac[3], hwaddr->mac[4], hwaddr->mac[5]);
-+    if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
-+      continue;
- 
--  if (is_def)
--    grub_net_default_server = 0;
-+    iface = grub_net_ipv6_get_link_local (card, &card->default_address);
-+    if (!iface)
-+      {
-+       grub_dhcp6_session_remove_all ();
-+       return grub_errno;
-+      }
- 
--  if (is_def && !grub_net_default_server && packet)
-+    grub_dhcp6_session_add (iface, iaid++);
-+  }
-+
-+  for (interval = 200; interval < 10000; interval *= 2)
-     {
--      const grub_uint8_t *options = packet->dhcp_options;
--      unsigned int option_max = 1024 - OFFSET_OF (dhcp_options, packet);
--      unsigned int i;
--
--      for (i = 0; i < option_max - sizeof (grub_net_dhcpv6_option_t); )
--	{
--	  grub_uint16_t num, len;
--	  grub_net_dhcpv6_option_t *opt =
--	    (grub_net_dhcpv6_option_t *)(options + i);
--
--	  num = grub_be_to_cpu16(opt->option_num);
--	  len = grub_be_to_cpu16(opt->option_len);
--
--	  grub_dprintf ("net", "got dhcpv6 option %d len %d\n", num, len);
--
--	  if (len == 0)
--	    break;
--
--	  if (len + i > 1024)
--	    break;
--
--	  if (num == GRUB_NET_DHCP6_BOOTFILE_URL)
--	    {
--	      char *scheme, *userinfo, *host, *file;
--	      char *tmp;
--	      int hostlen;
--	      int port;
--	      int rc = extract_url_info ((const char *)opt->option_data,
--					 (grub_size_t)len,
--					 &scheme, &userinfo, &host, &port,
--					 &file);
--	      if (rc < 0)
--		continue;
--
--	      /* right now this only handles tftp. */
--	      if (grub_strcmp("tftp", scheme))
--		{
--		  grub_free (scheme);
--		  grub_free (userinfo);
--		  grub_free (host);
--		  grub_free (file);
--		  continue;
--		}
--	      grub_free (userinfo);
--
--	      hostlen = grub_strlen (host);
--	      if (hostlen > 2 && host[0] == '[' && host[hostlen-1] == ']')
--		{
--		  tmp = host+1;
--		  host[hostlen-1] = '\0';
--		}
--	      else
--		tmp = host;
--
--	      *device = grub_xasprintf ("%s,%s", scheme, tmp);
--	      grub_free (scheme);
--	      grub_free (host);
--
--	      if (file && *file)
--		{
--		  tmp = grub_strrchr (file, '/');
--		  if (tmp)
--		    *(tmp+1) = '\0';
--		  else
--		    file[0] = '\0';
--		}
--	      else if (!file)
--		file = grub_strdup ("");
--
--	      if (file[0] == '/')
--		{
--		  *path = grub_strdup (file+1);
--		  grub_free (file);
--		}
--	      else
--		*path = file;
--	    }
--	  else if (num == GRUB_NET_DHCP6_IA_NA)
--	    {
--	      const grub_net_dhcpv6_option_t *ia_na_opt;
--	      const grub_net_dhcpv6_opt_ia_na_t *ia_na =
--		(const grub_net_dhcpv6_opt_ia_na_t *)opt;
--	      unsigned int left = len - OFFSET_OF (options, ia_na);
--	      unsigned int j;
--
--	      if ((grub_uint8_t *)ia_na + left >
--		  (grub_uint8_t *)options + option_max)
--		left -= ((grub_uint8_t *)ia_na + left)
--		        - ((grub_uint8_t *)options + option_max);
--
--	      if (len < OFFSET_OF (option_data, opt)
--			+ sizeof (grub_net_dhcpv6_option_t))
--		{
--		  grub_dprintf ("net",
--				"found dhcpv6 ia_na option with no address\n");
--		  continue;
--		}
--
--	      for (j = 0; left > sizeof (grub_net_dhcpv6_option_t); )
--		{
--		  ia_na_opt = (const grub_net_dhcpv6_option_t *)
--			       (ia_na->options + j);
--		  grub_uint16_t ia_na_opt_num, ia_na_opt_len;
--
--		  ia_na_opt_num = grub_be_to_cpu16 (ia_na_opt->option_num);
--		  ia_na_opt_len = grub_be_to_cpu16 (ia_na_opt->option_len);
--		  if (ia_na_opt_len == 0)
--		    break;
--		  if (j + ia_na_opt_len > left)
--		    break;
--		  if (ia_na_opt_num == GRUB_NET_DHCP6_IA_ADDRESS)
--		    {
--		      const grub_net_dhcpv6_opt_ia_address_t *ia_addr;
--
--		      ia_addr = (const grub_net_dhcpv6_opt_ia_address_t *)
--				 ia_na_opt;
--		      addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
--		      grub_memcpy(addr.ipv6, ia_addr->ipv6_address,
--				  sizeof (ia_addr->ipv6_address));
--		      inter = grub_net_add_addr (name, card, &addr, hwaddr, 0);
--		    }
--
--		  j += ia_na_opt_len;
--		  left -= ia_na_opt_len;
--		}
--	    }
--
--	  i += len + 4;
--	}
--
--      grub_print_error ();
-+      int done = 1;
-+
-+      FOR_DHCP6_SESSIONS (se)
-+       {
-+         struct grub_net_buff *nb;
-+         struct grub_net_dhcp6_option *opt;
-+         struct grub_net_dhcp6_packet *v6h;
-+         struct grub_net_dhcp6_option_duid_ll *duid;
-+         struct grub_net_dhcp6_option_iana *ia_na;
-+         grub_net_network_level_address_t multicast;
-+         grub_net_link_level_address_t ll_multicast;
-+         struct udphdr *udph;
-+
-+         multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
-+         multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48);
-+         multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL);
-+
-+         err = grub_net_link_layer_resolve (se->iface,
-+                   &multicast, &ll_multicast);
-+         if (err)
-+           {
-+             grub_dhcp6_session_remove_all ();
-+             return err;
-+           }
-+
-+         nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
-+
-+         if (!nb)
-+           {
-+             grub_dhcp6_session_remove_all ();
-+             return grub_errno;
-+           }
-+
-+         err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
-+         if (err)
-+           {
-+             grub_dhcp6_session_remove_all ();
-+             grub_netbuff_free (nb);
-+             return err;
-+           }
-+
-+         err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t));
-+         if (err)
-+           {
-+             grub_dhcp6_session_remove_all ();
-+             grub_netbuff_free (nb);
-+             return err;
-+           }
-+
-+         opt = (struct grub_net_dhcp6_option *)nb->data;
-+         opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME);
-+         opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t));
-+         grub_set_unaligned16 (opt->data, 0);
-+
-+         err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*duid));
-+         if (err)
-+           {
-+             grub_dhcp6_session_remove_all ();
-+             grub_netbuff_free (nb);
-+             return err;
-+           }
-+
-+         opt = (struct grub_net_dhcp6_option *)nb->data;
-+         opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID);
-+         opt->len = grub_cpu_to_be16 (sizeof (*duid));
-+
-+         duid = (struct grub_net_dhcp6_option_duid_ll *) opt->data;
-+         grub_memcpy (duid, &se->duid, sizeof (*duid));
-+
-+         err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*ia_na));
-+         if (err)
-+           {
-+             grub_dhcp6_session_remove_all ();
-+             grub_netbuff_free (nb);
-+             return err;
-+           }
-+
-+         opt = (struct grub_net_dhcp6_option *)nb->data;
-+         opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
-+         opt->len = grub_cpu_to_be16 (sizeof (*ia_na));
-+         ia_na = (struct grub_net_dhcp6_option_iana *)opt->data;
-+         ia_na->iaid = grub_cpu_to_be32 (se->iaid);
-+         ia_na->t1 = 0;
-+         ia_na->t2 = 0;
-+
-+         err = grub_netbuff_push (nb, sizeof (*v6h));
-+         if (err)
-+           {
-+             grub_dhcp6_session_remove_all ();
-+             grub_netbuff_free (nb);
-+             return err;
-+           }
-+
-+         v6h = (struct grub_net_dhcp6_packet *)nb->data;
-+         v6h->message_type = GRUB_NET_DHCP6_SOLICIT;
-+         v6h->transaction_id = se->transaction_id;
-+
-+         grub_netbuff_push (nb, sizeof (*udph));
-+
-+         udph = (struct udphdr *) nb->data;
-+         udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT);
-+         udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT);
-+         udph->chksum = 0;
-+         udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
-+
-+         udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP,
-+                           &se->iface->address, &multicast);
-+
-+         err = grub_net_send_ip_packet (se->iface, &multicast,
-+                   &ll_multicast, nb, GRUB_NET_IP_UDP);
-+         done = 0;
-+         grub_netbuff_free (nb);
-+
-+         if (err)
-+           {
-+             grub_dhcp6_session_remove_all ();
-+             return err;
-+           }
-+       }
-+      if (!done)
-+       grub_net_poll_cards (interval, 0);
-     }
- 
--  if (is_def)
-+  FOR_DHCP6_SESSIONS (se)
-     {
--      grub_env_set ("net_default_interface", name);
--      grub_env_export ("net_default_interface");
-+      grub_error_push ();
-+      err = grub_error (GRUB_ERR_FILE_NOT_FOUND,
-+                       N_("couldn't autoconfigure %s"),
-+                       se->iface->card->name);
-     }
- 
--    if (inter)
--      grub_net_add_ipv6_local (inter, mask);
--    return inter;
-+  grub_dhcp6_session_remove_all ();
-+
-+  return err;
- }
- 
-+static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp, cmd_bootp6;
- 
- void
- grub_bootp_init (void)
-@@ -1084,11 +1819,15 @@ grub_bootp_init (void)
-   cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt,
- 				       N_("VAR INTERFACE NUMBER DESCRIPTION"),
- 				       N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value."));
-+  cmd_bootp6 = grub_register_command ("net_bootp6", grub_cmd_bootp6,
-+				     N_("[CARD]"),
-+				     N_("perform a DHCPv6 autoconfiguration"));
- }
- 
- void
- grub_bootp_fini (void)
- {
-+  grub_unregister_command (cmd_bootp6);
-   grub_unregister_command (cmd_getdhcp);
-   grub_unregister_command (cmd_bootp);
-   grub_unregister_command (cmd_dhcp);
-diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
-index a673bea807a..8e25680db0c 100644
---- a/grub-core/net/drivers/efi/efinet.c
-+++ b/grub-core/net/drivers/efi/efinet.c
-@@ -393,9 +393,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
-     pxe_mode = pxe->mode;
-     if (pxe_mode->using_ipv6)
-       {
--	grub_net_link_level_address_t hwaddr;
--	struct grub_net_network_level_interface *intf;
--
- 	grub_dprintf ("efinet", "using ipv6 and dhcpv6\n");
- 	grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n",
- 		      pxe_mode->dhcp_ack_received ? "yes" : "no",
-@@ -403,15 +400,14 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
- 	if (!pxe_mode->dhcp_ack_received)
- 	  continue;
- 
--	hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
--	grub_memcpy (hwaddr.mac,
--		     card->efi_net->mode->current_address,
--		     sizeof (hwaddr.mac));
--
--	intf = grub_net_configure_by_dhcpv6_ack (card->name, card, 0, &hwaddr,
--	      (const struct grub_net_dhcpv6_packet *)&pxe_mode->dhcp_ack.dhcpv6,
--	      1, device, path);
--	if (intf && device && path)
-+	grub_net_configure_by_dhcpv6_reply (card->name, card, 0,
-+					    (struct grub_net_dhcp6_packet *)
-+					    &pxe_mode->dhcp_ack,
-+					    sizeof (pxe_mode->dhcp_ack),
-+					    1, device, path);
-+	if (grub_errno)
-+	  grub_print_error ();
-+	if (device && path)
- 	  grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
-       }
-     else
-diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
-index a5896f6dc26..ce6bdc75c6d 100644
---- a/grub-core/net/ip.c
-+++ b/grub-core/net/ip.c
-@@ -239,6 +239,45 @@ handle_dgram (struct grub_net_buff *nb,
-   {
-     struct udphdr *udph;
-     udph = (struct udphdr *) nb->data;
-+
-+    if (proto == GRUB_NET_IP_UDP && udph->dst == grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT))
-+      {
-+	if (udph->chksum)
-+	  {
-+	    grub_uint16_t chk, expected;
-+	    chk = udph->chksum;
-+	    udph->chksum = 0;
-+	    expected = grub_net_ip_transport_checksum (nb,
-+						       GRUB_NET_IP_UDP,
-+						       source,
-+						       dest);
-+	    if (expected != chk)
-+	      {
-+		grub_dprintf ("net", "Invalid UDP checksum. "
-+			      "Expected %x, got %x\n",
-+			      grub_be_to_cpu16 (expected),
-+			      grub_be_to_cpu16 (chk));
-+		grub_netbuff_free (nb);
-+		return GRUB_ERR_NONE;
-+	      }
-+	    udph->chksum = chk;
-+	  }
-+
-+	err = grub_netbuff_pull (nb, sizeof (*udph));
-+	if (err)
-+	  {
-+	    grub_netbuff_free (nb);
-+	    return err;
-+	  }
-+
-+	err = grub_net_process_dhcp6 (nb, card);
-+	if (err)
-+	  grub_print_error ();
-+
-+	grub_netbuff_free (nb);
-+	return GRUB_ERR_NONE;
-+      }
-+
-     if (proto == GRUB_NET_IP_UDP && grub_be_to_cpu16 (udph->dst) == 68)
-       {
- 	const struct grub_net_bootp_packet *bootp;
-diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
-index 99628801478..7614b58dca8 100644
---- a/include/grub/efi/api.h
-+++ b/include/grub/efi/api.h
-@@ -1532,7 +1532,7 @@ typedef struct grub_efi_pxe_ip_filter
- {
-   grub_efi_uint8_t filters;
-   grub_efi_uint8_t ip_count;
--  grub_efi_uint8_t reserved;
-+  grub_efi_uint16_t reserved;
-   grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT];
- } grub_efi_pxe_ip_filter_t;
- 
-diff --git a/include/grub/net.h b/include/grub/net.h
-index d55d505a03a..543251f7273 100644
---- a/include/grub/net.h
-+++ b/include/grub/net.h
-@@ -451,50 +451,65 @@ struct grub_net_bootp_packet
-   grub_uint8_t vendor[0];
- } GRUB_PACKED;
- 
--enum
--  {
--    GRUB_NET_DHCP6_IA_NA = 3,
--    GRUB_NET_DHCP6_IA_ADDRESS = 5,
--    GRUB_NET_DHCP6_BOOTFILE_URL = 59,
--  };
--
--struct grub_net_dhcpv6_option
-+struct grub_net_dhcp6_packet
- {
--  grub_uint16_t option_num;
--  grub_uint16_t option_len;
--  grub_uint8_t option_data[];
-+  grub_uint32_t message_type:8;
-+  grub_uint32_t transaction_id:24;
-+  grub_uint8_t dhcp_options[0];
- } GRUB_PACKED;
--typedef struct grub_net_dhcpv6_option grub_net_dhcpv6_option_t;
- 
--struct grub_net_dhcpv6_opt_ia_na
--{
--  grub_uint16_t option_num;
--  grub_uint16_t option_len;
-+struct grub_net_dhcp6_option {
-+  grub_uint16_t code;
-+  grub_uint16_t len;
-+  grub_uint8_t data[0];
-+} GRUB_PACKED;
-+
-+struct grub_net_dhcp6_option_iana {
-   grub_uint32_t iaid;
-   grub_uint32_t t1;
-   grub_uint32_t t2;
--  grub_uint8_t options[];
-+  grub_uint8_t data[0];
- } GRUB_PACKED;
--typedef struct grub_net_dhcpv6_opt_ia_na grub_net_dhcpv6_opt_ia_na_t;
- 
--struct grub_net_dhcpv6_opt_ia_address
--{
--  grub_uint16_t option_num;
--  grub_uint16_t option_len;
--  grub_uint64_t ipv6_address[2];
-+struct grub_net_dhcp6_option_iaaddr {
-+  grub_uint8_t addr[16];
-   grub_uint32_t preferred_lifetime;
-   grub_uint32_t valid_lifetime;
--  grub_uint8_t options[];
-+  grub_uint8_t data[0];
- } GRUB_PACKED;
--typedef struct grub_net_dhcpv6_opt_ia_address grub_net_dhcpv6_opt_ia_address_t;
- 
--struct grub_net_dhcpv6_packet
-+struct grub_net_dhcp6_option_duid_ll
- {
--  grub_uint32_t message_type:8;
--  grub_uint32_t transaction_id:24;
--  grub_uint8_t dhcp_options[1024];
-+  grub_uint16_t type;
-+  grub_uint16_t hw_type;
-+  grub_uint8_t hwaddr[6];
- } GRUB_PACKED;
--typedef struct grub_net_dhcpv6_packet grub_net_dhcpv6_packet_t;
-+
-+enum
-+  {
-+    GRUB_NET_DHCP6_SOLICIT = 1,
-+    GRUB_NET_DHCP6_ADVERTISE = 2,
-+    GRUB_NET_DHCP6_REQUEST = 3,
-+    GRUB_NET_DHCP6_REPLY = 7
-+  };
-+
-+enum
-+  {
-+    DHCP6_CLIENT_PORT = 546,
-+    DHCP6_SERVER_PORT = 547
-+  };
-+
-+enum
-+  {
-+    GRUB_NET_DHCP6_OPTION_CLIENTID = 1,
-+    GRUB_NET_DHCP6_OPTION_SERVERID = 2,
-+    GRUB_NET_DHCP6_OPTION_IA_NA = 3,
-+    GRUB_NET_DHCP6_OPTION_IAADDR = 5,
-+    GRUB_NET_DHCP6_OPTION_ORO = 6,
-+    GRUB_NET_DHCP6_OPTION_ELAPSED_TIME = 8,
-+    GRUB_NET_DHCP6_OPTION_DNS_SERVERS = 23,
-+    GRUB_NET_DHCP6_OPTION_BOOTFILE_URL = 59
-+  };
- 
- #define	GRUB_NET_BOOTP_RFC1048_MAGIC_0	0x63
- #define	GRUB_NET_BOOTP_RFC1048_MAGIC_1	0x82
-@@ -532,12 +547,12 @@ grub_net_configure_by_dhcp_ack (const char *name,
- 				int is_def, char **device, char **path);
- 
- struct grub_net_network_level_interface *
--grub_net_configure_by_dhcpv6_ack (const char *name,
--				 struct grub_net_card *card,
--				 grub_net_interface_flags_t flags,
--				 const grub_net_link_level_address_t *hwaddr,
--				 const struct grub_net_dhcpv6_packet *packet,
--				 int is_def, char **device, char **path);
-+grub_net_configure_by_dhcpv6_reply (const char *name,
-+				    struct grub_net_card *card,
-+				    grub_net_interface_flags_t flags,
-+				    const struct grub_net_dhcp6_packet *v6,
-+				    grub_size_t size,
-+				    int is_def, char **device, char **path);
- 
- int
- grub_ipv6_get_masksize(grub_uint16_t *mask);
-@@ -554,6 +569,10 @@ void
- grub_net_process_dhcp (struct grub_net_buff *nb,
- 		       struct grub_net_network_level_interface *iface);
- 
-+grub_err_t
-+grub_net_process_dhcp6 (struct grub_net_buff *nb,
-+			struct grub_net_card *card);
-+
- int
- grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a,
- 		     const grub_net_link_level_address_t *b);
diff --git a/SOURCES/0089-module-verifier-make-it-possible-to-run-checkers-on-.patch b/SOURCES/0089-module-verifier-make-it-possible-to-run-checkers-on-.patch
new file mode 100644
index 0000000..78c15d6
--- /dev/null
+++ b/SOURCES/0089-module-verifier-make-it-possible-to-run-checkers-on-.patch
@@ -0,0 +1,58 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 1 Aug 2018 10:24:52 -0400
+Subject: [PATCH] module-verifier: make it possible to run checkers on
+ grub-module-verifierxx.c
+
+This makes it so you can treat grub-module-verifierxx.c as a file you can
+build directly, so syntax checkers like vim's "syntastic" plugin, which uses
+"gcc -x c -fsyntax-only" to build it, will work.
+
+One still has to do whatever setup is required to make it pick the right
+include dirs, which -W options we use, etc., but this makes it so you can do
+the checking on the file you're editing, rather than on a different file.
+
+v2: fix the typo in the #else clause in util/grub-module-verifierXX.c
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub-module-verifier32.c | 2 ++
+ util/grub-module-verifier64.c | 2 ++
+ util/grub-module-verifierXX.c | 9 +++++++++
+ 3 files changed, 13 insertions(+)
+
+diff --git a/util/grub-module-verifier32.c b/util/grub-module-verifier32.c
+index 257229f8f0..ba7d41aafe 100644
+--- a/util/grub-module-verifier32.c
++++ b/util/grub-module-verifier32.c
+@@ -1,2 +1,4 @@
+ #define MODULEVERIFIER_ELF32 1
++#ifndef GRUB_MODULE_VERIFIERXX
+ #include "grub-module-verifierXX.c"
++#endif
+diff --git a/util/grub-module-verifier64.c b/util/grub-module-verifier64.c
+index 4db6b4bedd..fc23ef800b 100644
+--- a/util/grub-module-verifier64.c
++++ b/util/grub-module-verifier64.c
+@@ -1,2 +1,4 @@
+ #define MODULEVERIFIER_ELF64 1
++#ifndef GRUB_MODULE_VERIFIERXX
+ #include "grub-module-verifierXX.c"
++#endif
+diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c
+index ceb24309ae..a98e2f9b1a 100644
+--- a/util/grub-module-verifierXX.c
++++ b/util/grub-module-verifierXX.c
+@@ -1,3 +1,12 @@
++#define GRUB_MODULE_VERIFIERXX
++#if !defined(MODULEVERIFIER_ELF32) && !defined(MODULEVERIFIER_ELF64)
++#if __SIZEOF_POINTER__ == 8
++#include "grub-module-verifier64.c"
++#else
++#include "grub-module-verifier32.c"
++#endif
++#endif
++
+ #include <string.h>
+ 
+ #include <grub/elf.h>
diff --git a/SOURCES/0090-Rework-how-the-fdt-command-builds.patch b/SOURCES/0090-Rework-how-the-fdt-command-builds.patch
new file mode 100644
index 0000000..8f41272
--- /dev/null
+++ b/SOURCES/0090-Rework-how-the-fdt-command-builds.patch
@@ -0,0 +1,123 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 11 Jul 2019 13:01:41 +0200
+Subject: [PATCH] Rework how the fdt command builds.
+
+Trying to avoid all variants of:
+cat syminfo.lst | sort | gawk -f ../../grub-core/genmoddep.awk > moddep.lst || (rm -f moddep.lst; exit 1)
+grub_fdt_install in linux is not defined
+grub_fdt_load in linux is not defined
+grub_fdt_unload in linux is not defined
+grub_fdt_install in xen_boot is not defined
+grub_fdt_load in xen_boot is not defined
+grub_fdt_unload in xen_boot is not defined
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+[javierm: Fix build with platform emu, aarch64, and risc-v]
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/Makefile.core.def | 5 ++---
+ grub-core/lib/fdt.c         | 2 --
+ grub-core/loader/efi/fdt.c  | 2 ++
+ include/grub/fdt.h          | 6 ++++++
+ grub-core/Makefile.am       | 1 +
+ 5 files changed, 11 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 12797336c9..4e7d90da76 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -177,7 +177,6 @@ kernel = {
+   arm_coreboot = kern/arm/coreboot/init.c;
+   arm_coreboot = kern/arm/coreboot/timer.c;
+   arm_coreboot = kern/arm/coreboot/coreboot.S;
+-  arm_coreboot = lib/fdt.c;
+   arm_coreboot = bus/fdt.c;
+   arm_coreboot = term/ps2.c;
+   arm_coreboot = term/arm/pl050.c;
+@@ -351,6 +350,8 @@ kernel = {
+   riscv64 = kern/riscv/cache_flush.S;
+   riscv64 = kern/riscv/dl.c;
+ 
++  fdt = lib/fdt.c;
++
+   emu = disk/host.c;
+   emu = kern/emu/cache_s.S;
+   emu = kern/emu/hostdisk.c;
+@@ -1825,7 +1826,6 @@ module = {
+   riscv32 = loader/riscv/linux.c;
+   riscv64 = loader/riscv/linux.c;
+   emu = loader/emu/linux.c;
+-  fdt = lib/fdt.c;
+ 
+   common = loader/linux.c;
+   common = lib/cmdline.c;
+@@ -1837,7 +1837,6 @@ module = {
+ module = {
+   name = fdt;
+   efi = loader/efi/fdt.c;
+-  common = lib/fdt.c;
+   enable = fdt;
+ };
+ 
+diff --git a/grub-core/lib/fdt.c b/grub-core/lib/fdt.c
+index 0d371c5633..37e04bd69e 100644
+--- a/grub-core/lib/fdt.c
++++ b/grub-core/lib/fdt.c
+@@ -21,8 +21,6 @@
+ #include <grub/mm.h>
+ #include <grub/dl.h>
+ 
+-GRUB_MOD_LICENSE ("GPLv3+");
+-
+ #define FDT_SUPPORTED_VERSION	17
+ 
+ #define FDT_BEGIN_NODE	0x00000001
+diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c
+index c86f283d75..c572415d38 100644
+--- a/grub-core/loader/efi/fdt.c
++++ b/grub-core/loader/efi/fdt.c
+@@ -27,6 +27,8 @@
+ #include <grub/efi/memory.h>
+ #include <grub/cpu/efi/memory.h>
+ 
++GRUB_MOD_LICENSE ("GPLv3+");
++
+ static void *loaded_fdt;
+ static void *fdt;
+ 
+diff --git a/include/grub/fdt.h b/include/grub/fdt.h
+index e609c7e411..3514aa4a5b 100644
+--- a/include/grub/fdt.h
++++ b/include/grub/fdt.h
+@@ -19,6 +19,9 @@
+ #ifndef GRUB_FDT_HEADER
+ #define GRUB_FDT_HEADER	1
+ 
++#if !defined(GRUB_MACHINE_EMU) && \
++    (defined(__arm__) || defined(__aarch64__) || defined(__riscv))
++
+ #include <grub/types.h>
+ #include <grub/symbol.h>
+ 
+@@ -144,4 +147,7 @@ int EXPORT_FUNC(grub_fdt_set_prop) (void *fdt, unsigned int nodeoffset, const ch
+   grub_fdt_set_prop ((fdt), (nodeoffset), "reg", reg_64, 16);  \
+ })
+ 
++#endif /* !defined(GRUB_MACHINE_EMU) && \
++          (defined(__arm__) || defined(__aarch64__) || defined(__riscv)) */
++
+ #endif	/* ! GRUB_FDT_HEADER */
+diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
+index bfd29a3bf0..c2e8a82bce 100644
+--- a/grub-core/Makefile.am
++++ b/grub-core/Makefile.am
+@@ -76,6 +76,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/sb.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env_private.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/err.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fdt.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/file.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fs.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i18n.h
diff --git a/SOURCES/0090-efinet-UEFI-IPv6-PXE-support.patch b/SOURCES/0090-efinet-UEFI-IPv6-PXE-support.patch
deleted file mode 100644
index d8b22b8..0000000
--- a/SOURCES/0090-efinet-UEFI-IPv6-PXE-support.patch
+++ /dev/null
@@ -1,126 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Michael Chang <mchang@suse.com>
-Date: Wed, 15 Apr 2015 14:48:30 +0800
-Subject: [PATCH] efinet: UEFI IPv6 PXE support
-
-When grub2 image is booted from UEFI IPv6 PXE, the DHCPv6 Reply packet is
-cached in firmware buffer which can be obtained by PXE Base Code protocol. The
-network interface can be setup through the parameters in that obtained packet.
-
-Signed-off-by: Michael Chang <mchang@suse.com>
-Signed-off-by: Ken Lin <ken.lin@hpe.com>
----
- grub-core/net/drivers/efi/efinet.c |  2 ++
- include/grub/efi/api.h             | 71 +++++++++++++++++++++++---------------
- 2 files changed, 46 insertions(+), 27 deletions(-)
-
-diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
-index 8e25680db0c..014e5bf9802 100644
---- a/grub-core/net/drivers/efi/efinet.c
-+++ b/grub-core/net/drivers/efi/efinet.c
-@@ -409,6 +409,8 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
- 	  grub_print_error ();
- 	if (device && path)
- 	  grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
-+	if (grub_errno)
-+	  grub_print_error ();
-       }
-     else
-       {
-diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
-index 7614b58dca8..91ab528e4d0 100644
---- a/include/grub/efi/api.h
-+++ b/include/grub/efi/api.h
-@@ -1524,31 +1524,6 @@ typedef union
-   grub_efi_pxe_dhcpv6_packet_t dhcpv6;
- } grub_efi_pxe_packet_t;
- 
--#define GRUB_EFI_PXE_MAX_IPCNT 8
--#define GRUB_EFI_PXE_MAX_ARP_ENTRIES 8
--#define GRUB_EFI_PXE_MAX_ROUTE_ENTRIES 8
--
--typedef struct grub_efi_pxe_ip_filter
--{
--  grub_efi_uint8_t filters;
--  grub_efi_uint8_t ip_count;
--  grub_efi_uint16_t reserved;
--  grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT];
--} grub_efi_pxe_ip_filter_t;
--
--typedef struct grub_efi_pxe_arp_entry
--{
--  grub_efi_ip_address_t ip_addr;
--  grub_efi_mac_address_t mac_addr;
--} grub_efi_pxe_arp_entry_t;
--
--typedef struct grub_efi_pxe_route_entry
--{
--  grub_efi_ip_address_t ip_addr;
--  grub_efi_ip_address_t subnet_mask;
--  grub_efi_ip_address_t gateway_addr;
--} grub_efi_pxe_route_entry_t;
--
- typedef struct grub_efi_pxe_icmp_error
- {
-   grub_efi_uint8_t type;
-@@ -1574,6 +1549,48 @@ typedef struct grub_efi_pxe_tftp_error
-   grub_efi_char8_t error_string[127];
- } grub_efi_pxe_tftp_error_t;
- 
-+typedef struct {
-+  grub_uint8_t addr[4];
-+} grub_efi_pxe_ipv4_address_t;
-+
-+typedef struct {
-+  grub_uint8_t addr[16];
-+} grub_efi_pxe_ipv6_address_t;
-+
-+typedef struct {
-+  grub_uint8_t addr[32];
-+} grub_efi_pxe_mac_address_t;
-+
-+typedef union {
-+  grub_uint32_t addr[4];
-+  grub_efi_pxe_ipv4_address_t v4;
-+  grub_efi_pxe_ipv6_address_t v6;
-+} grub_efi_pxe_ip_address_t;
-+
-+#define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8
-+typedef struct grub_efi_pxe_ip_filter
-+{
-+  grub_efi_uint8_t filters;
-+  grub_efi_uint8_t ip_count;
-+  grub_efi_uint16_t reserved;
-+  grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT];
-+} grub_efi_pxe_ip_filter_t;
-+
-+typedef struct {
-+  grub_efi_pxe_ip_address_t ip_addr;
-+  grub_efi_pxe_mac_address_t mac_addr;
-+} grub_efi_pxe_arp_entry_t;
-+
-+typedef struct {
-+  grub_efi_pxe_ip_address_t ip_addr;
-+  grub_efi_pxe_ip_address_t subnet_mask;
-+  grub_efi_pxe_ip_address_t gw_addr;
-+} grub_efi_pxe_route_entry_t;
-+
-+
-+#define GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8
-+#define GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8
-+
- typedef struct grub_efi_pxe_mode
- {
-   grub_efi_boolean_t started;
-@@ -1605,9 +1622,9 @@ typedef struct grub_efi_pxe_mode
-   grub_efi_pxe_packet_t pxe_bis_reply;
-   grub_efi_pxe_ip_filter_t ip_filter;
-   grub_efi_uint32_t arp_cache_entries;
--  grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_MAX_ARP_ENTRIES];
-+  grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES];
-   grub_efi_uint32_t route_table_entries;
--  grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_MAX_ROUTE_ENTRIES];
-+  grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES];
-   grub_efi_pxe_icmp_error_t icmp_error;
-   grub_efi_pxe_tftp_error_t tftp_error;
- } grub_efi_pxe_mode_t;
diff --git a/SOURCES/0091-Disable-non-wordsize-allocations-on-arm.patch b/SOURCES/0091-Disable-non-wordsize-allocations-on-arm.patch
new file mode 100644
index 0000000..ea09b65
--- /dev/null
+++ b/SOURCES/0091-Disable-non-wordsize-allocations-on-arm.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 2 Aug 2018 10:56:38 -0400
+Subject: [PATCH] Disable non-wordsize allocations on arm
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ configure.ac | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/configure.ac b/configure.ac
+index 008f6c273b..54462e0892 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1260,6 +1260,26 @@ if test "x$target_cpu" = xarm; then
+     done
+   ])
+ 
++  AC_CACHE_CHECK([for options to disable movt and movw relocations],
++		 grub_cv_target_cc_mword_relocations,
++		 [grub_cv_target_cc_mword_relocations=no
++		  for cand in "-mword-relocations" ; do
++		    if test x"$grub_cv_target_cc_mword_relocations" != xno ; then
++		      break
++		    fi
++		    CFLAGS="$TARGET_CFLAGS $cand -Werror"
++		    CPPFLAGS="$TARGET_CPPFLAGS"
++		    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
++				      [grub_cv_target_cc_mword_relocations="$cand"],
++				      [])
++		  done
++		 ])
++  if test x"$grub_cv_target_cc_mword_relocations" = xno ; then
++    AC_MSG_ERROR(["your compiler doesn't support disabling movw/movt relocations"])
++  else
++    TARGET_CFLAGS="$TARGET_CFLAGS $grub_cv_target_cc_mword_relocations"
++  fi
++
+   if test x"$grub_cv_target_cc_mno_movt" != xno ; then
+     # A trick so that clang doesn't see it on link stage
+     TARGET_CPPFLAGS="$TARGET_CPPFLAGS $grub_cv_target_cc_mno_movt"
diff --git a/SOURCES/0091-grub.texi-Add-net_bootp6-doument.patch b/SOURCES/0091-grub.texi-Add-net_bootp6-doument.patch
deleted file mode 100644
index 3f8ec97..0000000
--- a/SOURCES/0091-grub.texi-Add-net_bootp6-doument.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Michael Chang <mchang@suse.com>
-Date: Tue, 5 May 2015 14:19:24 +0800
-Subject: [PATCH] grub.texi: Add net_bootp6 doument
-
-Update grub documentation for net_bootp6 command.
-
-Signed-off-by: Michael Chang <mchang@suse.com>
-Signed-off-by: Ken Lin <ken.lin@hpe.com>
----
- docs/grub.texi | 17 +++++++++++++++++
- 1 file changed, 17 insertions(+)
-
-diff --git a/docs/grub.texi b/docs/grub.texi
-index 0615d0ed97e..04ed6ac1f07 100644
---- a/docs/grub.texi
-+++ b/docs/grub.texi
-@@ -5487,6 +5487,7 @@ This command is only available on AArch64 systems.
- * net_add_dns::                 Add a DNS server
- * net_add_route::               Add routing entry
- * net_bootp::                   Perform a bootp/DHCP autoconfiguration
-+* net_bootp6::                  Perform a DHCPv6 autoconfiguration
- * net_del_addr::                Remove IP address from interface
- * net_del_dns::                 Remove a DNS server
- * net_del_route::               Remove a route entry
-@@ -5611,6 +5612,22 @@ Sets environment variable @samp{net_}@var{<card>}@samp{_boot_file}
- 
- @end deffn
- 
-+@node net_bootp6
-+@subsection net_bootp6
-+
-+@deffn Command net_bootp6 [@var{card}]
-+Perform configuration of @var{card} using DHCPv6 protocol. If no card name is
-+specified, try to configure all existing cards. If configuration was
-+successful, interface with name @var{card}@samp{:dhcp6} and configured address
-+is added to @var{card}.
-+
-+@table @samp
-+@item 1 (Domain Name Server)
-+Adds all servers from option value to the list of servers used during name
-+resolution.
-+@end table
-+
-+@end deffn
- 
- @node net_get_dhcp_option
- @subsection net_get_dhcp_option
diff --git a/SOURCES/0092-Prepend-prefix-when-HTTP-path-is-relative.patch b/SOURCES/0092-Prepend-prefix-when-HTTP-path-is-relative.patch
new file mode 100644
index 0000000..30d8075
--- /dev/null
+++ b/SOURCES/0092-Prepend-prefix-when-HTTP-path-is-relative.patch
@@ -0,0 +1,152 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Stephen Benjamin <stephen@redhat.com>
+Date: Thu, 16 Aug 2018 16:58:51 -0400
+Subject: [PATCH] Prepend prefix when HTTP path is relative
+
+This sets a couple of variables.  With the url http://www.example.com/foo/bar :
+http_path: /foo/bar
+http_url: http://www.example.com/foo/bar
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+Signed-off-by: Stephen Benjamin <stephen@redhat.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/kern/main.c    | 10 +++++-
+ grub-core/net/efi/http.c | 82 ++++++++++++++++++++++++++++++++++++------------
+ 2 files changed, 71 insertions(+), 21 deletions(-)
+
+diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
+index d1de9fa687..1c540fc8c2 100644
+--- a/grub-core/kern/main.c
++++ b/grub-core/kern/main.c
+@@ -131,11 +131,19 @@ grub_set_prefix_and_root (void)
+   if (fwdevice && fwpath)
+     {
+       char *fw_path;
++      char separator[3] = ")";
+ 
+-      fw_path = grub_xasprintf ("(%s)/%s", fwdevice, fwpath);
++      grub_dprintf ("fw_path", "\n");
++      grub_dprintf ("fw_path", "fwdevice:\"%s\" fwpath:\"%s\"\n", fwdevice, fwpath);
++
++      if (!grub_strncmp(fwdevice, "http", 4) && fwpath[0] != '/')
++	grub_strcpy(separator, ")/");
++
++      fw_path = grub_xasprintf ("(%s%s%s", fwdevice, separator, fwpath);
+       if (fw_path)
+ 	{
+ 	  grub_env_set ("fw_path", fw_path);
++	  grub_dprintf ("fw_path", "fw_path:\"%s\"\n", fw_path);
+ 	  grub_free (fw_path);
+ 	}
+     }
+diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
+index 243acbaa35..de351b2cd0 100644
+--- a/grub-core/net/efi/http.c
++++ b/grub-core/net/efi/http.c
+@@ -9,10 +9,52 @@
+ static void
+ http_configure (struct grub_efi_net_device *dev, int prefer_ip6)
+ {
++  grub_efi_ipv6_address_t address;
+   grub_efi_http_config_data_t http_config;
+   grub_efi_httpv4_access_point_t httpv4_node;
+   grub_efi_httpv6_access_point_t httpv6_node;
+   grub_efi_status_t status;
++  int https;
++  char *http_url;
++  const char *rest, *http_server, *http_path = NULL;
++
++  http_server = grub_env_get ("root");
++  https = (grub_strncmp (http_server, "https", 5) == 0) ? 1 : 0;
++
++  /* extract http server + port */
++  if (http_server)
++    {
++      http_server = grub_strchr (http_server, ',');
++      if (http_server)
++	http_server++;
++    }
++
++  /* fw_path is like (http,192.168.1.1:8000)/httpboot, extract path part */
++  http_path = grub_env_get ("fw_path");
++  if (http_path)
++    {
++      http_path = grub_strchr (http_path, ')');
++      if (http_path)
++	{
++	  http_path++;
++	  grub_env_unset ("http_path");
++	  grub_env_set ("http_path", http_path);
++	}
++    }
++
++  if (http_server && http_path)
++    {
++      if (grub_efi_string_to_ip6_address (http_server, &address, &rest) && *rest == 0)
++	http_url = grub_xasprintf ("%s://[%s]%s", https ? "https" : "http", http_server, http_path);
++      else
++	http_url = grub_xasprintf ("%s://%s%s", https ? "https" : "http", http_server, http_path);
++      if (http_url)
++	{
++	  grub_env_unset ("http_url");
++	  grub_env_set ("http_url", http_url);
++	  grub_free (http_url);
++	}
++    }
+ 
+   grub_efi_http_t *http = dev->http;
+ 
+@@ -352,32 +394,32 @@ grub_efihttp_open (struct grub_efi_net_device *dev,
+   grub_err_t err;
+   grub_off_t size;
+   char *buf;
+-  char *root_url;
+-  grub_efi_ipv6_address_t address;
+-  const char *rest;
++  char *file_name = NULL;
++  const char *http_path;
+ 
+-  if (grub_efi_string_to_ip6_address (file->device->net->server, &address, &rest) && *rest == 0)
+-    root_url = grub_xasprintf ("%s://[%s]", type ? "https" : "http", file->device->net->server);
+-  else
+-    root_url = grub_xasprintf ("%s://%s", type ? "https" : "http", file->device->net->server);
+-  if (root_url)
+-    {
+-      grub_env_unset ("root_url");
+-      grub_env_set ("root_url", root_url);
+-      grub_free (root_url);
+-    }
+-  else
+-    {
++  /* If path is relative, prepend http_path */
++  http_path = grub_env_get ("http_path");
++  if (http_path && file->device->net->name[0] != '/') {
++    file_name = grub_xasprintf ("%s/%s", http_path, file->device->net->name);
++    if (!file_name)
+       return grub_errno;
+-    }
++  }
+ 
+-  err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0);
++  err = efihttp_request (dev->http, file->device->net->server,
++			 file_name ? file_name : file->device->net->name, type, 1, 0);
+   if (err != GRUB_ERR_NONE)
+-    return err;
++    {
++      grub_free (file_name);
++      return err;
++    }
+ 
+-  err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size);
++  err = efihttp_request (dev->http, file->device->net->server,
++			 file_name ? file_name : file->device->net->name, type, 0, &size);
++  grub_free (file_name);
+   if (err != GRUB_ERR_NONE)
+-    return err;
++    {
++      return err;
++    }
+ 
+   buf = grub_malloc (size);
+   efihttp_read (dev, buf, size);
diff --git a/SOURCES/0092-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch b/SOURCES/0092-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch
deleted file mode 100644
index e800dd2..0000000
--- a/SOURCES/0092-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch
+++ /dev/null
@@ -1,108 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Michael Chang <mchang@suse.com>
-Date: Wed, 10 Jul 2019 23:58:28 +0200
-Subject: [PATCH] bootp: Add processing DHCPACK packet from HTTP Boot
-
-The vendor class identifier with the string "HTTPClient" is used to denote the
-packet as responding to HTTP boot request. In DHCP4 config, the filename for
-HTTP boot is the URL of the boot file while for PXE boot it is the path to the
-boot file. As a consequence, the next-server becomes obseleted because the HTTP
-URL already contains the server address for the boot file. For DHCP6 config,
-there's no difference definition in existing config as dhcp6.bootfile-url can
-be used to specify URL for both HTTP and PXE boot file.
-
-This patch adds processing for "HTTPClient" vendor class identifier in DHCPACK
-packet by treating it as HTTP format, not as the PXE format.
-
-Signed-off-by: Michael Chang <mchang@suse.com>
-Signed-off-by: Ken Lin <ken.lin@hpe.com>
----
- grub-core/net/bootp.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++
- include/grub/net.h    |  1 +
- 2 files changed, 56 insertions(+)
-
-diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
-index fe93b80f1cf..8fb8918ae7e 100644
---- a/grub-core/net/bootp.c
-+++ b/grub-core/net/bootp.c
-@@ -20,6 +20,7 @@
- #include <grub/env.h>
- #include <grub/i18n.h>
- #include <grub/command.h>
-+#include <grub/net.h>
- #include <grub/net/ip.h>
- #include <grub/net/netbuff.h>
- #include <grub/net/udp.h>
-@@ -500,6 +501,60 @@ grub_net_configure_by_dhcp_ack (const char *name,
-   if (opt && opt_len)
-     grub_env_set_net_property (name, "rootpath", (const char *) opt, opt_len);
- 
-+  opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER, &opt_len);
-+  if (opt && opt_len)
-+    {
-+      grub_env_set_net_property (name, "vendor_class_identifier", (const char *) opt, opt_len);
-+      if (opt && grub_strcmp (opt, "HTTPClient") == 0)
-+        {
-+          char *proto, *ip, *pa;
-+
-+          if (!dissect_url (bp->boot_file, &proto, &ip, &pa))
-+            return inter;
-+
-+          grub_env_set_net_property (name, "boot_file", pa, grub_strlen (pa));
-+          if (is_def)
-+            {
-+              grub_net_default_server = grub_strdup (ip);
-+              grub_env_set ("net_default_interface", name);
-+             grub_env_export ("net_default_interface");
-+            }
-+          if (device && !*device)
-+            {
-+              *device = grub_xasprintf ("%s,%s", proto, ip);
-+              grub_print_error ();
-+            }
-+          if (path)
-+            {
-+              *path = grub_strdup (pa);
-+              grub_print_error ();
-+              if (*path)
-+                {
-+                  char *slash;
-+                  slash = grub_strrchr (*path, '/');
-+                  if (slash)
-+                    *slash = 0;
-+                  else
-+                    **path = 0;
-+                }
-+            }
-+          grub_net_add_ipv4_local (inter, mask);
-+          inter->dhcp_ack = grub_malloc (size);
-+          if (inter->dhcp_ack)
-+            {
-+              grub_memcpy (inter->dhcp_ack, bp, size);
-+              inter->dhcp_acklen = size;
-+            }
-+          else
-+            grub_errno = GRUB_ERR_NONE;
-+
-+          grub_free (proto);
-+          grub_free (ip);
-+          grub_free (pa);
-+          return inter;
-+        }
-+    }
-+
-   opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_EXTENSIONS_PATH, &opt_len);
-   if (opt && opt_len)
-     grub_env_set_net_property (name, "extensionspath", (const char *) opt, opt_len);
-diff --git a/include/grub/net.h b/include/grub/net.h
-index 543251f7273..42af7de250a 100644
---- a/include/grub/net.h
-+++ b/include/grub/net.h
-@@ -531,6 +531,7 @@ enum
-     GRUB_NET_DHCP_MESSAGE_TYPE = 53,
-     GRUB_NET_DHCP_SERVER_IDENTIFIER = 54,
-     GRUB_NET_DHCP_PARAMETER_REQUEST_LIST = 55,
-+    GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER = 60,
-     GRUB_NET_BOOTP_CLIENT_ID = 61,
-     GRUB_NET_DHCP_TFTP_SERVER_NAME = 66,
-     GRUB_NET_DHCP_BOOTFILE_NAME = 67,
diff --git a/SOURCES/0093-Make-grub_error-more-verbose.patch b/SOURCES/0093-Make-grub_error-more-verbose.patch
new file mode 100644
index 0000000..306a3d3
--- /dev/null
+++ b/SOURCES/0093-Make-grub_error-more-verbose.patch
@@ -0,0 +1,61 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 27 Aug 2018 13:14:06 -0400
+Subject: [PATCH] Make grub_error() more verbose
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/err.c | 13 +++++++++++--
+ include/grub/err.h   |  8 ++++++--
+ 2 files changed, 17 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/kern/err.c b/grub-core/kern/err.c
+index 53c734de70..aebfe0cf83 100644
+--- a/grub-core/kern/err.c
++++ b/grub-core/kern/err.c
+@@ -33,15 +33,24 @@ static struct grub_error_saved grub_error_stack_items[GRUB_ERROR_STACK_SIZE];
+ static int grub_error_stack_pos;
+ static int grub_error_stack_assert;
+ 
++#ifdef grub_error
++#undef grub_error
++#endif
++
+ grub_err_t
+-grub_error (grub_err_t n, const char *fmt, ...)
++grub_error (grub_err_t n, const char *file, const int line, const char *fmt, ...)
+ {
+   va_list ap;
++  int m;
+ 
+   grub_errno = n;
+ 
++  m = grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "%s:%d:", file, line);
++  if (m < 0)
++    m = 0;
++
+   va_start (ap, fmt);
+-  grub_vsnprintf (grub_errmsg, sizeof (grub_errmsg), _(fmt), ap);
++  grub_vsnprintf (grub_errmsg + m, sizeof (grub_errmsg) - m, _(fmt), ap);
+   va_end (ap);
+ 
+   return n;
+diff --git a/include/grub/err.h b/include/grub/err.h
+index b08d5d0de4..c0f90ef07c 100644
+--- a/include/grub/err.h
++++ b/include/grub/err.h
+@@ -85,8 +85,12 @@ struct grub_error_saved
+ extern grub_err_t EXPORT_VAR(grub_errno);
+ extern char EXPORT_VAR(grub_errmsg)[GRUB_MAX_ERRMSG];
+ 
+-grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *fmt, ...)
+-    __attribute__ ((format (GNU_PRINTF, 2, 3)));
++grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *file, const int line, const char *fmt, ...)
++	__attribute__ ((format (GNU_PRINTF, 4, 5)));
++
++#define grub_error(n, fmt, ...) grub_error (n, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
++
++
+ void EXPORT_FUNC(grub_fatal) (const char *fmt, ...) __attribute__ ((noreturn));
+ void EXPORT_FUNC(grub_error_push) (void);
+ int EXPORT_FUNC(grub_error_pop) (void);
diff --git a/SOURCES/0093-efinet-Setting-network-from-UEFI-device-path.patch b/SOURCES/0093-efinet-Setting-network-from-UEFI-device-path.patch
deleted file mode 100644
index 11b2a72..0000000
--- a/SOURCES/0093-efinet-Setting-network-from-UEFI-device-path.patch
+++ /dev/null
@@ -1,405 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Michael Chang <mchang@suse.com>
-Date: Sun, 10 Jul 2016 23:46:31 +0800
-Subject: [PATCH] efinet: Setting network from UEFI device path
-
-The PXE Base Code protocol used to obtain cached PXE DHCPACK packet is no
-longer provided for HTTP Boot. Instead, we have to get the HTTP boot
-information from the device path nodes defined in following UEFI Specification
-sections.
-
- 9.3.5.12 IPv4 Device Path
- 9.3.5.13 IPv6 Device Path
- 9.3.5.23 Uniform Resource Identifiers (URI) Device Path
-
-This patch basically does:
-
-include/grub/efi/api.h:
-Add new structure of Uniform Resource Identifiers (URI) Device Path
-
-grub-core/net/drivers/efi/efinet.c:
-Check if PXE Base Code is available, if not it will try to obtain the netboot
-information from the device path where the image booted from. The DHCPACK
-packet is recoverd from the information in device patch and feed into the same
-DHCP packet processing functions to ensure the network interface is setting up
-the same way it used to be.
-
-Signed-off-by: Michael Chang <mchang@suse.com>
-Signed-off-by: Ken Lin <ken.lin@hpe.com>
----
- grub-core/net/drivers/efi/efinet.c | 284 +++++++++++++++++++++++++++++++++++--
- include/grub/efi/api.h             |  11 ++
- 2 files changed, 280 insertions(+), 15 deletions(-)
-
-diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
-index 014e5bf9802..8171ecaa5e4 100644
---- a/grub-core/net/drivers/efi/efinet.c
-+++ b/grub-core/net/drivers/efi/efinet.c
-@@ -26,6 +26,7 @@
- #include <grub/i18n.h>
- #include <grub/lib/hexdump.h>
- #include <grub/types.h>
-+#include <grub/net/netbuff.h>
- 
- GRUB_MOD_LICENSE ("GPLv3+");
- 
-@@ -331,6 +332,227 @@ grub_efinet_findcards (void)
-   grub_free (handles);
- }
- 
-+static struct grub_net_buff *
-+grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6)
-+{
-+  grub_efi_uint16_t uri_len;
-+  grub_efi_device_path_t *ldp, *ddp;
-+  grub_efi_uri_device_path_t *uri_dp;
-+  struct grub_net_buff *nb;
-+  grub_err_t err;
-+
-+  ddp = grub_efi_duplicate_device_path (dp);
-+  if (!ddp)
-+    return NULL;
-+
-+  ldp = grub_efi_find_last_device_path (ddp);
-+
-+  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
-+      || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
-+    {
-+      grub_free (ddp);
-+      return NULL;
-+    }
-+
-+  uri_len = GRUB_EFI_DEVICE_PATH_LENGTH (ldp) > 4 ? GRUB_EFI_DEVICE_PATH_LENGTH (ldp) - 4  : 0;
-+
-+  if (!uri_len)
-+    {
-+      grub_free (ddp);
-+      return NULL;
-+    }
-+
-+  uri_dp = (grub_efi_uri_device_path_t *) ldp;
-+
-+  ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
-+  ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
-+  ldp->length = sizeof (*ldp);
-+
-+  ldp = grub_efi_find_last_device_path (ddp);
-+
-+  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
-+      || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
-+          && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
-+    {
-+      grub_free (ddp);
-+      return NULL;
-+    }
-+
-+  nb = grub_netbuff_alloc (512);
-+  if (!nb)
-+    {
-+      grub_free (ddp);
-+      return NULL;
-+    }
-+
-+  if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE)
-+    {
-+      grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp;
-+      struct grub_net_bootp_packet *bp;
-+      grub_uint8_t *ptr;
-+
-+      bp = (struct grub_net_bootp_packet *) nb->tail;
-+      err = grub_netbuff_put (nb, sizeof (*bp) + 4);
-+      if (err)
-+	{
-+	  grub_free (ddp);
-+	  grub_netbuff_free (nb);
-+	  return NULL;
-+	}
-+
-+      if (sizeof(bp->boot_file) < uri_len)
-+	{
-+	  grub_free (ddp);
-+	  grub_netbuff_free (nb);
-+	  return NULL;
-+	}
-+      grub_memcpy (bp->boot_file, uri_dp->uri, uri_len);
-+      grub_memcpy (&bp->your_ip, ipv4->local_ip_address, sizeof (bp->your_ip));
-+      grub_memcpy (&bp->server_ip, ipv4->remote_ip_address, sizeof (bp->server_ip));
-+
-+      bp->vendor[0] = GRUB_NET_BOOTP_RFC1048_MAGIC_0;
-+      bp->vendor[1] = GRUB_NET_BOOTP_RFC1048_MAGIC_1;
-+      bp->vendor[2] = GRUB_NET_BOOTP_RFC1048_MAGIC_2;
-+      bp->vendor[3] = GRUB_NET_BOOTP_RFC1048_MAGIC_3;
-+
-+      ptr = nb->tail;
-+      err = grub_netbuff_put (nb, sizeof (ipv4->subnet_mask) + 2);
-+      if (err)
-+	{
-+	  grub_free (ddp);
-+	  grub_netbuff_free (nb);
-+	  return NULL;
-+	}
-+      *ptr++ = GRUB_NET_BOOTP_NETMASK;
-+      *ptr++ = sizeof (ipv4->subnet_mask);
-+      grub_memcpy (ptr, ipv4->subnet_mask, sizeof (ipv4->subnet_mask));
-+
-+      ptr = nb->tail;
-+      err = grub_netbuff_put (nb, sizeof (ipv4->gateway_ip_address) + 2);
-+      if (err)
-+	{
-+	  grub_free (ddp);
-+	  grub_netbuff_free (nb);
-+	  return NULL;
-+	}
-+      *ptr++ = GRUB_NET_BOOTP_ROUTER;
-+      *ptr++ = sizeof (ipv4->gateway_ip_address);
-+      grub_memcpy (ptr, ipv4->gateway_ip_address, sizeof (ipv4->gateway_ip_address));
-+
-+      ptr = nb->tail;
-+      err = grub_netbuff_put (nb, sizeof ("HTTPClient") + 1);
-+      if (err)
-+	{
-+	  grub_free (ddp);
-+	  grub_netbuff_free (nb);
-+	  return NULL;
-+	}
-+      *ptr++ = GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER;
-+      *ptr++ = sizeof ("HTTPClient") - 1;
-+      grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1);
-+
-+      ptr = nb->tail;
-+      err = grub_netbuff_put (nb, 1);
-+      if (err)
-+	{
-+	  grub_free (ddp);
-+	  grub_netbuff_free (nb);
-+	  return NULL;
-+	}
-+      *ptr = GRUB_NET_BOOTP_END;
-+      *use_ipv6 = 0;
-+
-+      ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
-+      ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
-+      ldp->length = sizeof (*ldp);
-+      ldp = grub_efi_find_last_device_path (ddp);
-+
-+      if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) ==  GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)
-+	{
-+	  grub_efi_mac_address_device_path_t *mac = (grub_efi_mac_address_device_path_t *) ldp;
-+	  bp->hw_type = mac->if_type;
-+	  bp->hw_len = sizeof (bp->mac_addr);
-+	  grub_memcpy (bp->mac_addr, mac->mac_address, bp->hw_len);
-+	}
-+    }
-+  else
-+    {
-+      grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) ldp;
-+
-+      struct grub_net_dhcp6_packet *d6p;
-+      struct grub_net_dhcp6_option *opt;
-+      struct grub_net_dhcp6_option_iana *iana;
-+      struct grub_net_dhcp6_option_iaaddr *iaaddr;
-+
-+      d6p = (struct grub_net_dhcp6_packet *)nb->tail;
-+      err = grub_netbuff_put (nb, sizeof(*d6p));
-+      if (err)
-+	{
-+	  grub_free (ddp);
-+	  grub_netbuff_free (nb);
-+	  return NULL;
-+	}
-+      d6p->message_type = GRUB_NET_DHCP6_REPLY;
-+
-+      opt = (struct grub_net_dhcp6_option *)nb->tail;
-+      err = grub_netbuff_put (nb, sizeof(*opt));
-+      if (err)
-+	{
-+	  grub_free (ddp);
-+	  grub_netbuff_free (nb);
-+	  return NULL;
-+	}
-+      opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
-+      opt->len = grub_cpu_to_be16_compile_time (sizeof(*iana) + sizeof(*opt) + sizeof(*iaaddr));
-+
-+      err = grub_netbuff_put (nb, sizeof(*iana));
-+      if (err)
-+	{
-+	  grub_free (ddp);
-+	  grub_netbuff_free (nb);
-+	  return NULL;
-+	}
-+
-+      opt = (struct grub_net_dhcp6_option *)nb->tail;
-+      err = grub_netbuff_put (nb, sizeof(*opt));
-+      if (err)
-+	{
-+	  grub_free (ddp);
-+	  grub_netbuff_free (nb);
-+	  return NULL;
-+	}
-+      opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR);
-+      opt->len = grub_cpu_to_be16_compile_time (sizeof (*iaaddr));
-+
-+      iaaddr = (struct grub_net_dhcp6_option_iaaddr *)nb->tail;
-+      err = grub_netbuff_put (nb, sizeof(*iaaddr));
-+      if (err)
-+	{
-+	  grub_free (ddp);
-+	  grub_netbuff_free (nb);
-+	  return NULL;
-+	}
-+      grub_memcpy (iaaddr->addr, ipv6->local_ip_address, sizeof(ipv6->local_ip_address));
-+
-+      opt = (struct grub_net_dhcp6_option *)nb->tail;
-+      err = grub_netbuff_put (nb, sizeof(*opt) + uri_len);
-+      if (err)
-+	{
-+	  grub_free (ddp);
-+	  grub_netbuff_free (nb);
-+	  return NULL;
-+	}
-+      opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL);
-+      opt->len = grub_cpu_to_be16 (uri_len);
-+      grub_memcpy (opt->data, uri_dp->uri, uri_len);
-+
-+      *use_ipv6 = 1;
-+    }
-+
-+  grub_free (ddp);
-+  return nb;
-+}
-+
- static void
- grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
- 			  char **path)
-@@ -346,7 +568,11 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
-   {
-     grub_efi_device_path_t *cdp;
-     struct grub_efi_pxe *pxe;
--    struct grub_efi_pxe_mode *pxe_mode;
-+    struct grub_efi_pxe_mode *pxe_mode = NULL;
-+    grub_uint8_t *packet_buf;
-+    grub_size_t packet_bufsz ;
-+    int ipv6;
-+    struct grub_net_buff *nb = NULL;
- 
-     if (card->driver != &efidriver)
-       continue;
-@@ -370,11 +596,21 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
-          */
- 	if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
- 	    || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
--		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
-+		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE
-+		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
- 	  continue;
- 	dup_dp = grub_efi_duplicate_device_path (dp);
- 	if (!dup_dp)
- 	  continue;
-+
-+	if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
-+	  {
-+	    dup_ldp = grub_efi_find_last_device_path (dup_dp);
-+	    dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
-+	    dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
-+	    dup_ldp->length = sizeof (*dup_ldp);
-+	  }
-+
- 	dup_ldp = grub_efi_find_last_device_path (dup_dp);
- 	dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
- 	dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
-@@ -387,23 +623,37 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
- 
-     pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
- 				  GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
--    if (! pxe)
--      continue;
-+    if (!pxe)
-+      {
-+	nb = grub_efinet_create_dhcp_ack_from_device_path (dp, &ipv6);
-+	if (!nb)
-+	  {
-+	    grub_print_error ();
-+	    continue;
-+	  }
-+	packet_buf = nb->head;
-+	packet_bufsz = nb->tail - nb->head;
-+      }
-+    else
-+      {
-+	pxe_mode = pxe->mode;
-+	packet_buf = (grub_uint8_t *) &pxe_mode->dhcp_ack;
-+	packet_bufsz = sizeof (pxe_mode->dhcp_ack);
-+	ipv6 = pxe_mode->using_ipv6;
-+      }
- 
--    pxe_mode = pxe->mode;
--    if (pxe_mode->using_ipv6)
-+    if (ipv6)
-       {
- 	grub_dprintf ("efinet", "using ipv6 and dhcpv6\n");
--	grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n",
--		      pxe_mode->dhcp_ack_received ? "yes" : "no",
--		      pxe_mode->dhcp_ack_received ? "" : " cannot continue");
--	if (!pxe_mode->dhcp_ack_received)
--	  continue;
-+	if (pxe_mode)
-+	  grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n",
-+			pxe_mode->dhcp_ack_received ? "yes" : "no",
-+			pxe_mode->dhcp_ack_received ? "" : " cannot continue");
- 
- 	grub_net_configure_by_dhcpv6_reply (card->name, card, 0,
- 					    (struct grub_net_dhcp6_packet *)
--					    &pxe_mode->dhcp_ack,
--					    sizeof (pxe_mode->dhcp_ack),
-+					    packet_buf,
-+					    packet_bufsz,
- 					    1, device, path);
- 	if (grub_errno)
- 	  grub_print_error ();
-@@ -417,11 +667,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
- 	grub_dprintf ("efinet", "using ipv4 and dhcp\n");
- 	grub_net_configure_by_dhcp_ack (card->name, card, 0,
- 					(struct grub_net_bootp_packet *)
--					&pxe_mode->dhcp_ack,
--					sizeof (pxe_mode->dhcp_ack),
-+					packet_buf,
-+					packet_bufsz,
- 					1, device, path);
- 	grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
-       }
-+
-+    if (nb)
-+      grub_netbuff_free (nb);
-+
-     return;
-   }
- }
-diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
-index 91ab528e4d0..4a51667adb1 100644
---- a/include/grub/efi/api.h
-+++ b/include/grub/efi/api.h
-@@ -864,6 +864,8 @@ struct grub_efi_ipv4_device_path
-   grub_efi_uint16_t remote_port;
-   grub_efi_uint16_t protocol;
-   grub_efi_uint8_t static_ip_address;
-+  grub_efi_ipv4_address_t gateway_ip_address;
-+  grub_efi_ipv4_address_t subnet_mask;
- } GRUB_PACKED;
- typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t;
- 
-@@ -918,6 +920,15 @@ struct grub_efi_sata_device_path
- } GRUB_PACKED;
- typedef struct grub_efi_sata_device_path grub_efi_sata_device_path_t;
- 
-+#define GRUB_EFI_URI_DEVICE_PATH_SUBTYPE		24
-+
-+struct grub_efi_uri_device_path
-+{
-+  grub_efi_device_path_t header;
-+  grub_efi_uint8_t uri[0];
-+} GRUB_PACKED;
-+typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t;
-+
- #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE	10
- 
- /* Media Device Path.  */
diff --git a/SOURCES/0094-Make-reset-an-alias-for-the-reboot-command.patch b/SOURCES/0094-Make-reset-an-alias-for-the-reboot-command.patch
new file mode 100644
index 0000000..22475d6
--- /dev/null
+++ b/SOURCES/0094-Make-reset-an-alias-for-the-reboot-command.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 31 Aug 2018 16:42:03 -0400
+Subject: [PATCH] Make "reset" an alias for the "reboot" command.
+
+I'm really tired of half the tools I get to use having one and the other half
+having the other.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/commands/reboot.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/commands/reboot.c b/grub-core/commands/reboot.c
+index 46d364c99a..f5cc228363 100644
+--- a/grub-core/commands/reboot.c
++++ b/grub-core/commands/reboot.c
+@@ -32,15 +32,18 @@ grub_cmd_reboot (grub_command_t cmd __attribute__ ((unused)),
+   grub_reboot ();
+ }
+ 
+-static grub_command_t cmd;
++static grub_command_t reboot_cmd, reset_cmd;
+ 
+ GRUB_MOD_INIT(reboot)
+ {
+-  cmd = grub_register_command ("reboot", grub_cmd_reboot,
+-			       0, N_("Reboot the computer."));
++  reboot_cmd = grub_register_command ("reboot", grub_cmd_reboot,
++				      0, N_("Reboot the computer."));
++  reset_cmd = grub_register_command ("reset", grub_cmd_reboot,
++				     0, N_("Reboot the computer."));
+ }
+ 
+ GRUB_MOD_FINI(reboot)
+ {
+-  grub_unregister_command (cmd);
++  grub_unregister_command (reboot_cmd);
++  grub_unregister_command (reset_cmd);
+ }
diff --git a/SOURCES/0094-efinet-Setting-DNS-server-from-UEFI-protocol.patch b/SOURCES/0094-efinet-Setting-DNS-server-from-UEFI-protocol.patch
deleted file mode 100644
index 1460c8a..0000000
--- a/SOURCES/0094-efinet-Setting-DNS-server-from-UEFI-protocol.patch
+++ /dev/null
@@ -1,336 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Michael Chang <mchang@suse.com>
-Date: Thu, 14 Jul 2016 17:48:45 +0800
-Subject: [PATCH] efinet: Setting DNS server from UEFI protocol
-
-In the URI device path node, any name rahter than address can be used for
-looking up the resources so that DNS service become needed to get answer of the
-name's address. Unfortunately the DNS is not defined in any of the device path
-nodes so that we use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL
-to obtain it.
-
-These two protcols are defined the sections of UEFI specification.
-
- 27.5 EFI IPv4 Configuration II Protocol
- 27.7 EFI IPv6 Configuration Protocol
-
-include/grub/efi/api.h:
-Add new structure and protocol UUID of EFI_IP4_CONFIG2_PROTOCOL and
-EFI_IP6_CONFIG_PROTOCOL.
-
-grub-core/net/drivers/efi/efinet.c:
-Use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL to obtain the list
-of DNS server address for IPv4 and IPv6 respectively. The address of DNS
-servers is structured into DHCPACK packet and feed into the same DHCP packet
-processing functions to ensure the network interface is setting up the same way
-it used to be.
-
-Signed-off-by: Michael Chang <mchang@suse.com>
-Signed-off-by: Ken Lin <ken.lin@hpe.com>
----
- grub-core/net/drivers/efi/efinet.c | 163 +++++++++++++++++++++++++++++++++++++
- include/grub/efi/api.h             |  75 +++++++++++++++++
- 2 files changed, 238 insertions(+)
-
-diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
-index 8171ecaa5e4..715a6168d77 100644
---- a/grub-core/net/drivers/efi/efinet.c
-+++ b/grub-core/net/drivers/efi/efinet.c
-@@ -33,6 +33,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
- /* GUID.  */
- static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID;
- static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID;
-+static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID;
-+static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID;
- 
- static grub_err_t
- send_card_buffer (struct grub_net_card *dev,
-@@ -332,6 +334,125 @@ grub_efinet_findcards (void)
-   grub_free (handles);
- }
- 
-+static grub_efi_handle_t
-+grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path,
-+			    grub_efi_device_path_t **r_device_path)
-+{
-+  grub_efi_handle_t handle;
-+  grub_efi_status_t status;
-+
-+  status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path,
-+		      protocol, &device_path, &handle);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    return 0;
-+
-+  if (r_device_path)
-+    *r_device_path = device_path;
-+
-+  return handle;
-+}
-+
-+static grub_efi_ipv4_address_t *
-+grub_dns_server_ip4_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns)
-+{
-+  grub_efi_handle_t hnd;
-+  grub_efi_status_t status;
-+  grub_efi_ip4_config2_protocol_t *conf;
-+  grub_efi_ipv4_address_t *addrs;
-+  grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv4_address_t);
-+
-+  hnd = grub_efi_locate_device_path (&ip4_config_guid, dp, NULL);
-+
-+  if (!hnd)
-+    return 0;
-+
-+  conf = grub_efi_open_protocol (hnd, &ip4_config_guid,
-+				GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-+
-+  if (!conf)
-+    return 0;
-+
-+  addrs  = grub_malloc (data_size);
-+  if (!addrs)
-+    return 0;
-+
-+  status = efi_call_4 (conf->get_data, conf,
-+		      GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
-+		      &data_size, addrs);
-+
-+  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
-+    {
-+      grub_free (addrs);
-+      addrs  = grub_malloc (data_size);
-+      if (!addrs)
-+	return 0;
-+
-+      status = efi_call_4 (conf->get_data,  conf,
-+			  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
-+			  &data_size, addrs);
-+    }
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      grub_free (addrs);
-+      return 0;
-+    }
-+
-+  *num_dns = data_size / sizeof (grub_efi_ipv4_address_t);
-+  return addrs;
-+}
-+
-+static grub_efi_ipv6_address_t *
-+grub_dns_server_ip6_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns)
-+{
-+  grub_efi_handle_t hnd;
-+  grub_efi_status_t status;
-+  grub_efi_ip6_config_protocol_t *conf;
-+  grub_efi_ipv6_address_t *addrs;
-+  grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv6_address_t);
-+
-+  hnd = grub_efi_locate_device_path (&ip6_config_guid, dp, NULL);
-+
-+  if (!hnd)
-+    return 0;
-+
-+  conf = grub_efi_open_protocol (hnd, &ip6_config_guid,
-+				GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-+
-+  if (!conf)
-+    return 0;
-+
-+  addrs  = grub_malloc (data_size);
-+  if (!addrs)
-+    return 0;
-+
-+  status = efi_call_4 (conf->get_data, conf,
-+		      GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
-+		      &data_size, addrs);
-+
-+  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
-+    {
-+      grub_free (addrs);
-+      addrs  = grub_malloc (data_size);
-+      if (!addrs)
-+	return 0;
-+
-+      status = efi_call_4 (conf->get_data,  conf,
-+			  GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
-+			  &data_size, addrs);
-+    }
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      grub_free (addrs);
-+      return 0;
-+    }
-+
-+  *num_dns = data_size / sizeof (grub_efi_ipv6_address_t);
-+  return addrs;
-+}
-+
- static struct grub_net_buff *
- grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6)
- {
-@@ -390,6 +511,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
-       grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp;
-       struct grub_net_bootp_packet *bp;
-       grub_uint8_t *ptr;
-+      grub_efi_ipv4_address_t *dns;
-+      grub_efi_uintn_t num_dns;
- 
-       bp = (struct grub_net_bootp_packet *) nb->tail;
-       err = grub_netbuff_put (nb, sizeof (*bp) + 4);
-@@ -451,6 +574,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
-       *ptr++ = sizeof ("HTTPClient") - 1;
-       grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1);
- 
-+      dns = grub_dns_server_ip4_address (dp, &num_dns);
-+      if (dns)
-+	{
-+	  grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns;
-+
-+	  ptr = nb->tail;
-+	  err = grub_netbuff_put (nb, size_dns + 2);
-+	  if (err)
-+	    {
-+	      grub_free (ddp);
-+	      grub_netbuff_free (nb);
-+	      return NULL;
-+	    }
-+	  *ptr++ = GRUB_NET_BOOTP_DNS;
-+	  *ptr++ = size_dns;
-+	  grub_memcpy (ptr, dns, size_dns);
-+	  grub_free (dns);
-+	}
-+
-       ptr = nb->tail;
-       err = grub_netbuff_put (nb, 1);
-       if (err)
-@@ -483,6 +625,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
-       struct grub_net_dhcp6_option *opt;
-       struct grub_net_dhcp6_option_iana *iana;
-       struct grub_net_dhcp6_option_iaaddr *iaaddr;
-+      grub_efi_ipv6_address_t *dns;
-+      grub_efi_uintn_t num_dns;
- 
-       d6p = (struct grub_net_dhcp6_packet *)nb->tail;
-       err = grub_netbuff_put (nb, sizeof(*d6p));
-@@ -546,6 +690,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
-       opt->len = grub_cpu_to_be16 (uri_len);
-       grub_memcpy (opt->data, uri_dp->uri, uri_len);
- 
-+      dns = grub_dns_server_ip6_address (dp, &num_dns);
-+      if (dns)
-+	{
-+	  grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns;
-+
-+	  opt = (struct grub_net_dhcp6_option *)nb->tail;
-+	  err = grub_netbuff_put (nb, sizeof(*opt) + size_dns);
-+	  if (err)
-+	  {
-+	    grub_free (ddp);
-+	    grub_netbuff_free (nb);
-+	    return NULL;
-+	  }
-+	  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS);
-+	  opt->len = grub_cpu_to_be16 (size_dns);
-+	  grub_memcpy (opt->data, dns, size_dns);
-+	  grub_free (dns);
-+	}
-+
-       *use_ipv6 = 1;
-     }
- 
-diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
-index 4a51667adb1..0b490195ad9 100644
---- a/include/grub/efi/api.h
-+++ b/include/grub/efi/api.h
-@@ -352,6 +352,15 @@
- #define GRUB_EFI_RNG_PROTOCOL_GUID \
-   { 0x3152bca5, 0xeade, 0x433d, \
-     { 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \
-+
-+#define GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID \
-+  { 0x5b446ed1, 0xe30b, 0x4faa, \
-+      { 0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \
-+  }
-+
-+#define GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID \
-+  { 0x937fe521, 0x95ae, 0x4d1a, \
-+      { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \
-   }
- 
- struct grub_efi_sal_system_table
-@@ -1883,6 +1892,72 @@ struct grub_efi_rng_protocol
- };
- typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t;
- 
-+enum grub_efi_ip4_config2_data_type {
-+  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
-+  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
-+  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
-+  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY,
-+  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
-+  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MAXIMUM
-+};
-+typedef enum grub_efi_ip4_config2_data_type grub_efi_ip4_config2_data_type_t;
-+
-+struct grub_efi_ip4_config2_protocol
-+{
-+  grub_efi_status_t (*set_data) (struct grub_efi_ip4_config2_protocol *this,
-+				 grub_efi_ip4_config2_data_type_t data_type,
-+				 grub_efi_uintn_t data_size,
-+				 void *data);
-+
-+  grub_efi_status_t (*get_data) (struct grub_efi_ip4_config2_protocol *this,
-+				 grub_efi_ip4_config2_data_type_t data_type,
-+				 grub_efi_uintn_t *data_size,
-+				 void *data);
-+
-+  grub_efi_status_t (*register_data_notify) (struct grub_efi_ip4_config2_protocol *this,
-+					     grub_efi_ip4_config2_data_type_t data_type,
-+					     grub_efi_event_t event);
-+
-+  grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip4_config2_protocol *this,
-+					     grub_efi_ip4_config2_data_type_t data_type,
-+					     grub_efi_event_t event);
-+};
-+typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t;
-+
-+enum grub_efi_ip6_config_data_type {
-+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
-+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID,
-+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY,
-+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_DUP_ADDR_DETECT_TRANSMITS,
-+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
-+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY,
-+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
-+  GRUB_EFI_IP6_CONFIG_DATA_TYPE_MAXIMUM
-+};
-+typedef enum grub_efi_ip6_config_data_type grub_efi_ip6_config_data_type_t;
-+
-+struct grub_efi_ip6_config_protocol
-+{
-+  grub_efi_status_t (*set_data) (struct grub_efi_ip6_config_protocol *this,
-+				 grub_efi_ip6_config_data_type_t data_type,
-+				 grub_efi_uintn_t data_size,
-+				 void *data);
-+
-+  grub_efi_status_t (*get_data) (struct grub_efi_ip6_config_protocol *this,
-+				 grub_efi_ip6_config_data_type_t data_type,
-+				 grub_efi_uintn_t *data_size,
-+				 void *data);
-+
-+  grub_efi_status_t (*register_data_notify) (struct grub_efi_ip6_config_protocol *this,
-+					     grub_efi_ip6_config_data_type_t data_type,
-+					     grub_efi_event_t event);
-+
-+  grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip6_config_protocol *this,
-+					     grub_efi_ip6_config_data_type_t data_type,
-+					     grub_efi_event_t event);
-+};
-+typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t;
-+
- #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
-   || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \
-   || defined(__riscv)
diff --git a/SOURCES/0095-Add-a-version-command.patch b/SOURCES/0095-Add-a-version-command.patch
new file mode 100644
index 0000000..18c355c
--- /dev/null
+++ b/SOURCES/0095-Add-a-version-command.patch
@@ -0,0 +1,134 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 11 Sep 2018 14:20:37 -0400
+Subject: [PATCH] Add a "version" command
+
+This adds a command that shows you info about grub's version, the grub
+target platform, the compiler version, and if you built with
+--with-rpm-version=<string>, the rpm package version.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+[rharwood: don't say GNU, commit message cleanup]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ configure.ac                 | 13 ++++++++++
+ grub-core/Makefile.core.def  |  5 ++++
+ grub-core/commands/version.c | 56 ++++++++++++++++++++++++++++++++++++++++++++
+ config.h.in                  |  1 +
+ 4 files changed, 75 insertions(+)
+ create mode 100644 grub-core/commands/version.c
+
+diff --git a/configure.ac b/configure.ac
+index 54462e0892..7b4e1854d3 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -284,6 +284,19 @@ AC_SUBST(target_cpu)
+ AC_SUBST(platform)
+ 
+ # Define default variables
++have_with_rpm_version=n
++AC_ARG_WITH([rpm_version],
++	    AS_HELP_STRING([--with-rpm-version=VERSION],
++			   [set the rpm package version [[guessed]]]),
++	    [have_with_rpm_version=y],
++	    [have_with_rpm_version=n])
++if test x$have_with_rpm_version = xy; then
++  rpm_version="$with_rpm_version"
++else
++  rpm_version=""
++fi
++GRUB_RPM_VERSION="$rpm_version"
++AC_SUBST(GRUB_RPM_VERSION)
+ 
+ have_with_bootdir=n
+ AC_ARG_WITH([bootdir],
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 4e7d90da76..4f203533f5 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -579,6 +579,11 @@ image = {
+   enable = mips_loongson;
+ };
+ 
++module = {
++  name = version;
++  common = commands/version.c;
++};
++
+ module = {
+   name = disk;
+   common = lib/disk.c;
+diff --git a/grub-core/commands/version.c b/grub-core/commands/version.c
+new file mode 100644
+index 0000000000..de0acb07ba
+--- /dev/null
++++ b/grub-core/commands/version.c
+@@ -0,0 +1,56 @@
++/* version.c - Command to print the grub version and build info. */
++/*
++ *  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 grub_err_t
++grub_cmd_version (grub_command_t cmd UNUSED, int argc, char **args UNUSED)
++{
++  if (argc != 0)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("no arguments expected"));
++
++  grub_printf (_("GRUB version %s\n"), PACKAGE_VERSION);
++  grub_printf (_("Platform %s-%s\n"), GRUB_TARGET_CPU, GRUB_PLATFORM);
++  if (grub_strlen(GRUB_RPM_VERSION) != 0)
++    grub_printf (_("RPM package version %s\n"), GRUB_RPM_VERSION);
++  grub_printf (_("Compiler version %s\n"), __VERSION__);
++
++  return 0;
++}
++
++static grub_command_t cmd;
++
++GRUB_MOD_INIT(version)
++{
++  cmd = grub_register_command ("version", grub_cmd_version, NULL,
++			       N_("Print version and build information."));
++}
++
++GRUB_MOD_FINI(version)
++{
++  grub_unregister_command (cmd);
++}
+diff --git a/config.h.in b/config.h.in
+index 9e8f9911b1..c7e316f0f1 100644
+--- a/config.h.in
++++ b/config.h.in
+@@ -59,6 +59,7 @@
+ 
+ #define GRUB_TARGET_CPU "@GRUB_TARGET_CPU@"
+ #define GRUB_PLATFORM "@GRUB_PLATFORM@"
++#define GRUB_RPM_VERSION "@GRUB_RPM_VERSION@"
+ 
+ #define RE_ENABLE_I18N 1
+ 
diff --git a/SOURCES/0095-Support-UEFI-networking-protocols.patch b/SOURCES/0095-Support-UEFI-networking-protocols.patch
deleted file mode 100644
index fb14386..0000000
--- a/SOURCES/0095-Support-UEFI-networking-protocols.patch
+++ /dev/null
@@ -1,5053 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Michael Chang <mchang@suse.com>
-Date: Wed, 22 Feb 2017 14:27:50 +0800
-Subject: [PATCH] Support UEFI networking protocols
-
-References: fate#320130, bsc#1015589, bsc#1076132
-Patch-Mainline: no
-
-V1:
-  * Add preliminary support of UEFI networking protocols
-  * Support UEFI HTTPS Boot
-
-V2:
-  * Workaround http data access in firmware
-  * Fix DNS device path parsing for efinet device
-  * Relaxed UEFI Protocol requirement
-  * Support Intel OPA (Omni-Path Architecture) PXE Boot
-
-V3:
-  * Fix bufio in calculating address of next_buf
-  * Check HTTP respond code
-  * Use HEAD request method to test before GET
-  * Finish HTTP transaction in one go
-  * Fix bsc#1076132
-
-Signed-off-by: Michael Chang <mchang@suse.com>
-[pjones: make efi_netfs not duplicate symbols from efinet]
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/Makefile.core.def        |   12 +
- grub-core/io/bufio.c               |    2 +-
- grub-core/kern/efi/efi.c           |   96 ++-
- grub-core/net/drivers/efi/efinet.c |   27 +
- grub-core/net/efi/dhcp.c           |  397 ++++++++++
- grub-core/net/efi/efi_netfs.c      |   57 ++
- grub-core/net/efi/http.c           |  419 +++++++++++
- grub-core/net/efi/ip4_config.c     |  398 ++++++++++
- grub-core/net/efi/ip6_config.c     |  422 +++++++++++
- grub-core/net/efi/net.c            | 1428 ++++++++++++++++++++++++++++++++++++
- grub-core/net/efi/pxe.c            |  424 +++++++++++
- grub-core/net/net.c                |   74 ++
- util/grub-mknetdir.c               |   23 +-
- include/grub/efi/api.h             |  180 ++++-
- include/grub/efi/dhcp.h            |  343 +++++++++
- include/grub/efi/http.h            |  215 ++++++
- include/grub/net/efi.h             |  144 ++++
- 17 files changed, 4620 insertions(+), 41 deletions(-)
- create mode 100644 grub-core/net/efi/dhcp.c
- create mode 100644 grub-core/net/efi/efi_netfs.c
- create mode 100644 grub-core/net/efi/http.c
- create mode 100644 grub-core/net/efi/ip4_config.c
- create mode 100644 grub-core/net/efi/ip6_config.c
- create mode 100644 grub-core/net/efi/net.c
- create mode 100644 grub-core/net/efi/pxe.c
- create mode 100644 include/grub/efi/dhcp.h
- create mode 100644 include/grub/efi/http.h
- create mode 100644 include/grub/net/efi.h
-
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 4b7c45a7b06..c40170f2dd2 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -2299,6 +2299,12 @@ module = {
-   common = hook/datehook.c;
- };
- 
-+module = {
-+  name = efi_netfs;
-+  common = net/efi/efi_netfs.c;
-+  enable = efi;
-+};
-+
- module = {
-   name = net;
-   common = net/net.c;
-@@ -2312,6 +2318,12 @@ module = {
-   common = net/ethernet.c;
-   common = net/arp.c;
-   common = net/netbuff.c;
-+  efi = net/efi/net.c;
-+  efi = net/efi/http.c;
-+  efi = net/efi/pxe.c;
-+  efi = net/efi/ip4_config.c;
-+  efi = net/efi/ip6_config.c;
-+  efi = net/efi/dhcp.c;
- };
- 
- module = {
-diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c
-index a458c3aca78..1637731535e 100644
---- a/grub-core/io/bufio.c
-+++ b/grub-core/io/bufio.c
-@@ -139,7 +139,7 @@ grub_bufio_read (grub_file_t file, char *buf, grub_size_t len)
-     return res;
- 
-   /* Need to read some more.  */
--  next_buf = (file->offset + res + len - 1) & ~((grub_off_t) bufio->block_size - 1);
-+  next_buf = (grub_divmod64 (file->offset + res + len - 1, bufio->block_size, NULL)) * bufio->block_size;
-   /* Now read between file->offset + res and bufio->buffer_at.  */
-   if (file->offset + res < next_buf)
-     {
-diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
-index d6a2fb57789..2a446f5031b 100644
---- a/grub-core/kern/efi/efi.c
-+++ b/grub-core/kern/efi/efi.c
-@@ -755,7 +755,7 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
- 	      {
- 		grub_efi_ipv4_device_path_t *ipv4
- 		  = (grub_efi_ipv4_device_path_t *) dp;
--		grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x)",
-+		grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x",
- 			     (unsigned) ipv4->local_ip_address[0],
- 			     (unsigned) ipv4->local_ip_address[1],
- 			     (unsigned) ipv4->local_ip_address[2],
-@@ -768,33 +768,60 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
- 			     (unsigned) ipv4->remote_port,
- 			     (unsigned) ipv4->protocol,
- 			     (unsigned) ipv4->static_ip_address);
-+		if (len == sizeof (*ipv4))
-+		  {
-+		    grub_printf (",%u.%u.%u.%u,%u.%u.%u.%u",
-+			(unsigned) ipv4->gateway_ip_address[0],
-+			(unsigned) ipv4->gateway_ip_address[1],
-+			(unsigned) ipv4->gateway_ip_address[2],
-+			(unsigned) ipv4->gateway_ip_address[3],
-+			(unsigned) ipv4->subnet_mask[0],
-+			(unsigned) ipv4->subnet_mask[1],
-+			(unsigned) ipv4->subnet_mask[2],
-+			(unsigned) ipv4->subnet_mask[3]);
-+		  }
-+		grub_printf (")");
- 	      }
- 	      break;
- 	    case GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE:
- 	      {
- 		grub_efi_ipv6_device_path_t *ipv6
- 		  = (grub_efi_ipv6_device_path_t *) dp;
--		grub_printf ("/IPv6(%x:%x:%x:%x:%x:%x:%x:%x,%x:%x:%x:%x:%x:%x:%x:%x,%u,%u,%x,%x)",
--			     (unsigned) ipv6->local_ip_address[0],
--			     (unsigned) ipv6->local_ip_address[1],
--			     (unsigned) ipv6->local_ip_address[2],
--			     (unsigned) ipv6->local_ip_address[3],
--			     (unsigned) ipv6->local_ip_address[4],
--			     (unsigned) ipv6->local_ip_address[5],
--			     (unsigned) ipv6->local_ip_address[6],
--			     (unsigned) ipv6->local_ip_address[7],
--			     (unsigned) ipv6->remote_ip_address[0],
--			     (unsigned) ipv6->remote_ip_address[1],
--			     (unsigned) ipv6->remote_ip_address[2],
--			     (unsigned) ipv6->remote_ip_address[3],
--			     (unsigned) ipv6->remote_ip_address[4],
--			     (unsigned) ipv6->remote_ip_address[5],
--			     (unsigned) ipv6->remote_ip_address[6],
--			     (unsigned) ipv6->remote_ip_address[7],
-+		grub_printf ("/IPv6(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%u,%u,%x,%x",
-+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[0]),
-+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[1]),
-+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[2]),
-+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[3]),
-+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[4]),
-+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[5]),
-+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[6]),
-+			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[7]),
-+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[0]),
-+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[1]),
-+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[2]),
-+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[3]),
-+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[4]),
-+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[5]),
-+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[6]),
-+			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[7]),
- 			     (unsigned) ipv6->local_port,
- 			     (unsigned) ipv6->remote_port,
- 			     (unsigned) ipv6->protocol,
- 			     (unsigned) ipv6->static_ip_address);
-+		if (len == sizeof (*ipv6))
-+		  {
-+		    grub_printf (",%u,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
-+			(unsigned) ipv6->prefix_length,
-+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[0]),
-+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[1]),
-+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[2]),
-+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[3]),
-+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[4]),
-+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[5]),
-+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[6]),
-+			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[7]));
-+		  }
-+		grub_printf (")");
- 	      }
- 	      break;
- 	    case GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE:
-@@ -834,6 +861,39 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
- 	      dump_vendor_path ("Messaging",
- 				(grub_efi_vendor_device_path_t *) dp);
- 	      break;
-+	    case GRUB_EFI_URI_DEVICE_PATH_SUBTYPE:
-+	      {
-+		grub_efi_uri_device_path_t *uri
-+		  = (grub_efi_uri_device_path_t *) dp;
-+		grub_printf ("/URI(%s)", uri->uri);
-+	      }
-+	      break;
-+	    case GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE:
-+	      {
-+		grub_efi_dns_device_path_t *dns
-+		  = (grub_efi_dns_device_path_t *) dp;
-+		if (dns->is_ipv6)
-+		  {
-+		    grub_printf ("/DNS(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x)",
-+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0]) >> 16),
-+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0])),
-+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1]) >> 16),
-+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1])),
-+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2]) >> 16),
-+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2])),
-+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]) >> 16),
-+			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3])));
-+		  }
-+		else
-+		  {
-+		    grub_printf ("/DNS(%d.%d.%d.%d)",
-+			  dns->dns_server_ip[0].v4.addr[0],
-+			  dns->dns_server_ip[0].v4.addr[1],
-+			  dns->dns_server_ip[0].v4.addr[2],
-+			  dns->dns_server_ip[0].v4.addr[3]);
-+		  }
-+	      }
-+	      break;
- 	    default:
- 	      grub_printf ("/UnknownMessaging(%x)", (unsigned) subtype);
- 	      break;
-diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
-index 715a6168d77..e11d759f19a 100644
---- a/grub-core/net/drivers/efi/efinet.c
-+++ b/grub-core/net/drivers/efi/efinet.c
-@@ -27,6 +27,7 @@
- #include <grub/lib/hexdump.h>
- #include <grub/types.h>
- #include <grub/net/netbuff.h>
-+#include <grub/env.h>
- 
- GRUB_MOD_LICENSE ("GPLv3+");
- 
-@@ -491,6 +492,17 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
- 
-   ldp = grub_efi_find_last_device_path (ddp);
- 
-+  /* Skip the DNS Device */
-+  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
-+      && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE)
-+    {
-+      ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
-+      ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
-+      ldp->length = sizeof (*ldp);
-+
-+      ldp = grub_efi_find_last_device_path (ddp);
-+    }
-+
-   if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
-       || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
-           && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
-@@ -760,6 +772,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
- 	if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
- 	    || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
- 		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE
-+		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE
- 		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
- 	  continue;
- 	dup_dp = grub_efi_duplicate_device_path (dp);
-@@ -774,6 +787,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
- 	    dup_ldp->length = sizeof (*dup_ldp);
- 	  }
- 
-+	dup_ldp = grub_efi_find_last_device_path (dup_dp);
-+	if (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE)
-+	  {
-+	    dup_ldp = grub_efi_find_last_device_path (dup_dp);
-+	    dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
-+	    dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
-+	    dup_ldp->length = sizeof (*dup_ldp);
-+	  }
-+
- 	dup_ldp = grub_efi_find_last_device_path (dup_dp);
- 	dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
- 	dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
-@@ -845,6 +867,9 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
- 
- GRUB_MOD_INIT(efinet)
- {
-+  if (grub_efi_net_config)
-+    return;
-+
-   grub_efinet_findcards ();
-   grub_efi_net_config = grub_efi_net_config_real;
- }
-@@ -856,5 +881,7 @@ GRUB_MOD_FINI(efinet)
-   FOR_NET_CARDS_SAFE (card, next) 
-     if (card->driver == &efidriver)
-       grub_net_card_unregister (card);
-+
-+  grub_efi_net_config = NULL;
- }
- 
-diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c
-new file mode 100644
-index 00000000000..dbef63d8c08
---- /dev/null
-+++ b/grub-core/net/efi/dhcp.c
-@@ -0,0 +1,397 @@
-+#include <grub/mm.h>
-+#include <grub/command.h>
-+#include <grub/efi/api.h>
-+#include <grub/efi/efi.h>
-+#include <grub/misc.h>
-+#include <grub/net/efi.h>
-+#include <grub/charset.h>
-+
-+#ifdef GRUB_EFI_NET_DEBUG
-+static void
-+dhcp4_mode_print (grub_efi_dhcp4_mode_data_t *mode)
-+{
-+    switch (mode->state)
-+      {
-+	case GRUB_EFI_DHCP4_STOPPED:
-+	  grub_printf ("STATE: STOPPED\n");
-+	  break;
-+	case GRUB_EFI_DHCP4_INIT:
-+	  grub_printf ("STATE: INIT\n");
-+	  break;
-+	case GRUB_EFI_DHCP4_SELECTING:
-+	  grub_printf ("STATE: SELECTING\n");
-+	  break;
-+	case GRUB_EFI_DHCP4_REQUESTING:
-+	  grub_printf ("STATE: REQUESTING\n");
-+	  break;
-+	case GRUB_EFI_DHCP4_BOUND:
-+	  grub_printf ("STATE: BOUND\n");
-+	  break;
-+	case GRUB_EFI_DHCP4_RENEWING:
-+	  grub_printf ("STATE: RENEWING\n");
-+	  break;
-+	case GRUB_EFI_DHCP4_REBINDING:
-+	  grub_printf ("STATE: REBINDING\n");
-+	  break;
-+	case GRUB_EFI_DHCP4_INIT_REBOOT:
-+	  grub_printf ("STATE: INIT_REBOOT\n");
-+	  break;
-+	case GRUB_EFI_DHCP4_REBOOTING:
-+	  grub_printf ("STATE: REBOOTING\n");
-+	  break;
-+	default:
-+	  grub_printf ("STATE: UNKNOWN\n");
-+	  break;
-+      }
-+
-+    grub_printf ("CLIENT_ADDRESS: %u.%u.%u.%u\n",
-+      mode->client_address[0],
-+      mode->client_address[1],
-+      mode->client_address[2],
-+      mode->client_address[3]);
-+    grub_printf ("SERVER_ADDRESS: %u.%u.%u.%u\n",
-+      mode->server_address[0],
-+      mode->server_address[1],
-+      mode->server_address[2],
-+      mode->server_address[3]);
-+    grub_printf ("SUBNET_MASK: %u.%u.%u.%u\n",
-+      mode->subnet_mask[0],
-+      mode->subnet_mask[1],
-+      mode->subnet_mask[2],
-+      mode->subnet_mask[3]);
-+    grub_printf ("ROUTER_ADDRESS: %u.%u.%u.%u\n",
-+      mode->router_address[0],
-+      mode->router_address[1],
-+      mode->router_address[2],
-+      mode->router_address[3]);
-+}
-+#endif
-+
-+static grub_efi_ipv4_address_t *
-+grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packet_t *reply_packet)
-+{
-+  grub_efi_dhcp4_packet_option_t **option_list;
-+  grub_efi_status_t status;
-+  grub_efi_uint32_t option_count = 0;
-+  grub_efi_uint32_t i;
-+
-+  status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, NULL);
-+
-+  if (status != GRUB_EFI_BUFFER_TOO_SMALL)
-+    return NULL;
-+
-+  option_list = grub_malloc (option_count * sizeof(*option_list));
-+  if (!option_list)
-+    return NULL;
-+
-+  status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, option_list);
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      grub_free (option_list);
-+      return NULL;
-+    }
-+
-+  for (i = 0; i < option_count; ++i)
-+    {
-+      if (option_list[i]->op_code == 6)
-+	{
-+	  grub_efi_ipv4_address_t *dns_address;
-+
-+	  if (((option_list[i]->length & 0x3) != 0) || (option_list[i]->length == 0))
-+	    continue;
-+
-+	  /* We only contact primary dns */
-+	  dns_address = grub_malloc (sizeof (*dns_address));
-+	  if (!dns_address)
-+	    {
-+	      grub_free (option_list);
-+	      return NULL;
-+	    }
-+	  grub_memcpy (dns_address, option_list[i]->data, sizeof (dns_address));
-+	  grub_free (option_list);
-+	  return dns_address;
-+	}
-+    }
-+
-+  grub_free (option_list);
-+  return NULL;
-+}
-+
-+#if 0
-+/* Somehow this doesn't work ... */
-+static grub_err_t
-+grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)),
-+		    int argc __attribute__ ((unused)),
-+		    char **args __attribute__ ((unused)))
-+{
-+  struct grub_efi_net_device *dev;
-+  for (dev = net_devices; dev; dev = dev->next)
-+    {
-+      grub_efi_pxe_t *pxe = dev->ip4_pxe;
-+      grub_efi_pxe_mode_t *mode = pxe->mode;
-+      grub_efi_status_t status;
-+
-+      if (!mode->started)
-+	{
-+	  status = efi_call_2 (pxe->start, pxe, 0);
-+
-+	  if (status != GRUB_EFI_SUCCESS)
-+	      grub_printf ("Couldn't start PXE\n");
-+	}
-+
-+      status = efi_call_2 (pxe->dhcp, pxe, 0);
-+      if (status != GRUB_EFI_SUCCESS)
-+	{
-+	  grub_printf ("dhcp4 configure failed, %d\n", (int)status);
-+	  continue;
-+	}
-+
-+      dev->prefer_ip6 = 0;
-+    }
-+
-+  return GRUB_ERR_NONE;
-+}
-+#endif
-+
-+static grub_err_t
-+grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)),
-+		    int argc,
-+		    char **args)
-+{
-+  struct grub_efi_net_device *netdev;
-+
-+  for (netdev = net_devices; netdev; netdev = netdev->next)
-+    {
-+      grub_efi_status_t status;
-+      grub_efi_dhcp4_mode_data_t mode;
-+      grub_efi_dhcp4_config_data_t config;
-+      grub_efi_dhcp4_packet_option_t *options;
-+      grub_efi_ipv4_address_t *dns_address;
-+      grub_efi_net_ip_manual_address_t net_ip;
-+      grub_efi_net_ip_address_t ip_addr;
-+      grub_efi_net_interface_t *inf = NULL;
-+
-+      if (argc > 0 && grub_strcmp (netdev->card_name, args[0]) != 0)
-+	continue;
-+
-+      grub_memset (&config, 0, sizeof(config));
-+
-+      config.option_count = 1;
-+      options = grub_malloc (sizeof(*options) + 2);
-+      /* Parameter request list */
-+      options->op_code = 55;
-+      options->length = 3;
-+      /* subnet mask */
-+      options->data[0] = 1;
-+      /* router */
-+      options->data[1] = 3;
-+      /* DNS */
-+      options->data[2] = 6;
-+      config.option_list = &options;
-+
-+      /* FIXME: What if the dhcp has bounded */
-+      status = efi_call_2 (netdev->dhcp4->configure, netdev->dhcp4, &config);
-+      grub_free (options);
-+      if (status != GRUB_EFI_SUCCESS)
-+	{
-+	  grub_printf ("dhcp4 configure failed, %d\n", (int)status);
-+	  continue;
-+	}
-+
-+      status = efi_call_2 (netdev->dhcp4->start, netdev->dhcp4, NULL);
-+      if (status != GRUB_EFI_SUCCESS)
-+	{
-+	  grub_printf ("dhcp4 start failed, %d\n", (int)status);
-+	  continue;
-+	}
-+
-+      status = efi_call_2 (netdev->dhcp4->get_mode_data, netdev->dhcp4, &mode);
-+      if (status != GRUB_EFI_SUCCESS)
-+	{
-+	  grub_printf ("dhcp4 get mode failed, %d\n", (int)status);
-+	  continue;
-+	}
-+
-+#ifdef GRUB_EFI_NET_DEBUG
-+      dhcp4_mode_print (&mode);
-+#endif
-+
-+      for (inf = netdev->net_interfaces; inf; inf = inf->next)
-+	if (inf->prefer_ip6 == 0)
-+	  break;
-+
-+      grub_memcpy (net_ip.ip4.address, mode.client_address, sizeof (net_ip.ip4.address));
-+      grub_memcpy (net_ip.ip4.subnet_mask, mode.subnet_mask, sizeof (net_ip.ip4.subnet_mask));
-+
-+      if (!inf)
-+	{
-+	  char *name = grub_xasprintf ("%s:dhcp", netdev->card_name);
-+
-+	  net_ip.is_ip6 = 0;
-+	  inf = grub_efi_net_create_interface (netdev,
-+		    name,
-+		    &net_ip,
-+		    1);
-+	  grub_free (name);
-+	}
-+      else
-+	{
-+	  efi_net_interface_set_address (inf, &net_ip, 1);
-+	}
-+
-+      grub_memcpy (ip_addr.ip4, mode.router_address, sizeof (ip_addr.ip4));
-+      efi_net_interface_set_gateway (inf, &ip_addr);
-+
-+      dns_address = grub_efi_dhcp4_parse_dns (netdev->dhcp4, mode.reply_packet);
-+      if (dns_address)
-+	efi_net_interface_set_dns (inf, (grub_efi_net_ip_address_t *)&dns_address);
-+
-+    }
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+
-+static grub_err_t
-+grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)),
-+		    int argc,
-+		    char **args)
-+{
-+  struct grub_efi_net_device *dev;
-+  grub_efi_uint32_t ia_id;
-+
-+  for (dev = net_devices, ia_id = 0; dev; dev = dev->next, ia_id++)
-+    {
-+      grub_efi_dhcp6_config_data_t config;
-+      grub_efi_dhcp6_packet_option_t *option_list[1];
-+      grub_efi_dhcp6_packet_option_t *opt;
-+      grub_efi_status_t status;
-+      grub_efi_dhcp6_mode_data_t mode;
-+      grub_efi_dhcp6_retransmission_t retrans;
-+      grub_efi_net_ip_manual_address_t net_ip;
-+      grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
-+      grub_efi_net_interface_t *inf = NULL;
-+
-+      if (argc > 0 && grub_strcmp (dev->card_name, args[0]) != 0)
-+	continue;
-+
-+      opt = grub_malloc (sizeof(*opt) + 2 * sizeof (grub_efi_uint16_t));
-+
-+#define GRUB_EFI_DHCP6_OPT_ORO 6
-+
-+      opt->op_code = grub_cpu_to_be16_compile_time (GRUB_EFI_DHCP6_OPT_ORO);
-+      opt->op_len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_efi_uint16_t));
-+
-+#define GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL 59
-+#define GRUB_EFI_DHCP6_OPT_DNS_SERVERS 23
-+
-+      grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL));
-+      grub_set_unaligned16 (opt->data + 1 * sizeof (grub_efi_uint16_t),
-+	      grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS));
-+
-+      option_list[0] = opt;
-+      retrans.irt = 4;
-+      retrans.mrc = 4;
-+      retrans.mrt = 32;
-+      retrans.mrd = 60;
-+
-+      config.dhcp6_callback = NULL;
-+      config.callback_context = NULL;
-+      config.option_count = 1;
-+      config.option_list = option_list;
-+      config.ia_descriptor.ia_id = ia_id;
-+      config.ia_descriptor.type = GRUB_EFI_DHCP6_IA_TYPE_NA;
-+      config.ia_info_event = NULL;
-+      config.reconfigure_accept = 0;
-+      config.rapid_commit = 0;
-+      config.solicit_retransmission = &retrans;
-+
-+      status = efi_call_2 (dev->dhcp6->configure, dev->dhcp6, &config);
-+      grub_free (opt);
-+      if (status != GRUB_EFI_SUCCESS)
-+	{
-+	  grub_printf ("dhcp6 configure failed, %d\n", (int)status);
-+	  continue;
-+	}
-+      status = efi_call_1 (dev->dhcp6->start, dev->dhcp6);
-+      if (status != GRUB_EFI_SUCCESS)
-+	{
-+	  grub_printf ("dhcp6 start failed, %d\n", (int)status);
-+	  continue;
-+	}
-+
-+      status = efi_call_3 (dev->dhcp6->get_mode_data, dev->dhcp6, &mode, NULL);
-+      if (status != GRUB_EFI_SUCCESS)
-+	{
-+	  grub_printf ("dhcp4 get mode failed, %d\n", (int)status);
-+	  continue;
-+	}
-+
-+      for (inf = dev->net_interfaces; inf; inf = inf->next)
-+	if (inf->prefer_ip6 == 1)
-+	  break;
-+
-+      grub_memcpy (net_ip.ip6.address, mode.ia->ia_address[0].ip_address, sizeof (net_ip.ip6.address));
-+      net_ip.ip6.prefix_length = 64;
-+      net_ip.ip6.is_anycast = 0;
-+      net_ip.is_ip6 = 1;
-+
-+      if (!inf)
-+	{
-+	  char *name = grub_xasprintf ("%s:dhcp", dev->card_name);
-+
-+	  inf = grub_efi_net_create_interface (dev,
-+		    name,
-+		    &net_ip,
-+		    1);
-+	  grub_free (name);
-+	}
-+      else
-+	{
-+	  efi_net_interface_set_address (inf, &net_ip, 1);
-+	}
-+
-+      {
-+	grub_efi_uint32_t count = 0;
-+	grub_efi_dhcp6_packet_option_t **options = NULL;
-+	grub_efi_uint32_t i;
-+
-+	status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, NULL);
-+
-+	if (status == GRUB_EFI_BUFFER_TOO_SMALL && count)
-+	  {
-+	    options = grub_malloc (count * sizeof(*options));
-+	    status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options);
-+	  }
-+
-+	if (status != GRUB_EFI_SUCCESS)
-+	  {
-+	    if (options)
-+	      grub_free (options);
-+	    continue;
-+	  }
-+
-+	for (i = 0; i < count; ++i)
-+	  {
-+	    if (options[i]->op_code == grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS))
-+	      {
-+		grub_efi_net_ip_address_t dns;
-+		grub_memcpy (dns.ip6, options[i]->data, sizeof(net_ip.ip6));
-+		efi_net_interface_set_dns (inf, &dns);
-+		break;
-+	      }
-+	  }
-+
-+	if (options)
-+	  grub_free (options);
-+      }
-+
-+      efi_call_1 (b->free_pool, mode.client_id);
-+      efi_call_1 (b->free_pool, mode.ia);
-+    }
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+grub_command_func_t grub_efi_net_bootp = grub_cmd_efi_bootp;
-+grub_command_func_t grub_efi_net_bootp6 = grub_cmd_efi_bootp6;
-diff --git a/grub-core/net/efi/efi_netfs.c b/grub-core/net/efi/efi_netfs.c
-new file mode 100644
-index 00000000000..ef371d885ea
---- /dev/null
-+++ b/grub-core/net/efi/efi_netfs.c
-@@ -0,0 +1,57 @@
-+#include <grub/dl.h>
-+#include <grub/env.h>
-+#define EFI_NET_CMD_PREFIX "net_efi"
-+#include <grub/net/efi.h>
-+
-+GRUB_MOD_LICENSE ("GPLv3+");
-+
-+static grub_command_t cmd_efi_lsroutes;
-+static grub_command_t cmd_efi_lscards;
-+static grub_command_t cmd_efi_lsaddrs;
-+static grub_command_t cmd_efi_addaddr;
-+static grub_command_t cmd_efi_bootp;
-+static grub_command_t cmd_efi_bootp6;
-+
-+static int initialized;
-+
-+GRUB_MOD_INIT(efi_netfs)
-+{
-+  if (grub_net_open)
-+    return;
-+
-+  if (grub_efi_net_fs_init ())
-+    {
-+      cmd_efi_lsroutes = grub_register_command ("net_efi_ls_routes", grub_efi_net_list_routes,
-+					    "", N_("list network routes"));
-+      cmd_efi_lscards = grub_register_command ("net_efi_ls_cards", grub_efi_net_list_cards,
-+					   "", N_("list network cards"));
-+      cmd_efi_lsaddrs = grub_register_command ("net_efi_ls_addr", grub_efi_net_list_addrs,
-+					  "", N_("list network addresses"));
-+      cmd_efi_addaddr = grub_register_command ("net_efi_add_addr", grub_efi_net_add_addr,
-+					  N_("SHORTNAME CARD ADDRESS [HWADDRESS]"),
-+					  N_("Add a network address."));
-+      cmd_efi_bootp = grub_register_command ("net_efi_bootp", grub_efi_net_bootp,
-+					 N_("[CARD]"),
-+					 N_("perform a bootp autoconfiguration"));
-+      cmd_efi_bootp6 = grub_register_command ("net_efi_bootp6", grub_efi_net_bootp6,
-+					 N_("[CARD]"),
-+					 N_("perform a bootp autoconfiguration"));
-+      initialized = 1;
-+    }
-+}
-+
-+GRUB_MOD_FINI(efi_netfs)
-+{
-+  if (initialized)
-+    {
-+      grub_unregister_command (cmd_efi_lsroutes);
-+      grub_unregister_command (cmd_efi_lscards);
-+      grub_unregister_command (cmd_efi_lsaddrs);
-+      grub_unregister_command (cmd_efi_addaddr);
-+      grub_unregister_command (cmd_efi_bootp);
-+      grub_unregister_command (cmd_efi_bootp6);
-+      grub_efi_net_fs_fini ();
-+      initialized = 0;
-+      return;
-+    }
-+}
-diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
-new file mode 100644
-index 00000000000..3f61fd2fa5b
---- /dev/null
-+++ b/grub-core/net/efi/http.c
-@@ -0,0 +1,419 @@
-+
-+#include <grub/efi/api.h>
-+#include <grub/efi/efi.h>
-+#include <grub/misc.h>
-+#include <grub/net/efi.h>
-+#include <grub/charset.h>
-+
-+static void
-+http_configure (struct grub_efi_net_device *dev, int prefer_ip6)
-+{
-+  grub_efi_http_config_data_t http_config;
-+  grub_efi_httpv4_access_point_t httpv4_node;
-+  grub_efi_httpv6_access_point_t httpv6_node;
-+  grub_efi_status_t status;
-+
-+  grub_efi_http_t *http = dev->http;
-+
-+  grub_memset (&http_config, 0, sizeof(http_config));
-+  http_config.http_version = GRUB_EFI_HTTPVERSION11;
-+  http_config.timeout_millisec = 5000;
-+
-+  if (prefer_ip6)
-+    {
-+      grub_efi_uintn_t sz;
-+      grub_efi_ip6_config_manual_address_t manual_address;
-+
-+      http_config.local_address_is_ipv6 = 1;
-+      sz = sizeof (manual_address);
-+      status = efi_call_4 (dev->ip6_config->get_data, dev->ip6_config,
-+			GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
-+			&sz, &manual_address);
-+
-+      if (status == GRUB_EFI_NOT_FOUND)
-+	{
-+	  grub_printf ("The MANUAL ADDRESS is not found\n");
-+	}
-+
-+      /* FIXME: The manual interface would return BUFFER TOO SMALL !!! */
-+      if (status != GRUB_EFI_SUCCESS)
-+	{
-+	  grub_printf ("??? %d\n",(int) status);
-+	  return;
-+	}
-+
-+      grub_memcpy (httpv6_node.local_address, manual_address.address, sizeof (httpv6_node.local_address));
-+      httpv6_node.local_port = 0;
-+      http_config.access_point.ipv6_node = &httpv6_node;
-+    }
-+  else
-+    {
-+      http_config.local_address_is_ipv6 = 0;
-+      grub_memset (&httpv4_node, 0, sizeof(httpv4_node));
-+      httpv4_node.use_default_address = 1;
-+
-+      /* Use random port here */
-+      /* See TcpBind() in edk2/NetworkPkg/TcpDxe/TcpDispatcher.c */
-+      httpv4_node.local_port = 0;
-+      http_config.access_point.ipv4_node = &httpv4_node;
-+    }
-+
-+  status = efi_call_2 (http->configure, http, &http_config);
-+
-+  if (status == GRUB_EFI_ALREADY_STARTED)
-+    {
-+      /* XXX: This hangs HTTPS boot */
-+#if 0
-+      if (efi_call_2 (http->configure, http, NULL) != GRUB_EFI_SUCCESS)
-+	{
-+	  grub_error (GRUB_ERR_IO, N_("couldn't reset http instance"));
-+	  grub_print_error ();
-+	  return;
-+	}
-+      status = efi_call_2 (http->configure, http, &http_config);
-+#endif
-+      return;
-+    }
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      grub_error (GRUB_ERR_IO, N_("couldn't configure http protocol, reason: %d"), (int)status);
-+      grub_print_error ();
-+      return ;
-+    }
-+}
-+
-+static grub_efi_boolean_t request_callback_done;
-+static grub_efi_boolean_t response_callback_done;
-+
-+static void
-+grub_efi_http_request_callback (grub_efi_event_t event __attribute__ ((unused)),
-+				void *context __attribute__ ((unused)))
-+{
-+  request_callback_done = 1;
-+}
-+
-+static void
-+grub_efi_http_response_callback (grub_efi_event_t event __attribute__ ((unused)),
-+				void *context __attribute__ ((unused)))
-+{
-+  response_callback_done = 1;
-+}
-+
-+static grub_err_t
-+efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, int headeronly, grub_off_t *file_size)
-+{
-+  grub_efi_http_request_data_t request_data;
-+  grub_efi_http_message_t request_message;
-+  grub_efi_http_token_t request_token;
-+  grub_efi_http_response_data_t response_data;
-+  grub_efi_http_message_t response_message;
-+  grub_efi_http_token_t response_token;
-+  grub_efi_http_header_t request_headers[3];
-+
-+  grub_efi_status_t status;
-+  grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
-+  char *url = NULL;
-+
-+  request_headers[0].field_name = (grub_efi_char8_t *)"Host";
-+  request_headers[0].field_value = (grub_efi_char8_t *)server;
-+  request_headers[1].field_name = (grub_efi_char8_t *)"Accept";
-+  request_headers[1].field_value = (grub_efi_char8_t *)"*/*";
-+  request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent";
-+  request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0";
-+
-+  {
-+    grub_efi_ipv6_address_t address;
-+    const char *rest;
-+    grub_efi_char16_t *ucs2_url;
-+    grub_size_t url_len, ucs2_url_len;
-+    const char *protocol = (use_https == 1) ? "https" : "http";
-+
-+    if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0)
-+      url = grub_xasprintf ("%s://[%s]%s", protocol, server, name);
-+    else
-+      url = grub_xasprintf ("%s://%s%s", protocol, server, name);
-+
-+    if (!url)
-+      {
-+	return grub_errno;
-+      }
-+
-+    url_len = grub_strlen (url);
-+    ucs2_url_len = url_len * GRUB_MAX_UTF16_PER_UTF8;
-+    ucs2_url = grub_malloc ((ucs2_url_len + 1) * sizeof (ucs2_url[0]));
-+
-+    if (!ucs2_url)
-+      {
-+	grub_free (url);
-+	return grub_errno;
-+      }
-+
-+    ucs2_url_len = grub_utf8_to_utf16 (ucs2_url, ucs2_url_len, (grub_uint8_t *)url, url_len, NULL); /* convert string format from ascii to usc2 */
-+    ucs2_url[ucs2_url_len] = 0;
-+    grub_free (url);
-+    request_data.url = ucs2_url;
-+  }
-+
-+  request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET;
-+
-+  request_message.data.request = &request_data;
-+  request_message.header_count = 3;
-+  request_message.headers = request_headers;
-+  request_message.body_length = 0;
-+  request_message.body = NULL;
-+
-+  /* request token */
-+  request_token.event = NULL;
-+  request_token.status = GRUB_EFI_NOT_READY;
-+  request_token.message = &request_message;
-+
-+  request_callback_done = 0;
-+  status = efi_call_5 (b->create_event,
-+                       GRUB_EFI_EVT_NOTIFY_SIGNAL,
-+                       GRUB_EFI_TPL_CALLBACK,
-+                       grub_efi_http_request_callback,
-+                       NULL,
-+                       &request_token.event);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      grub_free (request_data.url);
-+      return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status);
-+    }
-+
-+  status = efi_call_2 (http->request, http, &request_token);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      efi_call_1 (b->close_event, request_token.event);
-+      grub_free (request_data.url);
-+      return grub_error (GRUB_ERR_IO, "Fail to send a request! status=0x%x\n", status);
-+    }
-+  /* TODO: Add Timeout */
-+  while (!request_callback_done)
-+    efi_call_1(http->poll, http);
-+
-+  response_data.status_code = GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS;
-+  response_message.data.response = &response_data;
-+  /* herader_count will be updated by the HTTP driver on response */
-+  response_message.header_count = 0;
-+  /* headers will be populated by the driver on response */
-+  response_message.headers = NULL;
-+  /* use zero BodyLength to only receive the response headers */
-+  response_message.body_length = 0;
-+  response_message.body = NULL;
-+  response_token.event = NULL;
-+
-+  status = efi_call_5 (b->create_event,
-+              GRUB_EFI_EVT_NOTIFY_SIGNAL,
-+              GRUB_EFI_TPL_CALLBACK,
-+              grub_efi_http_response_callback,
-+              NULL,
-+              &response_token.event);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      efi_call_1 (b->close_event, request_token.event);
-+      grub_free (request_data.url);
-+      return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status);
-+    }
-+
-+  response_token.status = GRUB_EFI_SUCCESS;
-+  response_token.message = &response_message;
-+
-+  /* wait for HTTP response */
-+  response_callback_done = 0;
-+  status = efi_call_2 (http->response, http, &response_token);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      efi_call_1 (b->close_event, response_token.event);
-+      efi_call_1 (b->close_event, request_token.event);
-+      grub_free (request_data.url);
-+      return grub_error (GRUB_ERR_IO, "Fail to receive a response! status=%d\n", (int)status);
-+    }
-+
-+  /* TODO: Add Timeout */
-+  while (!response_callback_done)
-+    efi_call_1 (http->poll, http);
-+
-+  if (response_message.data.response->status_code != GRUB_EFI_HTTP_STATUS_200_OK)
-+    {
-+      grub_efi_http_status_code_t status_code = response_message.data.response->status_code;
-+
-+      if (response_message.headers)
-+	efi_call_1 (b->free_pool, response_message.headers);
-+      efi_call_1 (b->close_event, response_token.event);
-+      efi_call_1 (b->close_event, request_token.event);
-+      grub_free (request_data.url);
-+      if (status_code == GRUB_EFI_HTTP_STATUS_404_NOT_FOUND)
-+	{
-+	  return grub_error (GRUB_ERR_FILE_NOT_FOUND, _("file `%s' not found"), name);
-+	}
-+      else
-+	{
-+	  return grub_error (GRUB_ERR_NET_UNKNOWN_ERROR,
-+		  _("unsupported uefi http status code 0x%x"), status_code);
-+	}
-+    }
-+
-+  if (file_size)
-+    {
-+      int i;
-+      /* parse the length of the file from the ContentLength header */
-+      for (*file_size = 0, i = 0; i < (int)response_message.header_count; ++i)
-+	{
-+	  if (!grub_strcmp((const char*)response_message.headers[i].field_name, "Content-Length"))
-+	    {
-+	      *file_size = grub_strtoul((const char*)response_message.headers[i].field_value, 0, 10);
-+	      break;
-+	    }
-+	}
-+    }
-+
-+  if (response_message.headers)
-+    efi_call_1 (b->free_pool, response_message.headers);
-+  efi_call_1 (b->close_event, response_token.event);
-+  efi_call_1 (b->close_event, request_token.event);
-+  grub_free (request_data.url);
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_ssize_t
-+efihttp_read (struct grub_efi_net_device *dev,
-+		  char *buf,
-+		  grub_size_t len)
-+{
-+  grub_efi_http_message_t response_message;
-+  grub_efi_http_token_t response_token;
-+
-+  grub_efi_status_t status;
-+  grub_size_t sum = 0;
-+  grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
-+  grub_efi_http_t *http = dev->http;
-+
-+  if (!len)
-+    {
-+      grub_error (GRUB_ERR_BUG, "Invalid arguments to EFI HTTP Read");
-+      return -1;
-+    }
-+
-+  efi_call_5 (b->create_event,
-+              GRUB_EFI_EVT_NOTIFY_SIGNAL,
-+              GRUB_EFI_TPL_CALLBACK,
-+              grub_efi_http_response_callback,
-+              NULL,
-+              &response_token.event);
-+
-+  while (len)
-+    {
-+      response_message.data.response = NULL;
-+      response_message.header_count = 0;
-+      response_message.headers = NULL;
-+      response_message.body_length = len;
-+      response_message.body = buf;
-+
-+      response_token.message = &response_message;
-+      response_token.status = GRUB_EFI_NOT_READY;
-+
-+      response_callback_done = 0;
-+
-+      status = efi_call_2 (http->response, http, &response_token);
-+      if (status != GRUB_EFI_SUCCESS)
-+	{
-+	  efi_call_1 (b->close_event, response_token.event);
-+	  grub_error (GRUB_ERR_IO, "Error! status=%d\n", (int)status);
-+	  return -1;
-+	}
-+
-+      while (!response_callback_done)
-+	efi_call_1(http->poll, http);
-+
-+      sum += response_message.body_length;
-+      buf += response_message.body_length;
-+      len -= response_message.body_length;
-+    }
-+
-+  efi_call_1 (b->close_event, response_token.event);
-+
-+  return sum;
-+}
-+
-+static grub_err_t
-+grub_efihttp_open (struct grub_efi_net_device *dev,
-+		  int prefer_ip6 __attribute__ ((unused)),
-+		  grub_file_t file,
-+		  const char *filename __attribute__ ((unused)),
-+		  int type)
-+{
-+  grub_err_t err;
-+  grub_off_t size;
-+  char *buf;
-+
-+  err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0);
-+  if (err != GRUB_ERR_NONE)
-+    return err;
-+
-+  err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size);
-+  if (err != GRUB_ERR_NONE)
-+    return err;
-+
-+  buf = grub_malloc (size);
-+  efihttp_read (dev, buf, size);
-+
-+  file->size = size;
-+  file->data = buf;
-+  file->not_easily_seekable = 0;
-+  file->device->net->offset = 0;
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+grub_efihttp_close (struct grub_efi_net_device *dev __attribute__ ((unused)),
-+		    int prefer_ip6 __attribute__ ((unused)),
-+		    grub_file_t file)
-+{
-+  if (file->data)
-+    grub_free (file->data);
-+
-+  file->data = 0;
-+  file->offset = 0;
-+  file->size = 0;
-+  file->device->net->offset = 0;
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_ssize_t
-+grub_efihttp_read (struct grub_efi_net_device *dev __attribute__((unused)),
-+		  int prefer_ip6 __attribute__((unused)),
-+		  grub_file_t file,
-+		  char *buf,
-+		  grub_size_t len)
-+{
-+  grub_size_t r = len;
-+
-+  if (!file->data || !buf || !len)
-+    return 0;
-+
-+  if ((file->device->net->offset + len) > file->size)
-+    r = file->size - file->device->net->offset;
-+
-+  if (r)
-+    {
-+      grub_memcpy (buf, (char *)file->data + file->device->net->offset, r);
-+      file->device->net->offset += r;
-+    }
-+
-+  return r;
-+}
-+
-+struct grub_efi_net_io io_http =
-+  {
-+    .configure = http_configure,
-+    .open = grub_efihttp_open,
-+    .read = grub_efihttp_read,
-+    .close = grub_efihttp_close
-+  };
-diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c
-new file mode 100644
-index 00000000000..b711a5d9457
---- /dev/null
-+++ b/grub-core/net/efi/ip4_config.c
-@@ -0,0 +1,398 @@
-+
-+#include <grub/efi/api.h>
-+#include <grub/efi/efi.h>
-+#include <grub/misc.h>
-+#include <grub/net/efi.h>
-+#include <grub/charset.h>
-+
-+char *
-+grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address)
-+{
-+  char *hw_addr, *p;
-+  int sz, s;
-+  int i;
-+
-+  sz = (int)hw_address_size * (sizeof ("XX:") - 1) + 1;
-+
-+  hw_addr = grub_malloc (sz);
-+  if (!hw_addr)
-+    return NULL;
-+
-+  p = hw_addr;
-+  s = sz;
-+  for (i = 0; i < (int)hw_address_size; i++)
-+    {
-+      grub_snprintf (p, sz, "%02x:", hw_address[i]);
-+      p +=  sizeof ("XX:") - 1;
-+      s -=  sizeof ("XX:") - 1;
-+    }
-+
-+  hw_addr[sz - 2] = '\0';
-+  return hw_addr;
-+}
-+
-+char *
-+grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address)
-+{
-+  char *addr;
-+
-+  addr = grub_malloc (sizeof ("XXX.XXX.XXX.XXX"));
-+  if (!addr)
-+      return NULL;
-+
-+  /* FIXME: Use grub_xasprintf ? */
-+  grub_snprintf (addr,
-+	  sizeof ("XXX.XXX.XXX.XXX"),
-+	  "%u.%u.%u.%u",
-+	  (*address)[0],
-+	  (*address)[1],
-+	  (*address)[2],
-+	  (*address)[3]);
-+
-+  return addr;
-+}
-+
-+int
-+grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest)
-+{
-+  grub_uint32_t newip = 0;
-+  int i;
-+  const char *ptr = val;
-+
-+  for (i = 0; i < 4; i++)
-+    {
-+      unsigned long t;
-+      t = grub_strtoul (ptr, (char **) &ptr, 0);
-+      if (grub_errno)
-+	{
-+	  grub_errno = GRUB_ERR_NONE;
-+	  return 0;
-+	}
-+      if (*ptr != '.' && i == 0)
-+	{
-+	  /* XXX: t is in host byte order */
-+	  newip = t;
-+	  break;
-+	}
-+      if (t & ~0xff)
-+	return 0;
-+      newip <<= 8;
-+      newip |= t;
-+      if (i != 3 && *ptr != '.')
-+	return 0;
-+      ptr++;
-+    }
-+
-+  newip =  grub_cpu_to_be32 (newip);
-+
-+  grub_memcpy (address, &newip, sizeof(*address));
-+
-+  if (rest)
-+    *rest = (ptr - 1);
-+  return 1;
-+}
-+
-+static grub_efi_ip4_config2_interface_info_t *
-+efi_ip4_config_interface_info (grub_efi_ip4_config2_protocol_t *ip4_config)
-+{
-+  grub_efi_uintn_t sz;
-+  grub_efi_status_t status;
-+  grub_efi_ip4_config2_interface_info_t *interface_info;
-+
-+  sz = sizeof (*interface_info) + sizeof (*interface_info->route_table);
-+  interface_info = grub_malloc (sz);
-+  if (!interface_info)
-+    return NULL;
-+
-+  status = efi_call_4 (ip4_config->get_data, ip4_config,
-+		GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
-+		&sz, interface_info);
-+
-+  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
-+    {
-+      grub_free (interface_info);
-+      interface_info = grub_malloc (sz);
-+      status = efi_call_4 (ip4_config->get_data, ip4_config,
-+		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
-+		    &sz, interface_info);
-+    }
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      grub_free (interface_info);
-+      return NULL;
-+    }
-+
-+  return interface_info;
-+}
-+
-+static grub_efi_ip4_config2_manual_address_t *
-+efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config)
-+{
-+  grub_efi_uintn_t sz;
-+  grub_efi_status_t status;
-+  grub_efi_ip4_config2_manual_address_t *manual_address;
-+
-+  sz = sizeof (*manual_address);
-+  manual_address = grub_malloc (sz);
-+  if (!manual_address)
-+    return NULL;
-+
-+  status = efi_call_4 (ip4_config->get_data, ip4_config,
-+		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
-+		    &sz, manual_address);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      grub_free (manual_address);
-+      return NULL;
-+    }
-+
-+  return manual_address;
-+}
-+
-+char *
-+grub_efi_ip4_interface_name (struct grub_efi_net_device *dev)
-+{
-+  grub_efi_ip4_config2_interface_info_t *interface_info;
-+  char *name;
-+
-+  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
-+
-+  if (!interface_info)
-+    return NULL;
-+
-+  name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE
-+		      * GRUB_MAX_UTF8_PER_UTF16 + 1);
-+  *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name,
-+		      GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0;
-+  grub_free (interface_info);
-+  return name;
-+}
-+
-+static char *
-+grub_efi_ip4_interface_hw_address (struct grub_efi_net_device *dev)
-+{
-+  grub_efi_ip4_config2_interface_info_t *interface_info;
-+  char *hw_addr;
-+
-+  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
-+
-+  if (!interface_info)
-+    return NULL;
-+
-+  hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address);
-+  grub_free (interface_info);
-+
-+  return hw_addr;
-+}
-+
-+static char *
-+grub_efi_ip4_interface_address (struct grub_efi_net_device *dev)
-+{
-+  grub_efi_ip4_config2_manual_address_t *manual_address;
-+  char *addr;
-+
-+  manual_address = efi_ip4_config_manual_address (dev->ip4_config);
-+
-+  if (!manual_address)
-+    return NULL;
-+
-+  addr = grub_efi_ip4_address_to_string (&manual_address->address);
-+  grub_free (manual_address);
-+  return addr;
-+}
-+
-+
-+static int
-+address_mask_size (grub_efi_ipv4_address_t *address)
-+{
-+  grub_uint8_t i;
-+  grub_uint32_t u32_addr = grub_be_to_cpu32 (grub_get_unaligned32 (address));
-+
-+  if (u32_addr == 0)
-+    return 0;
-+
-+  for (i = 0; i < 32 ; ++i)
-+    {
-+      if (u32_addr == ((0xffffffff >> i) << i))
-+	return (32 - i);
-+    }
-+
-+  return -1;
-+}
-+
-+static char **
-+grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev)
-+{
-+  grub_efi_ip4_config2_interface_info_t *interface_info;
-+  char **ret;
-+  int i, id;
-+
-+  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
-+  if (!interface_info)
-+    return NULL;
-+
-+  ret = grub_malloc (sizeof (*ret) * (interface_info->route_table_size + 1));
-+
-+  if (!ret)
-+    {
-+      grub_free (interface_info);
-+      return NULL;
-+    }
-+
-+  id = 0;
-+  for (i = 0; i < (int)interface_info->route_table_size; i++)
-+    {
-+      char *subnet, *gateway, *mask;
-+      grub_uint32_t u32_subnet, u32_gateway;
-+      int mask_size;
-+      grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i;
-+      grub_efi_net_interface_t *inf;
-+      char *interface_name = NULL;
-+
-+      for (inf = dev->net_interfaces; inf; inf = inf->next)
-+	if (!inf->prefer_ip6)
-+	  interface_name = inf->name;
-+
-+      u32_gateway = grub_get_unaligned32 (&route_table->gateway_address);
-+      gateway = grub_efi_ip4_address_to_string (&route_table->gateway_address);
-+      u32_subnet = grub_get_unaligned32 (&route_table->subnet_address);
-+      subnet = grub_efi_ip4_address_to_string (&route_table->subnet_address);
-+      mask_size = address_mask_size (&route_table->subnet_mask);
-+      mask = grub_efi_ip4_address_to_string (&route_table->subnet_mask);
-+      if (u32_subnet && !u32_gateway && interface_name)
-+	ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, subnet, mask_size, interface_name);
-+      else if (u32_subnet && u32_gateway)
-+	ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, subnet, mask_size, gateway);
-+      else if (!u32_subnet && u32_gateway)
-+	ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, subnet, mask_size, gateway);
-+      grub_free (subnet);
-+      grub_free (gateway);
-+      grub_free (mask);
-+    }
-+
-+  ret[id] = NULL;
-+  grub_free (interface_info);
-+  return ret;
-+}
-+
-+static grub_efi_net_interface_t *
-+grub_efi_ip4_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address)
-+{
-+  grub_efi_ip4_config2_interface_info_t *interface_info;
-+  grub_efi_net_interface_t *inf;
-+  int i;
-+  grub_efi_ipv4_address_t *address = &ip_address->ip4;
-+
-+  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
-+  if (!interface_info)
-+    return NULL;
-+
-+  for (i = 0; i < (int)interface_info->route_table_size; i++)
-+    {
-+      grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i;
-+      grub_uint32_t u32_address, u32_mask, u32_subnet;
-+
-+      u32_address = grub_get_unaligned32 (address);
-+      u32_subnet = grub_get_unaligned32 (route_table->subnet_address);
-+      u32_mask = grub_get_unaligned32 (route_table->subnet_mask);
-+
-+      /* SKIP Default GATEWAY */
-+      if (!u32_subnet && !u32_mask)
-+	continue;
-+
-+      if ((u32_address & u32_mask) == u32_subnet)
-+	{
-+	  for (inf = dev->net_interfaces; inf; inf = inf->next)
-+	    if (!inf->prefer_ip6)
-+	      {
-+		grub_free (interface_info);
-+		return inf;
-+	      }
-+	}
-+    }
-+
-+  grub_free (interface_info);
-+  return NULL;
-+}
-+
-+static int
-+grub_efi_ip4_interface_set_manual_address (struct grub_efi_net_device *dev,
-+	    grub_efi_net_ip_manual_address_t *net_ip,
-+	    int with_subnet)
-+{
-+  grub_efi_status_t status;
-+  grub_efi_ip4_config2_manual_address_t *address = &net_ip->ip4;
-+
-+  if (!with_subnet)
-+    {
-+      grub_efi_ip4_config2_manual_address_t *manual_address =
-+      efi_ip4_config_manual_address (dev->ip4_config);
-+
-+      if (manual_address)
-+	{
-+	  grub_memcpy (address->subnet_mask, manual_address->subnet_mask, sizeof(address->subnet_mask));
-+	  grub_free (manual_address);
-+	}
-+      else
-+	{
-+	  /* XXX: */
-+	  address->subnet_mask[0] = 0xff;
-+	  address->subnet_mask[1] = 0xff;
-+	  address->subnet_mask[2] = 0xff;
-+	  address->subnet_mask[3] = 0;
-+	}
-+    }
-+
-+  status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
-+		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
-+		    sizeof(*address), address);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    return 0;
-+
-+  return 1;
-+}
-+
-+static int
-+grub_efi_ip4_interface_set_gateway (struct grub_efi_net_device *dev,
-+	      grub_efi_net_ip_address_t *address)
-+{
-+  grub_efi_status_t status;
-+
-+  status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
-+		GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY,
-+		sizeof (address->ip4), &address->ip4);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    return 0;
-+  return 1;
-+}
-+
-+/* FIXME: Multiple DNS */
-+static int
-+grub_efi_ip4_interface_set_dns (struct grub_efi_net_device *dev,
-+	      grub_efi_net_ip_address_t *address)
-+{
-+  grub_efi_status_t status;
-+
-+  status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
-+		GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
-+		sizeof (address->ip4), &address->ip4);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    return 0;
-+  return 1;
-+}
-+
-+grub_efi_net_ip_config_t *efi_net_ip4_config = &(grub_efi_net_ip_config_t)
-+  {
-+    .get_hw_address = grub_efi_ip4_interface_hw_address,
-+    .get_address = grub_efi_ip4_interface_address,
-+    .get_route_table = grub_efi_ip4_interface_route_table,
-+    .best_interface = grub_efi_ip4_interface_match,
-+    .set_address = grub_efi_ip4_interface_set_manual_address,
-+    .set_gateway = grub_efi_ip4_interface_set_gateway,
-+    .set_dns = grub_efi_ip4_interface_set_dns
-+  };
-diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c
-new file mode 100644
-index 00000000000..017c4d05bc7
---- /dev/null
-+++ b/grub-core/net/efi/ip6_config.c
-@@ -0,0 +1,422 @@
-+#include <grub/efi/api.h>
-+#include <grub/efi/efi.h>
-+#include <grub/misc.h>
-+#include <grub/net/efi.h>
-+#include <grub/charset.h>
-+
-+char *
-+grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address)
-+{
-+  char *str = grub_malloc (sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX"));
-+  char *p;
-+  int i;
-+  int squash;
-+
-+  if (!str)
-+    return NULL;
-+
-+  p = str;
-+  squash = 0;
-+  for (i = 0; i < 8; ++i)
-+    {
-+      grub_uint16_t addr;
-+
-+      if (i == 7)
-+	squash = 2;
-+
-+      addr = grub_get_unaligned16 (address->addr + i * 2);
-+
-+      if (grub_be_to_cpu16 (addr))
-+	{
-+	  char buf[sizeof ("XXXX")];
-+	  if (i > 0)
-+	    *p++ = ':';
-+	  grub_snprintf (buf, sizeof (buf), "%x", grub_be_to_cpu16 (addr));
-+	  grub_strcpy (p, buf);
-+	  p += grub_strlen (buf);
-+
-+	  if (squash == 1)
-+	    squash = 2;
-+	}
-+      else
-+	{
-+	  if (squash == 0)
-+	    {
-+	      *p++ = ':';
-+	      squash = 1;
-+	    }
-+	  else if (squash == 2)
-+	    {
-+	      *p++ = ':';
-+	      *p++ = '0';
-+	    }
-+	}
-+    }
-+  *p = '\0';
-+  return str;
-+}
-+
-+int
-+grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest)
-+{
-+  grub_uint16_t newip[8];
-+  const char *ptr = val;
-+  int word, quaddot = -1;
-+  int bracketed = 0;
-+
-+  if (ptr[0] == '[') {
-+    bracketed = 1;
-+    ptr++;
-+  }
-+
-+  if (ptr[0] == ':' && ptr[1] != ':')
-+    return 0;
-+  if (ptr[0] == ':')
-+    ptr++;
-+
-+  for (word = 0; word < 8; word++)
-+    {
-+      unsigned long t;
-+      if (*ptr == ':')
-+	{
-+	  quaddot = word;
-+	  word--;
-+	  ptr++;
-+	  continue;
-+	}
-+      t = grub_strtoul (ptr, (char **) &ptr, 16);
-+      if (grub_errno)
-+	{
-+	  grub_errno = GRUB_ERR_NONE;
-+	  break;
-+	}
-+      if (t & ~0xffff)
-+	return 0;
-+      newip[word] = grub_cpu_to_be16 (t);
-+      if (*ptr != ':')
-+	break;
-+      ptr++;
-+    }
-+  if (quaddot == -1 && word < 7)
-+    return 0;
-+  if (quaddot != -1)
-+    {
-+      grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot],
-+		    (word - quaddot + 1) * sizeof (newip[0]));
-+      grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
-+    }
-+  grub_memcpy (address, newip, 16);
-+  if (bracketed && *ptr == ']') {
-+    ptr++;
-+  }
-+  if (rest)
-+    *rest = ptr;
-+  return 1;
-+}
-+
-+static grub_efi_ip6_config_interface_info_t *
-+efi_ip6_config_interface_info (grub_efi_ip6_config_protocol_t *ip6_config)
-+{
-+  grub_efi_uintn_t sz;
-+  grub_efi_status_t status;
-+  grub_efi_ip6_config_interface_info_t *interface_info;
-+
-+  sz = sizeof (*interface_info) + sizeof (*interface_info->route_table);
-+  interface_info = grub_malloc (sz);
-+
-+  status = efi_call_4 (ip6_config->get_data, ip6_config,
-+		GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
-+		&sz, interface_info);
-+
-+  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
-+    {
-+      grub_free (interface_info);
-+      interface_info = grub_malloc (sz);
-+      status = efi_call_4 (ip6_config->get_data, ip6_config,
-+		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
-+		    &sz, interface_info);
-+    }
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      grub_free (interface_info);
-+      return NULL;
-+    }
-+
-+  return interface_info;
-+}
-+
-+static grub_efi_ip6_config_manual_address_t *
-+efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config)
-+{
-+  grub_efi_uintn_t sz;
-+  grub_efi_status_t status;
-+  grub_efi_ip6_config_manual_address_t *manual_address;
-+
-+  sz = sizeof (*manual_address);
-+  manual_address = grub_malloc (sz);
-+  if (!manual_address)
-+    return NULL;
-+
-+  status = efi_call_4 (ip6_config->get_data, ip6_config,
-+		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
-+		    &sz, manual_address);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      grub_free (manual_address);
-+      return NULL;
-+    }
-+
-+  return manual_address;
-+}
-+
-+char *
-+grub_efi_ip6_interface_name (struct grub_efi_net_device *dev)
-+{
-+  grub_efi_ip6_config_interface_info_t *interface_info;
-+  char *name;
-+
-+  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
-+
-+  if (!interface_info)
-+    return NULL;
-+
-+  name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE
-+		      * GRUB_MAX_UTF8_PER_UTF16 + 1);
-+  *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name,
-+		      GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0;
-+  grub_free (interface_info);
-+  return name;
-+}
-+
-+static char *
-+grub_efi_ip6_interface_hw_address (struct grub_efi_net_device *dev)
-+{
-+  grub_efi_ip6_config_interface_info_t *interface_info;
-+  char *hw_addr;
-+
-+  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
-+
-+  if (!interface_info)
-+    return NULL;
-+
-+  hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address);
-+  grub_free (interface_info);
-+
-+  return hw_addr;
-+}
-+
-+static char *
-+grub_efi_ip6_interface_address (struct grub_efi_net_device *dev)
-+{
-+  grub_efi_ip6_config_manual_address_t *manual_address;
-+  char *addr;
-+
-+  manual_address = efi_ip6_config_manual_address (dev->ip6_config);
-+
-+  if (!manual_address)
-+    return NULL;
-+
-+  addr = grub_efi_ip6_address_to_string ((grub_efi_pxe_ipv6_address_t *)&manual_address->address);
-+  grub_free (manual_address);
-+  return addr;
-+}
-+
-+static char **
-+grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev)
-+{
-+  grub_efi_ip6_config_interface_info_t *interface_info;
-+  char **ret;
-+  int i, id;
-+
-+  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
-+  if (!interface_info)
-+    return NULL;
-+
-+  ret = grub_malloc (sizeof (*ret) * (interface_info->route_count + 1));
-+
-+  if (!ret)
-+    {
-+      grub_free (interface_info);
-+      return NULL;
-+    }
-+
-+  id = 0;
-+  for (i = 0; i < (int)interface_info->route_count ; i++)
-+    {
-+      char *gateway, *destination;
-+      grub_uint64_t u64_gateway[2];
-+      grub_uint64_t u64_destination[2];
-+      grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i;
-+      grub_efi_net_interface_t *inf;
-+      char *interface_name = NULL;
-+
-+      gateway = grub_efi_ip6_address_to_string (&route_table->gateway);
-+      destination = grub_efi_ip6_address_to_string (&route_table->destination);
-+
-+      u64_gateway[0] = grub_get_unaligned64 (route_table->gateway.addr);
-+      u64_gateway[1] = grub_get_unaligned64 (route_table->gateway.addr + 8);
-+      u64_destination[0] = grub_get_unaligned64 (route_table->destination.addr);
-+      u64_destination[1] = grub_get_unaligned64 (route_table->destination.addr + 8);
-+
-+      for (inf = dev->net_interfaces; inf; inf = inf->next)
-+	if (inf->prefer_ip6)
-+	  interface_name = inf->name;
-+
-+      if ((!u64_gateway[0] && !u64_gateway[1])
-+	  && (u64_destination[0] || u64_destination[1]))
-+	{
-+	  if (interface_name)
-+	    {
-+	      if ((grub_be_to_cpu64 (u64_destination[0]) == 0xfe80000000000000ULL)
-+	      && (!u64_destination[1])
-+	      && (route_table->prefix_length == 64))
-+		ret[id++] = grub_xasprintf ("%s:link %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name);
-+	      else
-+		ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name);
-+	    }
-+	}
-+      else if ((u64_gateway[0] || u64_gateway[1])
-+	  && (u64_destination[0] || u64_destination[1]))
-+	ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway);
-+      else if ((u64_gateway[0] || u64_gateway[1])
-+	  && (!u64_destination[0] && !u64_destination[1]))
-+	ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway);
-+
-+      grub_free (gateway);
-+      grub_free (destination);
-+    }
-+
-+  ret[id] = NULL;
-+  grub_free (interface_info);
-+  return ret;
-+}
-+
-+static grub_efi_net_interface_t *
-+grub_efi_ip6_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address)
-+{
-+  grub_efi_ip6_config_interface_info_t *interface_info;
-+  grub_efi_net_interface_t *inf;
-+  int i;
-+  grub_efi_ipv6_address_t *address = &ip_address->ip6;
-+
-+  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
-+  if (!interface_info)
-+    return NULL;
-+
-+  for (i = 0; i < (int)interface_info->route_count ; i++)
-+    {
-+      grub_uint64_t u64_addr[2];
-+      grub_uint64_t u64_subnet[2];
-+      grub_uint64_t u64_mask[2];
-+
-+      grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i;
-+
-+      /* SKIP Default GATEWAY */
-+      if (route_table->prefix_length == 0)
-+	continue;
-+
-+      u64_addr[0] = grub_get_unaligned64 (address);
-+      u64_addr[1] = grub_get_unaligned64 (address + 4);
-+      u64_subnet[0] = grub_get_unaligned64 (route_table->destination.addr);
-+      u64_subnet[1] = grub_get_unaligned64 (route_table->destination.addr + 8);
-+      u64_mask[0] = (route_table->prefix_length <= 64) ?
-+	    0xffffffffffffffffULL << (64 - route_table->prefix_length) :
-+	    0xffffffffffffffffULL;
-+      u64_mask[1] = (route_table->prefix_length <= 64) ?
-+	    0 :
-+	    0xffffffffffffffffULL << (128 - route_table->prefix_length);
-+
-+      if (((u64_addr[0] & u64_mask[0]) == u64_subnet[0])
-+	  && ((u64_addr[1] & u64_mask[1]) == u64_subnet[1]))
-+	{
-+	  for (inf = dev->net_interfaces; inf; inf = inf->next)
-+	    if (inf->prefer_ip6)
-+	      {
-+		grub_free (interface_info);
-+		return inf;
-+	      }
-+	}
-+    }
-+
-+  grub_free (interface_info);
-+  return NULL;
-+}
-+
-+static int
-+grub_efi_ip6_interface_set_manual_address (struct grub_efi_net_device *dev,
-+	    grub_efi_net_ip_manual_address_t *net_ip,
-+	    int with_subnet)
-+{
-+  grub_efi_status_t status;
-+  grub_efi_ip6_config_manual_address_t *address = &net_ip->ip6;
-+
-+  if (!with_subnet)
-+    {
-+      grub_efi_ip6_config_manual_address_t *manual_address =
-+      efi_ip6_config_manual_address (dev->ip6_config);
-+
-+      if (manual_address)
-+	{
-+	  address->prefix_length = manual_address->prefix_length;
-+	  grub_free (manual_address);
-+	}
-+      else
-+	{
-+	  /* XXX: */
-+	  address->prefix_length = 64;
-+	}
-+    }
-+
-+  status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
-+		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
-+		    sizeof(*address), address);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    return 0;
-+
-+  return 1;
-+}
-+
-+static int
-+grub_efi_ip6_interface_set_gateway (struct grub_efi_net_device *dev,
-+	      grub_efi_net_ip_address_t *address)
-+{
-+  grub_efi_status_t status;
-+
-+  status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
-+		GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY,
-+		sizeof (address->ip6), &address->ip6);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    return 0;
-+  return 1;
-+}
-+
-+static int
-+grub_efi_ip6_interface_set_dns (struct grub_efi_net_device *dev,
-+	      grub_efi_net_ip_address_t *address)
-+{
-+
-+  grub_efi_status_t status;
-+
-+  status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
-+		GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
-+		sizeof (address->ip6), &address->ip6);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    return 0;
-+  return 1;
-+}
-+
-+grub_efi_net_ip_config_t *efi_net_ip6_config = &(grub_efi_net_ip_config_t)
-+  {
-+    .get_hw_address = grub_efi_ip6_interface_hw_address,
-+    .get_address = grub_efi_ip6_interface_address,
-+    .get_route_table = grub_efi_ip6_interface_route_table,
-+    .best_interface = grub_efi_ip6_interface_match,
-+    .set_address = grub_efi_ip6_interface_set_manual_address,
-+    .set_gateway = grub_efi_ip6_interface_set_gateway,
-+    .set_dns = grub_efi_ip6_interface_set_dns
-+  };
-diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
-new file mode 100644
-index 00000000000..86bce6535d3
---- /dev/null
-+++ b/grub-core/net/efi/net.c
-@@ -0,0 +1,1428 @@
-+#include <grub/net.h>
-+#include <grub/env.h>
-+#include <grub/mm.h>
-+#include <grub/misc.h>
-+#include <grub/dl.h>
-+#include <grub/command.h>
-+#include <grub/efi/api.h>
-+#include <grub/efi/efi.h>
-+#include <grub/i18n.h>
-+#include <grub/bufio.h>
-+#include <grub/efi/http.h>
-+#include <grub/efi/dhcp.h>
-+#include <grub/net/efi.h>
-+#include <grub/charset.h>
-+
-+GRUB_MOD_LICENSE ("GPLv3+");
-+
-+#define GRUB_EFI_IP6_PREFIX_LENGTH 64
-+
-+static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID;
-+static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID;
-+static grub_efi_guid_t http_service_binding_guid = GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID;
-+static grub_efi_guid_t http_guid = GRUB_EFI_HTTP_PROTOCOL_GUID;
-+static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID;
-+static grub_efi_guid_t dhcp4_service_binding_guid = GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID;
-+static grub_efi_guid_t dhcp4_guid = GRUB_EFI_DHCP4_PROTOCOL_GUID;
-+static grub_efi_guid_t dhcp6_service_binding_guid = GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID;
-+static grub_efi_guid_t dhcp6_guid = GRUB_EFI_DHCP6_PROTOCOL_GUID;
-+
-+struct grub_efi_net_device *net_devices;
-+
-+static char *default_server;
-+static grub_efi_net_interface_t *net_interface;
-+static grub_efi_net_interface_t *net_default_interface;
-+
-+#define efi_net_interface_configure(inf) inf->io->configure (inf->dev, inf->prefer_ip6)
-+#define efi_net_interface_open(inf, file, name) inf->io->open (inf->dev, inf->prefer_ip6, file, name, inf->io_type)
-+#define efi_net_interface_read(inf, file, buf, sz) inf->io->read (inf->dev, inf->prefer_ip6, file, buf, sz)
-+#define efi_net_interface_close(inf, file) inf->io->close (inf->dev, inf->prefer_ip6, file)
-+#define efi_net_interface(m,...) efi_net_interface_ ## m (net_interface, ## __VA_ARGS__)
-+
-+static grub_efi_handle_t
-+grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path,
-+                            grub_efi_device_path_t **r_device_path)
-+{
-+  grub_efi_handle_t handle;
-+  grub_efi_status_t status;
-+
-+  status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path,
-+                      protocol, &device_path, &handle);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    return 0;
-+
-+  if (r_device_path)
-+    *r_device_path = device_path;
-+
-+  return handle;
-+}
-+
-+static int
-+url_parse_fields (const char *url, char **proto, char **host, char **path)
-+{
-+  const char *p, *ps;
-+  grub_size_t l;
-+
-+  *proto = *host = *path = NULL;
-+  ps = p = url;
-+
-+  while ((p = grub_strchr (p, ':')))
-+    {
-+      if (grub_strlen (p) < sizeof ("://") - 1)
-+	break;
-+      if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0)
-+	{
-+	  l = p - ps;
-+	  *proto = grub_malloc (l + 1);
-+	  if (!*proto)
-+	    {
-+	      grub_print_error ();
-+	      return 0;
-+	    }
-+
-+	  grub_memcpy (*proto, ps, l);
-+	  (*proto)[l] = '\0';
-+	  p +=  sizeof ("://") - 1;
-+	  break;
-+	}
-+      ++p;
-+    }
-+
-+  if (!*proto)
-+    {
-+      grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url);
-+      return 0;
-+    }
-+
-+  ps = p;
-+  p = grub_strchr (p, '/');
-+
-+  if (!p)
-+    {
-+      grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url);
-+      grub_free (*proto);
-+      *proto = NULL;
-+      return 0;
-+    }
-+
-+  l = p - ps;
-+
-+  if (l > 2 && ps[0] == '[' && ps[l - 1] == ']')
-+    {
-+      *host = grub_malloc (l - 1);
-+      if (!*host)
-+	{
-+	  grub_print_error ();
-+	  grub_free (*proto);
-+	  *proto = NULL;
-+	  return 0;
-+	}
-+      grub_memcpy (*host, ps + 1, l - 2);
-+      (*host)[l - 2] = 0;
-+    }
-+  else
-+    {
-+      *host = grub_malloc (l + 1);
-+      if (!*host)
-+	{
-+	  grub_print_error ();
-+	  grub_free (*proto);
-+	  *proto = NULL;
-+	  return 0;
-+	}
-+      grub_memcpy (*host, ps, l);
-+      (*host)[l] = 0;
-+    }
-+
-+  *path = grub_strdup (p);
-+  if (!*path)
-+    {
-+      grub_print_error ();
-+      grub_free (*host);
-+      grub_free (*proto);
-+      *host = NULL;
-+      *proto = NULL;
-+      return 0;
-+    }
-+  return 1;
-+}
-+
-+static void
-+url_get_boot_location (const char *url, char **device, char **path, int is_default)
-+{
-+  char *protocol, *server, *file;
-+  char *slash;
-+
-+  if (!url_parse_fields (url, &protocol, &server, &file))
-+    return;
-+
-+  if ((slash = grub_strrchr (file, '/')))
-+    *slash = 0;
-+  else
-+    *file = 0;
-+
-+  *device = grub_xasprintf ("%s,%s", protocol, server);
-+  *path = grub_strdup(file);
-+
-+  if (is_default)
-+    default_server = server;
-+  else
-+    grub_free (server);
-+
-+  grub_free (protocol);
-+  grub_free (file);
-+}
-+
-+static void
-+pxe_get_boot_location (const struct grub_net_bootp_packet *bp,
-+		  char **device,
-+		  char **path,
-+		  int is_default)
-+{
-+  char *server = grub_xasprintf ("%d.%d.%d.%d",
-+	     ((grub_uint8_t *) &bp->server_ip)[0],
-+	     ((grub_uint8_t *) &bp->server_ip)[1],
-+	     ((grub_uint8_t *) &bp->server_ip)[2],
-+	     ((grub_uint8_t *) &bp->server_ip)[3]);
-+
-+  *device = grub_xasprintf ("tftp,%s", server);
-+
-+  *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file));
-+
-+  if (*path)
-+    {
-+      char *slash;
-+      slash = grub_strrchr (*path, '/');
-+      if (slash)
-+	*slash = 0;
-+      else
-+	**path = 0;
-+    }
-+
-+  if (is_default)
-+    default_server = server;
-+  else
-+    grub_free (server);
-+}
-+
-+static void
-+pxe_get_boot_location_v6 (const struct grub_net_dhcp6_packet *dp,
-+		  grub_size_t dhcp_size,
-+		  char **device,
-+		  char **path)
-+{
-+
-+  struct grub_net_dhcp6_option *dhcp_opt;
-+  grub_size_t dhcp_remain_size;
-+  *device = *path = 0;
-+
-+  if (dhcp_size < sizeof (*dp))
-+    {
-+      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small"));
-+      return;
-+    }
-+
-+  dhcp_remain_size = dhcp_size - sizeof (*dp);
-+  dhcp_opt = (struct grub_net_dhcp6_option *)dp->dhcp_options;
-+
-+  while (dhcp_remain_size)
-+    {
-+      grub_uint16_t code = grub_be_to_cpu16 (dhcp_opt->code);
-+      grub_uint16_t len = grub_be_to_cpu16 (dhcp_opt->len);
-+      grub_uint16_t option_size = sizeof (*dhcp_opt) + len;
-+
-+      if (dhcp_remain_size < option_size || code == 0)
-+	break;
-+
-+      if (code == GRUB_NET_DHCP6_OPTION_BOOTFILE_URL)
-+	{
-+	  char *url = grub_malloc (len + 1);
-+
-+	  grub_memcpy (url, dhcp_opt->data, len);
-+	  url[len] = 0;
-+
-+	  url_get_boot_location ((const char *)url, device, path, 1);
-+	  grub_free (url);
-+	  break;
-+	}
-+
-+      dhcp_remain_size -= option_size;
-+      dhcp_opt = (struct grub_net_dhcp6_option *)((grub_uint8_t *)dhcp_opt + option_size);
-+    }
-+}
-+
-+static grub_efi_net_interface_t *
-+grub_efi_net_config_from_device_path (grub_efi_device_path_t *dp,
-+		  struct grub_efi_net_device *netdev,
-+		  char **device,
-+		  char **path)
-+{
-+  grub_efi_net_interface_t *inf = NULL;
-+
-+  while (1)
-+    {
-+      grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
-+      grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
-+      grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp);
-+
-+      if (type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE)
-+	{
-+	  if (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
-+	    {
-+	      grub_efi_uri_device_path_t *uri_dp;
-+	      uri_dp = (grub_efi_uri_device_path_t *) dp;
-+	      /* Beware that uri_dp->uri may not be null terminated */
-+	      url_get_boot_location ((const char *)uri_dp->uri, device, path, 1);
-+	    }
-+	  else if (subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE)
-+	    {
-+	      grub_efi_net_ip_manual_address_t net_ip;
-+	      grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) dp;
-+
-+	      if (inf)
-+		continue;
-+	      grub_memcpy (net_ip.ip4.address, ipv4->local_ip_address, sizeof (net_ip.ip4.address));
-+	      grub_memcpy (net_ip.ip4.subnet_mask, ipv4->subnet_mask, sizeof (net_ip.ip4.subnet_mask));
-+	      net_ip.is_ip6 = 0;
-+	      inf = grub_efi_net_create_interface (netdev,
-+			    netdev->card_name,
-+			    &net_ip,
-+			    1);
-+	    }
-+	  else if (subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)
-+	    {
-+	      grub_efi_net_ip_manual_address_t net_ip;
-+	      grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) dp;
-+
-+	      if (inf)
-+		continue;
-+	      grub_memcpy (net_ip.ip6.address, ipv6->local_ip_address, sizeof (net_ip.ip6.address));
-+	      net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH;
-+	      net_ip.ip6.is_anycast = 0;
-+	      net_ip.is_ip6 = 1;
-+	      inf = grub_efi_net_create_interface (netdev,
-+			    netdev->card_name,
-+			    &net_ip,
-+			    1);
-+	    }
-+	}
-+
-+      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
-+        break;
-+      dp = (grub_efi_device_path_t *) ((char *) dp + len);
-+    }
-+
-+  return inf;
-+}
-+
-+static grub_efi_net_interface_t *
-+grub_efi_net_config_from_handle (grub_efi_handle_t *hnd,
-+		  struct grub_efi_net_device *netdev,
-+		  char **device,
-+		  char **path)
-+{
-+  grub_efi_pxe_t *pxe = NULL;
-+
-+  if (hnd == netdev->ip4_pxe_handle)
-+    pxe = netdev->ip4_pxe;
-+  else if (hnd == netdev->ip6_pxe_handle)
-+    pxe = netdev->ip6_pxe;
-+
-+  if (!pxe)
-+    return (grub_efi_net_config_from_device_path (
-+		grub_efi_get_device_path (hnd),
-+		netdev,
-+		device,
-+		path));
-+
-+  if (pxe->mode->using_ipv6)
-+    {
-+      grub_efi_net_ip_manual_address_t net_ip;
-+
-+      pxe_get_boot_location_v6 (
-+	    (const struct grub_net_dhcp6_packet *) &pxe->mode->dhcp_ack,
-+	    sizeof (pxe->mode->dhcp_ack),
-+	    device,
-+	    path);
-+
-+      grub_memcpy (net_ip.ip6.address, pxe->mode->station_ip.v6, sizeof(net_ip.ip6.address));
-+      net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH;
-+      net_ip.ip6.is_anycast = 0;
-+      net_ip.is_ip6 = 1;
-+      return (grub_efi_net_create_interface (netdev,
-+		    netdev->card_name,
-+		    &net_ip,
-+		    1));
-+    }
-+  else
-+    {
-+      grub_efi_net_ip_manual_address_t net_ip;
-+
-+      pxe_get_boot_location (
-+		(const struct grub_net_bootp_packet *) &pxe->mode->dhcp_ack,
-+		device,
-+		path,
-+		1);
-+
-+      grub_memcpy (net_ip.ip4.address, pxe->mode->station_ip.v4, sizeof (net_ip.ip4.address));
-+      grub_memcpy (net_ip.ip4.subnet_mask, pxe->mode->subnet_mask.v4, sizeof (net_ip.ip4.subnet_mask));
-+      net_ip.is_ip6 = 0;
-+      return (grub_efi_net_create_interface (netdev,
-+		    netdev->card_name,
-+		    &net_ip,
-+		    1));
-+    }
-+}
-+
-+static const char *
-+grub_efi_net_var_get_address (struct grub_env_var *var,
-+                   const char *val __attribute__ ((unused)))
-+{
-+  struct grub_efi_net_device *dev;
-+
-+  for (dev = net_devices; dev; dev = dev->next)
-+    {
-+      grub_efi_net_interface_t *inf;
-+
-+      for (inf = dev->net_interfaces; inf; inf = inf->next)
-+	{
-+	  char *var_name;
-+
-+	  var_name = grub_xasprintf ("net_%s_ip", inf->name);
-+	  if (grub_strcmp (var_name, var->name) == 0)
-+	    return efi_net_interface_get_address (inf);
-+	  grub_free (var_name);
-+	  var_name = grub_xasprintf ("net_%s_mac", inf->name);
-+	  if (grub_strcmp (var_name, var->name) == 0)
-+	    return efi_net_interface_get_hw_address (inf);
-+	  grub_free (var_name);
-+	}
-+    }
-+
-+  return NULL;
-+}
-+
-+static char *
-+grub_efi_net_var_set_interface (struct grub_env_var *var __attribute__ ((unused)),
-+		   const char *val)
-+{
-+  struct grub_efi_net_device *dev;
-+  grub_efi_net_interface_t *inf;
-+
-+  for (dev = net_devices; dev; dev = dev->next)
-+    for (inf = dev->net_interfaces; inf; inf = inf->next)
-+      if (grub_strcmp (inf->name, val) == 0)
-+	{
-+	  net_default_interface = inf;
-+	  return grub_strdup (val);
-+	}
-+
-+  return NULL;
-+}
-+
-+static char *
-+grub_efi_net_var_set_server (struct grub_env_var *var __attribute__ ((unused)),
-+		   const char *val)
-+{
-+  grub_free (default_server);
-+  default_server = grub_strdup (val);
-+  return grub_strdup (val);
-+}
-+
-+static const char *
-+grub_efi_net_var_get_server (struct grub_env_var *var __attribute__ ((unused)),
-+		   const char *val __attribute__ ((unused)))
-+{
-+  return default_server ? : "";
-+}
-+
-+static const char *
-+grub_efi_net_var_get_ip (struct grub_env_var *var __attribute__ ((unused)),
-+	       const char *val __attribute__ ((unused)))
-+{
-+  const char *intf = grub_env_get ("net_default_interface");
-+  const char *ret = NULL;
-+  if (intf)
-+    {
-+      char *buf = grub_xasprintf ("net_%s_ip", intf);
-+      if (buf)
-+	ret = grub_env_get (buf);
-+      grub_free (buf);
-+    }
-+  return ret;
-+}
-+
-+static const char *
-+grub_efi_net_var_get_mac (struct grub_env_var *var __attribute__ ((unused)),
-+	       const char *val __attribute__ ((unused)))
-+{
-+  const char *intf = grub_env_get ("net_default_interface");
-+  const char *ret = NULL;
-+  if (intf)
-+    {
-+      char *buf = grub_xasprintf ("net_%s_mac", intf);
-+      if (buf)
-+	ret = grub_env_get (buf);
-+      grub_free (buf);
-+    }
-+  return ret;
-+}
-+
-+static void
-+grub_efi_net_export_interface_vars (void)
-+{
-+  struct grub_efi_net_device *dev;
-+
-+  for (dev = net_devices; dev; dev = dev->next)
-+    {
-+      grub_efi_net_interface_t *inf;
-+
-+      for (inf = dev->net_interfaces; inf; inf = inf->next)
-+	{
-+	  char *var;
-+
-+	  var = grub_xasprintf ("net_%s_ip", inf->name);
-+	  grub_register_variable_hook (var, grub_efi_net_var_get_address, 0);
-+	  grub_env_export (var);
-+	  grub_free (var);
-+	  var = grub_xasprintf ("net_%s_mac", inf->name);
-+	  grub_register_variable_hook (var, grub_efi_net_var_get_address, 0);
-+	  grub_env_export (var);
-+	  grub_free (var);
-+	}
-+    }
-+}
-+
-+static void
-+grub_efi_net_unset_interface_vars (void)
-+{
-+  struct grub_efi_net_device *dev;
-+
-+  for (dev = net_devices; dev; dev = dev->next)
-+    {
-+      grub_efi_net_interface_t *inf;
-+
-+      for (inf = dev->net_interfaces; inf; inf = inf->next)
-+	{
-+	  char *var;
-+
-+	  var = grub_xasprintf ("net_%s_ip", inf->name);
-+	  grub_register_variable_hook (var, 0, 0);
-+	  grub_env_unset (var);
-+	  grub_free (var);
-+	  var = grub_xasprintf ("net_%s_mac", inf->name);
-+	  grub_register_variable_hook (var, 0, 0);
-+	  grub_env_unset (var);
-+	  grub_free (var);
-+	}
-+    }
-+}
-+
-+grub_efi_net_interface_t *
-+grub_efi_net_create_interface (struct grub_efi_net_device *dev,
-+		const char *interface_name,
-+		grub_efi_net_ip_manual_address_t *net_ip,
-+		int has_subnet)
-+{
-+  grub_efi_net_interface_t *inf;
-+
-+  for (inf = dev->net_interfaces; inf; inf = inf->next)
-+    {
-+      if (inf->prefer_ip6 == net_ip->is_ip6)
-+	break;
-+    }
-+
-+  if (!inf)
-+    {
-+      inf = grub_malloc (sizeof(*inf));
-+      inf->name = grub_strdup (interface_name);
-+      inf->prefer_ip6 = net_ip->is_ip6;
-+      inf->dev = dev;
-+      inf->next = dev->net_interfaces;
-+      inf->ip_config = (net_ip->is_ip6) ? efi_net_ip6_config : efi_net_ip4_config ;
-+      dev->net_interfaces = inf;
-+    }
-+  else
-+    {
-+      grub_free (inf->name);
-+      inf->name = grub_strdup (interface_name);
-+    }
-+
-+  if (!efi_net_interface_set_address (inf, net_ip, has_subnet))
-+    {
-+      grub_error (GRUB_ERR_BUG, N_("Set Address Failed"));
-+      return NULL;
-+    }
-+
-+  return inf;
-+}
-+
-+static void
-+grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
-+			  char **path)
-+{
-+  grub_efi_handle_t config_hnd;
-+
-+  struct grub_efi_net_device *netdev;
-+  grub_efi_net_interface_t *inf;
-+
-+  config_hnd = grub_efi_locate_device_path (&ip4_config_guid, grub_efi_get_device_path (hnd), NULL);
-+
-+  if (!config_hnd)
-+    return;
-+
-+  for (netdev = net_devices; netdev; netdev = netdev->next)
-+    if (netdev->handle == config_hnd)
-+      break;
-+
-+  if (!netdev)
-+    return;
-+
-+  if (!(inf = grub_efi_net_config_from_handle (hnd, netdev, device, path)))
-+    return;
-+
-+  grub_env_set ("net_default_interface", inf->name);
-+  grub_efi_net_export_interface_vars ();
-+}
-+
-+static grub_err_t
-+grub_efi_netfs_dir (grub_device_t device, const char *path __attribute__ ((unused)),
-+		 grub_fs_dir_hook_t hook __attribute__ ((unused)),
-+		 void *hook_data __attribute__ ((unused)))
-+{
-+  if (!device->net)
-+    return grub_error (GRUB_ERR_BUG, "invalid net device");
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+grub_efi_netfs_open (struct grub_file *file_out __attribute__ ((unused)),
-+		  const char *name __attribute__ ((unused)))
-+{
-+  struct grub_file *file, *bufio;
-+
-+  file = grub_malloc (sizeof (*file));
-+  if (!file)
-+    return grub_errno;
-+
-+  grub_memcpy (file, file_out, sizeof (struct grub_file));
-+  file->device->net->name = grub_strdup (name);
-+
-+  if (!file->device->net->name)
-+    {
-+      grub_free (file);
-+      return grub_errno;
-+    }
-+
-+  efi_net_interface(open, file, name);
-+  grub_print_error ();
-+
-+  bufio = grub_bufio_open (file, 32768);
-+  if (!bufio)
-+    {
-+      grub_free (file->device->net->name);
-+      grub_free (file);
-+      return grub_errno;
-+    }
-+  grub_memcpy (file_out, bufio, sizeof (struct grub_file));
-+  grub_free (bufio);
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_ssize_t
-+grub_efihttp_chunk_read (grub_file_t file, char *buf,
-+			grub_size_t len, grub_size_t chunk_size)
-+{
-+  char *chunk = grub_malloc (chunk_size);
-+  grub_size_t sum = 0;
-+
-+  while (len)
-+    {
-+      grub_ssize_t rd;
-+      grub_size_t sz = (len > chunk_size) ? chunk_size : len;
-+
-+      rd = efi_net_interface (read, file, chunk, sz);
-+
-+      if (rd <= 0)
-+	return rd;
-+
-+      if (buf)
-+	{
-+	  grub_memcpy (buf, chunk, rd);
-+	  buf += rd;
-+	}
-+      sum += rd;
-+      len -= rd;
-+    }
-+
-+  grub_free (chunk);
-+  return sum;
-+}
-+
-+static grub_ssize_t
-+grub_efi_netfs_read (grub_file_t file __attribute__ ((unused)),
-+		  char *buf __attribute__ ((unused)), grub_size_t len __attribute__ ((unused)))
-+{
-+  if (file->offset > file->device->net->offset)
-+    {
-+      grub_efihttp_chunk_read (file, NULL, file->offset - file->device->net->offset, 10240);
-+    }
-+  else if (file->offset < file->device->net->offset)
-+    {
-+      efi_net_interface (close, file);
-+      efi_net_interface (open, file, file->device->net->name);
-+      if (file->offset)
-+	grub_efihttp_chunk_read (file, NULL, file->offset, 10240);
-+    }
-+
-+  return efi_net_interface (read, file, buf, len);
-+}
-+
-+static grub_err_t
-+grub_efi_netfs_close (grub_file_t file)
-+{
-+  efi_net_interface (close, file);
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_efi_handle_t
-+grub_efi_service_binding (grub_efi_handle_t dev, grub_efi_guid_t *service_binding_guid)
-+{
-+  grub_efi_service_binding_t *service;
-+  grub_efi_status_t status;
-+  grub_efi_handle_t child_dev = NULL;
-+
-+  service = grub_efi_open_protocol (dev, service_binding_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-+  if (!service)
-+    {
-+      grub_error (GRUB_ERR_IO, N_("couldn't open efi service binding protocol"));
-+      return NULL;
-+    }
-+
-+  status = efi_call_2 (service->create_child, service, &child_dev);
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      grub_error (GRUB_ERR_IO, N_("Failed to create child device of http service %x"), status);
-+      return NULL;
-+    }
-+
-+  return child_dev;
-+}
-+
-+static grub_err_t
-+grub_efi_net_parse_address (const char *address,
-+    grub_efi_ip4_config2_manual_address_t *ip4,
-+    grub_efi_ip6_config_manual_address_t *ip6,
-+    int *is_ip6,
-+    int *has_cidr)
-+{
-+  const char *rest;
-+
-+  if (grub_efi_string_to_ip4_address (address, &ip4->address, &rest))
-+    {
-+      *is_ip6 = 0;
-+      if (*rest == '/')
-+	{
-+	  grub_uint32_t subnet_mask_size;
-+
-+	  subnet_mask_size = grub_strtoul (rest + 1, (char **) &rest, 0);
-+
-+	  if (!grub_errno && subnet_mask_size <= 32 && *rest == 0)
-+	    {
-+	      grub_uint32_t subnet_mask;
-+
-+	      subnet_mask = grub_cpu_to_be32 ((0xffffffffU << (32 - subnet_mask_size)));
-+	      grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask));
-+	      if (has_cidr)
-+		*has_cidr = 1;
-+	      return GRUB_ERR_NONE;
-+	    }
-+	}
-+      else if (*rest == 0)
-+	{
-+	  grub_uint32_t subnet_mask = 0xffffffffU;
-+	  grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask));
-+	  if (has_cidr)
-+	    *has_cidr = 0;
-+	  return GRUB_ERR_NONE;
-+	}
-+    }
-+  else if (grub_efi_string_to_ip6_address (address, &ip6->address, &rest))
-+    {
-+      *is_ip6 = 1;
-+      if (*rest == '/')
-+	{
-+	  grub_efi_uint8_t prefix_length;
-+
-+	  prefix_length = grub_strtoul (rest + 1, (char **) &rest, 0);
-+	  if (!grub_errno && prefix_length <= 128 && *rest == 0)
-+	    {
-+	      ip6->prefix_length = prefix_length;
-+	      ip6->is_anycast = 0;
-+	      if (has_cidr)
-+		*has_cidr = 1;
-+	      return GRUB_ERR_NONE;
-+	    }
-+	}
-+      else if (*rest == 0)
-+	{
-+	  ip6->prefix_length = 128;
-+	  ip6->is_anycast = 0;
-+	  if (has_cidr)
-+	    *has_cidr = 0;
-+	  return GRUB_ERR_NONE;
-+	}
-+    }
-+
-+  return grub_error (GRUB_ERR_NET_BAD_ADDRESS,
-+		   N_("unrecognised network address `%s'"),
-+		   address);
-+}
-+
-+static grub_efi_net_interface_t *
-+match_route (const char *server)
-+{
-+  grub_err_t err;
-+  grub_efi_ip4_config2_manual_address_t ip4;
-+  grub_efi_ip6_config_manual_address_t ip6;
-+  grub_efi_net_interface_t *inf;
-+  int is_ip6 = 0;
-+
-+  err = grub_efi_net_parse_address (server, &ip4, &ip6, &is_ip6, 0);
-+
-+  if (err)
-+    {
-+      grub_print_error ();
-+      return NULL;
-+    }
-+
-+  if (is_ip6)
-+    {
-+      struct grub_efi_net_device *dev;
-+      grub_efi_net_ip_address_t addr;
-+
-+      grub_memcpy (addr.ip6, ip6.address, sizeof(ip6.address));
-+
-+      for (dev = net_devices; dev; dev = dev->next)
-+	  if ((inf = efi_net_ip6_config->best_interface (dev, &addr)))
-+	    return inf;
-+    }
-+  else
-+    {
-+      struct grub_efi_net_device *dev;
-+      grub_efi_net_ip_address_t addr;
-+
-+      grub_memcpy (addr.ip4, ip4.address, sizeof(ip4.address));
-+
-+      for (dev = net_devices; dev; dev = dev->next)
-+	  if ((inf = efi_net_ip4_config->best_interface (dev, &addr)))
-+	    return inf;
-+    }
-+
-+  return 0;
-+}
-+
-+static void
-+grub_efi_net_add_pxebc_to_cards (void)
-+{
-+  grub_efi_uintn_t num_handles;
-+  grub_efi_handle_t *handles;
-+  grub_efi_handle_t *handle;
-+
-+  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &pxe_io_guid,
-+				    0, &num_handles);
-+  if (!handles)
-+    return;
-+
-+  for (handle = handles; num_handles--; handle++)
-+    {
-+      grub_efi_device_path_t *dp, *ddp, *ldp;
-+      grub_efi_pxe_t *pxe;
-+      struct grub_efi_net_device *d;
-+      int is_ip6 = 0;
-+
-+      dp = grub_efi_get_device_path (*handle);
-+      if (!dp)
-+	continue;
-+
-+      ddp = grub_efi_duplicate_device_path (dp);
-+      ldp = grub_efi_find_last_device_path (ddp);
-+
-+      if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
-+	  && ldp->subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE)
-+	{
-+	  ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
-+	  ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
-+	  ldp->length = sizeof (*ldp);
-+	}
-+      else if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
-+	  && ldp->subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)
-+	{
-+	  is_ip6 = 1;
-+	  ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
-+	  ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
-+	  ldp->length = sizeof (*ldp);
-+	}
-+
-+      for (d = net_devices; d; d = d->next)
-+	if (grub_efi_compare_device_paths (ddp, grub_efi_get_device_path (d->handle)) == 0)
-+	  break;
-+
-+      if (!d)
-+	{
-+	  grub_free (ddp);
-+	  continue;
-+	}
-+
-+      pxe = grub_efi_open_protocol (*handle, &pxe_io_guid,
-+				GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-+
-+      if (!pxe)
-+	{
-+	  grub_free (ddp);
-+	  continue;
-+	}
-+
-+      if (is_ip6)
-+	{
-+	  d->ip6_pxe_handle = *handle;
-+	  d->ip6_pxe = pxe;
-+	}
-+      else
-+	{
-+	  d->ip4_pxe_handle = *handle;
-+	  d->ip4_pxe = pxe;
-+	}
-+
-+      grub_free (ddp);
-+    }
-+
-+  grub_free (handles);
-+}
-+
-+static void
-+set_ip_policy_to_static (void)
-+{
-+  struct grub_efi_net_device *dev;
-+
-+  for (dev = net_devices; dev; dev = dev->next)
-+    {
-+      grub_efi_ip4_config2_policy_t ip4_policy = GRUB_EFI_IP4_CONFIG2_POLICY_STATIC;
-+
-+      if (efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
-+		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
-+		    sizeof (ip4_policy), &ip4_policy) != GRUB_EFI_SUCCESS)
-+	grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP4_CONFIG2_POLICY_STATIC on dev `%s'", dev->card_name);
-+
-+      if (dev->ip6_config)
-+	{
-+	  grub_efi_ip6_config_policy_t ip6_policy = GRUB_EFI_IP6_CONFIG_POLICY_MANUAL;
-+
-+	  if (efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
-+		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY,
-+		    sizeof (ip6_policy), &ip6_policy) != GRUB_EFI_SUCCESS)
-+	    grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP6_CONFIG_POLICY_MANUAL on dev `%s'", dev->card_name);
-+	}
-+    }
-+}
-+
-+/* FIXME: Do not fail if the card did not support any of the protocol (Eg http) */
-+static void
-+grub_efi_net_find_cards (void)
-+{
-+  grub_efi_uintn_t num_handles;
-+  grub_efi_handle_t *handles;
-+  grub_efi_handle_t *handle;
-+  int id;
-+
-+  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &ip4_config_guid,
-+				    0, &num_handles);
-+  if (!handles)
-+    return;
-+
-+  for (id = 0, handle = handles; num_handles--; handle++, id++)
-+    {
-+      grub_efi_device_path_t *dp;
-+      grub_efi_ip4_config2_protocol_t *ip4_config;
-+      grub_efi_ip6_config_protocol_t *ip6_config;
-+      grub_efi_handle_t http_handle;
-+      grub_efi_http_t *http;
-+      grub_efi_handle_t dhcp4_handle;
-+      grub_efi_dhcp4_protocol_t *dhcp4;
-+      grub_efi_handle_t dhcp6_handle;
-+      grub_efi_dhcp6_protocol_t *dhcp6;
-+
-+      struct grub_efi_net_device *d;
-+
-+      dp = grub_efi_get_device_path (*handle);
-+      if (!dp)
-+	continue;
-+
-+      ip4_config = grub_efi_open_protocol (*handle, &ip4_config_guid,
-+				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-+      if (!ip4_config)
-+	continue;
-+
-+      ip6_config = grub_efi_open_protocol (*handle, &ip6_config_guid,
-+				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-+
-+      http_handle = grub_efi_service_binding (*handle, &http_service_binding_guid);
-+      grub_errno = GRUB_ERR_NONE;
-+      http = (http_handle)
-+	? grub_efi_open_protocol (http_handle, &http_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL)
-+	: NULL;
-+
-+      dhcp4_handle = grub_efi_service_binding (*handle, &dhcp4_service_binding_guid);
-+      grub_errno = GRUB_ERR_NONE;
-+      dhcp4 = (dhcp4_handle)
-+	? grub_efi_open_protocol (dhcp4_handle, &dhcp4_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL)
-+	: NULL;
-+
-+
-+      dhcp6_handle = grub_efi_service_binding (*handle, &dhcp6_service_binding_guid);
-+      grub_errno = GRUB_ERR_NONE;
-+      dhcp6 = (dhcp6_handle)
-+	? grub_efi_open_protocol (dhcp6_handle, &dhcp6_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL)
-+	: NULL;
-+
-+      d = grub_malloc (sizeof (*d));
-+      if (!d)
-+	{
-+	  grub_free (handles);
-+	  while (net_devices)
-+	    {
-+	      d = net_devices->next;
-+	      grub_free (net_devices);
-+	      net_devices = d;
-+	    }
-+	  return;
-+	}
-+      d->handle = *handle;
-+      d->ip4_config = ip4_config;
-+      d->ip6_config = ip6_config;
-+      d->http_handle = http_handle;
-+      d->http = http;
-+      d->dhcp4_handle = dhcp4_handle;
-+      d->dhcp4 = dhcp4;
-+      d->dhcp6_handle = dhcp6_handle;
-+      d->dhcp6 = dhcp6;
-+      d->next = net_devices;
-+      d->card_name = grub_xasprintf ("efinet%d", id);
-+      d->net_interfaces = NULL;
-+      net_devices = d;
-+    }
-+
-+  grub_efi_net_add_pxebc_to_cards ();
-+  grub_free (handles);
-+  set_ip_policy_to_static ();
-+}
-+
-+static void
-+listroutes_ip4 (struct grub_efi_net_device *netdev)
-+{
-+  char **routes;
-+
-+  routes = NULL;
-+
-+  if ((routes = efi_net_ip4_config->get_route_table (netdev)))
-+    {
-+      char **r;
-+
-+      for (r = routes; *r; ++r)
-+	grub_printf ("%s\n", *r);
-+    }
-+
-+  if (routes)
-+    {
-+      char **r;
-+
-+      for (r = routes; *r; ++r)
-+	grub_free (*r);
-+      grub_free (routes);
-+    }
-+}
-+
-+static void
-+listroutes_ip6 (struct grub_efi_net_device *netdev)
-+{
-+  char **routes;
-+
-+  routes = NULL;
-+
-+  if ((routes = efi_net_ip6_config->get_route_table (netdev)))
-+    {
-+      char **r;
-+
-+      for (r = routes; *r; ++r)
-+	grub_printf ("%s\n", *r);
-+    }
-+
-+  if (routes)
-+    {
-+      char **r;
-+
-+      for (r = routes; *r; ++r)
-+	grub_free (*r);
-+      grub_free (routes);
-+    }
-+}
-+
-+static grub_err_t
-+grub_cmd_efi_listroutes (struct grub_command *cmd __attribute__ ((unused)),
-+		     int argc __attribute__ ((unused)),
-+		     char **args __attribute__ ((unused)))
-+{
-+  struct grub_efi_net_device *netdev;
-+
-+  for (netdev = net_devices; netdev; netdev = netdev->next)
-+    {
-+      listroutes_ip4 (netdev);
-+      listroutes_ip6 (netdev);
-+    }
-+
-+  return GRUB_ERR_NONE;
-+}
-+static grub_err_t
-+grub_cmd_efi_listcards (struct grub_command *cmd __attribute__ ((unused)),
-+		    int argc __attribute__ ((unused)),
-+		    char **args __attribute__ ((unused)))
-+{
-+  struct grub_efi_net_device *dev;
-+
-+  for (dev = net_devices; dev; dev = dev->next)
-+    {
-+      char *hw_addr;
-+
-+      hw_addr = efi_net_ip4_config->get_hw_address (dev);
-+
-+      if (hw_addr)
-+	{
-+	  grub_printf ("%s %s\n", dev->card_name, hw_addr);
-+	  grub_free (hw_addr);
-+	}
-+    }
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+grub_cmd_efi_listaddrs (struct grub_command *cmd __attribute__ ((unused)),
-+		    int argc __attribute__ ((unused)),
-+		    char **args __attribute__ ((unused)))
-+{
-+  struct grub_efi_net_device *dev;
-+  grub_efi_net_interface_t *inf;
-+
-+  for (dev = net_devices; dev; dev = dev->next)
-+    for (inf = dev->net_interfaces; inf; inf = inf->next)
-+      {
-+	char *hw_addr = NULL;
-+	char *addr = NULL;
-+
-+	if ((hw_addr = efi_net_interface_get_hw_address (inf))
-+	    && (addr = efi_net_interface_get_address (inf)))
-+	  grub_printf ("%s %s %s\n", inf->name, hw_addr, addr);
-+
-+	if (hw_addr)
-+	  grub_free (hw_addr);
-+	if (addr)
-+	  grub_free (addr);
-+      }
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+/* FIXME: support MAC specifying.  */
-+static grub_err_t
-+grub_cmd_efi_addaddr (struct grub_command *cmd __attribute__ ((unused)),
-+                  int argc, char **args)
-+{
-+  struct grub_efi_net_device *dev;
-+  grub_err_t err;
-+  grub_efi_ip4_config2_manual_address_t ip4;
-+  grub_efi_ip6_config_manual_address_t ip6;
-+  grub_efi_net_ip_manual_address_t net_ip;
-+  int is_ip6 = 0;
-+  int cidr = 0;
-+
-+  if (argc != 3)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("three arguments expected"));
-+
-+  for (dev = net_devices; dev; dev = dev->next)
-+    {
-+      if (grub_strcmp (dev->card_name, args[1]) == 0)
-+	break;
-+    }
-+
-+  if (!dev)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("card not found"));
-+
-+  err = grub_efi_net_parse_address (args[2], &ip4, &ip6, &is_ip6, &cidr);
-+
-+  if (err)
-+    return err;
-+
-+  net_ip.is_ip6 = is_ip6;
-+  if (is_ip6)
-+    grub_memcpy (&net_ip.ip6, &ip6, sizeof(net_ip.ip6));
-+  else
-+    grub_memcpy (&net_ip.ip4, &ip4, sizeof(net_ip.ip4));
-+
-+  if (!grub_efi_net_create_interface (dev,
-+		args[0],
-+		&net_ip,
-+		cidr))
-+    return grub_errno;
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static struct grub_fs grub_efi_netfs;
-+
-+static grub_net_t
-+grub_net_open_real (const char *name __attribute__ ((unused)))
-+{
-+  grub_size_t protnamelen;
-+  const char *protname, *server;
-+  grub_net_t ret;
-+
-+  net_interface = NULL;
-+
-+  if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
-+    {
-+      protname = "tftp";
-+      protnamelen = sizeof ("tftp") - 1;
-+      server = name + sizeof ("pxe:") - 1;
-+    }
-+  else if (grub_strcmp (name, "pxe") == 0)
-+    {
-+      protname = "tftp";
-+      protnamelen = sizeof ("tftp") - 1;
-+      server = default_server;
-+    }
-+  else
-+    {
-+      const char *comma;
-+
-+      comma = grub_strchr (name, ',');
-+      if (comma)
-+	{
-+	  protnamelen = comma - name;
-+	  server = comma + 1;
-+	  protname = name;
-+	}
-+      else
-+	{
-+	  protnamelen = grub_strlen (name);
-+	  server = default_server;
-+	  protname = name;
-+	}
-+    }
-+
-+  if (!server)
-+    {
-+      grub_error (GRUB_ERR_NET_BAD_ADDRESS,
-+		  N_("no server is specified"));
-+      return NULL;
-+    }
-+
-+  /*FIXME: Use DNS translate name to address */
-+  net_interface = match_route (server);
-+
-+  /*XXX: should we check device with default gateway ? */
-+  if (!net_interface && !(net_interface = net_default_interface))
-+    {
-+      grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' no route found"),
-+		  name);
-+      return NULL;
-+    }
-+
-+  if ((protnamelen == (sizeof ("https") - 1)
-+	&& grub_memcmp ("https", protname, protnamelen) == 0))
-+    {
-+      net_interface->io = &io_http;
-+      net_interface->io_type = 1;
-+    }
-+  else if ((protnamelen == (sizeof ("http") - 1)
-+	&& grub_memcmp ("http", protname, protnamelen) == 0))
-+    {
-+      net_interface->io = &io_http;
-+      net_interface->io_type = 0;
-+    }
-+  else if (protnamelen == (sizeof ("tftp") - 1)
-+	&& grub_memcmp ("tftp", protname, protnamelen) == 0)
-+    {
-+      net_interface->io = &io_pxe;
-+      net_interface->io_type = 0;
-+    }
-+  else
-+    {
-+      grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"),
-+		  name);
-+      return NULL;
-+    }
-+
-+  /*XXX: Should we try to avoid doing excess "reconfigure" here ??? */
-+  efi_net_interface (configure);
-+
-+  ret = grub_zalloc (sizeof (*ret));
-+  if (!ret)
-+    return NULL;
-+
-+  ret->server = grub_strdup (server);
-+  if (!ret->server)
-+    {
-+      grub_free (ret);
-+      return NULL;
-+    }
-+
-+  ret->fs = &grub_efi_netfs;
-+  return ret;
-+}
-+#if 0
-+static grub_command_t cmd_efi_lsaddr;
-+static grub_command_t cmd_efi_lscards;
-+static grub_command_t cmd_efi_lsroutes;
-+static grub_command_t cmd_efi_addaddr;
-+#endif
-+
-+static struct grub_fs grub_efi_netfs =
-+  {
-+    .name = "efi netfs",
-+    .fs_dir = grub_efi_netfs_dir,
-+    .fs_open = grub_efi_netfs_open,
-+    .fs_read = grub_efi_netfs_read,
-+    .fs_close = grub_efi_netfs_close,
-+    .fs_label = NULL,
-+    .fs_uuid = NULL,
-+    .fs_mtime = NULL,
-+  };
-+
-+int
-+grub_efi_net_boot_from_https (void)
-+{
-+  grub_efi_loaded_image_t *image = NULL;
-+  grub_efi_device_path_t *dp;
-+
-+  image = grub_efi_get_loaded_image (grub_efi_image_handle);
-+  if (!image)
-+    return 0;
-+
-+  dp = grub_efi_get_device_path (image->device_handle);
-+
-+  while (1)
-+    {
-+      grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
-+      grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
-+      grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp);
-+
-+      if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE)
-+	  && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
-+	{
-+	  grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp;
-+	  return (grub_strncmp ((const char*)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0) ? 1 : 0;
-+	}
-+
-+      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
-+        break;
-+      dp = (grub_efi_device_path_t *) ((char *) dp + len);
-+    }
-+
-+  return 0;
-+}
-+
-+int
-+grub_efi_net_boot_from_opa (void)
-+{
-+  grub_efi_loaded_image_t *image = NULL;
-+  grub_efi_device_path_t *dp;
-+
-+  image = grub_efi_get_loaded_image (grub_efi_image_handle);
-+  if (!image)
-+    return 0;
-+
-+  dp = grub_efi_get_device_path (image->device_handle);
-+
-+  while (1)
-+    {
-+      grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
-+      grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
-+      grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp);
-+
-+      if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE)
-+	  && (subtype == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE))
-+	{
-+	  grub_efi_mac_address_device_path_t *mac_dp  = (grub_efi_mac_address_device_path_t *)dp;
-+	  return (mac_dp->if_type == 0xC7) ? 1 : 0;
-+	}
-+
-+      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
-+        break;
-+      dp = (grub_efi_device_path_t *) ((char *) dp + len);
-+    }
-+
-+  return 0;
-+}
-+
-+static char *
-+grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
-+			 const char *val __attribute__ ((unused)))
-+{
-+  return NULL;
-+}
-+
-+grub_command_func_t grub_efi_net_list_routes = grub_cmd_efi_listroutes;
-+grub_command_func_t grub_efi_net_list_cards = grub_cmd_efi_listcards;
-+grub_command_func_t grub_efi_net_list_addrs = grub_cmd_efi_listaddrs;
-+grub_command_func_t grub_efi_net_add_addr = grub_cmd_efi_addaddr;
-+
-+int
-+grub_efi_net_fs_init ()
-+{
-+  grub_efi_net_find_cards ();
-+  grub_efi_net_config = grub_efi_net_config_real;
-+  grub_net_open = grub_net_open_real;
-+  grub_register_variable_hook ("net_default_server", grub_efi_net_var_get_server,
-+			       grub_efi_net_var_set_server);
-+  grub_env_export ("net_default_server");
-+  grub_register_variable_hook ("pxe_default_server", grub_efi_net_var_get_server,
-+			       grub_efi_net_var_set_server);
-+  grub_env_export ("pxe_default_server");
-+  grub_register_variable_hook ("net_default_interface", 0,
-+			       grub_efi_net_var_set_interface);
-+  grub_env_export ("net_default_interface");
-+  grub_register_variable_hook ("net_default_ip", grub_efi_net_var_get_ip,
-+			       0);
-+  grub_env_export ("net_default_ip");
-+  grub_register_variable_hook ("net_default_mac", grub_efi_net_var_get_mac,
-+			       0);
-+  grub_env_export ("net_default_mac");
-+
-+  grub_env_set ("grub_netfs_type", "efi");
-+  grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly);
-+  grub_env_export ("grub_netfs_type");
-+
-+  return 1;
-+}
-+
-+void
-+grub_efi_net_fs_fini (void)
-+{
-+  grub_env_unset ("grub_netfs_type");
-+  grub_efi_net_unset_interface_vars ();
-+  grub_register_variable_hook ("net_default_server", 0, 0);
-+  grub_env_unset ("net_default_server");
-+  grub_register_variable_hook ("net_default_interface", 0, 0);
-+  grub_env_unset ("net_default_interface");
-+  grub_register_variable_hook ("pxe_default_server", 0, 0);
-+  grub_env_unset ("pxe_default_server");
-+  grub_register_variable_hook ("net_default_ip", 0, 0);
-+  grub_env_unset ("net_default_ip");
-+  grub_register_variable_hook ("net_default_mac", 0, 0);
-+  grub_env_unset ("net_default_mac");
-+  grub_efi_net_config = NULL;
-+  grub_net_open = NULL;
-+  grub_fs_unregister (&grub_efi_netfs);
-+}
-diff --git a/grub-core/net/efi/pxe.c b/grub-core/net/efi/pxe.c
-new file mode 100644
-index 00000000000..531949cba5c
---- /dev/null
-+++ b/grub-core/net/efi/pxe.c
-@@ -0,0 +1,424 @@
-+
-+#include <grub/efi/api.h>
-+#include <grub/efi/efi.h>
-+#include <grub/misc.h>
-+#include <grub/net/efi.h>
-+#include <grub/charset.h>
-+
-+static grub_efi_ip6_config_manual_address_t *
-+efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config)
-+{
-+  grub_efi_uintn_t sz;
-+  grub_efi_status_t status;
-+  grub_efi_ip6_config_manual_address_t *manual_address;
-+
-+  sz = sizeof (*manual_address);
-+  manual_address = grub_malloc (sz);
-+  if (!manual_address)
-+    return NULL;
-+
-+  status = efi_call_4 (ip6_config->get_data, ip6_config,
-+		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
-+		    &sz, manual_address);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      grub_free (manual_address);
-+      return NULL;
-+    }
-+
-+  return manual_address;
-+}
-+
-+static grub_efi_ip4_config2_manual_address_t *
-+efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config)
-+{
-+  grub_efi_uintn_t sz;
-+  grub_efi_status_t status;
-+  grub_efi_ip4_config2_manual_address_t *manual_address;
-+
-+  sz = sizeof (*manual_address);
-+  manual_address = grub_malloc (sz);
-+  if (!manual_address)
-+    return NULL;
-+
-+  status = efi_call_4 (ip4_config->get_data, ip4_config,
-+		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
-+		    &sz, manual_address);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      grub_free (manual_address);
-+      return NULL;
-+    }
-+
-+  return manual_address;
-+}
-+
-+static void
-+pxe_configure (struct grub_efi_net_device *dev, int prefer_ip6)
-+{
-+  grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe;
-+
-+  grub_efi_pxe_mode_t *mode = pxe->mode;
-+
-+  if (!mode->started)
-+    {
-+      grub_efi_status_t status;
-+      status = efi_call_2 (pxe->start, pxe, prefer_ip6);
-+
-+      if (status != GRUB_EFI_SUCCESS)
-+	  grub_printf ("Couldn't start PXE\n");
-+    }
-+
-+#if 0
-+  grub_printf ("PXE STARTED: %u\n", mode->started);
-+  grub_printf ("PXE USING IPV6: %u\n", mode->using_ipv6);
-+#endif
-+
-+  if (mode->using_ipv6)
-+    {
-+      grub_efi_ip6_config_manual_address_t *manual_address;
-+      manual_address = efi_ip6_config_manual_address (dev->ip6_config);
-+
-+      if (manual_address &&
-+	  grub_memcmp (manual_address->address, mode->station_ip.v6, sizeof (manual_address->address)) != 0)
-+	{
-+	  grub_efi_status_t status;
-+	  grub_efi_pxe_ip_address_t station_ip;
-+
-+	  grub_memcpy (station_ip.v6.addr, manual_address->address, sizeof (station_ip.v6.addr));
-+	  status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, NULL);
-+
-+	  if (status != GRUB_EFI_SUCCESS)
-+	      grub_printf ("Couldn't set station ip\n");
-+
-+	  grub_free (manual_address);
-+	}
-+    }
-+  else
-+    {
-+      grub_efi_ip4_config2_manual_address_t *manual_address;
-+      manual_address = efi_ip4_config_manual_address (dev->ip4_config);
-+
-+      if (manual_address &&
-+	  grub_memcmp (manual_address->address, mode->station_ip.v4, sizeof (manual_address->address)) != 0)
-+	{
-+	  grub_efi_status_t status;
-+	  grub_efi_pxe_ip_address_t station_ip;
-+	  grub_efi_pxe_ip_address_t subnet_mask;
-+
-+	  grub_memcpy (station_ip.v4.addr, manual_address->address, sizeof (station_ip.v4.addr));
-+	  grub_memcpy (subnet_mask.v4.addr, manual_address->subnet_mask, sizeof (subnet_mask.v4.addr));
-+
-+	  status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, &subnet_mask);
-+
-+	  if (status != GRUB_EFI_SUCCESS)
-+	      grub_printf ("Couldn't set station ip\n");
-+
-+	  grub_free (manual_address);
-+	}
-+    }
-+
-+#if 0
-+  if (mode->using_ipv6)
-+    {
-+      grub_printf ("PXE STATION IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
-+	mode->station_ip.v6.addr[0],
-+	mode->station_ip.v6.addr[1],
-+	mode->station_ip.v6.addr[2],
-+	mode->station_ip.v6.addr[3],
-+	mode->station_ip.v6.addr[4],
-+	mode->station_ip.v6.addr[5],
-+	mode->station_ip.v6.addr[6],
-+	mode->station_ip.v6.addr[7],
-+	mode->station_ip.v6.addr[8],
-+	mode->station_ip.v6.addr[9],
-+	mode->station_ip.v6.addr[10],
-+	mode->station_ip.v6.addr[11],
-+	mode->station_ip.v6.addr[12],
-+	mode->station_ip.v6.addr[13],
-+	mode->station_ip.v6.addr[14],
-+	mode->station_ip.v6.addr[15]);
-+    }
-+  else
-+    {
-+      grub_printf ("PXE STATION IP: %d.%d.%d.%d\n",
-+	mode->station_ip.v4.addr[0],
-+	mode->station_ip.v4.addr[1],
-+	mode->station_ip.v4.addr[2],
-+	mode->station_ip.v4.addr[3]);
-+      grub_printf ("PXE SUBNET MASK: %d.%d.%d.%d\n",
-+	mode->subnet_mask.v4.addr[0],
-+	mode->subnet_mask.v4.addr[1],
-+	mode->subnet_mask.v4.addr[2],
-+	mode->subnet_mask.v4.addr[3]);
-+    }
-+#endif
-+
-+  /* TODO: Set The Station IP to the IP2 Config */
-+}
-+
-+static int
-+parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
-+{
-+  grub_uint16_t newip[8];
-+  const char *ptr = val;
-+  int word, quaddot = -1;
-+  int bracketed = 0;
-+
-+  if (ptr[0] == '[') {
-+    bracketed = 1;
-+    ptr++;
-+  }
-+
-+  if (ptr[0] == ':' && ptr[1] != ':')
-+    return 0;
-+  if (ptr[0] == ':')
-+    ptr++;
-+
-+  for (word = 0; word < 8; word++)
-+    {
-+      unsigned long t;
-+      if (*ptr == ':')
-+	{
-+	  quaddot = word;
-+	  word--;
-+	  ptr++;
-+	  continue;
-+	}
-+      t = grub_strtoul (ptr, (char **) &ptr, 16);
-+      if (grub_errno)
-+	{
-+	  grub_errno = GRUB_ERR_NONE;
-+	  break;
-+	}
-+      if (t & ~0xffff)
-+	return 0;
-+      newip[word] = grub_cpu_to_be16 (t);
-+      if (*ptr != ':')
-+	break;
-+      ptr++;
-+    }
-+  if (quaddot == -1 && word < 7)
-+    return 0;
-+  if (quaddot != -1)
-+    {
-+      grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot],
-+		    (word - quaddot + 1) * sizeof (newip[0]));
-+      grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
-+    }
-+  grub_memcpy (ip, newip, 16);
-+  if (bracketed && *ptr == ']') {
-+    ptr++;
-+  }
-+  if (rest)
-+    *rest = ptr;
-+  return 1;
-+}
-+
-+static grub_err_t
-+pxe_open (struct grub_efi_net_device *dev,
-+	  int prefer_ip6,
-+	  grub_file_t file,
-+	  const char *filename,
-+	  int type __attribute__((unused)))
-+{
-+  int i;
-+  char *p;
-+  grub_efi_status_t status;
-+  grub_efi_pxe_ip_address_t server_ip;
-+  grub_efi_uint64_t file_size = 0;
-+  grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe;
-+
-+  if (pxe->mode->using_ipv6)
-+    {
-+      const char *rest;
-+      grub_uint64_t ip6[2];
-+      if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0)
-+	grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr));
-+      /* TODO: ERROR Handling Here */
-+#if 0
-+      grub_printf ("PXE SERVER IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
-+	server_ip.v6.addr[0],
-+	server_ip.v6.addr[1],
-+	server_ip.v6.addr[2],
-+	server_ip.v6.addr[3],
-+	server_ip.v6.addr[4],
-+	server_ip.v6.addr[5],
-+	server_ip.v6.addr[6],
-+	server_ip.v6.addr[7],
-+	server_ip.v6.addr[8],
-+	server_ip.v6.addr[9],
-+	server_ip.v6.addr[10],
-+	server_ip.v6.addr[11],
-+	server_ip.v6.addr[12],
-+	server_ip.v6.addr[13],
-+	server_ip.v6.addr[14],
-+	server_ip.v6.addr[15]);
-+#endif
-+    }
-+  else
-+    {
-+      for (i = 0, p = file->device->net->server; i < 4; ++i, ++p)
-+	server_ip.v4.addr[i] = grub_strtoul (p, &p, 10);
-+    }
-+
-+  status = efi_call_10 (pxe->mtftp,
-+	    pxe,
-+	    GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
-+	    NULL,
-+	    0,
-+	    &file_size,
-+	    NULL,
-+	    &server_ip,
-+	    (grub_efi_char8_t *)filename,
-+	    NULL,
-+	    0);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    return grub_error (GRUB_ERR_IO, "Couldn't get file size");
-+
-+  file->size = (grub_off_t)file_size;
-+  file->not_easily_seekable = 0;
-+  file->data = 0;
-+  file->device->net->offset = 0;
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+pxe_close (struct grub_efi_net_device *dev __attribute__((unused)),
-+	  int prefer_ip6 __attribute__((unused)),
-+	  grub_file_t file __attribute__((unused)))
-+{
-+  file->offset = 0;
-+  file->size = 0;
-+  file->device->net->offset = 0;
-+
-+  if (file->data)
-+    {
-+      grub_free (file->data);
-+      file->data = NULL;
-+    }
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_ssize_t
-+pxe_read (struct grub_efi_net_device *dev,
-+	  int prefer_ip6,
-+	  grub_file_t file,
-+	  char *buf,
-+	  grub_size_t len)
-+{
-+  int i;
-+  char *p;
-+  grub_efi_status_t status;
-+  grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe;
-+  grub_efi_uint64_t bufsz = len;
-+  grub_efi_pxe_ip_address_t server_ip;
-+  char *buf2 = NULL;
-+
-+  if (file->data)
-+    {
-+      /* TODO: RANGE Check for offset and file size */
-+      grub_memcpy (buf, (char*)file->data + file->device->net->offset, len);
-+      file->device->net->offset += len;
-+      return len;
-+    }
-+
-+  if (file->device->net->offset)
-+    {
-+      grub_error (GRUB_ERR_BUG, "No Offet Read Possible");
-+      grub_print_error ();
-+      return 0;
-+    }
-+
-+  if (pxe->mode->using_ipv6)
-+    {
-+      const char *rest;
-+      grub_uint64_t ip6[2];
-+      if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0)
-+	grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr));
-+      /* TODO: ERROR Handling Here */
-+    }
-+  else
-+    {
-+      for (i = 0, p = file->device->net->server; i < 4; ++i, ++p)
-+	server_ip.v4.addr[i] = grub_strtoul (p, &p, 10);
-+    }
-+
-+  status = efi_call_10 (pxe->mtftp,
-+	    pxe,
-+	    GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE,
-+	    buf,
-+	    0,
-+	    &bufsz,
-+	    NULL,
-+	    &server_ip,
-+	    (grub_efi_char8_t *)file->device->net->name,
-+	    NULL,
-+	    0);
-+
-+  if (bufsz != file->size)
-+    {
-+      grub_error (GRUB_ERR_BUG, "Short read should not happen here");
-+      grub_print_error ();
-+      return 0;
-+    }
-+
-+  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
-+    {
-+
-+      buf2 = grub_malloc (bufsz);
-+
-+      if (!buf2)
-+	{
-+	  grub_error (GRUB_ERR_OUT_OF_MEMORY, "ERROR OUT OF MEMORY");
-+	  grub_print_error ();
-+	  return 0;
-+	}
-+
-+      status = efi_call_10 (pxe->mtftp,
-+		pxe,
-+		GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE,
-+		buf2,
-+		0,
-+		&bufsz,
-+		NULL,
-+		&server_ip,
-+		(grub_efi_char8_t *)file->device->net->name,
-+		NULL,
-+		0);
-+    }
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      if (buf2)
-+	grub_free (buf2);
-+
-+      grub_error (GRUB_ERR_IO, "Failed to Read File");
-+      grub_print_error ();
-+      return 0;
-+    }
-+
-+  if (buf2)
-+    grub_memcpy (buf, buf2, len);
-+
-+  file->device->net->offset = len;
-+
-+  if (buf2)
-+    file->data = buf2;
-+
-+  return len;
-+}
-+
-+struct grub_efi_net_io io_pxe =
-+  {
-+    .configure = pxe_configure,
-+    .open = pxe_open,
-+    .read = pxe_read,
-+    .close = pxe_close
-+  };
-+
-diff --git a/grub-core/net/net.c b/grub-core/net/net.c
-index 0ce5e675ed7..55aed92722c 100644
---- a/grub-core/net/net.c
-+++ b/grub-core/net/net.c
-@@ -32,6 +32,9 @@
- #include <grub/loader.h>
- #include <grub/bufio.h>
- #include <grub/kernel.h>
-+#ifdef GRUB_MACHINE_EFI
-+#include <grub/net/efi.h>
-+#endif
- 
- GRUB_MOD_LICENSE ("GPLv3+");
- 
-@@ -2033,8 +2036,49 @@ static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute;
- static grub_command_t cmd_lsroutes, cmd_lscards;
- static grub_command_t cmd_lsaddr, cmd_slaac;
- 
-+#ifdef GRUB_MACHINE_EFI
-+
-+static enum {
-+  INIT_MODE_NONE,
-+  INIT_MODE_GRUB,
-+  INIT_MODE_EFI
-+} init_mode;
-+
-+static grub_command_t cmd_bootp, cmd_bootp6;
-+
-+#endif
-+
- GRUB_MOD_INIT(net)
- {
-+#ifdef GRUB_MACHINE_EFI
-+  if (grub_net_open)
-+    return;
-+
-+  if ((grub_efi_net_boot_from_https () || grub_efi_net_boot_from_opa ())
-+      && grub_efi_net_fs_init ())
-+    {
-+      cmd_lsroutes = grub_register_command ("net_ls_routes", grub_efi_net_list_routes,
-+					    "", N_("list network routes"));
-+      cmd_lscards = grub_register_command ("net_ls_cards", grub_efi_net_list_cards,
-+					   "", N_("list network cards"));
-+      cmd_lsaddr = grub_register_command ("net_ls_addr", grub_efi_net_list_addrs,
-+					  "", N_("list network addresses"));
-+      cmd_addaddr = grub_register_command ("net_add_addr", grub_efi_net_add_addr,
-+					    /* TRANSLATORS: HWADDRESS stands for
-+					       "hardware address".  */
-+					  N_("SHORTNAME CARD ADDRESS [HWADDRESS]"),
-+					  N_("Add a network address."));
-+      cmd_bootp = grub_register_command ("net_bootp", grub_efi_net_bootp,
-+					 N_("[CARD]"),
-+					 N_("perform a bootp autoconfiguration"));
-+      cmd_bootp6 = grub_register_command ("net_bootp6", grub_efi_net_bootp6,
-+					 N_("[CARD]"),
-+					 N_("perform a bootp autoconfiguration"));
-+      init_mode = INIT_MODE_EFI;
-+      return;
-+    }
-+#endif
-+
-   grub_register_variable_hook ("net_default_server", defserver_get_env,
- 			       defserver_set_env);
-   grub_env_export ("net_default_server");
-@@ -2082,10 +2126,37 @@ GRUB_MOD_INIT(net)
- 						grub_net_restore_hw,
- 						GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK);
-   grub_net_poll_cards_idle = grub_net_poll_cards_idle_real;
-+
-+#ifdef GRUB_MACHINE_EFI
-+  grub_env_set ("grub_netfs_type", "grub");
-+  grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly);
-+  grub_env_export ("grub_netfs_type");
-+  init_mode = INIT_MODE_GRUB;
-+#endif
-+
- }
- 
- GRUB_MOD_FINI(net)
- {
-+
-+#ifdef GRUB_MACHINE_EFI
-+  if (init_mode == INIT_MODE_NONE)
-+    return;
-+
-+  if (init_mode == INIT_MODE_EFI)
-+    {
-+      grub_unregister_command (cmd_lsroutes);
-+      grub_unregister_command (cmd_lscards);
-+      grub_unregister_command (cmd_lsaddr);
-+      grub_unregister_command (cmd_addaddr);
-+      grub_unregister_command (cmd_bootp);
-+      grub_unregister_command (cmd_bootp6);
-+      grub_efi_net_fs_fini ();
-+      init_mode = INIT_MODE_NONE;
-+      return;
-+    }
-+#endif
-+
-   grub_register_variable_hook ("net_default_server", 0, 0);
-   grub_register_variable_hook ("pxe_default_server", 0, 0);
- 
-@@ -2104,4 +2175,7 @@ GRUB_MOD_FINI(net)
-   grub_net_fini_hw (0);
-   grub_loader_unregister_preboot_hook (fini_hnd);
-   grub_net_poll_cards_idle = grub_net_poll_cards_idle_real;
-+#ifdef GRUB_MACHINE_EFI
-+  init_mode = INIT_MODE_NONE;
-+#endif
- }
-diff --git a/util/grub-mknetdir.c b/util/grub-mknetdir.c
-index a2461cda1c4..77958dd9dd5 100644
---- a/util/grub-mknetdir.c
-+++ b/util/grub-mknetdir.c
-@@ -32,13 +32,15 @@
- 
- static char *rootdir = NULL, *subdir = NULL;
- static char *debug_image = NULL;
-+static char efi_netfs = 0;
- 
- enum
-   {
-     OPTION_NET_DIRECTORY = 0x301,
-     OPTION_SUBDIR,
-     OPTION_DEBUG,
--    OPTION_DEBUG_IMAGE
-+    OPTION_DEBUG_IMAGE,
-+    OPTION_DEBUG_EFI_NETFS
-   };
- 
- static struct argp_option options[] = {
-@@ -49,6 +51,7 @@ static struct argp_option options[] = {
-    0, N_("relative subdirectory on network server"), 2},
-   {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2},
-   {"debug-image", OPTION_DEBUG_IMAGE, N_("STRING"), OPTION_HIDDEN, 0, 2},
-+  {"debug-efi-netfs", OPTION_DEBUG_EFI_NETFS, 0, OPTION_HIDDEN, 0, 2},
-   {0, 0, 0, 0, 0, 0}
- };
- 
-@@ -67,6 +70,9 @@ argp_parser (int key, char *arg, struct argp_state *state)
-       free (subdir);
-       subdir = xstrdup (arg);
-       return 0;
-+    case OPTION_DEBUG_EFI_NETFS:
-+      efi_netfs = 1;
-+      return 0;
-       /* This is an undocumented feature...  */
-     case OPTION_DEBUG:
-       verbosity++;
-@@ -82,7 +88,6 @@ argp_parser (int key, char *arg, struct argp_state *state)
-     }
- }
- 
--
- struct argp argp = {
-   options, argp_parser, NULL,
-   "\v"N_("Prepares GRUB network boot images at net_directory/subdir "
-@@ -92,7 +97,7 @@ struct argp argp = {
- 
- static char *base;
- 
--static const struct
-+static struct
- {
-   const char *mkimage_target;
-   const char *netmodule;
-@@ -156,6 +161,7 @@ process_input_dir (const char *input_dir, enum grub_install_plat platform)
-   grub_install_push_module (targets[platform].netmodule);
- 
-   output = grub_util_path_concat_ext (2, grubdir, "core", targets[platform].ext);
-+
-   grub_install_make_image_wrap (input_dir, prefix, output,
- 				0, load_cfg,
- 				targets[platform].mkimage_target, 0);
-@@ -195,7 +201,16 @@ main (int argc, char *argv[])
- 
-   grub_install_mkdir_p (base);
- 
--  grub_install_push_module ("tftp");
-+  if (!efi_netfs)
-+    {
-+      grub_install_push_module ("tftp");
-+      grub_install_push_module ("http");
-+    }
-+  else
-+    {
-+      targets[GRUB_INSTALL_PLATFORM_I386_EFI].netmodule = "efi_netfs";
-+      targets[GRUB_INSTALL_PLATFORM_X86_64_EFI].netmodule = "efi_netfs";
-+    }
- 
-   if (!grub_install_source_directory)
-     {
-diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
-index 0b490195ad9..f431f49973e 100644
---- a/include/grub/efi/api.h
-+++ b/include/grub/efi/api.h
-@@ -622,6 +622,23 @@ typedef union
- 
- typedef grub_efi_uint64_t grub_efi_physical_address_t;
- typedef grub_efi_uint64_t grub_efi_virtual_address_t;
-+typedef struct {
-+  grub_uint8_t addr[4];
-+} grub_efi_pxe_ipv4_address_t;
-+
-+typedef struct {
-+  grub_uint8_t addr[16];
-+} grub_efi_pxe_ipv6_address_t;
-+
-+typedef struct {
-+  grub_uint8_t addr[32];
-+} grub_efi_pxe_mac_address_t;
-+
-+typedef union {
-+    grub_uint32_t addr[4];
-+    grub_efi_pxe_ipv4_address_t v4;
-+    grub_efi_pxe_ipv6_address_t v6;
-+} grub_efi_pxe_ip_address_t;
- 
- struct grub_efi_guid
- {
-@@ -889,6 +906,8 @@ struct grub_efi_ipv6_device_path
-   grub_efi_uint16_t remote_port;
-   grub_efi_uint16_t protocol;
-   grub_efi_uint8_t static_ip_address;
-+  grub_efi_uint8_t prefix_length;
-+  grub_efi_ipv6_address_t gateway_ip_address;
- } GRUB_PACKED;
- typedef struct grub_efi_ipv6_device_path grub_efi_ipv6_device_path_t;
- 
-@@ -938,6 +957,15 @@ struct grub_efi_uri_device_path
- } GRUB_PACKED;
- typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t;
- 
-+#define GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE                31
-+struct grub_efi_dns_device_path
-+{
-+  grub_efi_device_path_t header;
-+  grub_efi_uint8_t is_ipv6;
-+  grub_efi_pxe_ip_address_t dns_server_ip[0];
-+} GRUB_PACKED;
-+typedef struct grub_efi_dns_device_path grub_efi_dns_device_path_t;
-+
- #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE	10
- 
- /* Media Device Path.  */
-@@ -1020,6 +1048,23 @@ struct grub_efi_bios_device_path
- } GRUB_PACKED;
- typedef struct grub_efi_bios_device_path grub_efi_bios_device_path_t;
- 
-+/* Service Binding definitions */
-+struct grub_efi_service_binding;
-+
-+typedef grub_efi_status_t
-+(*grub_efi_service_binding_create_child) (struct grub_efi_service_binding *this,
-+                                          grub_efi_handle_t *child_handle);
-+
-+typedef grub_efi_status_t
-+(*grub_efi_service_binding_destroy_child) (struct grub_efi_service_binding *this,
-+                                           grub_efi_handle_t *child_handle);
-+
-+typedef struct grub_efi_service_binding
-+{
-+  grub_efi_service_binding_create_child create_child;
-+  grub_efi_service_binding_destroy_child destroy_child;
-+} grub_efi_service_binding_t;
-+
- struct grub_efi_open_protocol_information_entry
- {
-   grub_efi_handle_t agent_handle;
-@@ -1569,23 +1614,27 @@ typedef struct grub_efi_pxe_tftp_error
-   grub_efi_char8_t error_string[127];
- } grub_efi_pxe_tftp_error_t;
- 
--typedef struct {
--  grub_uint8_t addr[4];
--} grub_efi_pxe_ipv4_address_t;
-+typedef grub_efi_uint16_t grub_efi_pxe_base_code_udp_port_t;
- 
--typedef struct {
--  grub_uint8_t addr[16];
--} grub_efi_pxe_ipv6_address_t;
-+typedef enum {
-+  GRUB_EFI_PXE_BASE_CODE_TFTP_FIRST,
-+  GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
-+  GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE,
-+  GRUB_EFI_PXE_BASE_CODE_TFTP_WRITE_FILE,
-+  GRUB_EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY,
-+  GRUB_EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE,
-+  GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_FILE,
-+  GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY,
-+  GRUB_EFI_PXE_BASE_CODE_MTFTP_LAST
-+} grub_efi_pxe_base_code_tftp_opcode_t;
- 
- typedef struct {
--  grub_uint8_t addr[32];
--} grub_efi_pxe_mac_address_t;
--
--typedef union {
--  grub_uint32_t addr[4];
--  grub_efi_pxe_ipv4_address_t v4;
--  grub_efi_pxe_ipv6_address_t v6;
--} grub_efi_pxe_ip_address_t;
-+  grub_efi_ip_address_t mcast_ip;
-+  grub_efi_pxe_base_code_udp_port_t c_port;
-+  grub_efi_pxe_base_code_udp_port_t s_port;
-+  grub_efi_uint16_t listen_timeout;
-+  grub_efi_uint16_t transmit_timeout;
-+} grub_efi_pxe_base_code_mtftp_info_t;
- 
- #define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8
- typedef struct grub_efi_pxe_ip_filter
-@@ -1652,17 +1701,31 @@ typedef struct grub_efi_pxe_mode
- typedef struct grub_efi_pxe
- {
-   grub_uint64_t rev;
--  void (*start) (void);
-+  grub_efi_status_t (*start) (struct grub_efi_pxe *this, grub_efi_boolean_t use_ipv6);
-   void (*stop) (void);
--  void (*dhcp) (void);
-+  grub_efi_status_t (*dhcp) (struct grub_efi_pxe *this,
-+			    grub_efi_boolean_t sort_offers);
-   void (*discover) (void);
--  void (*mftp) (void);
-+  grub_efi_status_t (*mtftp) (struct grub_efi_pxe *this,
-+			    grub_efi_pxe_base_code_tftp_opcode_t operation,
-+			    void *buffer_ptr,
-+			    grub_efi_boolean_t overwrite,
-+			    grub_efi_uint64_t *buffer_size,
-+			    grub_efi_uintn_t *block_size,
-+			    grub_efi_pxe_ip_address_t *server_ip,
-+			    //grub_efi_ip_address_t *server_ip,
-+			    grub_efi_char8_t *filename,
-+			    grub_efi_pxe_base_code_mtftp_info_t *info,
-+			    grub_efi_boolean_t dont_use_buffer);
-   void (*udpwrite) (void);
-   void (*udpread) (void);
-   void (*setipfilter) (void);
-   void (*arp) (void);
-   void (*setparams) (void);
--  void (*setstationip) (void);
-+  grub_efi_status_t (*set_station_ip) (struct grub_efi_pxe *this,
-+			    grub_efi_pxe_ip_address_t *new_station_ip,
-+			    grub_efi_pxe_ip_address_t *new_subnet_mask);
-+  //void (*setstationip) (void);
-   void (*setpackets) (void);
-   struct grub_efi_pxe_mode *mode;
- } grub_efi_pxe_t;
-@@ -1924,6 +1987,44 @@ struct grub_efi_ip4_config2_protocol
- };
- typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t;
- 
-+struct grub_efi_ip4_route_table {
-+  grub_efi_ipv4_address_t subnet_address;
-+  grub_efi_ipv4_address_t subnet_mask;
-+  grub_efi_ipv4_address_t gateway_address;
-+};
-+
-+typedef struct grub_efi_ip4_route_table grub_efi_ip4_route_table_t;
-+
-+#define GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32
-+
-+struct grub_efi_ip4_config2_interface_info {
-+  grub_efi_char16_t name[GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE];
-+  grub_efi_uint8_t if_type;
-+  grub_efi_uint32_t hw_address_size;
-+  grub_efi_mac_address_t hw_address;
-+  grub_efi_ipv4_address_t station_address;
-+  grub_efi_ipv4_address_t subnet_mask;
-+  grub_efi_uint32_t route_table_size;
-+  grub_efi_ip4_route_table_t *route_table;
-+};
-+
-+typedef struct grub_efi_ip4_config2_interface_info grub_efi_ip4_config2_interface_info_t;
-+
-+enum grub_efi_ip4_config2_policy {
-+  GRUB_EFI_IP4_CONFIG2_POLICY_STATIC,
-+  GRUB_EFI_IP4_CONFIG2_POLICY_DHCP,
-+  GRUB_EFI_IP4_CONFIG2_POLICY_MAX
-+};
-+
-+typedef enum grub_efi_ip4_config2_policy grub_efi_ip4_config2_policy_t;
-+
-+struct grub_efi_ip4_config2_manual_address {
-+  grub_efi_ipv4_address_t address;
-+  grub_efi_ipv4_address_t subnet_mask;
-+};
-+
-+typedef struct grub_efi_ip4_config2_manual_address grub_efi_ip4_config2_manual_address_t;
-+
- enum grub_efi_ip6_config_data_type {
-   GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
-   GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID,
-@@ -1958,6 +2059,49 @@ struct grub_efi_ip6_config_protocol
- };
- typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t;
- 
-+enum grub_efi_ip6_config_policy {
-+  GRUB_EFI_IP6_CONFIG_POLICY_MANUAL,
-+  GRUB_EFI_IP6_CONFIG_POLICY_AUTOMATIC
-+};
-+typedef enum grub_efi_ip6_config_policy grub_efi_ip6_config_policy_t;
-+
-+struct grub_efi_ip6_address_info {
-+  grub_efi_ipv6_address_t address;
-+  grub_efi_uint8_t prefix_length;
-+};
-+typedef struct grub_efi_ip6_address_info grub_efi_ip6_address_info_t;
-+
-+struct grub_efi_ip6_route_table {
-+  grub_efi_pxe_ipv6_address_t gateway;
-+  grub_efi_pxe_ipv6_address_t destination;
-+  grub_efi_uint8_t prefix_length;
-+};
-+typedef struct grub_efi_ip6_route_table grub_efi_ip6_route_table_t;
-+
-+struct grub_efi_ip6_config_interface_info {
-+  grub_efi_char16_t name[32];
-+  grub_efi_uint8_t if_type;
-+  grub_efi_uint32_t hw_address_size;
-+  grub_efi_mac_address_t hw_address;
-+  grub_efi_uint32_t address_info_count;
-+  grub_efi_ip6_address_info_t *address_info;
-+  grub_efi_uint32_t route_count;
-+  grub_efi_ip6_route_table_t *route_table;
-+};
-+typedef struct grub_efi_ip6_config_interface_info grub_efi_ip6_config_interface_info_t;
-+
-+struct grub_efi_ip6_config_dup_addr_detect_transmits {
-+  grub_efi_uint32_t dup_addr_detect_transmits;
-+};
-+typedef struct grub_efi_ip6_config_dup_addr_detect_transmits grub_efi_ip6_config_dup_addr_detect_transmits_t;
-+
-+struct grub_efi_ip6_config_manual_address {
-+  grub_efi_ipv6_address_t address;
-+  grub_efi_boolean_t is_anycast;
-+  grub_efi_uint8_t prefix_length;
-+};
-+typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t;
-+
- #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
-   || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \
-   || defined(__riscv)
-diff --git a/include/grub/efi/dhcp.h b/include/grub/efi/dhcp.h
-new file mode 100644
-index 00000000000..fdb88eb810e
---- /dev/null
-+++ b/include/grub/efi/dhcp.h
-@@ -0,0 +1,343 @@
-+#ifndef GRUB_EFI_DHCP_HEADER
-+#define GRUB_EFI_DHCP_HEADER	1
-+
-+#define GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID \
-+  { 0x9d9a39d8, 0xbd42, 0x4a73, \
-+    { 0xa4, 0xd5, 0x8e, 0xe9, 0x4b, 0xe1, 0x13, 0x80 } \
-+  }
-+
-+#define GRUB_EFI_DHCP4_PROTOCOL_GUID \
-+  { 0x8a219718, 0x4ef5, 0x4761, \
-+    { 0x91, 0xc8, 0xc0, 0xf0, 0x4b, 0xda, 0x9e, 0x56 } \
-+  }
-+
-+#define GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID \
-+  { 0x9fb9a8a1, 0x2f4a, 0x43a6, \
-+    { 0x88, 0x9c, 0xd0, 0xf7, 0xb6, 0xc4 ,0x7a, 0xd5 } \
-+  }
-+
-+#define GRUB_EFI_DHCP6_PROTOCOL_GUID \
-+  { 0x87c8bad7, 0x595, 0x4053, \
-+    { 0x82, 0x97, 0xde, 0xde, 0x39, 0x5f, 0x5d, 0x5b } \
-+  }
-+
-+typedef struct grub_efi_dhcp4_protocol grub_efi_dhcp4_protocol_t;
-+
-+enum grub_efi_dhcp4_state {
-+  GRUB_EFI_DHCP4_STOPPED,
-+  GRUB_EFI_DHCP4_INIT,
-+  GRUB_EFI_DHCP4_SELECTING,
-+  GRUB_EFI_DHCP4_REQUESTING,
-+  GRUB_EFI_DHCP4_BOUND,
-+  GRUB_EFI_DHCP4_RENEWING,
-+  GRUB_EFI_DHCP4_REBINDING,
-+  GRUB_EFI_DHCP4_INIT_REBOOT,
-+  GRUB_EFI_DHCP4_REBOOTING
-+};
-+
-+typedef enum grub_efi_dhcp4_state grub_efi_dhcp4_state_t;
-+
-+struct grub_efi_dhcp4_header {
-+  grub_efi_uint8_t op_code;
-+  grub_efi_uint8_t hw_type;
-+  grub_efi_uint8_t hw_addr_len;
-+  grub_efi_uint8_t hops;
-+  grub_efi_uint32_t xid;
-+  grub_efi_uint16_t seconds;
-+  grub_efi_uint16_t reserved;
-+  grub_efi_ipv4_address_t client_addr;
-+  grub_efi_ipv4_address_t your_addr;
-+  grub_efi_ipv4_address_t server_addr;
-+  grub_efi_ipv4_address_t gateway_addr;
-+  grub_efi_uint8_t client_hw_addr[16];
-+  grub_efi_char8_t server_name[64];
-+  grub_efi_char8_t boot_file_name[128];
-+} GRUB_PACKED;
-+
-+typedef struct grub_efi_dhcp4_header grub_efi_dhcp4_header_t;
-+
-+struct grub_efi_dhcp4_packet {
-+  grub_efi_uint32_t size;
-+  grub_efi_uint32_t length;
-+  struct {
-+    grub_efi_dhcp4_header_t header;
-+    grub_efi_uint32_t magik;
-+    grub_efi_uint8_t option[1];
-+  } dhcp4;
-+} GRUB_PACKED;
-+
-+typedef struct grub_efi_dhcp4_packet grub_efi_dhcp4_packet_t;
-+
-+struct grub_efi_dhcp4_listen_point {
-+  grub_efi_ipv4_address_t listen_address;
-+  grub_efi_ipv4_address_t subnet_mask;
-+  grub_efi_uint16_t listen_port;
-+};
-+
-+typedef struct grub_efi_dhcp4_listen_point grub_efi_dhcp4_listen_point_t;
-+
-+struct grub_efi_dhcp4_transmit_receive_token {
-+  grub_efi_status_t status;
-+  grub_efi_event_t completion_event;
-+  grub_efi_ipv4_address_t remote_address;
-+  grub_efi_uint16_t remote_port;
-+  grub_efi_ipv4_address_t gateway_address;
-+  grub_efi_uint32_t listen_point_count;
-+  grub_efi_dhcp4_listen_point_t *listen_points;
-+  grub_efi_uint32_t timeout_value;
-+  grub_efi_dhcp4_packet_t *packet;
-+  grub_efi_uint32_t response_count;
-+  grub_efi_dhcp4_packet_t *response_list;
-+};
-+
-+typedef struct grub_efi_dhcp4_transmit_receive_token grub_efi_dhcp4_transmit_receive_token_t;
-+
-+enum grub_efi_dhcp4_event {
-+  GRUB_EFI_DHCP4_SEND_DISCOVER = 0X01,
-+  GRUB_EFI_DHCP4_RCVD_OFFER,
-+  GRUB_EFI_DHCP4_SELECT_OFFER,
-+  GRUB_EFI_DHCP4_SEND_REQUEST,
-+  GRUB_EFI_DHCP4_RCVD_ACK,
-+  GRUB_EFI_DHCP4_RCVD_NAK,
-+  GRUB_EFI_DHCP4_SEND_DECLINE,
-+  GRUB_EFI_DHCP4_BOUND_COMPLETED,
-+  GRUB_EFI_DHCP4_ENTER_RENEWING,
-+  GRUB_EFI_DHCP4_ENTER_REBINDING,
-+  GRUB_EFI_DHCP4_ADDRESS_LOST,
-+  GRUB_EFI_DHCP4_FAIL
-+};
-+
-+typedef enum grub_efi_dhcp4_event grub_efi_dhcp4_event_t;
-+
-+struct grub_efi_dhcp4_packet_option {
-+  grub_efi_uint8_t op_code;
-+  grub_efi_uint8_t length;
-+  grub_efi_uint8_t data[1];
-+} GRUB_PACKED;
-+
-+typedef struct grub_efi_dhcp4_packet_option grub_efi_dhcp4_packet_option_t;
-+
-+struct grub_efi_dhcp4_config_data {
-+  grub_efi_uint32_t discover_try_count;
-+  grub_efi_uint32_t *discover_timeout;
-+  grub_efi_uint32_t request_try_count;
-+  grub_efi_uint32_t *request_timeout;
-+  grub_efi_ipv4_address_t client_address;
-+  grub_efi_status_t (*dhcp4_callback) (
-+    grub_efi_dhcp4_protocol_t *this,
-+    void *context,
-+    grub_efi_dhcp4_state_t current_state,
-+    grub_efi_dhcp4_event_t dhcp4_event,
-+    grub_efi_dhcp4_packet_t *packet,
-+    grub_efi_dhcp4_packet_t **new_packet
-+  );
-+  void *callback_context;
-+  grub_efi_uint32_t option_count;
-+  grub_efi_dhcp4_packet_option_t **option_list;
-+};
-+
-+typedef struct grub_efi_dhcp4_config_data grub_efi_dhcp4_config_data_t;
-+
-+struct grub_efi_dhcp4_mode_data {
-+  grub_efi_dhcp4_state_t state;
-+  grub_efi_dhcp4_config_data_t config_data;
-+  grub_efi_ipv4_address_t client_address;
-+  grub_efi_mac_address_t client_mac_address;
-+  grub_efi_ipv4_address_t server_address;
-+  grub_efi_ipv4_address_t router_address;
-+  grub_efi_ipv4_address_t subnet_mask;
-+  grub_efi_uint32_t lease_time;
-+  grub_efi_dhcp4_packet_t *reply_packet;
-+};
-+
-+typedef struct grub_efi_dhcp4_mode_data grub_efi_dhcp4_mode_data_t;
-+
-+struct grub_efi_dhcp4_protocol {
-+  grub_efi_status_t (*get_mode_data) (grub_efi_dhcp4_protocol_t *this,
-+	      grub_efi_dhcp4_mode_data_t *dhcp4_mode_data);
-+  grub_efi_status_t (*configure) (grub_efi_dhcp4_protocol_t *this,
-+	      grub_efi_dhcp4_config_data_t *dhcp4_cfg_data);
-+  grub_efi_status_t (*start) (grub_efi_dhcp4_protocol_t *this,
-+	      grub_efi_event_t completion_event);
-+  grub_efi_status_t (*renew_rebind) (grub_efi_dhcp4_protocol_t *this,
-+	      grub_efi_boolean_t rebind_request,
-+	      grub_efi_event_t completion_event);
-+  grub_efi_status_t (*release) (grub_efi_dhcp4_protocol_t *this);
-+  grub_efi_status_t (*stop) (grub_efi_dhcp4_protocol_t *this);
-+  grub_efi_status_t (*build) (grub_efi_dhcp4_protocol_t *this,
-+	      grub_efi_dhcp4_packet_t *seed_packet,
-+	      grub_efi_uint32_t delete_count,
-+	      grub_efi_uint8_t *delete_list,
-+	      grub_efi_uint32_t append_count,
-+	      grub_efi_dhcp4_packet_option_t *append_list[],
-+	      grub_efi_dhcp4_packet_t **new_packet);
-+  grub_efi_status_t (*transmit_receive) (grub_efi_dhcp4_protocol_t *this,
-+	      grub_efi_dhcp4_transmit_receive_token_t *token);
-+  grub_efi_status_t (*parse) (grub_efi_dhcp4_protocol_t *this,
-+	      grub_efi_dhcp4_packet_t *packet,
-+	      grub_efi_uint32_t *option_count,
-+	      grub_efi_dhcp4_packet_option_t *packet_option_list[]);
-+};
-+
-+typedef struct grub_efi_dhcp6_protocol grub_efi_dhcp6_protocol_t;
-+
-+struct grub_efi_dhcp6_retransmission {
-+  grub_efi_uint32_t irt;
-+  grub_efi_uint32_t mrc;
-+  grub_efi_uint32_t mrt;
-+  grub_efi_uint32_t mrd;
-+};
-+
-+typedef struct grub_efi_dhcp6_retransmission grub_efi_dhcp6_retransmission_t;
-+
-+enum grub_efi_dhcp6_event {
-+  GRUB_EFI_DHCP6_SEND_SOLICIT,
-+  GRUB_EFI_DHCP6_RCVD_ADVERTISE,
-+  GRUB_EFI_DHCP6_SELECT_ADVERTISE,
-+  GRUB_EFI_DHCP6_SEND_REQUEST,
-+  GRUB_EFI_DHCP6_RCVD_REPLY,
-+  GRUB_EFI_DHCP6_RCVD_RECONFIGURE,
-+  GRUB_EFI_DHCP6_SEND_DECLINE,
-+  GRUB_EFI_DHCP6_SEND_CONFIRM,
-+  GRUB_EFI_DHCP6_SEND_RELEASE,
-+  GRUB_EFI_DHCP6_SEND_RENEW,
-+  GRUB_EFI_DHCP6_SEND_REBIND
-+};
-+
-+typedef enum grub_efi_dhcp6_event grub_efi_dhcp6_event_t;
-+
-+struct grub_efi_dhcp6_packet_option {
-+  grub_efi_uint16_t op_code;
-+  grub_efi_uint16_t op_len;
-+  grub_efi_uint8_t data[1];
-+} GRUB_PACKED;
-+
-+typedef struct grub_efi_dhcp6_packet_option grub_efi_dhcp6_packet_option_t;
-+
-+struct grub_efi_dhcp6_header {
-+  grub_efi_uint32_t transaction_id:24;
-+  grub_efi_uint32_t message_type:8;
-+} GRUB_PACKED;
-+
-+typedef struct grub_efi_dhcp6_header grub_efi_dhcp6_header_t;
-+
-+struct grub_efi_dhcp6_packet {
-+  grub_efi_uint32_t size;
-+  grub_efi_uint32_t length;
-+  struct {
-+    grub_efi_dhcp6_header_t header;
-+    grub_efi_uint8_t option[1];
-+  } dhcp6;
-+} GRUB_PACKED;
-+
-+typedef struct grub_efi_dhcp6_packet grub_efi_dhcp6_packet_t;
-+
-+struct grub_efi_dhcp6_ia_address {
-+  grub_efi_ipv6_address_t ip_address;
-+  grub_efi_uint32_t preferred_lifetime;
-+  grub_efi_uint32_t valid_lifetime;
-+};
-+
-+typedef struct grub_efi_dhcp6_ia_address grub_efi_dhcp6_ia_address_t;
-+
-+enum grub_efi_dhcp6_state {
-+  GRUB_EFI_DHCP6_INIT,
-+  GRUB_EFI_DHCP6_SELECTING,
-+  GRUB_EFI_DHCP6_REQUESTING,
-+  GRUB_EFI_DHCP6_DECLINING,
-+  GRUB_EFI_DHCP6_CONFIRMING,
-+  GRUB_EFI_DHCP6_RELEASING,
-+  GRUB_EFI_DHCP6_BOUND,
-+  GRUB_EFI_DHCP6_RENEWING,
-+  GRUB_EFI_DHCP6_REBINDING
-+};
-+
-+typedef enum grub_efi_dhcp6_state grub_efi_dhcp6_state_t;
-+
-+#define GRUB_EFI_DHCP6_IA_TYPE_NA 3
-+#define GRUB_EFI_DHCP6_IA_TYPE_TA 4
-+
-+struct grub_efi_dhcp6_ia_descriptor {
-+  grub_efi_uint16_t type;
-+  grub_efi_uint32_t ia_id;
-+};
-+
-+typedef struct grub_efi_dhcp6_ia_descriptor grub_efi_dhcp6_ia_descriptor_t;
-+
-+struct grub_efi_dhcp6_ia {
-+  grub_efi_dhcp6_ia_descriptor_t descriptor;
-+  grub_efi_dhcp6_state_t state;
-+  grub_efi_dhcp6_packet_t *reply_packet;
-+  grub_efi_uint32_t ia_address_count;
-+  grub_efi_dhcp6_ia_address_t ia_address[1];
-+};
-+
-+typedef struct grub_efi_dhcp6_ia grub_efi_dhcp6_ia_t;
-+
-+struct grub_efi_dhcp6_duid {
-+  grub_efi_uint16_t length;
-+  grub_efi_uint8_t duid[1];
-+};
-+
-+typedef struct grub_efi_dhcp6_duid grub_efi_dhcp6_duid_t;
-+
-+struct grub_efi_dhcp6_mode_data {
-+  grub_efi_dhcp6_duid_t *client_id;
-+  grub_efi_dhcp6_ia_t *ia;
-+};
-+
-+typedef struct grub_efi_dhcp6_mode_data grub_efi_dhcp6_mode_data_t;
-+
-+struct grub_efi_dhcp6_config_data {
-+  grub_efi_status_t (*dhcp6_callback) (grub_efi_dhcp6_protocol_t this,
-+		void *context,
-+		grub_efi_dhcp6_state_t current_state,
-+		grub_efi_dhcp6_event_t dhcp6_event,
-+		grub_efi_dhcp6_packet_t *packet,
-+		grub_efi_dhcp6_packet_t **new_packet);
-+  void *callback_context;
-+  grub_efi_uint32_t option_count;
-+  grub_efi_dhcp6_packet_option_t **option_list;
-+  grub_efi_dhcp6_ia_descriptor_t ia_descriptor;
-+  grub_efi_event_t ia_info_event;
-+  grub_efi_boolean_t reconfigure_accept;
-+  grub_efi_boolean_t rapid_commit;
-+  grub_efi_dhcp6_retransmission_t *solicit_retransmission;
-+};
-+
-+typedef struct grub_efi_dhcp6_config_data grub_efi_dhcp6_config_data_t;
-+
-+struct grub_efi_dhcp6_protocol {
-+  grub_efi_status_t (*get_mode_data) (grub_efi_dhcp6_protocol_t *this,
-+	    grub_efi_dhcp6_mode_data_t *dhcp6_mode_data,
-+	    grub_efi_dhcp6_config_data_t *dhcp6_config_data);
-+  grub_efi_status_t (*configure) (grub_efi_dhcp6_protocol_t *this,
-+	    grub_efi_dhcp6_config_data_t *dhcp6_cfg_data);
-+  grub_efi_status_t (*start) (grub_efi_dhcp6_protocol_t *this);
-+  grub_efi_status_t (*info_request) (grub_efi_dhcp6_protocol_t *this,
-+	    grub_efi_boolean_t send_client_id,
-+	    grub_efi_dhcp6_packet_option_t *option_request,
-+	    grub_efi_uint32_t option_count,
-+	    grub_efi_dhcp6_packet_option_t *option_list[],
-+	    grub_efi_dhcp6_retransmission_t *retransmission,
-+	    grub_efi_event_t timeout_event,
-+	    grub_efi_status_t (*reply_callback) (grub_efi_dhcp6_protocol_t *this,
-+		    void *context,
-+		    grub_efi_dhcp6_packet_t *packet),
-+	    void *callback_context);
-+  grub_efi_status_t (*renew_rebind) (grub_efi_dhcp6_protocol_t *this,
-+	    grub_efi_boolean_t rebind_request);
-+  grub_efi_status_t (*decline) (grub_efi_dhcp6_protocol_t *this,
-+	    grub_efi_uint32_t address_count,
-+	    grub_efi_ipv6_address_t *addresses);
-+  grub_efi_status_t (*release) (grub_efi_dhcp6_protocol_t *this,
-+	    grub_efi_uint32_t address_count,
-+	    grub_efi_ipv6_address_t *addresses);
-+  grub_efi_status_t (*stop) (grub_efi_dhcp6_protocol_t *this);
-+  grub_efi_status_t (*parse) (grub_efi_dhcp6_protocol_t *this,
-+	    grub_efi_dhcp6_packet_t *packet,
-+	    grub_efi_uint32_t *option_count,
-+	    grub_efi_dhcp6_packet_option_t *packet_option_list[]);
-+};
-+
-+#endif /* ! GRUB_EFI_DHCP_HEADER */
-diff --git a/include/grub/efi/http.h b/include/grub/efi/http.h
-new file mode 100644
-index 00000000000..c5e9a89f505
---- /dev/null
-+++ b/include/grub/efi/http.h
-@@ -0,0 +1,215 @@
-+/*
-+ *  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/>.
-+ */
-+
-+#ifndef GRUB_EFI_HTTP_HEADER
-+#define GRUB_EFI_HTTP_HEADER	1
-+
-+#include <grub/symbol.h>
-+#include <grub/net.h>
-+#include <grub/efi/api.h>
-+
-+#define GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \
-+  { 0xbdc8e6af, 0xd9bc, 0x4379, \
-+      { 0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c } \
-+  }
-+
-+#define GRUB_EFI_HTTP_PROTOCOL_GUID \
-+  { 0x7A59B29B, 0x910B, 0x4171, \
-+      { 0x82, 0x42, 0xA8, 0x5A, 0x0D, 0xF2, 0x5B, 0x5B } \
-+  }
-+
-+#define EFIHTTP_WAIT_TIME 10000 // 10000ms = 10s
-+#define EFIHTTP_RX_BUF_LEN 10240
-+
-+//******************************************
-+// Protocol Interface Structure
-+//******************************************
-+struct grub_efi_http;
-+
-+//******************************************
-+// EFI_HTTP_VERSION
-+//******************************************
-+typedef enum {
-+  GRUB_EFI_HTTPVERSION10,
-+  GRUB_EFI_HTTPVERSION11,
-+  GRUB_EFI_HTTPVERSIONUNSUPPORTED
-+} grub_efi_http_version_t;
-+
-+//******************************************
-+// EFI_HTTPv4_ACCESS_POINT
-+//******************************************
-+typedef struct {
-+  grub_efi_boolean_t use_default_address;
-+  grub_efi_ipv4_address_t local_address;
-+  grub_efi_ipv4_address_t local_subnet;
-+  grub_efi_uint16_t local_port;
-+} grub_efi_httpv4_access_point_t;
-+
-+//******************************************
-+// EFI_HTTPv6_ACCESS_POINT
-+//******************************************
-+typedef struct {
-+  grub_efi_ipv6_address_t local_address;
-+  grub_efi_uint16_t local_port;
-+} grub_efi_httpv6_access_point_t;
-+
-+//******************************************
-+// EFI_HTTP_CONFIG_DATA
-+//******************************************
-+typedef struct {
-+  grub_efi_http_version_t http_version;
-+  grub_efi_uint32_t timeout_millisec;
-+  grub_efi_boolean_t local_address_is_ipv6;
-+  union {
-+    grub_efi_httpv4_access_point_t *ipv4_node;
-+    grub_efi_httpv6_access_point_t *ipv6_node;
-+  } access_point;
-+} grub_efi_http_config_data_t;
-+
-+//******************************************
-+// EFI_HTTP_METHOD
-+//******************************************
-+typedef enum {
-+  GRUB_EFI_HTTPMETHODGET,
-+  GRUB_EFI_HTTPMETHODPOST,
-+  GRUB_EFI_HTTPMETHODPATCH,
-+  GRUB_EFI_HTTPMETHODOPTIONS,
-+  GRUB_EFI_HTTPMETHODCONNECT,
-+  GRUB_EFI_HTTPMETHODHEAD,
-+  GRUB_EFI_HTTPMETHODPUT,
-+  GRUB_EFI_HTTPMETHODDELETE,
-+  GRUB_EFI_HTTPMETHODTRACE,
-+} grub_efi_http_method_t;
-+
-+//******************************************
-+// EFI_HTTP_REQUEST_DATA
-+//******************************************
-+typedef struct {
-+  grub_efi_http_method_t method;
-+  grub_efi_char16_t *url;
-+} grub_efi_http_request_data_t;
-+
-+typedef enum {
-+  GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS = 0,
-+  GRUB_EFI_HTTP_STATUS_100_CONTINUE,
-+  GRUB_EFI_HTTP_STATUS_101_SWITCHING_PROTOCOLS,
-+  GRUB_EFI_HTTP_STATUS_200_OK,
-+  GRUB_EFI_HTTP_STATUS_201_CREATED,
-+  GRUB_EFI_HTTP_STATUS_202_ACCEPTED,
-+  GRUB_EFI_HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION,
-+  GRUB_EFI_HTTP_STATUS_204_NO_CONTENT,
-+  GRUB_EFI_HTTP_STATUS_205_RESET_CONTENT,
-+  GRUB_EFI_HTTP_STATUS_206_PARTIAL_CONTENT,
-+  GRUB_EFI_HTTP_STATUS_300_MULTIPLE_CHIOCES,
-+  GRUB_EFI_HTTP_STATUS_301_MOVED_PERMANENTLY,
-+  GRUB_EFI_HTTP_STATUS_302_FOUND,
-+  GRUB_EFI_HTTP_STATUS_303_SEE_OTHER,
-+  GRUB_EFI_HTTP_STATUS_304_NOT_MODIFIED,
-+  GRUB_EFI_HTTP_STATUS_305_USE_PROXY,
-+  GRUB_EFI_HTTP_STATUS_307_TEMPORARY_REDIRECT,
-+  GRUB_EFI_HTTP_STATUS_400_BAD_REQUEST,
-+  GRUB_EFI_HTTP_STATUS_401_UNAUTHORIZED,
-+  GRUB_EFI_HTTP_STATUS_402_PAYMENT_REQUIRED,
-+  GRUB_EFI_HTTP_STATUS_403_FORBIDDEN,
-+  GRUB_EFI_HTTP_STATUS_404_NOT_FOUND,
-+  GRUB_EFI_HTTP_STATUS_405_METHOD_NOT_ALLOWED,
-+  GRUB_EFI_HTTP_STATUS_406_NOT_ACCEPTABLE,
-+  GRUB_EFI_HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED,
-+  GRUB_EFI_HTTP_STATUS_408_REQUEST_TIME_OUT,
-+  GRUB_EFI_HTTP_STATUS_409_CONFLICT,
-+  GRUB_EFI_HTTP_STATUS_410_GONE,
-+  GRUB_EFI_HTTP_STATUS_411_LENGTH_REQUIRED,
-+  GRUB_EFI_HTTP_STATUS_412_PRECONDITION_FAILED,
-+  GRUB_EFI_HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE,
-+  GRUB_EFI_HTTP_STATUS_414_REQUEST_URI_TOO_LARGE,
-+  GRUB_EFI_HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE,
-+  GRUB_EFI_HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED,
-+  GRUB_EFI_HTTP_STATUS_417_EXPECTATION_FAILED,
-+  GRUB_EFI_HTTP_STATUS_500_INTERNAL_SERVER_ERROR,
-+  GRUB_EFI_HTTP_STATUS_501_NOT_IMPLEMENTED,
-+  GRUB_EFI_HTTP_STATUS_502_BAD_GATEWAY,
-+  GRUB_EFI_HTTP_STATUS_503_SERVICE_UNAVAILABLE,
-+  GRUB_EFI_HTTP_STATUS_504_GATEWAY_TIME_OUT,
-+  GRUB_EFI_HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED
-+} grub_efi_http_status_code_t;
-+
-+//******************************************
-+// EFI_HTTP_RESPONSE_DATA
-+//******************************************
-+typedef struct {
-+  grub_efi_http_status_code_t status_code;
-+} grub_efi_http_response_data_t;
-+
-+//******************************************
-+// EFI_HTTP_HEADER
-+//******************************************
-+typedef struct {
-+  grub_efi_char8_t *field_name;
-+  grub_efi_char8_t *field_value;
-+} grub_efi_http_header_t;
-+
-+//******************************************
-+// EFI_HTTP_MESSAGE
-+//******************************************
-+typedef struct {
-+  union {
-+    grub_efi_http_request_data_t *request;
-+    grub_efi_http_response_data_t *response;
-+  } data;
-+  grub_efi_uint32_t header_count;
-+  grub_efi_http_header_t *headers;
-+  grub_efi_uint32_t body_length;
-+  void *body;
-+} grub_efi_http_message_t;
-+
-+//******************************************
-+// EFI_HTTP_TOKEN
-+//******************************************
-+typedef struct {
-+  grub_efi_event_t event;
-+  grub_efi_status_t status;
-+  grub_efi_http_message_t *message;
-+} grub_efi_http_token_t;
-+
-+struct grub_efi_http {
-+  grub_efi_status_t
-+  (*get_mode_data) (struct grub_efi_http *this,
-+                    grub_efi_http_config_data_t *http_config_data);
-+
-+  grub_efi_status_t
-+  (*configure) (struct grub_efi_http *this,
-+                grub_efi_http_config_data_t *http_config_data);
-+
-+  grub_efi_status_t
-+  (*request) (struct grub_efi_http *this,
-+              grub_efi_http_token_t *token);
-+
-+  grub_efi_status_t
-+  (*cancel) (struct grub_efi_http *this,
-+             grub_efi_http_token_t *token);
-+
-+  grub_efi_status_t
-+  (*response) (struct grub_efi_http *this,
-+               grub_efi_http_token_t *token);
-+
-+  grub_efi_status_t
-+  (*poll) (struct grub_efi_http *this);
-+};
-+typedef struct grub_efi_http grub_efi_http_t;
-+
-+#endif /* !GRUB_EFI_HTTP_HEADER */
-diff --git a/include/grub/net/efi.h b/include/grub/net/efi.h
-new file mode 100644
-index 00000000000..de90d223e8e
---- /dev/null
-+++ b/include/grub/net/efi.h
-@@ -0,0 +1,144 @@
-+#ifndef GRUB_NET_EFI_HEADER
-+#define GRUB_NET_EFI_HEADER	1
-+
-+#include <grub/efi/api.h>
-+#include <grub/efi/http.h>
-+#include <grub/efi/dhcp.h>
-+#include <grub/command.h>
-+
-+typedef struct grub_efi_net_interface grub_efi_net_interface_t;
-+typedef struct grub_efi_net_ip_config grub_efi_net_ip_config_t;
-+typedef union grub_efi_net_ip_address grub_efi_net_ip_address_t;
-+typedef struct grub_efi_net_ip_manual_address grub_efi_net_ip_manual_address_t;
-+
-+struct grub_efi_net_interface
-+{
-+  char *name;
-+  int prefer_ip6;
-+  struct grub_efi_net_device *dev;
-+  struct grub_efi_net_io *io;
-+  grub_efi_net_ip_config_t *ip_config;
-+  int io_type;
-+  struct grub_efi_net_interface *next;
-+};
-+
-+#define efi_net_interface_get_hw_address(inf) inf->ip_config->get_hw_address (inf->dev)
-+#define efi_net_interface_get_address(inf) inf->ip_config->get_address (inf->dev)
-+#define efi_net_interface_get_route_table(inf) inf->ip_config->get_route_table (inf->dev)
-+#define efi_net_interface_set_address(inf, addr, with_subnet) inf->ip_config->set_address (inf->dev, addr, with_subnet)
-+#define efi_net_interface_set_gateway(inf, addr) inf->ip_config->set_gateway (inf->dev, addr)
-+#define efi_net_interface_set_dns(inf, addr) inf->ip_config->set_dns (inf->dev, addr)
-+
-+struct grub_efi_net_ip_config
-+{
-+  char * (*get_hw_address) (struct grub_efi_net_device *dev);
-+  char * (*get_address) (struct grub_efi_net_device *dev);
-+  char ** (*get_route_table) (struct grub_efi_net_device *dev);
-+  grub_efi_net_interface_t * (*best_interface) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address);
-+  int (*set_address) (struct grub_efi_net_device *dev, grub_efi_net_ip_manual_address_t *net_ip, int with_subnet);
-+  int (*set_gateway) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address);
-+  int (*set_dns) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *dns);
-+};
-+
-+union grub_efi_net_ip_address
-+{
-+  grub_efi_ipv4_address_t ip4;
-+  grub_efi_ipv6_address_t ip6;
-+};
-+
-+struct grub_efi_net_ip_manual_address
-+{
-+  int is_ip6;
-+  union
-+  {
-+    grub_efi_ip4_config2_manual_address_t ip4;
-+    grub_efi_ip6_config_manual_address_t ip6;
-+  };
-+};
-+
-+struct grub_efi_net_device
-+{
-+  grub_efi_handle_t handle;
-+  grub_efi_ip4_config2_protocol_t *ip4_config;
-+  grub_efi_ip6_config_protocol_t *ip6_config;
-+  grub_efi_handle_t http_handle;
-+  grub_efi_http_t *http;
-+  grub_efi_handle_t ip4_pxe_handle;
-+  grub_efi_pxe_t *ip4_pxe;
-+  grub_efi_handle_t ip6_pxe_handle;
-+  grub_efi_pxe_t *ip6_pxe;
-+  grub_efi_handle_t dhcp4_handle;
-+  grub_efi_dhcp4_protocol_t *dhcp4;
-+  grub_efi_handle_t dhcp6_handle;
-+  grub_efi_dhcp6_protocol_t *dhcp6;
-+  char *card_name;
-+  grub_efi_net_interface_t *net_interfaces;
-+  struct grub_efi_net_device *next;
-+};
-+
-+struct grub_efi_net_io
-+{
-+  void (*configure) (struct grub_efi_net_device *dev, int prefer_ip6);
-+  grub_err_t (*open) (struct grub_efi_net_device *dev,
-+		    int prefer_ip6,
-+		    grub_file_t file,
-+		    const char *filename,
-+		    int type);
-+  grub_ssize_t (*read) (struct grub_efi_net_device *dev,
-+			int prefer_ip6,
-+			grub_file_t file,
-+			char *buf,
-+			grub_size_t len);
-+  grub_err_t (*close) (struct grub_efi_net_device *dev,
-+		      int prefer_ip6,
-+		      grub_file_t file);
-+};
-+
-+extern struct grub_efi_net_device *net_devices;
-+
-+extern struct grub_efi_net_io io_http;
-+extern struct grub_efi_net_io io_pxe;
-+
-+extern grub_efi_net_ip_config_t *efi_net_ip4_config;
-+extern grub_efi_net_ip_config_t *efi_net_ip6_config;
-+
-+char *
-+grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address);
-+
-+char *
-+grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address);
-+
-+char *
-+grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address);
-+
-+int
-+grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest);
-+
-+int
-+grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest);
-+
-+char *
-+grub_efi_ip6_interface_name (struct grub_efi_net_device *dev);
-+
-+char *
-+grub_efi_ip4_interface_name (struct grub_efi_net_device *dev);
-+
-+grub_efi_net_interface_t *
-+grub_efi_net_create_interface (struct grub_efi_net_device *dev,
-+		const char *interface_name,
-+		grub_efi_net_ip_manual_address_t *net_ip,
-+		int has_subnet);
-+
-+int grub_efi_net_fs_init (void);
-+void grub_efi_net_fs_fini (void);
-+int grub_efi_net_boot_from_https (void);
-+int grub_efi_net_boot_from_opa (void);
-+
-+extern grub_command_func_t grub_efi_net_list_routes;
-+extern grub_command_func_t grub_efi_net_list_cards;
-+extern grub_command_func_t grub_efi_net_list_addrs;
-+extern grub_command_func_t grub_efi_net_add_addr;
-+extern grub_command_func_t grub_efi_net_bootp;
-+extern grub_command_func_t grub_efi_net_bootp6;
-+
-+#endif /* ! GRUB_NET_EFI_HEADER */
diff --git a/SOURCES/0096-AUDIT-0-http-boot-tracker-bug.patch b/SOURCES/0096-AUDIT-0-http-boot-tracker-bug.patch
deleted file mode 100644
index ef3e67b..0000000
--- a/SOURCES/0096-AUDIT-0-http-boot-tracker-bug.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Sebastian Krahmer <krahmer@suse.com>
-Date: Tue, 28 Nov 2017 17:24:38 +0800
-Subject: [PATCH] AUDIT-0: http boot tracker bug
-
-Fixing a memory leak in case of error, and a integer overflow, leading to a
-heap overflow due to overly large chunk sizes.
-
-We need to check against some maximum value, otherwise values like 0xffffffff
-will eventually lead in the allocation functions to small sized buffers, since
-the len is rounded up to the next reasonable alignment. The following memcpy
-will then smash the heap, leading to RCE.
-
-This is no big issue for pure http boot, since its going to execute an
-untrusted kernel anyway, but it will break trusted boot scenarios, where only
-signed code is allowed to be executed.
-
-Signed-off-by: Michael Chang <mchang@suse.com>
----
- grub-core/net/efi/net.c | 4 +++-
- grub-core/net/http.c    | 5 ++++-
- 2 files changed, 7 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
-index 86bce6535d3..4bb308026ce 100644
---- a/grub-core/net/efi/net.c
-+++ b/grub-core/net/efi/net.c
-@@ -645,8 +645,10 @@ grub_efihttp_chunk_read (grub_file_t file, char *buf,
- 
-       rd = efi_net_interface (read, file, chunk, sz);
- 
--      if (rd <= 0)
-+      if (rd <= 0) {
-+	grub_free (chunk);
- 	return rd;
-+      }
- 
-       if (buf)
- 	{
-diff --git a/grub-core/net/http.c b/grub-core/net/http.c
-index 12a2632ea55..b52b558d631 100644
---- a/grub-core/net/http.c
-+++ b/grub-core/net/http.c
-@@ -31,7 +31,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
- 
- enum
-   {
--    HTTP_PORT = 80
-+    HTTP_PORT = 80,
-+    HTTP_MAX_CHUNK_SIZE = 0x80000000
-   };
- 
- 
-@@ -78,6 +79,8 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len)
-   if (data->in_chunk_len == 2)
-     {
-       data->chunk_rem = grub_strtoul (ptr, 0, 16);
-+      if (data->chunk_rem > HTTP_MAX_CHUNK_SIZE)
-+	  return GRUB_ERR_NET_PACKET_TOO_BIG;
-       grub_errno = GRUB_ERR_NONE;
-       if (data->chunk_rem == 0)
- 	{
diff --git a/SOURCES/0096-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch b/SOURCES/0096-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch
new file mode 100644
index 0000000..72c8d30
--- /dev/null
+++ b/SOURCES/0096-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch
@@ -0,0 +1,74 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 11 Sep 2018 15:58:29 -0400
+Subject: [PATCH] Add more dprintf, and nerf dprintf in script.c
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/disk/diskfilter.c  | 3 +++
+ grub-core/disk/efi/efidisk.c | 1 +
+ grub-core/kern/device.c      | 1 +
+ grub-core/script/script.c    | 5 +++++
+ 4 files changed, 10 insertions(+)
+
+diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c
+index 0320115662..7cdffe3ebd 100644
+--- a/grub-core/disk/diskfilter.c
++++ b/grub-core/disk/diskfilter.c
+@@ -188,6 +188,8 @@ scan_disk (const char *name, int accept_diskfilter)
+   grub_disk_t disk;
+   static int scan_depth = 0;
+ 
++  grub_dprintf ("diskfilter", "scanning %s\n", name);
++
+   if (!accept_diskfilter && is_valid_diskfilter_name (name))
+     return 0;
+ 
+@@ -1212,6 +1214,7 @@ insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id,
+ 	   the same.  */
+ 	if (pv->disk && grub_disk_native_sectors (disk) >= pv->part_size)
+ 	  return GRUB_ERR_NONE;
++	grub_dprintf ("diskfilter", "checking %s\n", disk->name);
+ 	pv->disk = grub_disk_open (disk->name);
+ 	if (!pv->disk)
+ 	  return grub_errno;
+diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c
+index f077b5f553..fe8ba6e6c9 100644
+--- a/grub-core/disk/efi/efidisk.c
++++ b/grub-core/disk/efi/efidisk.c
+@@ -855,6 +855,7 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle)
+ 	  return 0;
+ 	}
+ 
++      grub_dprintf ("efidisk", "getting disk for %s\n", device_name);
+       parent = grub_disk_open (device_name);
+       grub_free (dup_dp);
+ 
+diff --git a/grub-core/kern/device.c b/grub-core/kern/device.c
+index 73b8ecc0c0..f58b58c89d 100644
+--- a/grub-core/kern/device.c
++++ b/grub-core/kern/device.c
+@@ -34,6 +34,7 @@ grub_device_open (const char *name)
+ {
+   grub_device_t dev = 0;
+ 
++  grub_dprintf ("device", "opening device %s\n", name);
+   if (! name)
+     {
+       name = grub_env_get ("root");
+diff --git a/grub-core/script/script.c b/grub-core/script/script.c
+index ec4d4337c6..844e8343ca 100644
+--- a/grub-core/script/script.c
++++ b/grub-core/script/script.c
+@@ -22,6 +22,11 @@
+ #include <grub/parser.h>
+ #include <grub/mm.h>
+ 
++#ifdef grub_dprintf
++#undef grub_dprintf
++#endif
++#define grub_dprintf(no, fmt, ...)
++
+ /* It is not possible to deallocate the memory when a syntax error was
+    found.  Because of that it is required to keep track of all memory
+    allocations.  The memory is freed in case of an error, or assigned
diff --git a/SOURCES/0097-arm-arm64-loader-Better-memory-allocation-and-error-.patch b/SOURCES/0097-arm-arm64-loader-Better-memory-allocation-and-error-.patch
new file mode 100644
index 0000000..57d937c
--- /dev/null
+++ b/SOURCES/0097-arm-arm64-loader-Better-memory-allocation-and-error-.patch
@@ -0,0 +1,279 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 11 Jul 2019 14:38:57 +0200
+Subject: [PATCH] arm/arm64 loader: Better memory allocation and error
+ messages.
+
+On mustang, our memory map looks like:
+
+Type      Physical start  - end             #Pages        Size Attributes
+reserved  0000004000000000-00000040001fffff 00000200      2MiB UC WC WT WB
+conv-mem  0000004000200000-0000004393ffffff 00393e00  14654MiB UC WC WT WB
+ldr-code  0000004394000000-00000043f7ffffff 00064000   1600MiB UC WC WT WB
+BS-data   00000043f8000000-00000043f801ffff 00000020    128KiB UC WC WT WB
+conv-mem  00000043f8020000-00000043fa15bfff 0000213c  34032KiB UC WC WT WB
+ldr-code  00000043fa15c000-00000043fa2a1fff 00000146   1304KiB UC WC WT WB
+ldr-data  00000043fa2a2000-00000043fa3e8fff 00000147   1308KiB UC WC WT WB
+conv-mem  00000043fa3e9000-00000043fa3e9fff 00000001      4KiB UC WC WT WB
+ldr-data  00000043fa3ea000-00000043fa3eafff 00000001      4KiB UC WC WT WB
+ldr-code  00000043fa3eb000-00000043fa4affff 000000c5    788KiB UC WC WT WB
+BS-code   00000043fa4b0000-00000043fa59ffff 000000f0    960KiB UC WC WT WB
+RT-code   00000043fa5a0000-00000043fa5affff 00000010     64KiB RT UC WC WT WB
+RT-data   00000043fa5b0000-00000043fa5bffff 00000010     64KiB RT UC WC WT WB
+RT-code   00000043fa5c0000-00000043fa5cffff 00000010     64KiB RT UC WC WT WB
+ldr-data  00000043fa5d0000-00000043fa5d0fff 00000001      4KiB UC WC WT WB
+BS-code   00000043fa5d1000-00000043fa5ddfff 0000000d     52KiB UC WC WT WB
+reserved  00000043fa5de000-00000043fa60ffff 00000032    200KiB UC WC WT WB
+ACPI-rec  00000043fa610000-00000043fa6affff 000000a0    640KiB UC WC WT WB
+ACPI-nvs  00000043fa6b0000-00000043fa6bffff 00000010     64KiB UC WC WT WB
+ACPI-rec  00000043fa6c0000-00000043fa70ffff 00000050    320KiB UC WC WT WB
+RT-code   00000043fa710000-00000043fa72ffff 00000020    128KiB RT UC WC WT WB
+RT-data   00000043fa730000-00000043fa78ffff 00000060    384KiB RT UC WC WT WB
+RT-code   00000043fa790000-00000043fa79ffff 00000010     64KiB RT UC WC WT WB
+RT-data   00000043fa7a0000-00000043fa99ffff 00000200      2MiB RT UC WC WT WB
+RT-code   00000043fa9a0000-00000043fa9affff 00000010     64KiB RT UC WC WT WB
+RT-data   00000043fa9b0000-00000043fa9cffff 00000020    128KiB RT UC WC WT WB
+BS-code   00000043fa9d0000-00000043fa9d9fff 0000000a     40KiB UC WC WT WB
+reserved  00000043fa9da000-00000043fa9dbfff 00000002      8KiB UC WC WT WB
+conv-mem  00000043fa9dc000-00000043fc29dfff 000018c2  25352KiB UC WC WT WB
+BS-data   00000043fc29e000-00000043fc78afff 000004ed   5044KiB UC WC WT WB
+conv-mem  00000043fc78b000-00000043fca01fff 00000277   2524KiB UC WC WT WB
+BS-data   00000043fca02000-00000043fcea3fff 000004a2   4744KiB UC WC WT WB
+conv-mem  00000043fcea4000-00000043fcea4fff 00000001      4KiB UC WC WT WB
+BS-data   00000043fcea5000-00000043fd192fff 000002ee   3000KiB UC WC WT WB
+conv-mem  00000043fd193000-00000043fd2b0fff 0000011e   1144KiB UC WC WT WB
+BS-data   00000043fd2b1000-00000043ff80ffff 0000255f  38268KiB UC WC WT WB
+BS-code   00000043ff810000-00000043ff99ffff 00000190   1600KiB UC WC WT WB
+RT-code   00000043ff9a0000-00000043ff9affff 00000010     64KiB RT UC WC WT WB
+conv-mem  00000043ff9b0000-00000043ff9bffff 00000010     64KiB UC WC WT WB
+RT-data   00000043ff9c0000-00000043ff9effff 00000030    192KiB RT UC WC WT WB
+conv-mem  00000043ff9f0000-00000043ffa05fff 00000016     88KiB UC WC WT WB
+BS-data   00000043ffa06000-00000043ffffffff 000005fa   6120KiB UC WC WT WB
+MMIO      0000000010510000-0000000010510fff 00000001      4KiB RT
+MMIO      0000000010548000-0000000010549fff 00000002      8KiB RT
+MMIO      0000000017000000-0000000017001fff 00000002      8KiB RT
+MMIO      000000001c025000-000000001c025fff 00000001      4KiB RT
+
+This patch adds a requirement when we're trying to find the base of ram, that
+the memory we choose is actually /allocatable/ conventional memory, not merely
+write-combining.  On this machine that means we wind up with an allocation
+around 0x4392XXXXXX, which is a reasonable address.
+
+This also changes grub_efi_allocate_pages_real() so that if 0 is allocated, it
+tries to allocate again starting with the same max address it did the first
+time, rather than interposing GRUB_EFI_MAX_USABLE_ADDRESS there, so that any
+per-platform constraints on its given address are maintained.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/efi/mm.c        | 33 +++++++++++++++-----
+ grub-core/loader/arm64/linux.c | 68 +++++++++++++++++++++++++++++++-----------
+ 2 files changed, 76 insertions(+), 25 deletions(-)
+
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index f6aef0ef64..85ad4b4494 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -154,6 +154,7 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
+ {
+   grub_efi_status_t status;
+   grub_efi_boot_services_t *b;
++  grub_efi_physical_address_t ret = address;
+ 
+   /* Limit the memory access to less than 4GB for 32-bit platforms.  */
+   if (address > GRUB_EFI_MAX_USABLE_ADDRESS)
+@@ -170,19 +171,22 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
+     }
+ 
+   b = grub_efi_system_table->boot_services;
+-  status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address);
++  status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret);
+   if (status != GRUB_EFI_SUCCESS)
+     {
++      grub_dprintf ("efi",
++		    "allocate_pages(%d, %d, 0x%0lx, 0x%016lx) = 0x%016lx\n",
++		    alloctype, memtype, pages, address, status);
+       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+       return NULL;
+     }
+ 
+-  if (address == 0)
++  if (ret == 0)
+     {
+       /* Uggh, the address 0 was allocated... This is too annoying,
+ 	 so reallocate another one.  */
+-      address = GRUB_EFI_MAX_USABLE_ADDRESS;
+-      status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address);
++      ret = address;
++      status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret);
+       grub_efi_free_pages (0, pages);
+       if (status != GRUB_EFI_SUCCESS)
+ 	{
+@@ -191,9 +195,9 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
+ 	}
+     }
+ 
+-  grub_efi_store_alloc (address, pages);
++  grub_efi_store_alloc (ret, pages);
+ 
+-  return (void *) ((grub_addr_t) address);
++  return (void *) ((grub_addr_t) ret);
+ }
+ 
+ void *
+@@ -713,8 +717,21 @@ grub_efi_get_ram_base(grub_addr_t *base_addr)
+   for (desc = memory_map, *base_addr = GRUB_EFI_MAX_USABLE_ADDRESS;
+        (grub_addr_t) desc < ((grub_addr_t) memory_map + memory_map_size);
+        desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
+-    if (desc->attribute & GRUB_EFI_MEMORY_WB)
+-      *base_addr = grub_min (*base_addr, desc->physical_start);
++    {
++      if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY &&
++          (desc->attribute & GRUB_EFI_MEMORY_WB))
++        {
++          *base_addr = grub_min (*base_addr, desc->physical_start);
++          grub_dprintf ("efi", "setting base_addr=0x%016lx\n", *base_addr);
++        }
++      else
++        {
++          grub_dprintf ("efi", "ignoring address 0x%016lx\n", desc->physical_start);
++        }
++    }
++
++  if (*base_addr == GRUB_EFI_MAX_USABLE_ADDRESS)
++    grub_dprintf ("efi", "base_addr 0x%016lx is probably wrong.\n", *base_addr);
+ 
+   grub_free(memory_map);
+ 
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index 04994d5c67..70a0075ec5 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -71,20 +71,25 @@ finalize_params_linux (void)
+ {
+   grub_efi_loaded_image_t *loaded_image = NULL;
+   int node, retval, len;
+-
++  grub_err_t err = GRUB_ERR_NONE;
+   void *fdt;
+ 
+   fdt = grub_fdt_load (GRUB_EFI_LINUX_FDT_EXTRA_SPACE);
+-
+   if (!fdt)
+-    goto failure;
++    {
++      err = grub_error(GRUB_ERR_BAD_OS, "failed to load FDT");
++      goto failure;
++    }
+ 
+   node = grub_fdt_find_subnode (fdt, 0, "chosen");
+   if (node < 0)
+     node = grub_fdt_add_subnode (fdt, 0, "chosen");
+ 
+   if (node < 1)
+-    goto failure;
++    {
++      err = grub_error(grub_errno, "failed to load chosen fdt node.");
++      goto failure;
++    }
+ 
+   /* Set initrd info */
+   if (initrd_start && initrd_end > initrd_start)
+@@ -95,15 +100,26 @@ finalize_params_linux (void)
+       retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start",
+ 				    initrd_start);
+       if (retval)
+-	goto failure;
++	{
++	  err = grub_error(retval, "Failed to set linux,initrd-start property");
++	  goto failure;
++	}
++
+       retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-end",
+ 				    initrd_end);
+       if (retval)
+-	goto failure;
++	{
++	  err = grub_error(retval, "Failed to set linux,initrd-end property");
++	  goto failure;
++	}
+     }
+ 
+-  if (grub_fdt_install() != GRUB_ERR_NONE)
+-    goto failure;
++  retval = grub_fdt_install();
++  if (retval != GRUB_ERR_NONE)
++    {
++      err = grub_error(retval, "Failed to install fdt");
++      goto failure;
++    }
+ 
+   grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n",
+                 fdt);
+@@ -111,14 +127,20 @@ finalize_params_linux (void)
+   /* Convert command line to UCS-2 */
+   loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
+   if (!loaded_image)
+-    goto failure;
++    {
++      err = grub_error(grub_errno, "Failed to install fdt");
++      goto failure;
++    }
+ 
+   loaded_image->load_options_size = len =
+     (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t);
+   loaded_image->load_options =
+     grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
+   if (!loaded_image->load_options)
+-    return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters");
++    {
++      err = grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters");
++      goto failure;
++    }
+ 
+   loaded_image->load_options_size =
+     2 * grub_utf8_to_utf16 (loaded_image->load_options, len,
+@@ -128,7 +150,7 @@ finalize_params_linux (void)
+ 
+ failure:
+   grub_fdt_unload();
+-  return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT");
++  return err;
+ }
+ 
+ static void
+@@ -212,16 +234,28 @@ grub_linux_unload (void)
+ static void *
+ allocate_initrd_mem (int initrd_pages)
+ {
+-  grub_addr_t max_addr;
++  grub_addr_t max_addr = 0;
++  grub_err_t err;
++  void *ret;
+ 
+-  if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE)
+-    return NULL;
++  err = grub_efi_get_ram_base (&max_addr);
++  if (err != GRUB_ERR_NONE)
++    {
++      grub_error (err, "grub_efi_get_ram_base() failed");
++      return NULL;
++    }
++
++  grub_dprintf ("linux", "max_addr: 0x%016lx, INITRD_MAX_ADDRESS_OFFSET: 0x%016llx\n",
++		max_addr, INITRD_MAX_ADDRESS_OFFSET);
+ 
+   max_addr += INITRD_MAX_ADDRESS_OFFSET - 1;
++  grub_dprintf ("linux", "calling grub_efi_allocate_pages_real (0x%016lx, 0x%08x, EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_DATA)", max_addr, initrd_pages);
+ 
+-  return grub_efi_allocate_pages_real (max_addr, initrd_pages,
+-				       GRUB_EFI_ALLOCATE_MAX_ADDRESS,
+-				       GRUB_EFI_LOADER_DATA);
++  ret = grub_efi_allocate_pages_real (max_addr, initrd_pages,
++				      GRUB_EFI_ALLOCATE_MAX_ADDRESS,
++				      GRUB_EFI_LOADER_DATA);
++  grub_dprintf ("linux", "got 0x%016llx\n", (unsigned long long)ret);
++  return ret;
+ }
+ 
+ static grub_err_t
diff --git a/SOURCES/0097-grub-editenv-Add-incr-command-to-increment-integer-v.patch b/SOURCES/0097-grub-editenv-Add-incr-command-to-increment-integer-v.patch
deleted file mode 100644
index f8de42a..0000000
--- a/SOURCES/0097-grub-editenv-Add-incr-command-to-increment-integer-v.patch
+++ /dev/null
@@ -1,93 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Hans de Goede <hdegoede@redhat.com>
-Date: Mon, 4 Jun 2018 19:49:47 +0200
-Subject: [PATCH] grub-editenv: Add "incr" command to increment integer value
- env. variables
-
-To be able to automatically detect if the last boot was successful,
-We want to keep count of succesful / failed boots in some integer
-environment variable.
-
-This commit adds a grub-editenvt "incr" command to increment such
-integer value env. variables by 1 for use from various boot scripts.
-
-Signed-off-by: Hans de Goede <hdegoede@redhat.com>
----
- util/grub-editenv.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 50 insertions(+)
-
-diff --git a/util/grub-editenv.c b/util/grub-editenv.c
-index db6f187cc63..948eec8a114 100644
---- a/util/grub-editenv.c
-+++ b/util/grub-editenv.c
-@@ -53,6 +53,9 @@ static struct argp_option options[] = {
-   /* TRANSLATORS: "unset" is a keyword. It's a summary of "unset" subcommand.  */
-   {N_("unset [NAME ...]"),    0, 0, OPTION_DOC|OPTION_NO_USAGE,
-    N_("Delete variables."), 0},
-+  /* TRANSLATORS: "incr" is a keyword. It's a summary of "incr" subcommand.  */
-+  {N_("incr [NAME ...]"),     0, 0, OPTION_DOC|OPTION_NO_USAGE,
-+   N_("Increase value of integer variables."), 0},
- 
-   {0,         0, 0, OPTION_DOC, N_("Options:"), -1},
-   {"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
-@@ -253,6 +256,51 @@ unset_variables (const char *name, int argc, char *argv[])
-   grub_envblk_close (envblk);
- }
- 
-+struct get_int_value_params {
-+  char *varname;
-+  int value;
-+};
-+
-+static int
-+get_int_value (const char *varname, const char *value, void *hook_data)
-+{
-+  struct get_int_value_params *params = hook_data;
-+
-+  if (strcmp (varname, params->varname) == 0) {
-+    params->value = strtol (value, NULL, 10);
-+    return 1;
-+  }
-+  return 0;
-+}
-+
-+static void
-+incr_variables (const char *name, int argc, char *argv[])
-+{
-+  grub_envblk_t envblk;
-+  char buf[16];
-+
-+  envblk = open_envblk_file (name);
-+  while (argc)
-+    {
-+      struct get_int_value_params params = {
-+        .varname = argv[0],
-+        .value = 0, /* Consider unset variables 0 */
-+      };
-+
-+      grub_envblk_iterate (envblk, &params, get_int_value);
-+      snprintf(buf, sizeof(buf), "%d", params.value + 1);
-+
-+      if (! grub_envblk_set (envblk, argv[0], buf))
-+        grub_util_error ("%s", _("environment block too small"));
-+
-+      argc--;
-+      argv++;
-+    }
-+
-+  write_envblk (name, envblk);
-+  grub_envblk_close (envblk);
-+}
-+
- int
- main (int argc, char *argv[])
- {
-@@ -292,6 +340,8 @@ main (int argc, char *argv[])
-     set_variables (filename, argc - curindex, argv + curindex);
-   else if (strcmp (command, "unset") == 0)
-     unset_variables (filename, argc - curindex, argv + curindex);
-+  else if (strcmp (command, "incr") == 0)
-+    incr_variables (filename, argc - curindex, argv + curindex);
-   else
-     {
-       char *program = xstrdup(program_name);
diff --git a/SOURCES/0098-Add-auto-hide-menu-support.patch b/SOURCES/0098-Add-auto-hide-menu-support.patch
deleted file mode 100644
index efb76c4..0000000
--- a/SOURCES/0098-Add-auto-hide-menu-support.patch
+++ /dev/null
@@ -1,189 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Hans de Goede <hdegoede@redhat.com>
-Date: Wed, 6 Jun 2018 08:44:11 +0200
-Subject: [PATCH] Add auto-hide menu support
-
-On single-os systems we do not want to show the menu, unless something
-went wrong with the previous boot, in which case the user may need the
-menu to debug/fix the problem.
-
-This commit adds a new grub.d/00_menu_auto_hide file which emits a
-config snippet implementing this. I've chosen to do this in a separate
-grub.d file because chances of this going upstream are small and this way
-it will be easier to rebase.
-
-Since auto-hiding the menu requires detecting the previous boot was ok,
-we get fastboot support (where we don't check for a key at all) for free
-so this commit also adds support for this.
-
-The new config-file code uses the following variables:
-
-menu_auto_hide     Set this to "1" to activate the new auto-hide feature
-                   Set this to "2" to auto-hide the menu even when multiple
-                   operating systems are installed. Note the menu will still
-                   auto show after booting an other os as that won't set
-                   boot_success.
-menu_show_once     Set this to "1" to force showing the menu once.
-boot_success       The OS sets this to "1" to indicate a successful boot.
-boot_indeterminate The OS increments this integer when rebooting after e.g.
-                   installing updates or a selinux relabel.
-fastboot           If set to "1" and the conditions for auto-hiding the menu
-                   are met, the menu is not shown and all checks for keypresses
-                   are skipped, booting the default immediately.
-
-30_os-prober.in changes somewhat inspired by:
-https://git.launchpad.net/~ubuntu-core-dev/grub/+git/ubuntu/tree/debian/patches/quick_boot.patch
-
-Signed-off-by: Hans de Goede <hdegoede@redhat.com>
----
-Changes in v2:
--Drop shutdown_success tests, there is no meaningful way for systemd to set
- this flag (by the time it knows all filesystems are unmounted or read-only
--Drop fwsetup_once support, systemd already supports booting directly into
- the fwsetup by doing "systemctl reboot --firmware"
----
- Makefile.util.def                |  6 +++++
- util/grub.d/01_menu_auto_hide.in | 48 ++++++++++++++++++++++++++++++++++++++++
- util/grub.d/30_os-prober.in      | 18 +++++++++++++++
- 3 files changed, 72 insertions(+)
- create mode 100644 util/grub.d/01_menu_auto_hide.in
-
-diff --git a/Makefile.util.def b/Makefile.util.def
-index 41906486a71..04551e095bd 100644
---- a/Makefile.util.def
-+++ b/Makefile.util.def
-@@ -458,6 +458,12 @@ script = {
-   installdir = grubconf;
- };
- 
-+script = {
-+  name = '01_menu_auto_hide';
-+  common = util/grub.d/01_menu_auto_hide.in;
-+  installdir = grubconf;
-+};
-+
- script = {
-   name = '01_users';
-   common = util/grub.d/01_users.in;
-diff --git a/util/grub.d/01_menu_auto_hide.in b/util/grub.d/01_menu_auto_hide.in
-new file mode 100644
-index 00000000000..ad175870a54
---- /dev/null
-+++ b/util/grub.d/01_menu_auto_hide.in
-@@ -0,0 +1,48 @@
-+#! /bin/sh
-+
-+# Disable / skip generating menu-auto-hide config parts on serial terminals
-+for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do
-+  case "$x" in
-+    serial*)
-+      exit 0
-+      ;;
-+  esac
-+done
-+
-+cat << EOF
-+if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then
-+  set last_boot_ok=1
-+else
-+  set last_boot_ok=0
-+fi
-+
-+# Reset boot_indeterminate after a successful boot
-+if [ "\${boot_success}" = "1" ] ; then
-+  set boot_indeterminate=0
-+# Avoid boot_indeterminate causing the menu to be hidden more then once
-+elif [ "\${boot_indeterminate}" = "1" ]; then
-+  set boot_indeterminate=2
-+fi
-+set boot_success=0
-+save_env boot_success boot_indeterminate
-+
-+if [ x\$feature_timeout_style = xy ] ; then
-+  if [ "\${menu_show_once}" ]; then
-+    unset menu_show_once
-+    save_env menu_show_once
-+    set timeout_style=menu
-+    set timeout=60
-+  elif [ "\${menu_auto_hide}" -a "\${last_boot_ok}" = "1" ]; then
-+    set orig_timeout_style=\${timeout_style}
-+    set orig_timeout=\${timeout}
-+    if [ "\${fastboot}" = "1" ]; then
-+      # timeout_style=menu + timeout=0 avoids the countdown code keypress check
-+      set timeout_style=menu
-+      set timeout=0
-+    else
-+      set timeout_style=hidden
-+      set timeout=1
-+    fi
-+  fi
-+fi
-+EOF
-diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in
-index 4b27bd20153..3c9431cfcfb 100644
---- a/util/grub.d/30_os-prober.in
-+++ b/util/grub.d/30_os-prober.in
-@@ -42,6 +42,7 @@ if [ -z "${OSPROBED}" ] ; then
- fi
- 
- osx_entry() {
-+    found_other_os=1
-     # TRANSLATORS: it refers on the OS residing on device %s
-     onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
-     hints=""
-@@ -102,6 +103,7 @@ for OS in ${OSPROBED} ; do
- 
-   case ${BOOT} in
-     chain)
-+      found_other_os=1
- 
- 	  onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
-       cat << EOF
-@@ -132,6 +134,7 @@ EOF
- EOF
-     ;;
-     efi)
-+      found_other_os=1
- 
- 	EFIPATH=${DEVICE#*@}
- 	DEVICE=${DEVICE%@*}
-@@ -176,6 +179,7 @@ EOF
- 	  LINITRD="${LINITRD#/boot}"
- 	fi
- 
-+        found_other_os=1
- 	onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
- 	recovery_params="$(echo "${LPARAMS}" | grep single)" || true
- 	counter=1
-@@ -257,6 +261,7 @@ EOF
-       done
-     ;;
-     hurd)
-+      found_other_os=1
-       onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
-       cat << EOF
- menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' {
-@@ -283,6 +288,7 @@ EOF
- EOF
-     ;;
-     minix)
-+      found_other_os=1
- 	  cat << EOF
- menuentry "${LONGNAME} (on ${DEVICE}, Multiboot)" {
- EOF
-@@ -299,3 +305,15 @@ EOF
-     ;;
-   esac
- done
-+
-+# We override the results of the menu_auto_hide code here, this is a bit ugly,
-+# but grub-mkconfig writes out the file linearly, so this is the only way
-+if [ "${found_other_os}" = "1" ]; then
-+  cat << EOF
-+# Other OS found, undo autohiding of menu unless menu_auto_hide=2
-+if [ "\${orig_timeout_style}" -a "\${menu_auto_hide}" != "2" ]; then
-+  set timeout_style=\${orig_timeout_style}
-+  set timeout=\${orig_timeout}
-+fi
-+EOF
-+fi
diff --git a/SOURCES/0098-Try-to-pick-better-locations-for-kernel-and-initrd.patch b/SOURCES/0098-Try-to-pick-better-locations-for-kernel-and-initrd.patch
new file mode 100644
index 0000000..4f42ea5
--- /dev/null
+++ b/SOURCES/0098-Try-to-pick-better-locations-for-kernel-and-initrd.patch
@@ -0,0 +1,211 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 11 Jul 2019 17:17:02 +0200
+Subject: [PATCH] Try to pick better locations for kernel and initrd
+
+- Don't limit allocations on 64-bit platforms to < 0x[37f]fffffff if
+  we're using the "large" code model ; use __UINTPTR_MAX__.
+- Get the comparison right to check the address we've allocated.
+- Fix the allocation for the command line as well.
+
+*But*, when we did this some systems started failing badly; coudln't
+parse partition tables, etc.  What's going on here is the disk controller
+is silently failing DMAs to addresses above 4GB, so we're trying to parse
+uninitialized (or HW zeroed) ram when looking for the partition table,
+etc.
+
+So to limit this, we make grub_malloc() pick addresses below 4GB on
+x86_64, but the direct EFI page allocation functions can get addresses
+above that.
+
+Additionally, we now try to locate kernel+initrd+cmdline+etc below
+0x7fffffff, and if they're too big to fit any memory window there, then
+we try a higher address.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+[david.abdurachmanov: fix macro for riscv64]
+Signed-off-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/kern/efi/mm.c           |  8 ++++----
+ grub-core/loader/i386/efi/linux.c | 24 +++++++++++++++++-------
+ include/grub/arm/efi/memory.h     |  1 +
+ include/grub/arm64/efi/memory.h   |  1 +
+ include/grub/i386/efi/memory.h    |  1 +
+ include/grub/ia64/efi/memory.h    |  1 +
+ include/grub/riscv64/efi/memory.h |  1 +
+ include/grub/x86_64/efi/memory.h  |  4 +++-
+ 8 files changed, 29 insertions(+), 12 deletions(-)
+
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index 85ad4b4494..e84961d078 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -122,7 +122,7 @@ grub_efi_allocate_pages_max (grub_efi_physical_address_t max,
+   grub_efi_boot_services_t *b;
+   grub_efi_physical_address_t address = max;
+ 
+-  if (max > 0xffffffff)
++  if (max > GRUB_EFI_MAX_USABLE_ADDRESS)
+     return 0;
+ 
+   b = grub_efi_system_table->boot_services;
+@@ -480,7 +480,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
+     {
+       if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
+ #if 1
+-	  && desc->physical_start <= GRUB_EFI_MAX_USABLE_ADDRESS
++	  && desc->physical_start <= GRUB_EFI_MAX_ALLOCATION_ADDRESS
+ #endif
+ 	  && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000
+ 	  && desc->num_pages != 0)
+@@ -498,9 +498,9 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
+ #if 1
+ 	  if (BYTES_TO_PAGES (filtered_desc->physical_start)
+ 	      + filtered_desc->num_pages
+-	      > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS))
++	      > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS))
+ 	    filtered_desc->num_pages
+-	      = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS)
++	      = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS)
+ 		 - BYTES_TO_PAGES (filtered_desc->physical_start));
+ #endif
+ 
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 3017d0f3e5..33e981e76e 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -27,6 +27,7 @@
+ #include <grub/lib/cmdline.h>
+ #include <grub/efi/efi.h>
+ #include <grub/efi/linux.h>
++#include <grub/cpu/efi/memory.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -106,7 +107,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+       size += ALIGN_UP (grub_file_size (files[i]), 4);
+     }
+ 
+-  initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size));
++  initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size));
++  if (!initrd_mem)
++    initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size));
+   if (!initrd_mem)
+     {
+       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd"));
+@@ -202,8 +205,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  params = grub_efi_allocate_pages_max (0x3fffffff,
++  params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS,
+ 					BYTES_TO_PAGES(sizeof(*params)));
++  if (!params)
++    params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS,
++					  BYTES_TO_PAGES(sizeof(*params)));
+   if (! params)
+     {
+       grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
+@@ -273,8 +279,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ #endif
+ 
+   grub_dprintf ("linux", "setting up cmdline\n");
+-  linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff,
+-					 BYTES_TO_PAGES(lh->cmdline_size + 1));
++  linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS,
++					      BYTES_TO_PAGES(lh->cmdline_size + 1));
++  if (!linux_cmdline)
++    linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS,
++						BYTES_TO_PAGES(lh->cmdline_size + 1));
+   if (!linux_cmdline)
+     {
+       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline"));
+@@ -301,11 +310,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   kernel_mem = grub_efi_allocate_pages_max(lh->pref_address,
+ 					   BYTES_TO_PAGES(lh->init_size));
+-
+   if (!kernel_mem)
+-    kernel_mem = grub_efi_allocate_pages_max(0x3fffffff,
++    kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS,
++					     BYTES_TO_PAGES(lh->init_size));
++  if (!kernel_mem)
++    kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS,
+ 					     BYTES_TO_PAGES(lh->init_size));
+-
+   if (!kernel_mem)
+     {
+       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel"));
+diff --git a/include/grub/arm/efi/memory.h b/include/grub/arm/efi/memory.h
+index 2c64918e3f..a4c2ec8350 100644
+--- a/include/grub/arm/efi/memory.h
++++ b/include/grub/arm/efi/memory.h
+@@ -2,5 +2,6 @@
+ #include <grub/efi/memory.h>
+ 
+ #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff
++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
+ 
+ #endif /* ! GRUB_MEMORY_CPU_HEADER */
+diff --git a/include/grub/arm64/efi/memory.h b/include/grub/arm64/efi/memory.h
+index c6cb324171..acb61dca44 100644
+--- a/include/grub/arm64/efi/memory.h
++++ b/include/grub/arm64/efi/memory.h
+@@ -2,5 +2,6 @@
+ #include <grub/efi/memory.h>
+ 
+ #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL
++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
+ 
+ #endif /* ! GRUB_MEMORY_CPU_HEADER */
+diff --git a/include/grub/i386/efi/memory.h b/include/grub/i386/efi/memory.h
+index 2c64918e3f..a4c2ec8350 100644
+--- a/include/grub/i386/efi/memory.h
++++ b/include/grub/i386/efi/memory.h
+@@ -2,5 +2,6 @@
+ #include <grub/efi/memory.h>
+ 
+ #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff
++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
+ 
+ #endif /* ! GRUB_MEMORY_CPU_HEADER */
+diff --git a/include/grub/ia64/efi/memory.h b/include/grub/ia64/efi/memory.h
+index 2c64918e3f..a4c2ec8350 100644
+--- a/include/grub/ia64/efi/memory.h
++++ b/include/grub/ia64/efi/memory.h
+@@ -2,5 +2,6 @@
+ #include <grub/efi/memory.h>
+ 
+ #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff
++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
+ 
+ #endif /* ! GRUB_MEMORY_CPU_HEADER */
+diff --git a/include/grub/riscv64/efi/memory.h b/include/grub/riscv64/efi/memory.h
+index c6cb324171..acb61dca44 100644
+--- a/include/grub/riscv64/efi/memory.h
++++ b/include/grub/riscv64/efi/memory.h
+@@ -2,5 +2,6 @@
+ #include <grub/efi/memory.h>
+ 
+ #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL
++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
+ 
+ #endif /* ! GRUB_MEMORY_CPU_HEADER */
+diff --git a/include/grub/x86_64/efi/memory.h b/include/grub/x86_64/efi/memory.h
+index 46e9145a30..e81cfb3221 100644
+--- a/include/grub/x86_64/efi/memory.h
++++ b/include/grub/x86_64/efi/memory.h
+@@ -2,9 +2,11 @@
+ #include <grub/efi/memory.h>
+ 
+ #if defined (__code_model_large__)
+-#define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff
++#define GRUB_EFI_MAX_USABLE_ADDRESS __UINTPTR_MAX__
++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS 0x7fffffff
+ #else
+ #define GRUB_EFI_MAX_USABLE_ADDRESS 0x7fffffff
++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
+ #endif
+ 
+ #endif /* ! GRUB_MEMORY_CPU_HEADER */
diff --git a/SOURCES/0099-Add-grub-set-bootflag-utility.patch b/SOURCES/0099-Add-grub-set-bootflag-utility.patch
deleted file mode 100644
index f5ff7d3..0000000
--- a/SOURCES/0099-Add-grub-set-bootflag-utility.patch
+++ /dev/null
@@ -1,291 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Hans de Goede <hdegoede@redhat.com>
-Date: Tue, 12 Jun 2018 13:25:16 +0200
-Subject: [PATCH] Add grub-set-bootflag utility
-
-This commit adds a new grub-set-bootflag utility, which can be used
-to set known bootflags in the grubenv: boot_success or menu_show_once.
-
-grub-set-bootflag is different from grub-editenv in 2 ways:
-
-1) It is intended to be executed by regular users so must be installed
-as suid root. As such it is written to not use any existing grubenv
-related code for easy auditing.
-
-It can't be executed through pkexec because we want to call it under gdm
-and pkexec does not work under gdm due the gdm user having /sbin/nologin
-as shell.
-
-2) Since it can be executed by regular users it only allows setting
-(assigning a value of 1 to) bootflags which it knows about. Currently
-those are just boot_success and menu_show_once.
-
-This commit also adds a couple of example systemd and files which show
-how this can be used to set boot_success from a user-session:
-
-docs/grub-boot-success.service
-docs/grub-boot-success.timer
-
-The 2 grub-boot-success.systemd files should be placed in /lib/systemd/user
-and a symlink to grub-boot-success.timer should be added to
-/lib/systemd/user/timers.target.wants.
-
-Signed-off-by: Hans de Goede <hdegoede@redhat.com>
----
- Makefile.util.def              |   7 ++
- util/grub-set-bootflag.c       | 160 +++++++++++++++++++++++++++++++++++++++++
- conf/Makefile.extra-dist       |   3 +
- docs/grub-boot-success.service |   6 ++
- docs/grub-boot-success.timer   |   6 ++
- util/grub-set-bootflag.1       |  20 ++++++
- 6 files changed, 202 insertions(+)
- create mode 100644 util/grub-set-bootflag.c
- create mode 100644 docs/grub-boot-success.service
- create mode 100644 docs/grub-boot-success.timer
- create mode 100644 util/grub-set-bootflag.1
-
-diff --git a/Makefile.util.def b/Makefile.util.def
-index 04551e095bd..c6375933faa 100644
---- a/Makefile.util.def
-+++ b/Makefile.util.def
-@@ -1445,3 +1445,10 @@ program = {
-   ldadd = grub-core/lib/gnulib/libgnu.a;
-   ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
- };
-+
-+program = {
-+  name = grub-set-bootflag;
-+  installdir = sbin;
-+  mansection = 1;
-+  common = util/grub-set-bootflag.c;
-+};
-diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c
-new file mode 100644
-index 00000000000..bb198f02351
---- /dev/null
-+++ b/util/grub-set-bootflag.c
-@@ -0,0 +1,160 @@
-+/* grub-set-bootflag.c - tool to set boot-flags in the grubenv. */
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2018 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/>.
-+ */
-+
-+/*
-+ * NOTE this gets run by users as root (through pkexec), so this does not
-+ * use any grub library / util functions to allow for easy auditing.
-+ * The grub headers are only included to get certain defines.
-+ */
-+
-+#include <config-util.h>     /* For *_DIR_NAME defines */
-+#include <grub/types.h>
-+#include <grub/lib/envblk.h> /* For GRUB_ENVBLK_DEFCFG define */
-+#include <errno.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <unistd.h>
-+
-+#define GRUBENV "/" GRUB_BOOT_DIR_NAME "/" GRUB_DIR_NAME "/" GRUB_ENVBLK_DEFCFG
-+#define GRUBENV_SIZE 1024
-+
-+const char *bootflags[] = {
-+  "boot_success",
-+  "menu_show_once",
-+  NULL
-+};
-+
-+static void usage(void)
-+{
-+  int i;
-+
-+  fprintf (stderr, "Usage: 'grub-set-bootflag <bootflag>', where <bootflag> is one of:\n");
-+  for (i = 0; bootflags[i]; i++)
-+    fprintf (stderr, "  %s\n", bootflags[i]);
-+}
-+
-+int main(int argc, char *argv[])
-+{
-+  /* NOTE buf must be at least the longest bootflag length + 4 bytes */
-+  char env[GRUBENV_SIZE + 1], buf[64], *s;
-+  const char *bootflag;
-+  int i, len, ret;
-+  FILE *f;
-+
-+  if (argc != 2)
-+    {
-+      usage();
-+      return 1;
-+    }
-+
-+  for (i = 0; bootflags[i]; i++)
-+    if (!strcmp (argv[1], bootflags[i]))
-+      break;
-+  if (!bootflags[i])
-+    {
-+      fprintf (stderr, "Invalid bootflag: '%s'\n", argv[1]);
-+      usage();
-+      return 1;
-+    }
-+
-+  bootflag = bootflags[i];
-+  len = strlen (bootflag);
-+
-+  f = fopen (GRUBENV, "r");
-+  if (!f)
-+    {
-+      perror ("Error opening " GRUBENV " for reading");
-+      return 1;     
-+    }
-+
-+  ret = fread (env, 1, GRUBENV_SIZE, f);
-+  fclose (f);
-+  if (ret != GRUBENV_SIZE)
-+    {
-+      errno = EINVAL;
-+      perror ("Error reading from " GRUBENV);
-+      return 1;     
-+    }
-+
-+  /* 0 terminate env */
-+  env[GRUBENV_SIZE] = 0;
-+
-+  if (strncmp (env, GRUB_ENVBLK_SIGNATURE, strlen (GRUB_ENVBLK_SIGNATURE)))
-+    {
-+      fprintf (stderr, "Error invalid environment block\n");
-+      return 1;
-+    }
-+
-+  /* Find a pre-existing definition of the bootflag */
-+  s = strstr (env, bootflag);
-+  while (s && s[len] != '=')
-+    s = strstr (s + len, bootflag);
-+
-+  if (s && ((s[len + 1] != '0' && s[len + 1] != '1') || s[len + 2] != '\n'))
-+    {
-+      fprintf (stderr, "Pre-existing bootflag '%s' has unexpected value\n", bootflag);
-+      return 1;     
-+    }
-+
-+  /* No pre-existing bootflag? -> find free space */
-+  if (!s)
-+    {
-+      for (i = 0; i < (len + 3); i++)
-+        buf[i] = '#';
-+      buf[i] = 0;
-+      s = strstr (env, buf);
-+    }
-+
-+  if (!s)
-+    {
-+      fprintf (stderr, "No space in grubenv to store bootflag '%s'\n", bootflag);
-+      return 1;     
-+    }
-+
-+  /* The grubenv is not 0 terminated, so memcpy the name + '=' , '1', '\n' */
-+  snprintf(buf, sizeof(buf), "%s=1\n", bootflag);
-+  memcpy(s, buf, len + 3);
-+
-+  /* "r+", don't truncate so that the diskspace stays reserved */
-+  f = fopen (GRUBENV, "r+");
-+  if (!f)
-+    {
-+      perror ("Error opening " GRUBENV " for writing");
-+      return 1;     
-+    }
-+
-+  ret = fwrite (env, 1, GRUBENV_SIZE, f);
-+  if (ret != GRUBENV_SIZE)
-+    {
-+      perror ("Error writing to " GRUBENV);
-+      return 1;     
-+    }
-+
-+  ret = fflush (f);
-+  if (ret)
-+    {
-+      perror ("Error flushing " GRUBENV);
-+      return 1;     
-+    }
-+
-+  fsync (fileno (f));
-+  fclose (f);
-+
-+  return 0;
-+}
-diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist
-index b909f2c073a..ea58362b555 100644
---- a/conf/Makefile.extra-dist
-+++ b/conf/Makefile.extra-dist
-@@ -14,6 +14,9 @@ EXTRA_DIST += util/import_unicode.py
- EXTRA_DIST += docs/autoiso.cfg
- EXTRA_DIST += docs/grub.cfg
- EXTRA_DIST += docs/osdetect.cfg
-+EXTRA_DIST += docs/org.gnu.grub.policy
-+EXTRA_DIST += docs/grub-boot-success.service
-+EXTRA_DIST += docs/grub-boot-success.timer
- 
- EXTRA_DIST += conf/i386-cygwin-img-ld.sc
- 
-diff --git a/docs/grub-boot-success.service b/docs/grub-boot-success.service
-new file mode 100644
-index 00000000000..80e79584c91
---- /dev/null
-+++ b/docs/grub-boot-success.service
-@@ -0,0 +1,6 @@
-+[Unit]
-+Description=Mark boot as successful
-+
-+[Service]
-+Type=oneshot
-+ExecStart=/usr/sbin/grub2-set-bootflag boot_success
-diff --git a/docs/grub-boot-success.timer b/docs/grub-boot-success.timer
-new file mode 100644
-index 00000000000..5d8fcba21aa
---- /dev/null
-+++ b/docs/grub-boot-success.timer
-@@ -0,0 +1,6 @@
-+[Unit]
-+Description=Mark boot as successful after the user session has run 2 minutes
-+ConditionUser=!@system
-+
-+[Timer]
-+OnActiveSec=2min
-diff --git a/util/grub-set-bootflag.1 b/util/grub-set-bootflag.1
-new file mode 100644
-index 00000000000..57801da22a0
---- /dev/null
-+++ b/util/grub-set-bootflag.1
-@@ -0,0 +1,20 @@
-+.TH GRUB-SET-BOOTFLAG 1 "Tue Jun 12 2018"
-+.SH NAME
-+\fBgrub-set-bootflag\fR \(em Set a bootflag in the GRUB environment block.
-+
-+.SH SYNOPSIS
-+\fBgrub-set-bootflag\fR <\fIBOOTFLAG\fR>
-+
-+.SH DESCRIPTION
-+\fBgrub-set-bootflag\fR is a command line to set bootflags in GRUB's
-+stored environment.
-+
-+.SH COMMANDS
-+.TP
-+\fBBOOTFLAG\fR
-+.RS 7
-+Bootflag to set, one of \fIboot_success\fR or \fIshow_menu_once\fR.
-+.RE
-+
-+.SH SEE ALSO
-+.BR "info grub"
diff --git a/SOURCES/0099-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch b/SOURCES/0099-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch
new file mode 100644
index 0000000..77db523
--- /dev/null
+++ b/SOURCES/0099-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch
@@ -0,0 +1,199 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 11 Jul 2019 18:03:25 +0200
+Subject: [PATCH] Attempt to fix up all the places -Wsign-compare=error finds.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/emu/misc.c         |  2 +-
+ grub-core/lib/reed_solomon.c      |  4 ++--
+ grub-core/osdep/linux/blocklist.c |  2 +-
+ grub-core/osdep/linux/getroot.c   |  2 +-
+ grub-core/osdep/linux/hostdisk.c  |  2 +-
+ util/grub-fstest.c                |  2 +-
+ util/grub-menulst2cfg.c           |  2 +-
+ util/grub-mkfont.c                | 13 +++++++------
+ util/grub-probe.c                 |  2 +-
+ util/setup.c                      |  2 +-
+ 10 files changed, 17 insertions(+), 16 deletions(-)
+
+diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c
+index 0ff13bcaf8..d278c2921f 100644
+--- a/grub-core/kern/emu/misc.c
++++ b/grub-core/kern/emu/misc.c
+@@ -185,7 +185,7 @@ grub_util_get_image_size (const char *path)
+   sz = ftello (f);
+   if (sz < 0)
+     grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
+-  if (sz != (size_t) sz)
++  if (sz > (off_t)(GRUB_SIZE_MAX >> 1))
+     grub_util_error (_("file `%s' is too big"), path);
+   ret = (size_t) sz;
+ 
+diff --git a/grub-core/lib/reed_solomon.c b/grub-core/lib/reed_solomon.c
+index 467305b46a..79037c093f 100644
+--- a/grub-core/lib/reed_solomon.c
++++ b/grub-core/lib/reed_solomon.c
+@@ -157,7 +157,7 @@ static void
+ rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs)
+ {
+   gf_single_t *rs_polynomial;
+-  int i, j;
++  unsigned int i, j;
+   gf_single_t *m;
+   m = xcalloc (s + rs, sizeof (gf_single_t));
+   grub_memcpy (m, data, s * sizeof (gf_single_t));
+@@ -324,7 +324,7 @@ static void
+ encode_block (gf_single_t *ptr, grub_size_t s,
+ 	      gf_single_t *rptr, grub_size_t rs)
+ {
+-  int i, j;
++  unsigned int i, j;
+   for (i = 0; i < SECTOR_SIZE; i++)
+     {
+       grub_size_t ds = (s + SECTOR_SIZE - 1 - i) / SECTOR_SIZE;
+diff --git a/grub-core/osdep/linux/blocklist.c b/grub-core/osdep/linux/blocklist.c
+index c77d6085cc..42a315031f 100644
+--- a/grub-core/osdep/linux/blocklist.c
++++ b/grub-core/osdep/linux/blocklist.c
+@@ -109,7 +109,7 @@ grub_install_get_blocklist (grub_device_t root_dev,
+   else
+     {
+       struct fiemap *fie2;
+-      int i;
++      unsigned int i;
+       fie2 = xmalloc (sizeof (*fie2)
+ 		      + fie1.fm_mapped_extents
+ 		      * sizeof (fie1.fm_extents[1]));
+diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
+index 28790307e0..9f730b3518 100644
+--- a/grub-core/osdep/linux/getroot.c
++++ b/grub-core/osdep/linux/getroot.c
+@@ -236,7 +236,7 @@ grub_find_root_devices_from_btrfs (const char *dir)
+ {
+   int fd;
+   struct btrfs_ioctl_fs_info_args fsi;
+-  int i, j = 0;
++  unsigned int i, j = 0;
+   char **ret;
+ 
+   fd = open (dir, 0);
+diff --git a/grub-core/osdep/linux/hostdisk.c b/grub-core/osdep/linux/hostdisk.c
+index da62f924e3..7bc99ac1c1 100644
+--- a/grub-core/osdep/linux/hostdisk.c
++++ b/grub-core/osdep/linux/hostdisk.c
+@@ -83,7 +83,7 @@ grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_sec
+   if (sector_size & (sector_size - 1) || !sector_size)
+     return -1;
+   for (log_sector_size = 0;
+-       (1 << log_sector_size) < sector_size;
++       (1U << log_sector_size) < sector_size;
+        log_sector_size++);
+ 
+   if (log_secsize)
+diff --git a/util/grub-fstest.c b/util/grub-fstest.c
+index 8386564200..bfcef852d8 100644
+--- a/util/grub-fstest.c
++++ b/util/grub-fstest.c
+@@ -323,7 +323,7 @@ cmd_cmp (char *src, char *dest)
+   read_file (src, cmp_hook, ff);
+ 
+   {
+-    grub_uint64_t pre;
++    long long pre;
+     pre = ftell (ff);
+     fseek (ff, 0, SEEK_END);
+     if (pre != ftell (ff))
+diff --git a/util/grub-menulst2cfg.c b/util/grub-menulst2cfg.c
+index a39f869394..358d604210 100644
+--- a/util/grub-menulst2cfg.c
++++ b/util/grub-menulst2cfg.c
+@@ -34,7 +34,7 @@ main (int argc, char **argv)
+   char *buf = NULL;
+   size_t bufsize = 0;
+   char *suffix = xstrdup ("");
+-  int suffixlen = 0;
++  size_t suffixlen = 0;
+   const char *out_fname = 0;
+ 
+   grub_util_host_init (&argc, &argv);
+diff --git a/util/grub-mkfont.c b/util/grub-mkfont.c
+index 0fe45a6103..3e09240b99 100644
+--- a/util/grub-mkfont.c
++++ b/util/grub-mkfont.c
+@@ -138,7 +138,8 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face,
+   int width, height;
+   int cuttop, cutbottom, cutleft, cutright;
+   grub_uint8_t *data;
+-  int mask, i, j, bitmap_size;
++  int mask, i, bitmap_size;
++  unsigned int j;
+   FT_GlyphSlot glyph;
+   int flag = FT_LOAD_RENDER | FT_LOAD_MONOCHROME;
+   FT_Error err;
+@@ -183,7 +184,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face,
+     cuttop = cutbottom = cutleft = cutright = 0;
+   else
+     {
+-      for (cuttop = 0; cuttop < glyph->bitmap.rows; cuttop++)
++      for (cuttop = 0; cuttop < (long)glyph->bitmap.rows; cuttop++)
+ 	{
+ 	  for (j = 0; j < glyph->bitmap.width; j++)
+ 	    if (glyph->bitmap.buffer[j / 8 + cuttop * glyph->bitmap.pitch]
+@@ -203,10 +204,10 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face,
+ 	    break;
+ 	}
+       cutbottom = glyph->bitmap.rows - 1 - cutbottom;
+-      if (cutbottom + cuttop >= glyph->bitmap.rows)
++      if (cutbottom + cuttop >= (long)glyph->bitmap.rows)
+ 	cutbottom = 0;
+ 
+-      for (cutleft = 0; cutleft < glyph->bitmap.width; cutleft++)
++      for (cutleft = 0; cutleft < (long)glyph->bitmap.width; cutleft++)
+ 	{
+ 	  for (j = 0; j < glyph->bitmap.rows; j++)
+ 	    if (glyph->bitmap.buffer[cutleft / 8 + j * glyph->bitmap.pitch]
+@@ -225,7 +226,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face,
+ 	    break;
+ 	}
+       cutright = glyph->bitmap.width - 1 - cutright;
+-      if (cutright + cutleft >= glyph->bitmap.width)
++      if (cutright + cutleft >= (long)glyph->bitmap.width)
+ 	cutright = 0;
+     }
+ 
+@@ -262,7 +263,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face,
+ 
+   mask = 0;
+   data = &glyph_info->bitmap[0] - 1;
+-  for (j = cuttop; j < height + cuttop; j++)
++  for (j = cuttop; j < (long)height + cuttop; j++)
+     for (i = cutleft; i < width + cutleft; i++)
+       add_pixel (&data, &mask,
+ 		 glyph->bitmap.buffer[i / 8 + j * glyph->bitmap.pitch] &
+diff --git a/util/grub-probe.c b/util/grub-probe.c
+index c08e46bbb4..c6fac732b4 100644
+--- a/util/grub-probe.c
++++ b/util/grub-probe.c
+@@ -798,7 +798,7 @@ argp_parser (int key, char *arg, struct argp_state *state)
+ 
+     case 't':
+       {
+-	int i;
++	unsigned int i;
+ 
+ 	for (i = PRINT_FS; i < ARRAY_SIZE (targets); i++)
+ 	  if (strcmp (arg, targets[i]) == 0)
+diff --git a/util/setup.c b/util/setup.c
+index da5f2c07f5..8b22bb8cca 100644
+--- a/util/setup.c
++++ b/util/setup.c
+@@ -406,7 +406,7 @@ SETUP (const char *dir,
+     int is_ldm;
+     grub_err_t err;
+     grub_disk_addr_t *sectors;
+-    int i;
++    unsigned int i;
+     grub_fs_t fs;
+     unsigned int nsec, maxsec;
+ 
diff --git a/SOURCES/0100-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch b/SOURCES/0100-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch
new file mode 100644
index 0000000..03b4bbf
--- /dev/null
+++ b/SOURCES/0100-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch
@@ -0,0 +1,59 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 11 Jul 2019 18:20:37 +0200
+Subject: [PATCH] Don't use -Wno-sign-compare -Wno-conversion -Wno-error, do
+ use -Wextra.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ configure.ac         | 14 +++++++++++---
+ conf/Makefile.common |  2 +-
+ 2 files changed, 12 insertions(+), 4 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 7b4e1854d3..490353713a 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1452,11 +1452,11 @@ fi
+ # Set them to their new values for the tests below.
+ CC="$TARGET_CC"
+ if test x"$platform" = xemu ; then
+-CFLAGS="$TARGET_CFLAGS -Wno-error"
++CFLAGS="$TARGET_CFLAGS"
+ elif test "x$TARGET_APPLE_LINKER" = x1 ; then
+-CFLAGS="$TARGET_CFLAGS -nostdlib -static -Wno-error"
++CFLAGS="$TARGET_CFLAGS -nostdlib -static"
+ else
+-CFLAGS="$TARGET_CFLAGS -nostdlib -Wno-error"
++CFLAGS="$TARGET_CFLAGS -nostdlib"
+ fi
+ CPPFLAGS="$TARGET_CPPFLAGS"
+ 
+@@ -1990,6 +1990,14 @@ if test x"$enable_werror" != xno ; then
+   HOST_CFLAGS="$HOST_CFLAGS -Werror"
+ fi
+ 
++AC_ARG_ENABLE([wextra],
++	      [AS_HELP_STRING([--disable-wextra],
++                             [do not use -Wextra when building GRUB])])
++if test x"$enable_wextra" != xno ; then
++  TARGET_CFLAGS="$TARGET_CFLAGS -Wextra"
++  HOST_CFLAGS="$HOST_CFLAGS -Wextra"
++fi
++
+ TARGET_CPP="$TARGET_CC -E"
+ TARGET_CCAS=$TARGET_CC
+ 
+diff --git a/conf/Makefile.common b/conf/Makefile.common
+index 2ff9b39357..35e14ff017 100644
+--- a/conf/Makefile.common
++++ b/conf/Makefile.common
+@@ -66,7 +66,7 @@ grubconfdir = $(sysconfdir)/grub.d
+ platformdir = $(pkglibdir)/$(target_cpu)-$(platform)
+ starfielddir = $(pkgdatadir)/themes/starfield
+ 
+-CFLAGS_GNULIB = -Wno-undef -Wno-sign-compare -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Wno-conversion
++CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code
+ CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib
+ 
+ CFLAGS_POSIX = -fno-builtin
diff --git a/SOURCES/0100-docs-Add-grub-boot-indeterminate.service-example.patch b/SOURCES/0100-docs-Add-grub-boot-indeterminate.service-example.patch
deleted file mode 100644
index 44f6ad3..0000000
--- a/SOURCES/0100-docs-Add-grub-boot-indeterminate.service-example.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Hans de Goede <hdegoede@redhat.com>
-Date: Tue, 19 Jun 2018 15:20:54 +0200
-Subject: [PATCH] docs: Add grub-boot-indeterminate.service example
-
-This is an example service file, for use from
-/lib/systemd/system/system-update.target.wants
-to increment the boot_indeterminate variable when
-doing offline updates.
-
-Signed-off-by: Hans de Goede <hdegoede@redhat.com>
----
- docs/grub-boot-indeterminate.service | 11 +++++++++++
- 1 file changed, 11 insertions(+)
- create mode 100644 docs/grub-boot-indeterminate.service
-
-diff --git a/docs/grub-boot-indeterminate.service b/docs/grub-boot-indeterminate.service
-new file mode 100644
-index 00000000000..6c8dcb186b6
---- /dev/null
-+++ b/docs/grub-boot-indeterminate.service
-@@ -0,0 +1,11 @@
-+[Unit]
-+Description=Mark boot as indeterminate
-+DefaultDependencies=false
-+Requires=sysinit.target
-+After=sysinit.target
-+Wants=system-update-pre.target
-+Before=system-update-pre.target
-+
-+[Service]
-+Type=oneshot
-+ExecStart=/usr/bin/grub2-editenv - incr boot_indeterminate
diff --git a/SOURCES/0101-gentpl-add-disable-support.patch b/SOURCES/0101-gentpl-add-disable-support.patch
deleted file mode 100644
index 2c3c998..0000000
--- a/SOURCES/0101-gentpl-add-disable-support.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Wed, 11 Jul 2018 13:43:15 -0400
-Subject: [PATCH] gentpl: add 'disable = ' support
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- gentpl.py | 14 +++++++++++++-
- 1 file changed, 13 insertions(+), 1 deletion(-)
-
-diff --git a/gentpl.py b/gentpl.py
-index 2cba0bbbd6f..628e8bec1d7 100644
---- a/gentpl.py
-+++ b/gentpl.py
-@@ -592,11 +592,21 @@ def platform_conditional(platform, closure):
- #  };
- #
- def foreach_enabled_platform(defn, closure):
-+    enabled = False
-+    disabled = False
-     if 'enable' in defn:
-+        enabled = True
-         for platform in GRUB_PLATFORMS:
-             if platform_tagged(defn, platform, "enable"):
-                platform_conditional(platform, closure)
--    else:
-+
-+    if 'disable' in defn:
-+        disabled = True
-+        for platform in GRUB_PLATFORMS:
-+            if not platform_tagged(defn, platform, "disable"):
-+                platform_conditional(platform, closure)
-+
-+    if not enabled and not disabled:
-         for platform in GRUB_PLATFORMS:
-             platform_conditional(platform, closure)
- 
-@@ -655,6 +665,8 @@ def first_time(defn, snippet):
- def is_platform_independent(defn):
-     if 'enable' in defn:
-         return False
-+    if 'disable' in defn:
-+        return False
-     for suffix in [ "", "_nodist" ]:
-         template = platform_values(defn, GRUB_PLATFORMS[0], suffix)
-         for platform in GRUB_PLATFORMS[1:]:
diff --git a/SOURCES/0101-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch b/SOURCES/0101-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch
new file mode 100644
index 0000000..5a9c6f2
--- /dev/null
+++ b/SOURCES/0101-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch
@@ -0,0 +1,101 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 12 Jul 2019 09:53:32 +0200
+Subject: [PATCH] x86-efi: Use bounce buffers for reading to addresses > 4GB
+
+Lots of machines apparently can't DMA correctly above 4GB during UEFI,
+so use bounce buffers for the initramfs read.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/i386/efi/linux.c | 52 +++++++++++++++++++++++++++++++++------
+ 1 file changed, 45 insertions(+), 7 deletions(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 33e981e76e..2f0336809e 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -35,11 +35,16 @@ static grub_dl_t my_mod;
+ static int loaded;
+ static void *kernel_mem;
+ static grub_uint64_t kernel_size;
+-static grub_uint8_t *initrd_mem;
++static void *initrd_mem;
+ static grub_uint32_t handover_offset;
+ struct linux_kernel_params *params;
+ static char *linux_cmdline;
+ 
++#define MIN(a, b) \
++  ({ typeof (a) _a = (a); \
++     typeof (b) _b = (b); \
++     _a < _b ? _a : _b; })
++
+ #define BYTES_TO_PAGES(bytes)   (((bytes) + 0xfff) >> 12)
+ 
+ static grub_err_t
+@@ -73,6 +78,44 @@ grub_linuxefi_unload (void)
+   return GRUB_ERR_NONE;
+ }
+ 
++#define BOUNCE_BUFFER_MAX 0x10000000ull
++
++static grub_ssize_t
++read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len)
++{
++  grub_ssize_t bufpos = 0;
++  static grub_size_t bbufsz = 0;
++  static char *bbuf = NULL;
++
++  if (bbufsz == 0)
++    bbufsz = MIN(BOUNCE_BUFFER_MAX, len);
++
++  while (!bbuf && bbufsz)
++    {
++      bbuf = grub_malloc(bbufsz);
++      if (!bbuf)
++	bbufsz >>= 1;
++    }
++  if (!bbuf)
++    grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate bounce buffer"));
++
++  while (bufpos < (long long)len)
++    {
++      grub_ssize_t sz;
++
++      sz = grub_file_read (file, bbuf, MIN(bbufsz, len - bufpos));
++      if (sz < 0)
++	return sz;
++      if (sz == 0)
++	break;
++
++      grub_memcpy(bufp + bufpos, bbuf, sz);
++      bufpos += sz;
++    }
++
++  return bufpos;
++}
++
+ static grub_err_t
+ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+                  int argc, char *argv[])
+@@ -126,7 +169,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+   for (i = 0; i < nfiles; i++)
+     {
+       grub_ssize_t cursize = grub_file_size (files[i]);
+-      if (grub_file_read (files[i], ptr, cursize) != cursize)
++      if (read (files[i], ptr, cursize) != cursize)
+         {
+           if (!grub_errno)
+             grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
+@@ -152,11 +195,6 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+   return grub_errno;
+ }
+ 
+-#define MIN(a, b) \
+-  ({ typeof (a) _a = (a);  \
+-     typeof (b) _b = (b); \
+-     _a < _b ? _a : _b; })
+-
+ static grub_err_t
+ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 		int argc, char *argv[])
diff --git a/SOURCES/0102-gentpl-add-pc-firmware-type.patch b/SOURCES/0102-gentpl-add-pc-firmware-type.patch
deleted file mode 100644
index 96dd2b8..0000000
--- a/SOURCES/0102-gentpl-add-pc-firmware-type.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 11 Jul 2019 11:04:24 +0200
-Subject: [PATCH] gentpl: add 'pc' firmware type
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- gentpl.py | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/gentpl.py b/gentpl.py
-index 628e8bec1d7..34a4eba2b42 100644
---- a/gentpl.py
-+++ b/gentpl.py
-@@ -51,6 +51,7 @@ GROUPS["riscv32"]  = [ "riscv32_efi" ]
- GROUPS["riscv64"]  = [ "riscv64_efi" ]
- 
- # Groups based on firmware
-+GROUPS["pc"] = [ "i386_pc" ]
- GROUPS["efi"]  = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi",
- 		   "riscv32_efi", "riscv64_efi" ]
- GROUPS["ieee1275"]   = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ]
diff --git a/SOURCES/0102-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch b/SOURCES/0102-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch
new file mode 100644
index 0000000..9b10d68
--- /dev/null
+++ b/SOURCES/0102-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch
@@ -0,0 +1,133 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 13 Sep 2018 14:42:34 -0400
+Subject: [PATCH] x86-efi: Re-arrange grub_cmd_linux() a little bit.
+
+This just helps the next patch be easier to read.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/i386/efi/linux.c | 75 +++++++++++++++++++++------------------
+ 1 file changed, 41 insertions(+), 34 deletions(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 2f0336809e..5f48fa5561 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -243,32 +243,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS,
+-					BYTES_TO_PAGES(sizeof(*params)));
+-  if (!params)
+-    params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS,
+-					  BYTES_TO_PAGES(sizeof(*params)));
+-  if (! params)
+-    {
+-      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
+-      goto fail;
+-    }
++  lh = (struct linux_i386_kernel_header *)kernel;
++  grub_dprintf ("linux", "original lh is at %p\n", kernel);
+ 
+-  grub_dprintf ("linux", "params = %p\n", params);
+-
+-  grub_memset (params, 0, sizeof(*params));
+-
+-  setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201);
+-  grub_dprintf ("linux", "copying %lu bytes from %p to %p\n",
+-		MIN((grub_size_t)0x202+setup_header_end_offset,
+-		    sizeof (*params)) - 0x1f1,
+-		(grub_uint8_t *)kernel + 0x1f1,
+-		(grub_uint8_t *)params + 0x1f1);
+-  grub_memcpy ((grub_uint8_t *)params + 0x1f1,
+-	       (grub_uint8_t *)kernel + 0x1f1,
+-		MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1);
+-  lh = (struct linux_i386_kernel_header *)params;
+-  grub_dprintf ("linux", "lh is at %p\n", lh);
+   grub_dprintf ("linux", "checking lh->boot_flag\n");
+   if (lh->boot_flag != grub_cpu_to_le16 (0xaa55))
+     {
+@@ -316,6 +293,34 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+     }
+ #endif
+ 
++  params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS,
++					BYTES_TO_PAGES(sizeof(*params)));
++  if (!params)
++    params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS,
++					  BYTES_TO_PAGES(sizeof(*params)));
++  if (! params)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
++      goto fail;
++    }
++
++  grub_dprintf ("linux", "params = %p\n", params);
++
++  grub_memset (params, 0, sizeof(*params));
++
++  setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201);
++  grub_dprintf ("linux", "copying %lu bytes from %p to %p\n",
++		MIN((grub_size_t)0x202+setup_header_end_offset,
++		    sizeof (*params)) - 0x1f1,
++		(grub_uint8_t *)kernel + 0x1f1,
++		(grub_uint8_t *)params + 0x1f1);
++  grub_memcpy ((grub_uint8_t *)params + 0x1f1,
++	       (grub_uint8_t *)kernel + 0x1f1,
++		MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1);
++
++  lh = (struct linux_i386_kernel_header *)params;
++  grub_dprintf ("linux", "new lh is at %p\n", lh);
++
+   grub_dprintf ("linux", "setting up cmdline\n");
+   linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS,
+ 					      BYTES_TO_PAGES(lh->cmdline_size + 1));
+@@ -341,8 +346,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_dprintf ("linux", "setting lh->cmd_line_ptr\n");
+   lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline;
+ 
+-  grub_dprintf ("linux", "computing handover offset\n");
+   handover_offset = lh->handover_offset;
++  grub_dprintf("linux", "handover_offset: %08x\n", handover_offset);
+ 
+   start = (lh->setup_sects + 1) * 512;
+ 
+@@ -359,26 +364,28 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel"));
+       goto fail;
+     }
+-
+-  grub_dprintf ("linux", "kernel_mem = %lx\n", (unsigned long) kernel_mem);
++  grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem);
+ 
+   grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
+-  loaded=1;
++
++  loaded = 1;
++
+   grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem);
+   lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem;
+ 
+   grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start);
+ 
+-  grub_dprintf ("linux", "setting lh->type_of_loader\n");
+   lh->type_of_loader = 0x6;
++  grub_dprintf ("linux", "setting lh->type_of_loader = 0x%02x\n",
++		lh->type_of_loader);
+ 
+-  grub_dprintf ("linux", "setting lh->ext_loader_{type,ver}\n");
+   params->ext_loader_type = 0;
+   params->ext_loader_ver = 2;
+-  grub_dprintf("linux", "kernel_mem: %p handover_offset: %08x\n",
+-	       kernel_mem, handover_offset);
++  grub_dprintf ("linux",
++		"setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n",
++		params->ext_loader_type, params->ext_loader_ver);
+ 
+- fail:
++fail:
+   if (file)
+     grub_file_close (file);
+ 
diff --git a/SOURCES/0103-efinet-also-use-the-firmware-acceleration-for-http.patch b/SOURCES/0103-efinet-also-use-the-firmware-acceleration-for-http.patch
deleted file mode 100644
index 915b5aa..0000000
--- a/SOURCES/0103-efinet-also-use-the-firmware-acceleration-for-http.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 30 Jul 2018 14:06:42 -0400
-Subject: [PATCH] efinet: also use the firmware acceleration for http
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/net/efi/net.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
-index 4bb308026ce..6603cd83edc 100644
---- a/grub-core/net/efi/net.c
-+++ b/grub-core/net/efi/net.c
-@@ -1324,7 +1324,9 @@ grub_efi_net_boot_from_https (void)
- 	  && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
- 	{
- 	  grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp;
--	  return (grub_strncmp ((const char*)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0) ? 1 : 0;
-+	  grub_dprintf ("efinet", "url:%s\n", (const char *)uri_dp->uri);
-+	  return (grub_strncmp ((const char *)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0 ||
-+	          grub_strncmp ((const char *)uri_dp->uri, "http://", sizeof ("http://") - 1) == 0);
- 	}
- 
-       if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
diff --git a/SOURCES/0103-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch b/SOURCES/0103-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch
new file mode 100644
index 0000000..700c98b
--- /dev/null
+++ b/SOURCES/0103-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch
@@ -0,0 +1,258 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 12 Sep 2018 16:03:55 -0400
+Subject: [PATCH] x86-efi: Make our own allocator for kernel stuff
+
+This helps enable allocations above 4GB.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/i386/efi/linux.c | 167 +++++++++++++++++++++-----------------
+ 1 file changed, 94 insertions(+), 73 deletions(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 5f48fa5561..3e4f7ef39f 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -47,6 +47,65 @@ static char *linux_cmdline;
+ 
+ #define BYTES_TO_PAGES(bytes)   (((bytes) + 0xfff) >> 12)
+ 
++struct allocation_choice {
++    grub_efi_physical_address_t addr;
++    grub_efi_allocate_type_t alloc_type;
++};
++
++static struct allocation_choice max_addresses[] =
++  {
++    { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
++    { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
++    { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
++    { 0, 0 }
++  };
++
++static inline void
++kernel_free(void *addr, grub_efi_uintn_t size)
++{
++  if (addr && size)
++    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)addr,
++			 BYTES_TO_PAGES(size));
++}
++
++static void *
++kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
++{
++  void *addr = 0;
++  unsigned int i;
++  grub_efi_physical_address_t prev_max = 0;
++
++  for (i = 0; max_addresses[i].addr != 0 && addr == 0; i++)
++    {
++      grub_uint64_t max = max_addresses[i].addr;
++      grub_efi_uintn_t pages;
++
++      if (max == prev_max)
++	continue;
++
++      pages = BYTES_TO_PAGES(size);
++      grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n",
++		    pages, (void *)max);
++
++      prev_max = max;
++      addr = grub_efi_allocate_pages_real (max, pages,
++					   max_addresses[i].alloc_type,
++					   GRUB_EFI_LOADER_DATA);
++      if (addr)
++	grub_dprintf ("linux", "Allocated at %p\n", addr);
++    }
++
++  while (grub_error_pop ())
++    {
++      ;
++    }
++
++  if (addr == NULL)
++    grub_error (GRUB_ERR_OUT_OF_MEMORY, "%s", errmsg);
++
++  return addr;
++}
++
+ static grub_err_t
+ grub_linuxefi_boot (void)
+ {
+@@ -62,19 +121,12 @@ grub_linuxefi_unload (void)
+ {
+   grub_dl_unref (my_mod);
+   loaded = 0;
+-  if (initrd_mem)
+-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem,
+-			 BYTES_TO_PAGES(params->ramdisk_size));
+-  if (linux_cmdline)
+-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)
+-			 linux_cmdline,
+-			 BYTES_TO_PAGES(params->cmdline_size + 1));
+-  if (kernel_mem)
+-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem,
+-			 BYTES_TO_PAGES(kernel_size));
+-  if (params)
+-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params,
+-			 BYTES_TO_PAGES(16384));
++
++  kernel_free(initrd_mem, params->ramdisk_size);
++  kernel_free(linux_cmdline, params->cmdline_size + 1);
++  kernel_free(kernel_mem, kernel_size);
++  kernel_free(params, sizeof(*params));
++
+   return GRUB_ERR_NONE;
+ }
+ 
+@@ -150,19 +202,13 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+       size += ALIGN_UP (grub_file_size (files[i]), 4);
+     }
+ 
+-  initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size));
+-  if (!initrd_mem)
+-    initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size));
+-  if (!initrd_mem)
+-    {
+-      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd"));
+-      goto fail;
+-    }
+-
+-  grub_dprintf ("linux", "initrd_mem = %lx\n", (unsigned long) initrd_mem);
++  initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
++  if (initrd_mem == NULL)
++    goto fail;
++  grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
+ 
+   params->ramdisk_size = size;
+-  params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem;
++  params->ramdisk_image = initrd_mem;
+ 
+   ptr = initrd_mem;
+ 
+@@ -221,7 +267,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   filelen = grub_file_size (file);
+ 
+   kernel = grub_malloc(filelen);
+-
+   if (!kernel)
+     {
+       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
+@@ -274,7 +319,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-#if defined(__x86_64__) || defined(__aarch64__)
++#if defined(__x86_64__)
+   grub_dprintf ("linux", "checking lh->xloadflags\n");
+   if (!(lh->xloadflags & LINUX_XLF_KERNEL_64))
+     {
+@@ -293,17 +338,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+     }
+ #endif
+ 
+-  params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS,
+-					BYTES_TO_PAGES(sizeof(*params)));
++  params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters");
+   if (!params)
+-    params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS,
+-					  BYTES_TO_PAGES(sizeof(*params)));
+-  if (! params)
+-    {
+-      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
+-      goto fail;
+-    }
+-
++    goto fail;
+   grub_dprintf ("linux", "params = %p\n", params);
+ 
+   grub_memset (params, 0, sizeof(*params));
+@@ -322,19 +359,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_dprintf ("linux", "new lh is at %p\n", lh);
+ 
+   grub_dprintf ("linux", "setting up cmdline\n");
+-  linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS,
+-					      BYTES_TO_PAGES(lh->cmdline_size + 1));
++  linux_cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline"));
+   if (!linux_cmdline)
+-    linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS,
+-						BYTES_TO_PAGES(lh->cmdline_size + 1));
+-  if (!linux_cmdline)
+-    {
+-      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline"));
+-      goto fail;
+-    }
+-
+-  grub_dprintf ("linux", "linux_cmdline = %lx\n",
+-		(unsigned long)linux_cmdline);
++    goto fail;
++  grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline);
+ 
+   grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+   grub_create_loader_cmdline (argc, argv,
+@@ -343,27 +371,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 			      GRUB_VERIFY_KERNEL_CMDLINE);
+ 
+   grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline);
+-  grub_dprintf ("linux", "setting lh->cmd_line_ptr\n");
+-  lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline;
++  grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n",
++		linux_cmdline);
++  lh->cmd_line_ptr = linux_cmdline;
+ 
+   handover_offset = lh->handover_offset;
+-  grub_dprintf("linux", "handover_offset: %08x\n", handover_offset);
++  grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset);
+ 
+   start = (lh->setup_sects + 1) * 512;
+ 
+-  kernel_mem = grub_efi_allocate_pages_max(lh->pref_address,
+-					   BYTES_TO_PAGES(lh->init_size));
+-  if (!kernel_mem)
+-    kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS,
+-					     BYTES_TO_PAGES(lh->init_size));
+-  if (!kernel_mem)
+-    kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS,
+-					     BYTES_TO_PAGES(lh->init_size));
+-  if (!kernel_mem)
++  grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address);
++  if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS)
+     {
+-      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel"));
+-      goto fail;
++      max_addresses[0].addr = lh->pref_address;
++      max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS;
+     }
++  kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel"));
++  if (!kernel_mem)
++    goto fail;
+   grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem);
+ 
+   grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
+@@ -398,18 +423,14 @@ fail:
+       loaded = 0;
+     }
+ 
+-  if (linux_cmdline && lh && !loaded)
+-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)
+-			 linux_cmdline,
+-			 BYTES_TO_PAGES(lh->cmdline_size + 1));
++  if (!loaded)
++    {
++      if (lh)
++	kernel_free (linux_cmdline, lh->cmdline_size + 1);
+ 
+-  if (kernel_mem && !loaded)
+-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem,
+-			 BYTES_TO_PAGES(kernel_size));
+-
+-  if (params && !loaded)
+-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params,
+-			 BYTES_TO_PAGES(16384));
++      kernel_free (kernel_mem, kernel_size);
++      kernel_free (params, sizeof(*params));
++    }
+ 
+   return grub_errno;
+ }
diff --git a/SOURCES/0104-efi-http-Make-root_url-reflect-the-protocol-hostname.patch b/SOURCES/0104-efi-http-Make-root_url-reflect-the-protocol-hostname.patch
deleted file mode 100644
index 985a037..0000000
--- a/SOURCES/0104-efi-http-Make-root_url-reflect-the-protocol-hostname.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 30 Jul 2018 16:39:57 -0400
-Subject: [PATCH] efi/http: Make root_url reflect the protocol+hostname of our
- boot url.
-
-This lets you write config files that don't know urls.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/net/efi/http.c | 19 +++++++++++++++++++
- 1 file changed, 19 insertions(+)
-
-diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
-index 3f61fd2fa5b..243acbaa35b 100644
---- a/grub-core/net/efi/http.c
-+++ b/grub-core/net/efi/http.c
-@@ -4,6 +4,7 @@
- #include <grub/misc.h>
- #include <grub/net/efi.h>
- #include <grub/charset.h>
-+#include <grub/env.h>
- 
- static void
- http_configure (struct grub_efi_net_device *dev, int prefer_ip6)
-@@ -351,6 +352,24 @@ grub_efihttp_open (struct grub_efi_net_device *dev,
-   grub_err_t err;
-   grub_off_t size;
-   char *buf;
-+  char *root_url;
-+  grub_efi_ipv6_address_t address;
-+  const char *rest;
-+
-+  if (grub_efi_string_to_ip6_address (file->device->net->server, &address, &rest) && *rest == 0)
-+    root_url = grub_xasprintf ("%s://[%s]", type ? "https" : "http", file->device->net->server);
-+  else
-+    root_url = grub_xasprintf ("%s://%s", type ? "https" : "http", file->device->net->server);
-+  if (root_url)
-+    {
-+      grub_env_unset ("root_url");
-+      grub_env_set ("root_url", root_url);
-+      grub_free (root_url);
-+    }
-+  else
-+    {
-+      return grub_errno;
-+    }
- 
-   err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0);
-   if (err != GRUB_ERR_NONE)
diff --git a/SOURCES/0104-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch b/SOURCES/0104-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch
new file mode 100644
index 0000000..6ac11a1
--- /dev/null
+++ b/SOURCES/0104-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch
@@ -0,0 +1,171 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 12 Sep 2018 16:12:27 -0400
+Subject: [PATCH] x86-efi: Allow initrd+params+cmdline allocations above 4GB.
+
+This enables everything except the kernel itself to be above 4GB.
+Putting the kernel up there still doesn't work, because of the way
+params->code32_start is used.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/i386/efi/linux.c | 67 +++++++++++++++++++++++++++++++++++----
+ include/grub/i386/linux.h         |  6 +++-
+ 2 files changed, 65 insertions(+), 8 deletions(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 3e4f7ef39f..6bc18d5aef 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -52,13 +52,22 @@ struct allocation_choice {
+     grub_efi_allocate_type_t alloc_type;
+ };
+ 
+-static struct allocation_choice max_addresses[] =
++static struct allocation_choice max_addresses[4] =
+   {
++    /* the kernel overrides this one with pref_address and
++     * GRUB_EFI_ALLOCATE_ADDRESS */
+     { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
++    /* this one is always below 4GB, which we still *prefer* even if the flag
++     * is set. */
+     { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
++    /* If the flag in params is set, this one gets changed to be above 4GB. */
+     { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
+     { 0, 0 }
+   };
++static struct allocation_choice saved_addresses[4];
++
++#define save_addresses() grub_memcpy(saved_addresses, max_addresses, sizeof(max_addresses))
++#define restore_addresses() grub_memcpy(max_addresses, saved_addresses, sizeof(max_addresses))
+ 
+ static inline void
+ kernel_free(void *addr, grub_efi_uintn_t size)
+@@ -80,6 +89,11 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
+       grub_uint64_t max = max_addresses[i].addr;
+       grub_efi_uintn_t pages;
+ 
++      /*
++       * When we're *not* loading the kernel, or >4GB allocations aren't
++       * supported, these entries are basically all the same, so don't re-try
++       * the same parameters.
++       */
+       if (max == prev_max)
+ 	continue;
+ 
+@@ -168,6 +182,9 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len)
+   return bufpos;
+ }
+ 
++#define LOW_U32(val) ((grub_uint32_t)(((grub_addr_t)(val)) & 0xffffffffull))
++#define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull))
++
+ static grub_err_t
+ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+                  int argc, char *argv[])
+@@ -207,8 +224,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+     goto fail;
+   grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
+ 
+-  params->ramdisk_size = size;
+-  params->ramdisk_image = initrd_mem;
++  params->ramdisk_size = LOW_U32(size);
++  params->ramdisk_image = LOW_U32(initrd_mem);
++#if defined(__x86_64__)
++  params->ext_ramdisk_size = HIGH_U32(size);
++  params->ext_ramdisk_image = HIGH_U32(initrd_mem);
++#endif
+ 
+   ptr = initrd_mem;
+ 
+@@ -338,6 +359,18 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+     }
+ #endif
+ 
++#if defined(__x86_64__)
++  if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G)
++    {
++      grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n");
++      max_addresses[2].addr = GRUB_EFI_MAX_USABLE_ADDRESS;
++    }
++  else
++    {
++      grub_dprintf ("linux", "Loading kernel above 4GB is not supported\n");
++    }
++#endif
++
+   params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters");
+   if (!params)
+     goto fail;
+@@ -372,21 +405,40 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline);
+   grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n",
+-		linux_cmdline);
+-  lh->cmd_line_ptr = linux_cmdline;
++		LOW_U32(linux_cmdline));
++  lh->cmd_line_ptr = LOW_U32(linux_cmdline);
++#if defined(__x86_64__)
++  if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull)
++    {
++      grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n",
++		    HIGH_U32(linux_cmdline));
++      params->ext_cmd_line_ptr = HIGH_U32(linux_cmdline);
++    }
++#endif
+ 
+   handover_offset = lh->handover_offset;
+   grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset);
+ 
+   start = (lh->setup_sects + 1) * 512;
+ 
++  /*
++   * AFAICS >4GB for kernel *cannot* work because of params->code32_start being
++   * 32-bit and getting called unconditionally in head_64.S from either entry
++   * point.
++   *
++   * so nerf that out here...
++   */
++  save_addresses();
+   grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address);
+   if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS)
+     {
+       max_addresses[0].addr = lh->pref_address;
+       max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS;
+     }
++  max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
++  max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
+   kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel"));
++  restore_addresses();
+   if (!kernel_mem)
+     goto fail;
+   grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem);
+@@ -395,8 +447,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   loaded = 1;
+ 
+-  grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem);
+-  lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem;
++  grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n",
++		LOW_U32(kernel_mem));
++  lh->code32_start = LOW_U32(kernel_mem);
+ 
+   grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start);
+ 
+diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h
+index 25ef52c04e..fac22476cc 100644
+--- a/include/grub/i386/linux.h
++++ b/include/grub/i386/linux.h
+@@ -236,7 +236,11 @@ struct linux_kernel_params
+   grub_uint32_t ofw_cif_handler;	/* b8 */
+   grub_uint32_t ofw_idt;		/* bc */
+ 
+-  grub_uint8_t padding7[0x1b8 - 0xc0];
++  grub_uint32_t ext_ramdisk_image;	/* 0xc0 */
++  grub_uint32_t ext_ramdisk_size;	/* 0xc4 */
++  grub_uint32_t ext_cmd_line_ptr;	/* 0xc8 */
++
++  grub_uint8_t padding7[0x1b8 - 0xcc];
+ 
+   union
+     {
diff --git a/SOURCES/0105-Fix-getroot.c-s-trampolines.patch b/SOURCES/0105-Fix-getroot.c-s-trampolines.patch
new file mode 100644
index 0000000..e744b77
--- /dev/null
+++ b/SOURCES/0105-Fix-getroot.c-s-trampolines.patch
@@ -0,0 +1,47 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 28 Sep 2018 15:42:19 -0400
+Subject: [PATCH] Fix getroot.c's trampolines.
+
+This makes the stack executable on most of the grub utilities, which is
+bad, and rpmdiff complains about it.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/osdep/linux/getroot.c | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
+index 9f730b3518..f0c503f43d 100644
+--- a/grub-core/osdep/linux/getroot.c
++++ b/grub-core/osdep/linux/getroot.c
+@@ -1264,22 +1264,20 @@ grub_util_get_grub_dev_os (const char *os_dev)
+   return grub_dev;
+ }
+ 
++static void *mp = NULL;
++static void
++btrfs_mount_path_hook(const char *m)
++{
++  mp = strdup (m);
++}
+ 
+ char *
+ grub_util_get_btrfs_subvol (const char *path, char **mount_path)
+ {
+-  char *mp = NULL;
+-
+   if (mount_path)
+     *mount_path = NULL;
+ 
+-  auto void
+-  mount_path_hook (const char *m)
+-  {
+-    mp = strdup (m);
+-  }
+-
+-  grub_find_root_btrfs_mount_path_hook = mount_path_hook;
++  grub_find_root_btrfs_mount_path_hook = btrfs_mount_path_hook;
+   grub_free (grub_find_root_devices_from_mountinfo (path, NULL));
+   grub_find_root_btrfs_mount_path_hook = NULL;
+ 
diff --git a/SOURCES/0105-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch b/SOURCES/0105-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch
deleted file mode 100644
index b65eafc..0000000
--- a/SOURCES/0105-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch
+++ /dev/null
@@ -1,149 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 26 Jun 2018 17:16:06 -0400
-Subject: [PATCH] Make it so we can tell configure which cflags utils are built
- with
-
-This lets us have kernel.img be built with TARGET_CFLAGS but grub-mkimage and
-friends built with HOST_CFLAGS.  That in turn lets us build with an ARM compiler
-that only has hard-float ABI versions of crt*.o and libgcc*, but still use soft
-float for grub.efi.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- configure.ac         | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
- conf/Makefile.common | 23 ++++++++++++-----------
- gentpl.py            |  8 ++++----
- 3 files changed, 64 insertions(+), 16 deletions(-)
-
-diff --git a/configure.ac b/configure.ac
-index b4455e4732d..3405348178a 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -877,11 +877,23 @@ if ( test "x$target_cpu" = xi386 || test "x$target_cpu" = xx86_64 ) && test "x$p
-   TARGET_CFLAGS="$TARGET_CFLAGS -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow"
- fi
- 
-+# Should grub utils get the host CFLAGS, or the target CFLAGS?
-+AC_ARG_WITH([utils],
-+            AS_HELP_STRING([--with-utils=host|target|build],
-+                           [choose which flags to build utilities with. (default=target)]),
-+	    [have_with_utils=y],
-+	    [have_with_utils=n])
-+if test x"$have_with_utils" = xy ; then
-+  with_utils="$withval"
-+else
-+  with_utils=target
-+fi
-+
- # GRUB doesn't use float or doubles at all. Yet some toolchains may decide
- # that floats are a good fit to run instead of what's written in the code.
- # Given that floating point unit is disabled (if present to begin with)
- # when GRUB is running which may result in various hard crashes.
--if test x"$platform" != xemu ; then
-+if test x"$platform" != xemu -a x"$with_utils" == xtarget ; then
-   AC_CACHE_CHECK([for options to get soft-float], grub_cv_target_cc_soft_float, [
-     grub_cv_target_cc_soft_float=no
-     if test "x$target_cpu" = xarm64; then
-@@ -2018,6 +2030,41 @@ HOST_CPPFLAGS="$HOST_CPPFLAGS -I\$(top_builddir)/include"
- TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_srcdir)/include"
- TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_builddir)/include"
- 
-+case "$with_utils" in
-+  host)
-+    UTILS_CFLAGS=$HOST_CFLAGS
-+    UTILS_CPPFLAGS=$HOST_CPPFLAGS
-+    UTILS_CCASFLAGS=$HOST_CCASFLAGS
-+    UTILS_LDFLAGS=$HOST_LDFLAGS
-+    ;;
-+  target)
-+    UTILS_CFLAGS=$TARGET_CFLAGS
-+    UTILS_CPPFLAGS=$TARGET_CPPFLAGS
-+    UTILS_CCASFLAGS=$TARGET_CCASFLAGS
-+    UTILS_LDFLAGS=$TARGET_LDFLAGS
-+    ;;
-+  build)
-+    UTILS_CFLAGS=$BUILD_CFLAGS
-+    UTILS_CPPFLAGS=$BUILD_CPPFLAGS
-+    UTILS_CCASFLAGS=$BUILD_CCASFLAGS
-+    UTILS_LDFLAGS=$BUILD_LDFLAGS
-+    ;;
-+  *)
-+    AC_MSG_ERROR([--with-utils must be either host, target, or build])
-+    ;;
-+esac
-+AC_MSG_NOTICE([Using $with_utils flags for utilities.])
-+
-+unset CFLAGS
-+unset CPPFLAGS
-+unset CCASFLAGS
-+unset LDFLAGS
-+
-+AC_SUBST(UTILS_CFLAGS)
-+AC_SUBST(UTILS_CPPFLAGS)
-+AC_SUBST(UTILS_CCASFLAGS)
-+AC_SUBST(UTILS_LDFLAGS)
-+
- GRUB_TARGET_CPU="${target_cpu}"
- GRUB_PLATFORM="${platform}"
- 
-diff --git a/conf/Makefile.common b/conf/Makefile.common
-index 5f0ef969857..2ff9b39357c 100644
---- a/conf/Makefile.common
-+++ b/conf/Makefile.common
-@@ -40,24 +40,25 @@ CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1
- CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
- STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx -R .note.gnu.property -R .gnu.build.attributes
- 
--CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding
--LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d
--CPPFLAGS_MODULE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM)
--CCASFLAGS_MODULE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
-+CFLAGS_MODULE = $(TARGET_CFLAGS) $(CFLAGS_PLATFORM) -ffreestanding
-+LDFLAGS_MODULE = $(TARGET_LDFLAGS) $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d
-+CPPFLAGS_MODULE = $(TARGET_CPPFLAGS) $(CPPFLAGS_DEFAULT) $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM)
-+CCASFLAGS_MODULE = $(TARGET_CCASFLAGS) $(CCASFLAGS_DEFAULT) $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
- 
- CFLAGS_IMAGE = $(CFLAGS_PLATFORM) -fno-builtin
- LDFLAGS_IMAGE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-S
- CPPFLAGS_IMAGE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM)
- CCASFLAGS_IMAGE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
- 
--CFLAGS_PROGRAM =
--LDFLAGS_PROGRAM =
--CPPFLAGS_PROGRAM =
--CCASFLAGS_PROGRAM =
-+CFLAGS_PROGRAM = $(UTILS_CFLAGS)
-+LDFLAGS_PROGRAM = $(UTILS_LDFLAGS)
-+CPPFLAGS_PROGRAM = $(UTILS_CPPFLAGS)
-+CCASFLAGS_PROGRAM = $(UTILS_CCASFLAGS)
- 
--CFLAGS_LIBRARY =
--CPPFLAGS_LIBRARY =
--CCASFLAGS_LIBRARY =
-+CFLAGS_LIBRARY = $(UTILS_CFLAGS)
-+LDFLAGS_LIBRARY = $(UTILS_LDFLAGS)
-+CPPFLAGS_LIBRARY = $(UTILS_CPPFLAGS)
-+CCASFLAGS_LIBRARY = $(UTILS_CCASFLAGS)
- 
- # Other variables
- 
-diff --git a/gentpl.py b/gentpl.py
-index 34a4eba2b42..59f62ef9522 100644
---- a/gentpl.py
-+++ b/gentpl.py
-@@ -697,10 +697,10 @@ def module(defn, platform):
-     var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform) + " ## platform sources")
-     var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + " ## platform nodist sources")
-     var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform))
--    var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_MODULE) " + platform_cflags(defn, platform))
--    var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_MODULE) " + platform_ldflags(defn, platform))
--    var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform))
--    var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform))
-+    var_set(cname(defn) + "_CFLAGS", "$(CFLAGS_MODULE) " + platform_cflags(defn, platform))
-+    var_set(cname(defn) + "_LDFLAGS", "$(LDFLAGS_MODULE) " + platform_ldflags(defn, platform))
-+    var_set(cname(defn) + "_CPPFLAGS", "$(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform))
-+    var_set(cname(defn) + "_CCASFLAGS", "$(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform))
-     var_set(cname(defn) + "_DEPENDENCIES", "$(TARGET_OBJ2ELF) " + platform_dependencies(defn, platform))
- 
-     gvar_add("dist_noinst_DATA", extra_dist(defn))
diff --git a/SOURCES/0106-Do-not-allow-stack-trampolines-anywhere.patch b/SOURCES/0106-Do-not-allow-stack-trampolines-anywhere.patch
new file mode 100644
index 0000000..658c7a4
--- /dev/null
+++ b/SOURCES/0106-Do-not-allow-stack-trampolines-anywhere.patch
@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 12 Jul 2019 10:06:50 +0200
+Subject: [PATCH] Do not allow stack trampolines, anywhere.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ configure.ac         | 3 +++
+ conf/Makefile.common | 2 +-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index 490353713a..a02d40a05b 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1998,6 +1998,9 @@ if test x"$enable_wextra" != xno ; then
+   HOST_CFLAGS="$HOST_CFLAGS -Wextra"
+ fi
+ 
++TARGET_CFLAGS="$TARGET_CFLAGS -Werror=trampolines -fno-trampolines"
++HOST_CFLAGS="$HOST_CFLAGS -Werror=trampolines -fno-trampolines"
++
+ TARGET_CPP="$TARGET_CC -E"
+ TARGET_CCAS=$TARGET_CC
+ 
+diff --git a/conf/Makefile.common b/conf/Makefile.common
+index 35e14ff017..0647c53b91 100644
+--- a/conf/Makefile.common
++++ b/conf/Makefile.common
+@@ -66,7 +66,7 @@ grubconfdir = $(sysconfdir)/grub.d
+ platformdir = $(pkglibdir)/$(target_cpu)-$(platform)
+ starfielddir = $(pkgdatadir)/themes/starfield
+ 
+-CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code
++CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Werror=trampolines -fno-trampolines
+ CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib
+ 
+ CFLAGS_POSIX = -fno-builtin
diff --git a/SOURCES/0106-module-verifier-make-it-possible-to-run-checkers-on-.patch b/SOURCES/0106-module-verifier-make-it-possible-to-run-checkers-on-.patch
deleted file mode 100644
index e31b38f..0000000
--- a/SOURCES/0106-module-verifier-make-it-possible-to-run-checkers-on-.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Wed, 1 Aug 2018 10:24:52 -0400
-Subject: [PATCH] module-verifier: make it possible to run checkers on
- grub-module-verifierxx.c
-
-This makes it so you can treat grub-module-verifierxx.c as a file you can
-build directly, so syntax checkers like vim's "syntastic" plugin, which uses
-"gcc -x c -fsyntax-only" to build it, will work.
-
-One still has to do whatever setup is required to make it pick the right
-include dirs, which -W options we use, etc., but this makes it so you can do
-the checking on the file you're editing, rather than on a different file.
-
-v2: fix the typo in the #else clause in util/grub-module-verifierXX.c
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- util/grub-module-verifier32.c | 2 ++
- util/grub-module-verifier64.c | 2 ++
- util/grub-module-verifierXX.c | 9 +++++++++
- 3 files changed, 13 insertions(+)
-
-diff --git a/util/grub-module-verifier32.c b/util/grub-module-verifier32.c
-index 257229f8f08..ba7d41aafea 100644
---- a/util/grub-module-verifier32.c
-+++ b/util/grub-module-verifier32.c
-@@ -1,2 +1,4 @@
- #define MODULEVERIFIER_ELF32 1
-+#ifndef GRUB_MODULE_VERIFIERXX
- #include "grub-module-verifierXX.c"
-+#endif
-diff --git a/util/grub-module-verifier64.c b/util/grub-module-verifier64.c
-index 4db6b4bedd1..fc23ef800b3 100644
---- a/util/grub-module-verifier64.c
-+++ b/util/grub-module-verifier64.c
-@@ -1,2 +1,4 @@
- #define MODULEVERIFIER_ELF64 1
-+#ifndef GRUB_MODULE_VERIFIERXX
- #include "grub-module-verifierXX.c"
-+#endif
-diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c
-index ceb24309aec..a98e2f9b1ac 100644
---- a/util/grub-module-verifierXX.c
-+++ b/util/grub-module-verifierXX.c
-@@ -1,3 +1,12 @@
-+#define GRUB_MODULE_VERIFIERXX
-+#if !defined(MODULEVERIFIER_ELF32) && !defined(MODULEVERIFIER_ELF64)
-+#if __SIZEOF_POINTER__ == 8
-+#include "grub-module-verifier64.c"
-+#else
-+#include "grub-module-verifier32.c"
-+#endif
-+#endif
-+
- #include <string.h>
- 
- #include <grub/elf.h>
diff --git a/SOURCES/0107-Reimplement-boot_counter.patch b/SOURCES/0107-Reimplement-boot_counter.patch
new file mode 100644
index 0000000..d018de4
--- /dev/null
+++ b/SOURCES/0107-Reimplement-boot_counter.patch
@@ -0,0 +1,196 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 4 Oct 2018 14:22:09 -0400
+Subject: [PATCH] Reimplement boot_counter
+
+This adds "increment" and "decrement" commands, and uses them to maintain our
+variables in 01_fallback_counter.  It also simplifies the counter logic, so
+that there are no nested tests that conflict with each other.
+
+Apparently, this *really* wasn't tested well enough.
+
+Resolves: rhbz#1614637
+Signed-off-by: Peter Jones <pjones@redhat.com>
+[lorbus: add comments and revert logic changes in 01_fallback_counting]
+Signed-off-by: Christian Glombek <lorbus@fedoraproject.org>
+---
+ Makefile.util.def                   |   6 +++
+ grub-core/Makefile.core.def         |   5 ++
+ grub-core/commands/increment.c      | 105 ++++++++++++++++++++++++++++++++++++
+ util/grub.d/01_fallback_counting.in |  22 ++++++++
+ 4 files changed, 138 insertions(+)
+ create mode 100644 grub-core/commands/increment.c
+ create mode 100644 util/grub.d/01_fallback_counting.in
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index d066652e9b..e10fe766d1 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -458,6 +458,12 @@ script = {
+   installdir = grubconf;
+ };
+ 
++script = {
++  name = '01_fallback_counting';
++  common = util/grub.d/01_fallback_counting.in;
++  installdir = grubconf;
++};
++
+ script = {
+   name = '01_menu_auto_hide';
+   common = util/grub.d/01_menu_auto_hide.in;
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 4f203533f5..ea4d59f51b 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -398,6 +398,11 @@ kernel = {
+   extra_dist = kern/mips/cache_flush.S;
+ };
+ 
++module = {
++  name = increment;
++  common = commands/increment.c;
++};
++
+ program = {
+   name = grub-emu;
+   mansection = 1;
+diff --git a/grub-core/commands/increment.c b/grub-core/commands/increment.c
+new file mode 100644
+index 0000000000..79cf137656
+--- /dev/null
++++ b/grub-core/commands/increment.c
+@@ -0,0 +1,105 @@
++/* increment.c - Commands to increment and decrement variables. */
++/*
++ *  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>
++#include <grub/env.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++typedef enum {
++    INCREMENT,
++    DECREMENT,
++} operation;
++
++static grub_err_t
++incr_decr(operation op, int argc, char **args)
++{
++  const char *old;
++  char *new;
++  long value;
++
++  if (argc < 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("no variable specified"));
++  if (argc > 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("too many arguments"));
++
++  old = grub_env_get (*args);
++  if (!old)
++    return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("No such variable \"%s\""),
++		       *args);
++
++  value = grub_strtol (old, NULL, 0);
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
++
++  switch (op)
++    {
++    case INCREMENT:
++      value += 1;
++      break;
++    case DECREMENT:
++      value -= 1;
++      break;
++    }
++
++  new = grub_xasprintf ("%ld", value);
++  if (!new)
++    return grub_errno;
++
++  grub_env_set (*args, new);
++  grub_free (new);
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_cmd_incr(struct grub_command *cmd UNUSED,
++              int argc, char **args)
++{
++  return incr_decr(INCREMENT, argc, args);
++}
++
++static grub_err_t
++grub_cmd_decr(struct grub_command *cmd UNUSED,
++              int argc, char **args)
++{
++  return incr_decr(DECREMENT, argc, args);
++}
++
++static grub_command_t cmd_incr, cmd_decr;
++
++GRUB_MOD_INIT(increment)
++{
++  cmd_incr = grub_register_command ("increment", grub_cmd_incr, N_("VARIABLE"),
++                                    N_("increment VARIABLE"));
++  cmd_decr = grub_register_command ("decrement", grub_cmd_decr, N_("VARIABLE"),
++                                    N_("decrement VARIABLE"));
++}
++
++GRUB_MOD_FINI(increment)
++{
++  grub_unregister_command (cmd_incr);
++  grub_unregister_command (cmd_decr);
++}
+diff --git a/util/grub.d/01_fallback_counting.in b/util/grub.d/01_fallback_counting.in
+new file mode 100644
+index 0000000000..be0e770ea8
+--- /dev/null
++++ b/util/grub.d/01_fallback_counting.in
+@@ -0,0 +1,22 @@
++#! /bin/sh -e
++
++# Boot Counting
++# The boot_counter env var can be used to count down boot attempts after an
++# OSTree upgrade and choose the rollback deployment when 0 is reached.  Both
++# boot_counter and boot_success need to be (re-)set from userspace.
++cat << EOF
++insmod increment
++# Check if boot_counter exists and boot_success=0 to activate this behaviour.
++if [ -n "\${boot_counter}" -a "\${boot_success}" = "0" ]; then
++  # if countdown has ended, choose to boot rollback deployment (default=1 on
++  # OSTree-based systems)
++  if  [ "\${boot_counter}" = "0" -o "\${boot_counter}" = "-1" ]; then
++    set default=1
++    set boot_counter=-1
++  # otherwise decrement boot_counter
++  else
++    decrement boot_counter
++  fi
++  save_env boot_counter
++fi
++EOF
diff --git a/SOURCES/0107-Rework-how-the-fdt-command-builds.patch b/SOURCES/0107-Rework-how-the-fdt-command-builds.patch
deleted file mode 100644
index 71328da..0000000
--- a/SOURCES/0107-Rework-how-the-fdt-command-builds.patch
+++ /dev/null
@@ -1,118 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 11 Jul 2019 13:01:41 +0200
-Subject: [PATCH] Rework how the fdt command builds.
-
-Trying to avoid all variants of:
-cat syminfo.lst | sort | gawk -f ../../grub-core/genmoddep.awk > moddep.lst || (rm -f moddep.lst; exit 1)
-grub_fdt_install in linux is not defined
-grub_fdt_load in linux is not defined
-grub_fdt_unload in linux is not defined
-grub_fdt_install in xen_boot is not defined
-grub_fdt_load in xen_boot is not defined
-grub_fdt_unload in xen_boot is not defined
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/Makefile.core.def | 5 ++---
- grub-core/lib/fdt.c         | 2 --
- grub-core/loader/efi/fdt.c  | 2 ++
- include/grub/fdt.h          | 4 ++++
- grub-core/Makefile.am       | 1 +
- 5 files changed, 9 insertions(+), 5 deletions(-)
-
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index c40170f2dd2..84a3d89de9a 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -177,7 +177,6 @@ kernel = {
-   arm_coreboot = kern/arm/coreboot/init.c;
-   arm_coreboot = kern/arm/coreboot/timer.c;
-   arm_coreboot = kern/arm/coreboot/coreboot.S;
--  arm_coreboot = lib/fdt.c;
-   arm_coreboot = bus/fdt.c;
-   arm_coreboot = term/ps2.c;
-   arm_coreboot = term/arm/pl050.c;
-@@ -351,6 +350,8 @@ kernel = {
-   riscv64 = kern/riscv/cache_flush.S;
-   riscv64 = kern/riscv/dl.c;
- 
-+  fdt = lib/fdt.c;
-+
-   emu = disk/host.c;
-   emu = kern/emu/cache_s.S;
-   emu = kern/emu/hostdisk.c;
-@@ -1825,7 +1826,6 @@ module = {
-   riscv32 = loader/riscv/linux.c;
-   riscv64 = loader/riscv/linux.c;
-   emu = loader/emu/linux.c;
--  fdt = lib/fdt.c;
- 
-   common = loader/linux.c;
-   common = lib/cmdline.c;
-@@ -1836,7 +1836,6 @@ module = {
- module = {
-   name = fdt;
-   efi = loader/efi/fdt.c;
--  common = lib/fdt.c;
-   enable = fdt;
- };
- 
-diff --git a/grub-core/lib/fdt.c b/grub-core/lib/fdt.c
-index 0d371c5633e..37e04bd69e7 100644
---- a/grub-core/lib/fdt.c
-+++ b/grub-core/lib/fdt.c
-@@ -21,8 +21,6 @@
- #include <grub/mm.h>
- #include <grub/dl.h>
- 
--GRUB_MOD_LICENSE ("GPLv3+");
--
- #define FDT_SUPPORTED_VERSION	17
- 
- #define FDT_BEGIN_NODE	0x00000001
-diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c
-index c86f283d756..c572415d38a 100644
---- a/grub-core/loader/efi/fdt.c
-+++ b/grub-core/loader/efi/fdt.c
-@@ -27,6 +27,8 @@
- #include <grub/efi/memory.h>
- #include <grub/cpu/efi/memory.h>
- 
-+GRUB_MOD_LICENSE ("GPLv3+");
-+
- static void *loaded_fdt;
- static void *fdt;
- 
-diff --git a/include/grub/fdt.h b/include/grub/fdt.h
-index e609c7e4111..22b7c5463fc 100644
---- a/include/grub/fdt.h
-+++ b/include/grub/fdt.h
-@@ -19,6 +19,8 @@
- #ifndef GRUB_FDT_HEADER
- #define GRUB_FDT_HEADER	1
- 
-+#if defined(__arm__) || defined(__aarch64__)
-+
- #include <grub/types.h>
- #include <grub/symbol.h>
- 
-@@ -144,4 +146,6 @@ int EXPORT_FUNC(grub_fdt_set_prop) (void *fdt, unsigned int nodeoffset, const ch
-   grub_fdt_set_prop ((fdt), (nodeoffset), "reg", reg_64, 16);  \
- })
- 
-+#endif /* defined(__arm__) || defined(__aarch64__) */
-+
- #endif	/* ! GRUB_FDT_HEADER */
-diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
-index f512573c0da..dd49939aaa9 100644
---- a/grub-core/Makefile.am
-+++ b/grub-core/Makefile.am
-@@ -76,6 +76,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/sb.h
- KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env.h
- KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env_private.h
- KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/err.h
-+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fdt.h
- KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/file.h
- KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fs.h
- KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i18n.h
diff --git a/SOURCES/0108-Disable-non-wordsize-allocations-on-arm.patch b/SOURCES/0108-Disable-non-wordsize-allocations-on-arm.patch
deleted file mode 100644
index f614c9e..0000000
--- a/SOURCES/0108-Disable-non-wordsize-allocations-on-arm.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 2 Aug 2018 10:56:38 -0400
-Subject: [PATCH] Disable non-wordsize allocations on arm
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- configure.ac | 20 ++++++++++++++++++++
- 1 file changed, 20 insertions(+)
-
-diff --git a/configure.ac b/configure.ac
-index 3405348178a..152e7dba652 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1288,6 +1288,26 @@ if test "x$target_cpu" = xarm; then
-     done
-   ])
- 
-+  AC_CACHE_CHECK([for options to disable movt and movw relocations],
-+		 grub_cv_target_cc_mword_relocations,
-+		 [grub_cv_target_cc_mword_relocations=no
-+		  for cand in "-mword-relocations" ; do
-+		    if test x"$grub_cv_target_cc_mword_relocations" != xno ; then
-+		      break
-+		    fi
-+		    CFLAGS="$TARGET_CFLAGS $cand -Werror"
-+		    CPPFLAGS="$TARGET_CPPFLAGS"
-+		    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
-+				      [grub_cv_target_cc_mword_relocations="$cand"],
-+				      [])
-+		  done
-+		 ])
-+  if test x"$grub_cv_target_cc_mword_relocations" = xno ; then
-+    AC_MSG_ERROR(["your compiler doesn't support disabling movw/movt relocations"])
-+  else
-+    TARGET_CFLAGS="$TARGET_CFLAGS $grub_cv_target_cc_mword_relocations"
-+  fi
-+
-   if test x"$grub_cv_target_cc_mno_movt" != xno ; then
-     # A trick so that clang doesn't see it on link stage
-     TARGET_CPPFLAGS="$TARGET_CPPFLAGS $grub_cv_target_cc_mno_movt"
diff --git a/SOURCES/0108-Fix-menu-entry-selection-based-on-ID-and-title.patch b/SOURCES/0108-Fix-menu-entry-selection-based-on-ID-and-title.patch
new file mode 100644
index 0000000..af74901
--- /dev/null
+++ b/SOURCES/0108-Fix-menu-entry-selection-based-on-ID-and-title.patch
@@ -0,0 +1,233 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 19 Oct 2018 10:57:52 -0400
+Subject: [PATCH] Fix menu entry selection based on ID and title
+
+Currently if grub_strtoul(saved_entry_value, NULL, 0) does not return an
+error, we assume the value it has produced is a correct index into our
+menu entry list, and do not try to interpret the value as the "id" or
+"title" .  In cases where "id" or "title" start with a numeral, this
+makes them impossible to use as selection criteria.
+
+This patch splits the search into three phases - matching id, matching
+title, and only once those have been exhausted, trying to interpret the
+ID as a numeral.  In that case, we also require that the entire string
+is numeric, not merely a string with leading numeric characters.
+
+Resolves: rhbz#1640979
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+[javierm: fix menu entry selection based on title]
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/normal/menu.c | 141 ++++++++++++++++++++++++------------------------
+ 1 file changed, 71 insertions(+), 70 deletions(-)
+
+diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
+index d7a222e681..4a02aadb01 100644
+--- a/grub-core/normal/menu.c
++++ b/grub-core/normal/menu.c
+@@ -164,12 +164,12 @@ grub_menu_set_timeout (int timeout)
+ }
+ 
+ static int
+-menuentry_eq (const char *id, const char *spec)
++menuentry_eq (const char *id, const char *spec, int limit)
+ {
+   const char *ptr1, *ptr2;
+   ptr1 = id;
+   ptr2 = spec;
+-  while (1)
++  while (limit == -1 || ptr1 - id <= limit)
+     {
+       if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0)
+ 	return ptr2 - spec;
+@@ -178,7 +178,11 @@ menuentry_eq (const char *id, const char *spec)
+       if (*ptr2 == '>')
+ 	ptr2++;
+       if (*ptr1 != *ptr2)
+-	return 0;
++	{
++	  if (limit > -1 && ptr1 - id == limit && !*ptr1 && grub_isspace(*ptr2))
++	    return ptr1 -id -1;
++	  return 0;
++	}
+       if (*ptr1 == 0)
+ 	return ptr1 - id;
+       ptr1++;
+@@ -187,6 +191,58 @@ menuentry_eq (const char *id, const char *spec)
+   return 0;
+ }
+ 
++static int
++get_entry_number_helper(grub_menu_t menu,
++			const char * const val, const char ** const tail)
++{
++  /* See if the variable matches the title of a menu entry.  */
++  int entry = -1;
++  grub_menu_entry_t e;
++  int i;
++
++  for (i = 0, e = menu->entry_list; e; i++)
++    {
++      int l = 0;
++      while (val[l] && !grub_isspace(val[l]))
++	l++;
++
++      if (menuentry_eq (e->id, val, l))
++	{
++	  if (tail)
++	    *tail = val + l;
++	  return i;
++	}
++      e = e->next;
++    }
++
++  for (i = 0, e = menu->entry_list; e; i++)
++    {
++
++      if (menuentry_eq (e->title, val, -1))
++	{
++	  if (tail)
++	    *tail = NULL;
++	  return i;
++	}
++      e = e->next;
++    }
++
++  if (tail)
++    *tail = NULL;
++
++  entry = (int) grub_strtoul (val, tail, 0);
++  if (grub_errno == GRUB_ERR_BAD_NUMBER ||
++      (*tail && **tail && !grub_isspace(**tail)))
++    {
++      entry = -1;
++      if (tail)
++	*tail = NULL;
++      grub_errno = GRUB_ERR_NONE;
++    }
++
++  return entry;
++}
++
+ /* Get the first entry number from the value of the environment variable NAME,
+    which is a space-separated list of non-negative integers.  The entry number
+    which is returned is stripped from the value of NAME.  If no entry number
+@@ -196,7 +252,6 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name)
+ {
+   const char *val, *tail;
+   int entry;
+-  int sz = 0;
+ 
+   val = grub_env_get (name);
+   if (! val)
+@@ -204,50 +259,24 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name)
+ 
+   grub_error_push ();
+ 
+-  entry = (int) grub_strtoul (val, &tail, 0);
++  entry = get_entry_number_helper(menu, val, &tail);
++  if (!(*tail == 0 || grub_isspace(*tail)))
++    entry = -1;
+ 
+-  if (grub_errno == GRUB_ERR_BAD_NUMBER)
++  if (entry >= 0)
+     {
+-      /* See if the variable matches the title of a menu entry.  */
+-      grub_menu_entry_t e = menu->entry_list;
+-      int i;
+-
+-      for (i = 0; e; i++)
+-	{
+-	  sz = menuentry_eq (e->title, val);
+-	  if (sz < 1)
+-	    sz = menuentry_eq (e->id, val);
+-
+-	  if (sz >= 1)
+-	    {
+-	      entry = i;
+-	      break;
+-	    }
+-	  e = e->next;
+-	}
+-
+-      if (sz > 0)
+-	grub_errno = GRUB_ERR_NONE;
+-
+-      if (! e)
+-	entry = -1;
+-    }
+-
+-  if (grub_errno == GRUB_ERR_NONE)
+-    {
+-      if (sz > 0)
+-	tail += sz;
+-
+       /* Skip whitespace to find the next entry.  */
+       while (*tail && grub_isspace (*tail))
+ 	tail++;
+-      grub_env_set (name, tail);
++      if (*tail)
++	grub_env_set (name, tail);
++      else
++	grub_env_unset (name);
+     }
+   else
+     {
+       grub_env_unset (name);
+       grub_errno = GRUB_ERR_NONE;
+-      entry = -1;
+     }
+ 
+   grub_error_pop ();
+@@ -524,6 +553,7 @@ static int
+ get_entry_number (grub_menu_t menu, const char *name)
+ {
+   const char *val;
++  const char *tail;
+   int entry;
+ 
+   val = grub_env_get (name);
+@@ -531,38 +561,9 @@ get_entry_number (grub_menu_t menu, const char *name)
+     return -1;
+ 
+   grub_error_push ();
+-
+-  entry = (int) grub_strtoul (val, 0, 0);
+-
+-  if (grub_errno == GRUB_ERR_BAD_NUMBER)
+-    {
+-      /* See if the variable matches the title of a menu entry.  */
+-      grub_menu_entry_t e = menu->entry_list;
+-      int i;
+-
+-      grub_errno = GRUB_ERR_NONE;
+-
+-      for (i = 0; e; i++)
+-	{
+-	  if (menuentry_eq (e->title, val)
+-	      || menuentry_eq (e->id, val))
+-	    {
+-	      entry = i;
+-	      break;
+-	    }
+-	  e = e->next;
+-	}
+-
+-      if (! e)
+-	entry = -1;
+-    }
+-
+-  if (grub_errno != GRUB_ERR_NONE)
+-    {
+-      grub_errno = GRUB_ERR_NONE;
+-      entry = -1;
+-    }
+-
++  entry = get_entry_number_helper(menu, val, &tail);
++  if (tail && *tail != '\0')
++    entry = -1;
+   grub_error_pop ();
+ 
+   return entry;
diff --git a/SOURCES/0109-Make-the-menu-entry-users-option-argument-to-be-opti.patch b/SOURCES/0109-Make-the-menu-entry-users-option-argument-to-be-opti.patch
new file mode 100644
index 0000000..68779eb
--- /dev/null
+++ b/SOURCES/0109-Make-the-menu-entry-users-option-argument-to-be-opti.patch
@@ -0,0 +1,46 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Mon, 26 Nov 2018 10:06:42 +0100
+Subject: [PATCH] Make the menu entry users option argument to be optional
+
+The --users option is used to restrict the access to specific menu entries
+only to a set of users. But the option requires an argument to either be a
+constant or a variable that has been set. So for example the following:
+
+  menuentry "May be run by superusers or users in $users" --users $users {
+  	    linux /vmlinuz
+  }
+
+Would fail if $users is not defined and grub would discard the menu entry.
+Instead, allow the --users option to have an optional argument and ignore
+the option if the argument was not set.
+
+Related: rhbz#1652434
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/menuentry.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c
+index b194123eb6..b175a1b43b 100644
+--- a/grub-core/commands/menuentry.c
++++ b/grub-core/commands/menuentry.c
+@@ -29,7 +29,7 @@ static const struct grub_arg_option options[] =
+   {
+     {"class", 1, GRUB_ARG_OPTION_REPEATABLE,
+      N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING},
+-    {"users", 2, 0,
++    {"users", 2, GRUB_ARG_OPTION_OPTIONAL,
+      N_("List of users allowed to boot this entry."), N_("USERNAME[,USERNAME]"),
+      ARG_TYPE_STRING},
+     {"hotkey", 3, 0,
+@@ -281,7 +281,7 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
+   if (! ctxt->state[3].set && ! ctxt->script)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition");
+ 
+-  if (ctxt->state[1].set)
++  if (ctxt->state[1].set && ctxt->state[1].arg)
+     users = ctxt->state[1].arg;
+   else if (ctxt->state[5].set)
+     users = NULL;
diff --git a/SOURCES/0109-Prepend-prefix-when-HTTP-path-is-relative.patch b/SOURCES/0109-Prepend-prefix-when-HTTP-path-is-relative.patch
deleted file mode 100644
index fc861d9..0000000
--- a/SOURCES/0109-Prepend-prefix-when-HTTP-path-is-relative.patch
+++ /dev/null
@@ -1,150 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Stephen Benjamin <stephen@redhat.com>
-Date: Thu, 16 Aug 2018 16:58:51 -0400
-Subject: [PATCH] Prepend prefix when HTTP path is relative
-
-This sets a couple of variables.  With the url http://www.example.com/foo/bar :
-http_path: /foo/bar
-http_url: http://www.example.com/foo/bar
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/kern/main.c    | 10 +++++-
- grub-core/net/efi/http.c | 82 ++++++++++++++++++++++++++++++++++++------------
- 2 files changed, 71 insertions(+), 21 deletions(-)
-
-diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
-index 48058d983ce..4ec3f5e4d33 100644
---- a/grub-core/kern/main.c
-+++ b/grub-core/kern/main.c
-@@ -131,11 +131,19 @@ grub_set_prefix_and_root (void)
-   if (fwdevice && fwpath)
-     {
-       char *fw_path;
-+      char separator[3] = ")";
- 
--      fw_path = grub_xasprintf ("(%s)/%s", fwdevice, fwpath);
-+      grub_dprintf ("fw_path", "\n");
-+      grub_dprintf ("fw_path", "fwdevice:\"%s\" fwpath:\"%s\"\n", fwdevice, fwpath);
-+
-+      if (!grub_strncmp(fwdevice, "http", 4) && fwpath[0] != '/')
-+	grub_strcpy(separator, ")/");
-+
-+      fw_path = grub_xasprintf ("(%s%s%s", fwdevice, separator, fwpath);
-       if (fw_path)
- 	{
- 	  grub_env_set ("fw_path", fw_path);
-+	  grub_dprintf ("fw_path", "fw_path:\"%s\"\n", fw_path);
- 	  grub_free (fw_path);
- 	}
-     }
-diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
-index 243acbaa35b..de351b2cd03 100644
---- a/grub-core/net/efi/http.c
-+++ b/grub-core/net/efi/http.c
-@@ -9,10 +9,52 @@
- static void
- http_configure (struct grub_efi_net_device *dev, int prefer_ip6)
- {
-+  grub_efi_ipv6_address_t address;
-   grub_efi_http_config_data_t http_config;
-   grub_efi_httpv4_access_point_t httpv4_node;
-   grub_efi_httpv6_access_point_t httpv6_node;
-   grub_efi_status_t status;
-+  int https;
-+  char *http_url;
-+  const char *rest, *http_server, *http_path = NULL;
-+
-+  http_server = grub_env_get ("root");
-+  https = (grub_strncmp (http_server, "https", 5) == 0) ? 1 : 0;
-+
-+  /* extract http server + port */
-+  if (http_server)
-+    {
-+      http_server = grub_strchr (http_server, ',');
-+      if (http_server)
-+	http_server++;
-+    }
-+
-+  /* fw_path is like (http,192.168.1.1:8000)/httpboot, extract path part */
-+  http_path = grub_env_get ("fw_path");
-+  if (http_path)
-+    {
-+      http_path = grub_strchr (http_path, ')');
-+      if (http_path)
-+	{
-+	  http_path++;
-+	  grub_env_unset ("http_path");
-+	  grub_env_set ("http_path", http_path);
-+	}
-+    }
-+
-+  if (http_server && http_path)
-+    {
-+      if (grub_efi_string_to_ip6_address (http_server, &address, &rest) && *rest == 0)
-+	http_url = grub_xasprintf ("%s://[%s]%s", https ? "https" : "http", http_server, http_path);
-+      else
-+	http_url = grub_xasprintf ("%s://%s%s", https ? "https" : "http", http_server, http_path);
-+      if (http_url)
-+	{
-+	  grub_env_unset ("http_url");
-+	  grub_env_set ("http_url", http_url);
-+	  grub_free (http_url);
-+	}
-+    }
- 
-   grub_efi_http_t *http = dev->http;
- 
-@@ -352,32 +394,32 @@ grub_efihttp_open (struct grub_efi_net_device *dev,
-   grub_err_t err;
-   grub_off_t size;
-   char *buf;
--  char *root_url;
--  grub_efi_ipv6_address_t address;
--  const char *rest;
-+  char *file_name = NULL;
-+  const char *http_path;
- 
--  if (grub_efi_string_to_ip6_address (file->device->net->server, &address, &rest) && *rest == 0)
--    root_url = grub_xasprintf ("%s://[%s]", type ? "https" : "http", file->device->net->server);
--  else
--    root_url = grub_xasprintf ("%s://%s", type ? "https" : "http", file->device->net->server);
--  if (root_url)
--    {
--      grub_env_unset ("root_url");
--      grub_env_set ("root_url", root_url);
--      grub_free (root_url);
--    }
--  else
--    {
-+  /* If path is relative, prepend http_path */
-+  http_path = grub_env_get ("http_path");
-+  if (http_path && file->device->net->name[0] != '/') {
-+    file_name = grub_xasprintf ("%s/%s", http_path, file->device->net->name);
-+    if (!file_name)
-       return grub_errno;
--    }
-+  }
- 
--  err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0);
-+  err = efihttp_request (dev->http, file->device->net->server,
-+			 file_name ? file_name : file->device->net->name, type, 1, 0);
-   if (err != GRUB_ERR_NONE)
--    return err;
-+    {
-+      grub_free (file_name);
-+      return err;
-+    }
- 
--  err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size);
-+  err = efihttp_request (dev->http, file->device->net->server,
-+			 file_name ? file_name : file->device->net->name, type, 0, &size);
-+  grub_free (file_name);
-   if (err != GRUB_ERR_NONE)
--    return err;
-+    {
-+      return err;
-+    }
- 
-   buf = grub_malloc (size);
-   efihttp_read (dev, buf, size);
diff --git a/SOURCES/0110-Add-efi-export-env-and-efi-load-env-commands.patch b/SOURCES/0110-Add-efi-export-env-and-efi-load-env-commands.patch
new file mode 100644
index 0000000..33d2724
--- /dev/null
+++ b/SOURCES/0110-Add-efi-export-env-and-efi-load-env-commands.patch
@@ -0,0 +1,346 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 16 Jan 2019 13:21:46 -0500
+Subject: [PATCH] Add efi-export-env and efi-load-env commands
+
+This adds "efi-export-env VARIABLE" and "efi-load-env", which manipulate the
+environment block stored in the EFI variable
+GRUB_ENV-91376aff-cba6-42be-949d-06fde81128e8.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/Makefile.core.def  |   6 ++
+ grub-core/commands/efi/env.c | 168 +++++++++++++++++++++++++++++++++++++++++++
+ grub-core/kern/efi/efi.c     |   3 +
+ grub-core/kern/efi/init.c    |   5 --
+ grub-core/lib/envblk.c       |  43 +++++++++++
+ util/grub-set-bootflag.c     |   1 +
+ include/grub/efi/efi.h       |   5 ++
+ include/grub/lib/envblk.h    |   3 +
+ 8 files changed, 229 insertions(+), 5 deletions(-)
+ create mode 100644 grub-core/commands/efi/env.c
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index ea4d59f51b..dc9fea6f44 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -820,6 +820,12 @@ module = {
+   enable = efi;
+ };
+ 
++module = {
++  name = efienv;
++  common = commands/efi/env.c;
++  enable = efi;
++};
++
+ module = {
+   name = efifwsetup;
+   efi = commands/efi/efifwsetup.c;
+diff --git a/grub-core/commands/efi/env.c b/grub-core/commands/efi/env.c
+new file mode 100644
+index 0000000000..cbd13e03e8
+--- /dev/null
++++ b/grub-core/commands/efi/env.c
+@@ -0,0 +1,168 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2012  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/misc.h>
++#include <grub/types.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/env.h>
++#include <grub/lib/envblk.h>
++#include <grub/command.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++static const grub_efi_guid_t grub_env_guid = GRUB_EFI_GRUB_VARIABLE_GUID;
++
++static grub_err_t
++grub_efi_export_env(grub_command_t cmd __attribute__ ((unused)),
++                    int argc, char *argv[])
++{
++  const char *value;
++  char *old_value;
++  struct grub_envblk envblk_s = { NULL, 0 };
++  grub_envblk_t envblk = &envblk_s;
++  grub_err_t err;
++  int changed = 1;
++  grub_efi_status_t status;
++
++  grub_dprintf ("efienv", "argc:%d\n", argc);
++  for (int i = 0; i < argc; i++)
++    grub_dprintf ("efienv", "argv[%d]: %s\n", i, argv[i]);
++
++  if (argc != 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("variable name expected"));
++
++  grub_efi_get_variable ("GRUB_ENV", &grub_env_guid, &envblk_s.size,
++                         (void **) &envblk_s.buf);
++  if (!envblk_s.buf || envblk_s.size < 1)
++    {
++      char *buf = grub_malloc (1025);
++      if (!buf)
++        return grub_errno;
++
++      grub_memcpy (buf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1);
++      grub_memset (buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1, '#',
++	      DEFAULT_ENVBLK_SIZE - sizeof (GRUB_ENVBLK_SIGNATURE) + 1);
++      buf[1024] = '\0';
++
++      envblk_s.buf = buf;
++      envblk_s.size = 1024;
++    }
++  else
++    {
++      char *buf = grub_realloc (envblk_s.buf, envblk_s.size + 1);
++      if (!buf)
++	return grub_errno;
++
++      envblk_s.buf = buf;
++      envblk_s.buf[envblk_s.size] = '\0';
++    }
++
++  err = grub_envblk_get(envblk, argv[0], &old_value);
++  if (err != GRUB_ERR_NONE)
++    {
++      grub_dprintf ("efienv", "grub_envblk_get returned %d\n", err);
++      return err;
++    }
++
++  value = grub_env_get(argv[0]);
++  if ((!value && !old_value) ||
++      (value && old_value && !grub_strcmp(old_value, value)))
++    changed = 0;
++
++  if (old_value)
++    grub_free(old_value);
++
++  if (changed == 0)
++    {
++      grub_dprintf ("efienv", "No changes necessary\n");
++      return 0;
++    }
++
++  if (value)
++    {
++      grub_dprintf ("efienv", "setting \"%s\" to \"%s\"\n", argv[0], value);
++      grub_envblk_set(envblk, argv[0], value);
++    }
++  else
++    {
++      grub_dprintf ("efienv", "deleting \"%s\" from envblk\n", argv[0]);
++      grub_envblk_delete(envblk, argv[0]);
++    }
++
++  grub_dprintf ("efienv", "envblk is %lu bytes:\n\"%s\"\n", envblk_s.size, envblk_s.buf);
++
++  grub_dprintf ("efienv", "removing GRUB_ENV\n");
++  status = grub_efi_set_variable ("GRUB_ENV", &grub_env_guid, NULL, 0);
++  if (status != GRUB_EFI_SUCCESS)
++    grub_dprintf ("efienv", "removal returned %ld\n", status);
++
++  grub_dprintf ("efienv", "setting GRUB_ENV\n");
++  status = grub_efi_set_variable ("GRUB_ENV", &grub_env_guid,
++				  envblk_s.buf, envblk_s.size);
++  if (status != GRUB_EFI_SUCCESS)
++    grub_dprintf ("efienv", "setting GRUB_ENV returned %ld\n", status);
++
++  return 0;
++}
++
++static int
++set_var (const char *name, const char *value,
++	 void *whitelist __attribute__((__unused__)))
++{
++  grub_env_set (name, value);
++  return 0;
++}
++
++static grub_err_t
++grub_efi_load_env(grub_command_t cmd __attribute__ ((unused)),
++                    int argc, char *argv[] __attribute__((__unused__)))
++{
++  struct grub_envblk envblk_s = { NULL, 0 };
++  grub_envblk_t envblk = &envblk_s;
++
++  grub_efi_get_variable ("GRUB_ENV", &grub_env_guid, &envblk_s.size,
++                         (void **) &envblk_s.buf);
++  if (!envblk_s.buf || envblk_s.size < 1)
++    return 0;
++
++  if (argc > 0)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unexpected argument"));
++
++  grub_envblk_iterate (envblk, NULL, set_var);
++  grub_free (envblk_s.buf);
++}
++
++static grub_command_t export_cmd, loadenv_cmd;
++
++GRUB_MOD_INIT(lsefi)
++{
++  export_cmd = grub_register_command ("efi-export-env", grub_efi_export_env,
++	    N_("VARIABLE_NAME"), N_("Export environment variable to UEFI."));
++  loadenv_cmd = grub_register_command ("efi-load-env", grub_efi_load_env,
++	    NULL, N_("Load the grub environment from UEFI."));
++}
++
++GRUB_MOD_FINI(lsefi)
++{
++  grub_unregister_command (export_cmd);
++  grub_unregister_command (loadenv_cmd);
++}
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index 2a446f5031..14bc10eb56 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -225,6 +225,9 @@ grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid,
+   if (status == GRUB_EFI_SUCCESS)
+     return GRUB_ERR_NONE;
+ 
++  if (status == GRUB_EFI_NOT_FOUND && datasize == 0)
++    return GRUB_ERR_NONE;
++
+   return grub_error (GRUB_ERR_IO, "could not set EFI variable `%s'", var);
+ }
+ 
+diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
+index 2d12e6188f..0574d8d621 100644
+--- a/grub-core/kern/efi/init.c
++++ b/grub-core/kern/efi/init.c
+@@ -85,11 +85,6 @@ stack_protector_init (void)
+ 
+ grub_addr_t grub_modbase;
+ 
+-#define GRUB_EFI_GRUB_VARIABLE_GUID \
+-  { 0x91376aff, 0xcba6, 0x42be, \
+-    { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \
+-  }
+-
+ /* Helper for grub_efi_env_init */
+ static int
+ set_var (const char *name, const char *value,
+diff --git a/grub-core/lib/envblk.c b/grub-core/lib/envblk.c
+index 2e4e78b132..874506da16 100644
+--- a/grub-core/lib/envblk.c
++++ b/grub-core/lib/envblk.c
+@@ -223,6 +223,49 @@ grub_envblk_delete (grub_envblk_t envblk, const char *name)
+     }
+ }
+ 
++struct get_var_state {
++  const char * const name;
++  char * value;
++  int found;
++};
++
++static int
++get_var (const char * const name, const char * const value, void *statep)
++{
++  struct get_var_state *state = (struct get_var_state *)statep;
++
++  if (!grub_strcmp(state->name, name))
++    {
++      state->found = 1;
++      state->value = grub_strdup(value);
++      if (!state->value)
++	grub_errno = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
++
++      return 1;
++    }
++
++  return 0;
++}
++
++grub_err_t
++grub_envblk_get (grub_envblk_t envblk, const char * const name, char ** const value)
++{
++  struct get_var_state state = {
++      .name = name,
++      .value = NULL,
++      .found = 0,
++  };
++
++  grub_envblk_iterate(envblk, (void *)&state, get_var);
++
++  *value = state.value;
++
++  if (state.found && !state.value)
++    return grub_errno;
++
++  return GRUB_ERR_NONE;
++}
++
+ void
+ grub_envblk_iterate (grub_envblk_t envblk,
+                      void *hook_data,
+diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c
+index d506f7e75b..a6ccc11383 100644
+--- a/util/grub-set-bootflag.c
++++ b/util/grub-set-bootflag.c
+@@ -25,6 +25,7 @@
+ 
+ #include <config-util.h>     /* For *_DIR_NAME defines */
+ #include <grub/types.h>
++#include <grub/err.h>
+ #include <grub/lib/envblk.h> /* For GRUB_ENVBLK_DEFCFG define */
+ #include <errno.h>
+ #include <stdio.h>
+diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
+index 2e0691454b..8dfc89a33b 100644
+--- a/include/grub/efi/efi.h
++++ b/include/grub/efi/efi.h
+@@ -24,6 +24,11 @@
+ #include <grub/dl.h>
+ #include <grub/efi/api.h>
+ 
++#define GRUB_EFI_GRUB_VARIABLE_GUID \
++  { 0x91376aff, 0xcba6, 0x42be, \
++    { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \
++  }
++
+ /* Variables.  */
+ extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table);
+ extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle);
+diff --git a/include/grub/lib/envblk.h b/include/grub/lib/envblk.h
+index c3e6559217..ab969af246 100644
+--- a/include/grub/lib/envblk.h
++++ b/include/grub/lib/envblk.h
+@@ -22,6 +22,8 @@
+ #define GRUB_ENVBLK_SIGNATURE	"# GRUB Environment Block\n"
+ #define GRUB_ENVBLK_DEFCFG	"grubenv"
+ 
++#define DEFAULT_ENVBLK_SIZE	1024
++
+ #ifndef ASM_FILE
+ 
+ struct grub_envblk
+@@ -33,6 +35,7 @@ typedef struct grub_envblk *grub_envblk_t;
+ 
+ grub_envblk_t grub_envblk_open (char *buf, grub_size_t size);
+ int grub_envblk_set (grub_envblk_t envblk, const char *name, const char *value);
++grub_err_t grub_envblk_get (grub_envblk_t envblk, const char * const name, char ** const value);
+ void grub_envblk_delete (grub_envblk_t envblk, const char *name);
+ void grub_envblk_iterate (grub_envblk_t envblk,
+                           void *hook_data,
diff --git a/SOURCES/0110-Make-grub_error-more-verbose.patch b/SOURCES/0110-Make-grub_error-more-verbose.patch
deleted file mode 100644
index 2492e9f..0000000
--- a/SOURCES/0110-Make-grub_error-more-verbose.patch
+++ /dev/null
@@ -1,61 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 27 Aug 2018 13:14:06 -0400
-Subject: [PATCH] Make grub_error() more verbose
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/kern/err.c | 13 +++++++++++--
- include/grub/err.h   |  8 ++++++--
- 2 files changed, 17 insertions(+), 4 deletions(-)
-
-diff --git a/grub-core/kern/err.c b/grub-core/kern/err.c
-index 53c734de70e..aebfe0cf839 100644
---- a/grub-core/kern/err.c
-+++ b/grub-core/kern/err.c
-@@ -33,15 +33,24 @@ static struct grub_error_saved grub_error_stack_items[GRUB_ERROR_STACK_SIZE];
- static int grub_error_stack_pos;
- static int grub_error_stack_assert;
- 
-+#ifdef grub_error
-+#undef grub_error
-+#endif
-+
- grub_err_t
--grub_error (grub_err_t n, const char *fmt, ...)
-+grub_error (grub_err_t n, const char *file, const int line, const char *fmt, ...)
- {
-   va_list ap;
-+  int m;
- 
-   grub_errno = n;
- 
-+  m = grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "%s:%d:", file, line);
-+  if (m < 0)
-+    m = 0;
-+
-   va_start (ap, fmt);
--  grub_vsnprintf (grub_errmsg, sizeof (grub_errmsg), _(fmt), ap);
-+  grub_vsnprintf (grub_errmsg + m, sizeof (grub_errmsg) - m, _(fmt), ap);
-   va_end (ap);
- 
-   return n;
-diff --git a/include/grub/err.h b/include/grub/err.h
-index b08d5d0de4c..c0f90ef07c8 100644
---- a/include/grub/err.h
-+++ b/include/grub/err.h
-@@ -85,8 +85,12 @@ struct grub_error_saved
- extern grub_err_t EXPORT_VAR(grub_errno);
- extern char EXPORT_VAR(grub_errmsg)[GRUB_MAX_ERRMSG];
- 
--grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *fmt, ...)
--    __attribute__ ((format (GNU_PRINTF, 2, 3)));
-+grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *file, const int line, const char *fmt, ...)
-+	__attribute__ ((format (GNU_PRINTF, 4, 5)));
-+
-+#define grub_error(n, fmt, ...) grub_error (n, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
-+
-+
- void EXPORT_FUNC(grub_fatal) (const char *fmt, ...) __attribute__ ((noreturn));
- void EXPORT_FUNC(grub_error_push) (void);
- int EXPORT_FUNC(grub_error_pop) (void);
diff --git a/SOURCES/0111-Make-it-possible-to-subtract-conditions-from-debug.patch b/SOURCES/0111-Make-it-possible-to-subtract-conditions-from-debug.patch
new file mode 100644
index 0000000..15305f8
--- /dev/null
+++ b/SOURCES/0111-Make-it-possible-to-subtract-conditions-from-debug.patch
@@ -0,0 +1,45 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 17 Jan 2019 13:10:39 -0500
+Subject: [PATCH] Make it possible to subtract conditions from debug=
+
+This makes it so you can do set debug to "all,-scripting,-lexer" and get the
+obvious outcome.  Any negation present will take preference over that
+conditional, so "all,-scripting,scripting" is the same thing as
+"all,-scripting".
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/misc.c | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index 9a2fae6398..578bf51a5f 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -164,12 +164,24 @@ int
+ grub_debug_enabled (const char * condition)
+ {
+   const char *debug;
++  char *negcond;
++  int negated = 0;
+ 
+   debug = grub_env_get ("debug");
+   if (!debug)
+     return 0;
+ 
+-  if (grub_strword (debug, "all") || grub_strword (debug, condition))
++  negcond = grub_zalloc (grub_strlen (condition) + 2);
++  if (negcond)
++    {
++      grub_strcpy (negcond, "-");
++      grub_strcpy (negcond+1, condition);
++      negated = grub_strword (debug, negcond);
++      grub_free (negcond);
++    }
++
++  if (!negated &&
++      (grub_strword (debug, "all") || grub_strword (debug, condition)))
+     return 1;
+ 
+   return 0;
diff --git a/SOURCES/0111-Make-reset-an-alias-for-the-reboot-command.patch b/SOURCES/0111-Make-reset-an-alias-for-the-reboot-command.patch
deleted file mode 100644
index c86acf1..0000000
--- a/SOURCES/0111-Make-reset-an-alias-for-the-reboot-command.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Fri, 31 Aug 2018 16:42:03 -0400
-Subject: [PATCH] Make "reset" an alias for the "reboot" command.
-
-I'm really tired of half the tools I get to use having one and the other half
-having the other.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/commands/reboot.c | 11 +++++++----
- 1 file changed, 7 insertions(+), 4 deletions(-)
-
-diff --git a/grub-core/commands/reboot.c b/grub-core/commands/reboot.c
-index 46d364c99a9..f5cc2283636 100644
---- a/grub-core/commands/reboot.c
-+++ b/grub-core/commands/reboot.c
-@@ -32,15 +32,18 @@ grub_cmd_reboot (grub_command_t cmd __attribute__ ((unused)),
-   grub_reboot ();
- }
- 
--static grub_command_t cmd;
-+static grub_command_t reboot_cmd, reset_cmd;
- 
- GRUB_MOD_INIT(reboot)
- {
--  cmd = grub_register_command ("reboot", grub_cmd_reboot,
--			       0, N_("Reboot the computer."));
-+  reboot_cmd = grub_register_command ("reboot", grub_cmd_reboot,
-+				      0, N_("Reboot the computer."));
-+  reset_cmd = grub_register_command ("reset", grub_cmd_reboot,
-+				     0, N_("Reboot the computer."));
- }
- 
- GRUB_MOD_FINI(reboot)
- {
--  grub_unregister_command (cmd);
-+  grub_unregister_command (reboot_cmd);
-+  grub_unregister_command (reset_cmd);
- }
diff --git a/SOURCES/0112-Add-a-version-command.patch b/SOURCES/0112-Add-a-version-command.patch
deleted file mode 100644
index 30c8224..0000000
--- a/SOURCES/0112-Add-a-version-command.patch
+++ /dev/null
@@ -1,132 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 11 Sep 2018 14:20:37 -0400
-Subject: [PATCH] Add a "version" command.
-
-This adds a command that shows you info about grub's version, the grub target
-platform, the compiler version, and if you built with
---with-rpm-version=<string>, the rpm package version.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- configure.ac                 | 13 ++++++++++
- grub-core/Makefile.core.def  |  5 ++++
- grub-core/commands/version.c | 56 ++++++++++++++++++++++++++++++++++++++++++++
- config.h.in                  |  1 +
- 4 files changed, 75 insertions(+)
- create mode 100644 grub-core/commands/version.c
-
-diff --git a/configure.ac b/configure.ac
-index 152e7dba652..cfdac6bed5a 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -312,6 +312,19 @@ AC_SUBST(target_cpu)
- AC_SUBST(platform)
- 
- # Define default variables
-+have_with_rpm_version=n
-+AC_ARG_WITH([rpm_version],
-+	    AS_HELP_STRING([--with-rpm-version=VERSION],
-+			   [set the rpm package version [[guessed]]]),
-+	    [have_with_rpm_version=y],
-+	    [have_with_rpm_version=n])
-+if test x$have_with_rpm_version = xy; then
-+  rpm_version="$with_rpm_version"
-+else
-+  rpm_version=""
-+fi
-+GRUB_RPM_VERSION="$rpm_version"
-+AC_SUBST(GRUB_RPM_VERSION)
- 
- have_with_bootdir=n
- AC_ARG_WITH([bootdir],
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 84a3d89de9a..498ca11762a 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -579,6 +579,11 @@ image = {
-   enable = mips_loongson;
- };
- 
-+module = {
-+  name = version;
-+  common = commands/version.c;
-+};
-+
- module = {
-   name = disk;
-   common = lib/disk.c;
-diff --git a/grub-core/commands/version.c b/grub-core/commands/version.c
-new file mode 100644
-index 00000000000..f0966a518f7
---- /dev/null
-+++ b/grub-core/commands/version.c
-@@ -0,0 +1,56 @@
-+/* version.c - Command to print the grub version and build info. */
-+/*
-+ *  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 grub_err_t
-+grub_cmd_version (grub_command_t cmd UNUSED, int argc, char **args UNUSED)
-+{
-+  if (argc != 0)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("no arguments expected"));
-+
-+  grub_printf (_("GNU GRUB  version %s\n"), PACKAGE_VERSION);
-+  grub_printf (_("Platform %s-%s\n"), GRUB_TARGET_CPU, GRUB_PLATFORM);
-+  if (grub_strlen(GRUB_RPM_VERSION) != 0)
-+    grub_printf (_("RPM package version %s\n"), GRUB_RPM_VERSION);
-+  grub_printf (_("Compiler version %s\n"), __VERSION__);
-+
-+  return 0;
-+}
-+
-+static grub_command_t cmd;
-+
-+GRUB_MOD_INIT(version)
-+{
-+  cmd = grub_register_command ("version", grub_cmd_version, NULL,
-+			       N_("Print version and build information."));
-+}
-+
-+GRUB_MOD_FINI(version)
-+{
-+  grub_unregister_command (cmd);
-+}
-diff --git a/config.h.in b/config.h.in
-index 9e8f9911b18..c7e316f0f1f 100644
---- a/config.h.in
-+++ b/config.h.in
-@@ -59,6 +59,7 @@
- 
- #define GRUB_TARGET_CPU "@GRUB_TARGET_CPU@"
- #define GRUB_PLATFORM "@GRUB_PLATFORM@"
-+#define GRUB_RPM_VERSION "@GRUB_RPM_VERSION@"
- 
- #define RE_ENABLE_I18N 1
- 
diff --git a/SOURCES/0112-Export-all-variables-from-the-initial-context-when-c.patch b/SOURCES/0112-Export-all-variables-from-the-initial-context-when-c.patch
new file mode 100644
index 0000000..214fa4f
--- /dev/null
+++ b/SOURCES/0112-Export-all-variables-from-the-initial-context-when-c.patch
@@ -0,0 +1,44 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 22 Jan 2019 15:40:25 +0100
+Subject: [PATCH] Export all variables from the initial context when creating a
+ submenu
+
+When a submenu is created, only the exported variables are copied to the
+new menu context. But we want the variables to be global, so export lets
+export all variables to the new created submenu.
+
+Also, don't unset the default variable when a new submenu is created.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/normal/context.c | 2 +-
+ grub-core/normal/menu.c    | 2 --
+ 2 files changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/grub-core/normal/context.c b/grub-core/normal/context.c
+index ee53d4a68e..87edd254c4 100644
+--- a/grub-core/normal/context.c
++++ b/grub-core/normal/context.c
+@@ -99,7 +99,7 @@ grub_env_new_context (int export_all)
+ grub_err_t
+ grub_env_context_open (void)
+ {
+-  return grub_env_new_context (0);
++  return grub_env_new_context (1);
+ }
+ 
+ int grub_extractor_level = 0;
+diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
+index 4a02aadb01..fe2e77a43e 100644
+--- a/grub-core/normal/menu.c
++++ b/grub-core/normal/menu.c
+@@ -375,8 +375,6 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
+ 
+   if (ptr && ptr[0] && ptr[1])
+     grub_env_set ("default", ptr + 1);
+-  else
+-    grub_env_unset ("default");
+ 
+   grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args);
+ 
diff --git a/SOURCES/0113-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch b/SOURCES/0113-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch
deleted file mode 100644
index 9afb315..0000000
--- a/SOURCES/0113-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch
+++ /dev/null
@@ -1,74 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 11 Sep 2018 15:58:29 -0400
-Subject: [PATCH] Add more dprintf, and nerf dprintf in script.c
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/disk/diskfilter.c  | 3 +++
- grub-core/disk/efi/efidisk.c | 1 +
- grub-core/kern/device.c      | 1 +
- grub-core/script/script.c    | 5 +++++
- 4 files changed, 10 insertions(+)
-
-diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c
-index 0320115662f..7cdffe3ebd5 100644
---- a/grub-core/disk/diskfilter.c
-+++ b/grub-core/disk/diskfilter.c
-@@ -188,6 +188,8 @@ scan_disk (const char *name, int accept_diskfilter)
-   grub_disk_t disk;
-   static int scan_depth = 0;
- 
-+  grub_dprintf ("diskfilter", "scanning %s\n", name);
-+
-   if (!accept_diskfilter && is_valid_diskfilter_name (name))
-     return 0;
- 
-@@ -1212,6 +1214,7 @@ insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id,
- 	   the same.  */
- 	if (pv->disk && grub_disk_native_sectors (disk) >= pv->part_size)
- 	  return GRUB_ERR_NONE;
-+	grub_dprintf ("diskfilter", "checking %s\n", disk->name);
- 	pv->disk = grub_disk_open (disk->name);
- 	if (!pv->disk)
- 	  return grub_errno;
-diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c
-index f077b5f5535..fe8ba6e6c93 100644
---- a/grub-core/disk/efi/efidisk.c
-+++ b/grub-core/disk/efi/efidisk.c
-@@ -855,6 +855,7 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle)
- 	  return 0;
- 	}
- 
-+      grub_dprintf ("efidisk", "getting disk for %s\n", device_name);
-       parent = grub_disk_open (device_name);
-       grub_free (dup_dp);
- 
-diff --git a/grub-core/kern/device.c b/grub-core/kern/device.c
-index 73b8ecc0c09..f58b58c89d5 100644
---- a/grub-core/kern/device.c
-+++ b/grub-core/kern/device.c
-@@ -34,6 +34,7 @@ grub_device_open (const char *name)
- {
-   grub_device_t dev = 0;
- 
-+  grub_dprintf ("device", "opening device %s\n", name);
-   if (! name)
-     {
-       name = grub_env_get ("root");
-diff --git a/grub-core/script/script.c b/grub-core/script/script.c
-index ec4d4337c66..844e8343ca7 100644
---- a/grub-core/script/script.c
-+++ b/grub-core/script/script.c
-@@ -22,6 +22,11 @@
- #include <grub/parser.h>
- #include <grub/mm.h>
- 
-+#ifdef grub_dprintf
-+#undef grub_dprintf
-+#endif
-+#define grub_dprintf(no, fmt, ...)
-+
- /* It is not possible to deallocate the memory when a syntax error was
-    found.  Because of that it is required to keep track of all memory
-    allocations.  The memory is freed in case of an error, or assigned
diff --git a/SOURCES/0113-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch b/SOURCES/0113-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch
new file mode 100644
index 0000000..43e8d16
--- /dev/null
+++ b/SOURCES/0113-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch
@@ -0,0 +1,168 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Christian Glombek <lorbus@fedoraproject.org>
+Date: Tue, 2 Apr 2019 16:22:21 +0200
+Subject: [PATCH] grub.d: Split out boot success reset from menu auto hide
+ script
+
+Also rename fallback and menu auto hide script to be executed
+before and after boot success reset script.
+In menu auto hide script, rename last_boot_ok var to menu_hide_ok
+
+Signed-off-by: Christian Glombek <lorbus@fedoraproject.org>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ Makefile.util.def                                  | 14 ++++++++----
+ ...allback_counting.in => 08_fallback_counting.in} | 14 ++++++------
+ util/grub.d/10_reset_boot_success.in               | 25 ++++++++++++++++++++++
+ .../{01_menu_auto_hide.in => 12_menu_auto_hide.in} | 23 +++++---------------
+ 4 files changed, 48 insertions(+), 28 deletions(-)
+ rename util/grub.d/{01_fallback_counting.in => 08_fallback_counting.in} (65%)
+ create mode 100644 util/grub.d/10_reset_boot_success.in
+ rename util/grub.d/{01_menu_auto_hide.in => 12_menu_auto_hide.in} (58%)
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index e10fe766d1..b4ce5383b7 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -459,14 +459,14 @@ script = {
+ };
+ 
+ script = {
+-  name = '01_fallback_counting';
+-  common = util/grub.d/01_fallback_counting.in;
++  name = '08_fallback_counting';
++  common = util/grub.d/08_fallback_counting.in;
+   installdir = grubconf;
+ };
+ 
+ script = {
+-  name = '01_menu_auto_hide';
+-  common = util/grub.d/01_menu_auto_hide.in;
++  name = '12_menu_auto_hide';
++  common = util/grub.d/12_menu_auto_hide.in;
+   installdir = grubconf;
+ };
+ 
+@@ -518,6 +518,12 @@ script = {
+   condition = COND_HOST_LINUX;
+ };
+ 
++script = {
++  name = '10_reset_boot_success';
++  common = util/grub.d/10_reset_boot_success.in;
++  installdir = grubconf;
++};
++
+ script = {
+   name = '10_xnu';
+   common = util/grub.d/10_xnu.in;
+diff --git a/util/grub.d/01_fallback_counting.in b/util/grub.d/08_fallback_counting.in
+similarity index 65%
+rename from util/grub.d/01_fallback_counting.in
+rename to util/grub.d/08_fallback_counting.in
+index be0e770ea8..2e2c3ff7d3 100644
+--- a/util/grub.d/01_fallback_counting.in
++++ b/util/grub.d/08_fallback_counting.in
+@@ -1,15 +1,17 @@
+ #! /bin/sh -e
+-
+-# Boot Counting
++# Fallback Countdown
++#
++# This snippet depends on 10_reset_boot_success and needs to be kept in sync.
++#
+ # The boot_counter env var can be used to count down boot attempts after an
+-# OSTree upgrade and choose the rollback deployment when 0 is reached.  Both
+-# boot_counter and boot_success need to be (re-)set from userspace.
++# OSTree upgrade and choose the rollback deployment when 0 is reached.
++# Both boot_counter=X and boot_success=1 need to be set from userspace.
+ cat << EOF
+ insmod increment
+ # Check if boot_counter exists and boot_success=0 to activate this behaviour.
+ if [ -n "\${boot_counter}" -a "\${boot_success}" = "0" ]; then
+-  # if countdown has ended, choose to boot rollback deployment (default=1 on
+-  # OSTree-based systems)
++  # if countdown has ended, choose to boot rollback deployment,
++  # i.e. default=1 on OSTree-based systems.
+   if  [ "\${boot_counter}" = "0" -o "\${boot_counter}" = "-1" ]; then
+     set default=1
+     set boot_counter=-1
+diff --git a/util/grub.d/10_reset_boot_success.in b/util/grub.d/10_reset_boot_success.in
+new file mode 100644
+index 0000000000..6c88d933dd
+--- /dev/null
++++ b/util/grub.d/10_reset_boot_success.in
+@@ -0,0 +1,25 @@
++#! /bin/sh -e
++# Reset Boot Success
++#
++# The 08_fallback_counting and 12_menu_auto_hide snippets rely on this one
++# and need to be kept in sync.
++#
++# The boot_success var needs to be set to 1 from userspace to mark a boot successful.
++cat << EOF
++insmod increment
++# Hiding the menu is ok if last boot was ok or if this is a first boot attempt to boot the entry
++if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then
++  set menu_hide_ok=1
++else
++  set menu_hide_ok=0 
++fi
++# Reset boot_indeterminate after a successful boot, increment otherwise
++if [ "\${boot_success}" = "1" ] ; then
++  set boot_indeterminate=0
++else
++  increment boot_indeterminate
++fi
++# Reset boot_success for current boot 
++set boot_success=0
++save_env boot_success boot_indeterminate
++EOF
+diff --git a/util/grub.d/01_menu_auto_hide.in b/util/grub.d/12_menu_auto_hide.in
+similarity index 58%
+rename from util/grub.d/01_menu_auto_hide.in
+rename to util/grub.d/12_menu_auto_hide.in
+index ad175870a5..6a7c0fa0d4 100644
+--- a/util/grub.d/01_menu_auto_hide.in
++++ b/util/grub.d/12_menu_auto_hide.in
+@@ -1,5 +1,8 @@
+ #! /bin/sh
+-
++# Menu Auto Hide
++#
++# This snippet depends on 10_reset_boot_success and needs to be kept in sync.
++#
+ # Disable / skip generating menu-auto-hide config parts on serial terminals
+ for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do
+   case "$x" in
+@@ -10,29 +13,13 @@ for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do
+ done
+ 
+ cat << EOF
+-if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then
+-  set last_boot_ok=1
+-else
+-  set last_boot_ok=0
+-fi
+-
+-# Reset boot_indeterminate after a successful boot
+-if [ "\${boot_success}" = "1" ] ; then
+-  set boot_indeterminate=0
+-# Avoid boot_indeterminate causing the menu to be hidden more then once
+-elif [ "\${boot_indeterminate}" = "1" ]; then
+-  set boot_indeterminate=2
+-fi
+-set boot_success=0
+-save_env boot_success boot_indeterminate
+-
+ if [ x\$feature_timeout_style = xy ] ; then
+   if [ "\${menu_show_once}" ]; then
+     unset menu_show_once
+     save_env menu_show_once
+     set timeout_style=menu
+     set timeout=60
+-  elif [ "\${menu_auto_hide}" -a "\${last_boot_ok}" = "1" ]; then
++  elif [ "\${menu_auto_hide}" -a "\${menu_hide_ok}" = "1" ]; then
+     set orig_timeout_style=\${timeout_style}
+     set orig_timeout=\${timeout}
+     if [ "\${fastboot}" = "1" ]; then
diff --git a/SOURCES/0114-Don-t-assume-that-boot-commands-will-only-return-on-.patch b/SOURCES/0114-Don-t-assume-that-boot-commands-will-only-return-on-.patch
new file mode 100644
index 0000000..df36517
--- /dev/null
+++ b/SOURCES/0114-Don-t-assume-that-boot-commands-will-only-return-on-.patch
@@ -0,0 +1,97 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 9 Apr 2019 13:12:40 +0200
+Subject: [PATCH] Don't assume that boot commands will only return on fail
+
+While it's true that for most loaders the boot command never returns, it
+may be the case that it does. For example the GRUB emulator boot command
+calls to systemctl kexec which in turn does an asynchonous call to kexec.
+
+So in this case GRUB will wrongly assume that the boot command fails and
+print a "Failed to boot both default and fallback entries" even when the
+kexec call later succeeds.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/normal/menu.c | 23 +++++++++++++----------
+ 1 file changed, 13 insertions(+), 10 deletions(-)
+
+diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
+index fe2e77a43e..ec0c92bade 100644
+--- a/grub-core/normal/menu.c
++++ b/grub-core/normal/menu.c
+@@ -285,7 +285,7 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name)
+ }
+ 
+ /* Run a menu entry.  */
+-static void
++static grub_err_t
+ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
+ {
+   grub_err_t err = GRUB_ERR_NONE;
+@@ -302,7 +302,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
+     {
+       grub_print_error ();
+       grub_errno = GRUB_ERR_NONE;
+-      return;
++      return grub_errno;
+     }
+ 
+   errs_before = grub_err_printed_errors;
+@@ -315,7 +315,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
+       grub_env_context_open ();
+       menu = grub_zalloc (sizeof (*menu));
+       if (! menu)
+-	return;
++	return grub_errno;
+       grub_env_set_menu (menu);
+       if (auto_boot)
+ 	grub_env_set ("timeout", "0");
+@@ -385,7 +385,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
+ 
+   if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
+     /* Implicit execution of boot, only if something is loaded.  */
+-    grub_command_execute ("boot", 0, 0);
++    err = grub_command_execute ("boot", 0, 0);
+ 
+   if (errs_before != grub_err_printed_errors)
+     grub_wait_after_message ();
+@@ -408,6 +408,8 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
+   else
+     grub_env_unset ("default");
+   grub_env_unset ("timeout");
++
++  return err;
+ }
+ 
+ /* Execute ENTRY from the menu MENU, falling back to entries specified
+@@ -422,10 +424,13 @@ grub_menu_execute_with_fallback (grub_menu_t menu,
+ 				 void *callback_data)
+ {
+   int fallback_entry;
++  grub_err_t err;
+ 
+   callback->notify_booting (entry, callback_data);
+ 
+-  grub_menu_execute_entry (entry, 1);
++  err = grub_menu_execute_entry (entry, 1);
++  if (err == GRUB_ERR_NONE)
++    return;
+ 
+   /* Deal with fallback entries.  */
+   while ((fallback_entry = get_and_remove_first_entry_number (menu, "fallback"))
+@@ -436,11 +441,9 @@ grub_menu_execute_with_fallback (grub_menu_t menu,
+ 
+       entry = grub_menu_get_entry (menu, fallback_entry);
+       callback->notify_fallback (entry, callback_data);
+-      grub_menu_execute_entry (entry, 1);
+-      /* If the function call to execute the entry returns at all, then this is
+-	 taken to indicate a boot failure.  For menu entries that do something
+-	 other than actually boot an operating system, this could assume
+-	 incorrectly that something failed.  */
++      err = grub_menu_execute_entry (entry, 1);
++      if (err == GRUB_ERR_NONE)
++        return;
+     }
+ 
+   if (!autobooted)
diff --git a/SOURCES/0114-arm-arm64-loader-Better-memory-allocation-and-error-.patch b/SOURCES/0114-arm-arm64-loader-Better-memory-allocation-and-error-.patch
deleted file mode 100644
index 1fdc552..0000000
--- a/SOURCES/0114-arm-arm64-loader-Better-memory-allocation-and-error-.patch
+++ /dev/null
@@ -1,279 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 11 Jul 2019 14:38:57 +0200
-Subject: [PATCH] arm/arm64 loader: Better memory allocation and error
- messages.
-
-On mustang, our memory map looks like:
-
-Type      Physical start  - end             #Pages        Size Attributes
-reserved  0000004000000000-00000040001fffff 00000200      2MiB UC WC WT WB
-conv-mem  0000004000200000-0000004393ffffff 00393e00  14654MiB UC WC WT WB
-ldr-code  0000004394000000-00000043f7ffffff 00064000   1600MiB UC WC WT WB
-BS-data   00000043f8000000-00000043f801ffff 00000020    128KiB UC WC WT WB
-conv-mem  00000043f8020000-00000043fa15bfff 0000213c  34032KiB UC WC WT WB
-ldr-code  00000043fa15c000-00000043fa2a1fff 00000146   1304KiB UC WC WT WB
-ldr-data  00000043fa2a2000-00000043fa3e8fff 00000147   1308KiB UC WC WT WB
-conv-mem  00000043fa3e9000-00000043fa3e9fff 00000001      4KiB UC WC WT WB
-ldr-data  00000043fa3ea000-00000043fa3eafff 00000001      4KiB UC WC WT WB
-ldr-code  00000043fa3eb000-00000043fa4affff 000000c5    788KiB UC WC WT WB
-BS-code   00000043fa4b0000-00000043fa59ffff 000000f0    960KiB UC WC WT WB
-RT-code   00000043fa5a0000-00000043fa5affff 00000010     64KiB RT UC WC WT WB
-RT-data   00000043fa5b0000-00000043fa5bffff 00000010     64KiB RT UC WC WT WB
-RT-code   00000043fa5c0000-00000043fa5cffff 00000010     64KiB RT UC WC WT WB
-ldr-data  00000043fa5d0000-00000043fa5d0fff 00000001      4KiB UC WC WT WB
-BS-code   00000043fa5d1000-00000043fa5ddfff 0000000d     52KiB UC WC WT WB
-reserved  00000043fa5de000-00000043fa60ffff 00000032    200KiB UC WC WT WB
-ACPI-rec  00000043fa610000-00000043fa6affff 000000a0    640KiB UC WC WT WB
-ACPI-nvs  00000043fa6b0000-00000043fa6bffff 00000010     64KiB UC WC WT WB
-ACPI-rec  00000043fa6c0000-00000043fa70ffff 00000050    320KiB UC WC WT WB
-RT-code   00000043fa710000-00000043fa72ffff 00000020    128KiB RT UC WC WT WB
-RT-data   00000043fa730000-00000043fa78ffff 00000060    384KiB RT UC WC WT WB
-RT-code   00000043fa790000-00000043fa79ffff 00000010     64KiB RT UC WC WT WB
-RT-data   00000043fa7a0000-00000043fa99ffff 00000200      2MiB RT UC WC WT WB
-RT-code   00000043fa9a0000-00000043fa9affff 00000010     64KiB RT UC WC WT WB
-RT-data   00000043fa9b0000-00000043fa9cffff 00000020    128KiB RT UC WC WT WB
-BS-code   00000043fa9d0000-00000043fa9d9fff 0000000a     40KiB UC WC WT WB
-reserved  00000043fa9da000-00000043fa9dbfff 00000002      8KiB UC WC WT WB
-conv-mem  00000043fa9dc000-00000043fc29dfff 000018c2  25352KiB UC WC WT WB
-BS-data   00000043fc29e000-00000043fc78afff 000004ed   5044KiB UC WC WT WB
-conv-mem  00000043fc78b000-00000043fca01fff 00000277   2524KiB UC WC WT WB
-BS-data   00000043fca02000-00000043fcea3fff 000004a2   4744KiB UC WC WT WB
-conv-mem  00000043fcea4000-00000043fcea4fff 00000001      4KiB UC WC WT WB
-BS-data   00000043fcea5000-00000043fd192fff 000002ee   3000KiB UC WC WT WB
-conv-mem  00000043fd193000-00000043fd2b0fff 0000011e   1144KiB UC WC WT WB
-BS-data   00000043fd2b1000-00000043ff80ffff 0000255f  38268KiB UC WC WT WB
-BS-code   00000043ff810000-00000043ff99ffff 00000190   1600KiB UC WC WT WB
-RT-code   00000043ff9a0000-00000043ff9affff 00000010     64KiB RT UC WC WT WB
-conv-mem  00000043ff9b0000-00000043ff9bffff 00000010     64KiB UC WC WT WB
-RT-data   00000043ff9c0000-00000043ff9effff 00000030    192KiB RT UC WC WT WB
-conv-mem  00000043ff9f0000-00000043ffa05fff 00000016     88KiB UC WC WT WB
-BS-data   00000043ffa06000-00000043ffffffff 000005fa   6120KiB UC WC WT WB
-MMIO      0000000010510000-0000000010510fff 00000001      4KiB RT
-MMIO      0000000010548000-0000000010549fff 00000002      8KiB RT
-MMIO      0000000017000000-0000000017001fff 00000002      8KiB RT
-MMIO      000000001c025000-000000001c025fff 00000001      4KiB RT
-
-This patch adds a requirement when we're trying to find the base of ram, that
-the memory we choose is actually /allocatable/ conventional memory, not merely
-write-combining.  On this machine that means we wind up with an allocation
-around 0x4392XXXXXX, which is a reasonable address.
-
-This also changes grub_efi_allocate_pages_real() so that if 0 is allocated, it
-tries to allocate again starting with the same max address it did the first
-time, rather than interposing GRUB_EFI_MAX_USABLE_ADDRESS there, so that any
-per-platform constraints on its given address are maintained.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/kern/efi/mm.c        | 33 +++++++++++++++-----
- grub-core/loader/arm64/linux.c | 68 +++++++++++++++++++++++++++++++-----------
- 2 files changed, 76 insertions(+), 25 deletions(-)
-
-diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
-index f6aef0ef649..85ad4b4494c 100644
---- a/grub-core/kern/efi/mm.c
-+++ b/grub-core/kern/efi/mm.c
-@@ -154,6 +154,7 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
- {
-   grub_efi_status_t status;
-   grub_efi_boot_services_t *b;
-+  grub_efi_physical_address_t ret = address;
- 
-   /* Limit the memory access to less than 4GB for 32-bit platforms.  */
-   if (address > GRUB_EFI_MAX_USABLE_ADDRESS)
-@@ -170,19 +171,22 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
-     }
- 
-   b = grub_efi_system_table->boot_services;
--  status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address);
-+  status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret);
-   if (status != GRUB_EFI_SUCCESS)
-     {
-+      grub_dprintf ("efi",
-+		    "allocate_pages(%d, %d, 0x%0lx, 0x%016lx) = 0x%016lx\n",
-+		    alloctype, memtype, pages, address, status);
-       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
-       return NULL;
-     }
- 
--  if (address == 0)
-+  if (ret == 0)
-     {
-       /* Uggh, the address 0 was allocated... This is too annoying,
- 	 so reallocate another one.  */
--      address = GRUB_EFI_MAX_USABLE_ADDRESS;
--      status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address);
-+      ret = address;
-+      status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret);
-       grub_efi_free_pages (0, pages);
-       if (status != GRUB_EFI_SUCCESS)
- 	{
-@@ -191,9 +195,9 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
- 	}
-     }
- 
--  grub_efi_store_alloc (address, pages);
-+  grub_efi_store_alloc (ret, pages);
- 
--  return (void *) ((grub_addr_t) address);
-+  return (void *) ((grub_addr_t) ret);
- }
- 
- void *
-@@ -713,8 +717,21 @@ grub_efi_get_ram_base(grub_addr_t *base_addr)
-   for (desc = memory_map, *base_addr = GRUB_EFI_MAX_USABLE_ADDRESS;
-        (grub_addr_t) desc < ((grub_addr_t) memory_map + memory_map_size);
-        desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
--    if (desc->attribute & GRUB_EFI_MEMORY_WB)
--      *base_addr = grub_min (*base_addr, desc->physical_start);
-+    {
-+      if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY &&
-+          (desc->attribute & GRUB_EFI_MEMORY_WB))
-+        {
-+          *base_addr = grub_min (*base_addr, desc->physical_start);
-+          grub_dprintf ("efi", "setting base_addr=0x%016lx\n", *base_addr);
-+        }
-+      else
-+        {
-+          grub_dprintf ("efi", "ignoring address 0x%016lx\n", desc->physical_start);
-+        }
-+    }
-+
-+  if (*base_addr == GRUB_EFI_MAX_USABLE_ADDRESS)
-+    grub_dprintf ("efi", "base_addr 0x%016lx is probably wrong.\n", *base_addr);
- 
-   grub_free(memory_map);
- 
-diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
-index 04994d5c67d..70a0075ec5e 100644
---- a/grub-core/loader/arm64/linux.c
-+++ b/grub-core/loader/arm64/linux.c
-@@ -71,20 +71,25 @@ finalize_params_linux (void)
- {
-   grub_efi_loaded_image_t *loaded_image = NULL;
-   int node, retval, len;
--
-+  grub_err_t err = GRUB_ERR_NONE;
-   void *fdt;
- 
-   fdt = grub_fdt_load (GRUB_EFI_LINUX_FDT_EXTRA_SPACE);
--
-   if (!fdt)
--    goto failure;
-+    {
-+      err = grub_error(GRUB_ERR_BAD_OS, "failed to load FDT");
-+      goto failure;
-+    }
- 
-   node = grub_fdt_find_subnode (fdt, 0, "chosen");
-   if (node < 0)
-     node = grub_fdt_add_subnode (fdt, 0, "chosen");
- 
-   if (node < 1)
--    goto failure;
-+    {
-+      err = grub_error(grub_errno, "failed to load chosen fdt node.");
-+      goto failure;
-+    }
- 
-   /* Set initrd info */
-   if (initrd_start && initrd_end > initrd_start)
-@@ -95,15 +100,26 @@ finalize_params_linux (void)
-       retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start",
- 				    initrd_start);
-       if (retval)
--	goto failure;
-+	{
-+	  err = grub_error(retval, "Failed to set linux,initrd-start property");
-+	  goto failure;
-+	}
-+
-       retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-end",
- 				    initrd_end);
-       if (retval)
--	goto failure;
-+	{
-+	  err = grub_error(retval, "Failed to set linux,initrd-end property");
-+	  goto failure;
-+	}
-     }
- 
--  if (grub_fdt_install() != GRUB_ERR_NONE)
--    goto failure;
-+  retval = grub_fdt_install();
-+  if (retval != GRUB_ERR_NONE)
-+    {
-+      err = grub_error(retval, "Failed to install fdt");
-+      goto failure;
-+    }
- 
-   grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n",
-                 fdt);
-@@ -111,14 +127,20 @@ finalize_params_linux (void)
-   /* Convert command line to UCS-2 */
-   loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
-   if (!loaded_image)
--    goto failure;
-+    {
-+      err = grub_error(grub_errno, "Failed to install fdt");
-+      goto failure;
-+    }
- 
-   loaded_image->load_options_size = len =
-     (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t);
-   loaded_image->load_options =
-     grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
-   if (!loaded_image->load_options)
--    return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters");
-+    {
-+      err = grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters");
-+      goto failure;
-+    }
- 
-   loaded_image->load_options_size =
-     2 * grub_utf8_to_utf16 (loaded_image->load_options, len,
-@@ -128,7 +150,7 @@ finalize_params_linux (void)
- 
- failure:
-   grub_fdt_unload();
--  return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT");
-+  return err;
- }
- 
- static void
-@@ -212,16 +234,28 @@ grub_linux_unload (void)
- static void *
- allocate_initrd_mem (int initrd_pages)
- {
--  grub_addr_t max_addr;
-+  grub_addr_t max_addr = 0;
-+  grub_err_t err;
-+  void *ret;
- 
--  if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE)
--    return NULL;
-+  err = grub_efi_get_ram_base (&max_addr);
-+  if (err != GRUB_ERR_NONE)
-+    {
-+      grub_error (err, "grub_efi_get_ram_base() failed");
-+      return NULL;
-+    }
-+
-+  grub_dprintf ("linux", "max_addr: 0x%016lx, INITRD_MAX_ADDRESS_OFFSET: 0x%016llx\n",
-+		max_addr, INITRD_MAX_ADDRESS_OFFSET);
- 
-   max_addr += INITRD_MAX_ADDRESS_OFFSET - 1;
-+  grub_dprintf ("linux", "calling grub_efi_allocate_pages_real (0x%016lx, 0x%08x, EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_DATA)", max_addr, initrd_pages);
- 
--  return grub_efi_allocate_pages_real (max_addr, initrd_pages,
--				       GRUB_EFI_ALLOCATE_MAX_ADDRESS,
--				       GRUB_EFI_LOADER_DATA);
-+  ret = grub_efi_allocate_pages_real (max_addr, initrd_pages,
-+				      GRUB_EFI_ALLOCATE_MAX_ADDRESS,
-+				      GRUB_EFI_LOADER_DATA);
-+  grub_dprintf ("linux", "got 0x%016llx\n", (unsigned long long)ret);
-+  return ret;
- }
- 
- static grub_err_t
diff --git a/SOURCES/0115-Try-to-pick-better-locations-for-kernel-and-initrd.patch b/SOURCES/0115-Try-to-pick-better-locations-for-kernel-and-initrd.patch
deleted file mode 100644
index ba918ed..0000000
--- a/SOURCES/0115-Try-to-pick-better-locations-for-kernel-and-initrd.patch
+++ /dev/null
@@ -1,196 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 11 Jul 2019 17:17:02 +0200
-Subject: [PATCH] Try to pick better locations for kernel and initrd
-
-- Don't limit allocations on 64-bit platforms to < 0x[37f]fffffff if
-  we're using the "large" code model ; use __UINTPTR_MAX__.
-- Get the comparison right to check the address we've allocated.
-- Fix the allocation for the command line as well.
-
-*But*, when we did this some systems started failing badly; coudln't
-parse partition tables, etc.  What's going on here is the disk controller
-is silently failing DMAs to addresses above 4GB, so we're trying to parse
-uninitialized (or HW zeroed) ram when looking for the partition table,
-etc.
-
-So to limit this, we make grub_malloc() pick addresses below 4GB on
-x86_64, but the direct EFI page allocation functions can get addresses
-above that.
-
-Additionally, we now try to locate kernel+initrd+cmdline+etc below
-0x7fffffff, and if they're too big to fit any memory window there, then
-we try a higher address.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/kern/efi/mm.c           |  8 ++++----
- grub-core/loader/i386/efi/linux.c | 24 +++++++++++++++++-------
- include/grub/arm/efi/memory.h     |  1 +
- include/grub/arm64/efi/memory.h   |  1 +
- include/grub/i386/efi/memory.h    |  1 +
- include/grub/ia64/efi/memory.h    |  1 +
- include/grub/x86_64/efi/memory.h  |  4 +++-
- 7 files changed, 28 insertions(+), 12 deletions(-)
-
-diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
-index 85ad4b4494c..e84961d078c 100644
---- a/grub-core/kern/efi/mm.c
-+++ b/grub-core/kern/efi/mm.c
-@@ -122,7 +122,7 @@ grub_efi_allocate_pages_max (grub_efi_physical_address_t max,
-   grub_efi_boot_services_t *b;
-   grub_efi_physical_address_t address = max;
- 
--  if (max > 0xffffffff)
-+  if (max > GRUB_EFI_MAX_USABLE_ADDRESS)
-     return 0;
- 
-   b = grub_efi_system_table->boot_services;
-@@ -480,7 +480,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
-     {
-       if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
- #if 1
--	  && desc->physical_start <= GRUB_EFI_MAX_USABLE_ADDRESS
-+	  && desc->physical_start <= GRUB_EFI_MAX_ALLOCATION_ADDRESS
- #endif
- 	  && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000
- 	  && desc->num_pages != 0)
-@@ -498,9 +498,9 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
- #if 1
- 	  if (BYTES_TO_PAGES (filtered_desc->physical_start)
- 	      + filtered_desc->num_pages
--	      > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS))
-+	      > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS))
- 	    filtered_desc->num_pages
--	      = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS)
-+	      = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS)
- 		 - BYTES_TO_PAGES (filtered_desc->physical_start));
- #endif
- 
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index 3017d0f3e52..33e981e76e7 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -27,6 +27,7 @@
- #include <grub/lib/cmdline.h>
- #include <grub/efi/efi.h>
- #include <grub/efi/linux.h>
-+#include <grub/cpu/efi/memory.h>
- 
- GRUB_MOD_LICENSE ("GPLv3+");
- 
-@@ -106,7 +107,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
-       size += ALIGN_UP (grub_file_size (files[i]), 4);
-     }
- 
--  initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size));
-+  initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size));
-+  if (!initrd_mem)
-+    initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size));
-   if (!initrd_mem)
-     {
-       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd"));
-@@ -202,8 +205,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-       goto fail;
-     }
- 
--  params = grub_efi_allocate_pages_max (0x3fffffff,
-+  params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS,
- 					BYTES_TO_PAGES(sizeof(*params)));
-+  if (!params)
-+    params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS,
-+					  BYTES_TO_PAGES(sizeof(*params)));
-   if (! params)
-     {
-       grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
-@@ -273,8 +279,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
- #endif
- 
-   grub_dprintf ("linux", "setting up cmdline\n");
--  linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff,
--					 BYTES_TO_PAGES(lh->cmdline_size + 1));
-+  linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS,
-+					      BYTES_TO_PAGES(lh->cmdline_size + 1));
-+  if (!linux_cmdline)
-+    linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS,
-+						BYTES_TO_PAGES(lh->cmdline_size + 1));
-   if (!linux_cmdline)
-     {
-       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline"));
-@@ -301,11 +310,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
- 
-   kernel_mem = grub_efi_allocate_pages_max(lh->pref_address,
- 					   BYTES_TO_PAGES(lh->init_size));
--
-   if (!kernel_mem)
--    kernel_mem = grub_efi_allocate_pages_max(0x3fffffff,
-+    kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS,
-+					     BYTES_TO_PAGES(lh->init_size));
-+  if (!kernel_mem)
-+    kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS,
- 					     BYTES_TO_PAGES(lh->init_size));
--
-   if (!kernel_mem)
-     {
-       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel"));
-diff --git a/include/grub/arm/efi/memory.h b/include/grub/arm/efi/memory.h
-index 2c64918e3f7..a4c2ec83502 100644
---- a/include/grub/arm/efi/memory.h
-+++ b/include/grub/arm/efi/memory.h
-@@ -2,5 +2,6 @@
- #include <grub/efi/memory.h>
- 
- #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff
-+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
- 
- #endif /* ! GRUB_MEMORY_CPU_HEADER */
-diff --git a/include/grub/arm64/efi/memory.h b/include/grub/arm64/efi/memory.h
-index c6cb3241714..acb61dca44b 100644
---- a/include/grub/arm64/efi/memory.h
-+++ b/include/grub/arm64/efi/memory.h
-@@ -2,5 +2,6 @@
- #include <grub/efi/memory.h>
- 
- #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL
-+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
- 
- #endif /* ! GRUB_MEMORY_CPU_HEADER */
-diff --git a/include/grub/i386/efi/memory.h b/include/grub/i386/efi/memory.h
-index 2c64918e3f7..a4c2ec83502 100644
---- a/include/grub/i386/efi/memory.h
-+++ b/include/grub/i386/efi/memory.h
-@@ -2,5 +2,6 @@
- #include <grub/efi/memory.h>
- 
- #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff
-+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
- 
- #endif /* ! GRUB_MEMORY_CPU_HEADER */
-diff --git a/include/grub/ia64/efi/memory.h b/include/grub/ia64/efi/memory.h
-index 2c64918e3f7..a4c2ec83502 100644
---- a/include/grub/ia64/efi/memory.h
-+++ b/include/grub/ia64/efi/memory.h
-@@ -2,5 +2,6 @@
- #include <grub/efi/memory.h>
- 
- #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff
-+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
- 
- #endif /* ! GRUB_MEMORY_CPU_HEADER */
-diff --git a/include/grub/x86_64/efi/memory.h b/include/grub/x86_64/efi/memory.h
-index 46e9145a308..e81cfb32213 100644
---- a/include/grub/x86_64/efi/memory.h
-+++ b/include/grub/x86_64/efi/memory.h
-@@ -2,9 +2,11 @@
- #include <grub/efi/memory.h>
- 
- #if defined (__code_model_large__)
--#define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff
-+#define GRUB_EFI_MAX_USABLE_ADDRESS __UINTPTR_MAX__
-+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS 0x7fffffff
- #else
- #define GRUB_EFI_MAX_USABLE_ADDRESS 0x7fffffff
-+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
- #endif
- 
- #endif /* ! GRUB_MEMORY_CPU_HEADER */
diff --git a/SOURCES/0115-grub-set-bootflag-Update-comment-about-running-as-ro.patch b/SOURCES/0115-grub-set-bootflag-Update-comment-about-running-as-ro.patch
new file mode 100644
index 0000000..9ffb3ae
--- /dev/null
+++ b/SOURCES/0115-grub-set-bootflag-Update-comment-about-running-as-ro.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 13 Nov 2019 12:15:43 +0100
+Subject: [PATCH] grub-set-bootflag: Update comment about running as root
+ through pkexec
+
+We have stopped using pkexec for grub-set-bootflag, instead it is now
+installed suid root, update the comment accordingly.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ util/grub-set-bootflag.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c
+index a6ccc11383..3eb04beb5e 100644
+--- a/util/grub-set-bootflag.c
++++ b/util/grub-set-bootflag.c
+@@ -18,7 +18,7 @@
+  */
+ 
+ /*
+- * NOTE this gets run by users as root (through pkexec), so this does not
++ * NOTE this gets run by users as root (its suid root), so this does not
+  * use any grub library / util functions to allow for easy auditing.
+  * The grub headers are only included to get certain defines.
+  */
diff --git a/SOURCES/0116-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch b/SOURCES/0116-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch
deleted file mode 100644
index c2f2a59..0000000
--- a/SOURCES/0116-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch
+++ /dev/null
@@ -1,397 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 11 Jul 2019 18:03:25 +0200
-Subject: [PATCH] Attempt to fix up all the places -Wsign-compare=error finds.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/kern/emu/misc.c                          |   2 +-
- grub-core/lib/reed_solomon.c                       |   4 +-
- grub-core/osdep/linux/blocklist.c                  |   2 +-
- grub-core/osdep/linux/getroot.c                    |   2 +-
- grub-core/osdep/linux/hostdisk.c                   |   2 +-
- util/grub-fstest.c                                 |   2 +-
- util/grub-menulst2cfg.c                            |   2 +-
- util/grub-mkfont.c                                 |  13 +-
- util/grub-probe.c                                  |   2 +-
- util/grub-rpm-sort.c                               |   2 +-
- util/setup.c                                       |   2 +-
- bootstrap.conf                                     |   3 +-
- .../gnulib-patches/fix-sign-compare-errors.patch   | 161 +++++++++++++++++++++
- 13 files changed, 181 insertions(+), 18 deletions(-)
- create mode 100644 grub-core/lib/gnulib-patches/fix-sign-compare-errors.patch
-
-diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c
-index eeea092752d..f08a1bb8415 100644
---- a/grub-core/kern/emu/misc.c
-+++ b/grub-core/kern/emu/misc.c
-@@ -189,7 +189,7 @@ grub_util_get_image_size (const char *path)
-   sz = ftello (f);
-   if (sz < 0)
-     grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
--  if (sz != (size_t) sz)
-+  if (sz > (off_t)(GRUB_SIZE_MAX >> 1))
-     grub_util_error (_("file `%s' is too big"), path);
-   ret = (size_t) sz;
- 
-diff --git a/grub-core/lib/reed_solomon.c b/grub-core/lib/reed_solomon.c
-index 467305b46ab..79037c093f7 100644
---- a/grub-core/lib/reed_solomon.c
-+++ b/grub-core/lib/reed_solomon.c
-@@ -157,7 +157,7 @@ static void
- rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs)
- {
-   gf_single_t *rs_polynomial;
--  int i, j;
-+  unsigned int i, j;
-   gf_single_t *m;
-   m = xcalloc (s + rs, sizeof (gf_single_t));
-   grub_memcpy (m, data, s * sizeof (gf_single_t));
-@@ -324,7 +324,7 @@ static void
- encode_block (gf_single_t *ptr, grub_size_t s,
- 	      gf_single_t *rptr, grub_size_t rs)
- {
--  int i, j;
-+  unsigned int i, j;
-   for (i = 0; i < SECTOR_SIZE; i++)
-     {
-       grub_size_t ds = (s + SECTOR_SIZE - 1 - i) / SECTOR_SIZE;
-diff --git a/grub-core/osdep/linux/blocklist.c b/grub-core/osdep/linux/blocklist.c
-index c77d6085ccb..42a315031ff 100644
---- a/grub-core/osdep/linux/blocklist.c
-+++ b/grub-core/osdep/linux/blocklist.c
-@@ -109,7 +109,7 @@ grub_install_get_blocklist (grub_device_t root_dev,
-   else
-     {
-       struct fiemap *fie2;
--      int i;
-+      unsigned int i;
-       fie2 = xmalloc (sizeof (*fie2)
- 		      + fie1.fm_mapped_extents
- 		      * sizeof (fie1.fm_extents[1]));
-diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
-index 28790307e00..9f730b35189 100644
---- a/grub-core/osdep/linux/getroot.c
-+++ b/grub-core/osdep/linux/getroot.c
-@@ -236,7 +236,7 @@ grub_find_root_devices_from_btrfs (const char *dir)
- {
-   int fd;
-   struct btrfs_ioctl_fs_info_args fsi;
--  int i, j = 0;
-+  unsigned int i, j = 0;
-   char **ret;
- 
-   fd = open (dir, 0);
-diff --git a/grub-core/osdep/linux/hostdisk.c b/grub-core/osdep/linux/hostdisk.c
-index da62f924e35..7bc99ac1c1d 100644
---- a/grub-core/osdep/linux/hostdisk.c
-+++ b/grub-core/osdep/linux/hostdisk.c
-@@ -83,7 +83,7 @@ grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_sec
-   if (sector_size & (sector_size - 1) || !sector_size)
-     return -1;
-   for (log_sector_size = 0;
--       (1 << log_sector_size) < sector_size;
-+       (1U << log_sector_size) < sector_size;
-        log_sector_size++);
- 
-   if (log_secsize)
-diff --git a/util/grub-fstest.c b/util/grub-fstest.c
-index 83865642009..bfcef852d83 100644
---- a/util/grub-fstest.c
-+++ b/util/grub-fstest.c
-@@ -323,7 +323,7 @@ cmd_cmp (char *src, char *dest)
-   read_file (src, cmp_hook, ff);
- 
-   {
--    grub_uint64_t pre;
-+    long long pre;
-     pre = ftell (ff);
-     fseek (ff, 0, SEEK_END);
-     if (pre != ftell (ff))
-diff --git a/util/grub-menulst2cfg.c b/util/grub-menulst2cfg.c
-index a39f8693947..358d604210b 100644
---- a/util/grub-menulst2cfg.c
-+++ b/util/grub-menulst2cfg.c
-@@ -34,7 +34,7 @@ main (int argc, char **argv)
-   char *buf = NULL;
-   size_t bufsize = 0;
-   char *suffix = xstrdup ("");
--  int suffixlen = 0;
-+  size_t suffixlen = 0;
-   const char *out_fname = 0;
- 
-   grub_util_host_init (&argc, &argv);
-diff --git a/util/grub-mkfont.c b/util/grub-mkfont.c
-index 0fe45a6103d..3e09240b99f 100644
---- a/util/grub-mkfont.c
-+++ b/util/grub-mkfont.c
-@@ -138,7 +138,8 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face,
-   int width, height;
-   int cuttop, cutbottom, cutleft, cutright;
-   grub_uint8_t *data;
--  int mask, i, j, bitmap_size;
-+  int mask, i, bitmap_size;
-+  unsigned int j;
-   FT_GlyphSlot glyph;
-   int flag = FT_LOAD_RENDER | FT_LOAD_MONOCHROME;
-   FT_Error err;
-@@ -183,7 +184,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face,
-     cuttop = cutbottom = cutleft = cutright = 0;
-   else
-     {
--      for (cuttop = 0; cuttop < glyph->bitmap.rows; cuttop++)
-+      for (cuttop = 0; cuttop < (long)glyph->bitmap.rows; cuttop++)
- 	{
- 	  for (j = 0; j < glyph->bitmap.width; j++)
- 	    if (glyph->bitmap.buffer[j / 8 + cuttop * glyph->bitmap.pitch]
-@@ -203,10 +204,10 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face,
- 	    break;
- 	}
-       cutbottom = glyph->bitmap.rows - 1 - cutbottom;
--      if (cutbottom + cuttop >= glyph->bitmap.rows)
-+      if (cutbottom + cuttop >= (long)glyph->bitmap.rows)
- 	cutbottom = 0;
- 
--      for (cutleft = 0; cutleft < glyph->bitmap.width; cutleft++)
-+      for (cutleft = 0; cutleft < (long)glyph->bitmap.width; cutleft++)
- 	{
- 	  for (j = 0; j < glyph->bitmap.rows; j++)
- 	    if (glyph->bitmap.buffer[cutleft / 8 + j * glyph->bitmap.pitch]
-@@ -225,7 +226,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face,
- 	    break;
- 	}
-       cutright = glyph->bitmap.width - 1 - cutright;
--      if (cutright + cutleft >= glyph->bitmap.width)
-+      if (cutright + cutleft >= (long)glyph->bitmap.width)
- 	cutright = 0;
-     }
- 
-@@ -262,7 +263,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face,
- 
-   mask = 0;
-   data = &glyph_info->bitmap[0] - 1;
--  for (j = cuttop; j < height + cuttop; j++)
-+  for (j = cuttop; j < (long)height + cuttop; j++)
-     for (i = cutleft; i < width + cutleft; i++)
-       add_pixel (&data, &mask,
- 		 glyph->bitmap.buffer[i / 8 + j * glyph->bitmap.pitch] &
-diff --git a/util/grub-probe.c b/util/grub-probe.c
-index c08e46bbb40..c6fac732b40 100644
---- a/util/grub-probe.c
-+++ b/util/grub-probe.c
-@@ -798,7 +798,7 @@ argp_parser (int key, char *arg, struct argp_state *state)
- 
-     case 't':
-       {
--	int i;
-+	unsigned int i;
- 
- 	for (i = PRINT_FS; i < ARRAY_SIZE (targets); i++)
- 	  if (strcmp (arg, targets[i]) == 0)
-diff --git a/util/grub-rpm-sort.c b/util/grub-rpm-sort.c
-index f33bd1ed568..8345944105f 100644
---- a/util/grub-rpm-sort.c
-+++ b/util/grub-rpm-sort.c
-@@ -232,7 +232,7 @@ main (int argc, char *argv[])
-   struct arguments arguments;
-   char **package_names = NULL;
-   size_t n_package_names = 0;
--  int i;
-+  unsigned int i;
- 
-   grub_util_host_init (&argc, &argv);
- 
-diff --git a/util/setup.c b/util/setup.c
-index da5f2c07f50..8b22bb8ccac 100644
---- a/util/setup.c
-+++ b/util/setup.c
-@@ -406,7 +406,7 @@ SETUP (const char *dir,
-     int is_ldm;
-     grub_err_t err;
-     grub_disk_addr_t *sectors;
--    int i;
-+    unsigned int i;
-     grub_fs_t fs;
-     unsigned int nsec, maxsec;
- 
-diff --git a/bootstrap.conf b/bootstrap.conf
-index 6b043fc354c..186be9c48ce 100644
---- a/bootstrap.conf
-+++ b/bootstrap.conf
-@@ -80,7 +80,8 @@ cp -a INSTALL INSTALL.grub
- bootstrap_post_import_hook () {
-   set -e
-   for patchname in fix-base64 fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \
--      fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width no-abort; do
-+      fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width no-abort \
-+      fix-sign-compare-errors; do
-     patch -d grub-core/lib/gnulib -p2 \
-       < "grub-core/lib/gnulib-patches/$patchname.patch"
-   done
-diff --git a/grub-core/lib/gnulib-patches/fix-sign-compare-errors.patch b/grub-core/lib/gnulib-patches/fix-sign-compare-errors.patch
-new file mode 100644
-index 00000000000..479029c0565
---- /dev/null
-+++ b/grub-core/lib/gnulib-patches/fix-sign-compare-errors.patch
-@@ -0,0 +1,161 @@
-+diff --git a/lib/regcomp.c b/lib/regcomp.c
-+index cc85f35ac58..361079d82d6 100644
-+--- a/lib/regcomp.c
-++++ b/lib/regcomp.c
-+@@ -322,7 +322,7 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state,
-+ 		*p++ = dfa->nodes[node].opr.c;
-+ 	      memset (&state, '\0', sizeof (state));
-+ 	      if (__mbrtowc (&wc, (const char *) buf, p - buf,
-+-			     &state) == p - buf
-++			     &state) == (size_t)(p - buf)
-+ 		  && (__wcrtomb ((char *) buf, __towlower (wc), &state)
-+ 		      != (size_t) -1))
-+ 		re_set_fastmap (fastmap, false, buf[0]);
-+@@ -3778,7 +3778,7 @@ fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax)
-+       num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2)
-+ 	     ? -2
-+ 	     : num == -1
-+-	     ? c - '0'
-++	     ? (Idx)(c - '0')
-+ 	     : MIN (RE_DUP_MAX + 1, num * 10 + c - '0'));
-+     }
-+   return num;
-+diff --git a/lib/regex_internal.c b/lib/regex_internal.c
-+index 9004ce809eb..193a1e3d332 100644
-+--- a/lib/regex_internal.c
-++++ b/lib/regex_internal.c
-+@@ -233,7 +233,7 @@ build_wcs_buffer (re_string_t *pstr)
-+       /* Apply the translation if we need.  */
-+       if (__glibc_unlikely (pstr->trans != NULL))
-+ 	{
-+-	  int i, ch;
-++	  unsigned int i, ch;
-+ 
-+ 	  for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
-+ 	    {
-+@@ -376,7 +376,7 @@ build_wcs_upper_buffer (re_string_t *pstr)
-+ 	prev_st = pstr->cur_state;
-+ 	if (__glibc_unlikely (pstr->trans != NULL))
-+ 	  {
-+-	    int i, ch;
-++	    unsigned int i, ch;
-+ 
-+ 	    for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
-+ 	      {
-+@@ -754,7 +754,7 @@ re_string_reconstruct (re_string_t *pstr, Idx idx, int eflags)
-+ 			  memset (&cur_state, 0, sizeof (cur_state));
-+ 			  mbclen = __mbrtowc (&wc2, (const char *) pp, mlen,
-+ 					      &cur_state);
-+-			  if (raw + offset - p <= mbclen
-++			  if ((size_t)(raw + offset - p) <= mbclen
-+ 			      && mbclen < (size_t) -2)
-+ 			    {
-+ 			      memset (&pstr->cur_state, '\0',
-+diff --git a/lib/regex_internal.h b/lib/regex_internal.h
-+index 5462419b787..e0f8292395d 100644
-+--- a/lib/regex_internal.h
-++++ b/lib/regex_internal.h
-+@@ -425,7 +425,7 @@ struct re_string_t
-+   unsigned char offsets_needed;
-+   unsigned char newline_anchor;
-+   unsigned char word_ops_used;
-+-  int mb_cur_max;
-++  unsigned int mb_cur_max;
-+ };
-+ typedef struct re_string_t re_string_t;
-+ 
-+@@ -702,7 +702,7 @@ struct re_dfa_t
-+   unsigned int is_utf8 : 1;
-+   unsigned int map_notascii : 1;
-+   unsigned int word_ops_used : 1;
-+-  int mb_cur_max;
-++  unsigned int mb_cur_max;
-+   bitset_t word_char;
-+   reg_syntax_t syntax;
-+   Idx *subexp_map;
-+diff --git a/lib/regexec.c b/lib/regexec.c
-+index 0a7a27b772e..b57d4f9141d 100644
-+--- a/lib/regexec.c
-++++ b/lib/regexec.c
-+@@ -443,7 +443,7 @@ re_search_stub (struct re_pattern_buffer *bufp, const char *string, Idx length,
-+     {
-+       if (ret_len)
-+ 	{
-+-	  assert (pmatch[0].rm_so == start);
-++	  assert (pmatch[0].rm_so == (long)start);
-+ 	  rval = pmatch[0].rm_eo - start;
-+ 	}
-+       else
-+@@ -877,11 +877,11 @@ re_search_internal (const regex_t *preg, const char *string, Idx length,
-+ 	    if (__glibc_unlikely (mctx.input.offsets_needed != 0))
-+ 	      {
-+ 		pmatch[reg_idx].rm_so =
-+-		  (pmatch[reg_idx].rm_so == mctx.input.valid_len
-++		  (pmatch[reg_idx].rm_so == (long)mctx.input.valid_len
-+ 		   ? mctx.input.valid_raw_len
-+ 		   : mctx.input.offsets[pmatch[reg_idx].rm_so]);
-+ 		pmatch[reg_idx].rm_eo =
-+-		  (pmatch[reg_idx].rm_eo == mctx.input.valid_len
-++		  (pmatch[reg_idx].rm_eo == (long)mctx.input.valid_len
-+ 		   ? mctx.input.valid_raw_len
-+ 		   : mctx.input.offsets[pmatch[reg_idx].rm_eo]);
-+ 	      }
-+@@ -1418,11 +1418,11 @@ set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch,
-+     }
-+   memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
-+ 
-+-  for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;)
-++  for (idx = pmatch[0].rm_so; idx <= (long)pmatch[0].rm_eo ;)
-+     {
-+       update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch);
-+ 
-+-      if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node)
-++      if (idx == (long)pmatch[0].rm_eo && cur_node == mctx->last_node)
-+ 	{
-+ 	  Idx reg_idx;
-+ 	  if (fs)
-+@@ -1519,7 +1519,7 @@ update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
-+       if (reg_num < nmatch)
-+ 	{
-+ 	  /* We are at the last node of this sub expression.  */
-+-	  if (pmatch[reg_num].rm_so < cur_idx)
-++	  if (pmatch[reg_num].rm_so < (long)cur_idx)
-+ 	    {
-+ 	      pmatch[reg_num].rm_eo = cur_idx;
-+ 	      /* This is a non-empty match or we are not inside an optional
-+@@ -2938,7 +2938,7 @@ check_arrival (re_match_context_t *mctx, state_array_t *path, Idx top_node,
-+       mctx->state_log[str_idx] = cur_state;
-+     }
-+ 
-+-  for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;)
-++  for (null_cnt = 0; str_idx < last_str && null_cnt <= (long)mctx->max_mb_elem_len;)
-+     {
-+       re_node_set_empty (&next_nodes);
-+       if (mctx->state_log[str_idx + 1])
-+@@ -3718,7 +3718,7 @@ check_node_accept_bytes (const re_dfa_t *dfa, Idx node_idx,
-+ 			 const re_string_t *input, Idx str_idx)
-+ {
-+   const re_token_t *node = dfa->nodes + node_idx;
-+-  int char_len, elem_len;
-++  unsigned int char_len, elem_len;
-+   Idx i;
-+ 
-+   if (__glibc_unlikely (node->type == OP_UTF8_PERIOD))
-+@@ -4066,7 +4066,7 @@ extend_buffers (re_match_context_t *mctx, int min_len)
-+   /* Double the lengths of the buffers, but allocate at least MIN_LEN.  */
-+   ret = re_string_realloc_buffers (pstr,
-+ 				   MAX (min_len,
-+-					MIN (pstr->len, pstr->bufs_len * 2)));
-++					MIN ((long)pstr->len, pstr->bufs_len * 2)));
-+   if (__glibc_unlikely (ret != REG_NOERROR))
-+     return ret;
-+ 
-+@@ -4236,7 +4236,7 @@ match_ctx_add_entry (re_match_context_t *mctx, Idx node, Idx str_idx, Idx from,
-+     = (from == to ? -1 : 0);
-+ 
-+   mctx->bkref_ents[mctx->nbkref_ents++].more = 0;
-+-  if (mctx->max_mb_elem_len < to - from)
-++  if (mctx->max_mb_elem_len < (long)(to - from))
-+     mctx->max_mb_elem_len = to - from;
-+   return REG_NOERROR;
-+ }
diff --git a/SOURCES/0116-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch b/SOURCES/0116-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch
new file mode 100644
index 0000000..11722d1
--- /dev/null
+++ b/SOURCES/0116-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch
@@ -0,0 +1,152 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 13 Nov 2019 13:02:01 +0100
+Subject: [PATCH] grub-set-bootflag: Write new env to tmpfile and then rename
+
+Make the grubenv writing code in grub-set-bootflag more robust by
+writing the modified grubenv to a tmpfile first and then renaming the
+tmpfile over the old grubenv (following symlinks).
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ util/grub-set-bootflag.c | 87 +++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 78 insertions(+), 9 deletions(-)
+
+diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c
+index 3eb04beb5e..3b4c25ca2a 100644
+--- a/util/grub-set-bootflag.c
++++ b/util/grub-set-bootflag.c
+@@ -28,7 +28,9 @@
+ #include <grub/err.h>
+ #include <grub/lib/envblk.h> /* For GRUB_ENVBLK_DEFCFG define */
+ #include <errno.h>
++#include <limits.h>
+ #include <stdio.h>
++#include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+ 
+@@ -56,8 +58,10 @@ int main(int argc, char *argv[])
+ {
+   /* NOTE buf must be at least the longest bootflag length + 4 bytes */
+   char env[GRUBENV_SIZE + 1], buf[64], *s;
++  /* +1 for 0 termination, +6 for "XXXXXX" in tmp filename */
++  char env_filename[PATH_MAX + 1], tmp_filename[PATH_MAX + 6 + 1];
+   const char *bootflag;
+-  int i, len, ret;
++  int i, fd, len, ret;
+   FILE *f;
+ 
+   if (argc != 2)
+@@ -89,7 +93,32 @@ int main(int argc, char *argv[])
+   bootflag = bootflags[i];
+   len = strlen (bootflag);
+ 
+-  f = fopen (GRUBENV, "r");
++  /*
++   * Really become root. setuid avoids an user killing us, possibly leaking
++   * the tmpfile. setgid avoids the new grubenv's gid being that of the user.
++   */
++  ret = setuid(0);
++  if (ret)
++    {
++      perror ("Error setuid(0) failed");
++      return 1;
++    }
++
++  ret = setgid(0);
++  if (ret)
++    {
++      perror ("Error setgid(0) failed");
++      return 1;
++    }
++
++  /* Canonicalize GRUBENV filename, resolving symlinks, etc. */
++  if (!realpath(GRUBENV, env_filename))
++    {
++      perror ("Error canonicalizing " GRUBENV " filename");
++      return 1;
++    }
++
++  f = fopen (env_filename, "r");
+   if (!f)
+     {
+       perror ("Error opening " GRUBENV " for reading");
+@@ -144,30 +173,70 @@ int main(int argc, char *argv[])
+   snprintf(buf, sizeof(buf), "%s=1\n", bootflag);
+   memcpy(s, buf, len + 3);
+ 
+-  /* "r+", don't truncate so that the diskspace stays reserved */
+-  f = fopen (GRUBENV, "r+");
++
++  /*
++   * Create a tempfile for writing the new env.  Use the canonicalized filename
++   * for the template so that the tmpfile is in the same dir / on same fs.
++   */
++  snprintf(tmp_filename, sizeof(tmp_filename), "%sXXXXXX", env_filename);
++  fd = mkstemp(tmp_filename);
++  if (fd == -1)
++    {
++      perror ("Creating tmpfile failed");
++      return 1;
++    }
++
++  f = fdopen (fd, "w");
+   if (!f)
+     {
+-      perror ("Error opening " GRUBENV " for writing");
++      perror ("Error fdopen of tmpfile failed");
++      unlink(tmp_filename);
+       return 1;     
+     }
+ 
+   ret = fwrite (env, 1, GRUBENV_SIZE, f);
+   if (ret != GRUBENV_SIZE)
+     {
+-      perror ("Error writing to " GRUBENV);
++      perror ("Error writing tmpfile");
++      unlink(tmp_filename);
+       return 1;     
+     }
+ 
+   ret = fflush (f);
+   if (ret)
+     {
+-      perror ("Error flushing " GRUBENV);
++      perror ("Error flushing tmpfile");
++      unlink(tmp_filename);
+       return 1;     
+     }
+ 
+-  fsync (fileno (f));
+-  fclose (f);
++  ret = fsync (fileno (f));
++  if (ret)
++    {
++      perror ("Error syncing tmpfile");
++      unlink(tmp_filename);
++      return 1;
++    }
++
++  ret = fclose (f);
++  if (ret)
++    {
++      perror ("Error closing tmpfile");
++      unlink(tmp_filename);
++      return 1;
++    }
++
++  /*
++   * And finally rename the tmpfile with the new env over the old env, the
++   * linux kernel guarantees that this is atomic (from a syscall pov).
++   */
++  ret = rename(tmp_filename, env_filename);
++  if (ret)
++    {
++      perror ("Error renaming tmpfile to " GRUBENV " failed");
++      unlink(tmp_filename);
++      return 1;
++    }
+ 
+   return 0;
+ }
diff --git a/SOURCES/0117-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch b/SOURCES/0117-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch
deleted file mode 100644
index de71484..0000000
--- a/SOURCES/0117-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 11 Jul 2019 18:20:37 +0200
-Subject: [PATCH] Don't use -Wno-sign-compare -Wno-conversion -Wno-error, do
- use -Wextra.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- configure.ac         | 14 +++++++++++---
- conf/Makefile.common |  2 +-
- 2 files changed, 12 insertions(+), 4 deletions(-)
-
-diff --git a/configure.ac b/configure.ac
-index cfdac6bed5a..bd28edf3141 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1480,11 +1480,11 @@ fi
- # Set them to their new values for the tests below.
- CC="$TARGET_CC"
- if test x"$platform" = xemu ; then
--CFLAGS="$TARGET_CFLAGS -Wno-error"
-+CFLAGS="$TARGET_CFLAGS"
- elif test "x$TARGET_APPLE_LINKER" = x1 ; then
--CFLAGS="$TARGET_CFLAGS -nostdlib -static -Wno-error"
-+CFLAGS="$TARGET_CFLAGS -nostdlib -static"
- else
--CFLAGS="$TARGET_CFLAGS -nostdlib -Wno-error"
-+CFLAGS="$TARGET_CFLAGS -nostdlib"
- fi
- CPPFLAGS="$TARGET_CPPFLAGS"
- 
-@@ -2054,6 +2054,14 @@ if test x"$enable_werror" != xno ; then
-   HOST_CFLAGS="$HOST_CFLAGS -Werror"
- fi
- 
-+AC_ARG_ENABLE([wextra],
-+	      [AS_HELP_STRING([--disable-wextra],
-+                             [do not use -Wextra when building GRUB])])
-+if test x"$enable_wextra" != xno ; then
-+  TARGET_CFLAGS="$TARGET_CFLAGS -Wextra"
-+  HOST_CFLAGS="$HOST_CFLAGS -Wextra"
-+fi
-+
- TARGET_CPP="$TARGET_CC -E"
- TARGET_CCAS=$TARGET_CC
- 
-diff --git a/conf/Makefile.common b/conf/Makefile.common
-index 2ff9b39357c..35e14ff017e 100644
---- a/conf/Makefile.common
-+++ b/conf/Makefile.common
-@@ -66,7 +66,7 @@ grubconfdir = $(sysconfdir)/grub.d
- platformdir = $(pkglibdir)/$(target_cpu)-$(platform)
- starfielddir = $(pkgdatadir)/themes/starfield
- 
--CFLAGS_GNULIB = -Wno-undef -Wno-sign-compare -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Wno-conversion
-+CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code
- CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib
- 
- CFLAGS_POSIX = -fno-builtin
diff --git a/SOURCES/0117-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch b/SOURCES/0117-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch
new file mode 100644
index 0000000..948ff73
--- /dev/null
+++ b/SOURCES/0117-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch
@@ -0,0 +1,81 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 26 Nov 2019 09:51:41 +0100
+Subject: [PATCH] grub.d: Fix boot_indeterminate getting set on boot_success=0
+ boot
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The "grub.d: Split out boot success reset from menu auto hide script"
+not only moved the code to clear boot_success and boot_indeterminate
+but for some reason also mixed in some broken changes to the
+boot_indeterminate handling.
+
+The boot_indeterminate var is meant to suppress the boot menu after
+a reboot from either a selinux-relabel or offline-updates. These
+2 special boot scenarios do not set boot_success since there is no
+successfull interaction with the user. Instead they increment
+boot_indeterminate, and if it is 1 and only when it is 1, so the
+first reboot after a "special" boot we suppress the menu.
+
+To ensure that we do show the menu if we somehow get stuck in a
+"special" boot loop where we do special-boots without them
+incrementing boot_indeterminate, the code before the
+"grub.d: Split out boot success reset from menu auto hide script"
+commit would increment boot_indeterminate once when it is 1, so that
+even if the "special" boot reboot-loop immediately we would show the
+menu on the next boot.
+
+That commit broke this however, because it not only moves the code,
+it also changes it from only "incrementing" boot_indeterminate once to
+always incrementing it, except when boot_success == 1 (and we reset it).
+
+This broken behavior causes the following problem:
+
+1. Boot a broken kernel, system hangs, power-cycle
+2. boot_success now != 1, so we increment boot_indeterminate from 0
+   (unset!) to 1. User either simply tries again, or makes some changes
+   but the end-result still is a system hang, power-cycle
+3. Now boot_indeterminate==1 so we do not show the menu even though the
+   previous boot failed -> BAD
+
+This commit fixes this by restoring the behavior of setting
+boot_indeterminate to 2 when it was 1 before.
+
+Fixes: "grub.d: Split out boot success reset from menu auto hide script"
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+[jpokorny: 01_menu_auto_hide.in: fix a then/than typo]
+Signed-off-by: Jan Pokorný <jpokorny@fedoraproject.org>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ util/grub.d/10_reset_boot_success.in | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/util/grub.d/10_reset_boot_success.in b/util/grub.d/10_reset_boot_success.in
+index 6c88d933dd..e73f4137b3 100644
+--- a/util/grub.d/10_reset_boot_success.in
++++ b/util/grub.d/10_reset_boot_success.in
+@@ -6,18 +6,18 @@
+ #
+ # The boot_success var needs to be set to 1 from userspace to mark a boot successful.
+ cat << EOF
+-insmod increment
+ # Hiding the menu is ok if last boot was ok or if this is a first boot attempt to boot the entry
+ if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then
+   set menu_hide_ok=1
+ else
+   set menu_hide_ok=0 
+ fi
+-# Reset boot_indeterminate after a successful boot, increment otherwise
++# Reset boot_indeterminate after a successful boot
+ if [ "\${boot_success}" = "1" ] ; then
+   set boot_indeterminate=0
+-else
+-  increment boot_indeterminate
++# Avoid boot_indeterminate causing the menu to be hidden more than once
++elif [ "\${boot_indeterminate}" = "1" ]; then
++  set boot_indeterminate=2
+ fi
+ # Reset boot_success for current boot 
+ set boot_success=0
diff --git a/SOURCES/0118-Add-start-symbol-for-RISC-V.patch b/SOURCES/0118-Add-start-symbol-for-RISC-V.patch
new file mode 100644
index 0000000..2746fa2
--- /dev/null
+++ b/SOURCES/0118-Add-start-symbol-for-RISC-V.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: David Abdurachmanov <david.abdurachmanov@sifive.com>
+Date: Sat, 9 Nov 2019 19:51:57 +0000
+Subject: [PATCH] Add start symbol for RISC-V
+
+All other architectures have start symbol.
+
+Hopefully this resolves:
+
+    BUILDSTDERR: ././grub-mkimage: error: undefined symbol start.
+
+Signed-off-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
+---
+ grub-core/kern/riscv/efi/startup.S | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/grub-core/kern/riscv/efi/startup.S b/grub-core/kern/riscv/efi/startup.S
+index f2a7b2b1ed..781773136e 100644
+--- a/grub-core/kern/riscv/efi/startup.S
++++ b/grub-core/kern/riscv/efi/startup.S
+@@ -29,6 +29,7 @@
+ 
+ 	.file 	"startup.S"
+ 	.text
++FUNCTION(start)
+ FUNCTION(_start)
+ 	/*
+ 	 *  EFI_SYSTEM_TABLE and EFI_HANDLE are passed in a1/a0.
diff --git a/SOURCES/0118-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch b/SOURCES/0118-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch
deleted file mode 100644
index fdd3096..0000000
--- a/SOURCES/0118-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch
+++ /dev/null
@@ -1,101 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Fri, 12 Jul 2019 09:53:32 +0200
-Subject: [PATCH] x86-efi: Use bounce buffers for reading to addresses > 4GB
-
-Lots of machines apparently can't DMA correctly above 4GB during UEFI,
-so use bounce buffers for the initramfs read.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/loader/i386/efi/linux.c | 52 +++++++++++++++++++++++++++++++++------
- 1 file changed, 45 insertions(+), 7 deletions(-)
-
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index 33e981e76e7..2f0336809e7 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -35,11 +35,16 @@ static grub_dl_t my_mod;
- static int loaded;
- static void *kernel_mem;
- static grub_uint64_t kernel_size;
--static grub_uint8_t *initrd_mem;
-+static void *initrd_mem;
- static grub_uint32_t handover_offset;
- struct linux_kernel_params *params;
- static char *linux_cmdline;
- 
-+#define MIN(a, b) \
-+  ({ typeof (a) _a = (a); \
-+     typeof (b) _b = (b); \
-+     _a < _b ? _a : _b; })
-+
- #define BYTES_TO_PAGES(bytes)   (((bytes) + 0xfff) >> 12)
- 
- static grub_err_t
-@@ -73,6 +78,44 @@ grub_linuxefi_unload (void)
-   return GRUB_ERR_NONE;
- }
- 
-+#define BOUNCE_BUFFER_MAX 0x10000000ull
-+
-+static grub_ssize_t
-+read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len)
-+{
-+  grub_ssize_t bufpos = 0;
-+  static grub_size_t bbufsz = 0;
-+  static char *bbuf = NULL;
-+
-+  if (bbufsz == 0)
-+    bbufsz = MIN(BOUNCE_BUFFER_MAX, len);
-+
-+  while (!bbuf && bbufsz)
-+    {
-+      bbuf = grub_malloc(bbufsz);
-+      if (!bbuf)
-+	bbufsz >>= 1;
-+    }
-+  if (!bbuf)
-+    grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate bounce buffer"));
-+
-+  while (bufpos < (long long)len)
-+    {
-+      grub_ssize_t sz;
-+
-+      sz = grub_file_read (file, bbuf, MIN(bbufsz, len - bufpos));
-+      if (sz < 0)
-+	return sz;
-+      if (sz == 0)
-+	break;
-+
-+      grub_memcpy(bufp + bufpos, bbuf, sz);
-+      bufpos += sz;
-+    }
-+
-+  return bufpos;
-+}
-+
- static grub_err_t
- grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
-                  int argc, char *argv[])
-@@ -126,7 +169,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
-   for (i = 0; i < nfiles; i++)
-     {
-       grub_ssize_t cursize = grub_file_size (files[i]);
--      if (grub_file_read (files[i], ptr, cursize) != cursize)
-+      if (read (files[i], ptr, cursize) != cursize)
-         {
-           if (!grub_errno)
-             grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
-@@ -152,11 +195,6 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
-   return grub_errno;
- }
- 
--#define MIN(a, b) \
--  ({ typeof (a) _a = (a);  \
--     typeof (b) _b = (b); \
--     _a < _b ? _a : _b; })
--
- static grub_err_t
- grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
- 		int argc, char *argv[])
diff --git a/SOURCES/0119-bootstrap.conf-Force-autogen.sh-to-use-python3.patch b/SOURCES/0119-bootstrap.conf-Force-autogen.sh-to-use-python3.patch
new file mode 100644
index 0000000..8bfc964
--- /dev/null
+++ b/SOURCES/0119-bootstrap.conf-Force-autogen.sh-to-use-python3.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Wed, 15 Jan 2020 12:47:46 +0100
+Subject: [PATCH] bootstrap.conf: Force autogen.sh to use python3
+
+The python-unversioned-command package is not installed in the buildroot,
+but the bootstrap script expects the python command to be present if one
+is not defined. So building the package leads to the following error:
+
+./autogen.sh: line 20: python: command not found
+
+This is harmless since gnulib is included as a source anyways, because the
+builders can't download. But still the issue should be fixed by forcing to
+use python3 that's the default in Fedora now.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ bootstrap.conf | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/bootstrap.conf b/bootstrap.conf
+index 6b043fc354..52d4af44be 100644
+--- a/bootstrap.conf
++++ b/bootstrap.conf
+@@ -92,7 +92,7 @@ bootstrap_post_import_hook () {
+     patch -d po -p3 \
+       < "po/gettext-patches/$patchname.patch"
+   done
+-  FROM_BOOTSTRAP=1 ./autogen.sh
++  PYTHON=python3 FROM_BOOTSTRAP=1 ./autogen.sh
+   set +e  # bootstrap expects this
+ }
+ 
diff --git a/SOURCES/0119-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch b/SOURCES/0119-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch
deleted file mode 100644
index f8284ec..0000000
--- a/SOURCES/0119-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch
+++ /dev/null
@@ -1,133 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 13 Sep 2018 14:42:34 -0400
-Subject: [PATCH] x86-efi: Re-arrange grub_cmd_linux() a little bit.
-
-This just helps the next patch be easier to read.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/loader/i386/efi/linux.c | 75 +++++++++++++++++++++------------------
- 1 file changed, 41 insertions(+), 34 deletions(-)
-
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index 2f0336809e7..5f48fa55619 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -243,32 +243,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-       goto fail;
-     }
- 
--  params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS,
--					BYTES_TO_PAGES(sizeof(*params)));
--  if (!params)
--    params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS,
--					  BYTES_TO_PAGES(sizeof(*params)));
--  if (! params)
--    {
--      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
--      goto fail;
--    }
-+  lh = (struct linux_i386_kernel_header *)kernel;
-+  grub_dprintf ("linux", "original lh is at %p\n", kernel);
- 
--  grub_dprintf ("linux", "params = %p\n", params);
--
--  grub_memset (params, 0, sizeof(*params));
--
--  setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201);
--  grub_dprintf ("linux", "copying %lu bytes from %p to %p\n",
--		MIN((grub_size_t)0x202+setup_header_end_offset,
--		    sizeof (*params)) - 0x1f1,
--		(grub_uint8_t *)kernel + 0x1f1,
--		(grub_uint8_t *)params + 0x1f1);
--  grub_memcpy ((grub_uint8_t *)params + 0x1f1,
--	       (grub_uint8_t *)kernel + 0x1f1,
--		MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1);
--  lh = (struct linux_i386_kernel_header *)params;
--  grub_dprintf ("linux", "lh is at %p\n", lh);
-   grub_dprintf ("linux", "checking lh->boot_flag\n");
-   if (lh->boot_flag != grub_cpu_to_le16 (0xaa55))
-     {
-@@ -316,6 +293,34 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-     }
- #endif
- 
-+  params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS,
-+					BYTES_TO_PAGES(sizeof(*params)));
-+  if (!params)
-+    params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS,
-+					  BYTES_TO_PAGES(sizeof(*params)));
-+  if (! params)
-+    {
-+      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
-+      goto fail;
-+    }
-+
-+  grub_dprintf ("linux", "params = %p\n", params);
-+
-+  grub_memset (params, 0, sizeof(*params));
-+
-+  setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201);
-+  grub_dprintf ("linux", "copying %lu bytes from %p to %p\n",
-+		MIN((grub_size_t)0x202+setup_header_end_offset,
-+		    sizeof (*params)) - 0x1f1,
-+		(grub_uint8_t *)kernel + 0x1f1,
-+		(grub_uint8_t *)params + 0x1f1);
-+  grub_memcpy ((grub_uint8_t *)params + 0x1f1,
-+	       (grub_uint8_t *)kernel + 0x1f1,
-+		MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1);
-+
-+  lh = (struct linux_i386_kernel_header *)params;
-+  grub_dprintf ("linux", "new lh is at %p\n", lh);
-+
-   grub_dprintf ("linux", "setting up cmdline\n");
-   linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS,
- 					      BYTES_TO_PAGES(lh->cmdline_size + 1));
-@@ -341,8 +346,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   grub_dprintf ("linux", "setting lh->cmd_line_ptr\n");
-   lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline;
- 
--  grub_dprintf ("linux", "computing handover offset\n");
-   handover_offset = lh->handover_offset;
-+  grub_dprintf("linux", "handover_offset: %08x\n", handover_offset);
- 
-   start = (lh->setup_sects + 1) * 512;
- 
-@@ -359,26 +364,28 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel"));
-       goto fail;
-     }
--
--  grub_dprintf ("linux", "kernel_mem = %lx\n", (unsigned long) kernel_mem);
-+  grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem);
- 
-   grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
--  loaded=1;
-+
-+  loaded = 1;
-+
-   grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem);
-   lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem;
- 
-   grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start);
- 
--  grub_dprintf ("linux", "setting lh->type_of_loader\n");
-   lh->type_of_loader = 0x6;
-+  grub_dprintf ("linux", "setting lh->type_of_loader = 0x%02x\n",
-+		lh->type_of_loader);
- 
--  grub_dprintf ("linux", "setting lh->ext_loader_{type,ver}\n");
-   params->ext_loader_type = 0;
-   params->ext_loader_ver = 2;
--  grub_dprintf("linux", "kernel_mem: %p handover_offset: %08x\n",
--	       kernel_mem, handover_offset);
-+  grub_dprintf ("linux",
-+		"setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n",
-+		params->ext_loader_type, params->ext_loader_ver);
- 
-- fail:
-+fail:
-   if (file)
-     grub_file_close (file);
- 
diff --git a/SOURCES/0120-efi-http-Export-fw-http-_path-variables-to-make-them.patch b/SOURCES/0120-efi-http-Export-fw-http-_path-variables-to-make-them.patch
new file mode 100644
index 0000000..f745782
--- /dev/null
+++ b/SOURCES/0120-efi-http-Export-fw-http-_path-variables-to-make-them.patch
@@ -0,0 +1,50 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Thu, 5 Mar 2020 16:21:47 +0100
+Subject: [PATCH] efi/http: Export {fw,http}_path variables to make them global
+
+The fw_path environment variable is used by http_configure() function to
+determine the HTTP path that should be used as prefix when using relative
+HTTP paths. And this is stored in the http_path environment variable.
+
+Later, that variable is looked up by grub_efihttp_open() to generate the
+complete path to be used in the HTTP request.
+
+But these variables are not exported, which means that are not global and
+so are only found in the initial context.
+
+This can cause commands like configfile that create a new context to fail
+because the fw_path and http_path variables will not be found.
+
+Resolves: rhbz#1616395
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/kern/main.c    | 1 +
+ grub-core/net/efi/http.c | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
+index 1c540fc8c2..b573be6650 100644
+--- a/grub-core/kern/main.c
++++ b/grub-core/kern/main.c
+@@ -143,6 +143,7 @@ grub_set_prefix_and_root (void)
+       if (fw_path)
+ 	{
+ 	  grub_env_set ("fw_path", fw_path);
++	  grub_env_export ("fw_path");
+ 	  grub_dprintf ("fw_path", "fw_path:\"%s\"\n", fw_path);
+ 	  grub_free (fw_path);
+ 	}
+diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
+index de351b2cd0..755b7a6d05 100644
+--- a/grub-core/net/efi/http.c
++++ b/grub-core/net/efi/http.c
+@@ -39,6 +39,7 @@ http_configure (struct grub_efi_net_device *dev, int prefer_ip6)
+ 	  http_path++;
+ 	  grub_env_unset ("http_path");
+ 	  grub_env_set ("http_path", http_path);
++	  grub_env_export ("http_path");
+ 	}
+     }
+ 
diff --git a/SOURCES/0120-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch b/SOURCES/0120-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch
deleted file mode 100644
index 4ad0696..0000000
--- a/SOURCES/0120-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch
+++ /dev/null
@@ -1,258 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Wed, 12 Sep 2018 16:03:55 -0400
-Subject: [PATCH] x86-efi: Make our own allocator for kernel stuff
-
-This helps enable allocations above 4GB.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/loader/i386/efi/linux.c | 167 +++++++++++++++++++++-----------------
- 1 file changed, 94 insertions(+), 73 deletions(-)
-
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index 5f48fa55619..3e4f7ef39f4 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -47,6 +47,65 @@ static char *linux_cmdline;
- 
- #define BYTES_TO_PAGES(bytes)   (((bytes) + 0xfff) >> 12)
- 
-+struct allocation_choice {
-+    grub_efi_physical_address_t addr;
-+    grub_efi_allocate_type_t alloc_type;
-+};
-+
-+static struct allocation_choice max_addresses[] =
-+  {
-+    { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-+    { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-+    { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-+    { 0, 0 }
-+  };
-+
-+static inline void
-+kernel_free(void *addr, grub_efi_uintn_t size)
-+{
-+  if (addr && size)
-+    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)addr,
-+			 BYTES_TO_PAGES(size));
-+}
-+
-+static void *
-+kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
-+{
-+  void *addr = 0;
-+  unsigned int i;
-+  grub_efi_physical_address_t prev_max = 0;
-+
-+  for (i = 0; max_addresses[i].addr != 0 && addr == 0; i++)
-+    {
-+      grub_uint64_t max = max_addresses[i].addr;
-+      grub_efi_uintn_t pages;
-+
-+      if (max == prev_max)
-+	continue;
-+
-+      pages = BYTES_TO_PAGES(size);
-+      grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n",
-+		    pages, (void *)max);
-+
-+      prev_max = max;
-+      addr = grub_efi_allocate_pages_real (max, pages,
-+					   max_addresses[i].alloc_type,
-+					   GRUB_EFI_LOADER_DATA);
-+      if (addr)
-+	grub_dprintf ("linux", "Allocated at %p\n", addr);
-+    }
-+
-+  while (grub_error_pop ())
-+    {
-+      ;
-+    }
-+
-+  if (addr == NULL)
-+    grub_error (GRUB_ERR_OUT_OF_MEMORY, "%s", errmsg);
-+
-+  return addr;
-+}
-+
- static grub_err_t
- grub_linuxefi_boot (void)
- {
-@@ -62,19 +121,12 @@ grub_linuxefi_unload (void)
- {
-   grub_dl_unref (my_mod);
-   loaded = 0;
--  if (initrd_mem)
--    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem,
--			 BYTES_TO_PAGES(params->ramdisk_size));
--  if (linux_cmdline)
--    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)
--			 linux_cmdline,
--			 BYTES_TO_PAGES(params->cmdline_size + 1));
--  if (kernel_mem)
--    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem,
--			 BYTES_TO_PAGES(kernel_size));
--  if (params)
--    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params,
--			 BYTES_TO_PAGES(16384));
-+
-+  kernel_free(initrd_mem, params->ramdisk_size);
-+  kernel_free(linux_cmdline, params->cmdline_size + 1);
-+  kernel_free(kernel_mem, kernel_size);
-+  kernel_free(params, sizeof(*params));
-+
-   return GRUB_ERR_NONE;
- }
- 
-@@ -150,19 +202,13 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
-       size += ALIGN_UP (grub_file_size (files[i]), 4);
-     }
- 
--  initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size));
--  if (!initrd_mem)
--    initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size));
--  if (!initrd_mem)
--    {
--      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd"));
--      goto fail;
--    }
--
--  grub_dprintf ("linux", "initrd_mem = %lx\n", (unsigned long) initrd_mem);
-+  initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
-+  if (initrd_mem == NULL)
-+    goto fail;
-+  grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
- 
-   params->ramdisk_size = size;
--  params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem;
-+  params->ramdisk_image = initrd_mem;
- 
-   ptr = initrd_mem;
- 
-@@ -221,7 +267,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   filelen = grub_file_size (file);
- 
-   kernel = grub_malloc(filelen);
--
-   if (!kernel)
-     {
-       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
-@@ -274,7 +319,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-       goto fail;
-     }
- 
--#if defined(__x86_64__) || defined(__aarch64__)
-+#if defined(__x86_64__)
-   grub_dprintf ("linux", "checking lh->xloadflags\n");
-   if (!(lh->xloadflags & LINUX_XLF_KERNEL_64))
-     {
-@@ -293,17 +338,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-     }
- #endif
- 
--  params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS,
--					BYTES_TO_PAGES(sizeof(*params)));
-+  params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters");
-   if (!params)
--    params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS,
--					  BYTES_TO_PAGES(sizeof(*params)));
--  if (! params)
--    {
--      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
--      goto fail;
--    }
--
-+    goto fail;
-   grub_dprintf ("linux", "params = %p\n", params);
- 
-   grub_memset (params, 0, sizeof(*params));
-@@ -322,19 +359,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   grub_dprintf ("linux", "new lh is at %p\n", lh);
- 
-   grub_dprintf ("linux", "setting up cmdline\n");
--  linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS,
--					      BYTES_TO_PAGES(lh->cmdline_size + 1));
-+  linux_cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline"));
-   if (!linux_cmdline)
--    linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS,
--						BYTES_TO_PAGES(lh->cmdline_size + 1));
--  if (!linux_cmdline)
--    {
--      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline"));
--      goto fail;
--    }
--
--  grub_dprintf ("linux", "linux_cmdline = %lx\n",
--		(unsigned long)linux_cmdline);
-+    goto fail;
-+  grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline);
- 
-   grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
-   grub_create_loader_cmdline (argc, argv,
-@@ -343,27 +371,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
- 			      GRUB_VERIFY_KERNEL_CMDLINE);
- 
-   grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline);
--  grub_dprintf ("linux", "setting lh->cmd_line_ptr\n");
--  lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline;
-+  grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n",
-+		linux_cmdline);
-+  lh->cmd_line_ptr = linux_cmdline;
- 
-   handover_offset = lh->handover_offset;
--  grub_dprintf("linux", "handover_offset: %08x\n", handover_offset);
-+  grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset);
- 
-   start = (lh->setup_sects + 1) * 512;
- 
--  kernel_mem = grub_efi_allocate_pages_max(lh->pref_address,
--					   BYTES_TO_PAGES(lh->init_size));
--  if (!kernel_mem)
--    kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS,
--					     BYTES_TO_PAGES(lh->init_size));
--  if (!kernel_mem)
--    kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS,
--					     BYTES_TO_PAGES(lh->init_size));
--  if (!kernel_mem)
-+  grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address);
-+  if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS)
-     {
--      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel"));
--      goto fail;
-+      max_addresses[0].addr = lh->pref_address;
-+      max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS;
-     }
-+  kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel"));
-+  if (!kernel_mem)
-+    goto fail;
-   grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem);
- 
-   grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
-@@ -398,18 +423,14 @@ fail:
-       loaded = 0;
-     }
- 
--  if (linux_cmdline && lh && !loaded)
--    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)
--			 linux_cmdline,
--			 BYTES_TO_PAGES(lh->cmdline_size + 1));
-+  if (!loaded)
-+    {
-+      if (lh)
-+	kernel_free (linux_cmdline, lh->cmdline_size + 1);
- 
--  if (kernel_mem && !loaded)
--    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem,
--			 BYTES_TO_PAGES(kernel_size));
--
--  if (params && !loaded)
--    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params,
--			 BYTES_TO_PAGES(16384));
-+      kernel_free (kernel_mem, kernel_size);
-+      kernel_free (params, sizeof(*params));
-+    }
- 
-   return grub_errno;
- }
diff --git a/SOURCES/0121-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch b/SOURCES/0121-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch
new file mode 100644
index 0000000..03d85c2
--- /dev/null
+++ b/SOURCES/0121-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch
@@ -0,0 +1,114 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Thu, 5 Mar 2020 16:21:58 +0100
+Subject: [PATCH] efi/http: Enclose literal IPv6 addresses in square brackets
+
+According to RFC 2732 (https://www.ietf.org/rfc/rfc2732.txt), literal IPv6
+addresses must be enclosed in square brackets. But GRUB currently does not
+do this and is causing HTTP servers to send Bad Request (400) responses.
+
+For example, the following is the HTTP stream when fetching a config file:
+
+HEAD /EFI/BOOT/grub.cfg HTTP/1.1
+Host: 2000:dead:beef:a::1
+Accept: */*
+User-Agent: UefiHttpBoot/1.0
+
+HTTP/1.1 400 Bad Request
+Date: Thu, 05 Mar 2020 14:46:02 GMT
+Server: Apache/2.4.41 (Fedora) OpenSSL/1.1.1d
+Connection: close
+Content-Type: text/html; charset=iso-8859-1
+
+and after enclosing the IPv6 address the HTTP request is successful:
+
+HEAD /EFI/BOOT/grub.cfg HTTP/1.1
+Host: [2000:dead:beef:a::1]
+Accept: */*
+User-Agent: UefiHttpBoot/1.0
+
+HTTP/1.1 200 OK
+Date: Thu, 05 Mar 2020 14:48:04 GMT
+Server: Apache/2.4.41 (Fedora) OpenSSL/1.1.1d
+Last-Modified: Thu, 27 Feb 2020 17:45:58 GMT
+ETag: "206-59f924b24b1da"
+Accept-Ranges: bytes
+Content-Length: 518
+
+Resolves: rhbz#1732765
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/net/efi/http.c | 37 ++++++++++++++++++++++++++++---------
+ 1 file changed, 28 insertions(+), 9 deletions(-)
+
+diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
+index 755b7a6d05..fc8cb25ae0 100644
+--- a/grub-core/net/efi/http.c
++++ b/grub-core/net/efi/http.c
+@@ -158,13 +158,7 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https,
+   grub_efi_status_t status;
+   grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
+   char *url = NULL;
+-
+-  request_headers[0].field_name = (grub_efi_char8_t *)"Host";
+-  request_headers[0].field_value = (grub_efi_char8_t *)server;
+-  request_headers[1].field_name = (grub_efi_char8_t *)"Accept";
+-  request_headers[1].field_value = (grub_efi_char8_t *)"*/*";
+-  request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent";
+-  request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0";
++  char *hostname = NULL;
+ 
+   {
+     grub_efi_ipv6_address_t address;
+@@ -174,9 +168,24 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https,
+     const char *protocol = (use_https == 1) ? "https" : "http";
+ 
+     if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0)
+-      url = grub_xasprintf ("%s://[%s]%s", protocol, server, name);
++      {
++        hostname = grub_xasprintf ("[%s]", server);
++        if (!hostname)
++          return GRUB_ERR_OUT_OF_MEMORY;
++
++        server = hostname;
++
++        url = grub_xasprintf ("%s://%s%s", protocol, server, name);
++        if (!url)
++          {
++            grub_free (hostname);
++            return GRUB_ERR_OUT_OF_MEMORY;
++          }
++      }
+     else
+-      url = grub_xasprintf ("%s://%s%s", protocol, server, name);
++      {
++        url = grub_xasprintf ("%s://%s%s", protocol, server, name);
++      }
+ 
+     if (!url)
+       {
+@@ -199,6 +208,13 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https,
+     request_data.url = ucs2_url;
+   }
+ 
++  request_headers[0].field_name = (grub_efi_char8_t *)"Host";
++  request_headers[0].field_value = (grub_efi_char8_t *)server;
++  request_headers[1].field_name = (grub_efi_char8_t *)"Accept";
++  request_headers[1].field_value = (grub_efi_char8_t *)"*/*";
++  request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent";
++  request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0";
++
+   request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET;
+ 
+   request_message.data.request = &request_data;
+@@ -228,6 +244,9 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https,
+ 
+   status = efi_call_2 (http->request, http, &request_token);
+ 
++  if (hostname)
++    grub_free (hostname);
++
+   if (status != GRUB_EFI_SUCCESS)
+     {
+       efi_call_1 (b->close_event, request_token.event);
diff --git a/SOURCES/0121-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch b/SOURCES/0121-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch
deleted file mode 100644
index b1233ce..0000000
--- a/SOURCES/0121-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch
+++ /dev/null
@@ -1,171 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Wed, 12 Sep 2018 16:12:27 -0400
-Subject: [PATCH] x86-efi: Allow initrd+params+cmdline allocations above 4GB.
-
-This enables everything except the kernel itself to be above 4GB.
-Putting the kernel up there still doesn't work, because of the way
-params->code32_start is used.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/loader/i386/efi/linux.c | 67 +++++++++++++++++++++++++++++++++++----
- include/grub/i386/linux.h         |  6 +++-
- 2 files changed, 65 insertions(+), 8 deletions(-)
-
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index 3e4f7ef39f4..6bc18d5aef5 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -52,13 +52,22 @@ struct allocation_choice {
-     grub_efi_allocate_type_t alloc_type;
- };
- 
--static struct allocation_choice max_addresses[] =
-+static struct allocation_choice max_addresses[4] =
-   {
-+    /* the kernel overrides this one with pref_address and
-+     * GRUB_EFI_ALLOCATE_ADDRESS */
-     { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-+    /* this one is always below 4GB, which we still *prefer* even if the flag
-+     * is set. */
-     { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-+    /* If the flag in params is set, this one gets changed to be above 4GB. */
-     { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-     { 0, 0 }
-   };
-+static struct allocation_choice saved_addresses[4];
-+
-+#define save_addresses() grub_memcpy(saved_addresses, max_addresses, sizeof(max_addresses))
-+#define restore_addresses() grub_memcpy(max_addresses, saved_addresses, sizeof(max_addresses))
- 
- static inline void
- kernel_free(void *addr, grub_efi_uintn_t size)
-@@ -80,6 +89,11 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
-       grub_uint64_t max = max_addresses[i].addr;
-       grub_efi_uintn_t pages;
- 
-+      /*
-+       * When we're *not* loading the kernel, or >4GB allocations aren't
-+       * supported, these entries are basically all the same, so don't re-try
-+       * the same parameters.
-+       */
-       if (max == prev_max)
- 	continue;
- 
-@@ -168,6 +182,9 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len)
-   return bufpos;
- }
- 
-+#define LOW_U32(val) ((grub_uint32_t)(((grub_addr_t)(val)) & 0xffffffffull))
-+#define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull))
-+
- static grub_err_t
- grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
-                  int argc, char *argv[])
-@@ -207,8 +224,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
-     goto fail;
-   grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
- 
--  params->ramdisk_size = size;
--  params->ramdisk_image = initrd_mem;
-+  params->ramdisk_size = LOW_U32(size);
-+  params->ramdisk_image = LOW_U32(initrd_mem);
-+#if defined(__x86_64__)
-+  params->ext_ramdisk_size = HIGH_U32(size);
-+  params->ext_ramdisk_image = HIGH_U32(initrd_mem);
-+#endif
- 
-   ptr = initrd_mem;
- 
-@@ -338,6 +359,18 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-     }
- #endif
- 
-+#if defined(__x86_64__)
-+  if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G)
-+    {
-+      grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n");
-+      max_addresses[2].addr = GRUB_EFI_MAX_USABLE_ADDRESS;
-+    }
-+  else
-+    {
-+      grub_dprintf ("linux", "Loading kernel above 4GB is not supported\n");
-+    }
-+#endif
-+
-   params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters");
-   if (!params)
-     goto fail;
-@@ -372,21 +405,40 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
- 
-   grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline);
-   grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n",
--		linux_cmdline);
--  lh->cmd_line_ptr = linux_cmdline;
-+		LOW_U32(linux_cmdline));
-+  lh->cmd_line_ptr = LOW_U32(linux_cmdline);
-+#if defined(__x86_64__)
-+  if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull)
-+    {
-+      grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n",
-+		    HIGH_U32(linux_cmdline));
-+      params->ext_cmd_line_ptr = HIGH_U32(linux_cmdline);
-+    }
-+#endif
- 
-   handover_offset = lh->handover_offset;
-   grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset);
- 
-   start = (lh->setup_sects + 1) * 512;
- 
-+  /*
-+   * AFAICS >4GB for kernel *cannot* work because of params->code32_start being
-+   * 32-bit and getting called unconditionally in head_64.S from either entry
-+   * point.
-+   *
-+   * so nerf that out here...
-+   */
-+  save_addresses();
-   grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address);
-   if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS)
-     {
-       max_addresses[0].addr = lh->pref_address;
-       max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS;
-     }
-+  max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
-+  max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
-   kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel"));
-+  restore_addresses();
-   if (!kernel_mem)
-     goto fail;
-   grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem);
-@@ -395,8 +447,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
- 
-   loaded = 1;
- 
--  grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem);
--  lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem;
-+  grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n",
-+		LOW_U32(kernel_mem));
-+  lh->code32_start = LOW_U32(kernel_mem);
- 
-   grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start);
- 
-diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h
-index 25ef52c04eb..fac22476cc5 100644
---- a/include/grub/i386/linux.h
-+++ b/include/grub/i386/linux.h
-@@ -236,7 +236,11 @@ struct linux_kernel_params
-   grub_uint32_t ofw_cif_handler;	/* b8 */
-   grub_uint32_t ofw_idt;		/* bc */
- 
--  grub_uint8_t padding7[0x1b8 - 0xc0];
-+  grub_uint32_t ext_ramdisk_image;	/* 0xc0 */
-+  grub_uint32_t ext_ramdisk_size;	/* 0xc4 */
-+  grub_uint32_t ext_cmd_line_ptr;	/* 0xc8 */
-+
-+  grub_uint8_t padding7[0x1b8 - 0xcc];
- 
-   union
-     {
diff --git a/SOURCES/0122-Fix-getroot.c-s-trampolines.patch b/SOURCES/0122-Fix-getroot.c-s-trampolines.patch
deleted file mode 100644
index 29ec44c..0000000
--- a/SOURCES/0122-Fix-getroot.c-s-trampolines.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Fri, 28 Sep 2018 15:42:19 -0400
-Subject: [PATCH] Fix getroot.c's trampolines.
-
-This makes the stack executable on most of the grub utilities, which is
-bad, and rpmdiff complains about it.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/osdep/linux/getroot.c | 16 +++++++---------
- 1 file changed, 7 insertions(+), 9 deletions(-)
-
-diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
-index 9f730b35189..f0c503f43d3 100644
---- a/grub-core/osdep/linux/getroot.c
-+++ b/grub-core/osdep/linux/getroot.c
-@@ -1264,22 +1264,20 @@ grub_util_get_grub_dev_os (const char *os_dev)
-   return grub_dev;
- }
- 
-+static void *mp = NULL;
-+static void
-+btrfs_mount_path_hook(const char *m)
-+{
-+  mp = strdup (m);
-+}
- 
- char *
- grub_util_get_btrfs_subvol (const char *path, char **mount_path)
- {
--  char *mp = NULL;
--
-   if (mount_path)
-     *mount_path = NULL;
- 
--  auto void
--  mount_path_hook (const char *m)
--  {
--    mp = strdup (m);
--  }
--
--  grub_find_root_btrfs_mount_path_hook = mount_path_hook;
-+  grub_find_root_btrfs_mount_path_hook = btrfs_mount_path_hook;
-   grub_free (grub_find_root_devices_from_mountinfo (path, NULL));
-   grub_find_root_btrfs_mount_path_hook = NULL;
- 
diff --git a/SOURCES/0122-efi-net-Allow-to-specify-a-port-number-in-addresses.patch b/SOURCES/0122-efi-net-Allow-to-specify-a-port-number-in-addresses.patch
new file mode 100644
index 0000000..8fe26cd
--- /dev/null
+++ b/SOURCES/0122-efi-net-Allow-to-specify-a-port-number-in-addresses.patch
@@ -0,0 +1,48 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Mon, 9 Mar 2020 15:29:45 +0100
+Subject: [PATCH] efi/net: Allow to specify a port number in addresses
+
+The grub_efi_net_parse_address() function is not covering the case where a
+port number is specified in an IPv4 or IPv6 address, so will fail to parse
+the network address.
+
+For most cases the issue is harmless, because the function is only used to
+match an address with a network interface and if fails the default is used.
+
+But still is a bug that has to be fixed and it causes error messages to be
+printed like the following:
+
+error: net/efi/net.c:782:unrecognised network address '192.168.122.1:8080'
+
+error: net/efi/net.c:781:unrecognised network address '[2000:dead:beef:a::1]:8080'
+
+Resolves: rhbz#1732765
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/net/efi/net.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
+index 6603cd83ed..84573937b1 100644
+--- a/grub-core/net/efi/net.c
++++ b/grub-core/net/efi/net.c
+@@ -742,7 +742,7 @@ grub_efi_net_parse_address (const char *address,
+ 	      return GRUB_ERR_NONE;
+ 	    }
+ 	}
+-      else if (*rest == 0)
++      else if (*rest == 0 || *rest == ':')
+ 	{
+ 	  grub_uint32_t subnet_mask = 0xffffffffU;
+ 	  grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask));
+@@ -768,7 +768,7 @@ grub_efi_net_parse_address (const char *address,
+ 	      return GRUB_ERR_NONE;
+ 	    }
+ 	}
+-      else if (*rest == 0)
++      else if (*rest == 0 || *rest == ':')
+ 	{
+ 	  ip6->prefix_length = 128;
+ 	  ip6->is_anycast = 0;
diff --git a/SOURCES/0123-Do-not-allow-stack-trampolines-anywhere.patch b/SOURCES/0123-Do-not-allow-stack-trampolines-anywhere.patch
deleted file mode 100644
index 4ee639d..0000000
--- a/SOURCES/0123-Do-not-allow-stack-trampolines-anywhere.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Fri, 12 Jul 2019 10:06:50 +0200
-Subject: [PATCH] Do not allow stack trampolines, anywhere.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- configure.ac         | 3 +++
- conf/Makefile.common | 2 +-
- 2 files changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/configure.ac b/configure.ac
-index bd28edf3141..907477a585c 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -2062,6 +2062,9 @@ if test x"$enable_wextra" != xno ; then
-   HOST_CFLAGS="$HOST_CFLAGS -Wextra"
- fi
- 
-+TARGET_CFLAGS="$TARGET_CFLAGS -Werror=trampolines -fno-trampolines"
-+HOST_CFLAGS="$HOST_CFLAGS -Werror=trampolines -fno-trampolines"
-+
- TARGET_CPP="$TARGET_CC -E"
- TARGET_CCAS=$TARGET_CC
- 
-diff --git a/conf/Makefile.common b/conf/Makefile.common
-index 35e14ff017e..0647c53b916 100644
---- a/conf/Makefile.common
-+++ b/conf/Makefile.common
-@@ -66,7 +66,7 @@ grubconfdir = $(sysconfdir)/grub.d
- platformdir = $(pkglibdir)/$(target_cpu)-$(platform)
- starfielddir = $(pkgdatadir)/themes/starfield
- 
--CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code
-+CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Werror=trampolines -fno-trampolines
- CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib
- 
- CFLAGS_POSIX = -fno-builtin
diff --git a/SOURCES/0123-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch b/SOURCES/0123-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch
new file mode 100644
index 0000000..2dc7001
--- /dev/null
+++ b/SOURCES/0123-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch
@@ -0,0 +1,48 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Mon, 9 Mar 2020 15:30:05 +0100
+Subject: [PATCH] efi/ip4_config: Improve check to detect literal IPv6
+ addresses
+
+The grub_efi_string_to_ip4_address() function wrongly assumes that an IPv6
+address is an IPv4 address, because it doesn't take into account the case
+of a caller passing an IPv6 address as a string.
+
+This leads to the grub_efi_net_parse_address() function to fail and print
+the following error message:
+
+error: net/efi/net.c:785:unrecognised network address '2000:dead:beef:a::1'
+
+Resolves: rhbz#1732765
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/net/efi/ip4_config.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c
+index b711a5d945..313c818b18 100644
+--- a/grub-core/net/efi/ip4_config.c
++++ b/grub-core/net/efi/ip4_config.c
+@@ -56,9 +56,20 @@ int
+ grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest)
+ {
+   grub_uint32_t newip = 0;
+-  int i;
++  int i, ncolon = 0;
+   const char *ptr = val;
+ 
++  /* Check that is not an IPv6 address */
++  for (i = 0; i < grub_strlen(ptr); i++)
++    {
++      if (ptr[i] == '[' && i == 0)
++        return 0;
++
++      if (ptr[i] == ':')
++          if (i == 0 || ++ncolon == 2)
++            return 0;
++    }
++
+   for (i = 0; i < 4; i++)
+     {
+       unsigned long t;
diff --git a/SOURCES/0124-Reimplement-boot_counter.patch b/SOURCES/0124-Reimplement-boot_counter.patch
deleted file mode 100644
index 164b229..0000000
--- a/SOURCES/0124-Reimplement-boot_counter.patch
+++ /dev/null
@@ -1,196 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 4 Oct 2018 14:22:09 -0400
-Subject: [PATCH] Reimplement boot_counter
-
-This adds "increment" and "decrement" commands, and uses them to maintain our
-variables in 01_fallback_counter.  It also simplifies the counter logic, so
-that there are no nested tests that conflict with each other.
-
-Apparently, this *really* wasn't tested well enough.
-
-Resolves: rhbz#1614637
-Signed-off-by: Peter Jones <pjones@redhat.com>
-[lorbus: add comments and revert logic changes in 01_fallback_counting]
-Signed-off-by: Christian Glombek <lorbus@fedoraproject.org>
----
- Makefile.util.def                   |   6 +++
- grub-core/Makefile.core.def         |   5 ++
- grub-core/commands/increment.c      | 105 ++++++++++++++++++++++++++++++++++++
- util/grub.d/01_fallback_counting.in |  22 ++++++++
- 4 files changed, 138 insertions(+)
- create mode 100644 grub-core/commands/increment.c
- create mode 100644 util/grub.d/01_fallback_counting.in
-
-diff --git a/Makefile.util.def b/Makefile.util.def
-index c6375933faa..2e5e05b25f1 100644
---- a/Makefile.util.def
-+++ b/Makefile.util.def
-@@ -458,6 +458,12 @@ script = {
-   installdir = grubconf;
- };
- 
-+script = {
-+  name = '01_fallback_counting';
-+  common = util/grub.d/01_fallback_counting.in;
-+  installdir = grubconf;
-+};
-+
- script = {
-   name = '01_menu_auto_hide';
-   common = util/grub.d/01_menu_auto_hide.in;
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 498ca11762a..1e15345107e 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -398,6 +398,11 @@ kernel = {
-   extra_dist = kern/mips/cache_flush.S;
- };
- 
-+module = {
-+  name = increment;
-+  common = commands/increment.c;
-+};
-+
- program = {
-   name = grub-emu;
-   mansection = 1;
-diff --git a/grub-core/commands/increment.c b/grub-core/commands/increment.c
-new file mode 100644
-index 00000000000..79cf137656c
---- /dev/null
-+++ b/grub-core/commands/increment.c
-@@ -0,0 +1,105 @@
-+/* increment.c - Commands to increment and decrement variables. */
-+/*
-+ *  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>
-+#include <grub/env.h>
-+
-+GRUB_MOD_LICENSE ("GPLv3+");
-+
-+typedef enum {
-+    INCREMENT,
-+    DECREMENT,
-+} operation;
-+
-+static grub_err_t
-+incr_decr(operation op, int argc, char **args)
-+{
-+  const char *old;
-+  char *new;
-+  long value;
-+
-+  if (argc < 1)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("no variable specified"));
-+  if (argc > 1)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("too many arguments"));
-+
-+  old = grub_env_get (*args);
-+  if (!old)
-+    return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("No such variable \"%s\""),
-+		       *args);
-+
-+  value = grub_strtol (old, NULL, 0);
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
-+
-+  switch (op)
-+    {
-+    case INCREMENT:
-+      value += 1;
-+      break;
-+    case DECREMENT:
-+      value -= 1;
-+      break;
-+    }
-+
-+  new = grub_xasprintf ("%ld", value);
-+  if (!new)
-+    return grub_errno;
-+
-+  grub_env_set (*args, new);
-+  grub_free (new);
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+grub_cmd_incr(struct grub_command *cmd UNUSED,
-+              int argc, char **args)
-+{
-+  return incr_decr(INCREMENT, argc, args);
-+}
-+
-+static grub_err_t
-+grub_cmd_decr(struct grub_command *cmd UNUSED,
-+              int argc, char **args)
-+{
-+  return incr_decr(DECREMENT, argc, args);
-+}
-+
-+static grub_command_t cmd_incr, cmd_decr;
-+
-+GRUB_MOD_INIT(increment)
-+{
-+  cmd_incr = grub_register_command ("increment", grub_cmd_incr, N_("VARIABLE"),
-+                                    N_("increment VARIABLE"));
-+  cmd_decr = grub_register_command ("decrement", grub_cmd_decr, N_("VARIABLE"),
-+                                    N_("decrement VARIABLE"));
-+}
-+
-+GRUB_MOD_FINI(increment)
-+{
-+  grub_unregister_command (cmd_incr);
-+  grub_unregister_command (cmd_decr);
-+}
-diff --git a/util/grub.d/01_fallback_counting.in b/util/grub.d/01_fallback_counting.in
-new file mode 100644
-index 00000000000..be0e770ea82
---- /dev/null
-+++ b/util/grub.d/01_fallback_counting.in
-@@ -0,0 +1,22 @@
-+#! /bin/sh -e
-+
-+# Boot Counting
-+# The boot_counter env var can be used to count down boot attempts after an
-+# OSTree upgrade and choose the rollback deployment when 0 is reached.  Both
-+# boot_counter and boot_success need to be (re-)set from userspace.
-+cat << EOF
-+insmod increment
-+# Check if boot_counter exists and boot_success=0 to activate this behaviour.
-+if [ -n "\${boot_counter}" -a "\${boot_success}" = "0" ]; then
-+  # if countdown has ended, choose to boot rollback deployment (default=1 on
-+  # OSTree-based systems)
-+  if  [ "\${boot_counter}" = "0" -o "\${boot_counter}" = "-1" ]; then
-+    set default=1
-+    set boot_counter=-1
-+  # otherwise decrement boot_counter
-+  else
-+    decrement boot_counter
-+  fi
-+  save_env boot_counter
-+fi
-+EOF
diff --git a/SOURCES/0124-efi-net-Print-a-debug-message-if-parsing-the-address.patch b/SOURCES/0124-efi-net-Print-a-debug-message-if-parsing-the-address.patch
new file mode 100644
index 0000000..da94e08
--- /dev/null
+++ b/SOURCES/0124-efi-net-Print-a-debug-message-if-parsing-the-address.patch
@@ -0,0 +1,68 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 10 Mar 2020 11:23:49 +0100
+Subject: [PATCH] efi/net: Print a debug message if parsing the address fails
+
+Currently if parsing the address fails an error message is printed. But in
+most cases this isn't a fatal error since the grub_efi_net_parse_address()
+function is only used to match an address with a network interface to use.
+
+And if this fails, the default interface is used which is good enough for
+most cases. So instead of printing an error that would pollute the console
+just print a debug message if the address is not parsed correctly.
+
+A user can enable debug messages for the efinet driver to have information
+about the failure and the fact that the default interface is being used.
+
+Related: rhbz#1732765
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/net/efi/net.c | 18 +++++++++++-------
+ 1 file changed, 11 insertions(+), 7 deletions(-)
+
+diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
+index 84573937b1..a3f0535d43 100644
+--- a/grub-core/net/efi/net.c
++++ b/grub-core/net/efi/net.c
+@@ -778,9 +778,9 @@ grub_efi_net_parse_address (const char *address,
+ 	}
+     }
+ 
+-  return grub_error (GRUB_ERR_NET_BAD_ADDRESS,
+-		   N_("unrecognised network address `%s'"),
+-		   address);
++  grub_dprintf ("efinet", "unrecognised network address '%s'\n", address);
++
++  return GRUB_ERR_NET_BAD_ADDRESS;
+ }
+ 
+ static grub_efi_net_interface_t *
+@@ -795,10 +795,7 @@ match_route (const char *server)
+   err = grub_efi_net_parse_address (server, &ip4, &ip6, &is_ip6, 0);
+ 
+   if (err)
+-    {
+-      grub_print_error ();
+       return NULL;
+-    }
+ 
+   if (is_ip6)
+     {
+@@ -1233,8 +1230,15 @@ grub_net_open_real (const char *name __attribute__ ((unused)))
+   /*FIXME: Use DNS translate name to address */
+   net_interface = match_route (server);
+ 
++  if (!net_interface && net_default_interface)
++    {
++      net_interface = net_default_interface;
++      grub_dprintf ("efinet", "interface lookup failed, using default '%s'\n",
++                    net_interface->name);
++    }
++
+   /*XXX: should we check device with default gateway ? */
+-  if (!net_interface && !(net_interface = net_default_interface))
++  if (!net_interface)
+     {
+       grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' no route found"),
+ 		  name);
diff --git a/SOURCES/0125-Fix-menu-entry-selection-based-on-ID-and-title.patch b/SOURCES/0125-Fix-menu-entry-selection-based-on-ID-and-title.patch
deleted file mode 100644
index 84c1370..0000000
--- a/SOURCES/0125-Fix-menu-entry-selection-based-on-ID-and-title.patch
+++ /dev/null
@@ -1,233 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Fri, 19 Oct 2018 10:57:52 -0400
-Subject: [PATCH] Fix menu entry selection based on ID and title
-
-Currently if grub_strtoul(saved_entry_value, NULL, 0) does not return an
-error, we assume the value it has produced is a correct index into our
-menu entry list, and do not try to interpret the value as the "id" or
-"title" .  In cases where "id" or "title" start with a numeral, this
-makes them impossible to use as selection criteria.
-
-This patch splits the search into three phases - matching id, matching
-title, and only once those have been exhausted, trying to interpret the
-ID as a numeral.  In that case, we also require that the entire string
-is numeric, not merely a string with leading numeric characters.
-
-Resolves: rhbz#1640979
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-[javierm: fix menu entry selection based on title]
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/normal/menu.c | 141 ++++++++++++++++++++++++------------------------
- 1 file changed, 71 insertions(+), 70 deletions(-)
-
-diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
-index 37d753d8081..ea714d27176 100644
---- a/grub-core/normal/menu.c
-+++ b/grub-core/normal/menu.c
-@@ -164,12 +164,12 @@ grub_menu_set_timeout (int timeout)
- }
- 
- static int
--menuentry_eq (const char *id, const char *spec)
-+menuentry_eq (const char *id, const char *spec, int limit)
- {
-   const char *ptr1, *ptr2;
-   ptr1 = id;
-   ptr2 = spec;
--  while (1)
-+  while (limit == -1 || ptr1 - id <= limit)
-     {
-       if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0)
- 	return ptr2 - spec;
-@@ -178,7 +178,11 @@ menuentry_eq (const char *id, const char *spec)
-       if (*ptr2 == '>')
- 	ptr2++;
-       if (*ptr1 != *ptr2)
--	return 0;
-+	{
-+	  if (limit > -1 && ptr1 - id == limit && !*ptr1 && grub_isspace(*ptr2))
-+	    return ptr1 -id -1;
-+	  return 0;
-+	}
-       if (*ptr1 == 0)
- 	return ptr1 - id;
-       ptr1++;
-@@ -187,6 +191,58 @@ menuentry_eq (const char *id, const char *spec)
-   return 0;
- }
- 
-+static int
-+get_entry_number_helper(grub_menu_t menu,
-+			const char * const val, const char ** const tail)
-+{
-+  /* See if the variable matches the title of a menu entry.  */
-+  int entry = -1;
-+  grub_menu_entry_t e;
-+  int i;
-+
-+  for (i = 0, e = menu->entry_list; e; i++)
-+    {
-+      int l = 0;
-+      while (val[l] && !grub_isspace(val[l]))
-+	l++;
-+
-+      if (menuentry_eq (e->id, val, l))
-+	{
-+	  if (tail)
-+	    *tail = val + l;
-+	  return i;
-+	}
-+      e = e->next;
-+    }
-+
-+  for (i = 0, e = menu->entry_list; e; i++)
-+    {
-+
-+      if (menuentry_eq (e->title, val, -1))
-+	{
-+	  if (tail)
-+	    *tail = NULL;
-+	  return i;
-+	}
-+      e = e->next;
-+    }
-+
-+  if (tail)
-+    *tail = NULL;
-+
-+  entry = (int) grub_strtoul (val, tail, 0);
-+  if (grub_errno == GRUB_ERR_BAD_NUMBER ||
-+      (*tail && **tail && !grub_isspace(**tail)))
-+    {
-+      entry = -1;
-+      if (tail)
-+	*tail = NULL;
-+      grub_errno = GRUB_ERR_NONE;
-+    }
-+
-+  return entry;
-+}
-+
- /* Get the first entry number from the value of the environment variable NAME,
-    which is a space-separated list of non-negative integers.  The entry number
-    which is returned is stripped from the value of NAME.  If no entry number
-@@ -196,7 +252,6 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name)
- {
-   const char *val, *tail;
-   int entry;
--  int sz = 0;
- 
-   val = grub_env_get (name);
-   if (! val)
-@@ -204,50 +259,24 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name)
- 
-   grub_error_push ();
- 
--  entry = (int) grub_strtoul (val, &tail, 0);
-+  entry = get_entry_number_helper(menu, val, &tail);
-+  if (!(*tail == 0 || grub_isspace(*tail)))
-+    entry = -1;
- 
--  if (grub_errno == GRUB_ERR_BAD_NUMBER)
-+  if (entry >= 0)
-     {
--      /* See if the variable matches the title of a menu entry.  */
--      grub_menu_entry_t e = menu->entry_list;
--      int i;
--
--      for (i = 0; e; i++)
--	{
--	  sz = menuentry_eq (e->title, val);
--	  if (sz < 1)
--	    sz = menuentry_eq (e->id, val);
--
--	  if (sz >= 1)
--	    {
--	      entry = i;
--	      break;
--	    }
--	  e = e->next;
--	}
--
--      if (sz > 0)
--	grub_errno = GRUB_ERR_NONE;
--
--      if (! e)
--	entry = -1;
--    }
--
--  if (grub_errno == GRUB_ERR_NONE)
--    {
--      if (sz > 0)
--	tail += sz;
--
-       /* Skip whitespace to find the next entry.  */
-       while (*tail && grub_isspace (*tail))
- 	tail++;
--      grub_env_set (name, tail);
-+      if (*tail)
-+	grub_env_set (name, tail);
-+      else
-+	grub_env_unset (name);
-     }
-   else
-     {
-       grub_env_unset (name);
-       grub_errno = GRUB_ERR_NONE;
--      entry = -1;
-     }
- 
-   grub_error_pop ();
-@@ -524,6 +553,7 @@ static int
- get_entry_number (grub_menu_t menu, const char *name)
- {
-   const char *val;
-+  const char *tail;
-   int entry;
- 
-   val = grub_env_get (name);
-@@ -531,38 +561,9 @@ get_entry_number (grub_menu_t menu, const char *name)
-     return -1;
- 
-   grub_error_push ();
--
--  entry = (int) grub_strtoul (val, 0, 0);
--
--  if (grub_errno == GRUB_ERR_BAD_NUMBER)
--    {
--      /* See if the variable matches the title of a menu entry.  */
--      grub_menu_entry_t e = menu->entry_list;
--      int i;
--
--      grub_errno = GRUB_ERR_NONE;
--
--      for (i = 0; e; i++)
--	{
--	  if (menuentry_eq (e->title, val)
--	      || menuentry_eq (e->id, val))
--	    {
--	      entry = i;
--	      break;
--	    }
--	  e = e->next;
--	}
--
--      if (! e)
--	entry = -1;
--    }
--
--  if (grub_errno != GRUB_ERR_NONE)
--    {
--      grub_errno = GRUB_ERR_NONE;
--      entry = -1;
--    }
--
-+  entry = get_entry_number_helper(menu, val, &tail);
-+  if (tail && *tail != '\0')
-+    entry = -1;
-   grub_error_pop ();
- 
-   return entry;
diff --git a/SOURCES/0125-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch b/SOURCES/0125-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch
new file mode 100644
index 0000000..8793b0d
--- /dev/null
+++ b/SOURCES/0125-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch
@@ -0,0 +1,30 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Wed, 22 Apr 2020 12:41:52 +0200
+Subject: [PATCH] kern/term: Also accept F8 as a user interrupt key
+
+Make F8, which used to be the hotkey to show the Windows boot menu during
+boot for a long long time, also interrupt sleeps / stop the menu countdown.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/kern/term.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/kern/term.c b/grub-core/kern/term.c
+index 14d5964983..4d61f4e979 100644
+--- a/grub-core/kern/term.c
++++ b/grub-core/kern/term.c
+@@ -144,9 +144,10 @@ grub_key_is_interrupt (int key)
+   /*
+    * ESC sometimes is the BIOS setup hotkey and may be hard to discover, also
+    * check F4, which was chosen because is not used as a hotkey to enter the
+-   * BIOS setup by any vendor.
++   * BIOS setup by any vendor. Also, F8 which was the key to get the Windows
++   * bootmenu for a long time.
+    */
+-  if (key == GRUB_TERM_ESC || key == GRUB_TERM_KEY_F4)
++  if (key == GRUB_TERM_ESC || key == GRUB_TERM_KEY_F4 || key == GRUB_TERM_KEY_F8)
+     return 1;
+ 
+   /*
diff --git a/SOURCES/0126-Make-the-menu-entry-users-option-argument-to-be-opti.patch b/SOURCES/0126-Make-the-menu-entry-users-option-argument-to-be-opti.patch
deleted file mode 100644
index e0d36db..0000000
--- a/SOURCES/0126-Make-the-menu-entry-users-option-argument-to-be-opti.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Mon, 26 Nov 2018 10:06:42 +0100
-Subject: [PATCH] Make the menu entry users option argument to be optional
-
-The --users option is used to restrict the access to specific menu entries
-only to a set of users. But the option requires an argument to either be a
-constant or a variable that has been set. So for example the following:
-
-  menuentry "May be run by superusers or users in $users" --users $users {
-  	    linux /vmlinuz
-  }
-
-Would fail if $users is not defined and grub would discard the menu entry.
-Instead, allow the --users option to have an optional argument and ignore
-the option if the argument was not set.
-
-Related: rhbz#1652434
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/commands/menuentry.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c
-index b194123eb67..b175a1b43b7 100644
---- a/grub-core/commands/menuentry.c
-+++ b/grub-core/commands/menuentry.c
-@@ -29,7 +29,7 @@ static const struct grub_arg_option options[] =
-   {
-     {"class", 1, GRUB_ARG_OPTION_REPEATABLE,
-      N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING},
--    {"users", 2, 0,
-+    {"users", 2, GRUB_ARG_OPTION_OPTIONAL,
-      N_("List of users allowed to boot this entry."), N_("USERNAME[,USERNAME]"),
-      ARG_TYPE_STRING},
-     {"hotkey", 3, 0,
-@@ -281,7 +281,7 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
-   if (! ctxt->state[3].set && ! ctxt->script)
-     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition");
- 
--  if (ctxt->state[1].set)
-+  if (ctxt->state[1].set && ctxt->state[1].arg)
-     users = ctxt->state[1].arg;
-   else if (ctxt->state[5].set)
-     users = NULL;
diff --git a/SOURCES/0126-efi-Set-image-base-address-before-jumping-to-the-PE-.patch b/SOURCES/0126-efi-Set-image-base-address-before-jumping-to-the-PE-.patch
new file mode 100644
index 0000000..6aa5013
--- /dev/null
+++ b/SOURCES/0126-efi-Set-image-base-address-before-jumping-to-the-PE-.patch
@@ -0,0 +1,62 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Thu, 23 Apr 2020 15:06:46 +0200
+Subject: [PATCH] efi: Set image base address before jumping to the PE/COFF
+ entry point
+
+Upstream GRUB uses the EFI LoadImage() and StartImage() to boot the Linux
+kernel. But our custom EFI loader that supports Secure Boot instead uses
+the EFI handover protocol (for x86) or jumping directly to the PE/COFF
+entry point (for aarch64).
+
+This is done to allow the bootloader to verify the images using the shim
+lock protocol to avoid booting untrusted binaries.
+
+Since the bootloader loads the kernel from the boot media instead of using
+LoadImage(), it is responsible to set the Loaded Image base address before
+booting the kernel.
+
+Otherwise the kernel EFI stub will complain that it was not set correctly
+and print the following warning message:
+
+EFI stub: ERROR: FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value
+
+Resolves: rhbz#1814690
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/loader/efi/linux.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
+index 0622dfa48d..e8b9ecb17f 100644
+--- a/grub-core/loader/efi/linux.c
++++ b/grub-core/loader/efi/linux.c
+@@ -72,6 +72,7 @@ grub_err_t
+ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
+ 		     void *kernel_params)
+ {
++  grub_efi_loaded_image_t *loaded_image = NULL;
+   handover_func hf;
+   int offset = 0;
+ 
+@@ -79,6 +80,19 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
+   offset = 512;
+ #endif
+ 
++  /*
++   * Since the EFI loader is not calling the LoadImage() and StartImage()
++   * services for loading the kernel and booting respectively, it has to
++   * set the Loaded Image base address.
++   */
++  loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
++  if (loaded_image)
++    loaded_image->image_base = kernel_addr;
++  else
++    grub_dprintf ("linux", "Loaded Image base address could not be set\n");
++
++  grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n",
++		kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params);
+   hf = (handover_func)((char *)kernel_addr + handover_offset + offset);
+   hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
+ 
diff --git a/SOURCES/0127-Add-efi-export-env-and-efi-load-env-commands.patch b/SOURCES/0127-Add-efi-export-env-and-efi-load-env-commands.patch
deleted file mode 100644
index 73456bc..0000000
--- a/SOURCES/0127-Add-efi-export-env-and-efi-load-env-commands.patch
+++ /dev/null
@@ -1,346 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Wed, 16 Jan 2019 13:21:46 -0500
-Subject: [PATCH] Add efi-export-env and efi-load-env commands
-
-This adds "efi-export-env VARIABLE" and "efi-load-env", which manipulate the
-environment block stored in the EFI variable
-GRUB_ENV-91376aff-cba6-42be-949d-06fde81128e8.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/Makefile.core.def  |   6 ++
- grub-core/commands/efi/env.c | 168 +++++++++++++++++++++++++++++++++++++++++++
- grub-core/kern/efi/efi.c     |   3 +
- grub-core/kern/efi/init.c    |   5 --
- grub-core/lib/envblk.c       |  43 +++++++++++
- util/grub-set-bootflag.c     |   1 +
- include/grub/efi/efi.h       |   5 ++
- include/grub/lib/envblk.h    |   3 +
- 8 files changed, 229 insertions(+), 5 deletions(-)
- create mode 100644 grub-core/commands/efi/env.c
-
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 1e15345107e..81fc274148e 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -820,6 +820,12 @@ module = {
-   enable = efi;
- };
- 
-+module = {
-+  name = efienv;
-+  common = commands/efi/env.c;
-+  enable = efi;
-+};
-+
- module = {
-   name = efifwsetup;
-   efi = commands/efi/efifwsetup.c;
-diff --git a/grub-core/commands/efi/env.c b/grub-core/commands/efi/env.c
-new file mode 100644
-index 00000000000..cbd13e03e81
---- /dev/null
-+++ b/grub-core/commands/efi/env.c
-@@ -0,0 +1,168 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2012  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/misc.h>
-+#include <grub/types.h>
-+#include <grub/mm.h>
-+#include <grub/misc.h>
-+#include <grub/efi/api.h>
-+#include <grub/efi/efi.h>
-+#include <grub/env.h>
-+#include <grub/lib/envblk.h>
-+#include <grub/command.h>
-+
-+GRUB_MOD_LICENSE ("GPLv3+");
-+
-+static const grub_efi_guid_t grub_env_guid = GRUB_EFI_GRUB_VARIABLE_GUID;
-+
-+static grub_err_t
-+grub_efi_export_env(grub_command_t cmd __attribute__ ((unused)),
-+                    int argc, char *argv[])
-+{
-+  const char *value;
-+  char *old_value;
-+  struct grub_envblk envblk_s = { NULL, 0 };
-+  grub_envblk_t envblk = &envblk_s;
-+  grub_err_t err;
-+  int changed = 1;
-+  grub_efi_status_t status;
-+
-+  grub_dprintf ("efienv", "argc:%d\n", argc);
-+  for (int i = 0; i < argc; i++)
-+    grub_dprintf ("efienv", "argv[%d]: %s\n", i, argv[i]);
-+
-+  if (argc != 1)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("variable name expected"));
-+
-+  grub_efi_get_variable ("GRUB_ENV", &grub_env_guid, &envblk_s.size,
-+                         (void **) &envblk_s.buf);
-+  if (!envblk_s.buf || envblk_s.size < 1)
-+    {
-+      char *buf = grub_malloc (1025);
-+      if (!buf)
-+        return grub_errno;
-+
-+      grub_memcpy (buf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1);
-+      grub_memset (buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1, '#',
-+	      DEFAULT_ENVBLK_SIZE - sizeof (GRUB_ENVBLK_SIGNATURE) + 1);
-+      buf[1024] = '\0';
-+
-+      envblk_s.buf = buf;
-+      envblk_s.size = 1024;
-+    }
-+  else
-+    {
-+      char *buf = grub_realloc (envblk_s.buf, envblk_s.size + 1);
-+      if (!buf)
-+	return grub_errno;
-+
-+      envblk_s.buf = buf;
-+      envblk_s.buf[envblk_s.size] = '\0';
-+    }
-+
-+  err = grub_envblk_get(envblk, argv[0], &old_value);
-+  if (err != GRUB_ERR_NONE)
-+    {
-+      grub_dprintf ("efienv", "grub_envblk_get returned %d\n", err);
-+      return err;
-+    }
-+
-+  value = grub_env_get(argv[0]);
-+  if ((!value && !old_value) ||
-+      (value && old_value && !grub_strcmp(old_value, value)))
-+    changed = 0;
-+
-+  if (old_value)
-+    grub_free(old_value);
-+
-+  if (changed == 0)
-+    {
-+      grub_dprintf ("efienv", "No changes necessary\n");
-+      return 0;
-+    }
-+
-+  if (value)
-+    {
-+      grub_dprintf ("efienv", "setting \"%s\" to \"%s\"\n", argv[0], value);
-+      grub_envblk_set(envblk, argv[0], value);
-+    }
-+  else
-+    {
-+      grub_dprintf ("efienv", "deleting \"%s\" from envblk\n", argv[0]);
-+      grub_envblk_delete(envblk, argv[0]);
-+    }
-+
-+  grub_dprintf ("efienv", "envblk is %lu bytes:\n\"%s\"\n", envblk_s.size, envblk_s.buf);
-+
-+  grub_dprintf ("efienv", "removing GRUB_ENV\n");
-+  status = grub_efi_set_variable ("GRUB_ENV", &grub_env_guid, NULL, 0);
-+  if (status != GRUB_EFI_SUCCESS)
-+    grub_dprintf ("efienv", "removal returned %ld\n", status);
-+
-+  grub_dprintf ("efienv", "setting GRUB_ENV\n");
-+  status = grub_efi_set_variable ("GRUB_ENV", &grub_env_guid,
-+				  envblk_s.buf, envblk_s.size);
-+  if (status != GRUB_EFI_SUCCESS)
-+    grub_dprintf ("efienv", "setting GRUB_ENV returned %ld\n", status);
-+
-+  return 0;
-+}
-+
-+static int
-+set_var (const char *name, const char *value,
-+	 void *whitelist __attribute__((__unused__)))
-+{
-+  grub_env_set (name, value);
-+  return 0;
-+}
-+
-+static grub_err_t
-+grub_efi_load_env(grub_command_t cmd __attribute__ ((unused)),
-+                    int argc, char *argv[] __attribute__((__unused__)))
-+{
-+  struct grub_envblk envblk_s = { NULL, 0 };
-+  grub_envblk_t envblk = &envblk_s;
-+
-+  grub_efi_get_variable ("GRUB_ENV", &grub_env_guid, &envblk_s.size,
-+                         (void **) &envblk_s.buf);
-+  if (!envblk_s.buf || envblk_s.size < 1)
-+    return 0;
-+
-+  if (argc > 0)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unexpected argument"));
-+
-+  grub_envblk_iterate (envblk, NULL, set_var);
-+  grub_free (envblk_s.buf);
-+}
-+
-+static grub_command_t export_cmd, loadenv_cmd;
-+
-+GRUB_MOD_INIT(lsefi)
-+{
-+  export_cmd = grub_register_command ("efi-export-env", grub_efi_export_env,
-+	    N_("VARIABLE_NAME"), N_("Export environment variable to UEFI."));
-+  loadenv_cmd = grub_register_command ("efi-load-env", grub_efi_load_env,
-+	    NULL, N_("Load the grub environment from UEFI."));
-+}
-+
-+GRUB_MOD_FINI(lsefi)
-+{
-+  grub_unregister_command (export_cmd);
-+  grub_unregister_command (loadenv_cmd);
-+}
-diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
-index 2a446f5031b..14bc10eb564 100644
---- a/grub-core/kern/efi/efi.c
-+++ b/grub-core/kern/efi/efi.c
-@@ -225,6 +225,9 @@ grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid,
-   if (status == GRUB_EFI_SUCCESS)
-     return GRUB_ERR_NONE;
- 
-+  if (status == GRUB_EFI_NOT_FOUND && datasize == 0)
-+    return GRUB_ERR_NONE;
-+
-   return grub_error (GRUB_ERR_IO, "could not set EFI variable `%s'", var);
- }
- 
-diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
-index 2d12e6188fd..0574d8d6217 100644
---- a/grub-core/kern/efi/init.c
-+++ b/grub-core/kern/efi/init.c
-@@ -85,11 +85,6 @@ stack_protector_init (void)
- 
- grub_addr_t grub_modbase;
- 
--#define GRUB_EFI_GRUB_VARIABLE_GUID \
--  { 0x91376aff, 0xcba6, 0x42be, \
--    { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \
--  }
--
- /* Helper for grub_efi_env_init */
- static int
- set_var (const char *name, const char *value,
-diff --git a/grub-core/lib/envblk.c b/grub-core/lib/envblk.c
-index 2e4e78b132d..874506da169 100644
---- a/grub-core/lib/envblk.c
-+++ b/grub-core/lib/envblk.c
-@@ -223,6 +223,49 @@ grub_envblk_delete (grub_envblk_t envblk, const char *name)
-     }
- }
- 
-+struct get_var_state {
-+  const char * const name;
-+  char * value;
-+  int found;
-+};
-+
-+static int
-+get_var (const char * const name, const char * const value, void *statep)
-+{
-+  struct get_var_state *state = (struct get_var_state *)statep;
-+
-+  if (!grub_strcmp(state->name, name))
-+    {
-+      state->found = 1;
-+      state->value = grub_strdup(value);
-+      if (!state->value)
-+	grub_errno = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
-+
-+      return 1;
-+    }
-+
-+  return 0;
-+}
-+
-+grub_err_t
-+grub_envblk_get (grub_envblk_t envblk, const char * const name, char ** const value)
-+{
-+  struct get_var_state state = {
-+      .name = name,
-+      .value = NULL,
-+      .found = 0,
-+  };
-+
-+  grub_envblk_iterate(envblk, (void *)&state, get_var);
-+
-+  *value = state.value;
-+
-+  if (state.found && !state.value)
-+    return grub_errno;
-+
-+  return GRUB_ERR_NONE;
-+}
-+
- void
- grub_envblk_iterate (grub_envblk_t envblk,
-                      void *hook_data,
-diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c
-index bb198f02351..6a79ee67444 100644
---- a/util/grub-set-bootflag.c
-+++ b/util/grub-set-bootflag.c
-@@ -25,6 +25,7 @@
- 
- #include <config-util.h>     /* For *_DIR_NAME defines */
- #include <grub/types.h>
-+#include <grub/err.h>
- #include <grub/lib/envblk.h> /* For GRUB_ENVBLK_DEFCFG define */
- #include <errno.h>
- #include <stdio.h>
-diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
-index 2e0691454b1..8dfc89a33b9 100644
---- a/include/grub/efi/efi.h
-+++ b/include/grub/efi/efi.h
-@@ -24,6 +24,11 @@
- #include <grub/dl.h>
- #include <grub/efi/api.h>
- 
-+#define GRUB_EFI_GRUB_VARIABLE_GUID \
-+  { 0x91376aff, 0xcba6, 0x42be, \
-+    { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \
-+  }
-+
- /* Variables.  */
- extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table);
- extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle);
-diff --git a/include/grub/lib/envblk.h b/include/grub/lib/envblk.h
-index c3e65592170..ab969af2461 100644
---- a/include/grub/lib/envblk.h
-+++ b/include/grub/lib/envblk.h
-@@ -22,6 +22,8 @@
- #define GRUB_ENVBLK_SIGNATURE	"# GRUB Environment Block\n"
- #define GRUB_ENVBLK_DEFCFG	"grubenv"
- 
-+#define DEFAULT_ENVBLK_SIZE	1024
-+
- #ifndef ASM_FILE
- 
- struct grub_envblk
-@@ -33,6 +35,7 @@ typedef struct grub_envblk *grub_envblk_t;
- 
- grub_envblk_t grub_envblk_open (char *buf, grub_size_t size);
- int grub_envblk_set (grub_envblk_t envblk, const char *name, const char *value);
-+grub_err_t grub_envblk_get (grub_envblk_t envblk, const char * const name, char ** const value);
- void grub_envblk_delete (grub_envblk_t envblk, const char *name);
- void grub_envblk_iterate (grub_envblk_t envblk,
-                           void *hook_data,
diff --git a/SOURCES/0127-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch b/SOURCES/0127-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch
new file mode 100644
index 0000000..d1c7b17
--- /dev/null
+++ b/SOURCES/0127-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch
@@ -0,0 +1,62 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Sat, 16 May 2020 11:33:18 +0200
+Subject: [PATCH] tpm: Don't propagate TPM measurement errors to the verifiers
+ layer
+
+Currently if the EFI firmware fails to do a TPM measurement for a file,
+the error will be propagated to the verifiers framework and so opening
+the file will not succeed.
+
+This mean that buggy firmwares will prevent the system to boot since the
+loader won't be able to open any file. But failing to do TPM measurements
+shouldn't be a fatal error and the system should still be able to boot.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/tpm.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/grub-core/commands/tpm.c b/grub-core/commands/tpm.c
+index 2052c36eab..e287d042e6 100644
+--- a/grub-core/commands/tpm.c
++++ b/grub-core/commands/tpm.c
+@@ -42,7 +42,8 @@ grub_tpm_verify_init (grub_file_t io,
+ static grub_err_t
+ grub_tpm_verify_write (void *context, void *buf, grub_size_t size)
+ {
+-  return grub_tpm_measure (buf, size, GRUB_BINARY_PCR, context);
++  grub_tpm_measure (buf, size, GRUB_BINARY_PCR, context);
++  return GRUB_ERR_NONE;
+ }
+ 
+ static grub_err_t
+@@ -50,7 +51,6 @@ grub_tpm_verify_string (char *str, enum grub_verify_string_type type)
+ {
+   const char *prefix = NULL;
+   char *description;
+-  grub_err_t status;
+ 
+   switch (type)
+     {
+@@ -66,15 +66,15 @@ grub_tpm_verify_string (char *str, enum grub_verify_string_type type)
+     }
+   description = grub_malloc (grub_strlen (str) + grub_strlen (prefix) + 1);
+   if (!description)
+-    return grub_errno;
++    return GRUB_ERR_NONE;
+   grub_memcpy (description, prefix, grub_strlen (prefix));
+   grub_memcpy (description + grub_strlen (prefix), str,
+ 	       grub_strlen (str) + 1);
+-  status =
+-    grub_tpm_measure ((unsigned char *) str, grub_strlen (str),
+-		      GRUB_STRING_PCR, description);
++
++  grub_tpm_measure ((unsigned char *) str, grub_strlen (str), GRUB_STRING_PCR,
++                    description);
+   grub_free (description);
+-  return status;
++  return GRUB_ERR_NONE;
+ }
+ 
+ struct grub_file_verifier grub_tpm_verifier = {
diff --git a/SOURCES/0128-Make-it-possible-to-subtract-conditions-from-debug.patch b/SOURCES/0128-Make-it-possible-to-subtract-conditions-from-debug.patch
deleted file mode 100644
index fce51ea..0000000
--- a/SOURCES/0128-Make-it-possible-to-subtract-conditions-from-debug.patch
+++ /dev/null
@@ -1,45 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 17 Jan 2019 13:10:39 -0500
-Subject: [PATCH] Make it possible to subtract conditions from debug=
-
-This makes it so you can do set debug to "all,-scripting,-lexer" and get the
-obvious outcome.  Any negation present will take preference over that
-conditional, so "all,-scripting,scripting" is the same thing as
-"all,-scripting".
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/kern/misc.c | 14 +++++++++++++-
- 1 file changed, 13 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
-index 9a2fae6398e..578bf51a5fc 100644
---- a/grub-core/kern/misc.c
-+++ b/grub-core/kern/misc.c
-@@ -164,12 +164,24 @@ int
- grub_debug_enabled (const char * condition)
- {
-   const char *debug;
-+  char *negcond;
-+  int negated = 0;
- 
-   debug = grub_env_get ("debug");
-   if (!debug)
-     return 0;
- 
--  if (grub_strword (debug, "all") || grub_strword (debug, condition))
-+  negcond = grub_zalloc (grub_strlen (condition) + 2);
-+  if (negcond)
-+    {
-+      grub_strcpy (negcond, "-");
-+      grub_strcpy (negcond+1, condition);
-+      negated = grub_strword (debug, negcond);
-+      grub_free (negcond);
-+    }
-+
-+  if (!negated &&
-+      (grub_strword (debug, "all") || grub_strword (debug, condition)))
-     return 1;
- 
-   return 0;
diff --git a/SOURCES/0128-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch b/SOURCES/0128-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch
new file mode 100644
index 0000000..7c41e87
--- /dev/null
+++ b/SOURCES/0128-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 26 May 2020 16:59:28 +0200
+Subject: [PATCH] x86-efi: Reduce maximum bounce buffer size to 16 MiB
+
+The EFI linux loader allocates a bounce buffer to copy the initrd since in
+some machines doing DMA on addresses above 4GB is not possible during EFI.
+
+But the verifiers framework also allocates a buffer to copy the initrd in
+its grub_file_open() handler. It does this since the data to verify has to
+be passed as a single chunk to modules that use the verifiers framework.
+
+If the initrd image size is big there may not be enough memory in the heap
+to allocate two buffers of that size. This causes an allocation failure in
+the verifiers framework and leads to the initrd not being read.
+
+To prevent these allocation failures, let's reduce the maximum size of the
+bounce buffer used in the EFI loader. Since the data read can be copied to
+the actual initrd address in multilple chunks.
+
+Resolves: rhbz#1838633
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/loader/i386/efi/linux.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 6bc18d5aef..15d40d6e35 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -144,7 +144,7 @@ grub_linuxefi_unload (void)
+   return GRUB_ERR_NONE;
+ }
+ 
+-#define BOUNCE_BUFFER_MAX 0x10000000ull
++#define BOUNCE_BUFFER_MAX 0x1000000ull
+ 
+ static grub_ssize_t
+ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len)
diff --git a/SOURCES/0129-Export-all-variables-from-the-initial-context-when-c.patch b/SOURCES/0129-Export-all-variables-from-the-initial-context-when-c.patch
deleted file mode 100644
index bfe3165..0000000
--- a/SOURCES/0129-Export-all-variables-from-the-initial-context-when-c.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Tue, 22 Jan 2019 15:40:25 +0100
-Subject: [PATCH] Export all variables from the initial context when creating a
- submenu
-
-When a submenu is created, only the exported variables are copied to the
-new menu context. But we want the variables to be global, so export lets
-export all variables to the new created submenu.
-
-Also, don't unset the default variable when a new submenu is created.
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/normal/context.c | 2 +-
- grub-core/normal/menu.c    | 2 --
- 2 files changed, 1 insertion(+), 3 deletions(-)
-
-diff --git a/grub-core/normal/context.c b/grub-core/normal/context.c
-index ee53d4a68e5..87edd254c44 100644
---- a/grub-core/normal/context.c
-+++ b/grub-core/normal/context.c
-@@ -99,7 +99,7 @@ grub_env_new_context (int export_all)
- grub_err_t
- grub_env_context_open (void)
- {
--  return grub_env_new_context (0);
-+  return grub_env_new_context (1);
- }
- 
- int grub_extractor_level = 0;
-diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
-index ea714d27176..d4832f17699 100644
---- a/grub-core/normal/menu.c
-+++ b/grub-core/normal/menu.c
-@@ -375,8 +375,6 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
- 
-   if (ptr && ptr[0] && ptr[1])
-     grub_env_set ("default", ptr + 1);
--  else
--    grub_env_unset ("default");
- 
-   grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args);
- 
diff --git a/SOURCES/0129-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch b/SOURCES/0129-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch
new file mode 100644
index 0000000..7fef93e
--- /dev/null
+++ b/SOURCES/0129-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch
@@ -0,0 +1,47 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 2 Jun 2020 13:25:01 +0200
+Subject: [PATCH] http: Prepend prefix when the HTTP path is relative as done
+ in efi/http
+
+There are two different HTTP drivers that can be used when requesting an
+HTTP resource: the efi/http that uses the EFI_HTTP_PROTOCOL and the http
+that uses GRUB's HTTP and TCP/IP implementation.
+
+The efi/http driver appends a prefix that is defined in the variable
+http_path, but the http driver doesn't.
+
+So using this driver and attempting to fetch a resource using a relative
+path fails.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/net/http.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/net/http.c b/grub-core/net/http.c
+index b52b558d63..7f878b5615 100644
+--- a/grub-core/net/http.c
++++ b/grub-core/net/http.c
+@@ -501,13 +501,20 @@ http_open (struct grub_file *file, const char *filename)
+ {
+   grub_err_t err;
+   struct http_data *data;
++  const char *http_path;
+ 
+   data = grub_zalloc (sizeof (*data));
+   if (!data)
+     return grub_errno;
+   file->size = GRUB_FILE_SIZE_UNKNOWN;
+ 
+-  data->filename = grub_strdup (filename);
++  /* If path is relative, prepend http_path */
++  http_path = grub_env_get ("http_path");
++  if (http_path && filename[0] != '/')
++    data->filename = grub_xasprintf ("%s/%s", http_path, filename);
++  else
++    data->filename = grub_strdup (filename);
++
+   if (!data->filename)
+     {
+       grub_free (data);
diff --git a/SOURCES/0130-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch b/SOURCES/0130-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch
new file mode 100644
index 0000000..f3b10c1
--- /dev/null
+++ b/SOURCES/0130-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 16 Jan 2019 13:21:46 -0500
+Subject: [PATCH] Fix a missing return in efi-export-env and efi-load-env
+ commands
+
+Somewhere along the way this got mis-merged to include a return without
+a value.  Fix it up.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/commands/efi/env.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/grub-core/commands/efi/env.c b/grub-core/commands/efi/env.c
+index cbd13e03e8..977edb6b06 100644
+--- a/grub-core/commands/efi/env.c
++++ b/grub-core/commands/efi/env.c
+@@ -149,6 +149,8 @@ grub_efi_load_env(grub_command_t cmd __attribute__ ((unused)),
+ 
+   grub_envblk_iterate (envblk, NULL, set_var);
+   grub_free (envblk_s.buf);
++
++  return GRUB_ERR_NONE;
+ }
+ 
+ static grub_command_t export_cmd, loadenv_cmd;
diff --git a/SOURCES/0130-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch b/SOURCES/0130-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch
deleted file mode 100644
index 9788fd5..0000000
--- a/SOURCES/0130-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch
+++ /dev/null
@@ -1,165 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Christian Glombek <lorbus@fedoraproject.org>
-Date: Tue, 2 Apr 2019 16:22:21 +0200
-Subject: [PATCH] grub.d: Split out boot success reset from menu auto hide
- script
-
-Also rename fallback and menu auto hide script to be executed
-before and after boot success reset script.
-In menu auto hide script, rename last_boot_ok var to menu_hide_ok
----
- Makefile.util.def                                  | 14 ++++++++----
- ...allback_counting.in => 08_fallback_counting.in} | 14 ++++++------
- util/grub.d/10_reset_boot_success.in               | 25 ++++++++++++++++++++++
- .../{01_menu_auto_hide.in => 12_menu_auto_hide.in} | 23 +++++---------------
- 4 files changed, 48 insertions(+), 28 deletions(-)
- rename util/grub.d/{01_fallback_counting.in => 08_fallback_counting.in} (65%)
- create mode 100644 util/grub.d/10_reset_boot_success.in
- rename util/grub.d/{01_menu_auto_hide.in => 12_menu_auto_hide.in} (58%)
-
-diff --git a/Makefile.util.def b/Makefile.util.def
-index 2e5e05b25f1..11ab2d6fad1 100644
---- a/Makefile.util.def
-+++ b/Makefile.util.def
-@@ -459,14 +459,14 @@ script = {
- };
- 
- script = {
--  name = '01_fallback_counting';
--  common = util/grub.d/01_fallback_counting.in;
-+  name = '08_fallback_counting';
-+  common = util/grub.d/08_fallback_counting.in;
-   installdir = grubconf;
- };
- 
- script = {
--  name = '01_menu_auto_hide';
--  common = util/grub.d/01_menu_auto_hide.in;
-+  name = '12_menu_auto_hide';
-+  common = util/grub.d/12_menu_auto_hide.in;
-   installdir = grubconf;
- };
- 
-@@ -518,6 +518,12 @@ script = {
-   condition = COND_HOST_LINUX;
- };
- 
-+script = {
-+  name = '10_reset_boot_success';
-+  common = util/grub.d/10_reset_boot_success.in;
-+  installdir = grubconf;
-+};
-+
- script = {
-   name = '10_xnu';
-   common = util/grub.d/10_xnu.in;
-diff --git a/util/grub.d/01_fallback_counting.in b/util/grub.d/08_fallback_counting.in
-similarity index 65%
-rename from util/grub.d/01_fallback_counting.in
-rename to util/grub.d/08_fallback_counting.in
-index be0e770ea82..2e2c3ff7d31 100644
---- a/util/grub.d/01_fallback_counting.in
-+++ b/util/grub.d/08_fallback_counting.in
-@@ -1,15 +1,17 @@
- #! /bin/sh -e
--
--# Boot Counting
-+# Fallback Countdown
-+#
-+# This snippet depends on 10_reset_boot_success and needs to be kept in sync.
-+#
- # The boot_counter env var can be used to count down boot attempts after an
--# OSTree upgrade and choose the rollback deployment when 0 is reached.  Both
--# boot_counter and boot_success need to be (re-)set from userspace.
-+# OSTree upgrade and choose the rollback deployment when 0 is reached.
-+# Both boot_counter=X and boot_success=1 need to be set from userspace.
- cat << EOF
- insmod increment
- # Check if boot_counter exists and boot_success=0 to activate this behaviour.
- if [ -n "\${boot_counter}" -a "\${boot_success}" = "0" ]; then
--  # if countdown has ended, choose to boot rollback deployment (default=1 on
--  # OSTree-based systems)
-+  # if countdown has ended, choose to boot rollback deployment,
-+  # i.e. default=1 on OSTree-based systems.
-   if  [ "\${boot_counter}" = "0" -o "\${boot_counter}" = "-1" ]; then
-     set default=1
-     set boot_counter=-1
-diff --git a/util/grub.d/10_reset_boot_success.in b/util/grub.d/10_reset_boot_success.in
-new file mode 100644
-index 00000000000..6c88d933dde
---- /dev/null
-+++ b/util/grub.d/10_reset_boot_success.in
-@@ -0,0 +1,25 @@
-+#! /bin/sh -e
-+# Reset Boot Success
-+#
-+# The 08_fallback_counting and 12_menu_auto_hide snippets rely on this one
-+# and need to be kept in sync.
-+#
-+# The boot_success var needs to be set to 1 from userspace to mark a boot successful.
-+cat << EOF
-+insmod increment
-+# Hiding the menu is ok if last boot was ok or if this is a first boot attempt to boot the entry
-+if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then
-+  set menu_hide_ok=1
-+else
-+  set menu_hide_ok=0 
-+fi
-+# Reset boot_indeterminate after a successful boot, increment otherwise
-+if [ "\${boot_success}" = "1" ] ; then
-+  set boot_indeterminate=0
-+else
-+  increment boot_indeterminate
-+fi
-+# Reset boot_success for current boot 
-+set boot_success=0
-+save_env boot_success boot_indeterminate
-+EOF
-diff --git a/util/grub.d/01_menu_auto_hide.in b/util/grub.d/12_menu_auto_hide.in
-similarity index 58%
-rename from util/grub.d/01_menu_auto_hide.in
-rename to util/grub.d/12_menu_auto_hide.in
-index ad175870a54..6a7c0fa0d43 100644
---- a/util/grub.d/01_menu_auto_hide.in
-+++ b/util/grub.d/12_menu_auto_hide.in
-@@ -1,5 +1,8 @@
- #! /bin/sh
--
-+# Menu Auto Hide
-+#
-+# This snippet depends on 10_reset_boot_success and needs to be kept in sync.
-+#
- # Disable / skip generating menu-auto-hide config parts on serial terminals
- for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do
-   case "$x" in
-@@ -10,29 +13,13 @@ for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do
- done
- 
- cat << EOF
--if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then
--  set last_boot_ok=1
--else
--  set last_boot_ok=0
--fi
--
--# Reset boot_indeterminate after a successful boot
--if [ "\${boot_success}" = "1" ] ; then
--  set boot_indeterminate=0
--# Avoid boot_indeterminate causing the menu to be hidden more then once
--elif [ "\${boot_indeterminate}" = "1" ]; then
--  set boot_indeterminate=2
--fi
--set boot_success=0
--save_env boot_success boot_indeterminate
--
- if [ x\$feature_timeout_style = xy ] ; then
-   if [ "\${menu_show_once}" ]; then
-     unset menu_show_once
-     save_env menu_show_once
-     set timeout_style=menu
-     set timeout=60
--  elif [ "\${menu_auto_hide}" -a "\${last_boot_ok}" = "1" ]; then
-+  elif [ "\${menu_auto_hide}" -a "\${menu_hide_ok}" = "1" ]; then
-     set orig_timeout_style=\${timeout_style}
-     set orig_timeout=\${timeout}
-     if [ "\${fastboot}" = "1" ]; then
diff --git a/SOURCES/0131-Fix-systemctl-kexec-exit-status-check.patch b/SOURCES/0131-Fix-systemctl-kexec-exit-status-check.patch
deleted file mode 100644
index 74ecedc..0000000
--- a/SOURCES/0131-Fix-systemctl-kexec-exit-status-check.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Tue, 9 Apr 2019 12:30:38 +0200
-Subject: [PATCH] Fix systemctl kexec exit status check
-
-There's always an error printed even when the systemctl kexec command does
-succeed. That's because systemctl executes it asynchronously, but the emu
-loader seems to expect it to be synchronous and that should never return.
-
-Also, it's wrong to test if kexecute == 1 since we already know that's the
-case or otherwise the function wouldn't had called grub_fatal() earlier.
-
-Finally, systemctl kexec failing shouldn't be a fatal error since the emu
-loader fallbacks to executing the kexec command in case of a failure.
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/loader/emu/linux.c | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c
-index fda9e00d24c..5b85b225eed 100644
---- a/grub-core/loader/emu/linux.c
-+++ b/grub-core/loader/emu/linux.c
-@@ -71,8 +71,10 @@ grub_linux_boot (void)
- 		(kexecute==1) ? "do-or-die" : "just-in-case");
-   rc = grub_util_exec (systemctl);
- 
--  if (kexecute == 1)
--    grub_fatal (N_("Error trying to perform 'systemctl kexec'"));
-+  if (rc == GRUB_ERR_NONE)
-+    return rc;
-+
-+  grub_error (rc, N_("Error trying to perform 'systemctl kexec'"));
- 
-   /* need to check read-only root before resetting hard!? */
-   grub_printf("Performing 'kexec -e'");
diff --git a/SOURCES/0131-efi-dhcp-fix-some-allocation-error-checking.patch b/SOURCES/0131-efi-dhcp-fix-some-allocation-error-checking.patch
new file mode 100644
index 0000000..90e7a34
--- /dev/null
+++ b/SOURCES/0131-efi-dhcp-fix-some-allocation-error-checking.patch
@@ -0,0 +1,37 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Sun, 19 Jul 2020 17:11:06 -0400
+Subject: [PATCH] efi+dhcp: fix some allocation error checking.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/efi/dhcp.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c
+index dbef63d8c0..e5c79b748b 100644
+--- a/grub-core/net/efi/dhcp.c
++++ b/grub-core/net/efi/dhcp.c
+@@ -80,7 +80,7 @@ grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packe
+   if (status != GRUB_EFI_BUFFER_TOO_SMALL)
+     return NULL;
+ 
+-  option_list = grub_malloc (option_count * sizeof(*option_list));
++  option_list = grub_calloc (option_count, sizeof(*option_list));
+   if (!option_list)
+     return NULL;
+ 
+@@ -360,8 +360,11 @@ grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)),
+ 
+ 	if (status == GRUB_EFI_BUFFER_TOO_SMALL && count)
+ 	  {
+-	    options = grub_malloc (count * sizeof(*options));
+-	    status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options);
++	    options = grub_calloc (count, sizeof(*options));
++	    if (options)
++	      status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options);
++	    else
++	      status = GRUB_EFI_OUT_OF_RESOURCES;
+ 	  }
+ 
+ 	if (status != GRUB_EFI_SUCCESS)
diff --git a/SOURCES/0132-Print-grub-emu-linux-loader-messages-as-debug.patch b/SOURCES/0132-Print-grub-emu-linux-loader-messages-as-debug.patch
deleted file mode 100644
index a49ec44..0000000
--- a/SOURCES/0132-Print-grub-emu-linux-loader-messages-as-debug.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Tue, 9 Apr 2019 12:42:37 +0200
-Subject: [PATCH] Print grub-emu linux loader messages as debug
-
-They just polute the output and should better be debug messages instead.
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/loader/emu/linux.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c
-index 5b85b225eed..22ab6af1727 100644
---- a/grub-core/loader/emu/linux.c
-+++ b/grub-core/loader/emu/linux.c
-@@ -50,7 +50,7 @@ grub_linux_boot (void)
-     initrd_param = grub_xasprintf("%s", "");
-   }
- 
--  grub_printf("%serforming 'kexec -l %s %s %s'\n",
-+  grub_dprintf ("linux", "%serforming 'kexec -l %s %s %s'\n",
- 	(kexecute) ? "P" : "Not p",
- 	kernel_path, initrd_param, boot_cmdline);
- 
-@@ -67,7 +67,7 @@ grub_linux_boot (void)
-   if (kexecute < 1)
-     grub_fatal (N_("Use '"PACKAGE"-emu --kexec' to force a system restart."));
- 
--  grub_printf("Performing 'systemctl kexec' (%s) ",
-+  grub_dprintf ("linux", "Performing 'systemctl kexec' (%s) ",
- 		(kexecute==1) ? "do-or-die" : "just-in-case");
-   rc = grub_util_exec (systemctl);
- 
diff --git a/SOURCES/0132-efi-http-fix-some-allocation-error-checking.patch b/SOURCES/0132-efi-http-fix-some-allocation-error-checking.patch
new file mode 100644
index 0000000..149ada8
--- /dev/null
+++ b/SOURCES/0132-efi-http-fix-some-allocation-error-checking.patch
@@ -0,0 +1,39 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Sun, 19 Jul 2020 17:14:15 -0400
+Subject: [PATCH] efi+http: fix some allocation error checking.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/efi/http.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
+index fc8cb25ae0..26647a50fa 100644
+--- a/grub-core/net/efi/http.c
++++ b/grub-core/net/efi/http.c
+@@ -412,8 +412,8 @@ grub_efihttp_open (struct grub_efi_net_device *dev,
+ 		  int type)
+ {
+   grub_err_t err;
+-  grub_off_t size;
+-  char *buf;
++  grub_off_t size = 0;
++  char *buf = NULL;
+   char *file_name = NULL;
+   const char *http_path;
+ 
+@@ -441,8 +441,11 @@ grub_efihttp_open (struct grub_efi_net_device *dev,
+       return err;
+     }
+ 
+-  buf = grub_malloc (size);
+-  efihttp_read (dev, buf, size);
++  if (size)
++    {
++      buf = grub_malloc (size);
++      efihttp_read (dev, buf, size);
++    }
+ 
+   file->size = size;
+   file->data = buf;
diff --git a/SOURCES/0133-Don-t-assume-that-boot-commands-will-only-return-on-.patch b/SOURCES/0133-Don-t-assume-that-boot-commands-will-only-return-on-.patch
deleted file mode 100644
index 418a1ef..0000000
--- a/SOURCES/0133-Don-t-assume-that-boot-commands-will-only-return-on-.patch
+++ /dev/null
@@ -1,97 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Tue, 9 Apr 2019 13:12:40 +0200
-Subject: [PATCH] Don't assume that boot commands will only return on fail
-
-While it's true that for most loaders the boot command never returns, it
-may be the case that it does. For example the GRUB emulator boot command
-calls to systemctl kexec which in turn does an asynchonous call to kexec.
-
-So in this case GRUB will wrongly assume that the boot command fails and
-print a "Failed to boot both default and fallback entries" even when the
-kexec call later succeeds.
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/normal/menu.c | 23 +++++++++++++----------
- 1 file changed, 13 insertions(+), 10 deletions(-)
-
-diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
-index d4832f17699..14ceb9bb060 100644
---- a/grub-core/normal/menu.c
-+++ b/grub-core/normal/menu.c
-@@ -285,7 +285,7 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name)
- }
- 
- /* Run a menu entry.  */
--static void
-+static grub_err_t
- grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
- {
-   grub_err_t err = GRUB_ERR_NONE;
-@@ -302,7 +302,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
-     {
-       grub_print_error ();
-       grub_errno = GRUB_ERR_NONE;
--      return;
-+      return grub_errno;
-     }
- 
-   errs_before = grub_err_printed_errors;
-@@ -315,7 +315,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
-       grub_env_context_open ();
-       menu = grub_zalloc (sizeof (*menu));
-       if (! menu)
--	return;
-+	return grub_errno;
-       grub_env_set_menu (menu);
-       if (auto_boot)
- 	grub_env_set ("timeout", "0");
-@@ -385,7 +385,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
- 
-   if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
-     /* Implicit execution of boot, only if something is loaded.  */
--    grub_command_execute ("boot", 0, 0);
-+    err = grub_command_execute ("boot", 0, 0);
- 
-   if (errs_before != grub_err_printed_errors)
-     grub_wait_after_message ();
-@@ -408,6 +408,8 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
-   else
-     grub_env_unset ("default");
-   grub_env_unset ("timeout");
-+
-+  return err;
- }
- 
- /* Execute ENTRY from the menu MENU, falling back to entries specified
-@@ -422,10 +424,13 @@ grub_menu_execute_with_fallback (grub_menu_t menu,
- 				 void *callback_data)
- {
-   int fallback_entry;
-+  grub_err_t err;
- 
-   callback->notify_booting (entry, callback_data);
- 
--  grub_menu_execute_entry (entry, 1);
-+  err = grub_menu_execute_entry (entry, 1);
-+  if (err == GRUB_ERR_NONE)
-+    return;
- 
-   /* Deal with fallback entries.  */
-   while ((fallback_entry = get_and_remove_first_entry_number (menu, "fallback"))
-@@ -436,11 +441,9 @@ grub_menu_execute_with_fallback (grub_menu_t menu,
- 
-       entry = grub_menu_get_entry (menu, fallback_entry);
-       callback->notify_fallback (entry, callback_data);
--      grub_menu_execute_entry (entry, 1);
--      /* If the function call to execute the entry returns at all, then this is
--	 taken to indicate a boot failure.  For menu entries that do something
--	 other than actually boot an operating system, this could assume
--	 incorrectly that something failed.  */
-+      err = grub_menu_execute_entry (entry, 1);
-+      if (err == GRUB_ERR_NONE)
-+        return;
-     }
- 
-   if (!autobooted)
diff --git a/SOURCES/0133-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch b/SOURCES/0133-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch
new file mode 100644
index 0000000..6413eb6
--- /dev/null
+++ b/SOURCES/0133-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch
@@ -0,0 +1,127 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Sun, 19 Jul 2020 17:27:00 -0400
+Subject: [PATCH] efi/ip[46]_config.c: fix some potential allocation overflows
+
+In theory all of this data comes from the firmware stack and it should
+be safe, but it's better to be paranoid.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/efi/ip4_config.c | 25 ++++++++++++++++++-------
+ grub-core/net/efi/ip6_config.c | 13 ++++++++++---
+ 2 files changed, 28 insertions(+), 10 deletions(-)
+
+diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c
+index 313c818b18..9725e928f7 100644
+--- a/grub-core/net/efi/ip4_config.c
++++ b/grub-core/net/efi/ip4_config.c
+@@ -4,15 +4,20 @@
+ #include <grub/misc.h>
+ #include <grub/net/efi.h>
+ #include <grub/charset.h>
++#include <grub/safemath.h>
+ 
+ char *
+ grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address)
+ {
+   char *hw_addr, *p;
+-  int sz, s;
+-  int i;
++  grub_size_t sz, s, i;
+ 
+-  sz = (int)hw_address_size * (sizeof ("XX:") - 1) + 1;
++  if (grub_mul (hw_address_size, sizeof ("XX:") - 1, &sz) ||
++      grub_add (sz, 1, &sz))
++    {
++      grub_errno = GRUB_ERR_OUT_OF_RANGE;
++      return NULL;
++    }
+ 
+   hw_addr = grub_malloc (sz);
+   if (!hw_addr)
+@@ -20,7 +25,7 @@ grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_a
+ 
+   p = hw_addr;
+   s = sz;
+-  for (i = 0; i < (int)hw_address_size; i++)
++  for (i = 0; i < hw_address_size; i++)
+     {
+       grub_snprintf (p, sz, "%02x:", hw_address[i]);
+       p +=  sizeof ("XX:") - 1;
+@@ -238,14 +243,20 @@ grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev)
+ {
+   grub_efi_ip4_config2_interface_info_t *interface_info;
+   char **ret;
+-  int i, id;
++  int id;
++  grub_size_t i, nmemb;
+ 
+   interface_info = efi_ip4_config_interface_info (dev->ip4_config);
+   if (!interface_info)
+     return NULL;
+ 
+-  ret = grub_malloc (sizeof (*ret) * (interface_info->route_table_size + 1));
++  if (grub_add (interface_info->route_table_size, 1, &nmemb))
++    {
++      grub_errno = GRUB_ERR_OUT_OF_RANGE;
++      return NULL;
++    }
+ 
++  ret = grub_calloc (nmemb, sizeof (*ret));
+   if (!ret)
+     {
+       grub_free (interface_info);
+@@ -253,7 +264,7 @@ grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev)
+     }
+ 
+   id = 0;
+-  for (i = 0; i < (int)interface_info->route_table_size; i++)
++  for (i = 0; i < interface_info->route_table_size; i++)
+     {
+       char *subnet, *gateway, *mask;
+       grub_uint32_t u32_subnet, u32_gateway;
+diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c
+index 017c4d05bc..a46f6f9b68 100644
+--- a/grub-core/net/efi/ip6_config.c
++++ b/grub-core/net/efi/ip6_config.c
+@@ -3,6 +3,7 @@
+ #include <grub/misc.h>
+ #include <grub/net/efi.h>
+ #include <grub/charset.h>
++#include <grub/safemath.h>
+ 
+ char *
+ grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address)
+@@ -228,14 +229,20 @@ grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev)
+ {
+   grub_efi_ip6_config_interface_info_t *interface_info;
+   char **ret;
+-  int i, id;
++  int id;
++  grub_size_t i, nmemb;
+ 
+   interface_info = efi_ip6_config_interface_info (dev->ip6_config);
+   if (!interface_info)
+     return NULL;
+ 
+-  ret = grub_malloc (sizeof (*ret) * (interface_info->route_count + 1));
++  if (grub_add (interface_info->route_count, 1, &nmemb))
++    {
++      grub_errno = GRUB_ERR_OUT_OF_RANGE;
++      return NULL;
++    }
+ 
++  ret = grub_calloc (nmemb, sizeof (*ret));
+   if (!ret)
+     {
+       grub_free (interface_info);
+@@ -243,7 +250,7 @@ grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev)
+     }
+ 
+   id = 0;
+-  for (i = 0; i < (int)interface_info->route_count ; i++)
++  for (i = 0; i < interface_info->route_count ; i++)
+     {
+       char *gateway, *destination;
+       grub_uint64_t u64_gateway[2];
diff --git a/SOURCES/0134-Fix-undefined-references-for-fdt-when-building-with-.patch b/SOURCES/0134-Fix-undefined-references-for-fdt-when-building-with-.patch
deleted file mode 100644
index 9065da8..0000000
--- a/SOURCES/0134-Fix-undefined-references-for-fdt-when-building-with-.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Wed, 1 May 2019 00:36:19 +0200
-Subject: [PATCH] Fix undefined references for fdt when building with platform
- emu
-
-The fdt module isn't build for this platform, so adding the declarations
-with platform emu will lead to the following undefined reference errors:
-
-BUILDSTDERR: /usr/bin/ld: grub_emu_lite-symlist.o:(.data+0x500): undefined reference to `grub_fdt_add_subnode'
-BUILDSTDERR: /usr/bin/ld: grub_emu_lite-symlist.o:(.data+0x518): undefined reference to `grub_fdt_check_header'
-BUILDSTDERR: /usr/bin/ld: grub_emu_lite-symlist.o:(.data+0x530): undefined reference to `grub_fdt_check_header_nosize'
-BUILDSTDERR: /usr/bin/ld: grub_emu_lite-symlist.o:(.data+0x548): undefined reference to `grub_fdt_create_empty_tree'
-BUILDSTDERR: /usr/bin/ld: grub_emu_lite-symlist.o:(.data+0x560): undefined reference to `grub_fdt_find_subnode'
-BUILDSTDERR: /usr/bin/ld: grub_emu_lite-symlist.o:(.data+0x578): undefined reference to `grub_fdt_first_node'
-BUILDSTDERR: /usr/bin/ld: grub_emu_lite-symlist.o:(.data+0x590): undefined reference to `grub_fdt_get_nodename'
-BUILDSTDERR: /usr/bin/ld: grub_emu_lite-symlist.o:(.data+0x5a8): undefined reference to `grub_fdt_get_prop'
-BUILDSTDERR: /usr/bin/ld: grub_emu_lite-symlist.o:(.data+0x5c0): undefined reference to `grub_fdt_next_node'
-BUILDSTDERR: /usr/bin/ld: grub_emu_lite-symlist.o:(.data+0x5d8): undefined reference to `grub_fdt_set_prop'
-BUILDSTDERR: collect2: error: ld returned 1 exit status
-BUILDSTDERR: make[1]: *** [Makefile:27093: grub-emu-lite] Error 1
-BUILDSTDERR: make[1]: *** Waiting for unfinished jobs....
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- include/grub/fdt.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/include/grub/fdt.h b/include/grub/fdt.h
-index 22b7c5463fc..2041341fd68 100644
---- a/include/grub/fdt.h
-+++ b/include/grub/fdt.h
-@@ -19,7 +19,7 @@
- #ifndef GRUB_FDT_HEADER
- #define GRUB_FDT_HEADER	1
- 
--#if defined(__arm__) || defined(__aarch64__)
-+#if !defined(GRUB_MACHINE_EMU) && (defined(__arm__) || defined(__aarch64__))
- 
- #include <grub/types.h>
- #include <grub/symbol.h>
diff --git a/SOURCES/0134-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch b/SOURCES/0134-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch
new file mode 100644
index 0000000..8e63d1d
--- /dev/null
+++ b/SOURCES/0134-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch
@@ -0,0 +1,49 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Fri, 24 Jul 2020 17:18:09 +0100
+Subject: [PATCH] efilinux: Fix integer overflows in grub_cmd_initrd
+
+These could be triggered by an extremely large number of arguments to
+the initrd command on 32-bit architectures, or a crafted filesystem with
+very large files on any architecture.
+
+Signed-off-by: Colin Watson <cjwatson@debian.org>
+---
+ grub-core/loader/i386/efi/linux.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 15d40d6e35..f992ceeef2 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -28,6 +28,8 @@
+ #include <grub/efi/efi.h>
+ #include <grub/efi/linux.h>
+ #include <grub/cpu/efi/memory.h>
++#include <grub/tpm.h>
++#include <grub/safemath.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -206,7 +208,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  files = grub_zalloc (argc * sizeof (files[0]));
++  files = grub_calloc (argc, sizeof (files[0]));
+   if (!files)
+     goto fail;
+ 
+@@ -216,7 +218,11 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+       if (! files[i])
+         goto fail;
+       nfiles++;
+-      size += ALIGN_UP (grub_file_size (files[i]), 4);
++      if (grub_add (size, ALIGN_UP (grub_file_size (files[i]), 4), &size))
++	{
++	  grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
++	  goto fail;
++	}
+     }
+ 
+   initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
diff --git a/SOURCES/0135-Do-better-in-bootstrap.conf.patch b/SOURCES/0135-Do-better-in-bootstrap.conf.patch
deleted file mode 100644
index ec9d8ec..0000000
--- a/SOURCES/0135-Do-better-in-bootstrap.conf.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 29 Jul 2019 10:58:52 -0400
-Subject: [PATCH] Do better in bootstrap.conf
-
----
- bootstrap.conf | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
-diff --git a/bootstrap.conf b/bootstrap.conf
-index 186be9c48ce..9259526e891 100644
---- a/bootstrap.conf
-+++ b/bootstrap.conf
-@@ -16,7 +16,13 @@
- # along with this program.  If not, see <https://www.gnu.org/licenses/>.
- 
- 
--GNULIB_REVISION=d271f868a8df9bbec29049d01e056481b7a1a263
-+# GNULIB_REVISION=d271f868a8df9bbec29049d01e056481b7a1a263
-+if [[ -z "${GNULIB_REVISION}" ]] ;then
-+  GNULIB_REVISION=fixes
-+fi
-+if [[ -z "${GNULIB_URL}" ]] ;then
-+  GNULIB_URL=https://github.com/rhboot/gnulib.git
-+fi
- 
- # gnulib modules used by this package.
- # mbswidth is used by gnulib-fix-width.diff's changes to argp rather than
diff --git a/SOURCES/0135-linuxefi-fail-kernel-validation-without-shim-protoco.patch b/SOURCES/0135-linuxefi-fail-kernel-validation-without-shim-protoco.patch
new file mode 100644
index 0000000..828fe16
--- /dev/null
+++ b/SOURCES/0135-linuxefi-fail-kernel-validation-without-shim-protoco.patch
@@ -0,0 +1,130 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dimitri John Ledkov <xnox@ubuntu.com>
+Date: Wed, 22 Jul 2020 11:31:43 +0100
+Subject: [PATCH] linuxefi: fail kernel validation without shim protocol.
+
+If certificates that signed grub are installed into db, grub can be
+booted directly. It will then boot any kernel without signature
+validation. The booted kernel will think it was booted in secureboot
+mode and will implement lockdown, yet it could have been tampered.
+
+This version of the patch skips calling verification, when booted
+without secureboot. And is indented with gnu ident.
+
+CVE-2020-15705
+
+Reported-by: Mathieu Trudel-Lapierre <cyphermox@ubuntu.com>
+Signed-off-by: Dimitri John Ledkov <xnox@ubuntu.com>
+---
+ grub-core/loader/arm64/linux.c     | 13 +++++++++----
+ grub-core/loader/efi/chainloader.c |  1 +
+ grub-core/loader/efi/linux.c       |  1 +
+ grub-core/loader/i386/efi/linux.c  | 17 +++++++++++------
+ 4 files changed, 22 insertions(+), 10 deletions(-)
+
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index 70a0075ec5..47f8cf0d84 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -34,6 +34,7 @@
+ #include <grub/i18n.h>
+ #include <grub/lib/cmdline.h>
+ #include <grub/verify.h>
++#include <grub/efi/sb.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -363,11 +364,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
+ 
+-  rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size);
+-  if (rc < 0)
++  if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED)
+     {
+-      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
+-      goto fail;
++      rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size);
++      if (rc <= 0)
++	{
++	  grub_error (GRUB_ERR_INVALID_COMMAND,
++		      N_("%s has invalid signature"), argv[0]);
++	  goto fail;
++	}
+     }
+ 
+   pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset);
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index ac8dfd40c6..d41e8ea14a 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -1084,6 +1084,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+ 
+       return 0;
+     }
++  // -1 fall-through to fail
+ 
+ fail:
+   if (dev)
+diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
+index e8b9ecb17f..9260731c10 100644
+--- a/grub-core/loader/efi/linux.c
++++ b/grub-core/loader/efi/linux.c
+@@ -33,6 +33,7 @@ struct grub_efi_shim_lock
+ };
+ typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
+ 
++// Returns 1 on success, -1 on error, 0 when not available
+ int
+ grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
+ {
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index f992ceeef2..3cf0f9b330 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -30,6 +30,7 @@
+ #include <grub/cpu/efi/memory.h>
+ #include <grub/tpm.h>
+ #include <grub/safemath.h>
++#include <grub/efi/sb.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -101,7 +102,7 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
+ 
+       pages = BYTES_TO_PAGES(size);
+       grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n",
+-		    pages, (void *)max);
++		    (unsigned long)pages, (void *)(unsigned long)max);
+ 
+       prev_max = max;
+       addr = grub_efi_allocate_pages_real (max, pages,
+@@ -307,12 +308,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  rc = grub_linuxefi_secure_validate (kernel, filelen);
+-  if (rc < 0)
++  if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED)
+     {
+-      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"),
+-		  argv[0]);
+-      goto fail;
++      rc = grub_linuxefi_secure_validate (kernel, filelen);
++      if (rc <= 0)
++	{
++	  grub_error (GRUB_ERR_INVALID_COMMAND,
++		      N_("%s has invalid signature"), argv[0]);
++	  goto fail;
++	}
+     }
+ 
+   lh = (struct linux_i386_kernel_header *)kernel;
+@@ -386,6 +390,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201);
+   grub_dprintf ("linux", "copying %lu bytes from %p to %p\n",
++		(unsigned long)
+ 		MIN((grub_size_t)0x202+setup_header_end_offset,
+ 		    sizeof (*params)) - 0x1f1,
+ 		(grub_uint8_t *)kernel + 0x1f1,
diff --git a/SOURCES/0136-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch b/SOURCES/0136-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch
new file mode 100644
index 0000000..f20f5c7
--- /dev/null
+++ b/SOURCES/0136-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch
@@ -0,0 +1,37 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 20 Jul 2020 12:24:02 -0400
+Subject: [PATCH] Fix const char ** pointers in grub-core/net/bootp.c
+
+This will need to get folded back in the right place on the next rebase,
+but it's before "Make grub_strtol() "end" pointers have safer const
+qualifiers" currently, so for now I'm leaving it here instead of merging
+it back with the original patch.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/bootp.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
+index 8fb8918ae7..7baf3540c8 100644
+--- a/grub-core/net/bootp.c
++++ b/grub-core/net/bootp.c
+@@ -329,7 +329,7 @@ grub_net_configure_by_dhcp_ack (const char *name,
+   struct grub_net_network_level_interface *inter;
+   int mask = -1;
+   char server_ip[sizeof ("xxx.xxx.xxx.xxx")];
+-  const grub_uint8_t *opt;
++  const char *opt;
+   grub_uint8_t opt_len, overload = 0;
+   const char *boot_file = 0, *server_name = 0;
+   grub_size_t boot_file_len, server_name_len;
+@@ -505,7 +505,7 @@ grub_net_configure_by_dhcp_ack (const char *name,
+   if (opt && opt_len)
+     {
+       grub_env_set_net_property (name, "vendor_class_identifier", (const char *) opt, opt_len);
+-      if (opt && grub_strcmp (opt, "HTTPClient") == 0)
++      if (opt && grub_strcmp ((char *)opt, "HTTPClient") == 0)
+         {
+           char *proto, *ip, *pa;
+ 
diff --git a/SOURCES/0136-Use-git-to-apply-gnulib-patches.patch b/SOURCES/0136-Use-git-to-apply-gnulib-patches.patch
deleted file mode 100644
index 7654648..0000000
--- a/SOURCES/0136-Use-git-to-apply-gnulib-patches.patch
+++ /dev/null
@@ -1,631 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 29 Jul 2019 11:21:27 -0400
-Subject: [PATCH] Use git to apply gnulib patches.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- bootstrap.conf                                     |   6 -
- conf/Makefile.extra-dist                           |  10 -
- grub-core/lib/gnulib-patches/fix-base64.patch      |  21 --
- grub-core/lib/gnulib-patches/fix-null-deref.patch  |  13 --
- .../lib/gnulib-patches/fix-null-state-deref.patch  |  12 --
- .../gnulib-patches/fix-regcomp-uninit-token.patch  |  15 --
- .../gnulib-patches/fix-regexec-null-deref.patch    |  12 --
- .../gnulib-patches/fix-sign-compare-errors.patch   | 161 ---------------
- .../lib/gnulib-patches/fix-uninit-structure.patch  |  11 --
- .../lib/gnulib-patches/fix-unused-value.patch      |  14 --
- grub-core/lib/gnulib-patches/fix-width.patch       | 217 ---------------------
- grub-core/lib/gnulib-patches/no-abort.patch        |  26 ---
- 12 files changed, 518 deletions(-)
- delete mode 100644 grub-core/lib/gnulib-patches/fix-base64.patch
- delete mode 100644 grub-core/lib/gnulib-patches/fix-null-deref.patch
- delete mode 100644 grub-core/lib/gnulib-patches/fix-null-state-deref.patch
- delete mode 100644 grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch
- delete mode 100644 grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch
- delete mode 100644 grub-core/lib/gnulib-patches/fix-sign-compare-errors.patch
- delete mode 100644 grub-core/lib/gnulib-patches/fix-uninit-structure.patch
- delete mode 100644 grub-core/lib/gnulib-patches/fix-unused-value.patch
- delete mode 100644 grub-core/lib/gnulib-patches/fix-width.patch
- delete mode 100644 grub-core/lib/gnulib-patches/no-abort.patch
-
-diff --git a/bootstrap.conf b/bootstrap.conf
-index 9259526e891..452f4d79b0d 100644
---- a/bootstrap.conf
-+++ b/bootstrap.conf
-@@ -85,12 +85,6 @@ cp -a INSTALL INSTALL.grub
- 
- bootstrap_post_import_hook () {
-   set -e
--  for patchname in fix-base64 fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \
--      fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width no-abort \
--      fix-sign-compare-errors; do
--    patch -d grub-core/lib/gnulib -p2 \
--      < "grub-core/lib/gnulib-patches/$patchname.patch"
--  done
-   for patchname in \
-       0001-Support-POTFILES-shell \
-       0002-Handle-gettext_printf-shell-function \
-diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist
-index ea58362b555..8ddf22e6c99 100644
---- a/conf/Makefile.extra-dist
-+++ b/conf/Makefile.extra-dist
-@@ -30,16 +30,6 @@ EXTRA_DIST += grub-core/gensymlist.sh
- EXTRA_DIST += grub-core/genemuinit.sh
- EXTRA_DIST += grub-core/genemuinitheader.sh
- 
--EXTRA_DIST += grub-core/lib/gnulib-patches/fix-base64.patch
--EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-deref.patch
--EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-state-deref.patch
--EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch
--EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch
--EXTRA_DIST += grub-core/lib/gnulib-patches/fix-uninit-structure.patch
--EXTRA_DIST += grub-core/lib/gnulib-patches/fix-unused-value.patch
--EXTRA_DIST += grub-core/lib/gnulib-patches/fix-width.patch
--EXTRA_DIST += grub-core/lib/gnulib-patches/no-abort.patch
--
- EXTRA_DIST += grub-core/lib/libgcrypt
- EXTRA_DIST += grub-core/lib/libgcrypt-grub/mpi/generic
- EXTRA_DIST += $(shell find $(top_srcdir)/include -name '*.h')
-diff --git a/grub-core/lib/gnulib-patches/fix-base64.patch b/grub-core/lib/gnulib-patches/fix-base64.patch
-deleted file mode 100644
-index 985db127971..00000000000
---- a/grub-core/lib/gnulib-patches/fix-base64.patch
-+++ /dev/null
-@@ -1,21 +0,0 @@
--diff --git a/lib/base64.h b/lib/base64.h
--index 9cd0183b8..185a2afa1 100644
----- a/lib/base64.h
--+++ b/lib/base64.h
--@@ -21,8 +21,14 @@
-- /* Get size_t. */
-- # include <stddef.h>
-- 
---/* Get bool. */
---# include <stdbool.h>
--+#ifndef GRUB_POSIX_BOOL_DEFINED
--+typedef enum { false = 0, true = 1 } bool;
--+#define GRUB_POSIX_BOOL_DEFINED 1
--+#endif
--+
--+#ifndef _GL_ATTRIBUTE_CONST
--+# define _GL_ATTRIBUTE_CONST /* empty */
--+#endif
-- 
-- # ifdef __cplusplus
-- extern "C" {
-diff --git a/grub-core/lib/gnulib-patches/fix-null-deref.patch b/grub-core/lib/gnulib-patches/fix-null-deref.patch
-deleted file mode 100644
-index 8fafa153a47..00000000000
---- a/grub-core/lib/gnulib-patches/fix-null-deref.patch
-+++ /dev/null
-@@ -1,13 +0,0 @@
--diff --git a/lib/argp-parse.c b/lib/argp-parse.c
--index 6dec57310..900adad54 100644
----- a/lib/argp-parse.c
--+++ b/lib/argp-parse.c
--@@ -940,7 +940,7 @@ weak_alias (__argp_parse, argp_parse)
-- void *
-- __argp_input (const struct argp *argp, const struct argp_state *state)
-- {
---  if (state)
--+  if (state && state->pstate)
--     {
--       struct group *group;
--       struct parser *parser = state->pstate;
-diff --git a/grub-core/lib/gnulib-patches/fix-null-state-deref.patch b/grub-core/lib/gnulib-patches/fix-null-state-deref.patch
-deleted file mode 100644
-index 813ec09c8a1..00000000000
---- a/grub-core/lib/gnulib-patches/fix-null-state-deref.patch
-+++ /dev/null
-@@ -1,12 +0,0 @@
----- a/lib/argp-help.c	2020-10-28 14:32:19.189215988 +0000
--+++ b/lib/argp-help.c	2020-10-28 14:38:21.204673940 +0000
--@@ -145,7 +145,8 @@
--       if (*(int *)((char *)upptr + up->uparams_offs) >= upptr->rmargin)
--         {
--           __argp_failure (state, 0, 0,
---                          dgettext (state->root_argp->argp_domain,
--+                          dgettext (state == NULL ? NULL
--+                                    : state->root_argp->argp_domain,
--                                     "\
-- ARGP_HELP_FMT: %s value is less than or equal to %s"),
--                           "rmargin", up->name);
-diff --git a/grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch b/grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch
-deleted file mode 100644
-index 02e06315dff..00000000000
---- a/grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch
-+++ /dev/null
-@@ -1,15 +0,0 @@
----- a/lib/regcomp.c	2020-11-24 17:06:08.159223858 +0000
--+++ b/lib/regcomp.c	2020-11-24 17:06:15.630253923 +0000
--@@ -3808,11 +3808,7 @@
-- create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
-- 	     re_token_type_t type)
-- {
---  re_token_t t;
---#if defined GCC_LINT || defined lint
---  memset (&t, 0, sizeof t);
---#endif
---  t.type = type;
--+  re_token_t t = { .type = type };
--   return create_token_tree (dfa, left, right, &t);
-- }
-- 
-diff --git a/grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch b/grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch
-deleted file mode 100644
-index db6dac9c9e3..00000000000
---- a/grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch
-+++ /dev/null
-@@ -1,12 +0,0 @@
----- a/lib/regexec.c	2020-10-21 14:25:35.310195912 +0000
--+++ b/lib/regexec.c	2020-11-05 10:55:09.621542984 +0000
--@@ -1692,6 +1692,9 @@
-- {
--   Idx top = mctx->state_log_top;
--
--+  if (mctx->state_log == NULL)
--+    return REG_NOERROR;
--+
--   if ((next_state_log_idx >= mctx->input.bufs_len
--        && mctx->input.bufs_len < mctx->input.len)
--       || (next_state_log_idx >= mctx->input.valid_len
-diff --git a/grub-core/lib/gnulib-patches/fix-sign-compare-errors.patch b/grub-core/lib/gnulib-patches/fix-sign-compare-errors.patch
-deleted file mode 100644
-index 479029c0565..00000000000
---- a/grub-core/lib/gnulib-patches/fix-sign-compare-errors.patch
-+++ /dev/null
-@@ -1,161 +0,0 @@
--diff --git a/lib/regcomp.c b/lib/regcomp.c
--index cc85f35ac58..361079d82d6 100644
----- a/lib/regcomp.c
--+++ b/lib/regcomp.c
--@@ -322,7 +322,7 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state,
-- 		*p++ = dfa->nodes[node].opr.c;
-- 	      memset (&state, '\0', sizeof (state));
-- 	      if (__mbrtowc (&wc, (const char *) buf, p - buf,
---			     &state) == p - buf
--+			     &state) == (size_t)(p - buf)
-- 		  && (__wcrtomb ((char *) buf, __towlower (wc), &state)
-- 		      != (size_t) -1))
-- 		re_set_fastmap (fastmap, false, buf[0]);
--@@ -3778,7 +3778,7 @@ fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax)
--       num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2)
-- 	     ? -2
-- 	     : num == -1
---	     ? c - '0'
--+	     ? (Idx)(c - '0')
-- 	     : MIN (RE_DUP_MAX + 1, num * 10 + c - '0'));
--     }
--   return num;
--diff --git a/lib/regex_internal.c b/lib/regex_internal.c
--index 9004ce809eb..193a1e3d332 100644
----- a/lib/regex_internal.c
--+++ b/lib/regex_internal.c
--@@ -233,7 +233,7 @@ build_wcs_buffer (re_string_t *pstr)
--       /* Apply the translation if we need.  */
--       if (__glibc_unlikely (pstr->trans != NULL))
-- 	{
---	  int i, ch;
--+	  unsigned int i, ch;
-- 
-- 	  for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
-- 	    {
--@@ -376,7 +376,7 @@ build_wcs_upper_buffer (re_string_t *pstr)
-- 	prev_st = pstr->cur_state;
-- 	if (__glibc_unlikely (pstr->trans != NULL))
-- 	  {
---	    int i, ch;
--+	    unsigned int i, ch;
-- 
-- 	    for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
-- 	      {
--@@ -754,7 +754,7 @@ re_string_reconstruct (re_string_t *pstr, Idx idx, int eflags)
-- 			  memset (&cur_state, 0, sizeof (cur_state));
-- 			  mbclen = __mbrtowc (&wc2, (const char *) pp, mlen,
-- 					      &cur_state);
---			  if (raw + offset - p <= mbclen
--+			  if ((size_t)(raw + offset - p) <= mbclen
-- 			      && mbclen < (size_t) -2)
-- 			    {
-- 			      memset (&pstr->cur_state, '\0',
--diff --git a/lib/regex_internal.h b/lib/regex_internal.h
--index 5462419b787..e0f8292395d 100644
----- a/lib/regex_internal.h
--+++ b/lib/regex_internal.h
--@@ -425,7 +425,7 @@ struct re_string_t
--   unsigned char offsets_needed;
--   unsigned char newline_anchor;
--   unsigned char word_ops_used;
---  int mb_cur_max;
--+  unsigned int mb_cur_max;
-- };
-- typedef struct re_string_t re_string_t;
-- 
--@@ -702,7 +702,7 @@ struct re_dfa_t
--   unsigned int is_utf8 : 1;
--   unsigned int map_notascii : 1;
--   unsigned int word_ops_used : 1;
---  int mb_cur_max;
--+  unsigned int mb_cur_max;
--   bitset_t word_char;
--   reg_syntax_t syntax;
--   Idx *subexp_map;
--diff --git a/lib/regexec.c b/lib/regexec.c
--index 0a7a27b772e..b57d4f9141d 100644
----- a/lib/regexec.c
--+++ b/lib/regexec.c
--@@ -443,7 +443,7 @@ re_search_stub (struct re_pattern_buffer *bufp, const char *string, Idx length,
--     {
--       if (ret_len)
-- 	{
---	  assert (pmatch[0].rm_so == start);
--+	  assert (pmatch[0].rm_so == (long)start);
-- 	  rval = pmatch[0].rm_eo - start;
-- 	}
--       else
--@@ -877,11 +877,11 @@ re_search_internal (const regex_t *preg, const char *string, Idx length,
-- 	    if (__glibc_unlikely (mctx.input.offsets_needed != 0))
-- 	      {
-- 		pmatch[reg_idx].rm_so =
---		  (pmatch[reg_idx].rm_so == mctx.input.valid_len
--+		  (pmatch[reg_idx].rm_so == (long)mctx.input.valid_len
-- 		   ? mctx.input.valid_raw_len
-- 		   : mctx.input.offsets[pmatch[reg_idx].rm_so]);
-- 		pmatch[reg_idx].rm_eo =
---		  (pmatch[reg_idx].rm_eo == mctx.input.valid_len
--+		  (pmatch[reg_idx].rm_eo == (long)mctx.input.valid_len
-- 		   ? mctx.input.valid_raw_len
-- 		   : mctx.input.offsets[pmatch[reg_idx].rm_eo]);
-- 	      }
--@@ -1418,11 +1418,11 @@ set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch,
--     }
--   memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
-- 
---  for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;)
--+  for (idx = pmatch[0].rm_so; idx <= (long)pmatch[0].rm_eo ;)
--     {
--       update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch);
-- 
---      if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node)
--+      if (idx == (long)pmatch[0].rm_eo && cur_node == mctx->last_node)
-- 	{
-- 	  Idx reg_idx;
-- 	  if (fs)
--@@ -1519,7 +1519,7 @@ update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
--       if (reg_num < nmatch)
-- 	{
-- 	  /* We are at the last node of this sub expression.  */
---	  if (pmatch[reg_num].rm_so < cur_idx)
--+	  if (pmatch[reg_num].rm_so < (long)cur_idx)
-- 	    {
-- 	      pmatch[reg_num].rm_eo = cur_idx;
-- 	      /* This is a non-empty match or we are not inside an optional
--@@ -2938,7 +2938,7 @@ check_arrival (re_match_context_t *mctx, state_array_t *path, Idx top_node,
--       mctx->state_log[str_idx] = cur_state;
--     }
-- 
---  for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;)
--+  for (null_cnt = 0; str_idx < last_str && null_cnt <= (long)mctx->max_mb_elem_len;)
--     {
--       re_node_set_empty (&next_nodes);
--       if (mctx->state_log[str_idx + 1])
--@@ -3718,7 +3718,7 @@ check_node_accept_bytes (const re_dfa_t *dfa, Idx node_idx,
-- 			 const re_string_t *input, Idx str_idx)
-- {
--   const re_token_t *node = dfa->nodes + node_idx;
---  int char_len, elem_len;
--+  unsigned int char_len, elem_len;
--   Idx i;
-- 
--   if (__glibc_unlikely (node->type == OP_UTF8_PERIOD))
--@@ -4066,7 +4066,7 @@ extend_buffers (re_match_context_t *mctx, int min_len)
--   /* Double the lengths of the buffers, but allocate at least MIN_LEN.  */
--   ret = re_string_realloc_buffers (pstr,
-- 				   MAX (min_len,
---					MIN (pstr->len, pstr->bufs_len * 2)));
--+					MIN ((long)pstr->len, pstr->bufs_len * 2)));
--   if (__glibc_unlikely (ret != REG_NOERROR))
--     return ret;
-- 
--@@ -4236,7 +4236,7 @@ match_ctx_add_entry (re_match_context_t *mctx, Idx node, Idx str_idx, Idx from,
--     = (from == to ? -1 : 0);
-- 
--   mctx->bkref_ents[mctx->nbkref_ents++].more = 0;
---  if (mctx->max_mb_elem_len < to - from)
--+  if (mctx->max_mb_elem_len < (long)(to - from))
--     mctx->max_mb_elem_len = to - from;
--   return REG_NOERROR;
-- }
-diff --git a/grub-core/lib/gnulib-patches/fix-uninit-structure.patch b/grub-core/lib/gnulib-patches/fix-uninit-structure.patch
-deleted file mode 100644
-index 7b4d9f67af4..00000000000
---- a/grub-core/lib/gnulib-patches/fix-uninit-structure.patch
-+++ /dev/null
-@@ -1,11 +0,0 @@
----- a/lib/regcomp.c	2020-10-22 13:49:06.770168928 +0000
--+++ b/lib/regcomp.c	2020-10-22 13:50:37.026528298 +0000
--@@ -3662,7 +3662,7 @@
--   Idx alloc = 0;
-- #endif /* not RE_ENABLE_I18N */
--   reg_errcode_t ret;
---  re_token_t br_token;
--+  re_token_t br_token = {0};
--   bin_tree_t *tree;
-- 
--   sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
-diff --git a/grub-core/lib/gnulib-patches/fix-unused-value.patch b/grub-core/lib/gnulib-patches/fix-unused-value.patch
-deleted file mode 100644
-index ba51f1bf223..00000000000
---- a/grub-core/lib/gnulib-patches/fix-unused-value.patch
-+++ /dev/null
-@@ -1,14 +0,0 @@
----- a/lib/regexec.c	2020-10-21 14:25:35.310195912 +0000
--+++ b/lib/regexec.c	2020-10-21 14:32:07.961765604 +0000
--@@ -828,7 +828,11 @@
-- 		    break;
-- 		  if (__glibc_unlikely (err != REG_NOMATCH))
-- 		    goto free_return;
--+#ifdef DEBUG
--+		  /* Only used for assertion below when DEBUG is set, otherwise
--+		     it will be over-written when we loop around.  */
-- 		  match_last = -1;
--+#endif
-- 		}
-- 	      else
-- 		break; /* We found a match.  */
-diff --git a/grub-core/lib/gnulib-patches/fix-width.patch b/grub-core/lib/gnulib-patches/fix-width.patch
-deleted file mode 100644
-index 0a208ad08b5..00000000000
---- a/grub-core/lib/gnulib-patches/fix-width.patch
-+++ /dev/null
-@@ -1,217 +0,0 @@
--diff --git a/lib/argp-fmtstream.c b/lib/argp-fmtstream.c
--index ba6a407f7..d0685b3d4 100644
----- a/lib/argp-fmtstream.c
--+++ b/lib/argp-fmtstream.c
--@@ -28,9 +28,11 @@
-- #include <errno.h>
-- #include <stdarg.h>
-- #include <ctype.h>
--+#include <wchar.h>
-- 
-- #include "argp-fmtstream.h"
-- #include "argp-namefrob.h"
--+#include "mbswidth.h"
-- 
-- #ifndef ARGP_FMTSTREAM_USE_LINEWRAP
-- 
--@@ -115,6 +117,51 @@ weak_alias (__argp_fmtstream_free, argp_fmtstream_free)
-- #endif
-- #endif
-- 
--+
--+/* Return the pointer to the first character that doesn't fit in l columns.  */
--+static inline const ptrdiff_t
--+add_width (const char *ptr, const char *end, size_t l)
--+{
--+  mbstate_t ps;
--+  const char *ptr0 = ptr;
--+
--+  memset (&ps, 0, sizeof (ps));
--+
--+  while (ptr < end)
--+    {
--+      wchar_t wc;
--+      size_t s, k;
--+
--+      s = mbrtowc (&wc, ptr, end - ptr, &ps);
--+      if (s == (size_t) -1)
--+	break;
--+      if (s == (size_t) -2)
--+	{
--+	  if (1 >= l)
--+	    break;
--+	  l--;
--+	  ptr++;
--+	  continue;
--+	}
--+
--+      if (wc == '\e' && ptr + 3 < end
--+	  && ptr[1] == '[' && (ptr[2] == '0' || ptr[2] == '1')
--+	  && ptr[3] == 'm')
--+	{
--+	  ptr += 4;
--+	  continue;
--+	}
--+
--+      k = wcwidth (wc);
--+
--+      if (k >= l)
--+	break;
--+      l -= k;
--+      ptr += s;
--+    }
--+  return ptr - ptr0;
--+}
--+
-- /* Process FS's buffer so that line wrapping is done from POINT_OFFS to the
--    end of its buffer.  This code is mostly from glibc stdio/linewrap.c.  */
-- void
--@@ -168,13 +215,15 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
--       if (!nl)
--         {
--           /* The buffer ends in a partial line.  */
--+          size_t display_width = mbsnwidth (buf, fs->p - buf,
--+                                            MBSW_STOP_AT_NUL);
-- 
---          if (fs->point_col + len < fs->rmargin)
--+          if (fs->point_col + display_width < fs->rmargin)
--             {
--               /* The remaining buffer text is a partial line and fits
--                  within the maximum line width.  Advance point for the
--                  characters to be written and stop scanning.  */
---              fs->point_col += len;
--+              fs->point_col += display_width;
--               break;
--             }
--           else
--@@ -182,14 +231,18 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
--                the end of the buffer.  */
--             nl = fs->p;
--         }
---      else if (fs->point_col + (nl - buf) < (ssize_t) fs->rmargin)
---        {
---          /* The buffer contains a full line that fits within the maximum
---             line width.  Reset point and scan the next line.  */
---          fs->point_col = 0;
---          buf = nl + 1;
---          continue;
---        }
--+      else
--+	{
--+	  size_t display_width = mbsnwidth (buf, nl - buf, MBSW_STOP_AT_NUL);
--+	  if (display_width < (ssize_t) fs->rmargin)
--+	    {
--+	      /* The buffer contains a full line that fits within the maximum
--+		 line width.  Reset point and scan the next line.  */
--+	      fs->point_col = 0;
--+	      buf = nl + 1;
--+	      continue;
--+	    }
--+	}
-- 
--       /* This line is too long.  */
--       r = fs->rmargin - 1;
--@@ -225,7 +278,7 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
--           char *p, *nextline;
--           int i;
-- 
---          p = buf + (r + 1 - fs->point_col);
--+          p = buf + add_width (buf, fs->p, (r + 1 - fs->point_col));
--           while (p >= buf && !isblank ((unsigned char) *p))
--             --p;
--           nextline = p + 1;     /* This will begin the next line.  */
--@@ -243,7 +296,7 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
--             {
--               /* A single word that is greater than the maximum line width.
--                  Oh well.  Put it on an overlong line by itself.  */
---              p = buf + (r + 1 - fs->point_col);
--+              p = buf + add_width (buf, fs->p, (r + 1 - fs->point_col));
--               /* Find the end of the long word.  */
--               if (p < nl)
--                 do
--@@ -277,7 +330,8 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
--               && fs->p > nextline)
--             {
--               /* The margin needs more blanks than we removed.  */
---              if (fs->end - fs->p > fs->wmargin + 1)
--+              if (mbsnwidth (fs->p, fs->end - fs->p, MBSW_STOP_AT_NUL)
--+                  > fs->wmargin + 1)
--                 /* Make some space for them.  */
--                 {
--                   size_t mv = fs->p - nextline;
--diff --git a/lib/argp-help.c b/lib/argp-help.c
--index e5375a0f0..5d8f451ec 100644
----- a/lib/argp-help.c
--+++ b/lib/argp-help.c
--@@ -51,6 +51,7 @@
-- #include "argp.h"
-- #include "argp-fmtstream.h"
-- #include "argp-namefrob.h"
--+#include "mbswidth.h"
-- 
-- #ifndef SIZE_MAX
-- # define SIZE_MAX ((size_t) -1)
--@@ -1432,7 +1433,7 @@ argp_args_usage (const struct argp *argp, const struct argp_state *state,
-- 
--       /* Manually do line wrapping so that it (probably) won't get wrapped at
--          any embedded spaces.  */
---      space (stream, 1 + nl - cp);
--+      space (stream, 1 + mbsnwidth (cp, nl - cp, MBSW_STOP_AT_NUL));
-- 
--       __argp_fmtstream_write (stream, cp, nl - cp);
--     }
--diff --git a/lib/mbswidth.c b/lib/mbswidth.c
--index 408a15e34..b3fb7f83a 100644
----- a/lib/mbswidth.c
--+++ b/lib/mbswidth.c
--@@ -38,6 +38,14 @@
-- /* Get INT_MAX.  */
-- #include <limits.h>
-- 
--+#ifndef FALLTHROUGH
--+# if __GNUC__ < 7
--+#  define FALLTHROUGH ((void) 0)
--+# else
--+#  define FALLTHROUGH __attribute__ ((__fallthrough__))
--+# endif
--+#endif
--+
-- /* Returns the number of columns needed to represent the multibyte
--    character string pointed to by STRING.  If a non-printable character
--    occurs, and MBSW_REJECT_UNPRINTABLE is specified, -1 is returned.
--@@ -90,6 +98,10 @@ mbsnwidth (const char *string, size_t nbytes, int flags)
--               p++;
--               width++;
--               break;
--+            case '\0':
--+              if (flags & MBSW_STOP_AT_NUL)
--+                return width;
--+              FALLTHROUGH;
--             default:
--               /* If we have a multibyte sequence, scan it up to its end.  */
--               {
--@@ -168,6 +180,9 @@ mbsnwidth (const char *string, size_t nbytes, int flags)
--     {
--       unsigned char c = (unsigned char) *p++;
-- 
--+      if (c == 0 && (flags & MBSW_STOP_AT_NUL))
--+        return width;
--+
--       if (isprint (c))
--         {
--           if (width == INT_MAX)
--diff --git a/lib/mbswidth.h b/lib/mbswidth.h
--index 2b5c53c37..45a123e63 100644
----- a/lib/mbswidth.h
--+++ b/lib/mbswidth.h
--@@ -45,6 +45,10 @@ extern "C" {
--    control characters and 1 otherwise.  */
-- #define MBSW_REJECT_UNPRINTABLE 2
-- 
--+/* If this bit is set \0 is treated as the end of string.
--+   Otherwise it's treated as a normal one column width character.  */
--+#define MBSW_STOP_AT_NUL 4
--+
-- 
-- /* Returns the number of screen columns needed for STRING.  */
-- #define mbswidth gnu_mbswidth  /* avoid clash with UnixWare 7.1.1 function */
-diff --git a/grub-core/lib/gnulib-patches/no-abort.patch b/grub-core/lib/gnulib-patches/no-abort.patch
-deleted file mode 100644
-index e469c4762eb..00000000000
---- a/grub-core/lib/gnulib-patches/no-abort.patch
-+++ /dev/null
-@@ -1,26 +0,0 @@
--diff --git a/lib/regcomp.c b/lib/regcomp.c
--index cc85f35ac..de45ebb5c 100644
----- a/lib/regcomp.c
--+++ b/lib/regcomp.c
--@@ -528,9 +528,9 @@ regerror (int errcode, const regex_t *__restrict preg, char *__restrict errbuf,
--        to this routine.  If we are given anything else, or if other regex
--        code generates an invalid error code, then the program has a bug.
--        Dump core so we can fix it.  */
---    abort ();
---
---  msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]);
--+    msg = gettext ("unknown regexp error");
--+  else
--+    msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]);
-- 
--   msg_size = strlen (msg) + 1; /* Includes the null.  */
-- 
--@@ -1136,7 +1136,7 @@ optimize_utf8 (re_dfa_t *dfa)
-- 	}
-- 	break;
--       default:
---	abort ();
--+	break;
--       }
-- 
--   if (mb_chars || has_period)
diff --git a/SOURCES/0137-Fix-build-error-with-the-fdt-module-on-risc-v.patch b/SOURCES/0137-Fix-build-error-with-the-fdt-module-on-risc-v.patch
deleted file mode 100644
index 35f2878..0000000
--- a/SOURCES/0137-Fix-build-error-with-the-fdt-module-on-risc-v.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Tue, 27 Aug 2019 10:34:24 +0200
-Subject: [PATCH] Fix build error with the fdt module on risc-v
-
-The risc-v architecture also uses Device Trees, but the symbols in the
-fdt header aren't defined for this arch which lead to following error:
-
-BUILDSTDERR: ../../grub-core/loader/efi/fdt.c: In function 'grub_fdt_load':
-BUILDSTDERR: ../../grub-core/loader/efi/fdt.c:48:39: warning: implicit declaration of function 'grub_fdt_get_totalsize' [-Wimplicit-function-declaration]
-BUILDSTDERR:    48 |       size = GRUB_EFI_BYTES_TO_PAGES (grub_fdt_get_totalsize (fdt));
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- include/grub/fdt.h | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
-diff --git a/include/grub/fdt.h b/include/grub/fdt.h
-index 2041341fd68..3514aa4a5b6 100644
---- a/include/grub/fdt.h
-+++ b/include/grub/fdt.h
-@@ -19,7 +19,8 @@
- #ifndef GRUB_FDT_HEADER
- #define GRUB_FDT_HEADER	1
- 
--#if !defined(GRUB_MACHINE_EMU) && (defined(__arm__) || defined(__aarch64__))
-+#if !defined(GRUB_MACHINE_EMU) && \
-+    (defined(__arm__) || defined(__aarch64__) || defined(__riscv))
- 
- #include <grub/types.h>
- #include <grub/symbol.h>
-@@ -146,6 +147,7 @@ int EXPORT_FUNC(grub_fdt_set_prop) (void *fdt, unsigned int nodeoffset, const ch
-   grub_fdt_set_prop ((fdt), (nodeoffset), "reg", reg_64, 16);  \
- })
- 
--#endif /* defined(__arm__) || defined(__aarch64__) */
-+#endif /* !defined(GRUB_MACHINE_EMU) && \
-+          (defined(__arm__) || defined(__aarch64__) || defined(__riscv)) */
- 
- #endif	/* ! GRUB_FDT_HEADER */
diff --git a/SOURCES/0137-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch b/SOURCES/0137-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch
new file mode 100644
index 0000000..ea92110
--- /dev/null
+++ b/SOURCES/0137-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch
@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 20 Jul 2020 12:24:02 -0400
+Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/ip4_config.c
+
+This will need to get folded back in the right place on the next rebase,
+but it's before "Make grub_strtol() "end" pointers have safer const
+qualifiers" currently, so for now I'm leaving it here instead of merging
+it back with the original patch.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/efi/ip4_config.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c
+index 9725e928f7..cb880fc3e8 100644
+--- a/grub-core/net/efi/ip4_config.c
++++ b/grub-core/net/efi/ip4_config.c
+@@ -61,7 +61,8 @@ int
+ grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest)
+ {
+   grub_uint32_t newip = 0;
+-  int i, ncolon = 0;
++  grub_size_t i;
++  int ncolon = 0;
+   const char *ptr = val;
+ 
+   /* Check that is not an IPv6 address */
+@@ -78,7 +79,7 @@ grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *addres
+   for (i = 0; i < 4; i++)
+     {
+       unsigned long t;
+-      t = grub_strtoul (ptr, (char **) &ptr, 0);
++      t = grub_strtoul (ptr, &ptr, 0);
+       if (grub_errno)
+ 	{
+ 	  grub_errno = GRUB_ERR_NONE;
diff --git a/SOURCES/0138-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch b/SOURCES/0138-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch
new file mode 100644
index 0000000..915e6d7
--- /dev/null
+++ b/SOURCES/0138-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 20 Jul 2020 12:24:02 -0400
+Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/ip6_config.c
+
+This will need to get folded back in the right place on the next rebase,
+but it's before "Make grub_strtol() "end" pointers have safer const
+qualifiers" currently, so for now I'm leaving it here instead of merging
+it back with the original patch.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/efi/ip6_config.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c
+index a46f6f9b68..1c5415d718 100644
+--- a/grub-core/net/efi/ip6_config.c
++++ b/grub-core/net/efi/ip6_config.c
+@@ -85,7 +85,7 @@ grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *addres
+ 	  ptr++;
+ 	  continue;
+ 	}
+-      t = grub_strtoul (ptr, (char **) &ptr, 16);
++      t = grub_strtoul (ptr, &ptr, 16);
+       if (grub_errno)
+ 	{
+ 	  grub_errno = GRUB_ERR_NONE;
diff --git a/SOURCES/0138-grub-set-bootflag-Update-comment-about-running-as-ro.patch b/SOURCES/0138-grub-set-bootflag-Update-comment-about-running-as-ro.patch
deleted file mode 100644
index cd4ef77..0000000
--- a/SOURCES/0138-grub-set-bootflag-Update-comment-about-running-as-ro.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Hans de Goede <hdegoede@redhat.com>
-Date: Wed, 13 Nov 2019 12:15:43 +0100
-Subject: [PATCH] grub-set-bootflag: Update comment about running as root
- through pkexec
-
-We have stopped using pkexec for grub-set-bootflag, instead it is now
-installed suid root, update the comment accordingly.
-
-Signed-off-by: Hans de Goede <hdegoede@redhat.com>
----
- util/grub-set-bootflag.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c
-index 6a79ee67444..65d74ce010f 100644
---- a/util/grub-set-bootflag.c
-+++ b/util/grub-set-bootflag.c
-@@ -18,7 +18,7 @@
-  */
- 
- /*
-- * NOTE this gets run by users as root (through pkexec), so this does not
-+ * NOTE this gets run by users as root (its suid root), so this does not
-  * use any grub library / util functions to allow for easy auditing.
-  * The grub headers are only included to get certain defines.
-  */
diff --git a/SOURCES/0139-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch b/SOURCES/0139-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch
new file mode 100644
index 0000000..fbba65a
--- /dev/null
+++ b/SOURCES/0139-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch
@@ -0,0 +1,37 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 20 Jul 2020 12:24:02 -0400
+Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/net.c
+
+This will need to get folded back in the right place on the next rebase,
+but it's before "Make grub_strtol() "end" pointers have safer const
+qualifiers" currently, so for now I'm leaving it here instead of merging
+it back with the original patch.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/efi/net.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
+index a3f0535d43..78e5442fc5 100644
+--- a/grub-core/net/efi/net.c
++++ b/grub-core/net/efi/net.c
+@@ -729,7 +729,7 @@ grub_efi_net_parse_address (const char *address,
+ 	{
+ 	  grub_uint32_t subnet_mask_size;
+ 
+-	  subnet_mask_size = grub_strtoul (rest + 1, (char **) &rest, 0);
++	  subnet_mask_size = grub_strtoul (rest + 1, &rest, 0);
+ 
+ 	  if (!grub_errno && subnet_mask_size <= 32 && *rest == 0)
+ 	    {
+@@ -758,7 +758,7 @@ grub_efi_net_parse_address (const char *address,
+ 	{
+ 	  grub_efi_uint8_t prefix_length;
+ 
+-	  prefix_length = grub_strtoul (rest + 1, (char **) &rest, 0);
++	  prefix_length = grub_strtoul (rest + 1, &rest, 0);
+ 	  if (!grub_errno && prefix_length <= 128 && *rest == 0)
+ 	    {
+ 	      ip6->prefix_length = prefix_length;
diff --git a/SOURCES/0139-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch b/SOURCES/0139-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch
deleted file mode 100644
index 122bf68..0000000
--- a/SOURCES/0139-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch
+++ /dev/null
@@ -1,152 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Hans de Goede <hdegoede@redhat.com>
-Date: Wed, 13 Nov 2019 13:02:01 +0100
-Subject: [PATCH] grub-set-bootflag: Write new env to tmpfile and then rename
-
-Make the grubenv writing code in grub-set-bootflag more robust by
-writing the modified grubenv to a tmpfile first and then renaming the
-tmpfile over the old grubenv (following symlinks).
-
-Signed-off-by: Hans de Goede <hdegoede@redhat.com>
----
- util/grub-set-bootflag.c | 87 +++++++++++++++++++++++++++++++++++++++++++-----
- 1 file changed, 78 insertions(+), 9 deletions(-)
-
-diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c
-index 65d74ce010f..d1c5e28862b 100644
---- a/util/grub-set-bootflag.c
-+++ b/util/grub-set-bootflag.c
-@@ -28,7 +28,9 @@
- #include <grub/err.h>
- #include <grub/lib/envblk.h> /* For GRUB_ENVBLK_DEFCFG define */
- #include <errno.h>
-+#include <limits.h>
- #include <stdio.h>
-+#include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- 
-@@ -54,8 +56,10 @@ int main(int argc, char *argv[])
- {
-   /* NOTE buf must be at least the longest bootflag length + 4 bytes */
-   char env[GRUBENV_SIZE + 1], buf[64], *s;
-+  /* +1 for 0 termination, +6 for "XXXXXX" in tmp filename */
-+  char env_filename[PATH_MAX + 1], tmp_filename[PATH_MAX + 6 + 1];
-   const char *bootflag;
--  int i, len, ret;
-+  int i, fd, len, ret;
-   FILE *f;
- 
-   if (argc != 2)
-@@ -77,7 +81,32 @@ int main(int argc, char *argv[])
-   bootflag = bootflags[i];
-   len = strlen (bootflag);
- 
--  f = fopen (GRUBENV, "r");
-+  /*
-+   * Really become root. setuid avoids an user killing us, possibly leaking
-+   * the tmpfile. setgid avoids the new grubenv's gid being that of the user.
-+   */
-+  ret = setuid(0);
-+  if (ret)
-+    {
-+      perror ("Error setuid(0) failed");
-+      return 1;
-+    }
-+
-+  ret = setgid(0);
-+  if (ret)
-+    {
-+      perror ("Error setgid(0) failed");
-+      return 1;
-+    }
-+
-+  /* Canonicalize GRUBENV filename, resolving symlinks, etc. */
-+  if (!realpath(GRUBENV, env_filename))
-+    {
-+      perror ("Error canonicalizing " GRUBENV " filename");
-+      return 1;
-+    }
-+
-+  f = fopen (env_filename, "r");
-   if (!f)
-     {
-       perror ("Error opening " GRUBENV " for reading");
-@@ -132,30 +161,70 @@ int main(int argc, char *argv[])
-   snprintf(buf, sizeof(buf), "%s=1\n", bootflag);
-   memcpy(s, buf, len + 3);
- 
--  /* "r+", don't truncate so that the diskspace stays reserved */
--  f = fopen (GRUBENV, "r+");
-+
-+  /*
-+   * Create a tempfile for writing the new env.  Use the canonicalized filename
-+   * for the template so that the tmpfile is in the same dir / on same fs.
-+   */
-+  snprintf(tmp_filename, sizeof(tmp_filename), "%sXXXXXX", env_filename);
-+  fd = mkstemp(tmp_filename);
-+  if (fd == -1)
-+    {
-+      perror ("Creating tmpfile failed");
-+      return 1;
-+    }
-+
-+  f = fdopen (fd, "w");
-   if (!f)
-     {
--      perror ("Error opening " GRUBENV " for writing");
-+      perror ("Error fdopen of tmpfile failed");
-+      unlink(tmp_filename);
-       return 1;     
-     }
- 
-   ret = fwrite (env, 1, GRUBENV_SIZE, f);
-   if (ret != GRUBENV_SIZE)
-     {
--      perror ("Error writing to " GRUBENV);
-+      perror ("Error writing tmpfile");
-+      unlink(tmp_filename);
-       return 1;     
-     }
- 
-   ret = fflush (f);
-   if (ret)
-     {
--      perror ("Error flushing " GRUBENV);
-+      perror ("Error flushing tmpfile");
-+      unlink(tmp_filename);
-       return 1;     
-     }
- 
--  fsync (fileno (f));
--  fclose (f);
-+  ret = fsync (fileno (f));
-+  if (ret)
-+    {
-+      perror ("Error syncing tmpfile");
-+      unlink(tmp_filename);
-+      return 1;
-+    }
-+
-+  ret = fclose (f);
-+  if (ret)
-+    {
-+      perror ("Error closing tmpfile");
-+      unlink(tmp_filename);
-+      return 1;
-+    }
-+
-+  /*
-+   * And finally rename the tmpfile with the new env over the old env, the
-+   * linux kernel guarantees that this is atomic (from a syscall pov).
-+   */
-+  ret = rename(tmp_filename, env_filename);
-+  if (ret)
-+    {
-+      perror ("Error renaming tmpfile to " GRUBENV " failed");
-+      unlink(tmp_filename);
-+      return 1;
-+    }
- 
-   return 0;
- }
diff --git a/SOURCES/0140-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch b/SOURCES/0140-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch
new file mode 100644
index 0000000..9b9acfe
--- /dev/null
+++ b/SOURCES/0140-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch
@@ -0,0 +1,46 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 20 Jul 2020 12:24:02 -0400
+Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/pxe.c
+
+This will need to get folded back in the right place on the next rebase,
+but it's before "Make grub_strtol() "end" pointers have safer const
+qualifiers" currently, so for now I'm leaving it here instead of merging
+it back with the original patch.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/efi/pxe.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/net/efi/pxe.c b/grub-core/net/efi/pxe.c
+index 531949cba5..73e2bb01c1 100644
+--- a/grub-core/net/efi/pxe.c
++++ b/grub-core/net/efi/pxe.c
+@@ -187,7 +187,7 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
+ 	  ptr++;
+ 	  continue;
+ 	}
+-      t = grub_strtoul (ptr, (char **) &ptr, 16);
++      t = grub_strtoul (ptr, &ptr, 16);
+       if (grub_errno)
+ 	{
+ 	  grub_errno = GRUB_ERR_NONE;
+@@ -225,7 +225,7 @@ pxe_open (struct grub_efi_net_device *dev,
+ 	  int type __attribute__((unused)))
+ {
+   int i;
+-  char *p;
++  const char *p;
+   grub_efi_status_t status;
+   grub_efi_pxe_ip_address_t server_ip;
+   grub_efi_uint64_t file_size = 0;
+@@ -313,7 +313,7 @@ pxe_read (struct grub_efi_net_device *dev,
+ 	  grub_size_t len)
+ {
+   int i;
+-  char *p;
++  const char *p;
+   grub_efi_status_t status;
+   grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe;
+   grub_efi_uint64_t bufsz = len;
diff --git a/SOURCES/0140-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch b/SOURCES/0140-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch
deleted file mode 100644
index 54b73e6..0000000
--- a/SOURCES/0140-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch
+++ /dev/null
@@ -1,75 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Hans de Goede <hdegoede@redhat.com>
-Date: Tue, 26 Nov 2019 09:51:41 +0100
-Subject: [PATCH] grub.d: Fix boot_indeterminate getting set on boot_success=0
- boot
-
-The "grub.d: Split out boot success reset from menu auto hide script"
-not only moved the code to clear boot_success and boot_indeterminate
-but for some reason also mixed in some broken changes to the
-boot_indeterminate handling.
-
-The boot_indeterminate var is meant to suppress the boot menu after
-a reboot from either a selinux-relabel or offline-updates. These
-2 special boot scenarios do not set boot_success since there is no
-successfull interaction with the user. Instead they increment
-boot_indeterminate, and if it is 1 and only when it is 1, so the
-first reboot after a "special" boot we suppress the menu.
-
-To ensure that we do show the menu if we somehow get stuck in a
-"special" boot loop where we do special-boots without them
-incrementing boot_indeterminate, the code before the
-"grub.d: Split out boot success reset from menu auto hide script"
-commit would increment boot_indeterminate once when it is 1, so that
-even if the "special" boot reboot-loop immediately we would show the
-menu on the next boot.
-
-That commit broke this however, because it not only moves the code,
-it also changes it from only "incrementing" boot_indeterminate once to
-always incrementing it, except when boot_success == 1 (and we reset it).
-
-This broken behavior causes the following problem:
-
-1. Boot a broken kernel, system hangs, power-cycle
-2. boot_success now != 1, so we increment boot_indeterminate from 0
-   (unset!) to 1. User either simply tries again, or makes some changes
-   but the end-result still is a system hang, power-cycle
-3. Now boot_indeterminate==1 so we do not show the menu even though the
-   previous boot failed -> BAD
-
-This commit fixes this by restoring the behavior of setting
-boot_indeterminate to 2 when it was 1 before.
-
-Fixes: "grub.d: Split out boot success reset from menu auto hide script"
-Signed-off-by: Hans de Goede <hdegoede@redhat.com>
----
- util/grub.d/10_reset_boot_success.in | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/util/grub.d/10_reset_boot_success.in b/util/grub.d/10_reset_boot_success.in
-index 6c88d933dde..737e1ae5b68 100644
---- a/util/grub.d/10_reset_boot_success.in
-+++ b/util/grub.d/10_reset_boot_success.in
-@@ -6,18 +6,18 @@
- #
- # The boot_success var needs to be set to 1 from userspace to mark a boot successful.
- cat << EOF
--insmod increment
- # Hiding the menu is ok if last boot was ok or if this is a first boot attempt to boot the entry
- if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then
-   set menu_hide_ok=1
- else
-   set menu_hide_ok=0 
- fi
--# Reset boot_indeterminate after a successful boot, increment otherwise
-+# Reset boot_indeterminate after a successful boot
- if [ "\${boot_success}" = "1" ] ; then
-   set boot_indeterminate=0
--else
--  increment boot_indeterminate
-+# Avoid boot_indeterminate causing the menu to be hidden more then once
-+elif [ "\${boot_indeterminate}" = "1" ]; then
-+  set boot_indeterminate=2
- fi
- # Reset boot_success for current boot 
- set boot_success=0
diff --git a/SOURCES/0141-Add-systemd-integration-scripts-to-make-systemctl-re.patch b/SOURCES/0141-Add-systemd-integration-scripts-to-make-systemctl-re.patch
new file mode 100644
index 0000000..8cf45c3
--- /dev/null
+++ b/SOURCES/0141-Add-systemd-integration-scripts-to-make-systemctl-re.patch
@@ -0,0 +1,190 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 22 Jul 2020 14:03:42 +0200
+Subject: [PATCH] Add systemd integration scripts to make "systemctl reboot
+ --boot-loader-menu=xxx" work with grub
+
+This commit adds a number of scripts / config files to make
+"systemctl reboot --boot-loader-menu=xxx" work with grub:
+
+1. /lib/systemd/system/systemd-logind.service.d/10-grub.conf
+This sets SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU in the env. for logind,
+indicating that the boot-loader which is used supports this feature, see:
+https://github.com/systemd/systemd/blob/master/docs/ENVIRONMENT.md
+
+2. /lib/systemd/system/grub-systemd-integration.service
+   /lib/systemd/system/reboot.target.wants/grub-systemd-integration.service ->
+     ../grub-systemd-integration.service
+   /usr/libexec/grub/grub-systemd-integration.sh
+
+The symlink in the .wants dir causes the added service file to be started
+by systemd just before rebooting the system.
+If /run/systemd/reboot-to-boot-loader-menu exist then the service will run
+the grub-systemd-integration.sh script.
+This script sets the new menu_show_once_timeout grubenv variable to the
+requested timeout in seconds.
+
+3. /etc/grub.d/14_menu_show_once
+
+This new grub-mkconfig snippet adds the necessary code to the generated
+grub.conf to honor the new menu_show_once_timeout variable, and to
+automatically clear it after consuming it.
+
+Note the service and libexec script use grub-systemd-integration as name
+because in the future they may be used to add further integration with
+systemctl reboot --foo options, e.g. support for --boot-loader-entry=NAME.
+
+A few notes about upstreaming this patch from the rhboot grub2 fork:
+1. I have deliberately put the grub.conf bits for this in a new / separate
+   grub-mkconfig snippet generator for easy upstreaming
+2. Even though the commit message mentions the .wants symlink for the .service
+   I have been unable to come up with a clean way to do this at "make install"
+   time, this should be fixed before upstreaming.
+
+Downstream notes:
+1. Since make install does not add the .wants symlink, this needs to be done
+   in grub2.spec %install
+2. This is keeping support for the "old" Fedora specific menu_show_once env
+   variable, which has a hardcoded timeout of 60 sec in 12_menu_auto_hide in
+   place for now. This can be dropped (eventually) in a follow-up patch once
+   GNOME has been converted to use the systemd dbus API equivalent of
+   "systemctl reboot --boot-loader-menu=xxx".
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ Makefile.util.def                                | 27 ++++++++++++++++++++++++
+ conf/Makefile.common                             |  6 ++++++
+ util/grub.d/14_menu_show_once.in                 | 13 ++++++++++++
+ util/systemd/10-grub-logind-service.conf.in      |  2 ++
+ util/systemd/grub-systemd-integration.service.in |  8 +++++++
+ util/systemd/systemd-integration.sh.in           |  6 ++++++
+ 6 files changed, 62 insertions(+)
+ create mode 100755 util/grub.d/14_menu_show_once.in
+ create mode 100644 util/systemd/10-grub-logind-service.conf.in
+ create mode 100644 util/systemd/grub-systemd-integration.service.in
+ create mode 100644 util/systemd/systemd-integration.sh.in
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index b4ce5383b7..6366442129 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -470,6 +470,12 @@ script = {
+   installdir = grubconf;
+ };
+ 
++script = {
++  name = '14_menu_show_once';
++  common = util/grub.d/14_menu_show_once.in;
++  installdir = grubconf;
++};
++
+ script = {
+   name = '01_users';
+   common = util/grub.d/01_users.in;
+@@ -569,6 +575,27 @@ script = {
+   installdir = grubconf;
+ };
+ 
++script = {
++  name = 'grub-systemd-integration.service';
++  common = util/systemd/grub-systemd-integration.service.in;
++  installdir = systemdunit;
++  condition = COND_HOST_LINUX;
++};
++
++script = {
++  name = 'systemd-integration.sh';
++  common = util/systemd/systemd-integration.sh.in;
++  installdir = grublibexec;
++  condition = COND_HOST_LINUX;
++};
++
++script = {
++  name = '10-grub-logind-service.conf';
++  common = util/systemd/10-grub-logind-service.conf.in;
++  installdir = systemd_logind_service_d;
++  condition = COND_HOST_LINUX;
++};
++
+ program = {
+   mansection = 1;
+   name = grub-mkrescue;
+diff --git a/conf/Makefile.common b/conf/Makefile.common
+index 0647c53b91..9fe5863b2d 100644
+--- a/conf/Makefile.common
++++ b/conf/Makefile.common
+@@ -63,8 +63,11 @@ CCASFLAGS_LIBRARY = $(UTILS_CCASFLAGS)
+ # Other variables
+ 
+ grubconfdir = $(sysconfdir)/grub.d
++grublibexecdir = $(libexecdir)/$(grubdirname)
+ platformdir = $(pkglibdir)/$(target_cpu)-$(platform)
+ starfielddir = $(pkgdatadir)/themes/starfield
++systemdunitdir = ${prefix}/lib/systemd/system
++systemd_logind_service_ddir = $(systemdunitdir)/systemd-logind.service.d
+ 
+ CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Werror=trampolines -fno-trampolines
+ CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib
+@@ -121,6 +124,9 @@ noinst_LIBRARIES =
+ dist_noinst_DATA =
+ platform_SCRIPTS =
+ platform_PROGRAMS =
++grublibexec_SCRIPTS =
++systemdunit_SCRIPTS =
++systemd_logind_service_d_SCRIPTS =
+ 
+ TESTS =
+ EXTRA_DIST =
+diff --git a/util/grub.d/14_menu_show_once.in b/util/grub.d/14_menu_show_once.in
+new file mode 100755
+index 0000000000..1cd7f36142
+--- /dev/null
++++ b/util/grub.d/14_menu_show_once.in
+@@ -0,0 +1,13 @@
++#! /bin/sh
++# Force the menu to be shown once, with a timeout of ${menu_show_once_timeout}
++# if requested by ${menu_show_once_timeout} being set in the env.
++cat << EOF
++if [ x\$feature_timeout_style = xy ]; then
++  if [ "\${menu_show_once_timeout}" ]; then
++    set timeout_style=menu
++    set timeout="\${menu_show_once_timeout}"
++    unset menu_show_once_timeout
++    save_env menu_show_once_timeout
++  fi
++fi
++EOF
+diff --git a/util/systemd/10-grub-logind-service.conf.in b/util/systemd/10-grub-logind-service.conf.in
+new file mode 100644
+index 0000000000..f2d4ac0073
+--- /dev/null
++++ b/util/systemd/10-grub-logind-service.conf.in
+@@ -0,0 +1,2 @@
++[Service]
++Environment=SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU=true
+diff --git a/util/systemd/grub-systemd-integration.service.in b/util/systemd/grub-systemd-integration.service.in
+new file mode 100644
+index 0000000000..c81fb594ce
+--- /dev/null
++++ b/util/systemd/grub-systemd-integration.service.in
+@@ -0,0 +1,8 @@
++[Unit]
++Description=Grub2 systemctl reboot --boot-loader-menu=... support
++Before=umount.target systemd-reboot.service
++DefaultDependencies=no
++ConditionPathExists=/run/systemd/reboot-to-boot-loader-menu
++
++[Service]
++ExecStart=@libexecdir@/@grubdirname@/systemd-integration.sh
+diff --git a/util/systemd/systemd-integration.sh.in b/util/systemd/systemd-integration.sh.in
+new file mode 100644
+index 0000000000..dc1218597b
+--- /dev/null
++++ b/util/systemd/systemd-integration.sh.in
+@@ -0,0 +1,6 @@
++#!/bin/sh
++
++TIMEOUT_USEC=$(cat /run/systemd/reboot-to-boot-loader-menu)
++TIMEOUT=$(((TIMEOUT_USEC + 500000) / 1000000))
++
++@grub_editenv@ - set menu_show_once_timeout=$TIMEOUT
diff --git a/SOURCES/0141-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch b/SOURCES/0141-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch
deleted file mode 100644
index b694ec9..0000000
--- a/SOURCES/0141-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: David Abdurachmanov <david.abdurachmanov@sifive.com>
-Date: Thu, 16 Jan 2020 13:10:10 +0100
-Subject: [PATCH] Also define GRUB_EFI_MAX_ALLOCATION_ADDRESS for RISC-V
-
-The commit "Try to pick better locations for kernel and initrd" missed to
-define this macro for the RISC-V (riscv64) architecture, so add it there.
-
-Signed-off-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
----
- include/grub/riscv64/efi/memory.h | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/include/grub/riscv64/efi/memory.h b/include/grub/riscv64/efi/memory.h
-index c6cb3241714..acb61dca44b 100644
---- a/include/grub/riscv64/efi/memory.h
-+++ b/include/grub/riscv64/efi/memory.h
-@@ -2,5 +2,6 @@
- #include <grub/efi/memory.h>
- 
- #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL
-+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
- 
- #endif /* ! GRUB_MEMORY_CPU_HEADER */
diff --git a/SOURCES/0142-chainloader-Define-machine-types-for-RISC-V.patch b/SOURCES/0142-chainloader-Define-machine-types-for-RISC-V.patch
deleted file mode 100644
index 480db52..0000000
--- a/SOURCES/0142-chainloader-Define-machine-types-for-RISC-V.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: David Abdurachmanov <david.abdurachmanov@sifive.com>
-Date: Sat, 9 Nov 2019 18:06:32 +0000
-Subject: [PATCH] chainloader: Define machine types for RISC-V
-
-The commit "Add secureboot support on efi chainloader" didn't add machine
-types for RISC-V, so this patch adds them.
-
-Note, that grub-core/loader/riscv/linux.c is skipped because Linux is not
-supported yet. This patch might need a new revision once that's the case.
-
-Signed-off-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
----
- grub-core/loader/efi/chainloader.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
-index 47f5aa14817..ac8dfd40c61 100644
---- a/grub-core/loader/efi/chainloader.c
-+++ b/grub-core/loader/efi/chainloader.c
-@@ -333,6 +333,10 @@ static const grub_uint16_t machine_type __attribute__((__unused__)) =
-   GRUB_PE32_MACHINE_I386;
- #elif defined(__ia64__)
-   GRUB_PE32_MACHINE_IA64;
-+#elif defined(__riscv) && (__riscv_xlen == 32)
-+  GRUB_PE32_MACHINE_RISCV32;
-+#elif defined(__riscv) && (__riscv_xlen == 64)
-+  GRUB_PE32_MACHINE_RISCV64;
- #else
- #error this architecture is not supported by grub2
- #endif
diff --git a/SOURCES/0142-systemd-integration.sh-Also-set-old-menu_show_once-g.patch b/SOURCES/0142-systemd-integration.sh-Also-set-old-menu_show_once-g.patch
new file mode 100644
index 0000000..a16ed68
--- /dev/null
+++ b/SOURCES/0142-systemd-integration.sh-Also-set-old-menu_show_once-g.patch
@@ -0,0 +1,32 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Thu, 23 Jul 2020 09:27:36 +0200
+Subject: [PATCH] systemd-integration.sh: Also set old menu_show_once grubenv
+ var
+
+Downstream RH / Fedora patch for compatibility with old, not (yet)
+regenerated grub.cfg files which miss the menu_show_once_timeout check.
+This older grubenv variable leads to a fixed timeout of 60 seconds.
+
+Note that the new menu_show_once_timeout will overrule these 60 seconds
+if both are set and the grub.cfg does have the menu_show_once_timeout
+check.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ util/systemd/systemd-integration.sh.in | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/util/systemd/systemd-integration.sh.in b/util/systemd/systemd-integration.sh.in
+index dc1218597b..a4c071c5b0 100644
+--- a/util/systemd/systemd-integration.sh.in
++++ b/util/systemd/systemd-integration.sh.in
+@@ -4,3 +4,8 @@ TIMEOUT_USEC=$(cat /run/systemd/reboot-to-boot-loader-menu)
+ TIMEOUT=$(((TIMEOUT_USEC + 500000) / 1000000))
+ 
+ @grub_editenv@ - set menu_show_once_timeout=$TIMEOUT
++
++# Downstream RH / Fedora patch for compatibility with old, not (yet)
++# regenerated grub.cfg files which miss the menu_show_once_timeout check
++# this older grubenv variable leads to a fixed timeout of 60 seconds
++@grub_editenv@ - set menu_show_once=1
diff --git a/SOURCES/0143-Add-start-symbol-for-RISC-V.patch b/SOURCES/0143-Add-start-symbol-for-RISC-V.patch
deleted file mode 100644
index 677efae..0000000
--- a/SOURCES/0143-Add-start-symbol-for-RISC-V.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: David Abdurachmanov <david.abdurachmanov@sifive.com>
-Date: Sat, 9 Nov 2019 19:51:57 +0000
-Subject: [PATCH] Add start symbol for RISC-V
-
-All other architectures have start symbol.
-
-Hopefully this resolves:
-
-    BUILDSTDERR: ././grub-mkimage: error: undefined symbol start.
-
-Signed-off-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
----
- grub-core/kern/riscv/efi/startup.S | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/grub-core/kern/riscv/efi/startup.S b/grub-core/kern/riscv/efi/startup.S
-index f2a7b2b1ede..781773136e8 100644
---- a/grub-core/kern/riscv/efi/startup.S
-+++ b/grub-core/kern/riscv/efi/startup.S
-@@ -29,6 +29,7 @@
- 
- 	.file 	"startup.S"
- 	.text
-+FUNCTION(start)
- FUNCTION(_start)
- 	/*
- 	 *  EFI_SYSTEM_TABLE and EFI_HANDLE are passed in a1/a0.
diff --git a/SOURCES/0143-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch b/SOURCES/0143-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch
new file mode 100644
index 0000000..f891a69
--- /dev/null
+++ b/SOURCES/0143-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch
@@ -0,0 +1,121 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Thu, 3 Dec 2020 09:13:24 +0100
+Subject: [PATCH] at_keyboard: use set 1 when keyboard is in Translate mode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When keyboard controller acts in Translate mode (0x40 mask), then use
+set 1 since translation is done.
+Otherwise use the mode queried from the controller (usually set 2).
+
+Added "atkeyb" debugging messages in at_keyboard module as well.
+
+Resolves: rhbz#1897587
+
+Tested on:
+- Asus N53SN (set 1 used)
+- Dell Precision (set 1 used)
+- HP Elitebook (set 2 used)
+- HP G5430 (set 1 used, keyboard in XT mode!)
+- Lenovo P71 & Lenovo T460s (set 2 used)
+- QEMU/KVM (set 1 used)
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+---
+ grub-core/term/at_keyboard.c | 29 ++++++++++++++++++++++++-----
+ include/grub/at_keyboard.h   |  4 ++++
+ 2 files changed, 28 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c
+index 597111077b..2601438260 100644
+--- a/grub-core/term/at_keyboard.c
++++ b/grub-core/term/at_keyboard.c
+@@ -135,20 +135,28 @@ query_mode (void)
+   int e;
+ 
+   e = write_mode (0);
+-  if (!e)
++  if (!e) {
++    grub_dprintf("atkeyb", "query_mode: write_mode(0) failed\n");
+     return 0;
++  }
+ 
+   do {
+     keyboard_controller_wait_until_ready ();
+     ret = grub_inb (KEYBOARD_REG_DATA);
+   } while (ret == GRUB_AT_ACK);
+   /* QEMU translates the set even in no-translate mode.  */
+-  if (ret == 0x43 || ret == 1)
++  if (ret == 0x43 || ret == 1) {
++    grub_dprintf("atkeyb", "query_mode: returning 1 (ret=0x%x)\n", ret);
+     return 1;
+-  if (ret == 0x41 || ret == 2)
++  }
++  if (ret == 0x41 || ret == 2) {
++    grub_dprintf("atkeyb", "query_mode: returning 2 (ret=0x%x)\n", ret);
+     return 2;
+-  if (ret == 0x3f || ret == 3)
++  }
++  if (ret == 0x3f || ret == 3) {
++    grub_dprintf("atkeyb", "query_mode: returning 3 (ret=0x%x)\n", ret);
+     return 3;
++  }
+   return 0;
+ }
+ 
+@@ -165,7 +173,13 @@ set_scancodes (void)
+     }
+ 
+ #if !USE_SCANCODE_SET
+-  ps2_state.current_set = 1;
++  if ((grub_keyboard_controller_orig & KEYBOARD_AT_TRANSLATE) == KEYBOARD_AT_TRANSLATE) {
++    grub_dprintf ("atkeyb", "queried set is %d but keyboard in Translate mode, so actually in set 1\n", grub_keyboard_orig_set);
++    ps2_state.current_set = 1;
++  } else {
++    grub_dprintf ("atkeyb", "using queried set %d\n", grub_keyboard_orig_set);
++    ps2_state.current_set = grub_keyboard_orig_set;
++  }
+   return;
+ #else
+ 
+@@ -266,6 +280,7 @@ grub_keyboard_controller_init (void)
+   grub_keyboard_orig_set = 2;
+ #else
+   grub_keyboard_controller_orig = grub_keyboard_controller_read ();
++  grub_dprintf ("atkeyb", "grub_keyboard_controller_orig = 0x%x\n", grub_keyboard_controller_orig);
+   grub_keyboard_orig_set = query_mode ();
+ #endif
+   set_scancodes ();
+@@ -275,11 +290,15 @@ grub_keyboard_controller_init (void)
+ static grub_err_t
+ grub_keyboard_controller_fini (struct grub_term_input *term __attribute__ ((unused)))
+ {
++/* In !USE_SCANCODE_SET mode, we didn't change anything, so nothing to restore */
++#if USE_SCANCODE_SET
+   if (ps2_state.current_set == 0)
+     return GRUB_ERR_NONE;
++  grub_dprintf ("atkeyb", "restoring set %d, controller 0x%x\n", grub_keyboard_orig_set, grub_keyboard_controller_orig);
+   if (grub_keyboard_orig_set)
+     write_mode (grub_keyboard_orig_set);
+   grub_keyboard_controller_write (grub_keyboard_controller_orig);
++#endif
+   return GRUB_ERR_NONE;
+ }
+ 
+diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h
+index bcb4d9ba78..9414dc1b99 100644
+--- a/include/grub/at_keyboard.h
++++ b/include/grub/at_keyboard.h
+@@ -19,6 +19,10 @@
+ #ifndef GRUB_AT_KEYBOARD_HEADER
+ #define GRUB_AT_KEYBOARD_HEADER	1
+ 
++/*
++ * Refer to https://wiki.osdev.org/%228042%22_PS/2_Controller for details.
++ */
++
+ /* Used for sending commands to the controller.  */
+ #define KEYBOARD_COMMAND_ISREADY(x)	!((x) & 0x02)
+ #define KEYBOARD_COMMAND_READ		0x20
diff --git a/SOURCES/0144-bootstrap.conf-Force-autogen.sh-to-use-python3.patch b/SOURCES/0144-bootstrap.conf-Force-autogen.sh-to-use-python3.patch
deleted file mode 100644
index 5c3b968..0000000
--- a/SOURCES/0144-bootstrap.conf-Force-autogen.sh-to-use-python3.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Wed, 15 Jan 2020 12:47:46 +0100
-Subject: [PATCH] bootstrap.conf: Force autogen.sh to use python3
-
-The python-unversioned-command package is not installed in the buildroot,
-but the bootstrap script expects the python command to be present if one
-is not defined. So building the package leads to the following error:
-
-./autogen.sh: line 20: python: command not found
-
-This is harmless since gnulib is included as a source anyways, because the
-builders can't download. But still the issue should be fixed by forcing to
-use python3 that's the default in Fedora now.
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- bootstrap.conf | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/bootstrap.conf b/bootstrap.conf
-index 452f4d79b0d..03f10930230 100644
---- a/bootstrap.conf
-+++ b/bootstrap.conf
-@@ -93,7 +93,7 @@ bootstrap_post_import_hook () {
-     patch -d po -p3 \
-       < "po/gettext-patches/$patchname.patch"
-   done
--  FROM_BOOTSTRAP=1 ./autogen.sh
-+  PYTHON=python3 FROM_BOOTSTRAP=1 ./autogen.sh
-   set +e  # bootstrap expects this
- }
- 
diff --git a/SOURCES/0144-grub-install-disable-support-for-EFI-platforms.patch b/SOURCES/0144-grub-install-disable-support-for-EFI-platforms.patch
new file mode 100644
index 0000000..f6a7530
--- /dev/null
+++ b/SOURCES/0144-grub-install-disable-support-for-EFI-platforms.patch
@@ -0,0 +1,101 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jan Hlavac <jhlavac@redhat.com>
+Date: Fri, 20 Nov 2020 23:51:47 +0100
+Subject: [PATCH] grub-install: disable support for EFI platforms
+
+For each platform, GRUB is shipped as a kernel image and a set of
+modules. These files are then used by the grub-install utility to
+install GRUB on a specific device. However, in order to support UEFI
+Secure Boot, the resulting EFI binary must be signed by a recognized
+private key. For this reason, for EFI platforms, most distributions also
+ship prebuilt EFI binaries signed by a distribution-specific private
+key. In this case, however, the grub-install utility should not be used
+because it would overwrite the signed EFI binary.
+
+The current fix is suboptimal because it preserves all EFI-related code.
+A better solution could be to modularize the code and provide a
+build-time option.
+
+Resolves: rhbz#1737444
+
+Signed-off-by: Jan Hlavac <jhlavac@redhat.com>
+[rharwood: drop man page]
+---
+ util/grub-install.c | 37 ++++++++++++++++---------------------
+ docs/grub.texi      |  7 +++++++
+ 2 files changed, 23 insertions(+), 21 deletions(-)
+
+diff --git a/util/grub-install.c b/util/grub-install.c
+index a2bec7446c..5babc7af55 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -899,6 +899,22 @@ main (int argc, char *argv[])
+ 
+   platform = grub_install_get_target (grub_install_source_directory);
+ 
++  switch (platform)
++    {
++    case GRUB_INSTALL_PLATFORM_ARM_EFI:
++    case GRUB_INSTALL_PLATFORM_ARM64_EFI:
++    case GRUB_INSTALL_PLATFORM_I386_EFI:
++    case GRUB_INSTALL_PLATFORM_IA64_EFI:
++    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
++      is_efi = 1;
++      grub_util_error (_("this utility cannot be used for EFI platforms"
++                         " because it does not support UEFI Secure Boot"));
++      break;
++    default:
++      is_efi = 0;
++      break;
++    }
++
+   {
+     char *platname = grub_install_get_platform_name (platform);
+     fprintf (stderr, _("Installing for %s platform.\n"), platname);
+@@ -1011,28 +1027,7 @@ main (int argc, char *argv[])
+   grub_hostfs_init ();
+   grub_host_init ();
+ 
+-  switch (platform)
+-    {
+-    case GRUB_INSTALL_PLATFORM_I386_EFI:
+-    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+-    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+-    case GRUB_INSTALL_PLATFORM_ARM64_EFI:
+-    case GRUB_INSTALL_PLATFORM_RISCV32_EFI:
+-    case GRUB_INSTALL_PLATFORM_RISCV64_EFI:
+-    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+-      is_efi = 1;
+-      break;
+-    default:
+-      is_efi = 0;
+-      break;
+-
+-      /* pacify warning.  */
+-    case GRUB_INSTALL_PLATFORM_MAX:
+-      break;
+-    }
+-
+   /* Find the EFI System Partition.  */
+-
+   if (is_efi)
+     {
+       grub_fs_t fs;
+diff --git a/docs/grub.texi b/docs/grub.texi
+index 04ed6ac1f0..4870faaa00 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -6509,6 +6509,13 @@ grub2-install @var{install_device}
+ The device name @var{install_device} is an OS device name or a GRUB
+ device name.
+ 
++In order to support UEFI Secure Boot, the resulting GRUB EFI binary must
++be signed by a recognized private key. For this reason, for EFI
++platforms, most distributions also ship prebuilt GRUB EFI binaries
++signed by a distribution-specific private key. In this case, however,
++@command{grub2-install} should not be used because it would overwrite
++the signed EFI binary.
++
+ @command{grub2-install} accepts the following options:
+ 
+ @table @option
diff --git a/SOURCES/0145-New-with-debug-timestamps-configure-flag-to-prepend-.patch b/SOURCES/0145-New-with-debug-timestamps-configure-flag-to-prepend-.patch
new file mode 100644
index 0000000..ec5b30b
--- /dev/null
+++ b/SOURCES/0145-New-with-debug-timestamps-configure-flag-to-prepend-.patch
@@ -0,0 +1,112 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Sat, 23 Nov 2019 14:57:41 +0100
+Subject: [PATCH] New --with-debug-timestamps configure flag to prepend debug
+ traces with absolute and relative timestamp
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+---
+ configure.ac          | 18 ++++++++++++++++++
+ grub-core/kern/misc.c | 20 ++++++++++++++++++++
+ config.h.in           |  1 +
+ 3 files changed, 39 insertions(+)
+
+diff --git a/configure.ac b/configure.ac
+index a02d40a05b..ab0d326f00 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1585,6 +1585,17 @@ else
+ fi
+ AC_SUBST([BOOT_TIME_STATS])
+ 
++AC_ARG_WITH([debug-timestamps],
++	   AS_HELP_STRING([--with-debug-timestamps],
++                          [prepend debug traces with absolute and relative timestamps]))
++
++if test x$with_debug_timestamps = xyes; then
++  DEBUG_WITH_TIMESTAMPS=1
++else
++  DEBUG_WITH_TIMESTAMPS=0
++fi
++AC_SUBST([DEBUG_WITH_TIMESTAMPS])
++
+ AC_ARG_ENABLE([grub-emu-sdl],
+ 	      [AS_HELP_STRING([--enable-grub-emu-sdl],
+                              [build and install the `grub-emu' debugging utility with SDL support (default=guessed)])])
+@@ -2136,6 +2147,7 @@ AM_CONDITIONAL([COND_APPLE_LINKER], [test x$TARGET_APPLE_LINKER = x1])
+ AM_CONDITIONAL([COND_ENABLE_EFIEMU], [test x$enable_efiemu = xyes])
+ AM_CONDITIONAL([COND_ENABLE_CACHE_STATS], [test x$DISK_CACHE_STATS = x1])
+ AM_CONDITIONAL([COND_ENABLE_BOOT_TIME_STATS], [test x$BOOT_TIME_STATS = x1])
++AM_CONDITIONAL([COND_DEBUG_WITH_TIMESTAMPS], [test x$DEBUG_WITH_TIMESTAMPS = x1])
+ 
+ AM_CONDITIONAL([COND_HAVE_CXX], [test x$HAVE_CXX = xyes])
+ 
+@@ -2231,6 +2243,12 @@ else
+ echo With boot time statistics: No
+ fi
+ 
++if [ x"$with_debug_timestamps" = xyes ]; then
++echo Debug traces with timestamps: Yes
++else
++echo Debug traces with timestamps: No
++fi
++
+ if [ x"$efiemu_excuse" = x ]; then
+ echo efiemu runtime: Yes
+ else
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index 578bf51a5f..9f54b6b7d2 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -25,6 +25,9 @@
+ #include <grub/env.h>
+ #include <grub/i18n.h>
+ #include <grub/backtrace.h>
++#if DEBUG_WITH_TIMESTAMPS
++#include <grub/time.h>
++#endif
+ 
+ union printf_arg
+ {
+@@ -192,9 +195,26 @@ grub_real_dprintf (const char *file, const int line, const char *condition,
+ 		   const char *fmt, ...)
+ {
+   va_list args;
++#if DEBUG_WITH_TIMESTAMPS
++  static long unsigned int last_time = 0;
++  static int last_had_cr = 1;
++#endif
+ 
+   if (grub_debug_enabled (condition))
+     {
++#if DEBUG_WITH_TIMESTAMPS
++      /* Don't print timestamp if last printed message isn't terminated yet */
++      if (last_had_cr) {
++        long unsigned int tmabs = (long unsigned int) grub_get_time_ms();
++        long unsigned int tmrel = tmabs - last_time;
++        last_time = tmabs;
++        grub_printf ("%3lu.%03lus +%2lu.%03lus ", tmabs / 1000, tmabs % 1000, tmrel / 1000, tmrel % 1000);
++      }
++      if (fmt[grub_strlen(fmt)-1] == '\n')
++        last_had_cr = 1;
++      else
++        last_had_cr = 0;
++#endif
+       grub_printf ("%s:%d: ", file, line);
+       va_start (args, fmt);
+       grub_vprintf (fmt, args);
+diff --git a/config.h.in b/config.h.in
+index c7e316f0f1..c80e3e0aba 100644
+--- a/config.h.in
++++ b/config.h.in
+@@ -12,6 +12,7 @@
+ /* Define to 1 to enable disk cache statistics.  */
+ #define DISK_CACHE_STATS @DISK_CACHE_STATS@
+ #define BOOT_TIME_STATS @BOOT_TIME_STATS@
++#define DEBUG_WITH_TIMESTAMPS @DEBUG_WITH_TIMESTAMPS@
+ 
+ /* We don't need those.  */
+ #define MINILZO_CFG_SKIP_LZO_PTR 1
diff --git a/SOURCES/0145-efi-http-Export-fw-http-_path-variables-to-make-them.patch b/SOURCES/0145-efi-http-Export-fw-http-_path-variables-to-make-them.patch
deleted file mode 100644
index 6f2e93d..0000000
--- a/SOURCES/0145-efi-http-Export-fw-http-_path-variables-to-make-them.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Thu, 5 Mar 2020 16:21:47 +0100
-Subject: [PATCH] efi/http: Export {fw,http}_path variables to make them global
-
-The fw_path environment variable is used by http_configure() function to
-determine the HTTP path that should be used as prefix when using relative
-HTTP paths. And this is stored in the http_path environment variable.
-
-Later, that variable is looked up by grub_efihttp_open() to generate the
-complete path to be used in the HTTP request.
-
-But these variables are not exported, which means that are not global and
-so are only found in the initial context.
-
-This can cause commands like configfile that create a new context to fail
-because the fw_path and http_path variables will not be found.
-
-Resolves: rhbz#1616395
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/kern/main.c    | 1 +
- grub-core/net/efi/http.c | 1 +
- 2 files changed, 2 insertions(+)
-
-diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
-index 4ec3f5e4d33..0285e95a2bb 100644
---- a/grub-core/kern/main.c
-+++ b/grub-core/kern/main.c
-@@ -143,6 +143,7 @@ grub_set_prefix_and_root (void)
-       if (fw_path)
- 	{
- 	  grub_env_set ("fw_path", fw_path);
-+	  grub_env_export ("fw_path");
- 	  grub_dprintf ("fw_path", "fw_path:\"%s\"\n", fw_path);
- 	  grub_free (fw_path);
- 	}
-diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
-index de351b2cd03..755b7a6d054 100644
---- a/grub-core/net/efi/http.c
-+++ b/grub-core/net/efi/http.c
-@@ -39,6 +39,7 @@ http_configure (struct grub_efi_net_device *dev, int prefer_ip6)
- 	  http_path++;
- 	  grub_env_unset ("http_path");
- 	  grub_env_set ("http_path", http_path);
-+	  grub_env_export ("http_path");
- 	}
-     }
- 
diff --git a/SOURCES/0146-Added-debug-statements-to-grub_disk_open-and-grub_di.patch b/SOURCES/0146-Added-debug-statements-to-grub_disk_open-and-grub_di.patch
new file mode 100644
index 0000000..d26027c
--- /dev/null
+++ b/SOURCES/0146-Added-debug-statements-to-grub_disk_open-and-grub_di.patch
@@ -0,0 +1,47 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Sat, 23 Nov 2019 15:22:16 +0100
+Subject: [PATCH] Added debug statements to grub_disk_open() and
+ grub_disk_close() on success
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+---
+ grub-core/kern/disk.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c
+index e1b0e073e0..05a28ab142 100644
+--- a/grub-core/kern/disk.c
++++ b/grub-core/kern/disk.c
+@@ -285,6 +285,8 @@ grub_disk_open (const char *name)
+       return 0;
+     }
+ 
++  grub_dprintf ("disk", "Opening `%s' succeeded.\n", name);
++
+   return disk;
+ }
+ 
+@@ -292,7 +294,7 @@ void
+ grub_disk_close (grub_disk_t disk)
+ {
+   grub_partition_t part;
+-  grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
++  grub_dprintf ("disk", "Closing `%s'...\n", disk->name);
+ 
+   if (disk->dev && disk->dev->disk_close)
+     (disk->dev->disk_close) (disk);
+@@ -306,8 +308,10 @@ grub_disk_close (grub_disk_t disk)
+       grub_free (disk->partition);
+       disk->partition = part;
+     }
++  grub_dprintf ("disk", "Closing `%s' succeeded.\n", disk->name);
+   grub_free ((void *) disk->name);
+   grub_free (disk);
++
+ }
+ 
+ /* Small read (less than cache size and not pass across cache unit boundaries).
diff --git a/SOURCES/0146-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch b/SOURCES/0146-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch
deleted file mode 100644
index c394549..0000000
--- a/SOURCES/0146-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch
+++ /dev/null
@@ -1,114 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Thu, 5 Mar 2020 16:21:58 +0100
-Subject: [PATCH] efi/http: Enclose literal IPv6 addresses in square brackets
-
-According to RFC 2732 (https://www.ietf.org/rfc/rfc2732.txt), literal IPv6
-addresses must be enclosed in square brackets. But GRUB currently does not
-do this and is causing HTTP servers to send Bad Request (400) responses.
-
-For example, the following is the HTTP stream when fetching a config file:
-
-HEAD /EFI/BOOT/grub.cfg HTTP/1.1
-Host: 2000:dead:beef:a::1
-Accept: */*
-User-Agent: UefiHttpBoot/1.0
-
-HTTP/1.1 400 Bad Request
-Date: Thu, 05 Mar 2020 14:46:02 GMT
-Server: Apache/2.4.41 (Fedora) OpenSSL/1.1.1d
-Connection: close
-Content-Type: text/html; charset=iso-8859-1
-
-and after enclosing the IPv6 address the HTTP request is successful:
-
-HEAD /EFI/BOOT/grub.cfg HTTP/1.1
-Host: [2000:dead:beef:a::1]
-Accept: */*
-User-Agent: UefiHttpBoot/1.0
-
-HTTP/1.1 200 OK
-Date: Thu, 05 Mar 2020 14:48:04 GMT
-Server: Apache/2.4.41 (Fedora) OpenSSL/1.1.1d
-Last-Modified: Thu, 27 Feb 2020 17:45:58 GMT
-ETag: "206-59f924b24b1da"
-Accept-Ranges: bytes
-Content-Length: 518
-
-Resolves: rhbz#1732765
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/net/efi/http.c | 37 ++++++++++++++++++++++++++++---------
- 1 file changed, 28 insertions(+), 9 deletions(-)
-
-diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
-index 755b7a6d054..fc8cb25ae0a 100644
---- a/grub-core/net/efi/http.c
-+++ b/grub-core/net/efi/http.c
-@@ -158,13 +158,7 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https,
-   grub_efi_status_t status;
-   grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
-   char *url = NULL;
--
--  request_headers[0].field_name = (grub_efi_char8_t *)"Host";
--  request_headers[0].field_value = (grub_efi_char8_t *)server;
--  request_headers[1].field_name = (grub_efi_char8_t *)"Accept";
--  request_headers[1].field_value = (grub_efi_char8_t *)"*/*";
--  request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent";
--  request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0";
-+  char *hostname = NULL;
- 
-   {
-     grub_efi_ipv6_address_t address;
-@@ -174,9 +168,24 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https,
-     const char *protocol = (use_https == 1) ? "https" : "http";
- 
-     if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0)
--      url = grub_xasprintf ("%s://[%s]%s", protocol, server, name);
-+      {
-+        hostname = grub_xasprintf ("[%s]", server);
-+        if (!hostname)
-+          return GRUB_ERR_OUT_OF_MEMORY;
-+
-+        server = hostname;
-+
-+        url = grub_xasprintf ("%s://%s%s", protocol, server, name);
-+        if (!url)
-+          {
-+            grub_free (hostname);
-+            return GRUB_ERR_OUT_OF_MEMORY;
-+          }
-+      }
-     else
--      url = grub_xasprintf ("%s://%s%s", protocol, server, name);
-+      {
-+        url = grub_xasprintf ("%s://%s%s", protocol, server, name);
-+      }
- 
-     if (!url)
-       {
-@@ -199,6 +208,13 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https,
-     request_data.url = ucs2_url;
-   }
- 
-+  request_headers[0].field_name = (grub_efi_char8_t *)"Host";
-+  request_headers[0].field_value = (grub_efi_char8_t *)server;
-+  request_headers[1].field_name = (grub_efi_char8_t *)"Accept";
-+  request_headers[1].field_value = (grub_efi_char8_t *)"*/*";
-+  request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent";
-+  request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0";
-+
-   request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET;
- 
-   request_message.data.request = &request_data;
-@@ -228,6 +244,9 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https,
- 
-   status = efi_call_2 (http->request, http, &request_token);
- 
-+  if (hostname)
-+    grub_free (hostname);
-+
-   if (status != GRUB_EFI_SUCCESS)
-     {
-       efi_call_1 (b->close_event, request_token.event);
diff --git a/SOURCES/0147-Introduce-function-grub_debug_is_enabled-void-return.patch b/SOURCES/0147-Introduce-function-grub_debug_is_enabled-void-return.patch
new file mode 100644
index 0000000..9ce5d9d
--- /dev/null
+++ b/SOURCES/0147-Introduce-function-grub_debug_is_enabled-void-return.patch
@@ -0,0 +1,51 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Mon, 25 Nov 2019 09:29:53 +0100
+Subject: [PATCH] Introduce function grub_debug_is_enabled(void) returning 1 if
+ 'debug' is in the environment and not empty
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+---
+ grub-core/kern/misc.c | 13 +++++++++++++
+ include/grub/misc.h   |  1 +
+ 2 files changed, 14 insertions(+)
+
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index 9f54b6b7d2..a186ad3dd4 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -163,6 +163,19 @@ int grub_err_printf (const char *fmt, ...)
+ __attribute__ ((alias("grub_printf")));
+ #endif
+ 
++/* Return 1 if 'debug' is set and not empty */
++int
++grub_debug_is_enabled (void)
++{
++  const char *debug;
++
++  debug = grub_env_get ("debug");
++  if (!debug || debug[0] == '\0')
++    return 0;
++
++  return 1;
++}
++
+ int
+ grub_debug_enabled (const char * condition)
+ {
+diff --git a/include/grub/misc.h b/include/grub/misc.h
+index 3adc4036e3..6c4aa85ac5 100644
+--- a/include/grub/misc.h
++++ b/include/grub/misc.h
+@@ -340,6 +340,7 @@ grub_puts (const char *s)
+ }
+ 
+ int EXPORT_FUNC(grub_puts_) (const char *s);
++int EXPORT_FUNC(grub_debug_is_enabled) (void);
+ int EXPORT_FUNC(grub_debug_enabled) (const char *condition);
+ void EXPORT_FUNC(grub_real_dprintf) (const char *file,
+                                      const int line,
diff --git a/SOURCES/0147-efi-net-Allow-to-specify-a-port-number-in-addresses.patch b/SOURCES/0147-efi-net-Allow-to-specify-a-port-number-in-addresses.patch
deleted file mode 100644
index 209aed8..0000000
--- a/SOURCES/0147-efi-net-Allow-to-specify-a-port-number-in-addresses.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Mon, 9 Mar 2020 15:29:45 +0100
-Subject: [PATCH] efi/net: Allow to specify a port number in addresses
-
-The grub_efi_net_parse_address() function is not covering the case where a
-port number is specified in an IPv4 or IPv6 address, so will fail to parse
-the network address.
-
-For most cases the issue is harmless, because the function is only used to
-match an address with a network interface and if fails the default is used.
-
-But still is a bug that has to be fixed and it causes error messages to be
-printed like the following:
-
-error: net/efi/net.c:782:unrecognised network address '192.168.122.1:8080'
-
-error: net/efi/net.c:781:unrecognised network address '[2000:dead:beef:a::1]:8080'
-
-Resolves: rhbz#1732765
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/net/efi/net.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
-index 6603cd83edc..84573937b18 100644
---- a/grub-core/net/efi/net.c
-+++ b/grub-core/net/efi/net.c
-@@ -742,7 +742,7 @@ grub_efi_net_parse_address (const char *address,
- 	      return GRUB_ERR_NONE;
- 	    }
- 	}
--      else if (*rest == 0)
-+      else if (*rest == 0 || *rest == ':')
- 	{
- 	  grub_uint32_t subnet_mask = 0xffffffffU;
- 	  grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask));
-@@ -768,7 +768,7 @@ grub_efi_net_parse_address (const char *address,
- 	      return GRUB_ERR_NONE;
- 	    }
- 	}
--      else if (*rest == 0)
-+      else if (*rest == 0 || *rest == ':')
- 	{
- 	  ip6->prefix_length = 128;
- 	  ip6->is_anycast = 0;
diff --git a/SOURCES/0148-Don-t-clear-screen-when-debugging-is-enabled.patch b/SOURCES/0148-Don-t-clear-screen-when-debugging-is-enabled.patch
new file mode 100644
index 0000000..c35d8a3
--- /dev/null
+++ b/SOURCES/0148-Don-t-clear-screen-when-debugging-is-enabled.patch
@@ -0,0 +1,31 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Sat, 23 Nov 2019 16:23:54 +0100
+Subject: [PATCH] Don't clear screen when debugging is enabled
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+[rharwood@redhat.com: rebase fuzz]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/normal/main.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index af9792c963..7de9e4c36d 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -215,8 +215,9 @@ grub_normal_init_page (struct grub_term_output *term,
+   char *msg_formatted;
+   grub_uint32_t *unicode_msg;
+   grub_uint32_t *last_position;
+- 
+-  grub_term_cls (term);
++
++  if (! grub_debug_is_enabled ())
++    grub_term_cls (term);
+ 
+   msg_formatted = grub_xasprintf (_("GRUB version %s"), PACKAGE_VERSION);
+   if (!msg_formatted)
diff --git a/SOURCES/0148-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch b/SOURCES/0148-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch
deleted file mode 100644
index f92dee4..0000000
--- a/SOURCES/0148-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Mon, 9 Mar 2020 15:30:05 +0100
-Subject: [PATCH] efi/ip4_config: Improve check to detect literal IPv6
- addresses
-
-The grub_efi_string_to_ip4_address() function wrongly assumes that an IPv6
-address is an IPv4 address, because it doesn't take into account the case
-of a caller passing an IPv6 address as a string.
-
-This leads to the grub_efi_net_parse_address() function to fail and print
-the following error message:
-
-error: net/efi/net.c:785:unrecognised network address '2000:dead:beef:a::1'
-
-Resolves: rhbz#1732765
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/net/efi/ip4_config.c | 13 ++++++++++++-
- 1 file changed, 12 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c
-index b711a5d9457..313c818b184 100644
---- a/grub-core/net/efi/ip4_config.c
-+++ b/grub-core/net/efi/ip4_config.c
-@@ -56,9 +56,20 @@ int
- grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest)
- {
-   grub_uint32_t newip = 0;
--  int i;
-+  int i, ncolon = 0;
-   const char *ptr = val;
- 
-+  /* Check that is not an IPv6 address */
-+  for (i = 0; i < grub_strlen(ptr); i++)
-+    {
-+      if (ptr[i] == '[' && i == 0)
-+        return 0;
-+
-+      if (ptr[i] == ':')
-+          if (i == 0 || ++ncolon == 2)
-+            return 0;
-+    }
-+
-   for (i = 0; i < 4; i++)
-     {
-       unsigned long t;
diff --git a/SOURCES/0149-efi-net-Print-a-debug-message-if-parsing-the-address.patch b/SOURCES/0149-efi-net-Print-a-debug-message-if-parsing-the-address.patch
deleted file mode 100644
index 33d8f88..0000000
--- a/SOURCES/0149-efi-net-Print-a-debug-message-if-parsing-the-address.patch
+++ /dev/null
@@ -1,68 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Tue, 10 Mar 2020 11:23:49 +0100
-Subject: [PATCH] efi/net: Print a debug message if parsing the address fails
-
-Currently if parsing the address fails an error message is printed. But in
-most cases this isn't a fatal error since the grub_efi_net_parse_address()
-function is only used to match an address with a network interface to use.
-
-And if this fails, the default interface is used which is good enough for
-most cases. So instead of printing an error that would pollute the console
-just print a debug message if the address is not parsed correctly.
-
-A user can enable debug messages for the efinet driver to have information
-about the failure and the fact that the default interface is being used.
-
-Related: rhbz#1732765
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/net/efi/net.c | 18 +++++++++++-------
- 1 file changed, 11 insertions(+), 7 deletions(-)
-
-diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
-index 84573937b18..a3f0535d43c 100644
---- a/grub-core/net/efi/net.c
-+++ b/grub-core/net/efi/net.c
-@@ -778,9 +778,9 @@ grub_efi_net_parse_address (const char *address,
- 	}
-     }
- 
--  return grub_error (GRUB_ERR_NET_BAD_ADDRESS,
--		   N_("unrecognised network address `%s'"),
--		   address);
-+  grub_dprintf ("efinet", "unrecognised network address '%s'\n", address);
-+
-+  return GRUB_ERR_NET_BAD_ADDRESS;
- }
- 
- static grub_efi_net_interface_t *
-@@ -795,10 +795,7 @@ match_route (const char *server)
-   err = grub_efi_net_parse_address (server, &ip4, &ip6, &is_ip6, 0);
- 
-   if (err)
--    {
--      grub_print_error ();
-       return NULL;
--    }
- 
-   if (is_ip6)
-     {
-@@ -1233,8 +1230,15 @@ grub_net_open_real (const char *name __attribute__ ((unused)))
-   /*FIXME: Use DNS translate name to address */
-   net_interface = match_route (server);
- 
-+  if (!net_interface && net_default_interface)
-+    {
-+      net_interface = net_default_interface;
-+      grub_dprintf ("efinet", "interface lookup failed, using default '%s'\n",
-+                    net_interface->name);
-+    }
-+
-   /*XXX: should we check device with default gateway ? */
--  if (!net_interface && !(net_interface = net_default_interface))
-+  if (!net_interface)
-     {
-       grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' no route found"),
- 		  name);
diff --git a/SOURCES/0149-kern-file-Fix-error-handling-in-grub_file_open.patch b/SOURCES/0149-kern-file-Fix-error-handling-in-grub_file_open.patch
new file mode 100644
index 0000000..e444325
--- /dev/null
+++ b/SOURCES/0149-kern-file-Fix-error-handling-in-grub_file_open.patch
@@ -0,0 +1,34 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Steve McIntyre <steve@einval.com>
+Date: Tue, 6 Dec 2022 01:45:11 +0000
+Subject: [PATCH] kern/file: Fix error handling in grub_file_open()
+
+grub_file_open() calls grub_file_get_device_name(), but doesn't check
+the return. Instead, it checks if grub_errno is set.
+
+However, nothing initialises grub_errno here when grub_file_open()
+starts. This means that trying to open one file that doesn't exist and
+then trying to open another file that does will (incorrectly) also
+fail to open that second file.
+
+Let's fix that.
+
+Signed-off-by: Steve McIntyre <steve@einval.com>
+---
+ grub-core/kern/file.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
+index 58454458c4..5b58f45cfd 100644
+--- a/grub-core/kern/file.c
++++ b/grub-core/kern/file.c
+@@ -66,6 +66,9 @@ grub_file_open (const char *name, enum grub_file_type type)
+   const char *file_name;
+   grub_file_filter_id_t filter;
+ 
++  /* Reset grub_errno before we start */
++  grub_errno = GRUB_ERR_NONE;
++
+   device_name = grub_file_get_device_name (name);
+   if (grub_errno)
+     goto fail;
diff --git a/SOURCES/0150-grub_file_-instrumentation-new-file-debug-tag.patch b/SOURCES/0150-grub_file_-instrumentation-new-file-debug-tag.patch
new file mode 100644
index 0000000..6327899
--- /dev/null
+++ b/SOURCES/0150-grub_file_-instrumentation-new-file-debug-tag.patch
@@ -0,0 +1,71 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Fri, 29 Nov 2019 11:02:00 +0100
+Subject: [PATCH] grub_file_* instrumentation (new 'file' debug tag)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+---
+ grub-core/kern/file.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
+index 5b58f45cfd..ec10e54fc0 100644
+--- a/grub-core/kern/file.c
++++ b/grub-core/kern/file.c
+@@ -66,6 +66,8 @@ grub_file_open (const char *name, enum grub_file_type type)
+   const char *file_name;
+   grub_file_filter_id_t filter;
+ 
++  grub_dprintf ("file", "Opening `%s' ...\n", name);
++
+   /* Reset grub_errno before we start */
+   grub_errno = GRUB_ERR_NONE;
+ 
+@@ -131,6 +133,8 @@ grub_file_open (const char *name, enum grub_file_type type)
+   if (!file)
+     grub_file_close (last_file);
+ 
++  grub_dprintf ("file", "Opening `%s' succeeded.\n", name);
++
+   return file;
+ 
+  fail:
+@@ -141,6 +145,8 @@ grub_file_open (const char *name, enum grub_file_type type)
+ 
+   grub_free (file);
+ 
++  grub_dprintf ("file", "Opening `%s' failed.\n", name);
++
+   return 0;
+ }
+ 
+@@ -172,6 +178,7 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len)
+ 
+   if (len == 0)
+     return 0;
++
+   read_hook = file->read_hook;
+   read_hook_data = file->read_hook_data;
+   if (!file->read_hook)
+@@ -192,11 +199,18 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len)
+ grub_err_t
+ grub_file_close (grub_file_t file)
+ {
++  grub_dprintf ("file", "Closing `%s' ...\n", file->name);
+   if (file->fs->fs_close)
+     (file->fs->fs_close) (file);
+ 
+   if (file->device)
+     grub_device_close (file->device);
++
++  if (grub_errno == GRUB_ERR_NONE)
++    grub_dprintf ("file", "Closing `%s' succeeded.\n", file->name);
++  else
++    grub_dprintf ("file", "Closing `%s' failed with %d.\n", file->name, grub_errno);
++
+   grub_free (file->name);
+   grub_free (file);
+   return grub_errno;
diff --git a/SOURCES/0150-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch b/SOURCES/0150-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch
deleted file mode 100644
index 3dd525a..0000000
--- a/SOURCES/0150-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Wed, 22 Apr 2020 12:41:52 +0200
-Subject: [PATCH] kern/term: Also accept F8 as a user interrupt key
-
-Make F8, which used to be the hotkey to show the Windows boot menu during
-boot for a long long time, also interrupt sleeps / stop the menu countdown.
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/kern/term.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/kern/term.c b/grub-core/kern/term.c
-index 14d59649832..4d61f4e9790 100644
---- a/grub-core/kern/term.c
-+++ b/grub-core/kern/term.c
-@@ -144,9 +144,10 @@ grub_key_is_interrupt (int key)
-   /*
-    * ESC sometimes is the BIOS setup hotkey and may be hard to discover, also
-    * check F4, which was chosen because is not used as a hotkey to enter the
--   * BIOS setup by any vendor.
-+   * BIOS setup by any vendor. Also, F8 which was the key to get the Windows
-+   * bootmenu for a long time.
-    */
--  if (key == GRUB_TERM_ESC || key == GRUB_TERM_KEY_F4)
-+  if (key == GRUB_TERM_ESC || key == GRUB_TERM_KEY_F4 || key == GRUB_TERM_KEY_F8)
-     return 1;
- 
-   /*
diff --git a/SOURCES/0151-efi-Set-image-base-address-before-jumping-to-the-PE-.patch b/SOURCES/0151-efi-Set-image-base-address-before-jumping-to-the-PE-.patch
deleted file mode 100644
index 336bcf1..0000000
--- a/SOURCES/0151-efi-Set-image-base-address-before-jumping-to-the-PE-.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Thu, 23 Apr 2020 15:06:46 +0200
-Subject: [PATCH] efi: Set image base address before jumping to the PE/COFF
- entry point
-
-Upstream GRUB uses the EFI LoadImage() and StartImage() to boot the Linux
-kernel. But our custom EFI loader that supports Secure Boot instead uses
-the EFI handover protocol (for x86) or jumping directly to the PE/COFF
-entry point (for aarch64).
-
-This is done to allow the bootloader to verify the images using the shim
-lock protocol to avoid booting untrusted binaries.
-
-Since the bootloader loads the kernel from the boot media instead of using
-LoadImage(), it is responsible to set the Loaded Image base address before
-booting the kernel.
-
-Otherwise the kernel EFI stub will complain that it was not set correctly
-and print the following warning message:
-
-EFI stub: ERROR: FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value
-
-Resolves: rhbz#1814690
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/loader/efi/linux.c | 14 ++++++++++++++
- 1 file changed, 14 insertions(+)
-
-diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
-index 0622dfa48d4..e8b9ecb17f6 100644
---- a/grub-core/loader/efi/linux.c
-+++ b/grub-core/loader/efi/linux.c
-@@ -72,6 +72,7 @@ grub_err_t
- grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
- 		     void *kernel_params)
- {
-+  grub_efi_loaded_image_t *loaded_image = NULL;
-   handover_func hf;
-   int offset = 0;
- 
-@@ -79,6 +80,19 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
-   offset = 512;
- #endif
- 
-+  /*
-+   * Since the EFI loader is not calling the LoadImage() and StartImage()
-+   * services for loading the kernel and booting respectively, it has to
-+   * set the Loaded Image base address.
-+   */
-+  loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
-+  if (loaded_image)
-+    loaded_image->image_base = kernel_addr;
-+  else
-+    grub_dprintf ("linux", "Loaded Image base address could not be set\n");
-+
-+  grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n",
-+		kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params);
-   hf = (handover_func)((char *)kernel_addr + handover_offset + offset);
-   hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
- 
diff --git a/SOURCES/0151-ieee1275-Avoiding-many-unecessary-open-close.patch b/SOURCES/0151-ieee1275-Avoiding-many-unecessary-open-close.patch
new file mode 100644
index 0000000..f6c5244
--- /dev/null
+++ b/SOURCES/0151-ieee1275-Avoiding-many-unecessary-open-close.patch
@@ -0,0 +1,136 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Diego Domingos <diegodo@br.ibm.com>
+Date: Mon, 14 Dec 2020 17:42:45 +0100
+Subject: [PATCH] ieee1275: Avoiding many unecessary open/close
+
+Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
+---
+ grub-core/disk/ieee1275/ofdisk.c | 64 ++++++++++++++++++++++------------------
+ 1 file changed, 35 insertions(+), 29 deletions(-)
+
+diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c
+index 03674cb477..ea7f78ac7d 100644
+--- a/grub-core/disk/ieee1275/ofdisk.c
++++ b/grub-core/disk/ieee1275/ofdisk.c
+@@ -44,7 +44,7 @@ struct ofdisk_hash_ent
+ };
+ 
+ static grub_err_t
+-grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size,
++grub_ofdisk_get_block_size (grub_uint32_t *block_size,
+ 			    struct ofdisk_hash_ent *op);
+ 
+ #define OFDISK_HASH_SZ	8
+@@ -461,6 +461,7 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
+   grub_ssize_t actual;
+   grub_uint32_t block_size = 0;
+   grub_err_t err;
++  struct ofdisk_hash_ent *op;
+ 
+   if (grub_strncmp (name, "ieee1275/", sizeof ("ieee1275/") - 1) != 0)
+       return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+@@ -471,6 +472,35 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
+ 
+   grub_dprintf ("disk", "Opening `%s'.\n", devpath);
+ 
++  op = ofdisk_hash_find (devpath);
++  if (!op)
++    op = ofdisk_hash_add (devpath, NULL);
++  if (!op)
++    {
++      grub_free (devpath);
++      return grub_errno;
++    }
++
++  /* Check if the call to open is the same to the last disk already opened */
++  if (last_devpath && !grub_strcmp(op->open_path,last_devpath))
++  {
++      goto finish;
++  }
++
++ /* If not, we need to close the previous disk and open the new one */
++  else {
++    if (last_ihandle){
++        grub_ieee1275_close (last_ihandle);
++    }
++    last_ihandle = 0;
++    last_devpath = NULL;
++
++    grub_ieee1275_open (op->open_path, &last_ihandle);
++    if (! last_ihandle)
++      return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
++    last_devpath = op->open_path;
++  }
++
+   if (grub_ieee1275_finddevice (devpath, &dev))
+     {
+       grub_free (devpath);
+@@ -491,25 +521,18 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
+       return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a block device");
+     }
+ 
++
++  finish:
+   /* XXX: There is no property to read the number of blocks.  There
+      should be a property `#blocks', but it is not there.  Perhaps it
+      is possible to use seek for this.  */
+   disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN;
+ 
+   {
+-    struct ofdisk_hash_ent *op;
+-    op = ofdisk_hash_find (devpath);
+-    if (!op)
+-      op = ofdisk_hash_add (devpath, NULL);
+-    if (!op)
+-      {
+-        grub_free (devpath);
+-        return grub_errno;
+-      }
+     disk->id = (unsigned long) op;
+     disk->data = op->open_path;
+ 
+-    err = grub_ofdisk_get_block_size (devpath, &block_size, op);
++    err = grub_ofdisk_get_block_size (&block_size, op);
+     if (err)
+       {
+         grub_free (devpath);
+@@ -532,13 +555,6 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
+ static void
+ grub_ofdisk_close (grub_disk_t disk)
+ {
+-  if (disk->data == last_devpath)
+-    {
+-      if (last_ihandle)
+-	grub_ieee1275_close (last_ihandle);
+-      last_ihandle = 0;
+-      last_devpath = NULL;
+-    }
+   disk->data = 0;
+ }
+ 
+@@ -685,7 +701,7 @@ grub_ofdisk_init (void)
+ }
+ 
+ static grub_err_t
+-grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size,
++grub_ofdisk_get_block_size (grub_uint32_t *block_size,
+ 			    struct ofdisk_hash_ent *op)
+ {
+   struct size_args_ieee1275
+@@ -698,16 +714,6 @@ grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size,
+       grub_ieee1275_cell_t size2;
+     } args_ieee1275;
+ 
+-  if (last_ihandle)
+-    grub_ieee1275_close (last_ihandle);
+-
+-  last_ihandle = 0;
+-  last_devpath = NULL;
+-
+-  grub_ieee1275_open (device, &last_ihandle);
+-  if (! last_ihandle)
+-    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
+-
+   *block_size = 0;
+ 
+   if (op->block_size_fails >= 2)
diff --git a/SOURCES/0152-ieee1275-powerpc-implements-fibre-channel-discovery-.patch b/SOURCES/0152-ieee1275-powerpc-implements-fibre-channel-discovery-.patch
new file mode 100644
index 0000000..04c5c32
--- /dev/null
+++ b/SOURCES/0152-ieee1275-powerpc-implements-fibre-channel-discovery-.patch
@@ -0,0 +1,90 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Diego Domingos <diegodo@br.ibm.com>
+Date: Mon, 14 Dec 2020 17:45:28 +0100
+Subject: [PATCH] ieee1275/powerpc: implements fibre channel discovery for
+ ofpathname
+
+grub-ofpathname doesn't work with fibre channel because there is no
+function currently implemented for it.
+This patch enables it by prividing a function that looks for the port
+name, building the entire path for OF devices.
+
+Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
+---
+ grub-core/osdep/linux/ofpath.c | 49 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 49 insertions(+)
+
+diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c
+index a6153d3595..0f5d54e9f2 100644
+--- a/grub-core/osdep/linux/ofpath.c
++++ b/grub-core/osdep/linux/ofpath.c
+@@ -350,6 +350,38 @@ of_path_of_ide(const char *sys_devname __attribute__((unused)), const char *devi
+   return ret;
+ }
+ 
++
++static void
++of_fc_port_name(const char *path, const char *subpath, char *port_name)
++{
++  char *bname, *basepath, *p;
++  int fd;
++
++  bname = xmalloc(sizeof(char)*150);
++  basepath = xmalloc(strlen(path));
++
++  /* Generate the path to get port name information from the drive */
++  strncpy(basepath,path,subpath-path);
++  basepath[subpath-path-1] = '\0';
++  p = get_basename(basepath);
++  snprintf(bname,sizeof(char)*150,"%s/fc_transport/%s/port_name",basepath,p);
++
++  /* Read the information from the port name */
++  fd = open (bname, O_RDONLY);
++  if (fd < 0)
++    grub_util_error (_("cannot open `%s': %s"), bname, strerror (errno));
++
++  if (read(fd,port_name,sizeof(char)*19) < 0)
++    grub_util_error (_("cannot read `%s': %s"), bname, strerror (errno));
++
++  sscanf(port_name,"0x%s",port_name);
++  
++  close(fd);
++
++  free(bname);
++  free(basepath);
++}
++
+ #ifdef __sparc__
+ static char *
+ of_path_of_nvme(const char *sys_devname __attribute__((unused)),
+@@ -577,6 +609,16 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
+   digit_string = trailing_digits (device);
+   if (strncmp (of_path, "/vdevice/", sizeof ("/vdevice/") - 1) == 0)
+     {
++      if(strstr(of_path,"vfc-client"))
++      {
++	char * port_name = xmalloc(sizeof(char)*17);
++	of_fc_port_name(sysfs_path, p, port_name);
++	
++	snprintf(disk,sizeof(disk),"/%s@%s", disk_name, port_name);
++	free(port_name);
++      }
++      else
++      {
+       unsigned long id = 0x8000 | (tgt << 8) | (bus << 5) | lun;
+       if (*digit_string == '\0')
+ 	{
+@@ -590,6 +632,13 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
+ 	  snprintf(disk, sizeof (disk),
+ 		   "/%s@%04lx000000000000:%c", disk_name, id, 'a' + (part - 1));
+ 	}
++	}
++    } else if (strstr(of_path,"fibre-channel")||(strstr(of_path,"vfc-client"))){
++	char * port_name = xmalloc(sizeof(char)*17);
++	of_fc_port_name(sysfs_path, p, port_name);
++	
++	snprintf(disk,sizeof(disk),"/%s@%s", disk_name, port_name);
++	free(port_name);
+     }
+   else
+     {
diff --git a/SOURCES/0152-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch b/SOURCES/0152-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch
deleted file mode 100644
index 747773d..0000000
--- a/SOURCES/0152-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Sat, 16 May 2020 11:33:18 +0200
-Subject: [PATCH] tpm: Don't propagate TPM measurement errors to the verifiers
- layer
-
-Currently if the EFI firmware fails to do a TPM measurement for a file,
-the error will be propagated to the verifiers framework and so opening
-the file will not succeed.
-
-This mean that buggy firmwares will prevent the system to boot since the
-loader won't be able to open any file. But failing to do TPM measurements
-shouldn't be a fatal error and the system should still be able to boot.
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/commands/tpm.c | 14 +++++++-------
- 1 file changed, 7 insertions(+), 7 deletions(-)
-
-diff --git a/grub-core/commands/tpm.c b/grub-core/commands/tpm.c
-index 2052c36eaba..e287d042e6b 100644
---- a/grub-core/commands/tpm.c
-+++ b/grub-core/commands/tpm.c
-@@ -42,7 +42,8 @@ grub_tpm_verify_init (grub_file_t io,
- static grub_err_t
- grub_tpm_verify_write (void *context, void *buf, grub_size_t size)
- {
--  return grub_tpm_measure (buf, size, GRUB_BINARY_PCR, context);
-+  grub_tpm_measure (buf, size, GRUB_BINARY_PCR, context);
-+  return GRUB_ERR_NONE;
- }
- 
- static grub_err_t
-@@ -50,7 +51,6 @@ grub_tpm_verify_string (char *str, enum grub_verify_string_type type)
- {
-   const char *prefix = NULL;
-   char *description;
--  grub_err_t status;
- 
-   switch (type)
-     {
-@@ -66,15 +66,15 @@ grub_tpm_verify_string (char *str, enum grub_verify_string_type type)
-     }
-   description = grub_malloc (grub_strlen (str) + grub_strlen (prefix) + 1);
-   if (!description)
--    return grub_errno;
-+    return GRUB_ERR_NONE;
-   grub_memcpy (description, prefix, grub_strlen (prefix));
-   grub_memcpy (description + grub_strlen (prefix), str,
- 	       grub_strlen (str) + 1);
--  status =
--    grub_tpm_measure ((unsigned char *) str, grub_strlen (str),
--		      GRUB_STRING_PCR, description);
-+
-+  grub_tpm_measure ((unsigned char *) str, grub_strlen (str), GRUB_STRING_PCR,
-+                    description);
-   grub_free (description);
--  return status;
-+  return GRUB_ERR_NONE;
- }
- 
- struct grub_file_verifier grub_tpm_verifier = {
diff --git a/SOURCES/0153-ieee1275-powerpc-enables-device-mapper-discovery.patch b/SOURCES/0153-ieee1275-powerpc-enables-device-mapper-discovery.patch
new file mode 100644
index 0000000..85dbde7
--- /dev/null
+++ b/SOURCES/0153-ieee1275-powerpc-enables-device-mapper-discovery.patch
@@ -0,0 +1,106 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Diego Domingos <diegodo@br.ibm.com>
+Date: Mon, 14 Dec 2020 17:47:16 +0100
+Subject: [PATCH] ieee1275/powerpc: enables device mapper discovery
+
+this patch enables the device mapper discovery on ofpath.c. Currently,
+when we are dealing with a device like /dev/dm-* the ofpath returns null
+since there is no function implemented to handle this case.
+
+This patch implements a function that will look into /sys/block/dm-*
+devices and search recursively inside slaves directory to find the root
+disk.
+
+Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
+---
+ grub-core/osdep/linux/ofpath.c | 64 +++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 63 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c
+index 0f5d54e9f2..cc849d9c94 100644
+--- a/grub-core/osdep/linux/ofpath.c
++++ b/grub-core/osdep/linux/ofpath.c
+@@ -37,6 +37,7 @@
+ #include <fcntl.h>
+ #include <errno.h>
+ #include <ctype.h>
++#include <dirent.h>
+ 
+ #ifdef __sparc__
+ typedef enum
+@@ -755,13 +756,74 @@ strip_trailing_digits (const char *p)
+   return new;
+ }
+ 
++static char *
++get_slave_from_dm(const char * device){
++  char *curr_device, *tmp;
++  char *directory;
++  char *ret = NULL;
++
++  directory = grub_strdup (device);
++  tmp = get_basename(directory);
++  curr_device = grub_strdup (tmp);
++  *tmp = '\0';
++
++  /* Recursively check for slaves devices so we can find the root device */
++  while ((curr_device[0] == 'd') && (curr_device[1] == 'm') && (curr_device[2] == '-')){
++    DIR *dp;
++    struct dirent *ep;
++    char* device_path;
++
++    device_path = grub_xasprintf ("/sys/block/%s/slaves", curr_device);
++    dp = opendir(device_path);
++    free(device_path);
++
++    if (dp != NULL)
++    {
++      ep = readdir (dp);
++      while (ep != NULL){
++
++	/* avoid some system directories */
++        if (!strcmp(ep->d_name,"."))
++            goto next_dir;
++        if (!strcmp(ep->d_name,".."))
++            goto next_dir;
++
++	free (curr_device);
++	free (ret);
++	curr_device = grub_strdup (ep->d_name);
++	ret = grub_xasprintf ("%s%s", directory, curr_device);
++	break;
++
++        next_dir:
++         ep = readdir (dp);
++         continue;
++      }
++      closedir (dp);
++    }
++    else
++      grub_util_warn (_("cannot open directory `%s'"), device_path);
++  }
++
++  free (directory);
++  free (curr_device);
++
++  return ret;
++}
++
+ char *
+ grub_util_devname_to_ofpath (const char *sys_devname)
+ {
+-  char *name_buf, *device, *devnode, *devicenode, *ofpath;
++  char *name_buf, *device, *devnode, *devicenode, *ofpath, *realname;
+ 
+   name_buf = xrealpath (sys_devname);
+ 
++  realname = get_slave_from_dm (name_buf);
++  if (realname)
++    {
++      free (name_buf);
++      name_buf = realname;
++    }
++
+   device = get_basename (name_buf);
+   devnode = strip_trailing_digits (name_buf);
+   devicenode = strip_trailing_digits (device);
diff --git a/SOURCES/0153-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch b/SOURCES/0153-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch
deleted file mode 100644
index 825d0f7..0000000
--- a/SOURCES/0153-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Tue, 26 May 2020 16:59:28 +0200
-Subject: [PATCH] x86-efi: Reduce maximum bounce buffer size to 16 MiB
-
-The EFI linux loader allocates a bounce buffer to copy the initrd since in
-some machines doing DMA on addresses above 4GB is not possible during EFI.
-
-But the verifiers framework also allocates a buffer to copy the initrd in
-its grub_file_open() handler. It does this since the data to verify has to
-be passed as a single chunk to modules that use the verifiers framework.
-
-If the initrd image size is big there may not be enough memory in the heap
-to allocate two buffers of that size. This causes an allocation failure in
-the verifiers framework and leads to the initrd not being read.
-
-To prevent these allocation failures, let's reduce the maximum size of the
-bounce buffer used in the EFI loader. Since the data read can be copied to
-the actual initrd address in multilple chunks.
-
-Resolves: rhbz#1838633
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/loader/i386/efi/linux.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index 6bc18d5aef5..15d40d6e35b 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -144,7 +144,7 @@ grub_linuxefi_unload (void)
-   return GRUB_ERR_NONE;
- }
- 
--#define BOUNCE_BUFFER_MAX 0x10000000ull
-+#define BOUNCE_BUFFER_MAX 0x1000000ull
- 
- static grub_ssize_t
- read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len)
diff --git a/SOURCES/0154-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch b/SOURCES/0154-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch
new file mode 100644
index 0000000..f938fd1
--- /dev/null
+++ b/SOURCES/0154-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch
@@ -0,0 +1,245 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Fri, 18 Dec 2020 15:39:26 +0100
+Subject: [PATCH] Add 'at_keyboard_fallback_set' var to force the set manually
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This seems required with HP DL380p Gen 8 systems.
+Indeed, with this system, we can see the following sequence:
+
+1. controller is queried to get current configuration (returns 0x30 which is quite standard)
+2. controller is queried to get the current keyboard set in used, using code 0xf0 (first part)
+3. controller answers with 0xfa which means "ACK" (== ok)
+4. then we send "0" to tell "we want to know which set your are supporting"
+5. controller answers with 0xfa ("ACK")
+6. controller should then give us 1, 2, 3 or 0x43, 0x41, 0x3f, but here it gives us 0xfe which means "NACK"
+
+Since there seems no way to determine the current set, and in fact the
+controller expects set2 to be used, we need to rely on an environment
+variable.
+Everything has been tested on this system: using 0xFE (resend command),
+making sure we wait for ACK in the 2 steps "write_mode", etc.
+
+Below is litterature I used to come up with "there is no other
+solution":
+- https://wiki.osdev.org/%228042%22_PS/2_Controller
+- http://www-ug.eecg.toronto.edu/msl/nios_devices/datasheets/PS2%20Keyboard%20Protocol.htm
+- http://www.s100computers.com/My%20System%20Pages/MSDOS%20Board/PC%20Keyboard.pdf
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/term/at_keyboard.c | 121 ++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 96 insertions(+), 25 deletions(-)
+
+diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c
+index 2601438260..dac0f946fe 100644
+--- a/grub-core/term/at_keyboard.c
++++ b/grub-core/term/at_keyboard.c
+@@ -31,6 +31,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ static grub_uint8_t grub_keyboard_controller_orig;
+ static grub_uint8_t grub_keyboard_orig_set;
+ struct grub_ps2_state ps2_state;
++static int fallback_set;
+ 
+ static int ping_sent;
+ 
+@@ -76,6 +77,8 @@ at_command (grub_uint8_t data)
+ 	break;
+       return 0;
+     }
++  if (i == GRUB_AT_TRIES)
++    grub_dprintf ("atkeyb", "at_command() timed out! (stopped after %d tries)\n", i);
+   return (i != GRUB_AT_TRIES);
+ }
+ 
+@@ -105,6 +108,21 @@ grub_keyboard_controller_read (void)
+ 
+ #endif
+ 
++static int
++resend_last_result (void)
++{
++  grub_uint8_t ret;
++  keyboard_controller_wait_until_ready ();
++  grub_dprintf ("atkeyb", "resend_last_result: sending 0xfe\n");
++  grub_outb (0xfe, KEYBOARD_REG_DATA);
++  ret = wait_ack ();
++  grub_dprintf ("atkeyb", "resend_last_result: wait_ack() returned 0x%x\n", ret);
++  keyboard_controller_wait_until_ready ();
++  ret = grub_inb (KEYBOARD_REG_DATA);
++  grub_dprintf ("atkeyb", "resend_last_result: read 0x%x from controller\n", ret);
++  return ret;
++}
++
+ static int
+ write_mode (int mode)
+ {
+@@ -113,11 +131,14 @@ write_mode (int mode)
+     {
+       grub_uint8_t ack;
+       keyboard_controller_wait_until_ready ();
++      grub_dprintf ("atkeyb", "write_mode: sending 0xf0\n");
+       grub_outb (0xf0, KEYBOARD_REG_DATA);
+       keyboard_controller_wait_until_ready ();
++      grub_dprintf ("atkeyb", "write_mode: sending mode %d\n", mode);
+       grub_outb (mode, KEYBOARD_REG_DATA);
+       keyboard_controller_wait_until_ready ();
+       ack = wait_ack ();
++      grub_dprintf ("atkeyb", "write_mode: wait_ack() returned 0x%x\n", ack);
+       if (ack == GRUB_AT_NACK)
+ 	continue;
+       if (ack == GRUB_AT_ACK)
+@@ -125,6 +146,9 @@ write_mode (int mode)
+       return 0;
+     }
+ 
++  if (i == GRUB_AT_TRIES)
++    grub_dprintf ("atkeyb", "write_mode() timed out! (stopped after %d tries)\n", i);
++
+   return (i != GRUB_AT_TRIES);
+ }
+ 
+@@ -132,31 +156,66 @@ static int
+ query_mode (void)
+ {
+   grub_uint8_t ret;
++  grub_uint64_t endtime;
++  unsigned i;
+   int e;
++  char *envvar;
+ 
+-  e = write_mode (0);
+-  if (!e) {
+-    grub_dprintf("atkeyb", "query_mode: write_mode(0) failed\n");
+-    return 0;
+-  }
++  for (i = 0; i < GRUB_AT_TRIES; i++) {
++    grub_dprintf ("atkeyb", "query_mode: sending command to controller\n");
++    e = write_mode (0);
++    if (!e) {
++      grub_dprintf ("atkeyb", "query_mode: write_mode(0) failed\n");
++      return 0;
++    }
+ 
+-  do {
+-    keyboard_controller_wait_until_ready ();
+-    ret = grub_inb (KEYBOARD_REG_DATA);
+-  } while (ret == GRUB_AT_ACK);
+-  /* QEMU translates the set even in no-translate mode.  */
+-  if (ret == 0x43 || ret == 1) {
+-    grub_dprintf("atkeyb", "query_mode: returning 1 (ret=0x%x)\n", ret);
+-    return 1;
+-  }
+-  if (ret == 0x41 || ret == 2) {
+-    grub_dprintf("atkeyb", "query_mode: returning 2 (ret=0x%x)\n", ret);
+-    return 2;
++    endtime = grub_get_time_ms () + 20;
++    do {
++      keyboard_controller_wait_until_ready ();
++      ret = grub_inb (KEYBOARD_REG_DATA);
++      grub_dprintf ("atkeyb", "query_mode/loop: read 0x%x from controller\n", ret);
++    } while ((ret == GRUB_AT_ACK || ret == GRUB_AT_NACK) && grub_get_time_ms () < endtime);
++    if (ret == 0xfe) {
++      grub_dprintf ("atkeyb", "query_mode: asking controller to resend last result\n");
++      ret = resend_last_result();
++      grub_dprintf ("atkeyb", "query_mode: read 0x%x from controller\n", ret);
++    }
++    /* QEMU translates the set even in no-translate mode.  */
++    if (ret == 0x43 || ret == 1) {
++      grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 1\n", ret);
++      return 1;
++    }
++    if (ret == 0x41 || ret == 2) {
++      grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 2\n", ret);
++      return 2;
++    }
++    if (ret == 0x3f || ret == 3) {
++      grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 3\n", ret);
++      return 3;
++    }
++    grub_dprintf ("atkeyb", "query_mode: controller returned unexpected value 0x%x, retrying\n", ret);
+   }
+-  if (ret == 0x3f || ret == 3) {
+-    grub_dprintf("atkeyb", "query_mode: returning 3 (ret=0x%x)\n", ret);
+-    return 3;
++
++  /*
++   * Falling here means we tried querying and the controller returned something
++   * we don't understand, try to use 'at_keyboard_fallback_set' if it exists,
++   * otherwise return 0.
++   */
++  envvar = grub_env_get ("at_keyboard_fallback_set");
++  if (envvar) {
++    fallback_set = grub_strtoul (envvar, 0, 10);
++    if ((grub_errno) || (fallback_set < 1) || (fallback_set > 3)) {
++      grub_dprintf ("atkeyb", "WARNING: ignoring unexpected value '%s' for '%s' variable\n",
++		    envvar, "at_keyboard_fallback_set");
++      fallback_set = 0;
++    } else {
++      grub_dprintf ("atkeyb", "query_mode: '%s' specified in environment, returning %d\n",
++		    "at_keyboard_fallback_set", fallback_set);
++    }
++    return fallback_set;
+   }
++  grub_dprintf ("atkeyb", "WARNING: no '%s' specified in environment, returning 0\n",
++		"at_keyboard_fallback_set");
+   return 0;
+ }
+ 
+@@ -165,14 +224,25 @@ set_scancodes (void)
+ {
+   /* You must have visited computer museum. Keyboard without scancode set
+      knowledge. Assume XT. */
+-  if (!grub_keyboard_orig_set)
+-    {
+-      grub_dprintf ("atkeyb", "No sets support assumed\n");
+-      ps2_state.current_set = 1;
++  if (!grub_keyboard_orig_set) {
++    if (fallback_set) {
++      grub_dprintf ("atkeyb", "No sets support assumed but set forced to %d\n", fallback_set);
++      ps2_state.current_set = fallback_set;
+       return;
+     }
++    grub_dprintf ("atkeyb", "No sets support assumed, forcing to set 1\n");
++    ps2_state.current_set = 1;
++    return;
++  }
+ 
+ #if !USE_SCANCODE_SET
++  if (fallback_set) {
++    grub_dprintf ("atkeyb", "queried set is %d but set forced to %d\n",
++		  grub_keyboard_orig_set, fallback_set);
++    ps2_state.current_set = fallback_set;
++    return;
++  }
++
+   if ((grub_keyboard_controller_orig & KEYBOARD_AT_TRANSLATE) == KEYBOARD_AT_TRANSLATE) {
+     grub_dprintf ("atkeyb", "queried set is %d but keyboard in Translate mode, so actually in set 1\n", grub_keyboard_orig_set);
+     ps2_state.current_set = 1;
+@@ -261,6 +331,7 @@ grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused)))
+ static void
+ grub_keyboard_controller_init (void)
+ {
++  grub_dprintf ("atkeyb", "initializing the controller\n");
+   ps2_state.at_keyboard_status = 0;
+   /* Drain input buffer. */
+   while (1)
+@@ -282,6 +353,7 @@ grub_keyboard_controller_init (void)
+   grub_keyboard_controller_orig = grub_keyboard_controller_read ();
+   grub_dprintf ("atkeyb", "grub_keyboard_controller_orig = 0x%x\n", grub_keyboard_controller_orig);
+   grub_keyboard_orig_set = query_mode ();
++  grub_dprintf ("atkeyb", "grub_keyboard_orig_set = %d\n", grub_keyboard_orig_set);
+ #endif
+   set_scancodes ();
+   keyboard_controller_led (ps2_state.led_status);
+@@ -329,7 +401,6 @@ grub_at_restore_hw (void)
+   return GRUB_ERR_NONE;
+ }
+ 
+-
+ static struct grub_term_input grub_at_keyboard_term =
+   {
+     .name = "at_keyboard",
diff --git a/SOURCES/0154-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch b/SOURCES/0154-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch
deleted file mode 100644
index 97d2e06..0000000
--- a/SOURCES/0154-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Tue, 2 Jun 2020 13:25:01 +0200
-Subject: [PATCH] http: Prepend prefix when the HTTP path is relative as done
- in efi/http
-
-There are two different HTTP drivers that can be used when requesting an
-HTTP resource: the efi/http that uses the EFI_HTTP_PROTOCOL and the http
-that uses GRUB's HTTP and TCP/IP implementation.
-
-The efi/http driver appends a prefix that is defined in the variable
-http_path, but the http driver doesn't.
-
-So using this driver and attempting to fetch a resource using a relative
-path fails.
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/net/http.c | 9 ++++++++-
- 1 file changed, 8 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/net/http.c b/grub-core/net/http.c
-index b52b558d631..7f878b56157 100644
---- a/grub-core/net/http.c
-+++ b/grub-core/net/http.c
-@@ -501,13 +501,20 @@ http_open (struct grub_file *file, const char *filename)
- {
-   grub_err_t err;
-   struct http_data *data;
-+  const char *http_path;
- 
-   data = grub_zalloc (sizeof (*data));
-   if (!data)
-     return grub_errno;
-   file->size = GRUB_FILE_SIZE_UNKNOWN;
- 
--  data->filename = grub_strdup (filename);
-+  /* If path is relative, prepend http_path */
-+  http_path = grub_env_get ("http_path");
-+  if (http_path && filename[0] != '/')
-+    data->filename = grub_xasprintf ("%s/%s", http_path, filename);
-+  else
-+    data->filename = grub_strdup (filename);
-+
-   if (!data->filename)
-     {
-       grub_free (data);
diff --git a/SOURCES/0155-Add-suport-for-signing-grub-with-an-appended-signatu.patch b/SOURCES/0155-Add-suport-for-signing-grub-with-an-appended-signatu.patch
new file mode 100644
index 0000000..81660d4
--- /dev/null
+++ b/SOURCES/0155-Add-suport-for-signing-grub-with-an-appended-signatu.patch
@@ -0,0 +1,309 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Rashmica Gupta <rashmica.g@gmail.com>
+Date: Thu, 11 Jun 2020 11:26:23 +1000
+Subject: [PATCH] Add suport for signing grub with an appended signature
+
+Add infrastructure to allow firmware to verify the integrity of grub
+by use of a Linux-kernel-module-style appended signature. We initially
+target powerpc-ieee1275, but the code should be extensible to other
+platforms.
+
+Usually these signatures are appended to a file without modifying the
+ELF file itself. (This is what the 'sign-file' tool does, for example.)
+The verifier loads the signed file from the file system and looks at the
+end of the file for the appended signature. However, on powerpc-ieee1275
+platforms, the bootloader is often stored directly in the PReP partition
+as raw bytes without a file-system. This makes determining the location
+of an appended signature more difficult.
+
+To address this, we add a new ELF note.
+
+The name field of shall be the string "Appended-Signature", zero-padded
+to 4 byte alignment. The type field shall be 0x41536967 (the ASCII values
+for the string "ASig"). It must be the final section in the ELF binary.
+
+The description shall contain the appended signature structure as defined
+by the Linux kernel. The description will also be padded to be a multiple
+of 4 bytes. The padding shall be added before the appended signature
+structure (not at the end) so that the final bytes of a signed ELF file
+are the appended signature magic.
+
+A subsequent patch documents how to create a grub core.img validly signed
+under this scheme.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
+---
+ util/grub-install-common.c  | 18 ++++++++++++++----
+ util/grub-mkimage.c         | 15 +++++++++++++--
+ util/grub-mkimagexx.c       | 39 ++++++++++++++++++++++++++++++++++++++-
+ util/mkimage.c              | 13 +++++++------
+ include/grub/util/install.h |  8 ++++++--
+ include/grub/util/mkimage.h |  4 ++--
+ 6 files changed, 80 insertions(+), 17 deletions(-)
+
+diff --git a/util/grub-install-common.c b/util/grub-install-common.c
+index 4e212e690c..a74fee16e2 100644
+--- a/util/grub-install-common.c
++++ b/util/grub-install-common.c
+@@ -461,10 +461,12 @@ static size_t npubkeys;
+ static char *sbat;
+ static int disable_shim_lock;
+ static grub_compression_t compression;
++static size_t appsig_size;
+ 
+ int
+ grub_install_parse (int key, char *arg)
+ {
++  const char *end;
+   switch (key)
+     {
+     case 'C':
+@@ -562,6 +564,12 @@ grub_install_parse (int key, char *arg)
+       grub_util_error (_("Unrecognized compression `%s'"), arg);
+     case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE:
+       return 1;
++    case GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE:
++      grub_errno = 0;
++      appsig_size = grub_strtol(arg, &end, 10);
++      if (grub_errno)
++        return 0;
++      return 1;
+     default:
+       return 0;
+     }
+@@ -661,11 +669,13 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
+ 		  " --output '%s' "
+ 		  " --dtb '%s' "
+ 		  "--sbat '%s' "
+-		  "--format '%s' --compression '%s' %s %s %s\n",
++		  "--format '%s' --compression '%s' "
++		  "--appended-signature-size %zu %s %s %s\n",
+ 		  dir, prefix,
+ 		  outname, dtb ? : "", sbat ? : "", mkimage_target,
+-		  compnames[compression], note ? "--note" : "",
+-		  disable_shim_lock ? "--disable-shim-lock" : "", s);
++		  compnames[compression], appsig_size,
++		  disable_shim_lock ? "--disable-shim-lock" : "",
++		  note ? "--note" : "", s);
+   free (s);
+ 
+   tgt = grub_install_get_image_target (mkimage_target);
+@@ -675,7 +685,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
+   grub_install_generate_image (dir, prefix, fp, outname,
+ 			       modules.entries, memdisk_path,
+ 			       pubkeys, npubkeys, config_path, tgt,
+-			       note, compression, dtb, sbat,
++			       note, appsig_size, compression, dtb, sbat,
+ 			       disable_shim_lock);
+   while (dc--)
+     grub_install_pop_module ();
+diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
+index c0d5599370..8a53310548 100644
+--- a/util/grub-mkimage.c
++++ b/util/grub-mkimage.c
+@@ -84,6 +84,7 @@ static struct argp_option options[] = {
+   {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0},
+   {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0},
+   {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
++  {"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0},
+   { 0, 0, 0, 0, 0, 0 }
+ };
+ 
+@@ -128,6 +129,7 @@ struct arguments
+   char *sbat;
+   int note;
+   int disable_shim_lock;
++  size_t appsig_size;
+   const struct grub_install_image_target_desc *image_target;
+   grub_compression_t comp;
+ };
+@@ -138,6 +140,7 @@ argp_parser (int key, char *arg, struct argp_state *state)
+   /* Get the input argument from argp_parse, which we
+      know is a pointer to our arguments structure. */
+   struct arguments *arguments = state->input;
++  const char* end;
+ 
+   switch (key)
+     {
+@@ -170,6 +173,13 @@ argp_parser (int key, char *arg, struct argp_state *state)
+       arguments->note = 1;
+       break;
+ 
++    case 'S':
++      grub_errno = 0;
++      arguments->appsig_size = grub_strtol(arg, &end, 10);
++      if (grub_errno)
++        return 0;
++      break;
++
+     case 'm':
+       if (arguments->memdisk)
+ 	free (arguments->memdisk);
+@@ -324,8 +334,9 @@ main (int argc, char *argv[])
+ 			       arguments.memdisk, arguments.pubkeys,
+ 			       arguments.npubkeys, arguments.config,
+ 			       arguments.image_target, arguments.note,
+-			       arguments.comp, arguments.dtb,
+-			       arguments.sbat, arguments.disable_shim_lock);
++			       arguments.appsig_size, arguments.comp,
++			       arguments.dtb, arguments.sbat,
++			       arguments.disable_shim_lock);
+ 
+   if (grub_util_file_sync (fp) < 0)
+     grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout",
+diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
+index d78fa3e533..393119486d 100644
+--- a/util/grub-mkimagexx.c
++++ b/util/grub-mkimagexx.c
+@@ -84,6 +84,15 @@ struct grub_ieee1275_note
+   struct grub_ieee1275_note_desc descriptor;
+ };
+ 
++#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature"
++#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */
++
++struct grub_appended_signature_note
++{
++  Elf32_Nhdr header;
++  char name[ALIGN_UP(sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 4)];
++};
++
+ #define GRUB_XEN_NOTE_NAME "Xen"
+ 
+ struct fixup_block_list
+@@ -207,7 +216,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr)
+ 
+ void
+ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target,
+-				    int note, char **core_img, size_t *core_size,
++				    int note, size_t appsig_size, char **core_img, size_t *core_size,
+ 				    Elf_Addr target_addr,
+ 				    struct grub_mkimage_layout *layout)
+ {
+@@ -221,6 +230,12 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
+   int shnum = 4;
+   int string_size = sizeof (".text") + sizeof ("mods") + 1;
+ 
++  if (appsig_size)
++    {
++      phnum++;
++      footer_size += ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4);
++    }
++
+   if (image_target->id != IMAGE_LOONGSON_ELF)
+     phnum += 2;
+ 
+@@ -484,6 +499,28 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
+       phdr->p_offset = grub_host_to_target32 (header_size + program_size);
+     }
+ 
++  if (appsig_size) {
++    int note_size = ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4);
++    struct grub_appended_signature_note *note_ptr = (struct grub_appended_signature_note *)
++      (elf_img + program_size + header_size + (note ? sizeof (struct grub_ieee1275_note) : 0));
++
++    note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME));
++    /* needs to sit at the end, so we round this up and sign some zero padding */
++    note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP(appsig_size, 4));
++    note_ptr->header.n_type = grub_host_to_target32 (GRUB_APPENDED_SIGNATURE_NOTE_TYPE);
++    strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME);
++
++    phdr++;
++    phdr->p_type = grub_host_to_target32 (PT_NOTE);
++    phdr->p_flags = grub_host_to_target32 (PF_R);
++    phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
++    phdr->p_vaddr = 0;
++    phdr->p_paddr = 0;
++    phdr->p_filesz = grub_host_to_target32 (note_size);
++    phdr->p_memsz = 0;
++    phdr->p_offset = grub_host_to_target32 (header_size + program_size + (note ? sizeof (struct grub_ieee1275_note) : 0));
++  }
++
+   {
+     char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)
+ 		       + shnum * sizeof (*shdr));
+diff --git a/util/mkimage.c b/util/mkimage.c
+index a26cf76f72..bab1227601 100644
+--- a/util/mkimage.c
++++ b/util/mkimage.c
+@@ -869,8 +869,9 @@ grub_install_generate_image (const char *dir, const char *prefix,
+ 			     char *memdisk_path, char **pubkey_paths,
+ 			     size_t npubkeys, char *config_path,
+ 			     const struct grub_install_image_target_desc *image_target,
+-			     int note, grub_compression_t comp, const char *dtb_path,
+-			     const char *sbat_path, int disable_shim_lock)
++			     int note, size_t appsig_size, grub_compression_t comp,
++			     const char *dtb_path, const char *sbat_path,
++			     int disable_shim_lock)
+ {
+   char *kernel_img, *core_img;
+   size_t total_module_size, core_size;
+@@ -1773,11 +1774,11 @@ grub_install_generate_image (const char *dir, const char *prefix,
+ 	else
+ 	  target_addr = image_target->link_addr;
+ 	if (image_target->voidp_sizeof == 4)
+-	  grub_mkimage_generate_elf32 (image_target, note, &core_img, &core_size,
+-				       target_addr, &layout);
++	  grub_mkimage_generate_elf32 (image_target, note, appsig_size, &core_img,
++				       &core_size, target_addr, &layout);
+ 	else
+-	  grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size,
+-				       target_addr, &layout);
++	  grub_mkimage_generate_elf64 (image_target, note, appsig_size, &core_img,
++				       &core_size, target_addr, &layout);
+       }
+       break;
+     }
+diff --git a/include/grub/util/install.h b/include/grub/util/install.h
+index 7df3191f47..cf4531e02b 100644
+--- a/include/grub/util/install.h
++++ b/include/grub/util/install.h
+@@ -67,6 +67,9 @@
+       N_("SBAT metadata"), 0 },						\
+   { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0,	\
+       N_("disable shim_lock verifier"), 0 },				\
++  { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\
++    "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \
++    1},                                                                 \
+   { "verbose", 'v', 0, 0,						\
+     N_("print verbose messages."), 1 }
+ 
+@@ -128,7 +131,8 @@ enum grub_install_options {
+   GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS,
+   GRUB_INSTALL_OPTIONS_DTB,
+   GRUB_INSTALL_OPTIONS_SBAT,
+-  GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK
++  GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK,
++  GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE
+ };
+ 
+ extern char *grub_install_source_directory;
+@@ -188,7 +192,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
+ 			     size_t npubkeys,
+ 			     char *config_path,
+ 			     const struct grub_install_image_target_desc *image_target,
+-			     int note,
++			     int note, size_t appsig_size,
+ 			     grub_compression_t comp, const char *dtb_file,
+ 			     const char *sbat_path, const int disable_shim_lock);
+ 
+diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h
+index 3819a67441..6f1da89b9b 100644
+--- a/include/grub/util/mkimage.h
++++ b/include/grub/util/mkimage.h
+@@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path,
+ 			   const struct grub_install_image_target_desc *image_target);
+ void
+ grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target,
+-			     int note, char **core_img, size_t *core_size,
++			     int note, size_t appsig_size, char **core_img, size_t *core_size,
+ 			     Elf32_Addr target_addr,
+ 			     struct grub_mkimage_layout *layout);
+ void
+ grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target,
+-			     int note, char **core_img, size_t *core_size,
++			     int note, size_t appsig_size, char **core_img, size_t *core_size,
+ 			     Elf64_Addr target_addr,
+ 			     struct grub_mkimage_layout *layout);
+ 
diff --git a/SOURCES/0155-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch b/SOURCES/0155-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch
deleted file mode 100644
index 1657d7a..0000000
--- a/SOURCES/0155-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Wed, 16 Jan 2019 13:21:46 -0500
-Subject: [PATCH] Fix a missing return in efi-export-env and efi-load-env
- commands
-
-Somewhere along the way this got mis-merged to include a return without
-a value.  Fix it up.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/commands/efi/env.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/grub-core/commands/efi/env.c b/grub-core/commands/efi/env.c
-index cbd13e03e81..977edb6b065 100644
---- a/grub-core/commands/efi/env.c
-+++ b/grub-core/commands/efi/env.c
-@@ -149,6 +149,8 @@ grub_efi_load_env(grub_command_t cmd __attribute__ ((unused)),
- 
-   grub_envblk_iterate (envblk, NULL, set_var);
-   grub_free (envblk_s.buf);
-+
-+  return GRUB_ERR_NONE;
- }
- 
- static grub_command_t export_cmd, loadenv_cmd;
diff --git a/SOURCES/0156-docs-grub-Document-signing-grub-under-UEFI.patch b/SOURCES/0156-docs-grub-Document-signing-grub-under-UEFI.patch
new file mode 100644
index 0000000..f2b5c17
--- /dev/null
+++ b/SOURCES/0156-docs-grub-Document-signing-grub-under-UEFI.patch
@@ -0,0 +1,61 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Sat, 15 Aug 2020 02:00:57 +1000
+Subject: [PATCH] docs/grub: Document signing grub under UEFI
+
+Before adding information about how grub is signed with an appended
+signature scheme, it's worth adding some information about how it
+can currently be signed for UEFI.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ docs/grub.texi | 22 +++++++++++++++++++++-
+ 1 file changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/docs/grub.texi b/docs/grub.texi
+index 4870faaa00..365d1d6931 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -5817,6 +5817,7 @@ environment variables and commands are listed in the same order.
+ * Secure Boot Advanced Targeting::   Embedded information for generation number based revocation
+ * Measured Boot::                    Measuring boot components
+ * Lockdown::                         Lockdown when booting on a secure setup
++* Signing GRUB itself::              Ensuring the integrity of the GRUB core image
+ @end menu
+ 
+ @node Authentication and authorisation
+@@ -5895,7 +5896,7 @@ commands.
+ 
+ GRUB's @file{core.img} can optionally provide enforcement that all files
+ subsequently read from disk are covered by a valid digital signature.
+-This document does @strong{not} cover how to ensure that your
++This section does @strong{not} cover how to ensure that your
+ platform's firmware (e.g., Coreboot) validates @file{core.img}.
+ 
+ If environment variable @code{check_signatures}
+@@ -6067,6 +6068,25 @@ be restricted and some operations/commands cannot be executed.
+ The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down.
+ Otherwise it does not exit.
+ 
++@node Signing GRUB itself
++@section Signing GRUB itself
++
++To ensure a complete secure-boot chain, there must be a way for the code that
++loads GRUB to verify the integrity of the core image.
++
++This is ultimately platform-specific and individual platforms can define their
++own mechanisms. However, there are general-purpose mechanisms that can be used
++with GRUB.
++
++@section Signing GRUB for UEFI secure boot
++
++On UEFI platforms, @file{core.img} is a PE binary. Therefore, it can be signed
++with a tool such as @command{pesign} or @command{sbsign}. Refer to the
++suggestions in @pxref{UEFI secure boot and shim} to ensure that the final
++image works under UEFI secure boot and can maintain the secure-boot chain. It
++will also be necessary to enrol the public key used into a relevant firmware
++key database.
++
+ @node Platform limitations
+ @chapter Platform limitations
+ 
diff --git a/SOURCES/0156-efi-dhcp-fix-some-allocation-error-checking.patch b/SOURCES/0156-efi-dhcp-fix-some-allocation-error-checking.patch
deleted file mode 100644
index 7549733..0000000
--- a/SOURCES/0156-efi-dhcp-fix-some-allocation-error-checking.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Sun, 19 Jul 2020 17:11:06 -0400
-Subject: [PATCH] efi+dhcp: fix some allocation error checking.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/net/efi/dhcp.c | 9 ++++++---
- 1 file changed, 6 insertions(+), 3 deletions(-)
-
-diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c
-index dbef63d8c08..e5c79b748b0 100644
---- a/grub-core/net/efi/dhcp.c
-+++ b/grub-core/net/efi/dhcp.c
-@@ -80,7 +80,7 @@ grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packe
-   if (status != GRUB_EFI_BUFFER_TOO_SMALL)
-     return NULL;
- 
--  option_list = grub_malloc (option_count * sizeof(*option_list));
-+  option_list = grub_calloc (option_count, sizeof(*option_list));
-   if (!option_list)
-     return NULL;
- 
-@@ -360,8 +360,11 @@ grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)),
- 
- 	if (status == GRUB_EFI_BUFFER_TOO_SMALL && count)
- 	  {
--	    options = grub_malloc (count * sizeof(*options));
--	    status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options);
-+	    options = grub_calloc (count, sizeof(*options));
-+	    if (options)
-+	      status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options);
-+	    else
-+	      status = GRUB_EFI_OUT_OF_RESOURCES;
- 	  }
- 
- 	if (status != GRUB_EFI_SUCCESS)
diff --git a/SOURCES/0157-docs-grub-Document-signing-grub-with-an-appended-sig.patch b/SOURCES/0157-docs-grub-Document-signing-grub-with-an-appended-sig.patch
new file mode 100644
index 0000000..ee3d659
--- /dev/null
+++ b/SOURCES/0157-docs-grub-Document-signing-grub-with-an-appended-sig.patch
@@ -0,0 +1,67 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Sat, 15 Aug 2020 02:19:36 +1000
+Subject: [PATCH] docs/grub: Document signing grub with an appended signature
+
+Signing grub for firmware that verifies an appended signature is a
+bit fiddly. I don't want people to have to figure it out from scratch
+so document it here.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ docs/grub.texi | 42 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+diff --git a/docs/grub.texi b/docs/grub.texi
+index 365d1d6931..afbde7c1f7 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -6087,6 +6087,48 @@ image works under UEFI secure boot and can maintain the secure-boot chain. It
+ will also be necessary to enrol the public key used into a relevant firmware
+ key database.
+ 
++@section Signing GRUB with an appended signature
++
++The @file{core.elf} itself can be signed with a Linux kernel module-style
++appended signature.
++
++To support IEEE1275 platforms where the boot image is often loaded directly
++from a disk partition rather than from a file system, the @file{core.elf}
++can specify the size and location of the appended signature with an ELF
++note added by @command{grub-install}.
++
++An image can be signed this way using the @command{sign-file} command from
++the Linux kernel:
++
++@example
++@group
++# grub.key is your private key and certificate.der is your public key
++
++# Determine the size of the appended signature. It depends on the signing
++# certificate and the hash algorithm
++touch empty
++sign-file SHA256 grub.key certificate.der empty empty.sig
++SIG_SIZE=`stat -c '%s' empty.sig`
++rm empty empty.sig
++
++# Build a grub image with $SIG_SIZE reserved for the signature
++grub-install --appended-signature-size $SIG_SIZE --modules="..." ...
++
++# Replace the reserved size with a signature:
++# cut off the last $SIG_SIZE bytes with truncate's minus modifier
++truncate -s -$SIG_SIZE /boot/grub/powerpc-ieee1275/core.elf core.elf.unsigned
++# sign the trimmed file with an appended signature, restoring the correct size
++sign-file SHA256 grub.key certificate.der core.elf.unsigned core.elf.signed
++
++# Don't forget to install the signed image as required
++# (e.g. on powerpc-ieee1275, to the PReP partition)
++@end group
++@end example
++
++As with UEFI secure boot, it is necessary to build in the required modules,
++or sign them separately.
++
++
+ @node Platform limitations
+ @chapter Platform limitations
+ 
diff --git a/SOURCES/0157-efi-http-fix-some-allocation-error-checking.patch b/SOURCES/0157-efi-http-fix-some-allocation-error-checking.patch
deleted file mode 100644
index 4dffab9..0000000
--- a/SOURCES/0157-efi-http-fix-some-allocation-error-checking.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Sun, 19 Jul 2020 17:14:15 -0400
-Subject: [PATCH] efi+http: fix some allocation error checking.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/net/efi/http.c | 11 +++++++----
- 1 file changed, 7 insertions(+), 4 deletions(-)
-
-diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
-index fc8cb25ae0a..26647a50fa4 100644
---- a/grub-core/net/efi/http.c
-+++ b/grub-core/net/efi/http.c
-@@ -412,8 +412,8 @@ grub_efihttp_open (struct grub_efi_net_device *dev,
- 		  int type)
- {
-   grub_err_t err;
--  grub_off_t size;
--  char *buf;
-+  grub_off_t size = 0;
-+  char *buf = NULL;
-   char *file_name = NULL;
-   const char *http_path;
- 
-@@ -441,8 +441,11 @@ grub_efihttp_open (struct grub_efi_net_device *dev,
-       return err;
-     }
- 
--  buf = grub_malloc (size);
--  efihttp_read (dev, buf, size);
-+  if (size)
-+    {
-+      buf = grub_malloc (size);
-+      efihttp_read (dev, buf, size);
-+    }
- 
-   file->size = size;
-   file->data = buf;
diff --git a/SOURCES/0158-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch b/SOURCES/0158-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch
new file mode 100644
index 0000000..b23ce49
--- /dev/null
+++ b/SOURCES/0158-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch
@@ -0,0 +1,44 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 30 Jul 2020 00:13:21 +1000
+Subject: [PATCH] dl: provide a fake grub_dl_set_persistent for the emu target
+
+Trying to start grub-emu with a module that calls grub_dl_set_persistent
+will crash because grub-emu fakes modules and passes NULL to the module
+init function.
+
+Provide an empty function for the emu case.
+
+Fixes: ee7808e2197c (dl: Add support for persistent modules)
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ include/grub/dl.h | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/include/grub/dl.h b/include/grub/dl.h
+index 2f76e6b043..20d870f2a4 100644
+--- a/include/grub/dl.h
++++ b/include/grub/dl.h
+@@ -245,11 +245,22 @@ grub_dl_get (const char *name)
+   return 0;
+ }
+ 
++#ifdef GRUB_MACHINE_EMU
++/*
++ * Under grub-emu, modules are faked and NULL is passed to GRUB_MOD_INIT.
++ * So we fake this out to avoid a NULL deref.
++ */
++static inline void
++grub_dl_set_persistent (grub_dl_t mod __attribute__((unused)))
++{
++}
++#else
+ static inline void
+ grub_dl_set_persistent (grub_dl_t mod)
+ {
+   mod->persistent = 1;
+ }
++#endif
+ 
+ static inline int
+ grub_dl_is_persistent (grub_dl_t mod)
diff --git a/SOURCES/0158-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch b/SOURCES/0158-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch
deleted file mode 100644
index 30c21a5..0000000
--- a/SOURCES/0158-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch
+++ /dev/null
@@ -1,127 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Sun, 19 Jul 2020 17:27:00 -0400
-Subject: [PATCH] efi/ip[46]_config.c: fix some potential allocation overflows
-
-In theory all of this data comes from the firmware stack and it should
-be safe, but it's better to be paranoid.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/net/efi/ip4_config.c | 25 ++++++++++++++++++-------
- grub-core/net/efi/ip6_config.c | 13 ++++++++++---
- 2 files changed, 28 insertions(+), 10 deletions(-)
-
-diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c
-index 313c818b184..9725e928f7e 100644
---- a/grub-core/net/efi/ip4_config.c
-+++ b/grub-core/net/efi/ip4_config.c
-@@ -4,15 +4,20 @@
- #include <grub/misc.h>
- #include <grub/net/efi.h>
- #include <grub/charset.h>
-+#include <grub/safemath.h>
- 
- char *
- grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address)
- {
-   char *hw_addr, *p;
--  int sz, s;
--  int i;
-+  grub_size_t sz, s, i;
- 
--  sz = (int)hw_address_size * (sizeof ("XX:") - 1) + 1;
-+  if (grub_mul (hw_address_size, sizeof ("XX:") - 1, &sz) ||
-+      grub_add (sz, 1, &sz))
-+    {
-+      grub_errno = GRUB_ERR_OUT_OF_RANGE;
-+      return NULL;
-+    }
- 
-   hw_addr = grub_malloc (sz);
-   if (!hw_addr)
-@@ -20,7 +25,7 @@ grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_a
- 
-   p = hw_addr;
-   s = sz;
--  for (i = 0; i < (int)hw_address_size; i++)
-+  for (i = 0; i < hw_address_size; i++)
-     {
-       grub_snprintf (p, sz, "%02x:", hw_address[i]);
-       p +=  sizeof ("XX:") - 1;
-@@ -238,14 +243,20 @@ grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev)
- {
-   grub_efi_ip4_config2_interface_info_t *interface_info;
-   char **ret;
--  int i, id;
-+  int id;
-+  grub_size_t i, nmemb;
- 
-   interface_info = efi_ip4_config_interface_info (dev->ip4_config);
-   if (!interface_info)
-     return NULL;
- 
--  ret = grub_malloc (sizeof (*ret) * (interface_info->route_table_size + 1));
-+  if (grub_add (interface_info->route_table_size, 1, &nmemb))
-+    {
-+      grub_errno = GRUB_ERR_OUT_OF_RANGE;
-+      return NULL;
-+    }
- 
-+  ret = grub_calloc (nmemb, sizeof (*ret));
-   if (!ret)
-     {
-       grub_free (interface_info);
-@@ -253,7 +264,7 @@ grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev)
-     }
- 
-   id = 0;
--  for (i = 0; i < (int)interface_info->route_table_size; i++)
-+  for (i = 0; i < interface_info->route_table_size; i++)
-     {
-       char *subnet, *gateway, *mask;
-       grub_uint32_t u32_subnet, u32_gateway;
-diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c
-index 017c4d05bc7..a46f6f9b685 100644
---- a/grub-core/net/efi/ip6_config.c
-+++ b/grub-core/net/efi/ip6_config.c
-@@ -3,6 +3,7 @@
- #include <grub/misc.h>
- #include <grub/net/efi.h>
- #include <grub/charset.h>
-+#include <grub/safemath.h>
- 
- char *
- grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address)
-@@ -228,14 +229,20 @@ grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev)
- {
-   grub_efi_ip6_config_interface_info_t *interface_info;
-   char **ret;
--  int i, id;
-+  int id;
-+  grub_size_t i, nmemb;
- 
-   interface_info = efi_ip6_config_interface_info (dev->ip6_config);
-   if (!interface_info)
-     return NULL;
- 
--  ret = grub_malloc (sizeof (*ret) * (interface_info->route_count + 1));
-+  if (grub_add (interface_info->route_count, 1, &nmemb))
-+    {
-+      grub_errno = GRUB_ERR_OUT_OF_RANGE;
-+      return NULL;
-+    }
- 
-+  ret = grub_calloc (nmemb, sizeof (*ret));
-   if (!ret)
-     {
-       grub_free (interface_info);
-@@ -243,7 +250,7 @@ grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev)
-     }
- 
-   id = 0;
--  for (i = 0; i < (int)interface_info->route_count ; i++)
-+  for (i = 0; i < interface_info->route_count ; i++)
-     {
-       char *gateway, *destination;
-       grub_uint64_t u64_gateway[2];
diff --git a/SOURCES/0159-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch b/SOURCES/0159-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch
deleted file mode 100644
index 95f7e20..0000000
--- a/SOURCES/0159-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Colin Watson <cjwatson@debian.org>
-Date: Fri, 24 Jul 2020 17:18:09 +0100
-Subject: [PATCH] efilinux: Fix integer overflows in grub_cmd_initrd
-
-These could be triggered by an extremely large number of arguments to
-the initrd command on 32-bit architectures, or a crafted filesystem with
-very large files on any architecture.
-
-Signed-off-by: Colin Watson <cjwatson@debian.org>
----
- grub-core/loader/i386/efi/linux.c | 10 ++++++++--
- 1 file changed, 8 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index 15d40d6e35b..f992ceeef20 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -28,6 +28,8 @@
- #include <grub/efi/efi.h>
- #include <grub/efi/linux.h>
- #include <grub/cpu/efi/memory.h>
-+#include <grub/tpm.h>
-+#include <grub/safemath.h>
- 
- GRUB_MOD_LICENSE ("GPLv3+");
- 
-@@ -206,7 +208,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
-       goto fail;
-     }
- 
--  files = grub_zalloc (argc * sizeof (files[0]));
-+  files = grub_calloc (argc, sizeof (files[0]));
-   if (!files)
-     goto fail;
- 
-@@ -216,7 +218,11 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
-       if (! files[i])
-         goto fail;
-       nfiles++;
--      size += ALIGN_UP (grub_file_size (files[i]), 4);
-+      if (grub_add (size, ALIGN_UP (grub_file_size (files[i]), 4), &size))
-+	{
-+	  grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
-+	  goto fail;
-+	}
-     }
- 
-   initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
diff --git a/SOURCES/0159-pgp-factor-out-rsa_pad.patch b/SOURCES/0159-pgp-factor-out-rsa_pad.patch
new file mode 100644
index 0000000..43fd882
--- /dev/null
+++ b/SOURCES/0159-pgp-factor-out-rsa_pad.patch
@@ -0,0 +1,191 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 1 Oct 2020 20:23:48 +1000
+Subject: [PATCH] pgp: factor out rsa_pad
+
+rsa_pad does the PKCS#1 v1.5 padding for the RSA signature scheme.
+We want to use it in other RSA signature verification applications.
+
+I considered and rejected putting it in lib/crypto.c. That file doesn't
+currently require any MPI functions, but rsa_pad does. That's not so
+much of a problem for the grub kernel and modules, but crypto.c also
+gets built into all the grub utilities. So - despite the utils not
+using any asymmetric ciphers -  we would need to built the entire MPI
+infrastructure in to them.
+
+A better and simpler solution is just to spin rsa_pad out into its own
+PKCS#1 v1.5 module.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/Makefile.core.def |  8 ++++++
+ grub-core/commands/pgp.c    | 28 ++-------------------
+ grub-core/lib/pkcs1_v15.c   | 59 +++++++++++++++++++++++++++++++++++++++++++++
+ include/grub/pkcs1_v15.h    | 27 +++++++++++++++++++++
+ 4 files changed, 96 insertions(+), 26 deletions(-)
+ create mode 100644 grub-core/lib/pkcs1_v15.c
+ create mode 100644 include/grub/pkcs1_v15.h
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index dc9fea6f44..64cc758835 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -2511,6 +2511,14 @@ module = {
+   cppflags = '$(CPPFLAGS_GCRY)';
+ };
+ 
++module = {
++  name = pkcs1_v15;
++  common = lib/pkcs1_v15.c;
++
++  cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';
++  cppflags = '$(CPPFLAGS_GCRY)';
++};
++
+ module = {
+   name = all_video;
+   common = lib/fake_module.c;
+diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
+index 5daa1e9d00..2408db4994 100644
+--- a/grub-core/commands/pgp.c
++++ b/grub-core/commands/pgp.c
+@@ -24,6 +24,7 @@
+ #include <grub/file.h>
+ #include <grub/command.h>
+ #include <grub/crypto.h>
++#include <grub/pkcs1_v15.h>
+ #include <grub/i18n.h>
+ #include <grub/gcrypt/gcrypt.h>
+ #include <grub/pubkey.h>
+@@ -411,32 +412,7 @@ static int
+ rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ 	 const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
+ {
+-  grub_size_t tlen, emlen, fflen;
+-  grub_uint8_t *em, *emptr;
+-  unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]);
+-  int ret;
+-  tlen = hash->mdlen + hash->asnlen;
+-  emlen = (nbits + 7) / 8;
+-  if (emlen < tlen + 11)
+-    return 1;
+-
+-  em = grub_malloc (emlen);
+-  if (!em)
+-    return 1;
+-
+-  em[0] = 0x00;
+-  em[1] = 0x01;
+-  fflen = emlen - tlen - 3;
+-  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
+-    *emptr = 0xff;
+-  *emptr++ = 0x00;
+-  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
+-  emptr += hash->asnlen;
+-  grub_memcpy (emptr, hval, hash->mdlen);
+-
+-  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
+-  grub_free (em);
+-  return ret;
++  return grub_crypto_rsa_pad(hmpi, hval, hash, sk->mpis[0]);
+ }
+ 
+ struct grub_pubkey_context
+diff --git a/grub-core/lib/pkcs1_v15.c b/grub-core/lib/pkcs1_v15.c
+new file mode 100644
+index 0000000000..dbacd563d0
+--- /dev/null
++++ b/grub-core/lib/pkcs1_v15.c
+@@ -0,0 +1,59 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2013  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/gcrypt/gcrypt.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++/*
++ * Given a hash value 'hval', of hash specification 'hash', perform
++ * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
++ * (see RFC 8017 s 9.2) and place the result in 'hmpi'.
++ */
++gcry_err_code_t
++grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
++		     const gcry_md_spec_t * hash, gcry_mpi_t mod)
++{
++  grub_size_t tlen, emlen, fflen;
++  grub_uint8_t *em, *emptr;
++  unsigned nbits = gcry_mpi_get_nbits (mod);
++  int ret;
++  tlen = hash->mdlen + hash->asnlen;
++  emlen = (nbits + 7) / 8;
++  if (emlen < tlen + 11)
++    return GPG_ERR_TOO_SHORT;
++
++  em = grub_malloc (emlen);
++  if (!em)
++    return 1;
++
++  em[0] = 0x00;
++  em[1] = 0x01;
++  fflen = emlen - tlen - 3;
++  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
++    *emptr = 0xff;
++  *emptr++ = 0x00;
++  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
++  emptr += hash->asnlen;
++  grub_memcpy (emptr, hval, hash->mdlen);
++
++  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
++  grub_free (em);
++  return ret;
++}
+diff --git a/include/grub/pkcs1_v15.h b/include/grub/pkcs1_v15.h
+new file mode 100644
+index 0000000000..5c338c84a1
+--- /dev/null
++++ b/include/grub/pkcs1_v15.h
+@@ -0,0 +1,27 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2013  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/>.
++ */
++
++/*
++ * Given a hash value 'hval', of hash specification 'hash', perform
++ * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
++ * (See RFC 8017 s 9.2)
++ */
++gcry_err_code_t
++grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
++		     const gcry_md_spec_t * hash, gcry_mpi_t mod);
++
diff --git a/SOURCES/0160-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch b/SOURCES/0160-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch
new file mode 100644
index 0000000..541474e
--- /dev/null
+++ b/SOURCES/0160-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch
@@ -0,0 +1,71 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Fri, 2 Oct 2020 10:49:26 +1000
+Subject: [PATCH] crypto: move storage for grub_crypto_pk_* to crypto.c
+
+The way gcry_rsa and friends (the asymmetric ciphers) are loaded for the
+pgp module is a bit quirky.
+
+include/grub/crypto.h contains:
+  extern struct gcry_pk_spec *grub_crypto_pk_rsa;
+
+commands/pgp.c contains the actual storage:
+  struct gcry_pk_spec *grub_crypto_pk_rsa;
+
+And the module itself saves to the storage in pgp.c:
+  GRUB_MOD_INIT(gcry_rsa)
+  {
+    grub_crypto_pk_rsa = &_gcry_pubkey_spec_rsa;
+  }
+
+This is annoying: gcry_rsa now has a dependency on pgp!
+
+We want to be able to bring in gcry_rsa without bringing in PGP,
+so move the storage to crypto.c.
+
+Previously, gcry_rsa depended on pgp and mpi. Now it depends on
+crypto and mpi. As pgp depends on crypto, this doesn't add any new
+module dependencies using the PGP verfier.
+
+[FWIW, the story is different for the symmetric ciphers. cryptodisk
+and friends (zfs encryption etc) use grub_crypto_lookup_cipher_by_name()
+to get a cipher handle. That depends on grub_ciphers being populated
+by people calling grub_cipher_register. import_gcry.py ensures that the
+symmetric ciphers call it.]
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/commands/pgp.c | 4 ----
+ grub-core/lib/crypto.c   | 4 ++++
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
+index 2408db4994..355a43844a 100644
+--- a/grub-core/commands/pgp.c
++++ b/grub-core/commands/pgp.c
+@@ -147,10 +147,6 @@ const char *hashes[] = {
+   [0x0b] = "sha224"
+ };
+ 
+-struct gcry_pk_spec *grub_crypto_pk_dsa;
+-struct gcry_pk_spec *grub_crypto_pk_ecdsa;
+-struct gcry_pk_spec *grub_crypto_pk_rsa;
+-
+ static int
+ dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
+ 	 const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
+diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c
+index ca334d5a40..c578128a59 100644
+--- a/grub-core/lib/crypto.c
++++ b/grub-core/lib/crypto.c
+@@ -121,6 +121,10 @@ grub_md_unregister (gcry_md_spec_t *cipher)
+       }
+ }
+ 
++struct gcry_pk_spec *grub_crypto_pk_dsa;
++struct gcry_pk_spec *grub_crypto_pk_ecdsa;
++struct gcry_pk_spec *grub_crypto_pk_rsa;
++
+ void
+ grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in,
+ 		  grub_size_t inlen)
diff --git a/SOURCES/0160-linuxefi-fail-kernel-validation-without-shim-protoco.patch b/SOURCES/0160-linuxefi-fail-kernel-validation-without-shim-protoco.patch
deleted file mode 100644
index 20fc786..0000000
--- a/SOURCES/0160-linuxefi-fail-kernel-validation-without-shim-protoco.patch
+++ /dev/null
@@ -1,130 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Dimitri John Ledkov <xnox@ubuntu.com>
-Date: Wed, 22 Jul 2020 11:31:43 +0100
-Subject: [PATCH] linuxefi: fail kernel validation without shim protocol.
-
-If certificates that signed grub are installed into db, grub can be
-booted directly. It will then boot any kernel without signature
-validation. The booted kernel will think it was booted in secureboot
-mode and will implement lockdown, yet it could have been tampered.
-
-This version of the patch skips calling verification, when booted
-without secureboot. And is indented with gnu ident.
-
-CVE-2020-15705
-
-Reported-by: Mathieu Trudel-Lapierre <cyphermox@ubuntu.com>
-Signed-off-by: Dimitri John Ledkov <xnox@ubuntu.com>
----
- grub-core/loader/arm64/linux.c     | 13 +++++++++----
- grub-core/loader/efi/chainloader.c |  1 +
- grub-core/loader/efi/linux.c       |  1 +
- grub-core/loader/i386/efi/linux.c  | 17 +++++++++++------
- 4 files changed, 22 insertions(+), 10 deletions(-)
-
-diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
-index 70a0075ec5e..47f8cf0d84b 100644
---- a/grub-core/loader/arm64/linux.c
-+++ b/grub-core/loader/arm64/linux.c
-@@ -34,6 +34,7 @@
- #include <grub/i18n.h>
- #include <grub/lib/cmdline.h>
- #include <grub/verify.h>
-+#include <grub/efi/sb.h>
- 
- GRUB_MOD_LICENSE ("GPLv3+");
- 
-@@ -363,11 +364,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
- 
-   grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
- 
--  rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size);
--  if (rc < 0)
-+  if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED)
-     {
--      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
--      goto fail;
-+      rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size);
-+      if (rc <= 0)
-+	{
-+	  grub_error (GRUB_ERR_INVALID_COMMAND,
-+		      N_("%s has invalid signature"), argv[0]);
-+	  goto fail;
-+	}
-     }
- 
-   pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset);
-diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
-index ac8dfd40c61..d41e8ea14a8 100644
---- a/grub-core/loader/efi/chainloader.c
-+++ b/grub-core/loader/efi/chainloader.c
-@@ -1084,6 +1084,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
- 
-       return 0;
-     }
-+  // -1 fall-through to fail
- 
- fail:
-   if (dev)
-diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
-index e8b9ecb17f6..9260731c107 100644
---- a/grub-core/loader/efi/linux.c
-+++ b/grub-core/loader/efi/linux.c
-@@ -33,6 +33,7 @@ struct grub_efi_shim_lock
- };
- typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
- 
-+// Returns 1 on success, -1 on error, 0 when not available
- int
- grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
- {
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index f992ceeef20..3cf0f9b330b 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -30,6 +30,7 @@
- #include <grub/cpu/efi/memory.h>
- #include <grub/tpm.h>
- #include <grub/safemath.h>
-+#include <grub/efi/sb.h>
- 
- GRUB_MOD_LICENSE ("GPLv3+");
- 
-@@ -101,7 +102,7 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
- 
-       pages = BYTES_TO_PAGES(size);
-       grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n",
--		    pages, (void *)max);
-+		    (unsigned long)pages, (void *)(unsigned long)max);
- 
-       prev_max = max;
-       addr = grub_efi_allocate_pages_real (max, pages,
-@@ -307,12 +308,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-       goto fail;
-     }
- 
--  rc = grub_linuxefi_secure_validate (kernel, filelen);
--  if (rc < 0)
-+  if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED)
-     {
--      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"),
--		  argv[0]);
--      goto fail;
-+      rc = grub_linuxefi_secure_validate (kernel, filelen);
-+      if (rc <= 0)
-+	{
-+	  grub_error (GRUB_ERR_INVALID_COMMAND,
-+		      N_("%s has invalid signature"), argv[0]);
-+	  goto fail;
-+	}
-     }
- 
-   lh = (struct linux_i386_kernel_header *)kernel;
-@@ -386,6 +390,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
- 
-   setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201);
-   grub_dprintf ("linux", "copying %lu bytes from %p to %p\n",
-+		(unsigned long)
- 		MIN((grub_size_t)0x202+setup_header_end_offset,
- 		    sizeof (*params)) - 0x1f1,
- 		(grub_uint8_t *)kernel + 0x1f1,
diff --git a/SOURCES/0161-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch b/SOURCES/0161-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch
deleted file mode 100644
index 9b0db5f..0000000
--- a/SOURCES/0161-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 20 Jul 2020 12:24:02 -0400
-Subject: [PATCH] Fix const char ** pointers in grub-core/net/bootp.c
-
-This will need to get folded back in the right place on the next rebase,
-but it's before "Make grub_strtol() "end" pointers have safer const
-qualifiers" currently, so for now I'm leaving it here instead of merging
-it back with the original patch.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/net/bootp.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
-index 8fb8918ae7e..7baf3540c81 100644
---- a/grub-core/net/bootp.c
-+++ b/grub-core/net/bootp.c
-@@ -329,7 +329,7 @@ grub_net_configure_by_dhcp_ack (const char *name,
-   struct grub_net_network_level_interface *inter;
-   int mask = -1;
-   char server_ip[sizeof ("xxx.xxx.xxx.xxx")];
--  const grub_uint8_t *opt;
-+  const char *opt;
-   grub_uint8_t opt_len, overload = 0;
-   const char *boot_file = 0, *server_name = 0;
-   grub_size_t boot_file_len, server_name_len;
-@@ -505,7 +505,7 @@ grub_net_configure_by_dhcp_ack (const char *name,
-   if (opt && opt_len)
-     {
-       grub_env_set_net_property (name, "vendor_class_identifier", (const char *) opt, opt_len);
--      if (opt && grub_strcmp (opt, "HTTPClient") == 0)
-+      if (opt && grub_strcmp ((char *)opt, "HTTPClient") == 0)
-         {
-           char *proto, *ip, *pa;
- 
diff --git a/SOURCES/0161-posix_wrap-tweaks-in-preparation-for-libtasn1.patch b/SOURCES/0161-posix_wrap-tweaks-in-preparation-for-libtasn1.patch
new file mode 100644
index 0000000..3176f1b
--- /dev/null
+++ b/SOURCES/0161-posix_wrap-tweaks-in-preparation-for-libtasn1.patch
@@ -0,0 +1,64 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Sat, 2 May 2020 00:27:57 +1000
+Subject: [PATCH] posix_wrap: tweaks in preparation for libtasn1
+
+ - Define SIZEOF_UNSIGNED_LONG_INT, it's the same as
+   SIZEOF_UNSIGNED_LONG.
+
+ - Define WORD_BIT, the size in bits of an int. This is a defined
+   in the Single Unix Specification and in gnulib's limits.h. gnulib
+   assumes it's 32 bits on all our platforms, including 64 bit
+   platforms, so we also use that value.
+
+ - Provide strto[u]l[l] preprocessor macros that resolve to
+   grub_strto[u]l[l]. To avoid gcrypt redefining strtoul, we
+   also define HAVE_STRTOUL here.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/lib/posix_wrap/limits.h    | 1 +
+ grub-core/lib/posix_wrap/stdlib.h    | 8 ++++++++
+ grub-core/lib/posix_wrap/sys/types.h | 1 +
+ 3 files changed, 10 insertions(+)
+
+diff --git a/grub-core/lib/posix_wrap/limits.h b/grub-core/lib/posix_wrap/limits.h
+index 7217138ffd..591dbf3289 100644
+--- a/grub-core/lib/posix_wrap/limits.h
++++ b/grub-core/lib/posix_wrap/limits.h
+@@ -37,5 +37,6 @@
+ #define LONG_MAX GRUB_LONG_MAX
+ 
+ #define CHAR_BIT 8
++#define WORD_BIT 32
+ 
+ #endif
+diff --git a/grub-core/lib/posix_wrap/stdlib.h b/grub-core/lib/posix_wrap/stdlib.h
+index 7a8d385e97..4634db09f2 100644
+--- a/grub-core/lib/posix_wrap/stdlib.h
++++ b/grub-core/lib/posix_wrap/stdlib.h
+@@ -58,4 +58,12 @@ abs (int c)
+   return (c >= 0) ? c : -c;
+ }
+ 
++#define strtol grub_strtol
++
++/* for libgcrypt */
++#define HAVE_STRTOUL
++#define strtoul grub_strtoul
++
++#define strtoull grub_strtoull
++
+ #endif
+diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h
+index 854eb0122e..f63412c8da 100644
+--- a/grub-core/lib/posix_wrap/sys/types.h
++++ b/grub-core/lib/posix_wrap/sys/types.h
+@@ -51,6 +51,7 @@ typedef grub_uint8_t byte;
+ typedef grub_addr_t uintptr_t;
+ 
+ #define SIZEOF_UNSIGNED_LONG GRUB_CPU_SIZEOF_LONG
++#define SIZEOF_UNSIGNED_LONG_INT GRUB_CPU_SIZEOF_LONG
+ #define SIZEOF_UNSIGNED_INT 4
+ #define SIZEOF_UNSIGNED_LONG_LONG 8
+ #define SIZEOF_UNSIGNED_SHORT 2
diff --git a/SOURCES/0162-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch b/SOURCES/0162-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch
deleted file mode 100644
index 6c16e9e..0000000
--- a/SOURCES/0162-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 20 Jul 2020 12:24:02 -0400
-Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/ip4_config.c
-
-This will need to get folded back in the right place on the next rebase,
-but it's before "Make grub_strtol() "end" pointers have safer const
-qualifiers" currently, so for now I'm leaving it here instead of merging
-it back with the original patch.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/net/efi/ip4_config.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c
-index 9725e928f7e..cb880fc3e8f 100644
---- a/grub-core/net/efi/ip4_config.c
-+++ b/grub-core/net/efi/ip4_config.c
-@@ -61,7 +61,8 @@ int
- grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest)
- {
-   grub_uint32_t newip = 0;
--  int i, ncolon = 0;
-+  grub_size_t i;
-+  int ncolon = 0;
-   const char *ptr = val;
- 
-   /* Check that is not an IPv6 address */
-@@ -78,7 +79,7 @@ grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *addres
-   for (i = 0; i < 4; i++)
-     {
-       unsigned long t;
--      t = grub_strtoul (ptr, (char **) &ptr, 0);
-+      t = grub_strtoul (ptr, &ptr, 0);
-       if (grub_errno)
- 	{
- 	  grub_errno = GRUB_ERR_NONE;
diff --git a/SOURCES/0162-libtasn1-import-libtasn1-4.16.0.patch b/SOURCES/0162-libtasn1-import-libtasn1-4.16.0.patch
new file mode 100644
index 0000000..9587661
--- /dev/null
+++ b/SOURCES/0162-libtasn1-import-libtasn1-4.16.0.patch
@@ -0,0 +1,8934 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Wed, 10 Jun 2020 16:31:22 +1000
+Subject: [PATCH] libtasn1: import libtasn1-4.16.0
+
+Import a very trimmed-down set of libtasn1 files:
+
+pushd /tmp
+wget https://ftp.gnu.org/gnu/libtasn1/libtasn1-4.16.0.tar.gz
+popd
+pushd grub-core/lib
+mkdir libtasn1
+cp /tmp/libtasn1-4.16.0/{README.md,LICENSE} libtasn1/
+mkdir libtasn1/lib
+cp /tmp/libtasn1-4.16.0/lib/{coding.c,decoding.c,element.c,element.h,errors.c,gstr.c,gstr.h,int.h,parser_aux.c,parser_aux.h,structure.c,structure.h}  libtasn1/lib
+cp /tmp/libtasn1-4.16.0/lib/includes/libtasn1.h ../../include/grub/
+git add libtasn1/ ../../include/grub/libtasn1.h
+popd
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/lib/libtasn1/lib/coding.c     | 1415 ++++++++++++++++++
+ grub-core/lib/libtasn1/lib/decoding.c   | 2478 +++++++++++++++++++++++++++++++
+ grub-core/lib/libtasn1/lib/element.c    | 1111 ++++++++++++++
+ grub-core/lib/libtasn1/lib/errors.c     |  100 ++
+ grub-core/lib/libtasn1/lib/gstr.c       |   74 +
+ grub-core/lib/libtasn1/lib/parser_aux.c | 1173 +++++++++++++++
+ grub-core/lib/libtasn1/lib/structure.c  | 1220 +++++++++++++++
+ grub-core/lib/libtasn1/lib/element.h    |   40 +
+ grub-core/lib/libtasn1/lib/gstr.h       |   47 +
+ grub-core/lib/libtasn1/lib/int.h        |  221 +++
+ grub-core/lib/libtasn1/lib/parser_aux.h |  172 +++
+ grub-core/lib/libtasn1/lib/structure.h  |   45 +
+ include/grub/libtasn1.h                 |  588 ++++++++
+ grub-core/lib/libtasn1/LICENSE          |   16 +
+ grub-core/lib/libtasn1/README.md        |   91 ++
+ 15 files changed, 8791 insertions(+)
+ create mode 100644 grub-core/lib/libtasn1/lib/coding.c
+ create mode 100644 grub-core/lib/libtasn1/lib/decoding.c
+ create mode 100644 grub-core/lib/libtasn1/lib/element.c
+ create mode 100644 grub-core/lib/libtasn1/lib/errors.c
+ create mode 100644 grub-core/lib/libtasn1/lib/gstr.c
+ create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.c
+ create mode 100644 grub-core/lib/libtasn1/lib/structure.c
+ create mode 100644 grub-core/lib/libtasn1/lib/element.h
+ create mode 100644 grub-core/lib/libtasn1/lib/gstr.h
+ create mode 100644 grub-core/lib/libtasn1/lib/int.h
+ create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.h
+ create mode 100644 grub-core/lib/libtasn1/lib/structure.h
+ create mode 100644 include/grub/libtasn1.h
+ create mode 100644 grub-core/lib/libtasn1/LICENSE
+ create mode 100644 grub-core/lib/libtasn1/README.md
+
+diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c
+new file mode 100644
+index 0000000000..245ea64cf0
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/coding.c
+@@ -0,0 +1,1415 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++
++/*****************************************************/
++/* File: coding.c                                    */
++/* Description: Functions to create a DER coding of  */
++/*   an ASN1 type.                                   */
++/*****************************************************/
++
++#include <int.h>
++#include "parser_aux.h"
++#include <gstr.h>
++#include "element.h"
++#include "minmax.h"
++#include <structure.h>
++
++#define MAX_TAG_LEN 16
++
++/******************************************************/
++/* Function : _asn1_error_description_value_not_found */
++/* Description: creates the ErrorDescription string   */
++/* for the ASN1_VALUE_NOT_FOUND error.                */
++/* Parameters:                                        */
++/*   node: node of the tree where the value is NULL.  */
++/*   ErrorDescription: string returned.               */
++/* Return:                                            */
++/******************************************************/
++static void
++_asn1_error_description_value_not_found (asn1_node node,
++					 char *ErrorDescription)
++{
++
++  if (ErrorDescription == NULL)
++    return;
++
++  Estrcpy (ErrorDescription, ":: value of element '");
++  _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription),
++			   ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40);
++  Estrcat (ErrorDescription, "' not found");
++
++}
++
++/**
++ * asn1_length_der:
++ * @len: value to convert.
++ * @der: buffer to hold the returned encoding (may be %NULL).
++ * @der_len: number of meaningful bytes of ANS (der[0]..der[der_len-1]).
++ *
++ * Creates the DER encoding of the provided length value.
++ * The @der buffer must have enough room for the output. The maximum
++ * length this function will encode is %ASN1_MAX_LENGTH_SIZE.
++ *
++ * To know the size of the DER encoding use a %NULL value for @der.
++ **/
++void
++asn1_length_der (unsigned long int len, unsigned char *der, int *der_len)
++{
++  int k;
++  unsigned char temp[ASN1_MAX_LENGTH_SIZE];
++#if SIZEOF_UNSIGNED_LONG_INT > 8
++  len &= 0xFFFFFFFFFFFFFFFF;
++#endif
++
++  if (len < 128)
++    {
++      /* short form */
++      if (der != NULL)
++	der[0] = (unsigned char) len;
++      *der_len = 1;
++    }
++  else
++    {
++      /* Long form */
++      k = 0;
++      while (len)
++	{
++	  temp[k++] = len & 0xFF;
++	  len = len >> 8;
++	}
++      *der_len = k + 1;
++      if (der != NULL)
++	{
++	  der[0] = ((unsigned char) k & 0x7F) + 128;
++	  while (k--)
++	    der[*der_len - 1 - k] = temp[k];
++	}
++    }
++}
++
++/******************************************************/
++/* Function : _asn1_tag_der                           */
++/* Description: creates the DER coding for the CLASS  */
++/* and TAG parameters.                                */
++/* It is limited by the ASN1_MAX_TAG_SIZE variable    */
++/* Parameters:                                        */
++/*   class: value to convert.                         */
++/*   tag_value: value to convert.                     */
++/*   ans: string returned.                            */
++/*   ans_len: number of meaningful bytes of ANS       */
++/*            (ans[0]..ans[ans_len-1]).               */
++/* Return:                                            */
++/******************************************************/
++static void
++_asn1_tag_der (unsigned char class, unsigned int tag_value,
++	       unsigned char ans[ASN1_MAX_TAG_SIZE], int *ans_len)
++{
++  int k;
++  unsigned char temp[ASN1_MAX_TAG_SIZE];
++
++  if (tag_value < 31)
++    {
++      /* short form */
++      ans[0] = (class & 0xE0) + ((unsigned char) (tag_value & 0x1F));
++      *ans_len = 1;
++    }
++  else
++    {
++      /* Long form */
++      ans[0] = (class & 0xE0) + 31;
++      k = 0;
++      while (tag_value != 0)
++	{
++	  temp[k++] = tag_value & 0x7F;
++	  tag_value >>= 7;
++
++	  if (k > ASN1_MAX_TAG_SIZE - 1)
++	    break;		/* will not encode larger tags */
++	}
++      *ans_len = k + 1;
++      while (k--)
++	ans[*ans_len - 1 - k] = temp[k] + 128;
++      ans[*ans_len - 1] -= 128;
++    }
++}
++
++/**
++ * asn1_octet_der:
++ * @str: the input data.
++ * @str_len: STR length (str[0]..str[*str_len-1]).
++ * @der: encoded string returned.
++ * @der_len: number of meaningful bytes of DER (der[0]..der[der_len-1]).
++ *
++ * Creates a length-value DER encoding for the input data.
++ * The DER encoding of the input data will be placed in the @der variable.
++ *
++ * Note that the OCTET STRING tag is not included in the output.
++ *
++ * This function does not return any value because it is expected
++ * that @der_len will contain enough bytes to store the string
++ * plus the DER encoding. The DER encoding size can be obtained using
++ * asn1_length_der().
++ **/
++void
++asn1_octet_der (const unsigned char *str, int str_len,
++		unsigned char *der, int *der_len)
++{
++  int len_len;
++
++  if (der == NULL || str_len < 0)
++    return;
++
++  asn1_length_der (str_len, der, &len_len);
++  memcpy (der + len_len, str, str_len);
++  *der_len = str_len + len_len;
++}
++
++
++/**
++ * asn1_encode_simple_der:
++ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
++ * @str: the string data.
++ * @str_len: the string length
++ * @tl: the encoded tag and length
++ * @tl_len: the bytes of the @tl field
++ *
++ * Creates the DER encoding for various simple ASN.1 types like strings etc.
++ * It stores the tag and length in @tl, which should have space for at least
++ * %ASN1_MAX_TL_SIZE bytes. Initially @tl_len should contain the size of @tl.
++ *
++ * The complete DER encoding should consist of the value in @tl appended
++ * with the provided @str.
++ *
++ * Returns: %ASN1_SUCCESS if successful or an error value.
++ **/
++int
++asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
++			unsigned int str_len, unsigned char *tl,
++			unsigned int *tl_len)
++{
++  int tag_len, len_len;
++  unsigned tlen;
++  unsigned char der_tag[ASN1_MAX_TAG_SIZE];
++  unsigned char der_length[ASN1_MAX_LENGTH_SIZE];
++  unsigned char *p;
++
++  if (str == NULL)
++    return ASN1_VALUE_NOT_VALID;
++
++  if (ETYPE_OK (etype) == 0)
++    return ASN1_VALUE_NOT_VALID;
++
++  /* doesn't handle constructed classes */
++  if (ETYPE_CLASS (etype) != ASN1_CLASS_UNIVERSAL)
++    return ASN1_VALUE_NOT_VALID;
++
++  _asn1_tag_der (ETYPE_CLASS (etype), ETYPE_TAG (etype), der_tag, &tag_len);
++
++  asn1_length_der (str_len, der_length, &len_len);
++
++  if (tag_len <= 0 || len_len <= 0)
++    return ASN1_VALUE_NOT_VALID;
++
++  tlen = tag_len + len_len;
++
++  if (*tl_len < tlen)
++    return ASN1_MEM_ERROR;
++
++  p = tl;
++  memcpy (p, der_tag, tag_len);
++  p += tag_len;
++  memcpy (p, der_length, len_len);
++
++  *tl_len = tlen;
++
++  return ASN1_SUCCESS;
++}
++
++/******************************************************/
++/* Function : _asn1_time_der                          */
++/* Description: creates the DER coding for a TIME     */
++/* type (length included).                            */
++/* Parameters:                                        */
++/*   str: TIME null-terminated string.                */
++/*   der: string returned.                            */
++/*   der_len: number of meaningful bytes of DER       */
++/*            (der[0]..der[ans_len-1]). Initially it  */
++/*            if must store the lenght of DER.        */
++/* Return:                                            */
++/*   ASN1_MEM_ERROR when DER isn't big enough         */
++/*   ASN1_SUCCESS otherwise                           */
++/******************************************************/
++static int
++_asn1_time_der (unsigned char *str, int str_len, unsigned char *der,
++		int *der_len)
++{
++  int len_len;
++  int max_len;
++
++  if (der == NULL)
++    return ASN1_VALUE_NOT_VALID;
++
++  max_len = *der_len;
++
++  asn1_length_der (str_len, (max_len > 0) ? der : NULL, &len_len);
++
++  if ((len_len + str_len) <= max_len)
++    memcpy (der + len_len, str, str_len);
++  *der_len = len_len + str_len;
++
++  if ((*der_len) > max_len)
++    return ASN1_MEM_ERROR;
++
++  return ASN1_SUCCESS;
++}
++
++
++/*
++void
++_asn1_get_utctime_der(unsigned char *der,int *der_len,unsigned char *str)
++{
++  int len_len,str_len;
++  char temp[20];
++
++  if(str==NULL) return;
++  str_len=asn1_get_length_der(der,*der_len,&len_len);
++  if (str_len<0) return;
++  memcpy(temp,der+len_len,str_len);
++  *der_len=str_len+len_len;
++  switch(str_len)
++  {
++  case 11:
++    temp[10]=0;
++    strcat(temp,"00+0000");
++    break;
++  case 13:
++    temp[12]=0;
++    strcat(temp,"+0000");
++    break;
++  case 15:
++    temp[15]=0;
++    memmove(temp+12,temp+10,6);
++    temp[10]=temp[11]='0';
++    break;
++  case 17:
++    temp[17]=0;
++    break;
++  default:
++    return;
++  }
++  strcpy(str,temp);
++}
++*/
++
++static
++void encode_val(uint64_t val, unsigned char *der, int max_len, int *der_len)
++{
++  int first, k;
++  unsigned char bit7;
++
++  first = 0;
++  for (k = sizeof(val); k >= 0; k--)
++    {
++      bit7 = (val >> (k * 7)) & 0x7F;
++      if (bit7 || first || !k)
++	{
++	  if (k)
++	    bit7 |= 0x80;
++	  if (max_len > (*der_len))
++	    der[*der_len] = bit7;
++	  (*der_len)++;
++	  first = 1;
++	}
++    }
++}
++
++/******************************************************/
++/* Function : _asn1_object_id_der                     */
++/* Description: creates the DER coding for an         */
++/* OBJECT IDENTIFIER  type (length included).         */
++/* Parameters:                                        */
++/*   str: OBJECT IDENTIFIER null-terminated string.   */
++/*   der: string returned.                            */
++/*   der_len: number of meaningful bytes of DER       */
++/*            (der[0]..der[ans_len-1]). Initially it  */
++/*            must store the length of DER.           */
++/* Return:                                            */
++/*   ASN1_MEM_ERROR when DER isn't big enough         */
++/*   ASN1_SUCCESS if succesful                        */
++/*   or an error value.                               */
++/******************************************************/
++static int
++_asn1_object_id_der (const char *str, unsigned char *der, int *der_len)
++{
++  int len_len, counter, max_len;
++  char *temp, *n_end, *n_start;
++  uint64_t val, val1 = 0;
++  int str_len = _asn1_strlen (str);
++
++  max_len = *der_len;
++  *der_len = 0;
++
++  if (der == NULL && max_len > 0)
++    return ASN1_VALUE_NOT_VALID;
++
++  temp = malloc (str_len + 2);
++  if (temp == NULL)
++    return ASN1_MEM_ALLOC_ERROR;
++
++  memcpy (temp, str, str_len);
++  temp[str_len] = '.';
++  temp[str_len + 1] = 0;
++
++  counter = 0;
++  n_start = temp;
++  while ((n_end = strchr (n_start, '.')))
++    {
++      *n_end = 0;
++      val = _asn1_strtou64 (n_start, NULL, 10);
++      counter++;
++
++      if (counter == 1)
++        {
++	  val1 = val;
++	}
++      else if (counter == 2)
++	{
++	  uint64_t val0;
++
++          if (val1 > 2)
++            {
++              free(temp);
++              return ASN1_VALUE_NOT_VALID;
++            }
++          else if ((val1 == 0 || val1 == 1) && val > 39)
++            {
++              free(temp);
++              return ASN1_VALUE_NOT_VALID;
++            }
++
++	  val0 = 40 * val1 + val;
++	  encode_val(val0, der, max_len, der_len);
++	}
++      else
++	{
++	  encode_val(val, der, max_len, der_len);
++	}
++      n_start = n_end + 1;
++    }
++
++  asn1_length_der (*der_len, NULL, &len_len);
++  if (max_len >= (*der_len + len_len))
++    {
++      memmove (der + len_len, der, *der_len);
++      asn1_length_der (*der_len, der, &len_len);
++    }
++  *der_len += len_len;
++
++  free (temp);
++
++  if (max_len < (*der_len))
++    return ASN1_MEM_ERROR;
++
++  return ASN1_SUCCESS;
++}
++
++/**
++ * asn1_object_id_der:
++ * @str: An object identifier in numeric, dot format.
++ * @der: buffer to hold the returned encoding (may be %NULL).
++ * @der_len: initially the size of @der; will hold the final size.
++ * @flags: must be zero
++ *
++ * Creates the DER encoding of the provided object identifier.
++ *
++ * Returns: %ASN1_SUCCESS if DER encoding was OK, %ASN1_VALUE_NOT_VALID
++ *   if @str is not a valid OID, %ASN1_MEM_ERROR if the @der
++ *   vector isn't big enough and in this case @der_len will contain the
++ *   length needed.
++ **/
++int asn1_object_id_der(const char *str, unsigned char *der, int *der_len, unsigned flags)
++{
++  unsigned char tag_der[MAX_TAG_LEN];
++  int tag_len = 0, r;
++  int max_len = *der_len;
++
++  *der_len = 0;
++
++  _asn1_tag_der (ETYPE_CLASS (ASN1_ETYPE_OBJECT_ID), ETYPE_TAG (ASN1_ETYPE_OBJECT_ID),
++                 tag_der, &tag_len);
++
++  if (max_len > tag_len)
++    {
++      memcpy(der, tag_der, tag_len);
++    }
++  max_len -= tag_len;
++  der += tag_len;
++
++  r = _asn1_object_id_der (str, der, &max_len);
++  if (r == ASN1_MEM_ERROR || r == ASN1_SUCCESS)
++    {
++      *der_len = max_len + tag_len;
++    }
++
++  return r;
++}
++
++static const unsigned char bit_mask[] =
++  { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80 };
++
++/**
++ * asn1_bit_der:
++ * @str: BIT string.
++ * @bit_len: number of meaningful bits in STR.
++ * @der: string returned.
++ * @der_len: number of meaningful bytes of DER
++ *   (der[0]..der[ans_len-1]).
++ *
++ * Creates a length-value DER encoding for the input data
++ * as it would have been for a BIT STRING.
++ * The DER encoded data will be copied in @der.
++ *
++ * Note that the BIT STRING tag is not included in the output.
++ *
++ * This function does not return any value because it is expected
++ * that @der_len will contain enough bytes to store the string
++ * plus the DER encoding. The DER encoding size can be obtained using
++ * asn1_length_der().
++ **/
++void
++asn1_bit_der (const unsigned char *str, int bit_len,
++	      unsigned char *der, int *der_len)
++{
++  int len_len, len_byte, len_pad;
++
++  if (der == NULL)
++    return;
++
++  len_byte = bit_len >> 3;
++  len_pad = 8 - (bit_len & 7);
++  if (len_pad == 8)
++    len_pad = 0;
++  else
++    len_byte++;
++  asn1_length_der (len_byte + 1, der, &len_len);
++  der[len_len] = len_pad;
++
++  if (str)
++    memcpy (der + len_len + 1, str, len_byte);
++  der[len_len + len_byte] &= bit_mask[len_pad];
++  *der_len = len_byte + len_len + 1;
++}
++
++
++/******************************************************/
++/* Function : _asn1_complete_explicit_tag             */
++/* Description: add the length coding to the EXPLICIT */
++/* tags.                                              */
++/* Parameters:                                        */
++/*   node: pointer to the tree element.               */
++/*   der: string with the DER coding of the whole tree*/
++/*   counter: number of meaningful bytes of DER       */
++/*            (der[0]..der[*counter-1]).              */
++/*   max_len: size of der vector                      */
++/* Return:                                            */
++/*   ASN1_MEM_ERROR if der vector isn't big enough,   */
++/*   otherwise ASN1_SUCCESS.                          */
++/******************************************************/
++static int
++_asn1_complete_explicit_tag (asn1_node node, unsigned char *der,
++			     int *counter, int *max_len)
++{
++  asn1_node p;
++  int is_tag_implicit, len2, len3;
++  unsigned char temp[SIZEOF_UNSIGNED_INT];
++
++  if (der == NULL && *max_len > 0)
++    return ASN1_VALUE_NOT_VALID;
++
++  is_tag_implicit = 0;
++
++  if (node->type & CONST_TAG)
++    {
++      p = node->down;
++      if (p == NULL)
++        return ASN1_DER_ERROR;
++      /* When there are nested tags we must complete them reverse to
++         the order they were created. This is because completing a tag
++         modifies all data within it, including the incomplete tags
++         which store buffer positions -- simon@josefsson.org 2002-09-06
++       */
++      while (p->right)
++	p = p->right;
++      while (p && p != node->down->left)
++	{
++	  if (type_field (p->type) == ASN1_ETYPE_TAG)
++	    {
++	      if (p->type & CONST_EXPLICIT)
++		{
++		  len2 = strtol (p->name, NULL, 10);
++		  _asn1_set_name (p, NULL);
++
++		  asn1_length_der (*counter - len2, temp, &len3);
++		  if (len3 <= (*max_len))
++		    {
++		      memmove (der + len2 + len3, der + len2,
++			       *counter - len2);
++		      memcpy (der + len2, temp, len3);
++		    }
++		  *max_len -= len3;
++		  *counter += len3;
++		  is_tag_implicit = 0;
++		}
++	      else
++		{		/* CONST_IMPLICIT */
++		  if (!is_tag_implicit)
++		    {
++		      is_tag_implicit = 1;
++		    }
++		}
++	    }
++	  p = p->left;
++	}
++    }
++
++  if (*max_len < 0)
++    return ASN1_MEM_ERROR;
++
++  return ASN1_SUCCESS;
++}
++
++const tag_and_class_st _asn1_tags[] = {
++  [ASN1_ETYPE_GENERALSTRING] =
++    {ASN1_TAG_GENERALSTRING, ASN1_CLASS_UNIVERSAL, "type:GENERALSTRING"},
++  [ASN1_ETYPE_NUMERIC_STRING] =
++    {ASN1_TAG_NUMERIC_STRING, ASN1_CLASS_UNIVERSAL, "type:NUMERIC_STR"},
++  [ASN1_ETYPE_IA5_STRING] =
++    {ASN1_TAG_IA5_STRING, ASN1_CLASS_UNIVERSAL, "type:IA5_STR"},
++  [ASN1_ETYPE_TELETEX_STRING] =
++    {ASN1_TAG_TELETEX_STRING, ASN1_CLASS_UNIVERSAL, "type:TELETEX_STR"},
++  [ASN1_ETYPE_PRINTABLE_STRING] =
++    {ASN1_TAG_PRINTABLE_STRING, ASN1_CLASS_UNIVERSAL, "type:PRINTABLE_STR"},
++  [ASN1_ETYPE_UNIVERSAL_STRING] =
++    {ASN1_TAG_UNIVERSAL_STRING, ASN1_CLASS_UNIVERSAL, "type:UNIVERSAL_STR"},
++  [ASN1_ETYPE_BMP_STRING] =
++    {ASN1_TAG_BMP_STRING, ASN1_CLASS_UNIVERSAL, "type:BMP_STR"},
++  [ASN1_ETYPE_UTF8_STRING] =
++    {ASN1_TAG_UTF8_STRING, ASN1_CLASS_UNIVERSAL, "type:UTF8_STR"},
++  [ASN1_ETYPE_VISIBLE_STRING] =
++    {ASN1_TAG_VISIBLE_STRING, ASN1_CLASS_UNIVERSAL, "type:VISIBLE_STR"},
++  [ASN1_ETYPE_OCTET_STRING] =
++    {ASN1_TAG_OCTET_STRING, ASN1_CLASS_UNIVERSAL, "type:OCT_STR"},
++  [ASN1_ETYPE_BIT_STRING] =
++    {ASN1_TAG_BIT_STRING, ASN1_CLASS_UNIVERSAL, "type:BIT_STR"},
++  [ASN1_ETYPE_OBJECT_ID] =
++    {ASN1_TAG_OBJECT_ID, ASN1_CLASS_UNIVERSAL, "type:OBJ_ID"},
++  [ASN1_ETYPE_NULL] = {ASN1_TAG_NULL, ASN1_CLASS_UNIVERSAL, "type:NULL"},
++  [ASN1_ETYPE_BOOLEAN] =
++    {ASN1_TAG_BOOLEAN, ASN1_CLASS_UNIVERSAL, "type:BOOLEAN"},
++  [ASN1_ETYPE_INTEGER] =
++    {ASN1_TAG_INTEGER, ASN1_CLASS_UNIVERSAL, "type:INTEGER"},
++  [ASN1_ETYPE_ENUMERATED] =
++    {ASN1_TAG_ENUMERATED, ASN1_CLASS_UNIVERSAL, "type:ENUMERATED"},
++  [ASN1_ETYPE_SEQUENCE] =
++    {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED,
++     "type:SEQUENCE"},
++  [ASN1_ETYPE_SEQUENCE_OF] =
++    {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED,
++     "type:SEQ_OF"},
++  [ASN1_ETYPE_SET] =
++    {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, "type:SET"},
++  [ASN1_ETYPE_SET_OF] =
++    {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED,
++     "type:SET_OF"},
++  [ASN1_ETYPE_GENERALIZED_TIME] =
++    {ASN1_TAG_GENERALIZEDTime, ASN1_CLASS_UNIVERSAL, "type:GENERALIZED_TIME"},
++  [ASN1_ETYPE_UTC_TIME] =
++    {ASN1_TAG_UTCTime, ASN1_CLASS_UNIVERSAL, "type:UTC_TIME"},
++};
++
++unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]);
++
++/******************************************************/
++/* Function : _asn1_insert_tag_der                    */
++/* Description: creates the DER coding of tags of one */
++/* NODE.                                              */
++/* Parameters:                                        */
++/*   node: pointer to the tree element.               */
++/*   der: string returned                             */
++/*   counter: number of meaningful bytes of DER       */
++/*            (counter[0]..der[*counter-1]).          */
++/*   max_len: size of der vector                      */
++/* Return:                                            */
++/*   ASN1_GENERIC_ERROR if the type is unknown,       */
++/*   ASN1_MEM_ERROR if der vector isn't big enough,   */
++/*   otherwise ASN1_SUCCESS.                          */
++/******************************************************/
++static int
++_asn1_insert_tag_der (asn1_node node, unsigned char *der, int *counter,
++		      int *max_len)
++{
++  asn1_node p;
++  int tag_len, is_tag_implicit;
++  unsigned char class, class_implicit = 0, temp[MAX(SIZEOF_UNSIGNED_INT * 3 + 1, LTOSTR_MAX_SIZE)];
++  unsigned long tag_implicit = 0;
++  unsigned char tag_der[MAX_TAG_LEN];
++
++  is_tag_implicit = 0;
++
++  if (node->type & CONST_TAG)
++    {
++      p = node->down;
++      while (p)
++	{
++	  if (type_field (p->type) == ASN1_ETYPE_TAG)
++	    {
++	      if (p->type & CONST_APPLICATION)
++		class = ASN1_CLASS_APPLICATION;
++	      else if (p->type & CONST_UNIVERSAL)
++		class = ASN1_CLASS_UNIVERSAL;
++	      else if (p->type & CONST_PRIVATE)
++		class = ASN1_CLASS_PRIVATE;
++	      else
++		class = ASN1_CLASS_CONTEXT_SPECIFIC;
++
++	      if (p->type & CONST_EXPLICIT)
++		{
++		  if (is_tag_implicit)
++		    _asn1_tag_der (class_implicit, tag_implicit, tag_der,
++				   &tag_len);
++		  else
++		    _asn1_tag_der (class | ASN1_CLASS_STRUCTURED,
++				   _asn1_strtoul (p->value, NULL, 10),
++				   tag_der, &tag_len);
++
++		  *max_len -= tag_len;
++		  if (der && *max_len >= 0)
++		    memcpy (der + *counter, tag_der, tag_len);
++		  *counter += tag_len;
++
++		  _asn1_ltostr (*counter, (char *) temp);
++		  _asn1_set_name (p, (const char *) temp);
++
++		  is_tag_implicit = 0;
++		}
++	      else
++		{		/* CONST_IMPLICIT */
++		  if (!is_tag_implicit)
++		    {
++		      if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) ||
++			  (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF)
++			  || (type_field (node->type) == ASN1_ETYPE_SET)
++			  || (type_field (node->type) == ASN1_ETYPE_SET_OF))
++			class |= ASN1_CLASS_STRUCTURED;
++		      class_implicit = class;
++		      tag_implicit = _asn1_strtoul (p->value, NULL, 10);
++		      is_tag_implicit = 1;
++		    }
++		}
++	    }
++	  p = p->right;
++	}
++    }
++
++  if (is_tag_implicit)
++    {
++      _asn1_tag_der (class_implicit, tag_implicit, tag_der, &tag_len);
++    }
++  else
++    {
++      unsigned type = type_field (node->type);
++      switch (type)
++	{
++	CASE_HANDLED_ETYPES:
++	  _asn1_tag_der (_asn1_tags[type].class, _asn1_tags[type].tag,
++			 tag_der, &tag_len);
++	  break;
++	case ASN1_ETYPE_TAG:
++	case ASN1_ETYPE_CHOICE:
++	case ASN1_ETYPE_ANY:
++	  tag_len = 0;
++	  break;
++	default:
++	  return ASN1_GENERIC_ERROR;
++	}
++    }
++
++  *max_len -= tag_len;
++  if (der && *max_len >= 0)
++    memcpy (der + *counter, tag_der, tag_len);
++  *counter += tag_len;
++
++  if (*max_len < 0)
++    return ASN1_MEM_ERROR;
++
++  return ASN1_SUCCESS;
++}
++
++/******************************************************/
++/* Function : _asn1_ordering_set                      */
++/* Description: puts the elements of a SET type in    */
++/* the correct order according to DER rules.          */
++/* Parameters:                                        */
++/*   der: string with the DER coding.                 */
++/*   node: pointer to the SET element.                */
++/* Return:                                            */
++/*    ASN1_SUCCESS if successful                      */
++/*    or an error value.                              */
++/******************************************************/
++static int
++_asn1_ordering_set (unsigned char *der, int der_len, asn1_node node)
++{
++  struct vet
++  {
++    int end;
++    unsigned long value;
++    struct vet *next, *prev;
++  };
++
++  int counter, len, len2;
++  struct vet *first, *last, *p_vet, *p2_vet;
++  asn1_node p;
++  unsigned char class, *temp;
++  unsigned long tag, t;
++  int err;
++
++  counter = 0;
++
++  if (type_field (node->type) != ASN1_ETYPE_SET)
++    return ASN1_VALUE_NOT_VALID;
++
++  p = node->down;
++  while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) ||
++	 (type_field (p->type) == ASN1_ETYPE_SIZE)))
++    p = p->right;
++
++  if ((p == NULL) || (p->right == NULL))
++    return ASN1_SUCCESS;
++
++  first = last = NULL;
++  while (p)
++    {
++      p_vet = malloc (sizeof (struct vet));
++      if (p_vet == NULL)
++        {
++	  err = ASN1_MEM_ALLOC_ERROR;
++	  goto error;
++	}
++
++      p_vet->next = NULL;
++      p_vet->prev = last;
++      if (first == NULL)
++	first = p_vet;
++      else
++	last->next = p_vet;
++      last = p_vet;
++
++      /* tag value calculation */
++      err = asn1_get_tag_der (der + counter, der_len - counter, &class, &len2,
++			      &tag);
++      if (err != ASN1_SUCCESS)
++	goto error;
++
++      t = ((unsigned int)class) << 24;
++      p_vet->value = t | tag;
++      counter += len2;
++
++      /* extraction and length */
++      len2 = asn1_get_length_der (der + counter, der_len - counter, &len);
++      if (len2 < 0)
++	{
++	  err = ASN1_DER_ERROR;
++	  goto error;
++	}
++      counter += len + len2;
++
++      p_vet->end = counter;
++      p = p->right;
++    }
++
++  p_vet = first;
++
++  while (p_vet)
++    {
++      p2_vet = p_vet->next;
++      counter = 0;
++      while (p2_vet)
++	{
++	  if (p_vet->value > p2_vet->value)
++	    {
++	      /* change position */
++	      temp = malloc (p_vet->end - counter);
++	      if (temp == NULL)
++		{
++		  err = ASN1_MEM_ALLOC_ERROR;
++		  goto error;
++		}
++
++	      memcpy (temp, der + counter, p_vet->end - counter);
++	      memcpy (der + counter, der + p_vet->end,
++		      p2_vet->end - p_vet->end);
++	      memcpy (der + counter + p2_vet->end - p_vet->end, temp,
++		      p_vet->end - counter);
++	      free (temp);
++
++	      tag = p_vet->value;
++	      p_vet->value = p2_vet->value;
++	      p2_vet->value = tag;
++
++	      p_vet->end = counter + (p2_vet->end - p_vet->end);
++	    }
++	  counter = p_vet->end;
++
++	  p2_vet = p2_vet->next;
++	  p_vet = p_vet->next;
++	}
++
++      if (p_vet != first)
++	p_vet->prev->next = NULL;
++      else
++	first = NULL;
++      free (p_vet);
++      p_vet = first;
++    }
++  return ASN1_SUCCESS;
++
++error:
++  while (first != NULL)
++    {
++      p_vet = first;
++      first = first->next;
++      free(p_vet);
++    }
++  return err;
++}
++
++struct vet
++{
++  unsigned char *ptr;
++  int size;
++};
++
++static int setof_compar(const void *_e1, const void *_e2)
++{
++  unsigned length;
++  const struct vet *e1 = _e1, *e2 = _e2;
++  int rval;
++
++  /* The encodings of the component values of a set-of value shall
++   * appear in ascending order, the encodings being compared
++   * as octet strings with the shorter components being
++   * padded at their trailing end with 0-octets.
++   * The padding octets are for comparison purposes and
++   * do not appear in the encodings.
++   */
++  length = MIN(e1->size, e2->size);
++
++  rval = memcmp(e1->ptr, e2->ptr, length);
++  if (rval == 0 && e1->size != e2->size)
++    {
++      if (e1->size > e2->size)
++        rval = 1;
++      else if (e2->size > e1->size)
++        rval = -1;
++    }
++
++  return rval;
++}
++
++/******************************************************/
++/* Function : _asn1_ordering_set_of                   */
++/* Description: puts the elements of a SET OF type in */
++/* the correct order according to DER rules.          */
++/* Parameters:                                        */
++/*   der: string with the DER coding.                 */
++/*   node: pointer to the SET OF element.             */
++/* Return:                                            */
++/*    ASN1_SUCCESS if successful                      */
++/*    or an error value.                              */
++/******************************************************/
++static int
++_asn1_ordering_set_of (unsigned char *der, int der_len, asn1_node node)
++{
++  int counter, len, len2;
++  struct vet *list = NULL, *tlist;
++  unsigned list_size = 0;
++  struct vet *p_vet;
++  asn1_node p;
++  unsigned char class;
++  unsigned i;
++  unsigned char *out = NULL;
++  int err;
++
++  if (der == NULL)
++    return ASN1_VALUE_NOT_VALID;
++
++  counter = 0;
++
++  if (type_field (node->type) != ASN1_ETYPE_SET_OF)
++    return ASN1_VALUE_NOT_VALID;
++
++  p = node->down;
++  while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) ||
++	 (type_field (p->type) == ASN1_ETYPE_SIZE)))
++    p = p->right;
++  if (p == NULL)
++    return ASN1_VALUE_NOT_VALID;
++  p = p->right;
++
++  if ((p == NULL) || (p->right == NULL))
++    return ASN1_SUCCESS;
++
++  while (p)
++    {
++      list_size++;
++      tlist = realloc (list, list_size*sizeof(struct vet));
++      if (tlist == NULL)
++	{
++	  err = ASN1_MEM_ALLOC_ERROR;
++	  goto error;
++	}
++      list = tlist;
++      p_vet = &list[list_size-1];
++
++      p_vet->ptr = der+counter;
++      p_vet->size = 0;
++
++      /* extraction of tag and length */
++      if (der_len - counter > 0)
++	{
++	  err = asn1_get_tag_der (der + counter, der_len - counter, &class,
++	                          &len, NULL);
++	  if (err != ASN1_SUCCESS)
++	    goto error;
++	  counter += len;
++          p_vet->size += len;
++
++	  len2 = asn1_get_length_der (der + counter, der_len - counter, &len);
++	  if (len2 < 0)
++	    {
++	      err = ASN1_DER_ERROR;
++	      goto error;
++	    }
++	  counter += len + len2;
++          p_vet->size += len + len2;
++
++	}
++      else
++	{
++	  err = ASN1_DER_ERROR;
++	  goto error;
++	}
++      p = p->right;
++    }
++
++  if (counter > der_len)
++    {
++      err = ASN1_DER_ERROR;
++      goto error;
++    }
++
++  qsort(list, list_size, sizeof(struct vet), setof_compar);
++
++  out = malloc(der_len);
++  if (out == NULL)
++    {
++      err = ASN1_MEM_ERROR;
++      goto error;
++    }
++
++  /* the sum of p_vet->size == der_len */
++  counter = 0;
++  for (i = 0; i < list_size; i++)
++    {
++      p_vet = &list[i];
++      memcpy(out+counter, p_vet->ptr, p_vet->size);
++      counter += p_vet->size;
++    }
++  memcpy(der, out, der_len);
++  free(out);
++
++  err = ASN1_SUCCESS;
++
++error:
++  free(list);
++  return err;
++}
++
++/**
++ * asn1_der_coding:
++ * @element: pointer to an ASN1 element
++ * @name: the name of the structure you want to encode (it must be
++ *   inside *POINTER).
++ * @ider: vector that will contain the DER encoding. DER must be a
++ *   pointer to memory cells already allocated.
++ * @len: number of bytes of *@ider: @ider[0]..@ider[len-1], Initialy
++ *   holds the sizeof of der vector.
++ * @ErrorDescription: return the error description or an empty
++ *   string if success.
++ *
++ * Creates the DER encoding for the NAME structure (inside *POINTER
++ * structure).
++ *
++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
++ *   if @name is not a valid element, %ASN1_VALUE_NOT_FOUND if there
++ *   is an element without a value, %ASN1_MEM_ERROR if the @ider
++ *   vector isn't big enough and in this case @len will contain the
++ *   length needed.
++ **/
++int
++asn1_der_coding (asn1_node_const element, const char *name, void *ider, int *len,
++		 char *ErrorDescription)
++{
++  asn1_node node, p, p2;
++  unsigned char temp[MAX(LTOSTR_MAX_SIZE, SIZEOF_UNSIGNED_LONG_INT * 3 + 1)];
++  int counter, counter_old, len2, len3, move, max_len, max_len_old;
++  int err;
++  unsigned char *der = ider;
++
++  if (ErrorDescription)
++    ErrorDescription[0] = 0;
++
++  node = asn1_find_node (element, name);
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  /* Node is now a locally allocated variable.
++   * That is because in some point we modify the
++   * structure, and I don't know why! --nmav
++   */
++  node = _asn1_copy_structure3 (node);
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  max_len = *len;
++
++  if (der == NULL && max_len > 0)
++    return ASN1_VALUE_NOT_VALID;
++
++  counter = 0;
++  move = DOWN;
++  p = node;
++
++  while (1)
++    {
++
++      counter_old = counter;
++      max_len_old = max_len;
++      if (move != UP)
++	{
++          p->start = counter;
++	  err = _asn1_insert_tag_der (p, der, &counter, &max_len);
++	  if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
++	    goto error;
++	}
++      switch (type_field (p->type))
++	{
++	case ASN1_ETYPE_NULL:
++	  max_len--;
++	  if (der != NULL && max_len >= 0)
++	    der[counter] = 0;
++	  counter++;
++	  move = RIGHT;
++	  break;
++	case ASN1_ETYPE_BOOLEAN:
++	  if ((p->type & CONST_DEFAULT) && (p->value == NULL))
++	    {
++	      counter = counter_old;
++	      max_len = max_len_old;
++	    }
++	  else
++	    {
++	      if (p->value == NULL)
++		{
++		  _asn1_error_description_value_not_found (p,
++							   ErrorDescription);
++		  err = ASN1_VALUE_NOT_FOUND;
++		  goto error;
++		}
++	      max_len -= 2;
++	      if (der != NULL && max_len >= 0)
++		{
++		  der[counter++] = 1;
++		  if (p->value[0] == 'F')
++		    der[counter++] = 0;
++		  else
++		    der[counter++] = 0xFF;
++		}
++	      else
++		counter += 2;
++	    }
++	  move = RIGHT;
++	  break;
++	case ASN1_ETYPE_INTEGER:
++	case ASN1_ETYPE_ENUMERATED:
++	  if ((p->type & CONST_DEFAULT) && (p->value == NULL))
++	    {
++	      counter = counter_old;
++	      max_len = max_len_old;
++	    }
++	  else
++	    {
++	      if (p->value == NULL)
++		{
++		  _asn1_error_description_value_not_found (p,
++							   ErrorDescription);
++		  err = ASN1_VALUE_NOT_FOUND;
++		  goto error;
++		}
++	      len2 = asn1_get_length_der (p->value, p->value_len, &len3);
++	      if (len2 < 0)
++		{
++		  err = ASN1_DER_ERROR;
++		  goto error;
++		}
++	      max_len -= len2 + len3;
++	      if (der != NULL && max_len >= 0)
++		memcpy (der + counter, p->value, len3 + len2);
++	      counter += len3 + len2;
++	    }
++	  move = RIGHT;
++	  break;
++	case ASN1_ETYPE_OBJECT_ID:
++	  if ((p->type & CONST_DEFAULT) && (p->value == NULL))
++	    {
++	      counter = counter_old;
++	      max_len = max_len_old;
++	    }
++	  else
++	    {
++	      if (p->value == NULL)
++		{
++		  _asn1_error_description_value_not_found (p,
++							   ErrorDescription);
++		  err = ASN1_VALUE_NOT_FOUND;
++		  goto error;
++		}
++	      len2 = max_len;
++	      err = _asn1_object_id_der ((char*)p->value, der + counter, &len2);
++	      if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
++		goto error;
++
++	      max_len -= len2;
++	      counter += len2;
++	    }
++	  move = RIGHT;
++	  break;
++	case ASN1_ETYPE_GENERALIZED_TIME:
++	case ASN1_ETYPE_UTC_TIME:
++	  if (p->value == NULL)
++	    {
++	      _asn1_error_description_value_not_found (p, ErrorDescription);
++	      err = ASN1_VALUE_NOT_FOUND;
++	      goto error;
++	    }
++	  len2 = max_len;
++	  err = _asn1_time_der (p->value, p->value_len, der + counter, &len2);
++	  if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
++	    goto error;
++
++	  max_len -= len2;
++	  counter += len2;
++	  move = RIGHT;
++	  break;
++	case ASN1_ETYPE_OCTET_STRING:
++	case ASN1_ETYPE_GENERALSTRING:
++	case ASN1_ETYPE_NUMERIC_STRING:
++	case ASN1_ETYPE_IA5_STRING:
++	case ASN1_ETYPE_TELETEX_STRING:
++	case ASN1_ETYPE_PRINTABLE_STRING:
++	case ASN1_ETYPE_UNIVERSAL_STRING:
++	case ASN1_ETYPE_BMP_STRING:
++	case ASN1_ETYPE_UTF8_STRING:
++	case ASN1_ETYPE_VISIBLE_STRING:
++	case ASN1_ETYPE_BIT_STRING:
++	  if (p->value == NULL)
++	    {
++	      _asn1_error_description_value_not_found (p, ErrorDescription);
++	      err = ASN1_VALUE_NOT_FOUND;
++	      goto error;
++	    }
++	  len2 = asn1_get_length_der (p->value, p->value_len, &len3);
++	  if (len2 < 0)
++	    {
++	      err = ASN1_DER_ERROR;
++	      goto error;
++	    }
++	  max_len -= len2 + len3;
++	  if (der != NULL && max_len >= 0)
++	    memcpy (der + counter, p->value, len3 + len2);
++	  counter += len3 + len2;
++	  move = RIGHT;
++	  break;
++	case ASN1_ETYPE_SEQUENCE:
++	case ASN1_ETYPE_SET:
++	  if (move != UP)
++	    {
++	      p->tmp_ival = counter;
++	      if (p->down == NULL)
++		{
++		  move = UP;
++		  continue;
++		}
++	      else
++		{
++		  p2 = p->down;
++		  while (p2 && (type_field (p2->type) == ASN1_ETYPE_TAG))
++		    p2 = p2->right;
++		  if (p2)
++		    {
++		      p = p2;
++		      move = RIGHT;
++		      continue;
++		    }
++		  move = UP;
++		  continue;
++		}
++	    }
++	  else
++	    {			/* move==UP */
++	      len2 = p->tmp_ival;
++	      p->tmp_ival = 0;
++	      if ((type_field (p->type) == ASN1_ETYPE_SET) && (max_len >= 0))
++		{
++		  err = _asn1_ordering_set (der + len2, counter - len2, p);
++		  if (err != ASN1_SUCCESS)
++		    goto error;
++		}
++	      asn1_length_der (counter - len2, temp, &len3);
++	      max_len -= len3;
++	      if (der != NULL && max_len >= 0)
++		{
++		  memmove (der + len2 + len3, der + len2, counter - len2);
++		  memcpy (der + len2, temp, len3);
++		}
++	      counter += len3;
++	      move = RIGHT;
++	    }
++	  break;
++	case ASN1_ETYPE_SEQUENCE_OF:
++	case ASN1_ETYPE_SET_OF:
++	  if (move != UP)
++	    {
++	      p->tmp_ival = counter;
++	      p = p->down;
++	      while ((type_field (p->type) == ASN1_ETYPE_TAG)
++		     || (type_field (p->type) == ASN1_ETYPE_SIZE))
++		p = p->right;
++	      if (p->right)
++		{
++		  p = p->right;
++		  move = RIGHT;
++		  continue;
++		}
++	      else
++		p = _asn1_find_up (p);
++	      move = UP;
++	    }
++	  if (move == UP)
++	    {
++	      len2 = p->tmp_ival;
++	      p->tmp_ival = 0;
++	      if ((type_field (p->type) == ASN1_ETYPE_SET_OF)
++		  && (counter - len2 > 0) && (max_len >= 0))
++		{
++		  err = _asn1_ordering_set_of (der + len2, counter - len2, p);
++		  if (err != ASN1_SUCCESS)
++		    goto error;
++		}
++	      asn1_length_der (counter - len2, temp, &len3);
++	      max_len -= len3;
++	      if (der != NULL && max_len >= 0)
++		{
++		  memmove (der + len2 + len3, der + len2, counter - len2);
++		  memcpy (der + len2, temp, len3);
++		}
++	      counter += len3;
++	      move = RIGHT;
++	    }
++	  break;
++	case ASN1_ETYPE_ANY:
++	  if (p->value == NULL)
++	    {
++	      _asn1_error_description_value_not_found (p, ErrorDescription);
++	      err = ASN1_VALUE_NOT_FOUND;
++	      goto error;
++	    }
++	  len2 = asn1_get_length_der (p->value, p->value_len, &len3);
++	  if (len2 < 0)
++	    {
++	      err = ASN1_DER_ERROR;
++	      goto error;
++	    }
++	  max_len -= len2;
++	  if (der != NULL && max_len >= 0)
++	    memcpy (der + counter, p->value + len3, len2);
++	  counter += len2;
++	  move = RIGHT;
++	  break;
++	default:
++	  move = (move == UP) ? RIGHT : DOWN;
++	  break;
++	}
++
++      if ((move != DOWN) && (counter != counter_old))
++	{
++          p->end = counter - 1;
++	  err = _asn1_complete_explicit_tag (p, der, &counter, &max_len);
++	  if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
++	    goto error;
++	}
++
++      if (p == node && move != DOWN)
++	break;
++
++      if (move == DOWN)
++	{
++	  if (p->down)
++	    p = p->down;
++	  else
++	    move = RIGHT;
++	}
++      if (move == RIGHT)
++	{
++	  if (p->right)
++	    p = p->right;
++	  else
++	    move = UP;
++	}
++      if (move == UP)
++	p = _asn1_find_up (p);
++    }
++
++  *len = counter;
++
++  if (max_len < 0)
++    {
++      err = ASN1_MEM_ERROR;
++      goto error;
++    }
++
++  err = ASN1_SUCCESS;
++
++error:
++  asn1_delete_structure (&node);
++  return err;
++}
+diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c
+new file mode 100644
+index 0000000000..ff04eb778c
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/decoding.c
+@@ -0,0 +1,2478 @@
++/*
++ * Copyright (C) 2002-2016 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++
++/*****************************************************/
++/* File: decoding.c                                  */
++/* Description: Functions to manage DER decoding     */
++/*****************************************************/
++
++#include <int.h>
++#include <parser_aux.h>
++#include <gstr.h>
++#include <structure.h>
++#include <element.h>
++#include <limits.h>
++#include <intprops.h>
++#include <c-ctype.h>
++
++#ifdef DEBUG
++# define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__)
++#else
++# define warn()
++#endif
++
++#define IS_ERR(len, flags) (len < -1 || ((flags & ASN1_DECODE_FLAG_STRICT_DER) && len < 0))
++
++#define HAVE_TWO(x) (x>=2?1:0)
++
++/* Decoding flags (dflags) used in several decoding functions.
++ *  DECODE_FLAG_HAVE_TAG: The provided buffer includes a tag
++ *  DECODE_FLAG_CONSTRUCTED: The provided buffer is of indefinite encoding (useful
++ *                           when no tags are present).
++ *  DECODE_FLAG_LEVEL1: Internal flag to indicate a level of recursion for BER strings.
++ *  DECODE_FLAG_LEVEL2: Internal flag to indicate two levels of recursion for BER strings.
++ *  DECODE_FLAG_LEVEL3: Internal flag to indicate three levels of recursion for BER strings.
++ *                      This is the maximum levels of recursion possible to prevent stack
++ *                      exhaustion.
++ */
++
++#define DECODE_FLAG_HAVE_TAG 1
++#define DECODE_FLAG_CONSTRUCTED (1<<1)
++#define DECODE_FLAG_LEVEL1 (1<<2)
++#define DECODE_FLAG_LEVEL2 (1<<3)
++#define DECODE_FLAG_LEVEL3 (1<<4)
++
++#define DECR_LEN(l, s) do { \
++	  l -= s; \
++	  if (l < 0) { \
++	    warn(); \
++	    result = ASN1_DER_ERROR; \
++	    goto cleanup; \
++	  } \
++	} while (0)
++
++static int
++_asn1_get_indefinite_length_string (const unsigned char *der, int der_len, int *len);
++
++static int
++_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
++			unsigned int _der_len, unsigned char **str,
++			unsigned int *str_len, unsigned int *ber_len,
++			unsigned dflags);
++
++static int
++_asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
++			unsigned int _der_len, const unsigned char **str,
++			unsigned int *str_len, unsigned dflags);
++
++static void
++_asn1_error_description_tag_error (asn1_node node, char *ErrorDescription)
++{
++
++  Estrcpy (ErrorDescription, ":: tag error near element '");
++  _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription),
++			   ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40);
++  Estrcat (ErrorDescription, "'");
++
++}
++
++/**
++ * asn1_get_length_der:
++ * @der: DER data to decode.
++ * @der_len: Length of DER data to decode.
++ * @len: Output variable containing the length of the DER length field.
++ *
++ * Extract a length field from DER data.
++ *
++ * Returns: Return the decoded length value, or -1 on indefinite
++ *   length, or -2 when the value was too big to fit in a int, or -4
++ *   when the decoded length value plus @len would exceed @der_len.
++ **/
++long
++asn1_get_length_der (const unsigned char *der, int der_len, int *len)
++{
++  unsigned int ans;
++  int k, punt, sum;
++
++  *len = 0;
++  if (der_len <= 0)
++    return 0;
++
++  if (!(der[0] & 128))
++    {
++      /* short form */
++      *len = 1;
++      ans = der[0];
++    }
++  else
++    {
++      /* Long form */
++      k = der[0] & 0x7F;
++      punt = 1;
++      if (k)
++	{ /* definite length method */
++	  ans = 0;
++	  while (punt <= k && punt < der_len)
++	    {
++	      if (INT_MULTIPLY_OVERFLOW (ans, 256))
++		return -2;
++	      ans *= 256;
++
++	      if (INT_ADD_OVERFLOW (ans, ((unsigned) der[punt])))
++		return -2;
++	      ans += der[punt];
++	      punt++;
++	    }
++	}
++      else
++	{			/* indefinite length method */
++	  *len = punt;
++	  return -1;
++	}
++
++      *len = punt;
++    }
++
++  sum = ans;
++  if (ans >= INT_MAX || INT_ADD_OVERFLOW (sum, (*len)))
++    return -2;
++  sum += *len;
++
++  if (sum > der_len)
++    return -4;
++
++  return ans;
++}
++
++/**
++ * asn1_get_tag_der:
++ * @der: DER data to decode.
++ * @der_len: Length of DER data to decode.
++ * @cls: Output variable containing decoded class.
++ * @len: Output variable containing the length of the DER TAG data.
++ * @tag: Output variable containing the decoded tag (may be %NULL).
++ *
++ * Decode the class and TAG from DER code.
++ *
++ * Returns: Returns %ASN1_SUCCESS on success, or an error.
++ **/
++int
++asn1_get_tag_der (const unsigned char *der, int der_len,
++		  unsigned char *cls, int *len, unsigned long *tag)
++{
++  unsigned int ris;
++  int punt;
++
++  if (der == NULL || der_len < 2 || len == NULL)
++    return ASN1_DER_ERROR;
++
++  *cls = der[0] & 0xE0;
++  if ((der[0] & 0x1F) != 0x1F)
++    {
++      /* short form */
++      *len = 1;
++      ris = der[0] & 0x1F;
++    }
++  else
++    {
++      /* Long form */
++      punt = 1;
++      ris = 0;
++      while (punt < der_len && der[punt] & 128)
++	{
++
++	  if (INT_MULTIPLY_OVERFLOW (ris, 128))
++	    return ASN1_DER_ERROR;
++	  ris *= 128;
++
++	  if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F))))
++	    return ASN1_DER_ERROR;
++	  ris += (der[punt] & 0x7F);
++	  punt++;
++	}
++
++      if (punt >= der_len)
++	return ASN1_DER_ERROR;
++
++      if (INT_MULTIPLY_OVERFLOW (ris, 128))
++	return ASN1_DER_ERROR;
++      ris *= 128;
++
++      if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F))))
++	return ASN1_DER_ERROR;
++      ris += (der[punt] & 0x7F);
++      punt++;
++
++      *len = punt;
++    }
++
++  if (tag)
++    *tag = ris;
++  return ASN1_SUCCESS;
++}
++
++/**
++ * asn1_get_length_ber:
++ * @ber: BER data to decode.
++ * @ber_len: Length of BER data to decode.
++ * @len: Output variable containing the length of the BER length field.
++ *
++ * Extract a length field from BER data.  The difference to
++ * asn1_get_length_der() is that this function will return a length
++ * even if the value has indefinite encoding.
++ *
++ * Returns: Return the decoded length value, or negative value when
++ *   the value was too big.
++ *
++ * Since: 2.0
++ **/
++long
++asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len)
++{
++  int ret;
++  long err;
++
++  ret = asn1_get_length_der (ber, ber_len, len);
++
++  if (ret == -1 && ber_len > 1)
++    {				/* indefinite length method */
++      err = _asn1_get_indefinite_length_string (ber + 1, ber_len-1, &ret);
++      if (err != ASN1_SUCCESS)
++	return -3;
++    }
++
++  return ret;
++}
++
++/**
++ * asn1_get_octet_der:
++ * @der: DER data to decode containing the OCTET SEQUENCE.
++ * @der_len: The length of the @der data to decode.
++ * @ret_len: Output variable containing the encoded length of the DER data.
++ * @str: Pre-allocated output buffer to put decoded OCTET SEQUENCE in.
++ * @str_size: Length of pre-allocated output buffer.
++ * @str_len: Output variable containing the length of the contents of the OCTET SEQUENCE.
++ *
++ * Extract an OCTET SEQUENCE from DER data. Note that this function
++ * expects the DER data past the tag field, i.e., the length and
++ * content octets.
++ *
++ * Returns: Returns %ASN1_SUCCESS on success, or an error.
++ **/
++int
++asn1_get_octet_der (const unsigned char *der, int der_len,
++		    int *ret_len, unsigned char *str, int str_size,
++		    int *str_len)
++{
++  int len_len = 0;
++
++  if (der_len <= 0)
++    return ASN1_GENERIC_ERROR;
++
++  *str_len = asn1_get_length_der (der, der_len, &len_len);
++
++  if (*str_len < 0)
++    return ASN1_DER_ERROR;
++
++  *ret_len = *str_len + len_len;
++  if (str_size >= *str_len)
++    {
++      if (*str_len > 0 && str != NULL)
++        memcpy (str, der + len_len, *str_len);
++    }
++  else
++    {
++      return ASN1_MEM_ERROR;
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++/*-
++ * _asn1_get_time_der:
++ * @type: %ASN1_ETYPE_GENERALIZED_TIME or %ASN1_ETYPE_UTC_TIME
++ * @der: DER data to decode containing the time
++ * @der_len: Length of DER data to decode.
++ * @ret_len: Output variable containing the length of the DER data.
++ * @str: Pre-allocated output buffer to put the textual time in.
++ * @str_size: Length of pre-allocated output buffer.
++ * @flags: Zero or %ASN1_DECODE_FLAG_STRICT_DER
++ *
++ * Performs basic checks in the DER encoded time object and returns its textual form.
++ * The textual form will be in the YYYYMMDD000000Z format for GeneralizedTime
++ * and YYMMDD000000Z for UTCTime.
++ *
++ * Returns: %ASN1_SUCCESS on success, or an error.
++ -*/
++static int
++_asn1_get_time_der (unsigned type, const unsigned char *der, int der_len, int *ret_len,
++		    char *str, int str_size, unsigned flags)
++{
++  int len_len, str_len;
++  unsigned i;
++  unsigned sign_count = 0;
++  unsigned dot_count = 0;
++  const unsigned char *p;
++
++  if (der_len <= 0 || str == NULL)
++    return ASN1_DER_ERROR;
++
++  str_len = asn1_get_length_der (der, der_len, &len_len);
++  if (str_len <= 0 || str_size < str_len)
++    return ASN1_DER_ERROR;
++
++  /* perform some sanity checks on the data */
++  if (str_len < 8)
++    {
++      warn();
++      return ASN1_TIME_ENCODING_ERROR;
++    }
++
++  if ((flags & ASN1_DECODE_FLAG_STRICT_DER) && !(flags & ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME))
++    {
++      p = &der[len_len];
++      for (i=0;i<(unsigned)(str_len-1);i++)
++         {
++           if (c_isdigit(p[i]) == 0)
++             {
++               if (type == ASN1_ETYPE_GENERALIZED_TIME)
++                 {
++                   /* tolerate lax encodings */
++                   if (p[i] == '.' && dot_count == 0)
++                     {
++                       dot_count++;
++                       continue;
++                     }
++
++               /* This is not really valid DER, but there are
++                * structures using that */
++                   if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) &&
++                       (p[i] == '+' || p[i] == '-') && sign_count == 0)
++                     {
++                       sign_count++;
++                       continue;
++                     }
++                 }
++
++               warn();
++               return ASN1_TIME_ENCODING_ERROR;
++             }
++         }
++
++      if (sign_count == 0 && p[str_len-1] != 'Z')
++        {
++          warn();
++          return ASN1_TIME_ENCODING_ERROR;
++        }
++    }
++  memcpy (str, der + len_len, str_len);
++  str[str_len] = 0;
++  *ret_len = str_len + len_len;
++
++  return ASN1_SUCCESS;
++}
++
++/**
++ * asn1_get_object_id_der:
++ * @der: DER data to decode containing the OBJECT IDENTIFIER
++ * @der_len: Length of DER data to decode.
++ * @ret_len: Output variable containing the length of the DER data.
++ * @str: Pre-allocated output buffer to put the textual object id in.
++ * @str_size: Length of pre-allocated output buffer.
++ *
++ * Converts a DER encoded object identifier to its textual form. This
++ * function expects the DER object identifier without the tag.
++ *
++ * Returns: %ASN1_SUCCESS on success, or an error.
++ **/
++int
++asn1_get_object_id_der (const unsigned char *der, int der_len, int *ret_len,
++			char *str, int str_size)
++{
++  int len_len, len, k;
++  int leading, parsed;
++  char temp[LTOSTR_MAX_SIZE];
++  uint64_t val, val1, val0;
++
++  *ret_len = 0;
++  if (str && str_size > 0)
++    str[0] = 0;			/* no oid */
++
++  if (str == NULL || der_len <= 0)
++    return ASN1_GENERIC_ERROR;
++
++  len = asn1_get_length_der (der, der_len, &len_len);
++
++  if (len <= 0 || len + len_len > der_len)
++    return ASN1_DER_ERROR;
++
++  /* leading octet can never be 0x80 */
++  if (der[len_len] == 0x80)
++    return ASN1_DER_ERROR;
++
++  val0 = 0;
++
++  for (k = 0; k < len; k++)
++    {
++      if (INT_LEFT_SHIFT_OVERFLOW (val0, 7))
++	return ASN1_DER_ERROR;
++
++      val0 <<= 7;
++      val0 |= der[len_len + k] & 0x7F;
++      if (!(der[len_len + k] & 0x80))
++	break;
++    }
++  parsed = ++k;
++
++  /* val0 = (X*40) + Y, X={0,1,2}, Y<=39 when X={0,1} */
++  /* X = val, Y = val1 */
++
++  /* check if X == 0  */
++  val = 0;
++  val1 = val0;
++  if (val1 > 39)
++    {
++      val = 1;
++      val1 = val0 - 40;
++      if (val1  > 39)
++        {
++          val = 2;
++          val1 = val0 - 80;
++        }
++    }
++
++  _asn1_str_cpy (str, str_size, _asn1_ltostr (val, temp));
++  _asn1_str_cat (str, str_size, ".");
++  _asn1_str_cat (str, str_size, _asn1_ltostr (val1, temp));
++
++  val = 0;
++  leading = 1;
++  for (k = parsed; k < len; k++)
++    {
++      /* X.690 mandates that the leading byte must never be 0x80
++       */
++      if (leading != 0 && der[len_len + k] == 0x80)
++	return ASN1_DER_ERROR;
++      leading = 0;
++
++      /* check for wrap around */
++      if (INT_LEFT_SHIFT_OVERFLOW (val, 7))
++	return ASN1_DER_ERROR;
++
++      val = val << 7;
++      val |= der[len_len + k] & 0x7F;
++
++      if (!(der[len_len + k] & 0x80))
++	{
++	  _asn1_str_cat (str, str_size, ".");
++	  _asn1_str_cat (str, str_size, _asn1_ltostr (val, temp));
++	  val = 0;
++	  leading = 1;
++	}
++    }
++
++  if (INT_ADD_OVERFLOW (len, len_len))
++    return ASN1_DER_ERROR;
++
++  *ret_len = len + len_len;
++
++  return ASN1_SUCCESS;
++}
++
++/**
++ * asn1_get_bit_der:
++ * @der: DER data to decode containing the BIT SEQUENCE.
++ * @der_len: Length of DER data to decode.
++ * @ret_len: Output variable containing the length of the DER data.
++ * @str: Pre-allocated output buffer to put decoded BIT SEQUENCE in.
++ * @str_size: Length of pre-allocated output buffer.
++ * @bit_len: Output variable containing the size of the BIT SEQUENCE.
++ *
++ * Extract a BIT SEQUENCE from DER data.
++ *
++ * Returns: %ASN1_SUCCESS on success, or an error.
++ **/
++int
++asn1_get_bit_der (const unsigned char *der, int der_len,
++		  int *ret_len, unsigned char *str, int str_size,
++		  int *bit_len)
++{
++  int len_len = 0, len_byte;
++
++  if (der_len <= 0)
++    return ASN1_GENERIC_ERROR;
++
++  len_byte = asn1_get_length_der (der, der_len, &len_len) - 1;
++  if (len_byte < 0)
++    return ASN1_DER_ERROR;
++
++  *ret_len = len_byte + len_len + 1;
++  *bit_len = len_byte * 8 - der[len_len];
++
++  if (*bit_len < 0)
++    return ASN1_DER_ERROR;
++
++  if (str_size >= len_byte)
++    {
++      if (len_byte > 0 && str)
++        memcpy (str, der + len_len + 1, len_byte);
++    }
++  else
++    {
++      return ASN1_MEM_ERROR;
++    }
++
++  return ASN1_SUCCESS;
++}
++
++/* tag_len: the total tag length (explicit+inner)
++ * inner_tag_len: the inner_tag length
++ */
++static int
++_asn1_extract_tag_der (asn1_node node, const unsigned char *der, int der_len,
++		       int *tag_len, int *inner_tag_len, unsigned flags)
++{
++  asn1_node p;
++  int counter, len2, len3, is_tag_implicit;
++  int result;
++  unsigned long tag, tag_implicit = 0;
++  unsigned char class, class2, class_implicit = 0;
++
++  if (der_len <= 0)
++    return ASN1_GENERIC_ERROR;
++
++  counter = is_tag_implicit = 0;
++
++  if (node->type & CONST_TAG)
++    {
++      p = node->down;
++      while (p)
++	{
++	  if (type_field (p->type) == ASN1_ETYPE_TAG)
++	    {
++	      if (p->type & CONST_APPLICATION)
++		class2 = ASN1_CLASS_APPLICATION;
++	      else if (p->type & CONST_UNIVERSAL)
++		class2 = ASN1_CLASS_UNIVERSAL;
++	      else if (p->type & CONST_PRIVATE)
++		class2 = ASN1_CLASS_PRIVATE;
++	      else
++		class2 = ASN1_CLASS_CONTEXT_SPECIFIC;
++
++	      if (p->type & CONST_EXPLICIT)
++		{
++		  if (asn1_get_tag_der
++		      (der + counter, der_len, &class, &len2,
++		       &tag) != ASN1_SUCCESS)
++		    return ASN1_DER_ERROR;
++
++                  DECR_LEN(der_len, len2);
++		  counter += len2;
++
++		  if (flags & ASN1_DECODE_FLAG_STRICT_DER)
++		    len3 =
++		      asn1_get_length_der (der + counter, der_len,
++					 &len2);
++		  else
++		    len3 =
++		      asn1_get_length_ber (der + counter, der_len,
++					 &len2);
++		  if (len3 < 0)
++		    return ASN1_DER_ERROR;
++
++                  DECR_LEN(der_len, len2);
++		  counter += len2;
++
++		  if (!is_tag_implicit)
++		    {
++		      if ((class != (class2 | ASN1_CLASS_STRUCTURED)) ||
++			  (tag != strtoul ((char *) p->value, NULL, 10)))
++			return ASN1_TAG_ERROR;
++		    }
++		  else
++		    {		/* ASN1_TAG_IMPLICIT */
++		      if ((class != class_implicit) || (tag != tag_implicit))
++			return ASN1_TAG_ERROR;
++		    }
++		  is_tag_implicit = 0;
++		}
++	      else
++		{		/* ASN1_TAG_IMPLICIT */
++		  if (!is_tag_implicit)
++		    {
++		      if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) ||
++			  (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF)
++			  || (type_field (node->type) == ASN1_ETYPE_SET)
++			  || (type_field (node->type) == ASN1_ETYPE_SET_OF))
++			class2 |= ASN1_CLASS_STRUCTURED;
++		      class_implicit = class2;
++		      tag_implicit = strtoul ((char *) p->value, NULL, 10);
++		      is_tag_implicit = 1;
++		    }
++		}
++	    }
++	  p = p->right;
++	}
++    }
++
++  if (is_tag_implicit)
++    {
++      if (asn1_get_tag_der
++	  (der + counter, der_len, &class, &len2,
++	   &tag) != ASN1_SUCCESS)
++	return ASN1_DER_ERROR;
++
++      DECR_LEN(der_len, len2);
++
++      if ((class != class_implicit) || (tag != tag_implicit))
++	{
++	  if (type_field (node->type) == ASN1_ETYPE_OCTET_STRING)
++	    {
++	      class_implicit |= ASN1_CLASS_STRUCTURED;
++	      if ((class != class_implicit) || (tag != tag_implicit))
++		return ASN1_TAG_ERROR;
++	    }
++	  else
++	    return ASN1_TAG_ERROR;
++	}
++    }
++  else
++    {
++      unsigned type = type_field (node->type);
++      if (type == ASN1_ETYPE_TAG)
++	{
++	  *tag_len = 0;
++	  if (inner_tag_len)
++	    *inner_tag_len = 0;
++	  return ASN1_SUCCESS;
++	}
++
++      if (asn1_get_tag_der
++	  (der + counter, der_len, &class, &len2,
++	   &tag) != ASN1_SUCCESS)
++	return ASN1_DER_ERROR;
++
++      DECR_LEN(der_len, len2);
++
++      switch (type)
++	{
++	case ASN1_ETYPE_NULL:
++	case ASN1_ETYPE_BOOLEAN:
++	case ASN1_ETYPE_INTEGER:
++	case ASN1_ETYPE_ENUMERATED:
++	case ASN1_ETYPE_OBJECT_ID:
++	case ASN1_ETYPE_GENERALSTRING:
++	case ASN1_ETYPE_NUMERIC_STRING:
++	case ASN1_ETYPE_IA5_STRING:
++	case ASN1_ETYPE_TELETEX_STRING:
++	case ASN1_ETYPE_PRINTABLE_STRING:
++	case ASN1_ETYPE_UNIVERSAL_STRING:
++	case ASN1_ETYPE_BMP_STRING:
++	case ASN1_ETYPE_UTF8_STRING:
++	case ASN1_ETYPE_VISIBLE_STRING:
++	case ASN1_ETYPE_BIT_STRING:
++	case ASN1_ETYPE_SEQUENCE:
++	case ASN1_ETYPE_SEQUENCE_OF:
++	case ASN1_ETYPE_SET:
++	case ASN1_ETYPE_SET_OF:
++	case ASN1_ETYPE_GENERALIZED_TIME:
++	case ASN1_ETYPE_UTC_TIME:
++	  if ((class != _asn1_tags[type].class)
++	      || (tag != _asn1_tags[type].tag))
++	    return ASN1_DER_ERROR;
++	  break;
++
++	case ASN1_ETYPE_OCTET_STRING:
++	  /* OCTET STRING is handled differently to allow
++	   * BER encodings (structured class). */
++	  if (((class != ASN1_CLASS_UNIVERSAL)
++	       && (class != (ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED)))
++	      || (tag != ASN1_TAG_OCTET_STRING))
++	    return ASN1_DER_ERROR;
++	  break;
++	case ASN1_ETYPE_ANY:
++	  counter -= len2;
++	  break;
++	case ASN1_ETYPE_CHOICE:
++	  counter -= len2;
++	  break;
++	default:
++	  return ASN1_DER_ERROR;
++	  break;
++	}
++    }
++
++  counter += len2;
++  *tag_len = counter;
++  if (inner_tag_len)
++    *inner_tag_len = len2;
++  return ASN1_SUCCESS;
++
++cleanup:
++  return result;
++}
++
++static int
++extract_tag_der_recursive(asn1_node node, const unsigned char *der, int der_len,
++		       int *ret_len, int *inner_len, unsigned flags)
++{
++asn1_node p;
++int ris = ASN1_DER_ERROR;
++
++  if (type_field (node->type) == ASN1_ETYPE_CHOICE)
++    {
++      p = node->down;
++      while (p)
++        {
++          ris = _asn1_extract_tag_der (p, der, der_len, ret_len, inner_len, flags);
++          if (ris == ASN1_SUCCESS)
++            break;
++          p = p->right;
++	}
++
++      *ret_len = 0;
++      return ris;
++    }
++  else
++    return _asn1_extract_tag_der (node, der, der_len, ret_len, inner_len, flags);
++}
++
++static int
++_asn1_delete_not_used (asn1_node node)
++{
++  asn1_node p, p2;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node;
++  while (p)
++    {
++      if (p->type & CONST_NOT_USED)
++	{
++	  p2 = NULL;
++	  if (p != node)
++	    {
++	      p2 = _asn1_find_left (p);
++	      if (!p2)
++		p2 = _asn1_find_up (p);
++	    }
++	  asn1_delete_structure (&p);
++	  p = p2;
++	}
++
++      if (!p)
++	break;			/* reach node */
++
++      if (p->down)
++	{
++	  p = p->down;
++	}
++      else
++	{
++	  if (p == node)
++	    p = NULL;
++	  else if (p->right)
++	    p = p->right;
++	  else
++	    {
++	      while (1)
++		{
++		  p = _asn1_find_up (p);
++		  if (p == node)
++		    {
++		      p = NULL;
++		      break;
++		    }
++		  if (p->right)
++		    {
++		      p = p->right;
++		      break;
++		    }
++		}
++	    }
++	}
++    }
++  return ASN1_SUCCESS;
++}
++
++static int
++_asn1_get_indefinite_length_string (const unsigned char *der,
++				    int der_len, int *len)
++{
++  int len2, len3, counter, indefinite;
++  int result;
++  unsigned long tag;
++  unsigned char class;
++
++  counter = indefinite = 0;
++
++  while (1)
++    {
++      if (HAVE_TWO(der_len) && (der[counter] == 0) && (der[counter + 1] == 0))
++	{
++	  counter += 2;
++	  DECR_LEN(der_len, 2);
++
++	  indefinite--;
++	  if (indefinite <= 0)
++	    break;
++	  else
++	    continue;
++	}
++
++      if (asn1_get_tag_der
++	  (der + counter, der_len, &class, &len2,
++	   &tag) != ASN1_SUCCESS)
++	return ASN1_DER_ERROR;
++
++      DECR_LEN(der_len, len2);
++      counter += len2;
++
++      len2 = asn1_get_length_der (der + counter, der_len, &len3);
++      if (len2 < -1)
++	return ASN1_DER_ERROR;
++
++      if (len2 == -1)
++	{
++	  indefinite++;
++	  counter += 1;
++          DECR_LEN(der_len, 1);
++	}
++      else
++	{
++	  counter += len2 + len3;
++          DECR_LEN(der_len, len2+len3);
++	}
++    }
++
++  *len = counter;
++  return ASN1_SUCCESS;
++
++cleanup:
++  return result;
++}
++
++static void delete_unneeded_choice_fields(asn1_node p)
++{
++  asn1_node p2;
++
++  while (p->right)
++    {
++      p2 = p->right;
++      asn1_delete_structure (&p2);
++    }
++}
++
++
++/**
++ * asn1_der_decoding2
++ * @element: pointer to an ASN1 structure.
++ * @ider: vector that contains the DER encoding.
++ * @max_ider_len: pointer to an integer giving the information about the
++ *   maximal number of bytes occupied by *@ider. The real size of the DER
++ *   encoding is returned through this pointer.
++ * @flags: flags controlling the behaviour of the function.
++ * @errorDescription: null-terminated string contains details when an
++ *   error occurred.
++ *
++ * Fill the structure *@element with values of a DER encoding string. The
++ * structure must just be created with function asn1_create_element().
++ *
++ * If %ASN1_DECODE_FLAG_ALLOW_PADDING flag is set then the function will ignore
++ * padding after the decoded DER data. Upon a successful return the value of
++ * *@max_ider_len will be set to the number of bytes decoded.
++ *
++ * If %ASN1_DECODE_FLAG_STRICT_DER flag is set then the function will
++ * not decode any BER-encoded elements.
++ *
++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
++ *   if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or
++ *   %ASN1_DER_ERROR if the der encoding doesn't match the structure
++ *   name (*@ELEMENT deleted).
++ **/
++int
++asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len,
++		    unsigned int flags, char *errorDescription)
++{
++  asn1_node node, p, p2, p3;
++  char temp[128];
++  int counter, len2, len3, len4, move, ris, tlen;
++  struct node_tail_cache_st tcache = {NULL, NULL};
++  unsigned char class;
++  unsigned long tag;
++  int tag_len;
++  int indefinite, result, total_len = *max_ider_len, ider_len = *max_ider_len;
++  int inner_tag_len;
++  unsigned char *ptmp;
++  const unsigned char *ptag;
++  const unsigned char *der = ider;
++
++  node = *element;
++
++  if (errorDescription != NULL)
++    errorDescription[0] = 0;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  if (node->type & CONST_OPTION)
++    {
++      result = ASN1_GENERIC_ERROR;
++      warn();
++      goto cleanup;
++    }
++
++  counter = 0;
++  move = DOWN;
++  p = node;
++  while (1)
++    {
++      tag_len = 0;
++      inner_tag_len = 0;
++      ris = ASN1_SUCCESS;
++      if (move != UP)
++	{
++	  if (p->type & CONST_SET)
++	    {
++	      p2 = _asn1_find_up (p);
++	      len2 = p2->tmp_ival;
++	      if (len2 == -1)
++		{
++		  if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1])
++		    {
++		      p = p2;
++		      move = UP;
++		      counter += 2;
++		      DECR_LEN(ider_len, 2);
++		      continue;
++		    }
++		}
++	      else if (counter == len2)
++		{
++		  p = p2;
++		  move = UP;
++		  continue;
++		}
++	      else if (counter > len2)
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++	      p2 = p2->down;
++	      while (p2)
++		{
++		  if ((p2->type & CONST_SET) && (p2->type & CONST_NOT_USED))
++		    {
++		      ris =
++			  extract_tag_der_recursive (p2, der + counter,
++						     ider_len, &len2, NULL, flags);
++		      if (ris == ASN1_SUCCESS)
++			{
++			  p2->type &= ~CONST_NOT_USED;
++			  p = p2;
++			  break;
++			}
++		    }
++		  p2 = p2->right;
++		}
++	      if (p2 == NULL)
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++	    }
++
++	  /* the position in the DER structure this starts */
++	  p->start = counter;
++	  p->end = total_len - 1;
++
++	  if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT))
++	    {
++	      p2 = _asn1_find_up (p);
++	      len2 = p2->tmp_ival;
++	      if (counter == len2)
++		{
++		  if (p->right)
++		    {
++		      p2 = p->right;
++		      move = RIGHT;
++		    }
++		  else
++		    move = UP;
++
++		  if (p->type & CONST_OPTION)
++		    asn1_delete_structure (&p);
++
++		  p = p2;
++		  continue;
++		}
++	    }
++
++	  if (type_field (p->type) == ASN1_ETYPE_CHOICE)
++	    {
++	      while (p->down)
++		{
++		  ris =
++		      extract_tag_der_recursive (p->down, der + counter,
++					         ider_len, &len2, NULL, flags);
++
++		  if (ris == ASN1_SUCCESS)
++		    {
++		      delete_unneeded_choice_fields(p->down);
++		      break;
++		    }
++		  else if (ris == ASN1_ERROR_TYPE_ANY)
++		    {
++		      result = ASN1_ERROR_TYPE_ANY;
++                      warn();
++		      goto cleanup;
++		    }
++		  else
++		    {
++		      p2 = p->down;
++		      asn1_delete_structure (&p2);
++		    }
++		}
++
++	      if (p->down == NULL)
++		{
++		  if (!(p->type & CONST_OPTION))
++		    {
++		      result = ASN1_DER_ERROR;
++                      warn();
++		      goto cleanup;
++		    }
++		}
++	      else if (type_field (p->type) != ASN1_ETYPE_CHOICE)
++		p = p->down;
++
++	      p->start = counter;
++	    }
++
++	  if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT))
++	    {
++	      p2 = _asn1_find_up (p);
++	      len2 = p2->tmp_ival;
++
++	      if ((len2 != -1) && (counter > len2))
++		ris = ASN1_TAG_ERROR;
++	    }
++
++	  if (ris == ASN1_SUCCESS)
++	    ris =
++	      extract_tag_der_recursive (p, der + counter, ider_len,
++	                                 &tag_len, &inner_tag_len, flags);
++
++	  if (ris != ASN1_SUCCESS)
++	    {
++	      if (p->type & CONST_OPTION)
++		{
++		  p->type |= CONST_NOT_USED;
++		  move = RIGHT;
++		}
++	      else if (p->type & CONST_DEFAULT)
++		{
++		  _asn1_set_value (p, NULL, 0);
++		  move = RIGHT;
++		}
++	      else
++		{
++		  if (errorDescription != NULL)
++		    _asn1_error_description_tag_error (p, errorDescription);
++
++		  result = ASN1_TAG_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++	    }
++	  else
++	    {
++	      DECR_LEN(ider_len, tag_len);
++	      counter += tag_len;
++	    }
++	}
++
++      if (ris == ASN1_SUCCESS)
++	{
++	  switch (type_field (p->type))
++	    {
++	    case ASN1_ETYPE_NULL:
++	      DECR_LEN(ider_len, 1);
++	      if (der[counter])
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++	      counter++;
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_BOOLEAN:
++	      DECR_LEN(ider_len, 2);
++
++	      if (der[counter++] != 1)
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++	      if (der[counter++] == 0)
++		_asn1_set_value (p, "F", 1);
++	      else
++		_asn1_set_value (p, "T", 1);
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_INTEGER:
++	    case ASN1_ETYPE_ENUMERATED:
++	      len2 =
++		asn1_get_length_der (der + counter, ider_len, &len3);
++	      if (len2 < 0)
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++
++	      DECR_LEN(ider_len, len3+len2);
++
++	      _asn1_set_value (p, der + counter, len3 + len2);
++	      counter += len3 + len2;
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_OBJECT_ID:
++	      result =
++		asn1_get_object_id_der (der + counter, ider_len, &len2,
++					temp, sizeof (temp));
++	      if (result != ASN1_SUCCESS)
++	        {
++                  warn();
++		  goto cleanup;
++		}
++
++	      DECR_LEN(ider_len, len2);
++
++	      tlen = strlen (temp);
++	      if (tlen > 0)
++		_asn1_set_value (p, temp, tlen + 1);
++
++	      counter += len2;
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_GENERALIZED_TIME:
++	    case ASN1_ETYPE_UTC_TIME:
++	      result =
++		_asn1_get_time_der (type_field (p->type), der + counter, ider_len, &len2, temp,
++				    sizeof (temp) - 1, flags);
++	      if (result != ASN1_SUCCESS)
++	        {
++                  warn();
++                  goto cleanup;
++                }
++
++	      DECR_LEN(ider_len, len2);
++
++	      tlen = strlen (temp);
++	      if (tlen > 0)
++		_asn1_set_value (p, temp, tlen);
++
++	      counter += len2;
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_OCTET_STRING:
++	      if (counter < inner_tag_len)
++	        {
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++	        }
++
++              ptag = der + counter - inner_tag_len;
++              if ((flags & ASN1_DECODE_FLAG_STRICT_DER) || !(ptag[0] & ASN1_CLASS_STRUCTURED))
++                {
++	          if (ptag[0] & ASN1_CLASS_STRUCTURED)
++		    {
++		      result = ASN1_DER_ERROR;
++                      warn();
++		      goto cleanup;
++		    }
++
++	          len2 =
++		    asn1_get_length_der (der + counter, ider_len, &len3);
++	          if (len2 < 0)
++		    {
++		      result = ASN1_DER_ERROR;
++                      warn();
++		      goto cleanup;
++		    }
++
++	          DECR_LEN(ider_len, len3+len2);
++
++	          _asn1_set_value (p, der + counter, len3 + len2);
++	          counter += len3 + len2;
++                }
++              else
++                {
++                  unsigned dflags = 0, vlen, ber_len;
++
++                  if (ptag[0] & ASN1_CLASS_STRUCTURED)
++                    dflags |= DECODE_FLAG_CONSTRUCTED;
++
++                  result = _asn1_decode_simple_ber(type_field (p->type), der+counter, ider_len, &ptmp, &vlen, &ber_len, dflags);
++                  if (result != ASN1_SUCCESS)
++	            {
++                      warn();
++		      goto cleanup;
++		    }
++
++		  DECR_LEN(ider_len, ber_len);
++
++		  _asn1_set_value_lv (p, ptmp, vlen);
++
++	          counter += ber_len;
++	          free(ptmp);
++                }
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_GENERALSTRING:
++	    case ASN1_ETYPE_NUMERIC_STRING:
++	    case ASN1_ETYPE_IA5_STRING:
++	    case ASN1_ETYPE_TELETEX_STRING:
++	    case ASN1_ETYPE_PRINTABLE_STRING:
++	    case ASN1_ETYPE_UNIVERSAL_STRING:
++	    case ASN1_ETYPE_BMP_STRING:
++	    case ASN1_ETYPE_UTF8_STRING:
++	    case ASN1_ETYPE_VISIBLE_STRING:
++	    case ASN1_ETYPE_BIT_STRING:
++	      len2 =
++		asn1_get_length_der (der + counter, ider_len, &len3);
++	      if (len2 < 0)
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++
++	      DECR_LEN(ider_len, len3+len2);
++
++	      _asn1_set_value (p, der + counter, len3 + len2);
++	      counter += len3 + len2;
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_SEQUENCE:
++	    case ASN1_ETYPE_SET:
++	      if (move == UP)
++		{
++		  len2 = p->tmp_ival;
++		  p->tmp_ival = 0;
++		  if (len2 == -1)
++		    {		/* indefinite length method */
++		      DECR_LEN(ider_len, 2);
++		      if ((der[counter]) || der[counter + 1])
++		        {
++		          result = ASN1_DER_ERROR;
++                          warn();
++		          goto cleanup;
++			}
++		      counter += 2;
++		    }
++		  else
++		    {		/* definite length method */
++		      if (len2 != counter)
++			{
++			  result = ASN1_DER_ERROR;
++                          warn();
++			  goto cleanup;
++			}
++		    }
++		  move = RIGHT;
++		}
++	      else
++		{		/* move==DOWN || move==RIGHT */
++		  len3 =
++		    asn1_get_length_der (der + counter, ider_len, &len2);
++                  if (IS_ERR(len3, flags))
++		    {
++		      result = ASN1_DER_ERROR;
++                      warn();
++		      goto cleanup;
++		    }
++
++	          DECR_LEN(ider_len, len2);
++		  counter += len2;
++
++		  if (len3 > 0)
++		    {
++		      p->tmp_ival = counter + len3;
++		      move = DOWN;
++		    }
++		  else if (len3 == 0)
++		    {
++		      p2 = p->down;
++		      while (p2)
++			{
++			  if (type_field (p2->type) != ASN1_ETYPE_TAG)
++			    {
++			      p3 = p2->right;
++			      asn1_delete_structure (&p2);
++			      p2 = p3;
++			    }
++			  else
++			    p2 = p2->right;
++			}
++		      move = RIGHT;
++		    }
++		  else
++		    {		/* indefinite length method */
++		      p->tmp_ival = -1;
++		      move = DOWN;
++		    }
++		}
++	      break;
++	    case ASN1_ETYPE_SEQUENCE_OF:
++	    case ASN1_ETYPE_SET_OF:
++	      if (move == UP)
++		{
++		  len2 = p->tmp_ival;
++		  if (len2 == -1)
++		    {		/* indefinite length method */
++		      if (!HAVE_TWO(ider_len) || ((der[counter]) || der[counter + 1]))
++			{
++			  result = _asn1_append_sequence_set (p, &tcache);
++			  if (result != 0)
++			    {
++                              warn();
++		              goto cleanup;
++		            }
++			  p = tcache.tail;
++			  move = RIGHT;
++			  continue;
++			}
++
++		      p->tmp_ival = 0;
++		      tcache.tail = NULL; /* finished decoding this structure */
++		      tcache.head = NULL;
++		      DECR_LEN(ider_len, 2);
++		      counter += 2;
++		    }
++		  else
++		    {		/* definite length method */
++		      if (len2 > counter)
++			{
++			  result = _asn1_append_sequence_set (p, &tcache);
++			  if (result != 0)
++			    {
++                              warn();
++		              goto cleanup;
++		            }
++			  p = tcache.tail;
++			  move = RIGHT;
++			  continue;
++			}
++
++		      p->tmp_ival = 0;
++		      tcache.tail = NULL; /* finished decoding this structure */
++		      tcache.head = NULL;
++
++		      if (len2 != counter)
++			{
++			  result = ASN1_DER_ERROR;
++                          warn();
++			  goto cleanup;
++			}
++		    }
++		}
++	      else
++		{		/* move==DOWN || move==RIGHT */
++		  len3 =
++		    asn1_get_length_der (der + counter, ider_len, &len2);
++                  if (IS_ERR(len3, flags))
++		    {
++		      result = ASN1_DER_ERROR;
++                      warn();
++		      goto cleanup;
++		    }
++
++		  DECR_LEN(ider_len, len2);
++		  counter += len2;
++		  if (len3)
++		    {
++		      if (len3 > 0)
++			{	/* definite length method */
++		          p->tmp_ival = counter + len3;
++			}
++		      else
++			{	/* indefinite length method */
++		          p->tmp_ival = -1;
++			}
++
++		      p2 = p->down;
++                      if (p2 == NULL)
++		        {
++		          result = ASN1_DER_ERROR;
++                          warn();
++		          goto cleanup;
++		        }
++
++		      while ((type_field (p2->type) == ASN1_ETYPE_TAG)
++			     || (type_field (p2->type) == ASN1_ETYPE_SIZE))
++			p2 = p2->right;
++		      if (p2->right == NULL)
++		        {
++			  result = _asn1_append_sequence_set (p, &tcache);
++			  if (result != 0)
++			    {
++                              warn();
++		              goto cleanup;
++		            }
++			}
++		      p = p2;
++		    }
++		}
++	      move = RIGHT;
++	      break;
++	    case ASN1_ETYPE_ANY:
++	      /* Check indefinite lenth method in an EXPLICIT TAG */
++
++	      if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) && (p->type & CONST_TAG) &&
++	          tag_len == 2 && (der[counter - 1] == 0x80))
++		indefinite = 1;
++	      else
++	        indefinite = 0;
++
++	      if (asn1_get_tag_der
++		  (der + counter, ider_len, &class, &len2,
++		   &tag) != ASN1_SUCCESS)
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++
++	      DECR_LEN(ider_len, len2);
++
++	      len4 =
++		asn1_get_length_der (der + counter + len2,
++				     ider_len, &len3);
++              if (IS_ERR(len4, flags))
++		{
++		  result = ASN1_DER_ERROR;
++                  warn();
++		  goto cleanup;
++		}
++	      if (len4 != -1) /* definite */
++		{
++		  len2 += len4;
++
++	          DECR_LEN(ider_len, len4+len3);
++		  _asn1_set_value_lv (p, der + counter, len2 + len3);
++		  counter += len2 + len3;
++		}
++	      else /* == -1 */
++		{		/* indefinite length */
++		  ider_len += len2; /* undo DECR_LEN */
++
++		  if (counter == 0)
++		    {
++		      result = ASN1_DER_ERROR;
++                      warn();
++		      goto cleanup;
++		    }
++
++		  result =
++		    _asn1_get_indefinite_length_string (der + counter, ider_len, &len2);
++		  if (result != ASN1_SUCCESS)
++		    {
++                      warn();
++                      goto cleanup;
++                    }
++
++	          DECR_LEN(ider_len, len2);
++		  _asn1_set_value_lv (p, der + counter, len2);
++		  counter += len2;
++
++		}
++
++	        /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with
++	           an indefinite length method. */
++	        if (indefinite)
++		  {
++	            DECR_LEN(ider_len, 2);
++		    if (!der[counter] && !der[counter + 1])
++		      {
++		        counter += 2;
++		      }
++		    else
++		      {
++		        result = ASN1_DER_ERROR;
++                        warn();
++		        goto cleanup;
++		      }
++		  }
++
++	      move = RIGHT;
++	      break;
++	    default:
++	      move = (move == UP) ? RIGHT : DOWN;
++	      break;
++	    }
++	}
++
++      if (p)
++        {
++          p->end = counter - 1;
++        }
++
++      if (p == node && move != DOWN)
++	break;
++
++      if (move == DOWN)
++	{
++	  if (p->down)
++	    p = p->down;
++	  else
++	    move = RIGHT;
++	}
++      if ((move == RIGHT) && !(p->type & CONST_SET))
++	{
++	  if (p->right)
++	    p = p->right;
++	  else
++	    move = UP;
++	}
++      if (move == UP)
++	p = _asn1_find_up (p);
++    }
++
++  _asn1_delete_not_used (*element);
++
++  if ((ider_len < 0) ||
++      (!(flags & ASN1_DECODE_FLAG_ALLOW_PADDING) && (ider_len != 0)))
++    {
++      warn();
++      result = ASN1_DER_ERROR;
++      goto cleanup;
++    }
++
++  *max_ider_len = total_len - ider_len;
++
++  return ASN1_SUCCESS;
++
++cleanup:
++  asn1_delete_structure (element);
++  return result;
++}
++
++
++/**
++ * asn1_der_decoding:
++ * @element: pointer to an ASN1 structure.
++ * @ider: vector that contains the DER encoding.
++ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1].
++ * @errorDescription: null-terminated string contains details when an
++ *   error occurred.
++ *
++ * Fill the structure *@element with values of a DER encoding
++ * string. The structure must just be created with function
++ * asn1_create_element().
++ *
++ * Note that the *@element variable is provided as a pointer for
++ * historical reasons.
++ *
++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
++ *   if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or
++ *   %ASN1_DER_ERROR if the der encoding doesn't match the structure
++ *   name (*@ELEMENT deleted).
++ **/
++int
++asn1_der_decoding (asn1_node * element, const void *ider, int ider_len,
++		   char *errorDescription)
++{
++  return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription);
++}
++
++/**
++ * asn1_der_decoding_element:
++ * @structure: pointer to an ASN1 structure
++ * @elementName: name of the element to fill
++ * @ider: vector that contains the DER encoding of the whole structure.
++ * @len: number of bytes of *der: der[0]..der[len-1]
++ * @errorDescription: null-terminated string contains details when an
++ *   error occurred.
++ *
++ * Fill the element named @ELEMENTNAME with values of a DER encoding
++ * string.  The structure must just be created with function
++ * asn1_create_element().  The DER vector must contain the encoding
++ * string of the whole @STRUCTURE.  If an error occurs during the
++ * decoding procedure, the *@STRUCTURE is deleted and set equal to
++ * %NULL.
++ *
++ * This function is deprecated and may just be an alias to asn1_der_decoding
++ * in future versions. Use asn1_der_decoding() instead.
++ *
++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
++ *   if ELEMENT is %NULL or @elementName == NULL, and
++ *   %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding doesn't
++ *   match the structure @structure (*ELEMENT deleted).
++ **/
++int
++asn1_der_decoding_element (asn1_node * structure, const char *elementName,
++			   const void *ider, int len, char *errorDescription)
++{
++  return asn1_der_decoding(structure, ider, len, errorDescription);
++}
++
++/**
++ * asn1_der_decoding_startEnd:
++ * @element: pointer to an ASN1 element
++ * @ider: vector that contains the DER encoding.
++ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1]
++ * @name_element: an element of NAME structure.
++ * @start: the position of the first byte of NAME_ELEMENT decoding
++ *   (@ider[*start])
++ * @end: the position of the last byte of NAME_ELEMENT decoding
++ *  (@ider[*end])
++ *
++ * Find the start and end point of an element in a DER encoding
++ * string. I mean that if you have a der encoding and you have already
++ * used the function asn1_der_decoding() to fill a structure, it may
++ * happen that you want to find the piece of string concerning an
++ * element of the structure.
++ *
++ * One example is the sequence "tbsCertificate" inside an X509
++ * certificate.
++ *
++ * Note that since libtasn1 3.7 the @ider and @ider_len parameters
++ * can be omitted, if the element is already decoded using asn1_der_decoding().
++ *
++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
++ *   if ELEMENT is %asn1_node EMPTY or @name_element is not a valid
++ *   element, %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding
++ *   doesn't match the structure ELEMENT.
++ **/
++int
++asn1_der_decoding_startEnd (asn1_node element, const void *ider, int ider_len,
++			    const char *name_element, int *start, int *end)
++{
++  asn1_node node, node_to_find;
++  int result = ASN1_DER_ERROR;
++
++  node = element;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  node_to_find = asn1_find_node (node, name_element);
++
++  if (node_to_find == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  *start = node_to_find->start;
++  *end = node_to_find->end;
++
++  if (*start == 0 && *end == 0)
++    {
++      if (ider == NULL || ider_len == 0)
++        return ASN1_GENERIC_ERROR;
++
++      /* it seems asn1_der_decoding() wasn't called before. Do it now */
++      result = asn1_der_decoding (&node, ider, ider_len, NULL);
++      if (result != ASN1_SUCCESS)
++        {
++          warn();
++          return result;
++        }
++
++      node_to_find = asn1_find_node (node, name_element);
++      if (node_to_find == NULL)
++        return ASN1_ELEMENT_NOT_FOUND;
++
++      *start = node_to_find->start;
++      *end = node_to_find->end;
++    }
++
++  if (*end < *start)
++    return ASN1_GENERIC_ERROR;
++
++  return ASN1_SUCCESS;
++}
++
++/**
++ * asn1_expand_any_defined_by:
++ * @definitions: ASN1 definitions
++ * @element: pointer to an ASN1 structure
++ *
++ * Expands every "ANY DEFINED BY" element of a structure created from
++ * a DER decoding process (asn1_der_decoding function). The element
++ * ANY must be defined by an OBJECT IDENTIFIER. The type used to
++ * expand the element ANY is the first one following the definition of
++ * the actual value of the OBJECT IDENTIFIER.
++ *
++ * Returns: %ASN1_SUCCESS if Substitution OK, %ASN1_ERROR_TYPE_ANY if
++ *   some "ANY DEFINED BY" element couldn't be expanded due to a
++ *   problem in OBJECT_ID -> TYPE association, or other error codes
++ *   depending on DER decoding.
++ **/
++int
++asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element)
++{
++  char name[2 * ASN1_MAX_NAME_SIZE + 2],
++    value[ASN1_MAX_NAME_SIZE];
++  int retCode = ASN1_SUCCESS, result;
++  int len, len2, len3;
++  asn1_node_const p2;
++  asn1_node p, p3, aux = NULL;
++  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
++  const char *definitionsName;
++
++  if ((definitions == NULL) || (*element == NULL))
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  definitionsName = definitions->name;
++
++  p = *element;
++  while (p)
++    {
++
++      switch (type_field (p->type))
++	{
++	case ASN1_ETYPE_ANY:
++	  if ((p->type & CONST_DEFINED_BY) && (p->value))
++	    {
++	      /* search the "DEF_BY" element */
++	      p2 = p->down;
++	      while ((p2) && (type_field (p2->type) != ASN1_ETYPE_CONSTANT))
++		p2 = p2->right;
++
++	      if (!p2)
++		{
++		  retCode = ASN1_ERROR_TYPE_ANY;
++		  break;
++		}
++
++	      p3 = _asn1_find_up (p);
++
++	      if (!p3)
++		{
++		  retCode = ASN1_ERROR_TYPE_ANY;
++		  break;
++		}
++
++	      p3 = p3->down;
++	      while (p3)
++		{
++		  if (!(strcmp (p3->name, p2->name)))
++		    break;
++		  p3 = p3->right;
++		}
++
++	      if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ||
++		  (p3->value == NULL))
++		{
++
++		  p3 = _asn1_find_up (p);
++		  p3 = _asn1_find_up (p3);
++
++		  if (!p3)
++		    {
++		      retCode = ASN1_ERROR_TYPE_ANY;
++		      break;
++		    }
++
++		  p3 = p3->down;
++
++		  while (p3)
++		    {
++		      if (!(strcmp (p3->name, p2->name)))
++			break;
++		      p3 = p3->right;
++		    }
++
++		  if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID)
++		      || (p3->value == NULL))
++		    {
++		      retCode = ASN1_ERROR_TYPE_ANY;
++		      break;
++		    }
++		}
++
++	      /* search the OBJECT_ID into definitions */
++	      p2 = definitions->down;
++	      while (p2)
++		{
++		  if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) &&
++		      (p2->type & CONST_ASSIGN))
++		    {
++		      snprintf(name, sizeof(name), "%s.%s", definitionsName, p2->name);
++
++		      len = ASN1_MAX_NAME_SIZE;
++		      result =
++			asn1_read_value (definitions, name, value, &len);
++
++		      if ((result == ASN1_SUCCESS)
++			  && (!_asn1_strcmp (p3->value, value)))
++			{
++			  p2 = p2->right;	/* pointer to the structure to
++						   use for expansion */
++			  while ((p2) && (p2->type & CONST_ASSIGN))
++			    p2 = p2->right;
++
++			  if (p2)
++			    {
++			      snprintf(name, sizeof(name), "%s.%s", definitionsName, p2->name);
++
++			      result =
++				asn1_create_element (definitions, name, &aux);
++			      if (result == ASN1_SUCCESS)
++				{
++				  _asn1_cpy_name (aux, p);
++				  len2 =
++				    asn1_get_length_der (p->value,
++							 p->value_len, &len3);
++				  if (len2 < 0)
++				    return ASN1_DER_ERROR;
++
++				  result =
++				    asn1_der_decoding (&aux, p->value + len3,
++						       len2,
++						       errorDescription);
++				  if (result == ASN1_SUCCESS)
++				    {
++
++				      _asn1_set_right (aux, p->right);
++				      _asn1_set_right (p, aux);
++
++				      result = asn1_delete_structure (&p);
++				      if (result == ASN1_SUCCESS)
++					{
++					  p = aux;
++					  aux = NULL;
++					  break;
++					}
++				      else
++					{	/* error with asn1_delete_structure */
++					  asn1_delete_structure (&aux);
++					  retCode = result;
++					  break;
++					}
++				    }
++				  else
++				    {	/* error with asn1_der_decoding */
++				      retCode = result;
++				      break;
++				    }
++				}
++			      else
++				{	/* error with asn1_create_element */
++				  retCode = result;
++				  break;
++				}
++			    }
++			  else
++			    {	/* error with the pointer to the structure to exapand */
++			      retCode = ASN1_ERROR_TYPE_ANY;
++			      break;
++			    }
++			}
++		    }
++		  p2 = p2->right;
++		}		/* end while */
++
++	      if (!p2)
++		{
++		  retCode = ASN1_ERROR_TYPE_ANY;
++		  break;
++		}
++
++	    }
++	  break;
++	default:
++	  break;
++	}
++
++
++      if (p->down)
++	{
++	  p = p->down;
++	}
++      else if (p == *element)
++	{
++	  p = NULL;
++	  break;
++	}
++      else if (p->right)
++	p = p->right;
++      else
++	{
++	  while (1)
++	    {
++	      p = _asn1_find_up (p);
++	      if (p == *element)
++		{
++		  p = NULL;
++		  break;
++		}
++	      if (p->right)
++		{
++		  p = p->right;
++		  break;
++		}
++	    }
++	}
++    }
++
++  return retCode;
++}
++
++/**
++ * asn1_expand_octet_string:
++ * @definitions: ASN1 definitions
++ * @element: pointer to an ASN1 structure
++ * @octetName: name of the OCTECT STRING field to expand.
++ * @objectName: name of the OBJECT IDENTIFIER field to use to define
++ *    the type for expansion.
++ *
++ * Expands an "OCTET STRING" element of a structure created from a DER
++ * decoding process (the asn1_der_decoding() function).  The type used
++ * for expansion is the first one following the definition of the
++ * actual value of the OBJECT IDENTIFIER indicated by OBJECTNAME.
++ *
++ * Returns: %ASN1_SUCCESS if substitution OK, %ASN1_ELEMENT_NOT_FOUND
++ *   if @objectName or @octetName are not correct,
++ *   %ASN1_VALUE_NOT_VALID if it wasn't possible to find the type to
++ *   use for expansion, or other errors depending on DER decoding.
++ **/
++int
++asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element,
++			  const char *octetName, const char *objectName)
++{
++  char name[2 * ASN1_MAX_NAME_SIZE + 1], value[ASN1_MAX_NAME_SIZE];
++  int retCode = ASN1_SUCCESS, result;
++  int len, len2, len3;
++  asn1_node_const p2;
++  asn1_node aux = NULL;
++  asn1_node octetNode = NULL, objectNode = NULL;
++  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
++
++  if ((definitions == NULL) || (*element == NULL))
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  octetNode = asn1_find_node (*element, octetName);
++  if (octetNode == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++  if (type_field (octetNode->type) != ASN1_ETYPE_OCTET_STRING)
++    return ASN1_ELEMENT_NOT_FOUND;
++  if (octetNode->value == NULL)
++    return ASN1_VALUE_NOT_FOUND;
++
++  objectNode = asn1_find_node (*element, objectName);
++  if (objectNode == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  if (type_field (objectNode->type) != ASN1_ETYPE_OBJECT_ID)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  if (objectNode->value == NULL)
++    return ASN1_VALUE_NOT_FOUND;
++
++
++  /* search the OBJECT_ID into definitions */
++  p2 = definitions->down;
++  while (p2)
++    {
++      if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) &&
++	  (p2->type & CONST_ASSIGN))
++	{
++	  strcpy (name, definitions->name);
++	  strcat (name, ".");
++	  strcat (name, p2->name);
++
++	  len = sizeof (value);
++	  result = asn1_read_value (definitions, name, value, &len);
++
++	  if ((result == ASN1_SUCCESS)
++	      && (!_asn1_strcmp (objectNode->value, value)))
++	    {
++
++	      p2 = p2->right;	/* pointer to the structure to
++				   use for expansion */
++	      while ((p2) && (p2->type & CONST_ASSIGN))
++		p2 = p2->right;
++
++	      if (p2)
++		{
++		  strcpy (name, definitions->name);
++		  strcat (name, ".");
++		  strcat (name, p2->name);
++
++		  result = asn1_create_element (definitions, name, &aux);
++		  if (result == ASN1_SUCCESS)
++		    {
++		      _asn1_cpy_name (aux, octetNode);
++		      len2 =
++			asn1_get_length_der (octetNode->value,
++					     octetNode->value_len, &len3);
++		      if (len2 < 0)
++			return ASN1_DER_ERROR;
++
++		      result =
++			asn1_der_decoding (&aux, octetNode->value + len3,
++					   len2, errorDescription);
++		      if (result == ASN1_SUCCESS)
++			{
++
++			  _asn1_set_right (aux, octetNode->right);
++			  _asn1_set_right (octetNode, aux);
++
++			  result = asn1_delete_structure (&octetNode);
++			  if (result == ASN1_SUCCESS)
++			    {
++			      aux = NULL;
++			      break;
++			    }
++			  else
++			    {	/* error with asn1_delete_structure */
++			      asn1_delete_structure (&aux);
++			      retCode = result;
++			      break;
++			    }
++			}
++		      else
++			{	/* error with asn1_der_decoding */
++			  retCode = result;
++			  break;
++			}
++		    }
++		  else
++		    {		/* error with asn1_create_element */
++		      retCode = result;
++		      break;
++		    }
++		}
++	      else
++		{		/* error with the pointer to the structure to exapand */
++		  retCode = ASN1_VALUE_NOT_VALID;
++		  break;
++		}
++	    }
++	}
++
++      p2 = p2->right;
++
++    }
++
++  if (!p2)
++    retCode = ASN1_VALUE_NOT_VALID;
++
++  return retCode;
++}
++
++/*-
++ * _asn1_decode_simple_der:
++ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
++ * @der: the encoded string
++ * @_der_len: the bytes of the encoded string
++ * @str: a pointer to the data
++ * @str_len: the length of the data
++ * @dflags: DECODE_FLAG_*
++ *
++ * Decodes a simple DER encoded type (e.g. a string, which is not constructed).
++ * The output is a pointer inside the @der.
++ *
++ * Returns: %ASN1_SUCCESS if successful or an error value.
++ -*/
++static int
++_asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
++			unsigned int _der_len, const unsigned char **str,
++			unsigned int *str_len, unsigned dflags)
++{
++  int tag_len, len_len;
++  const unsigned char *p;
++  int der_len = _der_len;
++  unsigned char class;
++  unsigned long tag;
++  long ret;
++
++  if (der == NULL || der_len == 0)
++    return ASN1_VALUE_NOT_VALID;
++
++  if (ETYPE_OK (etype) == 0 || ETYPE_IS_STRING(etype) == 0)
++    return ASN1_VALUE_NOT_VALID;
++
++  /* doesn't handle constructed classes */
++  class = ETYPE_CLASS(etype);
++  if (class != ASN1_CLASS_UNIVERSAL)
++    return ASN1_VALUE_NOT_VALID;
++
++  p = der;
++
++  if (dflags & DECODE_FLAG_HAVE_TAG)
++    {
++      ret = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag);
++      if (ret != ASN1_SUCCESS)
++        return ret;
++
++      if (class != ETYPE_CLASS (etype) || tag != ETYPE_TAG (etype))
++        {
++          warn();
++          return ASN1_DER_ERROR;
++        }
++
++      p += tag_len;
++      der_len -= tag_len;
++      if (der_len <= 0)
++        return ASN1_DER_ERROR;
++    }
++
++  ret = asn1_get_length_der (p, der_len, &len_len);
++  if (ret < 0)
++    return ASN1_DER_ERROR;
++
++  p += len_len;
++  der_len -= len_len;
++  if (der_len <= 0)
++    return ASN1_DER_ERROR;
++
++  *str_len = ret;
++  *str = p;
++
++  return ASN1_SUCCESS;
++}
++
++/**
++ * asn1_decode_simple_der:
++ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
++ * @der: the encoded string
++ * @_der_len: the bytes of the encoded string
++ * @str: a pointer to the data
++ * @str_len: the length of the data
++ *
++ * Decodes a simple DER encoded type (e.g. a string, which is not constructed).
++ * The output is a pointer inside the @der.
++ *
++ * Returns: %ASN1_SUCCESS if successful or an error value.
++ **/
++int
++asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
++			unsigned int _der_len, const unsigned char **str,
++			unsigned int *str_len)
++{
++  return _asn1_decode_simple_der(etype, der, _der_len, str, str_len, DECODE_FLAG_HAVE_TAG);
++}
++
++static int append(uint8_t **dst, unsigned *dst_size, const unsigned char *src, unsigned src_size)
++{
++  if (src_size == 0)
++    return ASN1_SUCCESS;
++
++  *dst = _asn1_realloc(*dst, *dst_size+src_size);
++  if (*dst == NULL)
++    return ASN1_MEM_ALLOC_ERROR;
++  memcpy(*dst + *dst_size, src, src_size);
++  *dst_size += src_size;
++  return ASN1_SUCCESS;
++}
++
++/*-
++ * _asn1_decode_simple_ber:
++ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
++ * @der: the encoded string
++ * @_der_len: the bytes of the encoded string
++ * @str: a pointer to the data
++ * @str_len: the length of the data
++ * @ber_len: the total length occupied by BER (may be %NULL)
++ * @have_tag: whether a DER tag is included
++ *
++ * Decodes a BER encoded type. The output is an allocated value
++ * of the data. This decodes BER STRINGS only. Other types are
++ * decoded as DER.
++ *
++ * Returns: %ASN1_SUCCESS if successful or an error value.
++ -*/
++static int
++_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
++			unsigned int _der_len, unsigned char **str,
++			unsigned int *str_len, unsigned int *ber_len,
++			unsigned dflags)
++{
++  int tag_len, len_len;
++  const unsigned char *p;
++  int der_len = _der_len;
++  uint8_t *total = NULL;
++  unsigned total_size = 0;
++  unsigned char class;
++  unsigned long tag;
++  unsigned char *out = NULL;
++  const unsigned char *cout = NULL;
++  unsigned out_len;
++  long result;
++
++  if (ber_len) *ber_len = 0;
++
++  if (der == NULL || der_len == 0)
++    {
++      warn();
++      return ASN1_VALUE_NOT_VALID;
++    }
++
++  if (ETYPE_OK (etype) == 0)
++    {
++      warn();
++      return ASN1_VALUE_NOT_VALID;
++    }
++
++  /* doesn't handle constructed + definite classes */
++  class = ETYPE_CLASS (etype);
++  if (class != ASN1_CLASS_UNIVERSAL)
++    {
++      warn();
++      return ASN1_VALUE_NOT_VALID;
++    }
++
++  p = der;
++
++  if (dflags & DECODE_FLAG_HAVE_TAG)
++    {
++      result = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag);
++        if (result != ASN1_SUCCESS)
++          {
++            warn();
++            return result;
++          }
++
++        if (tag != ETYPE_TAG (etype))
++          {
++            warn();
++            return ASN1_DER_ERROR;
++          }
++
++        p += tag_len;
++
++        DECR_LEN(der_len, tag_len);
++
++        if (ber_len) *ber_len += tag_len;
++    }
++
++  /* indefinite constructed */
++  if ((((dflags & DECODE_FLAG_CONSTRUCTED) || class == ASN1_CLASS_STRUCTURED) && ETYPE_IS_STRING(etype)) &&
++      !(dflags & DECODE_FLAG_LEVEL3))
++    {
++      if (der_len == 0)
++        {
++          warn();
++          result = ASN1_DER_ERROR;
++          goto cleanup;
++        }
++
++      if (der_len > 0 && p[0] == 0x80) /* indefinite */
++        {
++          len_len = 1;
++          DECR_LEN(der_len, len_len);
++          p += len_len;
++
++          if (ber_len) *ber_len += len_len;
++
++          /* decode the available octet strings */
++          do
++            {
++              unsigned tmp_len;
++              unsigned flags = DECODE_FLAG_HAVE_TAG;
++
++              if (dflags & DECODE_FLAG_LEVEL1)
++                flags |= DECODE_FLAG_LEVEL2;
++              else if (dflags & DECODE_FLAG_LEVEL2)
++                flags |= DECODE_FLAG_LEVEL3;
++              else
++		flags |= DECODE_FLAG_LEVEL1;
++
++              result = _asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len,
++                                               flags);
++              if (result != ASN1_SUCCESS)
++                {
++                  warn();
++                  goto cleanup;
++                }
++
++              p += tmp_len;
++              DECR_LEN(der_len, tmp_len);
++
++              if (ber_len) *ber_len += tmp_len;
++
++              DECR_LEN(der_len, 2); /* we need the EOC */
++
++              result = append(&total, &total_size, out, out_len);
++              if (result != ASN1_SUCCESS)
++                {
++                  warn();
++                  goto cleanup;
++	        }
++
++              free(out);
++              out = NULL;
++
++	      if (p[0] == 0 && p[1] == 0) /* EOC */
++	        {
++                  if (ber_len) *ber_len += 2;
++                  break;
++                }
++
++              /* no EOC */
++              der_len += 2;
++
++              if (der_len == 2)
++                {
++                  warn();
++                  result = ASN1_DER_ERROR;
++                  goto cleanup;
++                }
++            }
++          while(1);
++        }
++      else /* constructed */
++        {
++          long const_len;
++
++          result = asn1_get_length_ber(p, der_len, &len_len);
++          if (result < 0)
++            {
++              warn();
++              result = ASN1_DER_ERROR;
++              goto cleanup;
++            }
++
++          DECR_LEN(der_len, len_len);
++          p += len_len;
++
++          const_len = result;
++
++          if (ber_len) *ber_len += len_len;
++
++          /* decode the available octet strings */
++          while(const_len > 0)
++            {
++              unsigned tmp_len;
++              unsigned flags = DECODE_FLAG_HAVE_TAG;
++
++              if (dflags & DECODE_FLAG_LEVEL1)
++                flags |= DECODE_FLAG_LEVEL2;
++              else if (dflags & DECODE_FLAG_LEVEL2)
++                flags |= DECODE_FLAG_LEVEL3;
++              else
++		flags |= DECODE_FLAG_LEVEL1;
++
++              result = _asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len,
++                                               flags);
++              if (result != ASN1_SUCCESS)
++                {
++                  warn();
++                  goto cleanup;
++                }
++
++              p += tmp_len;
++              DECR_LEN(der_len, tmp_len);
++              DECR_LEN(const_len, tmp_len);
++
++              if (ber_len) *ber_len += tmp_len;
++
++              result = append(&total, &total_size, out, out_len);
++              if (result != ASN1_SUCCESS)
++                {
++                  warn();
++                  goto cleanup;
++	        }
++
++              free(out);
++              out = NULL;
++            }
++        }
++    }
++  else if (class == ETYPE_CLASS(etype))
++    {
++      if (ber_len)
++        {
++          result = asn1_get_length_der (p, der_len, &len_len);
++          if (result < 0)
++            {
++              warn();
++              result = ASN1_DER_ERROR;
++              goto cleanup;
++            }
++          *ber_len += result + len_len;
++        }
++
++      /* non-string values are decoded as DER */
++      result = _asn1_decode_simple_der(etype, der, _der_len, &cout, &out_len, dflags);
++      if (result != ASN1_SUCCESS)
++        {
++          warn();
++          goto cleanup;
++        }
++
++      result = append(&total, &total_size, cout, out_len);
++      if (result != ASN1_SUCCESS)
++        {
++          warn();
++          goto cleanup;
++        }
++    }
++  else
++    {
++      warn();
++      result = ASN1_DER_ERROR;
++      goto cleanup;
++    }
++
++  *str = total;
++  *str_len = total_size;
++
++  return ASN1_SUCCESS;
++cleanup:
++  free(out);
++  free(total);
++  return result;
++}
++
++/**
++ * asn1_decode_simple_ber:
++ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
++ * @der: the encoded string
++ * @_der_len: the bytes of the encoded string
++ * @str: a pointer to the data
++ * @str_len: the length of the data
++ * @ber_len: the total length occupied by BER (may be %NULL)
++ *
++ * Decodes a BER encoded type. The output is an allocated value
++ * of the data. This decodes BER STRINGS only. Other types are
++ * decoded as DER.
++ *
++ * Returns: %ASN1_SUCCESS if successful or an error value.
++ **/
++int
++asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
++			unsigned int _der_len, unsigned char **str,
++			unsigned int *str_len, unsigned int *ber_len)
++{
++  return _asn1_decode_simple_ber(etype, der, _der_len, str, str_len, ber_len, DECODE_FLAG_HAVE_TAG);
++}
+diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c
+new file mode 100644
+index 0000000000..997eb2725d
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/element.c
+@@ -0,0 +1,1111 @@
++/*
++ * Copyright (C) 2000-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++/*****************************************************/
++/* File: element.c                                   */
++/* Description: Functions with the read and write    */
++/*   functions.                                      */
++/*****************************************************/
++
++
++#include <int.h>
++#include "parser_aux.h"
++#include <gstr.h>
++#include "structure.h"
++#include "c-ctype.h"
++#include "element.h"
++
++void
++_asn1_hierarchical_name (asn1_node_const node, char *name, int name_size)
++{
++  asn1_node_const p;
++  char tmp_name[64];
++
++  p = node;
++
++  name[0] = 0;
++
++  while (p != NULL)
++    {
++      if (p->name[0] != 0)
++	{
++	  _asn1_str_cpy (tmp_name, sizeof (tmp_name), name),
++	    _asn1_str_cpy (name, name_size, p->name);
++	  _asn1_str_cat (name, name_size, ".");
++	  _asn1_str_cat (name, name_size, tmp_name);
++	}
++      p = _asn1_find_up (p);
++    }
++
++  if (name[0] == 0)
++    _asn1_str_cpy (name, name_size, "ROOT");
++}
++
++
++/******************************************************************/
++/* Function : _asn1_convert_integer                               */
++/* Description: converts an integer from a null terminated string */
++/*              to der decoding. The convertion from a null       */
++/*              terminated string to an integer is made with      */
++/*              the 'strtol' function.                            */
++/* Parameters:                                                    */
++/*   value: null terminated string to convert.                    */
++/*   value_out: convertion result (memory must be already         */
++/*              allocated).                                       */
++/*   value_out_size: number of bytes of value_out.                */
++/*   len: number of significant byte of value_out.                */
++/* Return: ASN1_MEM_ERROR or ASN1_SUCCESS                         */
++/******************************************************************/
++int
++_asn1_convert_integer (const unsigned char *value, unsigned char *value_out,
++		       int value_out_size, int *len)
++{
++  char negative;
++  unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
++  long valtmp;
++  int k, k2;
++
++  valtmp = _asn1_strtol (value, NULL, 10);
++
++  for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++)
++    {
++      val[SIZEOF_UNSIGNED_LONG_INT - k - 1] = (valtmp >> (8 * k)) & 0xFF;
++    }
++
++  if (val[0] & 0x80)
++    negative = 1;
++  else
++    negative = 0;
++
++  for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT - 1; k++)
++    {
++      if (negative && (val[k] != 0xFF))
++	break;
++      else if (!negative && val[k])
++	break;
++    }
++
++  if ((negative && !(val[k] & 0x80)) || (!negative && (val[k] & 0x80)))
++    k--;
++
++  *len = SIZEOF_UNSIGNED_LONG_INT - k;
++
++  if (SIZEOF_UNSIGNED_LONG_INT - k > value_out_size)
++    /* VALUE_OUT is too short to contain the value conversion */
++    return ASN1_MEM_ERROR;
++
++  if (value_out != NULL)
++    {
++      for (k2 = k; k2 < SIZEOF_UNSIGNED_LONG_INT; k2++)
++        value_out[k2 - k] = val[k2];
++    }
++
++#if 0
++  printf ("_asn1_convert_integer: valueIn=%s, lenOut=%d", value, *len);
++  for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++)
++    printf (", vOut[%d]=%d", k, value_out[k]);
++  printf ("\n");
++#endif
++
++  return ASN1_SUCCESS;
++}
++
++/* Appends a new element into the sequence (or set) defined by this
++ * node. The new element will have a name of '?number', where number
++ * is a monotonically increased serial number.
++ *
++ * The last element in the list may be provided in @pcache, to avoid
++ * traversing the list, an expensive operation in long lists.
++ *
++ * On success it returns in @pcache the added element (which is the
++ * tail in the list of added elements).
++ */
++int
++_asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache)
++{
++  asn1_node p, p2;
++  char temp[LTOSTR_MAX_SIZE];
++  long n;
++
++  if (!node || !(node->down))
++    return ASN1_GENERIC_ERROR;
++
++  p = node->down;
++  while ((type_field (p->type) == ASN1_ETYPE_TAG)
++	 || (type_field (p->type) == ASN1_ETYPE_SIZE))
++    p = p->right;
++
++  p2 = _asn1_copy_structure3 (p);
++  if (p2 == NULL)
++    return ASN1_GENERIC_ERROR;
++
++  if (pcache == NULL || pcache->tail == NULL || pcache->head != node)
++    {
++      while (p->right)
++        {
++          p = p->right;
++        }
++    }
++  else
++    {
++      p = pcache->tail;
++    }
++
++  _asn1_set_right (p, p2);
++  if (pcache)
++    {
++      pcache->head = node;
++      pcache->tail = p2;
++    }
++
++  if (p->name[0] == 0)
++    _asn1_str_cpy (temp, sizeof (temp), "?1");
++  else
++    {
++      n = strtol (p->name + 1, NULL, 0);
++      n++;
++      temp[0] = '?';
++      _asn1_ltostr (n, temp + 1);
++    }
++  _asn1_set_name (p2, temp);
++  /*  p2->type |= CONST_OPTION; */
++
++  return ASN1_SUCCESS;
++}
++
++
++/**
++ * asn1_write_value:
++ * @node_root: pointer to a structure
++ * @name: the name of the element inside the structure that you want to set.
++ * @ivalue: vector used to specify the value to set. If len is >0,
++ *   VALUE must be a two's complement form integer.  if len=0 *VALUE
++ *   must be a null terminated string with an integer value.
++ * @len: number of bytes of *value to use to set the value:
++ *   value[0]..value[len-1] or 0 if value is a null terminated string
++ *
++ * Set the value of one element inside a structure.
++ *
++ * If an element is OPTIONAL and you want to delete it, you must use
++ * the value=NULL and len=0.  Using "pkix.asn":
++ *
++ * result=asn1_write_value(cert, "tbsCertificate.issuerUniqueID",
++ * NULL, 0);
++ *
++ * Description for each type:
++ *
++ * INTEGER: VALUE must contain a two's complement form integer.
++ *
++ *            value[0]=0xFF ,               len=1 -> integer=-1.
++ *            value[0]=0xFF value[1]=0xFF , len=2 -> integer=-1.
++ *            value[0]=0x01 ,               len=1 -> integer= 1.
++ *            value[0]=0x00 value[1]=0x01 , len=2 -> integer= 1.
++ *            value="123"                 , len=0 -> integer= 123.
++ *
++ * ENUMERATED: As INTEGER (but only with not negative numbers).
++ *
++ * BOOLEAN: VALUE must be the null terminated string "TRUE" or
++ *   "FALSE" and LEN != 0.
++ *
++ *            value="TRUE" , len=1 -> boolean=TRUE.
++ *            value="FALSE" , len=1 -> boolean=FALSE.
++ *
++ * OBJECT IDENTIFIER: VALUE must be a null terminated string with
++ *   each number separated by a dot (e.g. "1.2.3.543.1").  LEN != 0.
++ *
++ *            value="1 2 840 10040 4 3" , len=1 -> OID=dsa-with-sha.
++ *
++ * UTCTime: VALUE must be a null terminated string in one of these
++ *   formats: "YYMMDDhhmmssZ", "YYMMDDhhmmssZ",
++ *   "YYMMDDhhmmss+hh'mm'", "YYMMDDhhmmss-hh'mm'",
++ *   "YYMMDDhhmm+hh'mm'", or "YYMMDDhhmm-hh'mm'".  LEN != 0.
++ *
++ *            value="9801011200Z" , len=1 -> time=Jannuary 1st, 1998
++ *            at 12h 00m Greenwich Mean Time
++ *
++ * GeneralizedTime: VALUE must be in one of this format:
++ *   "YYYYMMDDhhmmss.sZ", "YYYYMMDDhhmmss.sZ",
++ *   "YYYYMMDDhhmmss.s+hh'mm'", "YYYYMMDDhhmmss.s-hh'mm'",
++ *   "YYYYMMDDhhmm+hh'mm'", or "YYYYMMDDhhmm-hh'mm'" where ss.s
++ *   indicates the seconds with any precision like "10.1" or "01.02".
++ *   LEN != 0
++ *
++ *            value="2001010112001.12-0700" , len=1 -> time=Jannuary
++ *            1st, 2001 at 12h 00m 01.12s Pacific Daylight Time
++ *
++ * OCTET STRING: VALUE contains the octet string and LEN is the
++ *   number of octets.
++ *
++ *            value="$\backslash$x01$\backslash$x02$\backslash$x03" ,
++ *            len=3 -> three bytes octet string
++ *
++ * GeneralString: VALUE contains the generalstring and LEN is the
++ *   number of octets.
++ *
++ *            value="$\backslash$x01$\backslash$x02$\backslash$x03" ,
++ *            len=3 -> three bytes generalstring
++ *
++ * BIT STRING: VALUE contains the bit string organized by bytes and
++ *   LEN is the number of bits.
++ *
++ *   value="$\backslash$xCF" , len=6 -> bit string="110011" (six
++ *   bits)
++ *
++ * CHOICE: if NAME indicates a choice type, VALUE must specify one of
++ *   the alternatives with a null terminated string. LEN != 0. Using
++ *   "pkix.asn"\:
++ *
++ *           result=asn1_write_value(cert,
++ *           "certificate1.tbsCertificate.subject", "rdnSequence",
++ *           1);
++ *
++ * ANY: VALUE indicates the der encoding of a structure.  LEN != 0.
++ *
++ * SEQUENCE OF: VALUE must be the null terminated string "NEW" and
++ *   LEN != 0. With this instruction another element is appended in
++ *   the sequence. The name of this element will be "?1" if it's the
++ *   first one, "?2" for the second and so on.
++ *
++ *   Using "pkix.asn"\:
++ *
++ *   result=asn1_write_value(cert,
++ *   "certificate1.tbsCertificate.subject.rdnSequence", "NEW", 1);
++ *
++ * SET OF: the same as SEQUENCE OF.  Using "pkix.asn":
++ *
++ *           result=asn1_write_value(cert,
++ *           "tbsCertificate.subject.rdnSequence.?LAST", "NEW", 1);
++ *
++ * Returns: %ASN1_SUCCESS if the value was set,
++ *   %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, and
++ *   %ASN1_VALUE_NOT_VALID if @ivalue has a wrong format.
++ **/
++int
++asn1_write_value (asn1_node node_root, const char *name,
++		  const void *ivalue, int len)
++{
++  asn1_node node, p, p2;
++  unsigned char *temp, *value_temp = NULL, *default_temp = NULL;
++  int len2, k, k2, negative;
++  size_t i;
++  const unsigned char *value = ivalue;
++  unsigned int type;
++
++  node = asn1_find_node (node_root, name);
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  if ((node->type & CONST_OPTION) && (value == NULL) && (len == 0))
++    {
++      asn1_delete_structure (&node);
++      return ASN1_SUCCESS;
++    }
++
++  type = type_field (node->type);
++
++  if ((type == ASN1_ETYPE_SEQUENCE_OF || type == ASN1_ETYPE_SET_OF) && (value == NULL) && (len == 0))
++    {
++      p = node->down;
++      while ((type_field (p->type) == ASN1_ETYPE_TAG)
++	     || (type_field (p->type) == ASN1_ETYPE_SIZE))
++	p = p->right;
++
++      while (p->right)
++	asn1_delete_structure (&p->right);
++
++      return ASN1_SUCCESS;
++    }
++
++  /* Don't allow element deletion for other types */
++  if (value == NULL)
++    {
++      return ASN1_VALUE_NOT_VALID;
++    }
++
++  switch (type)
++    {
++    case ASN1_ETYPE_BOOLEAN:
++      if (!_asn1_strcmp (value, "TRUE"))
++	{
++	  if (node->type & CONST_DEFAULT)
++	    {
++	      p = node->down;
++	      while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
++		p = p->right;
++	      if (p->type & CONST_TRUE)
++		_asn1_set_value (node, NULL, 0);
++	      else
++		_asn1_set_value (node, "T", 1);
++	    }
++	  else
++	    _asn1_set_value (node, "T", 1);
++	}
++      else if (!_asn1_strcmp (value, "FALSE"))
++	{
++	  if (node->type & CONST_DEFAULT)
++	    {
++	      p = node->down;
++	      while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
++		p = p->right;
++	      if (p->type & CONST_FALSE)
++		_asn1_set_value (node, NULL, 0);
++	      else
++		_asn1_set_value (node, "F", 1);
++	    }
++	  else
++	    _asn1_set_value (node, "F", 1);
++	}
++      else
++	return ASN1_VALUE_NOT_VALID;
++      break;
++    case ASN1_ETYPE_INTEGER:
++    case ASN1_ETYPE_ENUMERATED:
++      if (len == 0)
++	{
++	  if ((c_isdigit (value[0])) || (value[0] == '-'))
++	    {
++	      value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
++	      if (value_temp == NULL)
++		return ASN1_MEM_ALLOC_ERROR;
++
++	      _asn1_convert_integer (value, value_temp,
++				     SIZEOF_UNSIGNED_LONG_INT, &len);
++	    }
++	  else
++	    {			/* is an identifier like v1 */
++	      if (!(node->type & CONST_LIST))
++		return ASN1_VALUE_NOT_VALID;
++	      p = node->down;
++	      while (p)
++		{
++		  if (type_field (p->type) == ASN1_ETYPE_CONSTANT)
++		    {
++		      if (!_asn1_strcmp (p->name, value))
++			{
++			  value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
++			  if (value_temp == NULL)
++			    return ASN1_MEM_ALLOC_ERROR;
++
++			  _asn1_convert_integer (p->value,
++						 value_temp,
++						 SIZEOF_UNSIGNED_LONG_INT,
++						 &len);
++			  break;
++			}
++		    }
++		  p = p->right;
++		}
++	      if (p == NULL)
++		return ASN1_VALUE_NOT_VALID;
++	    }
++	}
++      else
++	{			/* len != 0 */
++	  value_temp = malloc (len);
++	  if (value_temp == NULL)
++	    return ASN1_MEM_ALLOC_ERROR;
++	  memcpy (value_temp, value, len);
++	}
++
++      if (value_temp[0] & 0x80)
++	negative = 1;
++      else
++	negative = 0;
++
++      if (negative && (type_field (node->type) == ASN1_ETYPE_ENUMERATED))
++	{
++	  free (value_temp);
++	  return ASN1_VALUE_NOT_VALID;
++	}
++
++      for (k = 0; k < len - 1; k++)
++	if (negative && (value_temp[k] != 0xFF))
++	  break;
++	else if (!negative && value_temp[k])
++	  break;
++
++      if ((negative && !(value_temp[k] & 0x80)) ||
++	  (!negative && (value_temp[k] & 0x80)))
++	k--;
++
++      _asn1_set_value_lv (node, value_temp + k, len - k);
++
++      if (node->type & CONST_DEFAULT)
++	{
++	  p = node->down;
++	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
++	    p = p->right;
++	  if ((c_isdigit (p->value[0])) || (p->value[0] == '-'))
++	    {
++	      default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
++	      if (default_temp == NULL)
++		{
++		  free (value_temp);
++		  return ASN1_MEM_ALLOC_ERROR;
++		}
++
++	      _asn1_convert_integer (p->value, default_temp,
++				     SIZEOF_UNSIGNED_LONG_INT, &len2);
++	    }
++	  else
++	    {			/* is an identifier like v1 */
++	      if (!(node->type & CONST_LIST))
++		{
++		  free (value_temp);
++		  return ASN1_VALUE_NOT_VALID;
++		}
++	      p2 = node->down;
++	      while (p2)
++		{
++		  if (type_field (p2->type) == ASN1_ETYPE_CONSTANT)
++		    {
++		      if (!_asn1_strcmp (p2->name, p->value))
++			{
++			  default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
++			  if (default_temp == NULL)
++			    {
++			      free (value_temp);
++			      return ASN1_MEM_ALLOC_ERROR;
++			    }
++
++			  _asn1_convert_integer (p2->value,
++						 default_temp,
++						 SIZEOF_UNSIGNED_LONG_INT,
++						 &len2);
++			  break;
++			}
++		    }
++		  p2 = p2->right;
++		}
++	      if (p2 == NULL)
++		{
++		  free (value_temp);
++		  return ASN1_VALUE_NOT_VALID;
++		}
++	    }
++
++
++	  if ((len - k) == len2)
++	    {
++	      for (k2 = 0; k2 < len2; k2++)
++		if (value_temp[k + k2] != default_temp[k2])
++		  {
++		    break;
++		  }
++	      if (k2 == len2)
++		_asn1_set_value (node, NULL, 0);
++	    }
++	  free (default_temp);
++	}
++      free (value_temp);
++      break;
++    case ASN1_ETYPE_OBJECT_ID:
++      for (i = 0; i < _asn1_strlen (value); i++)
++	if ((!c_isdigit (value[i])) && (value[i] != '.') && (value[i] != '+'))
++	  return ASN1_VALUE_NOT_VALID;
++      if (node->type & CONST_DEFAULT)
++	{
++	  p = node->down;
++	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
++	    p = p->right;
++	  if (!_asn1_strcmp (value, p->value))
++	    {
++	      _asn1_set_value (node, NULL, 0);
++	      break;
++	    }
++	}
++      _asn1_set_value (node, value, _asn1_strlen (value) + 1);
++      break;
++    case ASN1_ETYPE_UTC_TIME:
++      {
++	len = _asn1_strlen (value);
++	if (len < 11)
++	  return ASN1_VALUE_NOT_VALID;
++	for (k = 0; k < 10; k++)
++	  if (!c_isdigit (value[k]))
++	    return ASN1_VALUE_NOT_VALID;
++	switch (len)
++	  {
++	  case 11:
++	    if (value[10] != 'Z')
++	      return ASN1_VALUE_NOT_VALID;
++	    break;
++	  case 13:
++	    if ((!c_isdigit (value[10])) || (!c_isdigit (value[11])) ||
++		(value[12] != 'Z'))
++	      return ASN1_VALUE_NOT_VALID;
++	    break;
++	  case 15:
++	    if ((value[10] != '+') && (value[10] != '-'))
++	      return ASN1_VALUE_NOT_VALID;
++	    for (k = 11; k < 15; k++)
++	      if (!c_isdigit (value[k]))
++		return ASN1_VALUE_NOT_VALID;
++	    break;
++	  case 17:
++	    if ((!c_isdigit (value[10])) || (!c_isdigit (value[11])))
++	      return ASN1_VALUE_NOT_VALID;
++	    if ((value[12] != '+') && (value[12] != '-'))
++	      return ASN1_VALUE_NOT_VALID;
++	    for (k = 13; k < 17; k++)
++	      if (!c_isdigit (value[k]))
++		return ASN1_VALUE_NOT_VALID;
++	    break;
++	  default:
++	    return ASN1_VALUE_NOT_FOUND;
++	  }
++	_asn1_set_value (node, value, len);
++      }
++      break;
++    case ASN1_ETYPE_GENERALIZED_TIME:
++      len = _asn1_strlen (value);
++      _asn1_set_value (node, value, len);
++      break;
++    case ASN1_ETYPE_OCTET_STRING:
++    case ASN1_ETYPE_GENERALSTRING:
++    case ASN1_ETYPE_NUMERIC_STRING:
++    case ASN1_ETYPE_IA5_STRING:
++    case ASN1_ETYPE_TELETEX_STRING:
++    case ASN1_ETYPE_PRINTABLE_STRING:
++    case ASN1_ETYPE_UNIVERSAL_STRING:
++    case ASN1_ETYPE_BMP_STRING:
++    case ASN1_ETYPE_UTF8_STRING:
++    case ASN1_ETYPE_VISIBLE_STRING:
++      if (len == 0)
++	len = _asn1_strlen (value);
++      _asn1_set_value_lv (node, value, len);
++      break;
++    case ASN1_ETYPE_BIT_STRING:
++      if (len == 0)
++	len = _asn1_strlen (value);
++      asn1_length_der ((len >> 3) + 2, NULL, &len2);
++      temp = malloc ((len >> 3) + 2 + len2);
++      if (temp == NULL)
++	return ASN1_MEM_ALLOC_ERROR;
++
++      asn1_bit_der (value, len, temp, &len2);
++      _asn1_set_value_m (node, temp, len2);
++      temp = NULL;
++      break;
++    case ASN1_ETYPE_CHOICE:
++      p = node->down;
++      while (p)
++	{
++	  if (!_asn1_strcmp (p->name, value))
++	    {
++	      p2 = node->down;
++	      while (p2)
++		{
++		  if (p2 != p)
++		    {
++		      asn1_delete_structure (&p2);
++		      p2 = node->down;
++		    }
++		  else
++		    p2 = p2->right;
++		}
++	      break;
++	    }
++	  p = p->right;
++	}
++      if (!p)
++	return ASN1_ELEMENT_NOT_FOUND;
++      break;
++    case ASN1_ETYPE_ANY:
++      _asn1_set_value_lv (node, value, len);
++      break;
++    case ASN1_ETYPE_SEQUENCE_OF:
++    case ASN1_ETYPE_SET_OF:
++      if (_asn1_strcmp (value, "NEW"))
++	return ASN1_VALUE_NOT_VALID;
++      _asn1_append_sequence_set (node, NULL);
++      break;
++    default:
++      return ASN1_ELEMENT_NOT_FOUND;
++      break;
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++#define PUT_VALUE( ptr, ptr_size, data, data_size) \
++	*len = data_size; \
++	if (ptr_size < data_size) { \
++		return ASN1_MEM_ERROR; \
++	} else { \
++		if (ptr && data_size > 0) \
++		  memcpy (ptr, data, data_size); \
++	}
++
++#define PUT_STR_VALUE( ptr, ptr_size, data) \
++	*len = _asn1_strlen (data) + 1; \
++	if (ptr_size < *len) { \
++		return ASN1_MEM_ERROR; \
++	} else { \
++		/* this strcpy is checked */ \
++		if (ptr) { \
++		  _asn1_strcpy (ptr, data); \
++		} \
++	}
++
++#define PUT_AS_STR_VALUE( ptr, ptr_size, data, data_size) \
++	*len = data_size + 1; \
++	if (ptr_size < *len) { \
++		return ASN1_MEM_ERROR; \
++	} else { \
++		/* this strcpy is checked */ \
++		if (ptr) { \
++		  if (data_size > 0) \
++		    memcpy (ptr, data, data_size); \
++		  ptr[data_size] = 0; \
++		} \
++	}
++
++#define ADD_STR_VALUE( ptr, ptr_size, data) \
++        *len += _asn1_strlen(data); \
++        if (ptr_size < (int) *len) { \
++                (*len)++; \
++                return ASN1_MEM_ERROR; \
++        } else { \
++                /* this strcat is checked */ \
++                if (ptr) _asn1_strcat (ptr, data); \
++        }
++
++/**
++ * asn1_read_value:
++ * @root: pointer to a structure.
++ * @name: the name of the element inside a structure that you want to read.
++ * @ivalue: vector that will contain the element's content, must be a
++ *   pointer to memory cells already allocated (may be %NULL).
++ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy
++ *   holds the sizeof value.
++ *
++ * Returns the value of one element inside a structure.
++ * If an element is OPTIONAL and this returns
++ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present
++ * in the der encoding that created the structure.  The first element
++ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and
++ * so on. If the @root provided is a node to specific sequence element,
++ * then the keyword "?CURRENT" is also acceptable and indicates the
++ * current sequence element of this node.
++ *
++ * Note that there can be valid values with length zero. In these case
++ * this function will succeed and @len will be zero.
++ *
++ * INTEGER: VALUE will contain a two's complement form integer.
++ *
++ *            integer=-1  -> value[0]=0xFF , len=1.
++ *            integer=1   -> value[0]=0x01 , len=1.
++ *
++ * ENUMERATED: As INTEGER (but only with not negative numbers).
++ *
++ * BOOLEAN: VALUE will be the null terminated string "TRUE" or
++ *   "FALSE" and LEN=5 or LEN=6.
++ *
++ * OBJECT IDENTIFIER: VALUE will be a null terminated string with
++ *   each number separated by a dot (i.e. "1.2.3.543.1").
++ *
++ *                      LEN = strlen(VALUE)+1
++ *
++ * UTCTime: VALUE will be a null terminated string in one of these
++ *   formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'".
++ *   LEN=strlen(VALUE)+1.
++ *
++ * GeneralizedTime: VALUE will be a null terminated string in the
++ *   same format used to set the value.
++ *
++ * OCTET STRING: VALUE will contain the octet string and LEN will be
++ *   the number of octets.
++ *
++ * GeneralString: VALUE will contain the generalstring and LEN will
++ *   be the number of octets.
++ *
++ * BIT STRING: VALUE will contain the bit string organized by bytes
++ *   and LEN will be the number of bits.
++ *
++ * CHOICE: If NAME indicates a choice type, VALUE will specify the
++ *   alternative selected.
++ *
++ * ANY: If NAME indicates an any type, VALUE will indicate the DER
++ *   encoding of the structure actually used.
++ *
++ * Returns: %ASN1_SUCCESS if value is returned,
++ *   %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element,
++ *   %ASN1_VALUE_NOT_FOUND if there isn't any value for the element
++ *   selected, and %ASN1_MEM_ERROR if The value vector isn't big enough
++ *   to store the result, and in this case @len will contain the number of
++ *   bytes needed. On the occasion that the stored data are of zero-length
++ *   this function may return %ASN1_SUCCESS even if the provided @len is zero.
++ **/
++int
++asn1_read_value (asn1_node_const root, const char *name, void *ivalue, int *len)
++{
++  return asn1_read_value_type (root, name, ivalue, len, NULL);
++}
++
++/**
++ * asn1_read_value_type:
++ * @root: pointer to a structure.
++ * @name: the name of the element inside a structure that you want to read.
++ * @ivalue: vector that will contain the element's content, must be a
++ *   pointer to memory cells already allocated (may be %NULL).
++ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy
++ *   holds the sizeof value.
++ * @etype: The type of the value read (ASN1_ETYPE)
++ *
++ * Returns the type and value of one element inside a structure.
++ * If an element is OPTIONAL and this returns
++ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present
++ * in the der encoding that created the structure.  The first element
++ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and
++ * so on. If the @root provided is a node to specific sequence element,
++ * then the keyword "?CURRENT" is also acceptable and indicates the
++ * current sequence element of this node.
++ *
++ * Note that there can be valid values with length zero. In these case
++ * this function will succeed and @len will be zero.
++ *
++ *
++ * INTEGER: VALUE will contain a two's complement form integer.
++ *
++ *            integer=-1  -> value[0]=0xFF , len=1.
++ *            integer=1   -> value[0]=0x01 , len=1.
++ *
++ * ENUMERATED: As INTEGER (but only with not negative numbers).
++ *
++ * BOOLEAN: VALUE will be the null terminated string "TRUE" or
++ *   "FALSE" and LEN=5 or LEN=6.
++ *
++ * OBJECT IDENTIFIER: VALUE will be a null terminated string with
++ *   each number separated by a dot (i.e. "1.2.3.543.1").
++ *
++ *                      LEN = strlen(VALUE)+1
++ *
++ * UTCTime: VALUE will be a null terminated string in one of these
++ *   formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'".
++ *   LEN=strlen(VALUE)+1.
++ *
++ * GeneralizedTime: VALUE will be a null terminated string in the
++ *   same format used to set the value.
++ *
++ * OCTET STRING: VALUE will contain the octet string and LEN will be
++ *   the number of octets.
++ *
++ * GeneralString: VALUE will contain the generalstring and LEN will
++ *   be the number of octets.
++ *
++ * BIT STRING: VALUE will contain the bit string organized by bytes
++ *   and LEN will be the number of bits.
++ *
++ * CHOICE: If NAME indicates a choice type, VALUE will specify the
++ *   alternative selected.
++ *
++ * ANY: If NAME indicates an any type, VALUE will indicate the DER
++ *   encoding of the structure actually used.
++ *
++ * Returns: %ASN1_SUCCESS if value is returned,
++ *   %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element,
++ *   %ASN1_VALUE_NOT_FOUND if there isn't any value for the element
++ *   selected, and %ASN1_MEM_ERROR if The value vector isn't big enough
++ *   to store the result, and in this case @len will contain the number of
++ *   bytes needed. On the occasion that the stored data are of zero-length
++ *   this function may return %ASN1_SUCCESS even if the provided @len is zero.
++ **/
++int
++asn1_read_value_type (asn1_node_const root, const char *name, void *ivalue,
++		      int *len, unsigned int *etype)
++{
++  asn1_node_const node, p, p2;
++  int len2, len3, result;
++  int value_size = *len;
++  unsigned char *value = ivalue;
++  unsigned type;
++
++  node = asn1_find_node (root, name);
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  type = type_field (node->type);
++
++  if ((type != ASN1_ETYPE_NULL) &&
++      (type != ASN1_ETYPE_CHOICE) &&
++      !(node->type & CONST_DEFAULT) && !(node->type & CONST_ASSIGN) &&
++      (node->value == NULL))
++    return ASN1_VALUE_NOT_FOUND;
++
++  if (etype)
++    *etype = type;
++  switch (type)
++    {
++    case ASN1_ETYPE_NULL:
++      PUT_STR_VALUE (value, value_size, "NULL");
++      break;
++    case ASN1_ETYPE_BOOLEAN:
++      if ((node->type & CONST_DEFAULT) && (node->value == NULL))
++	{
++	  p = node->down;
++	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
++	    p = p->right;
++	  if (p->type & CONST_TRUE)
++	    {
++	      PUT_STR_VALUE (value, value_size, "TRUE");
++	    }
++	  else
++	    {
++	      PUT_STR_VALUE (value, value_size, "FALSE");
++	    }
++	}
++      else if (node->value[0] == 'T')
++	{
++	  PUT_STR_VALUE (value, value_size, "TRUE");
++	}
++      else
++	{
++	  PUT_STR_VALUE (value, value_size, "FALSE");
++	}
++      break;
++    case ASN1_ETYPE_INTEGER:
++    case ASN1_ETYPE_ENUMERATED:
++      if ((node->type & CONST_DEFAULT) && (node->value == NULL))
++	{
++	  p = node->down;
++	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
++	    p = p->right;
++	  if ((c_isdigit (p->value[0])) || (p->value[0] == '-')
++	      || (p->value[0] == '+'))
++	    {
++	      result = _asn1_convert_integer
++		  (p->value, value, value_size, len);
++              if (result != ASN1_SUCCESS)
++		return result;
++	    }
++	  else
++	    {			/* is an identifier like v1 */
++	      p2 = node->down;
++	      while (p2)
++		{
++		  if (type_field (p2->type) == ASN1_ETYPE_CONSTANT)
++		    {
++		      if (!_asn1_strcmp (p2->name, p->value))
++			{
++			  result = _asn1_convert_integer
++			      (p2->value, value, value_size,
++			       len);
++			  if (result != ASN1_SUCCESS)
++			    return result;
++			  break;
++			}
++		    }
++		  p2 = p2->right;
++		}
++	    }
++	}
++      else
++	{
++	  len2 = -1;
++	  result = asn1_get_octet_der
++	      (node->value, node->value_len, &len2, value, value_size,
++	       len);
++          if (result != ASN1_SUCCESS)
++	    return result;
++	}
++      break;
++    case ASN1_ETYPE_OBJECT_ID:
++      if (node->type & CONST_ASSIGN)
++	{
++	  *len = 0;
++	  if (value)
++	    value[0] = 0;
++	  p = node->down;
++	  while (p)
++	    {
++	      if (type_field (p->type) == ASN1_ETYPE_CONSTANT)
++		{
++		  ADD_STR_VALUE (value, value_size, p->value);
++		  if (p->right)
++		    {
++		      ADD_STR_VALUE (value, value_size, ".");
++		    }
++		}
++	      p = p->right;
++	    }
++	  (*len)++;
++	}
++      else if ((node->type & CONST_DEFAULT) && (node->value == NULL))
++	{
++	  p = node->down;
++	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
++	    p = p->right;
++	  PUT_STR_VALUE (value, value_size, p->value);
++	}
++      else
++	{
++	  PUT_STR_VALUE (value, value_size, node->value);
++	}
++      break;
++    case ASN1_ETYPE_GENERALIZED_TIME:
++    case ASN1_ETYPE_UTC_TIME:
++      PUT_AS_STR_VALUE (value, value_size, node->value, node->value_len);
++      break;
++    case ASN1_ETYPE_OCTET_STRING:
++    case ASN1_ETYPE_GENERALSTRING:
++    case ASN1_ETYPE_NUMERIC_STRING:
++    case ASN1_ETYPE_IA5_STRING:
++    case ASN1_ETYPE_TELETEX_STRING:
++    case ASN1_ETYPE_PRINTABLE_STRING:
++    case ASN1_ETYPE_UNIVERSAL_STRING:
++    case ASN1_ETYPE_BMP_STRING:
++    case ASN1_ETYPE_UTF8_STRING:
++    case ASN1_ETYPE_VISIBLE_STRING:
++      len2 = -1;
++      result = asn1_get_octet_der
++	  (node->value, node->value_len, &len2, value, value_size,
++	   len);
++      if (result != ASN1_SUCCESS)
++	return result;
++      break;
++    case ASN1_ETYPE_BIT_STRING:
++      len2 = -1;
++      result = asn1_get_bit_der
++	  (node->value, node->value_len, &len2, value, value_size,
++	   len);
++      if (result != ASN1_SUCCESS)
++	return result;
++      break;
++    case ASN1_ETYPE_CHOICE:
++      PUT_STR_VALUE (value, value_size, node->down->name);
++      break;
++    case ASN1_ETYPE_ANY:
++      len3 = -1;
++      len2 = asn1_get_length_der (node->value, node->value_len, &len3);
++      if (len2 < 0)
++	return ASN1_DER_ERROR;
++      PUT_VALUE (value, value_size, node->value + len3, len2);
++      break;
++    default:
++      return ASN1_ELEMENT_NOT_FOUND;
++      break;
++    }
++  return ASN1_SUCCESS;
++}
++
++
++/**
++ * asn1_read_tag:
++ * @root: pointer to a structure
++ * @name: the name of the element inside a structure.
++ * @tagValue:  variable that will contain the TAG value.
++ * @classValue: variable that will specify the TAG type.
++ *
++ * Returns the TAG and the CLASS of one element inside a structure.
++ * CLASS can have one of these constants: %ASN1_CLASS_APPLICATION,
++ * %ASN1_CLASS_UNIVERSAL, %ASN1_CLASS_PRIVATE or
++ * %ASN1_CLASS_CONTEXT_SPECIFIC.
++ *
++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
++ *   @name is not a valid element.
++ **/
++int
++asn1_read_tag (asn1_node_const root, const char *name, int *tagValue,
++	       int *classValue)
++{
++  asn1_node node, p, pTag;
++
++  node = asn1_find_node (root, name);
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node->down;
++
++  /* pTag will points to the IMPLICIT TAG */
++  pTag = NULL;
++  if (node->type & CONST_TAG)
++    {
++      while (p)
++	{
++	  if (type_field (p->type) == ASN1_ETYPE_TAG)
++	    {
++	      if ((p->type & CONST_IMPLICIT) && (pTag == NULL))
++		pTag = p;
++	      else if (p->type & CONST_EXPLICIT)
++		pTag = NULL;
++	    }
++	  p = p->right;
++	}
++    }
++
++  if (pTag)
++    {
++      *tagValue = _asn1_strtoul (pTag->value, NULL, 10);
++
++      if (pTag->type & CONST_APPLICATION)
++	*classValue = ASN1_CLASS_APPLICATION;
++      else if (pTag->type & CONST_UNIVERSAL)
++	*classValue = ASN1_CLASS_UNIVERSAL;
++      else if (pTag->type & CONST_PRIVATE)
++	*classValue = ASN1_CLASS_PRIVATE;
++      else
++	*classValue = ASN1_CLASS_CONTEXT_SPECIFIC;
++    }
++  else
++    {
++      unsigned type = type_field (node->type);
++      *classValue = ASN1_CLASS_UNIVERSAL;
++
++      switch (type)
++	{
++	CASE_HANDLED_ETYPES:
++	  *tagValue = _asn1_tags[type].tag;
++	  break;
++	case ASN1_ETYPE_TAG:
++	case ASN1_ETYPE_CHOICE:
++	case ASN1_ETYPE_ANY:
++	  *tagValue = -1;
++	  break;
++	default:
++	  break;
++	}
++    }
++
++  return ASN1_SUCCESS;
++}
++
++/**
++ * asn1_read_node_value:
++ * @node: pointer to a node.
++ * @data: a point to a asn1_data_node_st
++ *
++ * Returns the value a data node inside a asn1_node structure.
++ * The data returned should be handled as constant values.
++ *
++ * Returns: %ASN1_SUCCESS if the node exists.
++ **/
++int
++asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data)
++{
++  data->name = node->name;
++  data->value = node->value;
++  data->value_len = node->value_len;
++  data->type = type_field (node->type);
++
++  return ASN1_SUCCESS;
++}
+diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c
+new file mode 100644
+index 0000000000..cee74daf79
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/errors.c
+@@ -0,0 +1,100 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++#include <int.h>
++#ifdef STDC_HEADERS
++#include <stdarg.h>
++#endif
++
++#define LIBTASN1_ERROR_ENTRY(name) { #name, name }
++
++struct libtasn1_error_entry
++{
++  const char *name;
++  int number;
++};
++typedef struct libtasn1_error_entry libtasn1_error_entry;
++
++static const libtasn1_error_entry error_algorithms[] = {
++  LIBTASN1_ERROR_ENTRY (ASN1_SUCCESS),
++  LIBTASN1_ERROR_ENTRY (ASN1_FILE_NOT_FOUND),
++  LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_FOUND),
++  LIBTASN1_ERROR_ENTRY (ASN1_IDENTIFIER_NOT_FOUND),
++  LIBTASN1_ERROR_ENTRY (ASN1_DER_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_FOUND),
++  LIBTASN1_ERROR_ENTRY (ASN1_GENERIC_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_VALID),
++  LIBTASN1_ERROR_ENTRY (ASN1_TAG_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_TAG_IMPLICIT),
++  LIBTASN1_ERROR_ENTRY (ASN1_ERROR_TYPE_ANY),
++  LIBTASN1_ERROR_ENTRY (ASN1_SYNTAX_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_MEM_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_MEM_ALLOC_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_DER_OVERFLOW),
++  LIBTASN1_ERROR_ENTRY (ASN1_NAME_TOO_LONG),
++  LIBTASN1_ERROR_ENTRY (ASN1_ARRAY_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_EMPTY),
++  LIBTASN1_ERROR_ENTRY (ASN1_TIME_ENCODING_ERROR),
++  LIBTASN1_ERROR_ENTRY (ASN1_RECURSION),
++  {0, 0}
++};
++
++/**
++ * asn1_perror:
++ * @error: is an error returned by a libtasn1 function.
++ *
++ * Prints a string to stderr with a description of an error.  This
++ * function is like perror().  The only difference is that it accepts
++ * an error returned by a libtasn1 function.
++ *
++ * Since: 1.6
++ **/
++void
++asn1_perror (int error)
++{
++  const char *str = asn1_strerror (error);
++  fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)");
++}
++
++/**
++ * asn1_strerror:
++ * @error: is an error returned by a libtasn1 function.
++ *
++ * Returns a string with a description of an error.  This function is
++ * similar to strerror.  The only difference is that it accepts an
++ * error (number) returned by a libtasn1 function.
++ *
++ * Returns: Pointer to static zero-terminated string describing error
++ *   code.
++ *
++ * Since: 1.6
++ **/
++const char *
++asn1_strerror (int error)
++{
++  const libtasn1_error_entry *p;
++
++  for (p = error_algorithms; p->name != NULL; p++)
++    if (p->number == error)
++      return p->name + sizeof ("ASN1_") - 1;
++
++  return NULL;
++}
+diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c
+new file mode 100644
+index 0000000000..e91a3a151c
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/gstr.c
+@@ -0,0 +1,74 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++#include <int.h>
++#include "gstr.h"
++
++/* These function are like strcat, strcpy. They only
++ * do bounds checking (they shouldn't cause buffer overruns),
++ * and they always produce null terminated strings.
++ *
++ * They should be used only with null terminated strings.
++ */
++void
++_asn1_str_cat (char *dest, size_t dest_tot_size, const char *src)
++{
++  size_t str_size = strlen (src);
++  size_t dest_size = strlen (dest);
++
++  if (dest_tot_size - dest_size > str_size)
++    {
++      strcat (dest, src);
++    }
++  else
++    {
++      if (dest_tot_size - dest_size > 0)
++	{
++	  strncat (dest, src, (dest_tot_size - dest_size) - 1);
++	  dest[dest_tot_size - 1] = 0;
++	}
++    }
++}
++
++/* Returns the bytes copied (not including the null terminator) */
++unsigned int
++_asn1_str_cpy (char *dest, size_t dest_tot_size, const char *src)
++{
++  size_t str_size = strlen (src);
++
++  if (dest_tot_size > str_size)
++    {
++      strcpy (dest, src);
++      return str_size;
++    }
++  else
++    {
++      if (dest_tot_size > 0)
++	{
++	  str_size = dest_tot_size - 1;
++	  memcpy (dest, src, str_size);
++	  dest[str_size] = 0;
++	  return str_size;
++	}
++      else
++	return 0;
++    }
++}
+diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c
+new file mode 100644
+index 0000000000..d5dbbf8765
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/parser_aux.c
+@@ -0,0 +1,1173 @@
++/*
++ * Copyright (C) 2000-2016 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++#include <limits.h> // WORD_BIT
++
++#include "int.h"
++#include "parser_aux.h"
++#include "gstr.h"
++#include "structure.h"
++#include "element.h"
++#include "c-ctype.h"
++
++char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1];	/* identifier name not found */
++
++/* Return a hash of the N bytes of X using the method described by
++   Bruno Haible in https://www.haible.de/bruno/hashfunc.html.
++   Note that while many hash functions reduce their result via modulo
++   to a 0..table_size-1 range, this function does not do that.
++
++   This implementation has been changed from size_t -> unsigned int. */
++
++#ifdef __clang__
++__attribute__((no_sanitize("integer")))
++#endif
++_GL_ATTRIBUTE_PURE
++static unsigned int
++_asn1_hash_name (const char *x)
++{
++  const unsigned char *s = (unsigned char *) x;
++  unsigned h = 0;
++
++  while (*s)
++    h = (*s++) + ((h << 9) | (h >> (WORD_BIT - 9)));
++
++  return h;
++}
++
++/******************************************************/
++/* Function : _asn1_add_static_node                   */
++/* Description: creates a new NODE_ASN element and    */
++/* puts it in the list pointed by e_list.       */
++/* Parameters:                                        */
++/*   e_list: of type list_type; must be NULL initially */
++/*   type: type of the new element (see ASN1_ETYPE_   */
++/*         and CONST_ constants).                     */
++/* Return: pointer to the new element.                */
++/******************************************************/
++asn1_node
++_asn1_add_static_node (list_type **e_list, unsigned int type)
++{
++  list_type *p;
++  asn1_node punt;
++
++  punt = calloc (1, sizeof (struct asn1_node_st));
++  if (punt == NULL)
++    return NULL;
++
++  p = malloc (sizeof (list_type));
++  if (p == NULL)
++    {
++      free (punt);
++      return NULL;
++    }
++
++  p->node = punt;
++  p->next = *e_list;
++  *e_list = p;
++
++  punt->type = type;
++
++  return punt;
++}
++
++static
++int _asn1_add_static_node2 (list_type **e_list, asn1_node node)
++{
++  list_type *p;
++
++  p = malloc (sizeof (list_type));
++  if (p == NULL)
++    {
++      return -1;
++    }
++
++  p->node = node;
++  p->next = *e_list;
++  *e_list = p;
++
++  return 0;
++}
++
++/**
++ * asn1_find_node:
++ * @pointer: NODE_ASN element pointer.
++ * @name: null terminated string with the element's name to find.
++ *
++ * Searches for an element called @name starting from @pointer.  The
++ * name is composed by different identifiers separated by dots.  When
++ * *@pointer has a name, the first identifier must be the name of
++ * *@pointer, otherwise it must be the name of one child of *@pointer.
++ *
++ * Returns: the search result, or %NULL if not found.
++ **/
++asn1_node
++asn1_find_node (asn1_node_const pointer, const char *name)
++{
++  asn1_node_const p;
++  char *n_end, n[ASN1_MAX_NAME_SIZE + 1];
++  const char *n_start;
++  unsigned int nsize;
++  unsigned int nhash;
++
++  if (pointer == NULL)
++    return NULL;
++
++  if (name == NULL)
++    return NULL;
++
++  p = pointer;
++  n_start = name;
++
++  if (name[0] == '?' && name[1] == 'C' && p->name[0] == '?')
++    { /* ?CURRENT */
++      n_start = strchr(n_start, '.');
++      if (n_start)
++        n_start++;
++    }
++  else if (p->name[0] != 0)
++    {				/* has *pointer got a name ? */
++      n_end = strchr (n_start, '.');	/* search the first dot */
++      if (n_end)
++	{
++	  nsize = n_end - n_start;
++	  if (nsize >= sizeof(n))
++		return NULL;
++
++	  memcpy (n, n_start, nsize);
++	  n[nsize] = 0;
++	  n_start = n_end;
++	  n_start++;
++
++	  nhash = _asn1_hash_name (n);
++	}
++      else
++	{
++	  _asn1_str_cpy (n, sizeof (n), n_start);
++	  nhash = _asn1_hash_name (n);
++
++	  n_start = NULL;
++	}
++
++      while (p)
++	{
++	  if (nhash == p->name_hash && (!strcmp (p->name, n)))
++	    break;
++	  else
++	    p = p->right;
++	}			/* while */
++
++      if (p == NULL)
++	return NULL;
++    }
++  else
++    {				/* *pointer doesn't have a name */
++      if (n_start[0] == 0)
++	return (asn1_node) p;
++    }
++
++  while (n_start)
++    {				/* Has the end of NAME been reached? */
++      n_end = strchr (n_start, '.');	/* search the next dot */
++      if (n_end)
++	{
++	  nsize = n_end - n_start;
++	  if (nsize >= sizeof(n))
++		return NULL;
++
++	  memcpy (n, n_start, nsize);
++	  n[nsize] = 0;
++	  n_start = n_end;
++	  n_start++;
++
++	  nhash = _asn1_hash_name (n);
++	}
++      else
++	{
++	  _asn1_str_cpy (n, sizeof (n), n_start);
++	  nhash = _asn1_hash_name (n);
++	  n_start = NULL;
++	}
++
++      if (p->down == NULL)
++	return NULL;
++
++      p = p->down;
++      if (p == NULL)
++        return NULL;
++
++      /* The identifier "?LAST" indicates the last element
++         in the right chain. */
++      if (n[0] == '?' && n[1] == 'L') /* ?LAST */
++	{
++	  while (p->right)
++	    p = p->right;
++	}
++      else
++	{			/* no "?LAST" */
++	  while (p)
++	    {
++	      if (p->name_hash == nhash && !strcmp (p->name, n))
++		break;
++	      else
++		p = p->right;
++	    }
++	}
++      if (p == NULL)
++        return NULL;
++    }				/* while */
++
++  return (asn1_node) p;
++}
++
++
++/******************************************************************/
++/* Function : _asn1_set_value                                     */
++/* Description: sets the field VALUE in a NODE_ASN element. The   */
++/*              previous value (if exist) will be lost            */
++/* Parameters:                                                    */
++/*   node: element pointer.                                       */
++/*   value: pointer to the value that you want to set.            */
++/*   len: character number of value.                              */
++/* Return: pointer to the NODE_ASN element.                       */
++/******************************************************************/
++asn1_node
++_asn1_set_value (asn1_node node, const void *value, unsigned int len)
++{
++  if (node == NULL)
++    return node;
++  if (node->value)
++    {
++      if (node->value != node->small_value)
++	free (node->value);
++      node->value = NULL;
++      node->value_len = 0;
++    }
++
++  if (!len)
++    return node;
++
++  if (len < sizeof (node->small_value))
++    {
++      node->value = node->small_value;
++    }
++  else
++    {
++      node->value = malloc (len);
++      if (node->value == NULL)
++	return NULL;
++    }
++  node->value_len = len;
++
++  memcpy (node->value, value, len);
++  return node;
++}
++
++/******************************************************************/
++/* Function : _asn1_set_value_lv                                  */
++/* Description: sets the field VALUE in a NODE_ASN element. The   */
++/*              previous value (if exist) will be lost. The value */
++/*		given is stored as an length-value format (LV     */
++/* Parameters:                                                    */
++/*   node: element pointer.                                       */
++/*   value: pointer to the value that you want to set.            */
++/*   len: character number of value.                              */
++/* Return: pointer to the NODE_ASN element.                       */
++/******************************************************************/
++asn1_node
++_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len)
++{
++  int len2;
++  void *temp;
++
++  if (node == NULL)
++    return node;
++
++  asn1_length_der (len, NULL, &len2);
++  temp = malloc (len + len2);
++  if (temp == NULL)
++    return NULL;
++
++  asn1_octet_der (value, len, temp, &len2);
++  return _asn1_set_value_m (node, temp, len2);
++}
++
++/* the same as _asn1_set_value except that it sets an already malloc'ed
++ * value.
++ */
++asn1_node
++_asn1_set_value_m (asn1_node node, void *value, unsigned int len)
++{
++  if (node == NULL)
++    return node;
++
++  if (node->value)
++    {
++      if (node->value != node->small_value)
++	free (node->value);
++      node->value = NULL;
++      node->value_len = 0;
++    }
++
++  if (!len)
++    return node;
++
++  node->value = value;
++  node->value_len = len;
++
++  return node;
++}
++
++/******************************************************************/
++/* Function : _asn1_append_value                                  */
++/* Description: appends to the field VALUE in a NODE_ASN element. */
++/*							          */
++/* Parameters:                                                    */
++/*   node: element pointer.                                       */
++/*   value: pointer to the value that you want to be appended.    */
++/*   len: character number of value.                              */
++/* Return: pointer to the NODE_ASN element.                       */
++/******************************************************************/
++asn1_node
++_asn1_append_value (asn1_node node, const void *value, unsigned int len)
++{
++  if (node == NULL)
++    return node;
++
++  if (node->value == NULL)
++    return _asn1_set_value (node, value, len);
++
++  if (len == 0)
++    return node;
++
++  if (node->value == node->small_value)
++    {
++      /* value is in node */
++      int prev_len = node->value_len;
++      node->value_len += len;
++      node->value = malloc (node->value_len);
++      if (node->value == NULL)
++	{
++	  node->value_len = 0;
++	  return NULL;
++	}
++
++      if (prev_len > 0)
++        memcpy (node->value, node->small_value, prev_len);
++
++      memcpy (&node->value[prev_len], value, len);
++
++      return node;
++    }
++  else /* if (node->value != NULL && node->value != node->small_value) */
++    {
++      /* value is allocated */
++      int prev_len = node->value_len;
++      node->value_len += len;
++
++      node->value = _asn1_realloc (node->value, node->value_len);
++      if (node->value == NULL)
++	{
++	  node->value_len = 0;
++	  return NULL;
++	}
++
++      memcpy (&node->value[prev_len], value, len);
++
++      return node;
++    }
++}
++
++/******************************************************************/
++/* Function : _asn1_set_name                                      */
++/* Description: sets the field NAME in a NODE_ASN element. The    */
++/*              previous value (if exist) will be lost            */
++/* Parameters:                                                    */
++/*   node: element pointer.                                       */
++/*   name: a null terminated string with the name that you want   */
++/*         to set.                                                */
++/* Return: pointer to the NODE_ASN element.                       */
++/******************************************************************/
++asn1_node
++_asn1_set_name (asn1_node node, const char *name)
++{
++  if (node == NULL)
++    return node;
++
++  _asn1_str_cpy (node->name, sizeof (node->name), name ? name : "");
++  node->name_hash = _asn1_hash_name (node->name);
++
++  return node;
++}
++
++/******************************************************************/
++/* Function : _asn1_cpy_name                                      */
++/* Description: copies the field NAME in a NODE_ASN element.      */
++/* Parameters:                                                    */
++/*   dst: a dest element pointer.                                 */
++/*   src: a source element pointer.                               */
++/* Return: pointer to the NODE_ASN element.                       */
++/******************************************************************/
++asn1_node
++_asn1_cpy_name (asn1_node dst, asn1_node_const src)
++{
++  if (dst == NULL)
++    return dst;
++
++  if (src == NULL)
++    {
++      dst->name[0] = 0;
++      dst->name_hash = _asn1_hash_name (dst->name);
++      return dst;
++    }
++
++  _asn1_str_cpy (dst->name, sizeof (dst->name), src->name);
++  dst->name_hash = src->name_hash;
++
++  return dst;
++}
++
++/******************************************************************/
++/* Function : _asn1_set_right                                     */
++/* Description: sets the field RIGHT in a NODE_ASN element.       */
++/* Parameters:                                                    */
++/*   node: element pointer.                                       */
++/*   right: pointer to a NODE_ASN element that you want be pointed*/
++/*          by NODE.                                              */
++/* Return: pointer to *NODE.                                      */
++/******************************************************************/
++asn1_node
++_asn1_set_right (asn1_node node, asn1_node right)
++{
++  if (node == NULL)
++    return node;
++  node->right = right;
++  if (right)
++    right->left = node;
++  return node;
++}
++
++
++/******************************************************************/
++/* Function : _asn1_get_last_right                                */
++/* Description: return the last element along the right chain.    */
++/* Parameters:                                                    */
++/*   node: starting element pointer.                              */
++/* Return: pointer to the last element along the right chain.     */
++/******************************************************************/
++asn1_node
++_asn1_get_last_right (asn1_node_const node)
++{
++  asn1_node_const p;
++
++  if (node == NULL)
++    return NULL;
++  p = node;
++  while (p->right)
++    p = p->right;
++  return (asn1_node) p;
++}
++
++/******************************************************************/
++/* Function : _asn1_remove_node                                   */
++/* Description: gets free the memory allocated for an NODE_ASN    */
++/*              element (not the elements pointed by it).         */
++/* Parameters:                                                    */
++/*   node: NODE_ASN element pointer.                              */
++/*   flags: ASN1_DELETE_FLAG_*                                    */
++/******************************************************************/
++void
++_asn1_remove_node (asn1_node node, unsigned int flags)
++{
++  if (node == NULL)
++    return;
++
++  if (node->value != NULL)
++    {
++      if (flags & ASN1_DELETE_FLAG_ZEROIZE)
++        {
++          safe_memset(node->value, 0, node->value_len);
++        }
++
++      if (node->value != node->small_value)
++        free (node->value);
++    }
++  free (node);
++}
++
++/******************************************************************/
++/* Function : _asn1_find_up                                       */
++/* Description: return the father of the NODE_ASN element.        */
++/* Parameters:                                                    */
++/*   node: NODE_ASN element pointer.                              */
++/* Return: Null if not found.                                     */
++/******************************************************************/
++asn1_node
++_asn1_find_up (asn1_node_const node)
++{
++  asn1_node_const p;
++
++  if (node == NULL)
++    return NULL;
++
++  p = node;
++
++  while ((p->left != NULL) && (p->left->right == p))
++    p = p->left;
++
++  return p->left;
++}
++
++static
++unsigned _asn1_is_up (asn1_node_const up_cand, asn1_node_const down)
++{
++  asn1_node_const d, u;
++
++  if (up_cand == NULL || down == NULL)
++    return 0;
++
++  d = down;
++
++  while ((u = _asn1_find_up(d)) != NULL && u != d)
++    {
++      if (u == up_cand)
++        return 1;
++      d = u;
++    }
++
++  return 0;
++}
++
++/******************************************************************/
++/* Function : _asn1_delete_node_from_list                         */
++/* Description: deletes the list element given                    */
++/******************************************************************/
++void
++_asn1_delete_node_from_list (list_type *list, asn1_node node)
++{
++  list_type *p = list;
++
++  while (p)
++    {
++      if (p->node == node)
++        p->node = NULL;
++      p = p->next;
++    }
++}
++
++/******************************************************************/
++/* Function : _asn1_delete_list                                   */
++/* Description: deletes the list elements (not the elements       */
++/*  pointed by them).                                             */
++/******************************************************************/
++void
++_asn1_delete_list (list_type *e_list)
++{
++  list_type *p;
++
++  while (e_list)
++    {
++      p = e_list;
++      e_list = e_list->next;
++      free (p);
++    }
++}
++
++/******************************************************************/
++/* Function : _asn1_delete_list_and nodes                         */
++/* Description: deletes the list elements and the elements        */
++/*  pointed by them.                                              */
++/******************************************************************/
++void
++_asn1_delete_list_and_nodes (list_type *e_list)
++{
++  list_type *p;
++
++  while (e_list)
++    {
++      p = e_list;
++      e_list = e_list->next;
++      _asn1_remove_node (p->node, 0);
++      free (p);
++    }
++}
++
++
++char *
++_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE])
++{
++  uint64_t d, r;
++  char temp[LTOSTR_MAX_SIZE];
++  int count, k, start;
++  uint64_t val;
++
++  if (v < 0)
++    {
++      str[0] = '-';
++      start = 1;
++      val = -((uint64_t)v);
++    }
++  else
++    {
++      val = v;
++      start = 0;
++    }
++
++  count = 0;
++  do
++    {
++      d = val / 10;
++      r = val - d * 10;
++      temp[start + count] = '0' + (char) r;
++      count++;
++      val = d;
++    }
++  while (val && ((start+count) < LTOSTR_MAX_SIZE-1));
++
++  for (k = 0; k < count; k++)
++    str[k + start] = temp[start + count - k - 1];
++  str[count + start] = 0;
++  return str;
++}
++
++
++/******************************************************************/
++/* Function : _asn1_change_integer_value                          */
++/* Description: converts into DER coding the value assign to an   */
++/*   INTEGER constant.                                            */
++/* Parameters:                                                    */
++/*   node: root of an ASN1element.                                */
++/* Return:                                                        */
++/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                       */
++/*   otherwise ASN1_SUCCESS                                             */
++/******************************************************************/
++int
++_asn1_change_integer_value (asn1_node node)
++{
++  asn1_node p;
++  unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
++  unsigned char val2[SIZEOF_UNSIGNED_LONG_INT + 1];
++  int len;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node;
++  while (p)
++    {
++      if ((type_field (p->type) == ASN1_ETYPE_INTEGER)
++	  && (p->type & CONST_ASSIGN))
++	{
++	  if (p->value)
++	    {
++	      _asn1_convert_integer (p->value, val, sizeof (val), &len);
++	      asn1_octet_der (val, len, val2, &len);
++	      _asn1_set_value (p, val2, len);
++	    }
++	}
++
++      if (p->down)
++	{
++	  p = p->down;
++	}
++      else
++	{
++	  if (p == node)
++	    p = NULL;
++	  else if (p->right)
++	    p = p->right;
++	  else
++	    {
++	      while (1)
++		{
++		  p = _asn1_find_up (p);
++		  if (p == node)
++		    {
++		      p = NULL;
++		      break;
++		    }
++		  if (p && p->right)
++		    {
++		      p = p->right;
++		      break;
++		    }
++		}
++	    }
++	}
++    }
++
++  return ASN1_SUCCESS;
++}
++
++#define MAX_CONSTANTS 1024
++/******************************************************************/
++/* Function : _asn1_expand_object_id                              */
++/* Description: expand the IDs of an OBJECT IDENTIFIER constant.  */
++/* Parameters:                                                    */
++/*   list: root of an object list                                 */
++/*   node: root of an ASN1 element.                               */
++/* Return:                                                        */
++/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                      */
++/*   otherwise ASN1_SUCCESS                                       */
++/******************************************************************/
++int
++_asn1_expand_object_id (list_type **list, asn1_node node)
++{
++  asn1_node p, p2, p3, p4, p5;
++  char name_root[ASN1_MAX_NAME_SIZE], name2[2 * ASN1_MAX_NAME_SIZE + 1];
++  int move, tlen, tries;
++  unsigned max_constants;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  _asn1_str_cpy (name_root, sizeof (name_root), node->name);
++
++  p = node;
++  move = DOWN;
++  tries = 0;
++
++  while (!((p == node) && (move == UP)))
++    {
++      if (move != UP)
++	{
++	  if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID)
++	      && (p->type & CONST_ASSIGN))
++	    {
++	      p2 = p->down;
++	      if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT))
++		{
++		  if (p2->value && !c_isdigit (p2->value[0]))
++		    {
++		      _asn1_str_cpy (name2, sizeof (name2), name_root);
++		      _asn1_str_cat (name2, sizeof (name2), ".");
++		      _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
++		      p3 = asn1_find_node (node, name2);
++		      if (!p3 || _asn1_is_up(p2, p3) ||
++			  (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ||
++			  !(p3->type & CONST_ASSIGN))
++			return ASN1_ELEMENT_NOT_FOUND;
++
++		      _asn1_set_down (p, p2->right);
++		      if (p2->down)
++			_asn1_delete_structure (*list, &p2->down, 0);
++		      _asn1_delete_node_from_list(*list, p2);
++		      _asn1_remove_node (p2, 0);
++		      p2 = p;
++		      p4 = p3->down;
++		      max_constants = 0;
++		      while (p4)
++			{
++			  if (type_field (p4->type) == ASN1_ETYPE_CONSTANT)
++			    {
++			      max_constants++;
++			      if (max_constants == MAX_CONSTANTS)
++                                return ASN1_RECURSION;
++
++			      p5 =
++				_asn1_add_single_node (ASN1_ETYPE_CONSTANT);
++			      _asn1_set_name (p5, p4->name);
++			      if (p4->value)
++			        {
++			          tlen = _asn1_strlen (p4->value);
++			          if (tlen > 0)
++			            _asn1_set_value (p5, p4->value, tlen + 1);
++			        }
++			      _asn1_add_static_node2(list, p5);
++
++			      if (p2 == p)
++				{
++				  _asn1_set_right (p5, p->down);
++				  _asn1_set_down (p, p5);
++				}
++			      else
++				{
++				  _asn1_set_right (p5, p2->right);
++				  _asn1_set_right (p2, p5);
++				}
++			      p2 = p5;
++			    }
++			  p4 = p4->right;
++			}
++		      move = DOWN;
++
++		      tries++;
++                      if (tries >= EXPAND_OBJECT_ID_MAX_RECURSION)
++                        return ASN1_RECURSION;
++
++		      continue;
++		    }
++		}
++	    }
++	  move = DOWN;
++	}
++      else
++	move = RIGHT;
++
++      tries = 0;
++      if (move == DOWN)
++	{
++	  if (p->down)
++	    p = p->down;
++	  else
++	    move = RIGHT;
++	}
++
++      if (p == node)
++	{
++	  move = UP;
++	  continue;
++	}
++
++      if (move == RIGHT)
++	{
++	  if (p && p->right)
++	    p = p->right;
++	  else
++	    move = UP;
++	}
++      if (move == UP)
++	p = _asn1_find_up (p);
++    }
++
++  /*******************************/
++  /*       expand DEFAULT        */
++  /*******************************/
++  p = node;
++  move = DOWN;
++
++  while (!((p == node) && (move == UP)))
++    {
++      if (move != UP)
++	{
++	  if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
++	      (p->type & CONST_DEFAULT))
++	    {
++	      p2 = p->down;
++	      if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT))
++		{
++		  _asn1_str_cpy (name2, sizeof (name2), name_root);
++		  _asn1_str_cat (name2, sizeof (name2), ".");
++		  if (p2->value)
++		    _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
++		  p3 = asn1_find_node (node, name2);
++		  if (!p3 || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID)
++		      || !(p3->type & CONST_ASSIGN))
++		    return ASN1_ELEMENT_NOT_FOUND;
++		  p4 = p3->down;
++		  name2[0] = 0;
++		  while (p4)
++		    {
++		      if (type_field (p4->type) == ASN1_ETYPE_CONSTANT)
++			{
++			  if (p4->value == NULL)
++			    return ASN1_VALUE_NOT_FOUND;
++
++			  if (name2[0])
++			    _asn1_str_cat (name2, sizeof (name2), ".");
++			  _asn1_str_cat (name2, sizeof (name2),
++					 (char *) p4->value);
++			}
++		      p4 = p4->right;
++		    }
++		  tlen = strlen (name2);
++		  if (tlen > 0)
++		    _asn1_set_value (p2, name2, tlen + 1);
++		}
++	    }
++	  move = DOWN;
++	}
++      else
++	move = RIGHT;
++
++      if (move == DOWN)
++	{
++	  if (p->down)
++	    p = p->down;
++	  else
++	    move = RIGHT;
++	}
++
++      if (p == node)
++	{
++	  move = UP;
++	  continue;
++	}
++
++      if (move == RIGHT)
++	{
++	  if (p && p->right)
++	    p = p->right;
++	  else
++	    move = UP;
++	}
++      if (move == UP)
++	p = _asn1_find_up (p);
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++/******************************************************************/
++/* Function : _asn1_type_set_config                               */
++/* Description: sets the CONST_SET and CONST_NOT_USED properties  */
++/*   in the fields of the SET elements.                           */
++/* Parameters:                                                    */
++/*   node: root of an ASN1 element.                               */
++/* Return:                                                        */
++/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                       */
++/*   otherwise ASN1_SUCCESS                                             */
++/******************************************************************/
++int
++_asn1_type_set_config (asn1_node node)
++{
++  asn1_node p, p2;
++  int move;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node;
++  move = DOWN;
++
++  while (!((p == node) && (move == UP)))
++    {
++      if (move != UP)
++	{
++	  if (type_field (p->type) == ASN1_ETYPE_SET)
++	    {
++	      p2 = p->down;
++	      while (p2)
++		{
++		  if (type_field (p2->type) != ASN1_ETYPE_TAG)
++		    p2->type |= CONST_SET | CONST_NOT_USED;
++		  p2 = p2->right;
++		}
++	    }
++	  move = DOWN;
++	}
++      else
++	move = RIGHT;
++
++      if (move == DOWN)
++	{
++	  if (p->down)
++	    p = p->down;
++	  else
++	    move = RIGHT;
++	}
++
++      if (p == node)
++	{
++	  move = UP;
++	  continue;
++	}
++
++      if (move == RIGHT)
++	{
++	  if (p && p->right)
++	    p = p->right;
++	  else
++	    move = UP;
++	}
++      if (move == UP)
++	p = _asn1_find_up (p);
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++/******************************************************************/
++/* Function : _asn1_check_identifier                              */
++/* Description: checks the definitions of all the identifiers     */
++/*   and the first element of an OBJECT_ID (e.g. {pkix 0 4}).     */
++/*   The _asn1_identifierMissing global variable is filled if     */
++/*   necessary.                                                   */
++/* Parameters:                                                    */
++/*   node: root of an ASN1 element.                               */
++/* Return:                                                        */
++/*   ASN1_ELEMENT_NOT_FOUND      if NODE is NULL,                 */
++/*   ASN1_IDENTIFIER_NOT_FOUND   if an identifier is not defined, */
++/*   otherwise ASN1_SUCCESS                                       */
++/******************************************************************/
++int
++_asn1_check_identifier (asn1_node_const node)
++{
++  asn1_node_const p, p2;
++  char name2[ASN1_MAX_NAME_SIZE * 2 + 2];
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node;
++  while (p)
++    {
++      if (p->value && type_field (p->type) == ASN1_ETYPE_IDENTIFIER)
++	{
++	  _asn1_str_cpy (name2, sizeof (name2), node->name);
++	  _asn1_str_cat (name2, sizeof (name2), ".");
++	  _asn1_str_cat (name2, sizeof (name2), (char *) p->value);
++	  p2 = asn1_find_node (node, name2);
++	  if (p2 == NULL)
++	    {
++	      if (p->value)
++		_asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p->value);
++	      else
++		_asn1_strcpy (_asn1_identifierMissing, "(null)");
++	      return ASN1_IDENTIFIER_NOT_FOUND;
++	    }
++	}
++      else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
++	       (p->type & CONST_DEFAULT))
++	{
++	  p2 = p->down;
++	  if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT))
++	    {
++	      _asn1_str_cpy (name2, sizeof (name2), node->name);
++	      if (p2->value)
++	        {
++	          _asn1_str_cat (name2, sizeof (name2), ".");
++	          _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
++	          _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value);
++	        }
++	      else
++		_asn1_strcpy (_asn1_identifierMissing, "(null)");
++
++	      p2 = asn1_find_node (node, name2);
++	      if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) ||
++		  !(p2->type & CONST_ASSIGN))
++		return ASN1_IDENTIFIER_NOT_FOUND;
++	      else
++		_asn1_identifierMissing[0] = 0;
++	    }
++	}
++      else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
++	       (p->type & CONST_ASSIGN))
++	{
++	  p2 = p->down;
++	  if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT))
++	    {
++	      if (p2->value && !c_isdigit (p2->value[0]))
++		{
++		  _asn1_str_cpy (name2, sizeof (name2), node->name);
++		  _asn1_str_cat (name2, sizeof (name2), ".");
++		  _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
++		  _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value);
++
++		  p2 = asn1_find_node (node, name2);
++		  if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID)
++		      || !(p2->type & CONST_ASSIGN))
++		    return ASN1_IDENTIFIER_NOT_FOUND;
++		  else
++		    _asn1_identifierMissing[0] = 0;
++		}
++	    }
++	}
++
++      if (p->down)
++	{
++	  p = p->down;
++	}
++      else if (p->right)
++	p = p->right;
++      else
++	{
++	  while (p)
++	    {
++	      p = _asn1_find_up (p);
++	      if (p == node)
++		{
++		  p = NULL;
++		  break;
++		}
++	      if (p && p->right)
++		{
++		  p = p->right;
++		  break;
++		}
++	    }
++	}
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++/******************************************************************/
++/* Function : _asn1_set_default_tag                               */
++/* Description: sets the default IMPLICIT or EXPLICIT property in */
++/*   the tagged elements that don't have this declaration.        */
++/* Parameters:                                                    */
++/*   node: pointer to a DEFINITIONS element.                      */
++/* Return:                                                        */
++/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to   */
++/*     a DEFINITIONS element,                                     */
++/*   otherwise ASN1_SUCCESS                                       */
++/******************************************************************/
++int
++_asn1_set_default_tag (asn1_node node)
++{
++  asn1_node p;
++
++  if ((node == NULL) || (type_field (node->type) != ASN1_ETYPE_DEFINITIONS))
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node;
++  while (p)
++    {
++      if ((type_field (p->type) == ASN1_ETYPE_TAG) &&
++	  !(p->type & CONST_EXPLICIT) && !(p->type & CONST_IMPLICIT))
++	{
++	  if (node->type & CONST_EXPLICIT)
++	    p->type |= CONST_EXPLICIT;
++	  else
++	    p->type |= CONST_IMPLICIT;
++	}
++
++      if (p->down)
++	{
++	  p = p->down;
++	}
++      else if (p->right)
++	p = p->right;
++      else
++	{
++	  while (1)
++	    {
++	      p = _asn1_find_up (p);
++	      if (p == node)
++		{
++		  p = NULL;
++		  break;
++		}
++	      if (p && p->right)
++		{
++		  p = p->right;
++		  break;
++		}
++	    }
++	}
++    }
++
++  return ASN1_SUCCESS;
++}
+diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c
+new file mode 100644
+index 0000000000..8189c56a4c
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/structure.c
+@@ -0,0 +1,1220 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++
++/*****************************************************/
++/* File: structure.c                                 */
++/* Description: Functions to create and delete an    */
++/*  ASN1 tree.                                       */
++/*****************************************************/
++
++
++#include <int.h>
++#include <structure.h>
++#include "parser_aux.h"
++#include <gstr.h>
++
++
++extern char _asn1_identifierMissing[];
++
++
++/******************************************************/
++/* Function : _asn1_add_single_node                     */
++/* Description: creates a new NODE_ASN element.       */
++/* Parameters:                                        */
++/*   type: type of the new element (see ASN1_ETYPE_         */
++/*         and CONST_ constants).                     */
++/* Return: pointer to the new element.                */
++/******************************************************/
++asn1_node
++_asn1_add_single_node (unsigned int type)
++{
++  asn1_node punt;
++
++  punt = calloc (1, sizeof (struct asn1_node_st));
++  if (punt == NULL)
++    return NULL;
++
++  punt->type = type;
++
++  return punt;
++}
++
++
++/******************************************************************/
++/* Function : _asn1_find_left                                     */
++/* Description: returns the NODE_ASN element with RIGHT field that*/
++/*              points the element NODE.                          */
++/* Parameters:                                                    */
++/*   node: NODE_ASN element pointer.                              */
++/* Return: NULL if not found.                                     */
++/******************************************************************/
++asn1_node
++_asn1_find_left (asn1_node_const node)
++{
++  if ((node == NULL) || (node->left == NULL) || (node->left->down == node))
++    return NULL;
++
++  return node->left;
++}
++
++
++int
++_asn1_create_static_structure (asn1_node_const pointer, char *output_file_name,
++			       char *vector_name)
++{
++  FILE *file;
++  asn1_node_const p;
++  unsigned long t;
++
++  file = fopen (output_file_name, "w");
++
++  if (file == NULL)
++    return ASN1_FILE_NOT_FOUND;
++
++  fprintf (file, "#if HAVE_CONFIG_H\n");
++  fprintf (file, "# include \"config.h\"\n");
++  fprintf (file, "#endif\n\n");
++
++  fprintf (file, "#include <libtasn1.h>\n\n");
++
++  fprintf (file, "const asn1_static_node %s[] = {\n", vector_name);
++
++  p = pointer;
++
++  while (p)
++    {
++      fprintf (file, "  { ");
++
++      if (p->name[0] != 0)
++	fprintf (file, "\"%s\", ", p->name);
++      else
++	fprintf (file, "NULL, ");
++
++      t = p->type;
++      if (p->down)
++	t |= CONST_DOWN;
++      if (p->right)
++	t |= CONST_RIGHT;
++
++      fprintf (file, "%lu, ", t);
++
++      if (p->value)
++	fprintf (file, "\"%s\"},\n", p->value);
++      else
++	fprintf (file, "NULL },\n");
++
++      if (p->down)
++	{
++	  p = p->down;
++	}
++      else if (p->right)
++	{
++	  p = p->right;
++	}
++      else
++	{
++	  while (1)
++	    {
++	      p = _asn1_find_up (p);
++	      if (p == pointer)
++		{
++		  p = NULL;
++		  break;
++		}
++	      if (p->right)
++		{
++		  p = p->right;
++		  break;
++		}
++	    }
++	}
++    }
++
++  fprintf (file, "  { NULL, 0, NULL }\n};\n");
++
++  fclose (file);
++
++  return ASN1_SUCCESS;
++}
++
++
++/**
++ * asn1_array2tree:
++ * @array: specify the array that contains ASN.1 declarations
++ * @definitions: return the pointer to the structure created by
++ *   *ARRAY ASN.1 declarations
++ * @errorDescription: return the error description.
++ *
++ * Creates the structures needed to manage the ASN.1 definitions.
++ * @array is a vector created by asn1_parser2array().
++ *
++ * Returns: %ASN1_SUCCESS if structure was created correctly,
++ *   %ASN1_ELEMENT_NOT_EMPTY if *@definitions not NULL,
++ *   %ASN1_IDENTIFIER_NOT_FOUND if in the file there is an identifier
++ *   that is not defined (see @errorDescription for more information),
++ *   %ASN1_ARRAY_ERROR if the array pointed by @array is wrong.
++ **/
++int
++asn1_array2tree (const asn1_static_node * array, asn1_node * definitions,
++		 char *errorDescription)
++{
++  asn1_node p, p_last = NULL;
++  unsigned long k;
++  int move;
++  int result;
++  unsigned int type;
++  list_type *e_list = NULL;
++
++  if (errorDescription)
++    errorDescription[0] = 0;
++
++  if (*definitions != NULL)
++    return ASN1_ELEMENT_NOT_EMPTY;
++
++  move = UP;
++
++  for (k = 0; array[k].value || array[k].type || array[k].name; k++)
++    {
++      type = convert_old_type (array[k].type);
++
++      p = _asn1_add_static_node (&e_list, type & (~CONST_DOWN));
++      if (array[k].name)
++	_asn1_set_name (p, array[k].name);
++      if (array[k].value)
++	_asn1_set_value (p, array[k].value, strlen (array[k].value) + 1);
++
++      if (*definitions == NULL)
++	*definitions = p;
++
++      if (move == DOWN)
++	{
++	  if (p_last && p_last->down)
++	      _asn1_delete_structure (e_list, &p_last->down, 0);
++	  _asn1_set_down (p_last, p);
++	}
++      else if (move == RIGHT)
++        {
++	  if (p_last && p_last->right)
++	      _asn1_delete_structure (e_list, &p_last->right, 0);
++	  _asn1_set_right (p_last, p);
++        }
++
++      p_last = p;
++
++      if (type & CONST_DOWN)
++	move = DOWN;
++      else if (type & CONST_RIGHT)
++	move = RIGHT;
++      else
++	{
++	  while (p_last != *definitions)
++	    {
++	      p_last = _asn1_find_up (p_last);
++
++	      if (p_last == NULL)
++		break;
++
++	      if (p_last->type & CONST_RIGHT)
++		{
++		  p_last->type &= ~CONST_RIGHT;
++		  move = RIGHT;
++		  break;
++		}
++	    }			/* while */
++	}
++    }				/* while */
++
++  if (p_last == *definitions)
++    {
++      result = _asn1_check_identifier (*definitions);
++      if (result == ASN1_SUCCESS)
++	{
++	  _asn1_change_integer_value (*definitions);
++	  result = _asn1_expand_object_id (&e_list, *definitions);
++	}
++    }
++  else
++    {
++      result = ASN1_ARRAY_ERROR;
++    }
++
++  if (errorDescription != NULL)
++    {
++      if (result == ASN1_IDENTIFIER_NOT_FOUND)
++	{
++	  Estrcpy (errorDescription, ":: identifier '");
++	  Estrcat (errorDescription, _asn1_identifierMissing);
++	  Estrcat (errorDescription, "' not found");
++	}
++      else
++	errorDescription[0] = 0;
++    }
++
++  if (result != ASN1_SUCCESS)
++    {
++      _asn1_delete_list_and_nodes (e_list);
++      *definitions = NULL;
++    }
++  else
++    _asn1_delete_list (e_list);
++
++  return result;
++}
++
++/**
++ * asn1_delete_structure:
++ * @structure: pointer to the structure that you want to delete.
++ *
++ * Deletes the structure *@structure.  At the end, *@structure is set
++ * to NULL.
++ *
++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
++ *   *@structure was NULL.
++ **/
++int
++asn1_delete_structure (asn1_node * structure)
++{
++  return _asn1_delete_structure (NULL, structure, 0);
++}
++
++/**
++ * asn1_delete_structure2:
++ * @structure: pointer to the structure that you want to delete.
++ * @flags: additional flags (see %ASN1_DELETE_FLAG)
++ *
++ * Deletes the structure *@structure.  At the end, *@structure is set
++ * to NULL.
++ *
++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
++ *   *@structure was NULL.
++ **/
++int
++asn1_delete_structure2 (asn1_node * structure, unsigned int flags)
++{
++  return _asn1_delete_structure (NULL, structure, flags);
++}
++
++int
++_asn1_delete_structure (list_type *e_list, asn1_node * structure, unsigned int flags)
++{
++  asn1_node p, p2, p3;
++
++  if (*structure == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = *structure;
++  while (p)
++    {
++      if (p->down)
++	{
++	  p = p->down;
++	}
++      else
++	{			/* no down */
++	  p2 = p->right;
++	  if (p != *structure)
++	    {
++	      p3 = _asn1_find_up (p);
++	      _asn1_set_down (p3, p2);
++	      if (e_list)
++		_asn1_delete_node_from_list (e_list, p);
++	      _asn1_remove_node (p, flags);
++	      p = p3;
++	    }
++	  else
++	    {			/* p==root */
++	      p3 = _asn1_find_left (p);
++	      if (!p3)
++		{
++		  p3 = _asn1_find_up (p);
++		  if (p3)
++		    _asn1_set_down (p3, p2);
++		  else
++		    {
++		      if (p->right)
++			p->right->left = NULL;
++		    }
++		}
++	      else
++		_asn1_set_right (p3, p2);
++	      if (e_list)
++		_asn1_delete_node_from_list (e_list, p);
++	      _asn1_remove_node (p, flags);
++	      p = NULL;
++	    }
++	}
++    }
++
++  *structure = NULL;
++  return ASN1_SUCCESS;
++}
++
++
++/**
++ * asn1_delete_element:
++ * @structure: pointer to the structure that contains the element you
++ *   want to delete.
++ * @element_name: element's name you want to delete.
++ *
++ * Deletes the element named *@element_name inside *@structure.
++ *
++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
++ *   the @element_name was not found.
++ **/
++int
++asn1_delete_element (asn1_node structure, const char *element_name)
++{
++  asn1_node p2, p3, source_node;
++
++  source_node = asn1_find_node (structure, element_name);
++
++  if (source_node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p2 = source_node->right;
++  p3 = _asn1_find_left (source_node);
++  if (!p3)
++    {
++      p3 = _asn1_find_up (source_node);
++      if (p3)
++	_asn1_set_down (p3, p2);
++      else if (source_node->right)
++	source_node->right->left = NULL;
++    }
++  else
++    _asn1_set_right (p3, p2);
++
++  return asn1_delete_structure (&source_node);
++}
++
++#ifndef __clang_analyzer__
++asn1_node
++_asn1_copy_structure3 (asn1_node_const source_node)
++{
++  asn1_node_const p_s;
++  asn1_node dest_node, p_d, p_d_prev;
++  int move;
++
++  if (source_node == NULL)
++    return NULL;
++
++  dest_node = _asn1_add_single_node (source_node->type);
++
++  p_s = source_node;
++  p_d = dest_node;
++
++  move = DOWN;
++
++  do
++    {
++      if (move != UP)
++	{
++	  if (p_s->name[0] != 0)
++	    _asn1_cpy_name (p_d, p_s);
++	  if (p_s->value)
++	    _asn1_set_value (p_d, p_s->value, p_s->value_len);
++	  if (p_s->down)
++	    {
++	      p_s = p_s->down;
++	      p_d_prev = p_d;
++	      p_d = _asn1_add_single_node (p_s->type);
++	      _asn1_set_down (p_d_prev, p_d);
++	      continue;
++	    }
++	  p_d->start = p_s->start;
++	  p_d->end = p_s->end;
++	}
++
++      if (p_s == source_node)
++	break;
++
++      if (p_s->right)
++	{
++	  move = RIGHT;
++	  p_s = p_s->right;
++	  p_d_prev = p_d;
++	  p_d = _asn1_add_single_node (p_s->type);
++	  _asn1_set_right (p_d_prev, p_d);
++	}
++      else
++	{
++	  move = UP;
++	  p_s = _asn1_find_up (p_s);
++	  p_d = _asn1_find_up (p_d);
++	}
++    }
++  while (p_s != source_node);
++  return dest_node;
++}
++#else
++
++/* Non-production code */
++asn1_node
++_asn1_copy_structure3 (asn1_node_const source_node)
++{
++  return NULL;
++}
++#endif /* __clang_analyzer__ */
++
++
++static asn1_node
++_asn1_copy_structure2 (asn1_node_const root, const char *source_name)
++{
++  asn1_node source_node;
++
++  source_node = asn1_find_node (root, source_name);
++
++  return _asn1_copy_structure3 (source_node);
++
++}
++
++
++static int
++_asn1_type_choice_config (asn1_node node)
++{
++  asn1_node p, p2, p3, p4;
++  int move, tlen;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node;
++  move = DOWN;
++
++  while (!((p == node) && (move == UP)))
++    {
++      if (move != UP)
++	{
++	  if ((type_field (p->type) == ASN1_ETYPE_CHOICE)
++	      && (p->type & CONST_TAG))
++	    {
++	      p2 = p->down;
++	      while (p2)
++		{
++		  if (type_field (p2->type) != ASN1_ETYPE_TAG)
++		    {
++		      p2->type |= CONST_TAG;
++		      p3 = _asn1_find_left (p2);
++		      while (p3)
++			{
++			  if (type_field (p3->type) == ASN1_ETYPE_TAG)
++			    {
++			      p4 = _asn1_add_single_node (p3->type);
++			      tlen = _asn1_strlen (p3->value);
++			      if (tlen > 0)
++				_asn1_set_value (p4, p3->value, tlen + 1);
++			      _asn1_set_right (p4, p2->down);
++			      _asn1_set_down (p2, p4);
++			    }
++			  p3 = _asn1_find_left (p3);
++			}
++		    }
++		  p2 = p2->right;
++		}
++	      p->type &= ~(CONST_TAG);
++	      p2 = p->down;
++	      while (p2)
++		{
++		  p3 = p2->right;
++		  if (type_field (p2->type) == ASN1_ETYPE_TAG)
++		    asn1_delete_structure (&p2);
++		  p2 = p3;
++		}
++	    }
++	  move = DOWN;
++	}
++      else
++	move = RIGHT;
++
++      if (move == DOWN)
++	{
++	  if (p->down)
++	    p = p->down;
++	  else
++	    move = RIGHT;
++	}
++
++      if (p == node)
++	{
++	  move = UP;
++	  continue;
++	}
++
++      if (move == RIGHT)
++	{
++	  if (p->right)
++	    p = p->right;
++	  else
++	    move = UP;
++	}
++      if (move == UP)
++	p = _asn1_find_up (p);
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++static int
++_asn1_expand_identifier (asn1_node * node, asn1_node_const root)
++{
++  asn1_node p, p2, p3;
++  char name2[ASN1_MAX_NAME_SIZE + 2];
++  int move;
++
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = *node;
++  move = DOWN;
++
++  while (!((p == *node) && (move == UP)))
++    {
++      if (move != UP)
++	{
++	  if (type_field (p->type) == ASN1_ETYPE_IDENTIFIER)
++	    {
++	      snprintf (name2, sizeof (name2), "%s.%s", root->name, p->value);
++	      p2 = _asn1_copy_structure2 (root, name2);
++	      if (p2 == NULL)
++		{
++		  return ASN1_IDENTIFIER_NOT_FOUND;
++		}
++	      _asn1_cpy_name (p2, p);
++	      p2->right = p->right;
++	      p2->left = p->left;
++	      if (p->right)
++		p->right->left = p2;
++	      p3 = p->down;
++	      if (p3)
++		{
++		  while (p3->right)
++		    p3 = p3->right;
++		  _asn1_set_right (p3, p2->down);
++		  _asn1_set_down (p2, p->down);
++		}
++
++	      p3 = _asn1_find_left (p);
++	      if (p3)
++		_asn1_set_right (p3, p2);
++	      else
++		{
++		  p3 = _asn1_find_up (p);
++		  if (p3)
++		    _asn1_set_down (p3, p2);
++		  else
++		    {
++		      p2->left = NULL;
++		    }
++		}
++
++	      if (p->type & CONST_SIZE)
++		p2->type |= CONST_SIZE;
++	      if (p->type & CONST_TAG)
++		p2->type |= CONST_TAG;
++	      if (p->type & CONST_OPTION)
++		p2->type |= CONST_OPTION;
++	      if (p->type & CONST_DEFAULT)
++		p2->type |= CONST_DEFAULT;
++	      if (p->type & CONST_SET)
++		p2->type |= CONST_SET;
++	      if (p->type & CONST_NOT_USED)
++		p2->type |= CONST_NOT_USED;
++
++	      if (p == *node)
++		*node = p2;
++	      _asn1_remove_node (p, 0);
++	      p = p2;
++	      move = DOWN;
++	      continue;
++	    }
++	  move = DOWN;
++	}
++      else
++	move = RIGHT;
++
++      if (move == DOWN)
++	{
++	  if (p->down)
++	    p = p->down;
++	  else
++	    move = RIGHT;
++	}
++
++      if (p == *node)
++	{
++	  move = UP;
++	  continue;
++	}
++
++      if (move == RIGHT)
++	{
++	  if (p->right)
++	    p = p->right;
++	  else
++	    move = UP;
++	}
++      if (move == UP)
++	p = _asn1_find_up (p);
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++/**
++ * asn1_create_element:
++ * @definitions: pointer to the structure returned by "parser_asn1" function
++ * @source_name: the name of the type of the new structure (must be
++ *   inside p_structure).
++ * @element: pointer to the structure created.
++ *
++ * Creates a structure of type @source_name.  Example using
++ *  "pkix.asn":
++ *
++ * rc = asn1_create_element(cert_def, "PKIX1.Certificate", certptr);
++ *
++ * Returns: %ASN1_SUCCESS if creation OK, %ASN1_ELEMENT_NOT_FOUND if
++ *   @source_name is not known.
++ **/
++int
++asn1_create_element (asn1_node_const definitions, const char *source_name,
++		     asn1_node * element)
++{
++  asn1_node dest_node;
++  int res;
++
++  dest_node = _asn1_copy_structure2 (definitions, source_name);
++
++  if (dest_node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  _asn1_set_name (dest_node, "");
++
++  res = _asn1_expand_identifier (&dest_node, definitions);
++  _asn1_type_choice_config (dest_node);
++
++  *element = dest_node;
++
++  return res;
++}
++
++
++/**
++ * asn1_print_structure:
++ * @out: pointer to the output file (e.g. stdout).
++ * @structure: pointer to the structure that you want to visit.
++ * @name: an element of the structure
++ * @mode: specify how much of the structure to print, can be
++ *   %ASN1_PRINT_NAME, %ASN1_PRINT_NAME_TYPE,
++ *   %ASN1_PRINT_NAME_TYPE_VALUE, or %ASN1_PRINT_ALL.
++ *
++ * Prints on the @out file descriptor the structure's tree starting
++ * from the @name element inside the structure @structure.
++ **/
++void
++asn1_print_structure (FILE * out, asn1_node_const structure, const char *name,
++		      int mode)
++{
++  asn1_node_const p, root;
++  int k, indent = 0, len, len2, len3;
++
++  if (out == NULL)
++    return;
++
++  root = asn1_find_node (structure, name);
++
++  if (root == NULL)
++    return;
++
++  p = root;
++  while (p)
++    {
++      if (mode == ASN1_PRINT_ALL)
++	{
++	  for (k = 0; k < indent; k++)
++	    fprintf (out, " ");
++	  fprintf (out, "name:");
++	  if (p->name[0] != 0)
++	    fprintf (out, "%s  ", p->name);
++	  else
++	    fprintf (out, "NULL  ");
++	}
++      else
++	{
++	  switch (type_field (p->type))
++	    {
++	    case ASN1_ETYPE_CONSTANT:
++	    case ASN1_ETYPE_TAG:
++	    case ASN1_ETYPE_SIZE:
++	      break;
++	    default:
++	      for (k = 0; k < indent; k++)
++		fprintf (out, " ");
++	      fprintf (out, "name:");
++	      if (p->name[0] != 0)
++		fprintf (out, "%s  ", p->name);
++	      else
++		fprintf (out, "NULL  ");
++	    }
++	}
++
++      if (mode != ASN1_PRINT_NAME)
++	{
++	  unsigned type = type_field (p->type);
++	  switch (type)
++	    {
++	    case ASN1_ETYPE_CONSTANT:
++	      if (mode == ASN1_PRINT_ALL)
++		fprintf (out, "type:CONST");
++	      break;
++	    case ASN1_ETYPE_TAG:
++	      if (mode == ASN1_PRINT_ALL)
++		fprintf (out, "type:TAG");
++	      break;
++	    case ASN1_ETYPE_SIZE:
++	      if (mode == ASN1_PRINT_ALL)
++		fprintf (out, "type:SIZE");
++	      break;
++	    case ASN1_ETYPE_DEFAULT:
++	      fprintf (out, "type:DEFAULT");
++	      break;
++	    case ASN1_ETYPE_IDENTIFIER:
++	      fprintf (out, "type:IDENTIFIER");
++	      break;
++	    case ASN1_ETYPE_ANY:
++	      fprintf (out, "type:ANY");
++	      break;
++	    case ASN1_ETYPE_CHOICE:
++	      fprintf (out, "type:CHOICE");
++	      break;
++	    case ASN1_ETYPE_DEFINITIONS:
++	      fprintf (out, "type:DEFINITIONS");
++	      break;
++	    CASE_HANDLED_ETYPES:
++	      fprintf (out, "%s", _asn1_tags[type].desc);
++	      break;
++	    default:
++	      break;
++	    }
++	}
++
++      if ((mode == ASN1_PRINT_NAME_TYPE_VALUE) || (mode == ASN1_PRINT_ALL))
++	{
++	  switch (type_field (p->type))
++	    {
++	    case ASN1_ETYPE_CONSTANT:
++	      if (mode == ASN1_PRINT_ALL)
++		if (p->value)
++		  fprintf (out, "  value:%s", p->value);
++	      break;
++	    case ASN1_ETYPE_TAG:
++	      if (mode == ASN1_PRINT_ALL)
++		if (p->value)
++		  fprintf (out, "  value:%s", p->value);
++	      break;
++	    case ASN1_ETYPE_SIZE:
++	      if (mode == ASN1_PRINT_ALL)
++		if (p->value)
++		  fprintf (out, "  value:%s", p->value);
++	      break;
++	    case ASN1_ETYPE_DEFAULT:
++	      if (p->value)
++		fprintf (out, "  value:%s", p->value);
++	      else if (p->type & CONST_TRUE)
++		fprintf (out, "  value:TRUE");
++	      else if (p->type & CONST_FALSE)
++		fprintf (out, "  value:FALSE");
++	      break;
++	    case ASN1_ETYPE_IDENTIFIER:
++	      if (p->value)
++		fprintf (out, "  value:%s", p->value);
++	      break;
++	    case ASN1_ETYPE_INTEGER:
++	      if (p->value)
++		{
++		  len2 = -1;
++		  len = asn1_get_length_der (p->value, p->value_len, &len2);
++		  fprintf (out, "  value:0x");
++		  if (len > 0)
++		    for (k = 0; k < len; k++)
++		      fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
++		}
++	      break;
++	    case ASN1_ETYPE_ENUMERATED:
++	      if (p->value)
++		{
++		  len2 = -1;
++		  len = asn1_get_length_der (p->value, p->value_len, &len2);
++		  fprintf (out, "  value:0x");
++		  if (len > 0)
++		    for (k = 0; k < len; k++)
++		      fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
++		}
++	      break;
++	    case ASN1_ETYPE_BOOLEAN:
++	      if (p->value)
++		{
++		  if (p->value[0] == 'T')
++		    fprintf (out, "  value:TRUE");
++		  else if (p->value[0] == 'F')
++		    fprintf (out, "  value:FALSE");
++		}
++	      break;
++	    case ASN1_ETYPE_BIT_STRING:
++	      if (p->value)
++		{
++		  len2 = -1;
++		  len = asn1_get_length_der (p->value, p->value_len, &len2);
++		  if (len > 0)
++		    {
++		      fprintf (out, "  value(%i):",
++			       (len - 1) * 8 - (p->value[len2]));
++		      for (k = 1; k < len; k++)
++			fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
++		    }
++		}
++	      break;
++	    case ASN1_ETYPE_GENERALIZED_TIME:
++	    case ASN1_ETYPE_UTC_TIME:
++	      if (p->value)
++		{
++		  fprintf (out, "  value:");
++		  for (k = 0; k < p->value_len; k++)
++		    fprintf (out, "%c", (p->value)[k]);
++		}
++	      break;
++	    case ASN1_ETYPE_GENERALSTRING:
++	    case ASN1_ETYPE_NUMERIC_STRING:
++	    case ASN1_ETYPE_IA5_STRING:
++	    case ASN1_ETYPE_TELETEX_STRING:
++	    case ASN1_ETYPE_PRINTABLE_STRING:
++	    case ASN1_ETYPE_UNIVERSAL_STRING:
++	    case ASN1_ETYPE_UTF8_STRING:
++	    case ASN1_ETYPE_VISIBLE_STRING:
++	      if (p->value)
++		{
++		  len2 = -1;
++		  len = asn1_get_length_der (p->value, p->value_len, &len2);
++		  fprintf (out, "  value:");
++		  if (len > 0)
++		    for (k = 0; k < len; k++)
++		      fprintf (out, "%c", (p->value)[k + len2]);
++		}
++	      break;
++	    case ASN1_ETYPE_BMP_STRING:
++	    case ASN1_ETYPE_OCTET_STRING:
++	      if (p->value)
++		{
++		  len2 = -1;
++		  len = asn1_get_length_der (p->value, p->value_len, &len2);
++		  fprintf (out, "  value:");
++		  if (len > 0)
++		    for (k = 0; k < len; k++)
++		      fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
++		}
++	      break;
++	    case ASN1_ETYPE_OBJECT_ID:
++	      if (p->value)
++		fprintf (out, "  value:%s", p->value);
++	      break;
++	    case ASN1_ETYPE_ANY:
++	      if (p->value)
++		{
++		  len3 = -1;
++		  len2 = asn1_get_length_der (p->value, p->value_len, &len3);
++		  fprintf (out, "  value:");
++		  if (len2 > 0)
++		    for (k = 0; k < len2; k++)
++		      fprintf (out, "%02x", (unsigned) (p->value)[k + len3]);
++		}
++	      break;
++	    case ASN1_ETYPE_SET:
++	    case ASN1_ETYPE_SET_OF:
++	    case ASN1_ETYPE_CHOICE:
++	    case ASN1_ETYPE_DEFINITIONS:
++	    case ASN1_ETYPE_SEQUENCE_OF:
++	    case ASN1_ETYPE_SEQUENCE:
++	    case ASN1_ETYPE_NULL:
++	      break;
++	    default:
++	      break;
++	    }
++	}
++
++      if (mode == ASN1_PRINT_ALL)
++	{
++	  if (p->type & 0x1FFFFF00)
++	    {
++	      fprintf (out, "  attr:");
++	      if (p->type & CONST_UNIVERSAL)
++		fprintf (out, "UNIVERSAL,");
++	      if (p->type & CONST_PRIVATE)
++		fprintf (out, "PRIVATE,");
++	      if (p->type & CONST_APPLICATION)
++		fprintf (out, "APPLICATION,");
++	      if (p->type & CONST_EXPLICIT)
++		fprintf (out, "EXPLICIT,");
++	      if (p->type & CONST_IMPLICIT)
++		fprintf (out, "IMPLICIT,");
++	      if (p->type & CONST_TAG)
++		fprintf (out, "TAG,");
++	      if (p->type & CONST_DEFAULT)
++		fprintf (out, "DEFAULT,");
++	      if (p->type & CONST_TRUE)
++		fprintf (out, "TRUE,");
++	      if (p->type & CONST_FALSE)
++		fprintf (out, "FALSE,");
++	      if (p->type & CONST_LIST)
++		fprintf (out, "LIST,");
++	      if (p->type & CONST_MIN_MAX)
++		fprintf (out, "MIN_MAX,");
++	      if (p->type & CONST_OPTION)
++		fprintf (out, "OPTION,");
++	      if (p->type & CONST_1_PARAM)
++		fprintf (out, "1_PARAM,");
++	      if (p->type & CONST_SIZE)
++		fprintf (out, "SIZE,");
++	      if (p->type & CONST_DEFINED_BY)
++		fprintf (out, "DEF_BY,");
++	      if (p->type & CONST_GENERALIZED)
++		fprintf (out, "GENERALIZED,");
++	      if (p->type & CONST_UTC)
++		fprintf (out, "UTC,");
++	      if (p->type & CONST_SET)
++		fprintf (out, "SET,");
++	      if (p->type & CONST_NOT_USED)
++		fprintf (out, "NOT_USED,");
++	      if (p->type & CONST_ASSIGN)
++		fprintf (out, "ASSIGNMENT,");
++	    }
++	}
++
++      if (mode == ASN1_PRINT_ALL)
++	{
++	  fprintf (out, "\n");
++	}
++      else
++	{
++	  switch (type_field (p->type))
++	    {
++	    case ASN1_ETYPE_CONSTANT:
++	    case ASN1_ETYPE_TAG:
++	    case ASN1_ETYPE_SIZE:
++	      break;
++	    default:
++	      fprintf (out, "\n");
++	    }
++	}
++
++      if (p->down)
++	{
++	  p = p->down;
++	  indent += 2;
++	}
++      else if (p == root)
++	{
++	  p = NULL;
++	  break;
++	}
++      else if (p->right)
++	p = p->right;
++      else
++	{
++	  while (1)
++	    {
++	      p = _asn1_find_up (p);
++	      if (p == root)
++		{
++		  p = NULL;
++		  break;
++		}
++	      indent -= 2;
++	      if (p->right)
++		{
++		  p = p->right;
++		  break;
++		}
++	    }
++	}
++    }
++}
++
++
++
++/**
++ * asn1_number_of_elements:
++ * @element: pointer to the root of an ASN1 structure.
++ * @name: the name of a sub-structure of ROOT.
++ * @num: pointer to an integer where the result will be stored
++ *
++ * Counts the number of elements of a sub-structure called NAME with
++ * names equal to "?1","?2", ...
++ *
++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
++ *   @name is not known, %ASN1_GENERIC_ERROR if pointer @num is %NULL.
++ **/
++int
++asn1_number_of_elements (asn1_node_const element, const char *name, int *num)
++{
++  asn1_node_const node, p;
++
++  if (num == NULL)
++    return ASN1_GENERIC_ERROR;
++
++  *num = 0;
++
++  node = asn1_find_node (element, name);
++  if (node == NULL)
++    return ASN1_ELEMENT_NOT_FOUND;
++
++  p = node->down;
++
++  while (p)
++    {
++      if (p->name[0] == '?')
++	(*num)++;
++      p = p->right;
++    }
++
++  return ASN1_SUCCESS;
++}
++
++
++/**
++ * asn1_find_structure_from_oid:
++ * @definitions: ASN1 definitions
++ * @oidValue: value of the OID to search (e.g. "1.2.3.4").
++ *
++ * Search the structure that is defined just after an OID definition.
++ *
++ * Returns: %NULL when @oidValue not found, otherwise the pointer to a
++ *   constant string that contains the element name defined just after
++ *   the OID.
++ **/
++const char *
++asn1_find_structure_from_oid (asn1_node_const definitions, const char *oidValue)
++{
++  char name[2 * ASN1_MAX_NAME_SIZE + 2];
++  char value[ASN1_MAX_NAME_SIZE];
++  asn1_node p;
++  int len;
++  int result;
++  const char *definitionsName;
++
++  if ((definitions == NULL) || (oidValue == NULL))
++    return NULL;		/* ASN1_ELEMENT_NOT_FOUND; */
++
++  definitionsName = definitions->name;
++
++  /* search the OBJECT_ID into definitions */
++  p = definitions->down;
++  while (p)
++    {
++      if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
++	  (p->type & CONST_ASSIGN))
++	{
++          snprintf(name, sizeof(name), "%s.%s", definitionsName, p->name);
++
++	  len = ASN1_MAX_NAME_SIZE;
++	  result = asn1_read_value (definitions, name, value, &len);
++
++	  if ((result == ASN1_SUCCESS) && (!strcmp (oidValue, value)))
++	    {
++	      p = p->right;
++	      if (p == NULL)	/* reach the end of ASN1 definitions */
++		return NULL;	/* ASN1_ELEMENT_NOT_FOUND; */
++
++	      return p->name;
++	    }
++	}
++      p = p->right;
++    }
++
++  return NULL;			/* ASN1_ELEMENT_NOT_FOUND; */
++}
++
++/**
++ * asn1_copy_node:
++ * @dst: Destination asn1 node.
++ * @dst_name: Field name in destination node.
++ * @src: Source asn1 node.
++ * @src_name: Field name in source node.
++ *
++ * Create a deep copy of a asn1_node variable. That
++ * function requires @dst to be expanded using asn1_create_element().
++ *
++ * Returns: Return %ASN1_SUCCESS on success.
++ **/
++int
++asn1_copy_node (asn1_node dst, const char *dst_name,
++		asn1_node_const src, const char *src_name)
++{
++  int result;
++  asn1_node dst_node;
++  void *data = NULL;
++  int size = 0;
++
++  result = asn1_der_coding (src, src_name, NULL, &size, NULL);
++  if (result != ASN1_MEM_ERROR)
++    return result;
++
++  data = malloc (size);
++  if (data == NULL)
++    return ASN1_MEM_ERROR;
++
++  result = asn1_der_coding (src, src_name, data, &size, NULL);
++  if (result != ASN1_SUCCESS)
++    {
++      free (data);
++      return result;
++    }
++
++  dst_node = asn1_find_node (dst, dst_name);
++  if (dst_node == NULL)
++    {
++      free (data);
++      return ASN1_ELEMENT_NOT_FOUND;
++    }
++
++  result = asn1_der_decoding (&dst_node, data, size, NULL);
++
++  free (data);
++
++  return result;
++}
++
++/**
++ * asn1_dup_node:
++ * @src: Source asn1 node.
++ * @src_name: Field name in source node.
++ *
++ * Create a deep copy of a asn1_node variable. This function
++ * will return an exact copy of the provided structure.
++ *
++ * Returns: Return %NULL on failure.
++ **/
++asn1_node
++asn1_dup_node (asn1_node_const src, const char *src_name)
++{
++  return _asn1_copy_structure2(src, src_name);
++}
+diff --git a/grub-core/lib/libtasn1/lib/element.h b/grub-core/lib/libtasn1/lib/element.h
+new file mode 100644
+index 0000000000..440a33f4bb
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/element.h
+@@ -0,0 +1,40 @@
++/*
++ * Copyright (C) 2000-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++#ifndef _ELEMENT_H
++#define _ELEMENT_H
++
++
++struct node_tail_cache_st
++{
++	asn1_node head; /* the first element of the sequence */
++	asn1_node tail;
++};
++
++int _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcached);
++
++int _asn1_convert_integer (const unsigned char *value,
++			   unsigned char *value_out,
++			   int value_out_size, int *len);
++
++void _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size);
++
++#endif
+diff --git a/grub-core/lib/libtasn1/lib/gstr.h b/grub-core/lib/libtasn1/lib/gstr.h
+new file mode 100644
+index 0000000000..48229844ff
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/gstr.h
+@@ -0,0 +1,47 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++#ifndef GSTR_H
++# define GSTR_H
++
++unsigned int _asn1_str_cpy (char *dest, size_t dest_tot_size,
++			    const char *src);
++void _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src);
++
++#define Estrcpy(x,y) _asn1_str_cpy(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y)
++#define Estrcat(x,y) _asn1_str_cat(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y)
++
++inline static
++void safe_memset(void *data, int c, size_t size)
++{
++	volatile unsigned volatile_zero = 0;
++	volatile char *vdata = (volatile char*)data;
++
++	/* This is based on a nice trick for safe memset,
++	 * sent by David Jacobson in the openssl-dev mailing list.
++	 */
++
++	if (size > 0) do {
++		memset(data, c, size);
++	} while(vdata[volatile_zero] != c);
++}
++
++#endif /* GSTR_H */
+diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h
+new file mode 100644
+index 0000000000..ea1625786c
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/int.h
+@@ -0,0 +1,221 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++#ifndef INT_H
++#define INT_H
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <string.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <stdint.h>
++
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#include <libtasn1.h>
++
++#define ASN1_SMALL_VALUE_SIZE 16
++
++/* This structure is also in libtasn1.h, but then contains less
++   fields.  You cannot make any modifications to these first fields
++   without breaking ABI.  */
++struct asn1_node_st
++{
++  /* public fields: */
++  char name[ASN1_MAX_NAME_SIZE + 1];	/* Node name */
++  unsigned int name_hash;
++  unsigned int type;		/* Node type */
++  unsigned char *value;		/* Node value */
++  int value_len;
++  asn1_node down;		/* Pointer to the son node */
++  asn1_node right;		/* Pointer to the brother node */
++  asn1_node left;		/* Pointer to the next list element */
++  /* private fields: */
++  unsigned char small_value[ASN1_SMALL_VALUE_SIZE];	/* For small values */
++
++  /* values used during decoding/coding */
++  int tmp_ival;
++  unsigned start; /* the start of the DER sequence - if decoded */
++  unsigned end; /* the end of the DER sequence - if decoded */
++};
++
++typedef struct tag_and_class_st
++{
++  unsigned tag;
++  unsigned class;
++  const char *desc;
++} tag_and_class_st;
++
++/* the types that are handled in _asn1_tags */
++#define CASE_HANDLED_ETYPES \
++	case ASN1_ETYPE_NULL: \
++	case ASN1_ETYPE_BOOLEAN: \
++	case ASN1_ETYPE_INTEGER: \
++	case ASN1_ETYPE_ENUMERATED: \
++	case ASN1_ETYPE_OBJECT_ID: \
++	case ASN1_ETYPE_OCTET_STRING: \
++	case ASN1_ETYPE_GENERALSTRING: \
++        case ASN1_ETYPE_NUMERIC_STRING: \
++        case ASN1_ETYPE_IA5_STRING: \
++        case ASN1_ETYPE_TELETEX_STRING: \
++        case ASN1_ETYPE_PRINTABLE_STRING: \
++        case ASN1_ETYPE_UNIVERSAL_STRING: \
++        case ASN1_ETYPE_BMP_STRING: \
++        case ASN1_ETYPE_UTF8_STRING: \
++        case ASN1_ETYPE_VISIBLE_STRING: \
++	case ASN1_ETYPE_BIT_STRING: \
++	case ASN1_ETYPE_SEQUENCE: \
++	case ASN1_ETYPE_SEQUENCE_OF: \
++	case ASN1_ETYPE_SET: \
++	case ASN1_ETYPE_UTC_TIME: \
++	case ASN1_ETYPE_GENERALIZED_TIME: \
++	case ASN1_ETYPE_SET_OF
++
++#define ETYPE_TAG(etype) (_asn1_tags[etype].tag)
++#define ETYPE_CLASS(etype) (_asn1_tags[etype].class)
++#define ETYPE_OK(etype) (((etype) != ASN1_ETYPE_INVALID && \
++                          (etype) <= _asn1_tags_size && \
++                          _asn1_tags[(etype)].desc != NULL)?1:0)
++
++#define ETYPE_IS_STRING(etype) ((etype == ASN1_ETYPE_GENERALSTRING || \
++	etype == ASN1_ETYPE_NUMERIC_STRING || etype == ASN1_ETYPE_IA5_STRING || \
++	etype == ASN1_ETYPE_TELETEX_STRING || etype == ASN1_ETYPE_PRINTABLE_STRING || \
++	etype == ASN1_ETYPE_UNIVERSAL_STRING || etype == ASN1_ETYPE_BMP_STRING || \
++	etype == ASN1_ETYPE_UTF8_STRING || etype == ASN1_ETYPE_VISIBLE_STRING || \
++	etype == ASN1_ETYPE_OCTET_STRING)?1:0)
++
++extern unsigned int _asn1_tags_size;
++extern const tag_and_class_st _asn1_tags[];
++
++#define _asn1_strlen(s) strlen((const char *) s)
++#define _asn1_strtol(n,e,b) strtol((const char *) n, e, b)
++#define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b)
++#define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b)
++#define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b)
++#define _asn1_strcat(a,b) strcat((char *)a, (const char *)b)
++
++#if SIZEOF_UNSIGNED_LONG_INT == 8
++# define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b)
++#else
++# define _asn1_strtou64(n,e,b) strtoull((const char *) n, e, b)
++#endif
++
++#define MAX_LOG_SIZE 1024	/* maximum number of characters of a log message */
++
++/* Define used for visiting trees. */
++#define UP     1
++#define RIGHT  2
++#define DOWN   3
++
++/***********************************************************************/
++/* List of constants to better specify the type of typedef asn1_node_st.   */
++/***********************************************************************/
++/*  Used with TYPE_TAG  */
++#define CONST_UNIVERSAL   (1U<<8)
++#define CONST_PRIVATE     (1U<<9)
++#define CONST_APPLICATION (1U<<10)
++#define CONST_EXPLICIT    (1U<<11)
++#define CONST_IMPLICIT    (1U<<12)
++
++#define CONST_TAG         (1U<<13)	/*  Used in ASN.1 assignement  */
++#define CONST_OPTION      (1U<<14)
++#define CONST_DEFAULT     (1U<<15)
++#define CONST_TRUE        (1U<<16)
++#define CONST_FALSE       (1U<<17)
++
++#define CONST_LIST        (1U<<18)	/*  Used with TYPE_INTEGER and TYPE_BIT_STRING  */
++#define CONST_MIN_MAX     (1U<<19)
++
++#define CONST_1_PARAM     (1U<<20)
++
++#define CONST_SIZE        (1U<<21)
++
++#define CONST_DEFINED_BY  (1U<<22)
++
++/* Those two are deprecated and used for backwards compatibility */
++#define CONST_GENERALIZED (1U<<23)
++#define CONST_UTC         (1U<<24)
++
++/* #define CONST_IMPORTS     (1U<<25) */
++
++#define CONST_NOT_USED    (1U<<26)
++#define CONST_SET         (1U<<27)
++#define CONST_ASSIGN      (1U<<28)
++
++#define CONST_DOWN        (1U<<29)
++#define CONST_RIGHT       (1U<<30)
++
++
++#define ASN1_ETYPE_TIME 17
++/****************************************/
++/* Returns the first 8 bits.            */
++/* Used with the field type of asn1_node_st */
++/****************************************/
++inline static unsigned int
++type_field (unsigned int ntype)
++{
++  return (ntype & 0xff);
++}
++
++/* To convert old types from a static structure */
++inline static unsigned int
++convert_old_type (unsigned int ntype)
++{
++  unsigned int type = ntype & 0xff;
++  if (type == ASN1_ETYPE_TIME)
++    {
++      if (ntype & CONST_UTC)
++	type = ASN1_ETYPE_UTC_TIME;
++      else
++	type = ASN1_ETYPE_GENERALIZED_TIME;
++
++      ntype &= ~(CONST_UTC | CONST_GENERALIZED);
++      ntype &= 0xffffff00;
++      ntype |= type;
++
++      return ntype;
++    }
++  else
++    return ntype;
++}
++
++static inline
++void *_asn1_realloc(void *ptr, size_t size)
++{
++  void *ret;
++
++  if (size == 0)
++    return ptr;
++
++  ret = realloc(ptr, size);
++  if (ret == NULL)
++    {
++      free(ptr);
++    }
++  return ret;
++}
++
++#endif /* INT_H */
+diff --git a/grub-core/lib/libtasn1/lib/parser_aux.h b/grub-core/lib/libtasn1/lib/parser_aux.h
+new file mode 100644
+index 0000000000..598e684b35
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/parser_aux.h
+@@ -0,0 +1,172 @@
++/*
++ * Copyright (C) 2000-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++#ifndef _PARSER_AUX_H
++#define _PARSER_AUX_H
++
++/***********************************************/
++/* Type: list_type                             */
++/* Description: type used in the list during   */
++/* the structure creation.                     */
++/***********************************************/
++typedef struct list_struct
++{
++  asn1_node node;
++  struct list_struct *next;
++} list_type;
++
++/***************************************/
++/*  Functions used by ASN.1 parser     */
++/***************************************/
++asn1_node _asn1_add_static_node (list_type **e_list, unsigned int type);
++
++void _asn1_delete_list (list_type *e_list);
++
++void _asn1_delete_list_and_nodes (list_type *e_list);
++
++void _asn1_delete_node_from_list (list_type *list, asn1_node node);
++
++asn1_node
++_asn1_set_value (asn1_node node, const void *value, unsigned int len);
++
++asn1_node _asn1_set_value_m (asn1_node node, void *value, unsigned int len);
++
++asn1_node
++_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len);
++
++asn1_node
++_asn1_append_value (asn1_node node, const void *value, unsigned int len);
++
++asn1_node _asn1_set_name (asn1_node node, const char *name);
++
++asn1_node _asn1_cpy_name (asn1_node dst, asn1_node_const src);
++
++asn1_node _asn1_set_right (asn1_node node, asn1_node right);
++
++asn1_node _asn1_get_last_right (asn1_node_const node);
++
++void _asn1_remove_node (asn1_node node, unsigned int flags);
++
++/* Max 64-bit integer length is 20 chars + 1 for sign + 1 for null termination */
++#define LTOSTR_MAX_SIZE 22
++char *_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]);
++
++asn1_node _asn1_find_up (asn1_node_const node);
++
++int _asn1_change_integer_value (asn1_node node);
++
++#define EXPAND_OBJECT_ID_MAX_RECURSION 16
++int _asn1_expand_object_id (list_type **list, asn1_node node);
++
++int _asn1_type_set_config (asn1_node node);
++
++int _asn1_check_identifier (asn1_node_const node);
++
++int _asn1_set_default_tag (asn1_node node);
++
++/******************************************************************/
++/* Function : _asn1_get_right                                     */
++/* Description: returns the element pointed by the RIGHT field of */
++/*              a NODE_ASN element.                               */
++/* Parameters:                                                    */
++/*   node: NODE_ASN element pointer.                              */
++/* Return: field RIGHT of NODE.                                   */
++/******************************************************************/
++inline static asn1_node
++_asn1_get_right (asn1_node_const node)
++{
++  if (node == NULL)
++    return NULL;
++  return node->right;
++}
++
++/******************************************************************/
++/* Function : _asn1_set_down                                      */
++/* Description: sets the field DOWN in a NODE_ASN element.        */
++/* Parameters:                                                    */
++/*   node: element pointer.                                       */
++/*   down: pointer to a NODE_ASN element that you want be pointed */
++/*          by NODE.                                              */
++/* Return: pointer to *NODE.                                      */
++/******************************************************************/
++inline static asn1_node
++_asn1_set_down (asn1_node node, asn1_node down)
++{
++  if (node == NULL)
++    return node;
++  node->down = down;
++  if (down)
++    down->left = node;
++  return node;
++}
++
++/******************************************************************/
++/* Function : _asn1_get_down                                      */
++/* Description: returns the element pointed by the DOWN field of  */
++/*              a NODE_ASN element.                               */
++/* Parameters:                                                    */
++/*   node: NODE_ASN element pointer.                              */
++/* Return: field DOWN of NODE.                                    */
++/******************************************************************/
++inline static asn1_node
++_asn1_get_down (asn1_node_const node)
++{
++  if (node == NULL)
++    return NULL;
++  return node->down;
++}
++
++/******************************************************************/
++/* Function : _asn1_get_name                                      */
++/* Description: returns the name of a NODE_ASN element.           */
++/* Parameters:                                                    */
++/*   node: NODE_ASN element pointer.                              */
++/* Return: a null terminated string.                              */
++/******************************************************************/
++inline static char *
++_asn1_get_name (asn1_node_const node)
++{
++  if (node == NULL)
++    return NULL;
++  return (char *) node->name;
++}
++
++/******************************************************************/
++/* Function : _asn1_mod_type                                      */
++/* Description: change the field TYPE of an NODE_ASN element.     */
++/*              The new value is the old one | (bitwise or) the   */
++/*              paramener VALUE.                                  */
++/* Parameters:                                                    */
++/*   node: NODE_ASN element pointer.                              */
++/*   value: the integer value that must be or-ed with the current */
++/*          value of field TYPE.                                  */
++/* Return: NODE pointer.                                          */
++/******************************************************************/
++inline static asn1_node
++_asn1_mod_type (asn1_node node, unsigned int value)
++{
++  if (node == NULL)
++    return node;
++  node->type |= value;
++  return node;
++}
++
++#endif
+diff --git a/grub-core/lib/libtasn1/lib/structure.h b/grub-core/lib/libtasn1/lib/structure.h
+new file mode 100644
+index 0000000000..99e685da07
+--- /dev/null
++++ b/grub-core/lib/libtasn1/lib/structure.h
+@@ -0,0 +1,45 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * The LIBTASN1 library is free software; you can redistribute it
++ * and/or modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++/*************************************************/
++/* File: structure.h                             */
++/* Description: list of exported object by       */
++/*   "structure.c"                               */
++/*************************************************/
++
++#ifndef _STRUCTURE_H
++#define _STRUCTURE_H
++
++#include "parser_aux.h" // list_type
++
++int _asn1_create_static_structure (asn1_node_const pointer,
++				   char *output_file_name, char *vector_name);
++
++asn1_node _asn1_copy_structure3 (asn1_node_const source_node);
++
++asn1_node _asn1_add_single_node (unsigned int type);
++
++asn1_node _asn1_find_left (asn1_node_const node);
++
++int
++_asn1_delete_structure (list_type *e_list, asn1_node *structure, unsigned int flags);
++
++#endif
+diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h
+new file mode 100644
+index 0000000000..6fd7a30dc3
+--- /dev/null
++++ b/include/grub/libtasn1.h
+@@ -0,0 +1,588 @@
++/*
++ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * LIBTASN1 is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * LIBTASN1 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with LIBTASN1; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ *
++ */
++
++/**
++ * libtasn1:Short_Description:
++ *
++ * GNU ASN.1 library
++ */
++/**
++ * libtasn1:Long_Description:
++ *
++ * The Libtasn1 library provides Abstract Syntax Notation One (ASN.1, as
++ * specified by the X.680 ITU-T recommendation) parsing and structures
++ * management, and Distinguished Encoding Rules (DER, as per X.690)
++ * encoding and decoding functions.
++ */
++
++
++#ifndef LIBTASN1_H
++#define LIBTASN1_H
++
++#ifndef ASN1_API
++#if defined ASN1_BUILDING && defined HAVE_VISIBILITY && HAVE_VISIBILITY
++#define ASN1_API __attribute__((__visibility__("default")))
++#elif defined ASN1_BUILDING && defined _MSC_VER && ! defined ASN1_STATIC
++#define ASN1_API __declspec(dllexport)
++#elif defined _MSC_VER && ! defined ASN1_STATIC
++#define ASN1_API __declspec(dllimport)
++#else
++#define ASN1_API
++#endif
++#endif
++
++#ifdef __GNUC__
++# define __LIBTASN1_CONST__  __attribute__((const))
++# define __LIBTASN1_PURE__  __attribute__((pure))
++#else
++# define __LIBTASN1_CONST__
++# define __LIBTASN1_PURE__
++#endif
++
++#include <sys/types.h>
++#include <time.h>
++#include <stdio.h>		/* for FILE* */
++
++#ifdef __cplusplus
++extern "C"
++{
++#endif
++
++/**
++ * ASN1_VERSION:
++ *
++ * Version of the library as a string.
++ */
++#define ASN1_VERSION "4.16.0"
++
++/**
++ * ASN1_VERSION_MAJOR:
++ *
++ * Major version number of the library.
++ */
++#define ASN1_VERSION_MAJOR 4
++
++/**
++ * ASN1_VERSION_MINOR:
++ *
++ * Minor version number of the library.
++ */
++#define ASN1_VERSION_MINOR 16
++
++/**
++ * ASN1_VERSION_PATCH:
++ *
++ * Patch version number of the library.
++ */
++#define ASN1_VERSION_PATCH 0
++
++/**
++ * ASN1_VERSION_NUMBER:
++ *
++ * Version number of the library as a number.
++ */
++#define ASN1_VERSION_NUMBER 0x041000
++
++
++#if defined __GNUC__ && !defined ASN1_INTERNAL_BUILD
++# define _ASN1_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
++# if _ASN1_GCC_VERSION >= 30100
++#  define _ASN1_GCC_ATTR_DEPRECATED __attribute__ ((__deprecated__))
++# endif
++#endif
++
++#ifndef _ASN1_GCC_ATTR_DEPRECATED
++#define _ASN1_GCC_ATTR_DEPRECATED
++#endif
++
++/*****************************************/
++/* Errors returned by libtasn1 functions */
++/*****************************************/
++#define ASN1_SUCCESS			0
++#define ASN1_FILE_NOT_FOUND		1
++#define ASN1_ELEMENT_NOT_FOUND		2
++#define ASN1_IDENTIFIER_NOT_FOUND	3
++#define ASN1_DER_ERROR			4
++#define ASN1_VALUE_NOT_FOUND		5
++#define ASN1_GENERIC_ERROR		6
++#define ASN1_VALUE_NOT_VALID		7
++#define ASN1_TAG_ERROR			8
++#define ASN1_TAG_IMPLICIT		9
++#define ASN1_ERROR_TYPE_ANY		10
++#define ASN1_SYNTAX_ERROR		11
++#define ASN1_MEM_ERROR			12
++#define ASN1_MEM_ALLOC_ERROR		13
++#define ASN1_DER_OVERFLOW		14
++#define ASN1_NAME_TOO_LONG		15
++#define ASN1_ARRAY_ERROR		16
++#define ASN1_ELEMENT_NOT_EMPTY		17
++#define ASN1_TIME_ENCODING_ERROR	18
++#define ASN1_RECURSION			19
++
++/*************************************/
++/* Constants used in asn1_visit_tree */
++/*************************************/
++#define ASN1_PRINT_NAME			1
++#define ASN1_PRINT_NAME_TYPE		2
++#define ASN1_PRINT_NAME_TYPE_VALUE	3
++#define ASN1_PRINT_ALL			4
++
++/*****************************************/
++/* Constants returned by asn1_read_tag   */
++/*****************************************/
++#define ASN1_CLASS_UNIVERSAL		0x00	/* old: 1 */
++#define ASN1_CLASS_APPLICATION		0x40	/* old: 2 */
++#define ASN1_CLASS_CONTEXT_SPECIFIC	0x80	/* old: 3 */
++#define ASN1_CLASS_PRIVATE		0xC0	/* old: 4 */
++#define ASN1_CLASS_STRUCTURED		0x20
++
++/*****************************************/
++/* Constants returned by asn1_read_tag   */
++/*****************************************/
++#define ASN1_TAG_BOOLEAN		0x01
++#define ASN1_TAG_INTEGER		0x02
++#define ASN1_TAG_SEQUENCE		0x10
++#define ASN1_TAG_SET			0x11
++#define ASN1_TAG_OCTET_STRING		0x04
++#define ASN1_TAG_BIT_STRING		0x03
++#define ASN1_TAG_UTCTime		0x17
++#define ASN1_TAG_GENERALIZEDTime	0x18
++#define ASN1_TAG_OBJECT_ID		0x06
++#define ASN1_TAG_ENUMERATED		0x0A
++#define ASN1_TAG_NULL			0x05
++#define ASN1_TAG_GENERALSTRING		0x1B
++#define ASN1_TAG_NUMERIC_STRING		0x12
++#define ASN1_TAG_IA5_STRING		0x16
++#define ASN1_TAG_TELETEX_STRING		0x14
++#define ASN1_TAG_PRINTABLE_STRING	0x13
++#define ASN1_TAG_UNIVERSAL_STRING	0x1C
++#define ASN1_TAG_BMP_STRING		0x1E
++#define ASN1_TAG_UTF8_STRING		0x0C
++#define ASN1_TAG_VISIBLE_STRING		0x1A
++
++/**
++ * asn1_node:
++ *
++ * Structure definition used for the node of the tree
++ * that represents an ASN.1 DEFINITION.
++ */
++typedef struct asn1_node_st asn1_node_st;
++
++typedef asn1_node_st *asn1_node;
++typedef const asn1_node_st *asn1_node_const;
++
++/**
++ * ASN1_MAX_NAME_SIZE:
++ *
++ * Maximum number of characters of a name
++ * inside a file with ASN1 definitions.
++ */
++#define ASN1_MAX_NAME_SIZE 64
++
++
++/**
++ * asn1_static_node:
++ * @name: Node name
++ * @type: Node typ
++ * @value: Node value
++ *
++ * For the on-disk format of ASN.1 trees, created by asn1_parser2array().
++ */
++struct asn1_static_node_st
++{
++  const char *name;		/* Node name */
++  unsigned int type;		/* Node type */
++  const void *value;		/* Node value */
++};
++typedef struct asn1_static_node_st asn1_static_node;
++
++/* List of constants for field type of node_asn  */
++#define ASN1_ETYPE_INVALID        0
++#define ASN1_ETYPE_CONSTANT       1
++#define ASN1_ETYPE_IDENTIFIER     2
++#define ASN1_ETYPE_INTEGER        3
++#define ASN1_ETYPE_BOOLEAN        4
++#define ASN1_ETYPE_SEQUENCE       5
++#define ASN1_ETYPE_BIT_STRING     6
++#define ASN1_ETYPE_OCTET_STRING   7
++#define ASN1_ETYPE_TAG            8
++#define ASN1_ETYPE_DEFAULT        9
++#define ASN1_ETYPE_SIZE          10
++#define ASN1_ETYPE_SEQUENCE_OF   11
++#define ASN1_ETYPE_OBJECT_ID     12
++#define ASN1_ETYPE_ANY           13
++#define ASN1_ETYPE_SET           14
++#define ASN1_ETYPE_SET_OF        15
++#define ASN1_ETYPE_DEFINITIONS   16
++#define ASN1_ETYPE_CHOICE        18
++#define ASN1_ETYPE_IMPORTS       19
++#define ASN1_ETYPE_NULL          20
++#define ASN1_ETYPE_ENUMERATED    21
++#define ASN1_ETYPE_GENERALSTRING 27
++#define ASN1_ETYPE_NUMERIC_STRING 28
++#define ASN1_ETYPE_IA5_STRING     29
++#define ASN1_ETYPE_TELETEX_STRING 30
++#define ASN1_ETYPE_PRINTABLE_STRING 31
++#define ASN1_ETYPE_UNIVERSAL_STRING 32
++#define ASN1_ETYPE_BMP_STRING     33
++#define ASN1_ETYPE_UTF8_STRING    34
++#define ASN1_ETYPE_VISIBLE_STRING 35
++#define ASN1_ETYPE_UTC_TIME       36
++#define ASN1_ETYPE_GENERALIZED_TIME 37
++
++/**
++ * ASN1_DELETE_FLAG_ZEROIZE:
++ *
++ * Used by: asn1_delete_structure2()
++ *
++ * Zeroize values prior to deinitialization.
++ */
++#define ASN1_DELETE_FLAG_ZEROIZE 1
++
++/**
++ * ASN1_DECODE_FLAG_ALLOW_PADDING:
++ *
++ * Used by: asn1_der_decoding2()
++ *
++ * This flag would allow arbitrary data past the DER data.
++ */
++#define ASN1_DECODE_FLAG_ALLOW_PADDING 1
++/**
++ * ASN1_DECODE_FLAG_STRICT_DER:
++ *
++ * Used by: asn1_der_decoding2()
++ *
++ * This flag would ensure that no BER decoding takes place.
++ */
++#define ASN1_DECODE_FLAG_STRICT_DER (1<<1)
++/**
++ * ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME:
++ *
++ * Used by: asn1_der_decoding2()
++ *
++ * This flag will tolerate Time encoding errors when in strict DER.
++ */
++#define ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME (1<<2)
++
++
++/**
++ * asn1_data_node_st:
++ * @name: Node name
++ * @value: Node value
++ * @value_len: Node value size
++ * @type: Node value type (ASN1_ETYPE_*)
++ *
++ * Data node inside a #asn1_node structure.
++ */
++struct asn1_data_node_st
++{
++  const char *name;		/* Node name */
++  const void *value;		/* Node value */
++  unsigned int value_len;	/* Node value size */
++  unsigned int type;		/* Node value type (ASN1_ETYPE_*) */
++};
++typedef struct asn1_data_node_st asn1_data_node_st;
++
++/***********************************/
++/*  Fixed constants                */
++/***********************************/
++
++/**
++ * ASN1_MAX_ERROR_DESCRIPTION_SIZE:
++ *
++ * Maximum number of characters
++ * of a description message
++ * (null character included).
++ */
++#define ASN1_MAX_ERROR_DESCRIPTION_SIZE 128
++
++/***********************************/
++/*  Functions definitions          */
++/***********************************/
++
++extern ASN1_API int
++  asn1_parser2tree (const char *file,
++		      asn1_node * definitions, char *error_desc);
++
++extern ASN1_API int
++  asn1_parser2array (const char *inputFileName,
++		       const char *outputFileName,
++		       const char *vectorName, char *error_desc);
++
++extern ASN1_API int
++  asn1_array2tree (const asn1_static_node * array,
++		     asn1_node * definitions, char *errorDescription);
++
++extern ASN1_API void
++  asn1_print_structure (FILE * out, asn1_node_const structure,
++			  const char *name, int mode);
++
++extern ASN1_API int
++  asn1_create_element (asn1_node_const definitions,
++			 const char *source_name, asn1_node * element);
++
++extern ASN1_API int asn1_delete_structure (asn1_node * structure);
++
++extern ASN1_API int asn1_delete_structure2 (asn1_node * structure, unsigned int flags);
++
++extern ASN1_API int
++  asn1_delete_element (asn1_node structure, const char *element_name);
++
++extern ASN1_API int
++  asn1_write_value (asn1_node node_root, const char *name,
++		      const void *ivalue, int len);
++
++extern ASN1_API int
++  asn1_read_value (asn1_node_const root, const char *name,
++		     void *ivalue, int *len);
++
++extern ASN1_API int
++  asn1_read_value_type (asn1_node_const root, const char *name,
++			  void *ivalue, int *len, unsigned int *etype);
++
++extern ASN1_API int
++  asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data);
++
++extern ASN1_API int
++  asn1_number_of_elements (asn1_node_const element, const char *name, int *num);
++
++extern ASN1_API int
++  asn1_der_coding (asn1_node_const element, const char *name,
++		     void *ider, int *len, char *ErrorDescription);
++
++extern ASN1_API int
++  asn1_der_decoding2 (asn1_node *element, const void *ider,
++			int *max_ider_len, unsigned int flags,
++			char *errorDescription);
++
++extern ASN1_API int
++  asn1_der_decoding (asn1_node * element, const void *ider,
++		       int ider_len, char *errorDescription);
++
++/* Do not use. Use asn1_der_decoding() instead. */
++extern ASN1_API int
++  asn1_der_decoding_element (asn1_node * structure,
++			       const char *elementName,
++			       const void *ider, int len,
++			       char *errorDescription) _ASN1_GCC_ATTR_DEPRECATED;
++
++extern ASN1_API int
++  asn1_der_decoding_startEnd (asn1_node element,
++				const void *ider, int ider_len,
++				const char *name_element,
++				int *start, int *end);
++
++extern ASN1_API int
++  asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element);
++
++extern ASN1_API int
++  asn1_expand_octet_string (asn1_node_const definitions,
++			      asn1_node * element,
++			      const char *octetName, const char *objectName);
++
++extern ASN1_API int
++  asn1_read_tag (asn1_node_const root, const char *name,
++		   int *tagValue, int *classValue);
++
++extern ASN1_API const char *asn1_find_structure_from_oid (asn1_node_const
++							    definitions,
++							    const char
++							    *oidValue);
++
++__LIBTASN1_PURE__
++extern ASN1_API const char *asn1_check_version (const char *req_version);
++
++__LIBTASN1_PURE__
++extern ASN1_API const char *asn1_strerror (int error);
++
++extern ASN1_API void asn1_perror (int error);
++
++#define ASN1_MAX_TAG_SIZE 4
++#define ASN1_MAX_LENGTH_SIZE 9
++#define ASN1_MAX_TL_SIZE (ASN1_MAX_TAG_SIZE+ASN1_MAX_LENGTH_SIZE)
++extern ASN1_API long
++  asn1_get_length_der (const unsigned char *der, int der_len, int *len);
++
++extern ASN1_API long
++  asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len);
++
++extern ASN1_API void
++  asn1_length_der (unsigned long int len, unsigned char *der, int *der_len);
++
++/* Other utility functions. */
++
++extern ASN1_API
++  int asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
++				unsigned int _der_len,
++				const unsigned char **str,
++				unsigned int *str_len);
++
++extern ASN1_API
++  int asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
++				unsigned int _der_len,
++				unsigned char **str,
++				unsigned int *str_len,
++				unsigned int *ber_len);
++
++extern ASN1_API int
++  asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
++			    unsigned int str_len, unsigned char *tl,
++			    unsigned int *tl_len);
++
++extern ASN1_API asn1_node
++  asn1_find_node (asn1_node_const pointer, const char *name);
++
++extern ASN1_API int
++  asn1_copy_node (asn1_node dst, const char *dst_name,
++		    asn1_node_const src, const char *src_name);
++extern ASN1_API asn1_node
++  asn1_dup_node (asn1_node_const src, const char *src_name);
++
++/* Internal and low-level DER utility functions. */
++
++extern ASN1_API int
++  asn1_get_tag_der (const unsigned char *der, int der_len,
++		      unsigned char *cls, int *len, unsigned long *tag);
++
++extern ASN1_API void
++  asn1_octet_der (const unsigned char *str, int str_len,
++		    unsigned char *der, int *der_len);
++
++extern ASN1_API int
++  asn1_get_octet_der (const unsigned char *der, int der_len,
++			int *ret_len, unsigned char *str,
++			int str_size, int *str_len);
++
++extern ASN1_API void asn1_bit_der (const unsigned char *str, int bit_len,
++				     unsigned char *der, int *der_len);
++
++extern ASN1_API int
++  asn1_get_bit_der (const unsigned char *der, int der_len,
++		      int *ret_len, unsigned char *str,
++		      int str_size, int *bit_len);
++
++extern ASN1_API int
++  asn1_get_object_id_der (const unsigned char *der,
++                          int der_len, int *ret_len,
++                          char *str, int str_size);
++
++extern ASN1_API int
++  asn1_object_id_der (const char *str, unsigned char *der, int *der_len,
++                      unsigned flags);
++
++/* Compatibility types */
++
++/**
++ * asn1_retCode:
++ *
++ * Type formerly returned by libtasn1 functions.
++ *
++ * Deprecated: 3.0: Use int instead.
++ */
++typedef int asn1_retCode;
++
++/**
++ * node_asn_struct:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_node instead.
++ */
++#define node_asn_struct asn1_node_st
++
++/**
++ * node_asn:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_node instead.
++ */
++#define node_asn asn1_node_st
++
++/**
++ * ASN1_TYPE:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_node instead.
++ */
++#define ASN1_TYPE asn1_node
++
++/**
++ * ASN1_TYPE_EMPTY:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use NULL instead.
++ */
++#define ASN1_TYPE_EMPTY NULL
++
++/**
++ * static_struct_asn:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_static_node instead.
++ */
++#define static_struct_asn asn1_static_node_st
++
++/**
++ * ASN1_ARRAY_TYPE:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_static_node instead.
++ */
++#define ASN1_ARRAY_TYPE asn1_static_node
++
++/**
++ * asn1_static_node_t:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_static_node instead.
++ */
++#define asn1_static_node_t asn1_static_node
++
++/**
++ * node_data_struct:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_data_node_st instead.
++ */
++#define node_data_struct asn1_data_node_st
++
++/**
++ * ASN1_DATA_NODE:
++ *
++ * Compat #define.
++ *
++ * Deprecated: 3.0: Use #asn1_data_node_st instead.
++ */
++#define ASN1_DATA_NODE asn1_data_node_st
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif				/* LIBTASN1_H */
+diff --git a/grub-core/lib/libtasn1/LICENSE b/grub-core/lib/libtasn1/LICENSE
+new file mode 100644
+index 0000000000..e8b3628db9
+--- /dev/null
++++ b/grub-core/lib/libtasn1/LICENSE
+@@ -0,0 +1,16 @@
++LICENSING
++=========
++
++The libtasn1 library is released under the GNU Lesser General Public
++License (LGPL) version 2.1 or later; see [COPYING.LESSER](doc/COPYING.LESSER)
++for the license terms.
++
++The GNU LGPL applies to the main libtasn1 library, while the
++included applications library are under the GNU GPL version 3.
++The libtasn1 library is located in the lib directory, while the applications
++in src/.
++
++The documentation in doc/ is under the GNU FDL license 1.3.
++
++For any copyright year range specified as YYYY-ZZZZ in this package
++note that the range specifies every single year in that closed interval.
+diff --git a/grub-core/lib/libtasn1/README.md b/grub-core/lib/libtasn1/README.md
+new file mode 100644
+index 0000000000..50a8642296
+--- /dev/null
++++ b/grub-core/lib/libtasn1/README.md
+@@ -0,0 +1,91 @@
++|Branch|CI system|Status|
++|:----:|:-------:|-----:|
++|Master|Gitlab|[![build status](https://gitlab.com/gnutls/libtasn1/badges/master/pipeline.svg)](https://gitlab.com/gnutls/libtasn1/commits/master)[![coverage report](https://gitlab.com/gnutls/libtasn1/badges/master/coverage.svg)](https://gnutls.gitlab.io/libtasn1/coverage)|
++
++# libtasn1
++
++This is GNU Libtasn1, a small ASN.1 library.
++
++The C library (libtasn1.*) is licensed under the GNU Lesser General
++Public License version 2.1 or later.  See the file COPYING.LIB.
++
++The command line tool, self tests, examples, and other auxilliary
++files, are licensed under the GNU General Public License version 3.0
++or later.  See the file COPYING.
++
++## Building the library
++
++We require several tools to build the software, including:
++
++* [Make](https://www.gnu.org/software/make/)
++* [Automake](https://www.gnu.org/software/automake/) (use 1.11.3 or later)
++* [Autoconf](https://www.gnu.org/software/autoconf/)
++* [Libtool](https://www.gnu.org/software/libtool/)
++* [Texinfo](https://www.gnu.org/software/texinfo/)
++* [help2man](http://www.gnu.org/software/help2man/)
++* [Tar](https://www.gnu.org/software/tar/)
++* [Gzip](https://www.gnu.org/software/gzip/)
++* [bison](https://www.gnu.org/software/bison/)
++* [Texlive & epsf](https://www.tug.org/texlive/) (for PDF manual)
++* [GTK-DOC](https://www.gtk.org/gtk-doc/) (for API manual)
++* [Git](https://git-scm.com/)
++* [libabigail](https://pagure.io/libabigail/) (for abi comparison in make dist)
++* [Valgrind](https://valgrind.org/) (optional)
++
++The required software is typically distributed with your operating
++system, and the instructions for installing them differ.  Here are
++some hints:
++
++gNewSense/Debian/Ubuntu:
++```
++sudo apt-get install make git-core autoconf automake libtool
++sudo apt-get install texinfo texlive texlive-generic-recommended texlive-extra-utils
++sudo apt-get install help2man gtk-doc-tools valgrind abigail-tools
++```
++
++The next step is to run autoreconf, ./configure, etc:
++
++```
++$ ./bootstrap
++```
++
++Then build the project normally:
++
++```
++$ make
++$ make check
++```
++
++Happy hacking!
++
++
++## Manual
++
++The manual is in the `doc/` directory of the release.  You can also browse
++the manual online at:
++
++ - https://gnutls.gitlab.io/libtasn1/
++
++
++## Code coverage report
++
++The coverage report is at:
++
++ - https://gnutls.gitlab.io/libtasn1/coverage
++
++
++## Issue trackers
++
++ - [Main issue tracker](https://gitlab.com/gnutls/libtasn1/issues)
++ - [oss-fuzz found issues](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=libtasn1&can=2)
++
++
++## Homepage
++
++The project homepage at the gnu site is at:
++
++http://www.gnu.org/software/libtasn1/
++
++
++For any copyright year range specified as YYYY-ZZZZ in this package
++note that the range specifies every single year in that closed interval.
diff --git a/SOURCES/0163-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch b/SOURCES/0163-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch
deleted file mode 100644
index 7c29683..0000000
--- a/SOURCES/0163-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 20 Jul 2020 12:24:02 -0400
-Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/ip6_config.c
-
-This will need to get folded back in the right place on the next rebase,
-but it's before "Make grub_strtol() "end" pointers have safer const
-qualifiers" currently, so for now I'm leaving it here instead of merging
-it back with the original patch.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/net/efi/ip6_config.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c
-index a46f6f9b685..1c5415d7185 100644
---- a/grub-core/net/efi/ip6_config.c
-+++ b/grub-core/net/efi/ip6_config.c
-@@ -85,7 +85,7 @@ grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *addres
- 	  ptr++;
- 	  continue;
- 	}
--      t = grub_strtoul (ptr, (char **) &ptr, 16);
-+      t = grub_strtoul (ptr, &ptr, 16);
-       if (grub_errno)
- 	{
- 	  grub_errno = GRUB_ERR_NONE;
diff --git a/SOURCES/0163-libtasn1-disable-code-not-needed-in-grub.patch b/SOURCES/0163-libtasn1-disable-code-not-needed-in-grub.patch
new file mode 100644
index 0000000..84dcbf0
--- /dev/null
+++ b/SOURCES/0163-libtasn1-disable-code-not-needed-in-grub.patch
@@ -0,0 +1,307 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Fri, 1 May 2020 17:12:23 +1000
+Subject: [PATCH] libtasn1: disable code not needed in grub
+
+We don't expect to be able to write ASN.1, only read it,
+so we can disable some code.
+
+Do that with #if 0/#endif, rather than deletion. This means
+that the difference between upstream and grub is smaller,
+which should make updating libtasn1 easier in the future.
+
+With these exclusions we also avoid the need for minmax.h,
+which is convenient because it means we don't have to
+import it from gnulib.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/lib/libtasn1/lib/coding.c    | 12 ++++++++++--
+ grub-core/lib/libtasn1/lib/decoding.c  |  2 ++
+ grub-core/lib/libtasn1/lib/element.c   |  4 ++--
+ grub-core/lib/libtasn1/lib/errors.c    |  3 +++
+ grub-core/lib/libtasn1/lib/structure.c | 10 ++++++----
+ include/grub/libtasn1.h                | 15 +++++++++++++++
+ 6 files changed, 38 insertions(+), 8 deletions(-)
+
+diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c
+index 245ea64cf0..52def59836 100644
+--- a/grub-core/lib/libtasn1/lib/coding.c
++++ b/grub-core/lib/libtasn1/lib/coding.c
+@@ -30,11 +30,11 @@
+ #include "parser_aux.h"
+ #include <gstr.h>
+ #include "element.h"
+-#include "minmax.h"
+ #include <structure.h>
+ 
+ #define MAX_TAG_LEN 16
+ 
++#if 0
+ /******************************************************/
+ /* Function : _asn1_error_description_value_not_found */
+ /* Description: creates the ErrorDescription string   */
+@@ -58,6 +58,7 @@ _asn1_error_description_value_not_found (asn1_node node,
+   Estrcat (ErrorDescription, "' not found");
+ 
+ }
++#endif
+ 
+ /**
+  * asn1_length_der:
+@@ -244,6 +245,7 @@ asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
+   return ASN1_SUCCESS;
+ }
+ 
++#if 0
+ /******************************************************/
+ /* Function : _asn1_time_der                          */
+ /* Description: creates the DER coding for a TIME     */
+@@ -281,7 +283,7 @@ _asn1_time_der (unsigned char *str, int str_len, unsigned char *der,
+ 
+   return ASN1_SUCCESS;
+ }
+-
++#endif
+ 
+ /*
+ void
+@@ -520,6 +522,7 @@ asn1_bit_der (const unsigned char *str, int bit_len,
+ }
+ 
+ 
++#if 0
+ /******************************************************/
+ /* Function : _asn1_complete_explicit_tag             */
+ /* Description: add the length coding to the EXPLICIT */
+@@ -596,6 +599,7 @@ _asn1_complete_explicit_tag (asn1_node node, unsigned char *der,
+ 
+   return ASN1_SUCCESS;
+ }
++#endif
+ 
+ const tag_and_class_st _asn1_tags[] = {
+   [ASN1_ETYPE_GENERALSTRING] =
+@@ -648,6 +652,8 @@ const tag_and_class_st _asn1_tags[] = {
+ 
+ unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]);
+ 
++
++#if 0
+ /******************************************************/
+ /* Function : _asn1_insert_tag_der                    */
+ /* Description: creates the DER coding of tags of one */
+@@ -1413,3 +1419,5 @@ error:
+   asn1_delete_structure (&node);
+   return err;
+ }
++
++#endif
+\ No newline at end of file
+diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c
+index ff04eb778c..42f9a92b5d 100644
+--- a/grub-core/lib/libtasn1/lib/decoding.c
++++ b/grub-core/lib/libtasn1/lib/decoding.c
+@@ -1613,6 +1613,7 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len,
+   return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription);
+ }
+ 
++#if 0
+ /**
+  * asn1_der_decoding_element:
+  * @structure: pointer to an ASN1 structure
+@@ -1643,6 +1644,7 @@ asn1_der_decoding_element (asn1_node * structure, const char *elementName,
+ {
+   return asn1_der_decoding(structure, ider, len, errorDescription);
+ }
++#endif
+ 
+ /**
+  * asn1_der_decoding_startEnd:
+diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c
+index 997eb2725d..539008d8e9 100644
+--- a/grub-core/lib/libtasn1/lib/element.c
++++ b/grub-core/lib/libtasn1/lib/element.c
+@@ -191,7 +191,7 @@ _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache)
+   return ASN1_SUCCESS;
+ }
+ 
+-
++#if 0
+ /**
+  * asn1_write_value:
+  * @node_root: pointer to a structure
+@@ -645,7 +645,7 @@ asn1_write_value (asn1_node node_root, const char *name,
+ 
+   return ASN1_SUCCESS;
+ }
+-
++#endif
+ 
+ #define PUT_VALUE( ptr, ptr_size, data, data_size) \
+ 	*len = data_size; \
+diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c
+index cee74daf79..42785e8622 100644
+--- a/grub-core/lib/libtasn1/lib/errors.c
++++ b/grub-core/lib/libtasn1/lib/errors.c
+@@ -57,6 +57,8 @@ static const libtasn1_error_entry error_algorithms[] = {
+   {0, 0}
+ };
+ 
++
++#if 0
+ /**
+  * asn1_perror:
+  * @error: is an error returned by a libtasn1 function.
+@@ -73,6 +75,7 @@ asn1_perror (int error)
+   const char *str = asn1_strerror (error);
+   fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)");
+ }
++#endif
+ 
+ /**
+  * asn1_strerror:
+diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c
+index 8189c56a4c..fcfde01a39 100644
+--- a/grub-core/lib/libtasn1/lib/structure.c
++++ b/grub-core/lib/libtasn1/lib/structure.c
+@@ -76,7 +76,7 @@ _asn1_find_left (asn1_node_const node)
+   return node->left;
+ }
+ 
+-
++#if 0
+ int
+ _asn1_create_static_structure (asn1_node_const pointer, char *output_file_name,
+ 			       char *vector_name)
+@@ -155,7 +155,7 @@ _asn1_create_static_structure (asn1_node_const pointer, char *output_file_name,
+ 
+   return ASN1_SUCCESS;
+ }
+-
++#endif
+ 
+ /**
+  * asn1_array2tree:
+@@ -718,7 +718,7 @@ asn1_create_element (asn1_node_const definitions, const char *source_name,
+   return res;
+ }
+ 
+-
++#if 0
+ /**
+  * asn1_print_structure:
+  * @out: pointer to the output file (e.g. stdout).
+@@ -1058,7 +1058,7 @@ asn1_print_structure (FILE * out, asn1_node_const structure, const char *name,
+ 	}
+     }
+ }
+-
++#endif
+ 
+ 
+ /**
+@@ -1153,6 +1153,7 @@ asn1_find_structure_from_oid (asn1_node_const definitions, const char *oidValue)
+   return NULL;			/* ASN1_ELEMENT_NOT_FOUND; */
+ }
+ 
++#if 0
+ /**
+  * asn1_copy_node:
+  * @dst: Destination asn1 node.
+@@ -1202,6 +1203,7 @@ asn1_copy_node (asn1_node dst, const char *dst_name,
+ 
+   return result;
+ }
++#endif
+ 
+ /**
+  * asn1_dup_node:
+diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h
+index 6fd7a30dc3..785eda2ae3 100644
+--- a/include/grub/libtasn1.h
++++ b/include/grub/libtasn1.h
+@@ -319,6 +319,8 @@ typedef struct asn1_data_node_st asn1_data_node_st;
+ /*  Functions definitions          */
+ /***********************************/
+ 
++/* These functions are not used in grub and should not be referenced. */
++#if 0
+ extern ASN1_API int
+   asn1_parser2tree (const char *file,
+ 		      asn1_node * definitions, char *error_desc);
+@@ -327,14 +329,17 @@ extern ASN1_API int
+   asn1_parser2array (const char *inputFileName,
+ 		       const char *outputFileName,
+ 		       const char *vectorName, char *error_desc);
++#endif
+ 
+ extern ASN1_API int
+   asn1_array2tree (const asn1_static_node * array,
+ 		     asn1_node * definitions, char *errorDescription);
+ 
++#if 0
+ extern ASN1_API void
+   asn1_print_structure (FILE * out, asn1_node_const structure,
+ 			  const char *name, int mode);
++#endif
+ 
+ extern ASN1_API int
+   asn1_create_element (asn1_node_const definitions,
+@@ -347,9 +352,11 @@ extern ASN1_API int asn1_delete_structure2 (asn1_node * structure, unsigned int
+ extern ASN1_API int
+   asn1_delete_element (asn1_node structure, const char *element_name);
+ 
++#if 0
+ extern ASN1_API int
+   asn1_write_value (asn1_node node_root, const char *name,
+ 		      const void *ivalue, int len);
++#endif
+ 
+ extern ASN1_API int
+   asn1_read_value (asn1_node_const root, const char *name,
+@@ -365,9 +372,11 @@ extern ASN1_API int
+ extern ASN1_API int
+   asn1_number_of_elements (asn1_node_const element, const char *name, int *num);
+ 
++#if 0
+ extern ASN1_API int
+   asn1_der_coding (asn1_node_const element, const char *name,
+ 		     void *ider, int *len, char *ErrorDescription);
++#endif
+ 
+ extern ASN1_API int
+   asn1_der_decoding2 (asn1_node *element, const void *ider,
+@@ -378,12 +387,14 @@ extern ASN1_API int
+   asn1_der_decoding (asn1_node * element, const void *ider,
+ 		       int ider_len, char *errorDescription);
+ 
++#if 0
+ /* Do not use. Use asn1_der_decoding() instead. */
+ extern ASN1_API int
+   asn1_der_decoding_element (asn1_node * structure,
+ 			       const char *elementName,
+ 			       const void *ider, int len,
+ 			       char *errorDescription) _ASN1_GCC_ATTR_DEPRECATED;
++#endif
+ 
+ extern ASN1_API int
+   asn1_der_decoding_startEnd (asn1_node element,
+@@ -408,13 +419,17 @@ extern ASN1_API const char *asn1_find_structure_from_oid (asn1_node_const
+ 							    const char
+ 							    *oidValue);
+ 
++#if 0
+ __LIBTASN1_PURE__
+ extern ASN1_API const char *asn1_check_version (const char *req_version);
++#endif
+ 
+ __LIBTASN1_PURE__
+ extern ASN1_API const char *asn1_strerror (int error);
+ 
++#if 0
+ extern ASN1_API void asn1_perror (int error);
++#endif
+ 
+ #define ASN1_MAX_TAG_SIZE 4
+ #define ASN1_MAX_LENGTH_SIZE 9
diff --git a/SOURCES/0164-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch b/SOURCES/0164-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch
deleted file mode 100644
index 0fe90c8..0000000
--- a/SOURCES/0164-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 20 Jul 2020 12:24:02 -0400
-Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/net.c
-
-This will need to get folded back in the right place on the next rebase,
-but it's before "Make grub_strtol() "end" pointers have safer const
-qualifiers" currently, so for now I'm leaving it here instead of merging
-it back with the original patch.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/net/efi/net.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
-index a3f0535d43c..78e5442fc52 100644
---- a/grub-core/net/efi/net.c
-+++ b/grub-core/net/efi/net.c
-@@ -729,7 +729,7 @@ grub_efi_net_parse_address (const char *address,
- 	{
- 	  grub_uint32_t subnet_mask_size;
- 
--	  subnet_mask_size = grub_strtoul (rest + 1, (char **) &rest, 0);
-+	  subnet_mask_size = grub_strtoul (rest + 1, &rest, 0);
- 
- 	  if (!grub_errno && subnet_mask_size <= 32 && *rest == 0)
- 	    {
-@@ -758,7 +758,7 @@ grub_efi_net_parse_address (const char *address,
- 	{
- 	  grub_efi_uint8_t prefix_length;
- 
--	  prefix_length = grub_strtoul (rest + 1, (char **) &rest, 0);
-+	  prefix_length = grub_strtoul (rest + 1, &rest, 0);
- 	  if (!grub_errno && prefix_length <= 128 && *rest == 0)
- 	    {
- 	      ip6->prefix_length = prefix_length;
diff --git a/SOURCES/0164-libtasn1-changes-for-grub-compatibility.patch b/SOURCES/0164-libtasn1-changes-for-grub-compatibility.patch
new file mode 100644
index 0000000..7c756bd
--- /dev/null
+++ b/SOURCES/0164-libtasn1-changes-for-grub-compatibility.patch
@@ -0,0 +1,202 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Fri, 1 May 2020 20:44:29 +1000
+Subject: [PATCH] libtasn1: changes for grub compatibility
+
+Do a few things to make libtasn1 compile as part of grub:
+
+ - replace strcat. grub removed strcat so replace it with the appropriate
+   calls to memcpy and strlen.
+
+ - replace c_isdigit with grub_isdigit (and don't import c-ctype from
+   gnulib) grub_isdigit provides the same functionality as c_isdigit: it
+   determines if the input is an ASCII digit without regard for locale.
+
+ - replace GL_ATTRIBUTE_PURE with __attribute__((pure)) which been
+   supported since gcc-2.96. This avoids messing around with gnulib.
+
+ - adjust libtasn1.h: drop the ASN1_API logic, it's not needed for our
+   modules. Unconditionally support const and pure attributes and adjust
+   header paths.
+
+ - adjust header paths to "grub/libtasn1.h".
+
+ - replace a 64 bit division with a call to grub_divmod64, preventing
+   creation of __udivdi3 calls on 32 bit platforms.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/lib/libtasn1/lib/decoding.c   | 11 ++++++-----
+ grub-core/lib/libtasn1/lib/element.c    |  3 ++-
+ grub-core/lib/libtasn1/lib/gstr.c       |  4 ++--
+ grub-core/lib/libtasn1/lib/parser_aux.c |  7 ++++---
+ grub-core/lib/libtasn1/lib/int.h        |  4 ++--
+ include/grub/libtasn1.h                 | 26 ++++++--------------------
+ 6 files changed, 22 insertions(+), 33 deletions(-)
+
+diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c
+index 42f9a92b5d..7856858b27 100644
+--- a/grub-core/lib/libtasn1/lib/decoding.c
++++ b/grub-core/lib/libtasn1/lib/decoding.c
+@@ -32,7 +32,8 @@
+ #include <element.h>
+ #include <limits.h>
+ #include <intprops.h>
+-#include <c-ctype.h>
++
++#define c_isdigit grub_isdigit
+ 
+ #ifdef DEBUG
+ # define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__)
+@@ -2008,8 +2009,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element,
+ 	  (p2->type & CONST_ASSIGN))
+ 	{
+ 	  strcpy (name, definitions->name);
+-	  strcat (name, ".");
+-	  strcat (name, p2->name);
++	  memcpy (name + strlen(name), ".", sizeof(" . "));
++	  memcpy (name + strlen(name), p2->name, strlen(p2->name) + 1);
+ 
+ 	  len = sizeof (value);
+ 	  result = asn1_read_value (definitions, name, value, &len);
+@@ -2026,8 +2027,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element,
+ 	      if (p2)
+ 		{
+ 		  strcpy (name, definitions->name);
+-		  strcat (name, ".");
+-		  strcat (name, p2->name);
++		  memcpy (name + strlen(name), ".", sizeof(" . "));
++		  memcpy (name + strlen(name), p2->name, strlen(p2->name) + 1);
+ 
+ 		  result = asn1_create_element (definitions, name, &aux);
+ 		  if (result == ASN1_SUCCESS)
+diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c
+index 539008d8e9..ed761ff56b 100644
+--- a/grub-core/lib/libtasn1/lib/element.c
++++ b/grub-core/lib/libtasn1/lib/element.c
+@@ -30,9 +30,10 @@
+ #include "parser_aux.h"
+ #include <gstr.h>
+ #include "structure.h"
+-#include "c-ctype.h"
+ #include "element.h"
+ 
++#define c_isdigit grub_isdigit
++
+ void
+ _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size)
+ {
+diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c
+index e91a3a151c..e33875c2c7 100644
+--- a/grub-core/lib/libtasn1/lib/gstr.c
++++ b/grub-core/lib/libtasn1/lib/gstr.c
+@@ -36,13 +36,13 @@ _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src)
+ 
+   if (dest_tot_size - dest_size > str_size)
+     {
+-      strcat (dest, src);
++      memcpy (dest + dest_size, src, str_size + 1);
+     }
+   else
+     {
+       if (dest_tot_size - dest_size > 0)
+ 	{
+-	  strncat (dest, src, (dest_tot_size - dest_size) - 1);
++	  memcpy (dest + dest_size, src, (dest_tot_size - dest_size) - 1);
+ 	  dest[dest_tot_size - 1] = 0;
+ 	}
+     }
+diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c
+index d5dbbf8765..89c9be69dc 100644
+--- a/grub-core/lib/libtasn1/lib/parser_aux.c
++++ b/grub-core/lib/libtasn1/lib/parser_aux.c
+@@ -26,7 +26,8 @@
+ #include "gstr.h"
+ #include "structure.h"
+ #include "element.h"
+-#include "c-ctype.h"
++
++#define c_isdigit grub_isdigit
+ 
+ char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1];	/* identifier name not found */
+ 
+@@ -40,7 +41,7 @@ char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1];	/* identifier name not fou
+ #ifdef __clang__
+ __attribute__((no_sanitize("integer")))
+ #endif
+-_GL_ATTRIBUTE_PURE
++__attribute__((__pure__))
+ static unsigned int
+ _asn1_hash_name (const char *x)
+ {
+@@ -634,7 +635,7 @@ _asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE])
+   count = 0;
+   do
+     {
+-      d = val / 10;
++      d = grub_divmod64(val, 10, NULL);
+       r = val - d * 10;
+       temp[start + count] = '0' + (char) r;
+       count++;
+diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h
+index ea1625786c..4a568efee9 100644
+--- a/grub-core/lib/libtasn1/lib/int.h
++++ b/grub-core/lib/libtasn1/lib/int.h
+@@ -35,7 +35,7 @@
+ #include <sys/types.h>
+ #endif
+ 
+-#include <libtasn1.h>
++#include "grub/libtasn1.h"
+ 
+ #define ASN1_SMALL_VALUE_SIZE 16
+ 
+@@ -115,7 +115,7 @@ extern const tag_and_class_st _asn1_tags[];
+ #define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b)
+ #define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b)
+ #define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b)
+-#define _asn1_strcat(a,b) strcat((char *)a, (const char *)b)
++#define _asn1_strcat(a,b) memcpy((char *)a + strlen((const char *)a), (const char *)b, strlen((const char *)b) + 1)
+ 
+ #if SIZEOF_UNSIGNED_LONG_INT == 8
+ # define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b)
+diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h
+index 785eda2ae3..28dbf16c4e 100644
+--- a/include/grub/libtasn1.h
++++ b/include/grub/libtasn1.h
+@@ -38,29 +38,15 @@
+ #ifndef LIBTASN1_H
+ #define LIBTASN1_H
+ 
+-#ifndef ASN1_API
+-#if defined ASN1_BUILDING && defined HAVE_VISIBILITY && HAVE_VISIBILITY
+-#define ASN1_API __attribute__((__visibility__("default")))
+-#elif defined ASN1_BUILDING && defined _MSC_VER && ! defined ASN1_STATIC
+-#define ASN1_API __declspec(dllexport)
+-#elif defined _MSC_VER && ! defined ASN1_STATIC
+-#define ASN1_API __declspec(dllimport)
+-#else
++/* grub: ASN1_API is not used */
+ #define ASN1_API
+-#endif
+-#endif
+ 
+-#ifdef __GNUC__
+-# define __LIBTASN1_CONST__  __attribute__((const))
+-# define __LIBTASN1_PURE__  __attribute__((pure))
+-#else
+-# define __LIBTASN1_CONST__
+-# define __LIBTASN1_PURE__
+-#endif
++/* grub: all our supported compilers support these attributes */
++#define __LIBTASN1_CONST__  __attribute__((const))
++#define __LIBTASN1_PURE__  __attribute__((pure))
+ 
+-#include <sys/types.h>
+-#include <time.h>
+-#include <stdio.h>		/* for FILE* */
++#include <grub/types.h>
++#include <grub/time.h>
+ 
+ #ifdef __cplusplus
+ extern "C"
diff --git a/SOURCES/0165-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch b/SOURCES/0165-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch
deleted file mode 100644
index 59f29e4..0000000
--- a/SOURCES/0165-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 20 Jul 2020 12:24:02 -0400
-Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/pxe.c
-
-This will need to get folded back in the right place on the next rebase,
-but it's before "Make grub_strtol() "end" pointers have safer const
-qualifiers" currently, so for now I'm leaving it here instead of merging
-it back with the original patch.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/net/efi/pxe.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/grub-core/net/efi/pxe.c b/grub-core/net/efi/pxe.c
-index 531949cba5c..73e2bb01c1b 100644
---- a/grub-core/net/efi/pxe.c
-+++ b/grub-core/net/efi/pxe.c
-@@ -187,7 +187,7 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
- 	  ptr++;
- 	  continue;
- 	}
--      t = grub_strtoul (ptr, (char **) &ptr, 16);
-+      t = grub_strtoul (ptr, &ptr, 16);
-       if (grub_errno)
- 	{
- 	  grub_errno = GRUB_ERR_NONE;
-@@ -225,7 +225,7 @@ pxe_open (struct grub_efi_net_device *dev,
- 	  int type __attribute__((unused)))
- {
-   int i;
--  char *p;
-+  const char *p;
-   grub_efi_status_t status;
-   grub_efi_pxe_ip_address_t server_ip;
-   grub_efi_uint64_t file_size = 0;
-@@ -313,7 +313,7 @@ pxe_read (struct grub_efi_net_device *dev,
- 	  grub_size_t len)
- {
-   int i;
--  char *p;
-+  const char *p;
-   grub_efi_status_t status;
-   grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe;
-   grub_efi_uint64_t bufsz = len;
diff --git a/SOURCES/0165-libtasn1-compile-into-asn1-module.patch b/SOURCES/0165-libtasn1-compile-into-asn1-module.patch
new file mode 100644
index 0000000..0fb433f
--- /dev/null
+++ b/SOURCES/0165-libtasn1-compile-into-asn1-module.patch
@@ -0,0 +1,70 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Fri, 5 Jun 2020 17:47:25 +1000
+Subject: [PATCH] libtasn1: compile into asn1 module
+
+Create a wrapper file that specifies the module license.
+Set up the makefile so it is built.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/Makefile.core.def        | 15 +++++++++++++++
+ grub-core/lib/libtasn1_wrap/wrap.c | 26 ++++++++++++++++++++++++++
+ 2 files changed, 41 insertions(+)
+ create mode 100644 grub-core/lib/libtasn1_wrap/wrap.c
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 64cc758835..ea92468fa2 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -2577,3 +2577,18 @@ module = {
+   common = commands/i386/wrmsr.c;
+   enable = x86;
+ };
++
++module = {
++  name = asn1;
++  common = lib/libtasn1/lib/decoding.c;
++  common = lib/libtasn1/lib/coding.c;
++  common = lib/libtasn1/lib/element.c;
++  common = lib/libtasn1/lib/structure.c;
++  common = lib/libtasn1/lib/parser_aux.c;
++  common = lib/libtasn1/lib/gstr.c;
++  common = lib/libtasn1/lib/errors.c;
++  common = lib/libtasn1_wrap/wrap.c;
++  cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
++  // -Wno-type-limits comes from libtasn1's configure.ac
++  cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1/lib -Wno-type-limits';
++};
+diff --git a/grub-core/lib/libtasn1_wrap/wrap.c b/grub-core/lib/libtasn1_wrap/wrap.c
+new file mode 100644
+index 0000000000..622ba942e3
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/wrap.c
+@@ -0,0 +1,26 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020 IBM Corporation
++ *
++ *  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>
++
++/*
++ * libtasn1 is provided under LGPL2.1+, which is compatible
++ * with GPL3+. As Grub as a whole is under GPL3+, this module
++ * is therefore under GPL3+ also.
++ */
++GRUB_MOD_LICENSE ("GPLv3+");
diff --git a/SOURCES/0166-Add-systemd-integration-scripts-to-make-systemctl-re.patch b/SOURCES/0166-Add-systemd-integration-scripts-to-make-systemctl-re.patch
deleted file mode 100644
index 130dc77..0000000
--- a/SOURCES/0166-Add-systemd-integration-scripts-to-make-systemctl-re.patch
+++ /dev/null
@@ -1,190 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Hans de Goede <hdegoede@redhat.com>
-Date: Wed, 22 Jul 2020 14:03:42 +0200
-Subject: [PATCH] Add systemd integration scripts to make "systemctl reboot
- --boot-loader-menu=xxx" work with grub
-
-This commit adds a number of scripts / config files to make
-"systemctl reboot --boot-loader-menu=xxx" work with grub:
-
-1. /lib/systemd/system/systemd-logind.service.d/10-grub.conf
-This sets SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU in the env. for logind,
-indicating that the boot-loader which is used supports this feature, see:
-https://github.com/systemd/systemd/blob/master/docs/ENVIRONMENT.md
-
-2. /lib/systemd/system/grub-systemd-integration.service
-   /lib/systemd/system/reboot.target.wants/grub-systemd-integration.service ->
-     ../grub-systemd-integration.service
-   /usr/libexec/grub/grub-systemd-integration.sh
-
-The symlink in the .wants dir causes the added service file to be started
-by systemd just before rebooting the system.
-If /run/systemd/reboot-to-boot-loader-menu exist then the service will run
-the grub-systemd-integration.sh script.
-This script sets the new menu_show_once_timeout grubenv variable to the
-requested timeout in seconds.
-
-3. /etc/grub.d/14_menu_show_once
-
-This new grub-mkconfig snippet adds the necessary code to the generated
-grub.conf to honor the new menu_show_once_timeout variable, and to
-automatically clear it after consuming it.
-
-Note the service and libexec script use grub-systemd-integration as name
-because in the future they may be used to add further integration with
-systemctl reboot --foo options, e.g. support for --boot-loader-entry=NAME.
-
-A few notes about upstreaming this patch from the rhboot grub2 fork:
-1. I have deliberately put the grub.conf bits for this in a new / separate
-   grub-mkconfig snippet generator for easy upstreaming
-2. Even though the commit message mentions the .wants symlink for the .service
-   I have been unable to come up with a clean way to do this at "make install"
-   time, this should be fixed before upstreaming.
-
-Downstream notes:
-1. Since make install does not add the .wants symlink, this needs to be done
-   in grub2.spec %install
-2. This is keeping support for the "old" Fedora specific menu_show_once env
-   variable, which has a hardcoded timeout of 60 sec in 12_menu_auto_hide in
-   place for now. This can be dropped (eventually) in a follow-up patch once
-   GNOME has been converted to use the systemd dbus API equivalent of
-   "systemctl reboot --boot-loader-menu=xxx".
-
-Signed-off-by: Hans de Goede <hdegoede@redhat.com>
----
- Makefile.util.def                                | 27 ++++++++++++++++++++++++
- conf/Makefile.common                             |  6 ++++++
- util/grub.d/14_menu_show_once.in                 | 13 ++++++++++++
- util/systemd/10-grub-logind-service.conf.in      |  2 ++
- util/systemd/grub-systemd-integration.service.in |  8 +++++++
- util/systemd/systemd-integration.sh.in           |  6 ++++++
- 6 files changed, 62 insertions(+)
- create mode 100755 util/grub.d/14_menu_show_once.in
- create mode 100644 util/systemd/10-grub-logind-service.conf.in
- create mode 100644 util/systemd/grub-systemd-integration.service.in
- create mode 100644 util/systemd/systemd-integration.sh.in
-
-diff --git a/Makefile.util.def b/Makefile.util.def
-index 11ab2d6fad1..e1242f54022 100644
---- a/Makefile.util.def
-+++ b/Makefile.util.def
-@@ -470,6 +470,12 @@ script = {
-   installdir = grubconf;
- };
- 
-+script = {
-+  name = '14_menu_show_once';
-+  common = util/grub.d/14_menu_show_once.in;
-+  installdir = grubconf;
-+};
-+
- script = {
-   name = '01_users';
-   common = util/grub.d/01_users.in;
-@@ -569,6 +575,27 @@ script = {
-   installdir = grubconf;
- };
- 
-+script = {
-+  name = 'grub-systemd-integration.service';
-+  common = util/systemd/grub-systemd-integration.service.in;
-+  installdir = systemdunit;
-+  condition = COND_HOST_LINUX;
-+};
-+
-+script = {
-+  name = 'systemd-integration.sh';
-+  common = util/systemd/systemd-integration.sh.in;
-+  installdir = grublibexec;
-+  condition = COND_HOST_LINUX;
-+};
-+
-+script = {
-+  name = '10-grub-logind-service.conf';
-+  common = util/systemd/10-grub-logind-service.conf.in;
-+  installdir = systemd_logind_service_d;
-+  condition = COND_HOST_LINUX;
-+};
-+
- program = {
-   mansection = 1;
-   name = grub-mkrescue;
-diff --git a/conf/Makefile.common b/conf/Makefile.common
-index 0647c53b916..9fe5863b2d9 100644
---- a/conf/Makefile.common
-+++ b/conf/Makefile.common
-@@ -63,8 +63,11 @@ CCASFLAGS_LIBRARY = $(UTILS_CCASFLAGS)
- # Other variables
- 
- grubconfdir = $(sysconfdir)/grub.d
-+grublibexecdir = $(libexecdir)/$(grubdirname)
- platformdir = $(pkglibdir)/$(target_cpu)-$(platform)
- starfielddir = $(pkgdatadir)/themes/starfield
-+systemdunitdir = ${prefix}/lib/systemd/system
-+systemd_logind_service_ddir = $(systemdunitdir)/systemd-logind.service.d
- 
- CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Werror=trampolines -fno-trampolines
- CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib
-@@ -121,6 +124,9 @@ noinst_LIBRARIES =
- dist_noinst_DATA =
- platform_SCRIPTS =
- platform_PROGRAMS =
-+grublibexec_SCRIPTS =
-+systemdunit_SCRIPTS =
-+systemd_logind_service_d_SCRIPTS =
- 
- TESTS =
- EXTRA_DIST =
-diff --git a/util/grub.d/14_menu_show_once.in b/util/grub.d/14_menu_show_once.in
-new file mode 100755
-index 00000000000..1cd7f36142b
---- /dev/null
-+++ b/util/grub.d/14_menu_show_once.in
-@@ -0,0 +1,13 @@
-+#! /bin/sh
-+# Force the menu to be shown once, with a timeout of ${menu_show_once_timeout}
-+# if requested by ${menu_show_once_timeout} being set in the env.
-+cat << EOF
-+if [ x\$feature_timeout_style = xy ]; then
-+  if [ "\${menu_show_once_timeout}" ]; then
-+    set timeout_style=menu
-+    set timeout="\${menu_show_once_timeout}"
-+    unset menu_show_once_timeout
-+    save_env menu_show_once_timeout
-+  fi
-+fi
-+EOF
-diff --git a/util/systemd/10-grub-logind-service.conf.in b/util/systemd/10-grub-logind-service.conf.in
-new file mode 100644
-index 00000000000..f2d4ac00732
---- /dev/null
-+++ b/util/systemd/10-grub-logind-service.conf.in
-@@ -0,0 +1,2 @@
-+[Service]
-+Environment=SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU=true
-diff --git a/util/systemd/grub-systemd-integration.service.in b/util/systemd/grub-systemd-integration.service.in
-new file mode 100644
-index 00000000000..c81fb594ce1
---- /dev/null
-+++ b/util/systemd/grub-systemd-integration.service.in
-@@ -0,0 +1,8 @@
-+[Unit]
-+Description=Grub2 systemctl reboot --boot-loader-menu=... support
-+Before=umount.target systemd-reboot.service
-+DefaultDependencies=no
-+ConditionPathExists=/run/systemd/reboot-to-boot-loader-menu
-+
-+[Service]
-+ExecStart=@libexecdir@/@grubdirname@/systemd-integration.sh
-diff --git a/util/systemd/systemd-integration.sh.in b/util/systemd/systemd-integration.sh.in
-new file mode 100644
-index 00000000000..dc1218597bc
---- /dev/null
-+++ b/util/systemd/systemd-integration.sh.in
-@@ -0,0 +1,6 @@
-+#!/bin/sh
-+
-+TIMEOUT_USEC=$(cat /run/systemd/reboot-to-boot-loader-menu)
-+TIMEOUT=$(((TIMEOUT_USEC + 500000) / 1000000))
-+
-+@grub_editenv@ - set menu_show_once_timeout=$TIMEOUT
diff --git a/SOURCES/0166-test_asn1-test-module-for-libtasn1.patch b/SOURCES/0166-test_asn1-test-module-for-libtasn1.patch
new file mode 100644
index 0000000..6cc13bd
--- /dev/null
+++ b/SOURCES/0166-test_asn1-test-module-for-libtasn1.patch
@@ -0,0 +1,1457 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Wed, 10 Jun 2020 17:48:42 +1000
+Subject: [PATCH] test_asn1: test module for libtasn1
+
+Import tests from libtasn1 that don't use functionality we don't
+import. I have put them here rather than in the libtasn1 directory
+because:
+
+ -  They need much more significant changes to run in the grub
+    context.
+
+ -  I don't expect they will need to be changed when updating
+    libtasn1: I expect the old tests will usually continue to pass on
+    new versions.
+
+This doesn't test the full decoder but that will be exercised in
+test suites for coming patch sets.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ Makefile.util.def                                  |   6 +
+ grub-core/Makefile.core.def                        |  13 ++
+ .../lib/libtasn1_wrap/tests/CVE-2018-1000654.c     |  61 ++++++
+ grub-core/lib/libtasn1_wrap/tests/Test_overflow.c  | 138 ++++++++++++++
+ grub-core/lib/libtasn1_wrap/tests/Test_simple.c    | 207 ++++++++++++++++++++
+ grub-core/lib/libtasn1_wrap/tests/Test_strings.c   | 150 +++++++++++++++
+ .../lib/libtasn1_wrap/tests/object-id-decoding.c   | 116 +++++++++++
+ .../lib/libtasn1_wrap/tests/object-id-encoding.c   | 120 ++++++++++++
+ grub-core/lib/libtasn1_wrap/tests/octet-string.c   | 211 +++++++++++++++++++++
+ grub-core/lib/libtasn1_wrap/tests/reproducers.c    |  81 ++++++++
+ grub-core/lib/libtasn1_wrap/wrap_tests.c           |  75 ++++++++
+ .../tests/CVE-2018-1000654-1_asn1_tab.h            |  32 ++++
+ .../tests/CVE-2018-1000654-2_asn1_tab.h            |  36 ++++
+ grub-core/lib/libtasn1_wrap/wrap_tests.h           |  38 ++++
+ .gitignore                                         |   1 +
+ tests/test_asn1.in                                 |  12 ++
+ 16 files changed, 1297 insertions(+)
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_overflow.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_simple.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_strings.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/octet-string.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/reproducers.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.c
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h
+ create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h
+ create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.h
+ create mode 100644 tests/test_asn1.in
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 6366442129..d04b3fe68a 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -1289,6 +1289,12 @@ script = {
+   common = tests/syslinux_test.in;
+ };
+ 
++script = {
++  testcase;
++  name = test_asn1;
++  common = tests/test_asn1.in;
++};
++
+ program = {
+   testcase;
+   name = example_unit_test;
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index ea92468fa2..a32e6ada59 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -2592,3 +2592,16 @@ module = {
+   // -Wno-type-limits comes from libtasn1's configure.ac
+   cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1/lib -Wno-type-limits';
+ };
++
++module = {
++  name = test_asn1;
++  common = lib/libtasn1_wrap/tests/CVE-2018-1000654.c;
++  common = lib/libtasn1_wrap/tests/object-id-decoding.c;
++  common = lib/libtasn1_wrap/tests/object-id-encoding.c;
++  common = lib/libtasn1_wrap/tests/octet-string.c;
++  common = lib/libtasn1_wrap/tests/reproducers.c;
++  common = lib/libtasn1_wrap/tests/Test_overflow.c;
++  common = lib/libtasn1_wrap/tests/Test_simple.c;
++  common = lib/libtasn1_wrap/tests/Test_strings.c;
++  common = lib/libtasn1_wrap/wrap_tests.c;
++};
+diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c
+new file mode 100644
+index 0000000000..534e304521
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c
+@@ -0,0 +1,61 @@
++/*
++ * Copyright (C) 2002-2018 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * 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 3 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/****************************************************************/
++/* Description: reproducer for CVE-2018-1000654			*/
++/****************************************************************/
++
++#include <grub/libtasn1.h>
++#include <grub/err.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/types.h>
++#include "../wrap_tests.h"
++
++#include "CVE-2018-1000654-1_asn1_tab.h"
++#include "CVE-2018-1000654-2_asn1_tab.h"
++
++void
++test_CVE_2018_1000654 (void)
++{
++  int result;
++  asn1_node definitions = NULL;
++  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
++
++  result = asn1_array2tree (CVE_2018_1000654_1_asn1_tab, &definitions, errorDescription);
++  if (result != ASN1_RECURSION)
++    {
++      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
++		  asn1_strerror (result), errorDescription);
++      return;
++    }
++
++  asn1_delete_structure (&definitions);
++
++  result = asn1_array2tree (CVE_2018_1000654_2_asn1_tab, &definitions, errorDescription);
++  if (result != ASN1_RECURSION)
++    {
++      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
++		  asn1_strerror (result), errorDescription);
++      return;
++    }
++
++  asn1_delete_structure (&definitions);
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c b/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c
+new file mode 100644
+index 0000000000..f48aea0ef8
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c
+@@ -0,0 +1,138 @@
++/*
++ * Copyright (C) 2012-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * 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 3 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/* Written by Simon Josefsson */
++
++#include <grub/libtasn1.h>
++#include <grub/err.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/types.h>
++#include "../wrap_tests.h"
++
++void
++test_overflow(void)
++{
++  /* Test that values larger than long are rejected.  This has worked
++     fine with all versions of libtasn1. */
++
++  {
++    unsigned char der[] = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
++    long l;
++    int len;
++
++    l = asn1_get_length_der (der, sizeof der, &len);
++
++    if (l != -2L)
++      {
++	grub_fatal ("ERROR: asn1_get_length_der bignum (l %ld len %d)\n", l, len);
++	return;
++      }
++  }
++
++  /* Test that values larger than int but smaller than long are
++     rejected.  This limitation was introduced with libtasn1 2.12. */
++#if (GRUB_LONG_MAX > GRUB_INT_MAX)
++    {
++      unsigned long num = ((long) GRUB_UINT_MAX) << 2;
++      unsigned char der[20];
++      int der_len;
++      long l;
++      int len;
++
++      asn1_length_der (num, der, &der_len);
++
++      l = asn1_get_length_der (der, der_len, &len);
++
++      if (l != -2L)
++	{
++	  grub_fatal ("ERROR: asn1_get_length_der intnum (l %ld len %d)\n", l,
++		      len);
++	  return;
++	}
++    }
++#endif
++
++  /* Test that values larger than would fit in the input string are
++     rejected.  This problem was fixed in libtasn1 2.12. */
++  {
++    unsigned long num = 64;
++    unsigned char der[20];
++    int der_len;
++    long l;
++    int len;
++
++    asn1_length_der (num, der, &der_len);
++
++    der_len = sizeof (der);
++    l = asn1_get_length_der (der, der_len, &len);
++
++    if (l != -4L)
++      {
++	grub_fatal ("ERROR: asn1_get_length_der overflow-small (l %ld len %d)\n",
++		    l, len);
++	return;
++      }
++  }
++
++  /* Test that values larger than would fit in the input string are
++     rejected.  This problem was fixed in libtasn1 2.12. */
++  {
++    unsigned long num = 1073741824;
++    unsigned char der[20];
++    int der_len;
++    long l;
++    int len;
++
++    asn1_length_der (num, der, &der_len);
++
++    der_len = sizeof (der);
++    l = asn1_get_length_der (der, der_len, &len);
++
++    if (l != -4L)
++      {
++	grub_fatal ("ERROR: asn1_get_length_der overflow-large1 (l %ld len %d)\n",
++		    l, len);
++	return;
++      }
++  }
++
++  /* Test that values larger than would fit in the input string are
++     rejected.  This problem was fixed in libtasn1 2.12. */
++  {
++    unsigned long num = 2147483649;
++    unsigned char der[20];
++    int der_len;
++    long l;
++    int len;
++
++    asn1_length_der (num, der, &der_len);
++
++    der_len = sizeof (der);
++    l = asn1_get_length_der (der, der_len, &len);
++
++    if (l != -2L)
++      {
++	grub_fatal ("ERROR: asn1_get_length_der overflow-large2 (l %ld len %d)\n",
++		    l, len);
++	return;
++      }
++  }
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_simple.c b/grub-core/lib/libtasn1_wrap/tests/Test_simple.c
+new file mode 100644
+index 0000000000..9f01006ddf
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/Test_simple.c
+@@ -0,0 +1,207 @@
++/*
++ * Copyright (C) 2011-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * 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 3 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, see <http://www.gnu.org/licenses/>.
++ *
++ * Written by Simon Josefsson
++ *
++ */
++
++#include <grub/libtasn1.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/err.h>
++#include "../wrap_tests.h"
++
++struct tv
++{
++  int bitlen;
++  const char *bitstr;
++  int derlen;
++  const char *der;
++};
++
++static const struct tv tv[] = {
++  {0, "", 2, "\x01\x00"},
++  {1, "\x00", 3, "\x02\x07\x00"},
++  {2, "\x00", 3, "\x02\x06\x00"},
++  {3, "\x00", 3, "\x02\x05\x00"},
++  {4, "\x00", 3, "\x02\x04\x00"},
++  {5, "\x00", 3, "\x02\x03\x00"},
++  {6, "\x00", 3, "\x02\x02\x00"},
++  {7, "\x00", 3, "\x02\x01\x00"},
++  {8, "\x00\x00", 3, "\x02\x00\x00"},
++  {9, "\x00\x00", 4, "\x03\x07\x00\x00"},
++  {10, "\x00\x00", 4, "\x03\x06\x00\x00"},
++  {11, "\x00\x00", 4, "\x03\x05\x00\x00"},
++  {12, "\x00\x00", 4, "\x03\x04\x00\x00"},
++  {13, "\x00\x00", 4, "\x03\x03\x00\x00"},
++  {14, "\x00\x00", 4, "\x03\x02\x00\x00"},
++  {15, "\x00\x00", 4, "\x03\x01\x00\x00"},
++  {16, "\x00\x00", 4, "\x03\x00\x00\x00"},
++  {17, "\x00\x00\x00", 5, "\x04\x07\x00\x00\x00"},
++  {18, "\x00\x00\x00", 5, "\x04\x06\x00\x00\x00"},
++  {19, "\x00\x00\x00", 5, "\x04\x05\x00\x00\x00"},
++  {1, "\xFF", 3, "\x02\x07\x80"},
++  {2, "\xFF", 3, "\x02\x06\xc0"},
++  {3, "\xFF", 3, "\x02\x05\xe0"},
++  {4, "\xFF", 3, "\x02\x04\xf0"},
++  {5, "\xFF", 3, "\x02\x03\xf8"},
++  {6, "\xFF", 3, "\x02\x02\xfc"},
++  {7, "\xFF", 3, "\x02\x01\xfe"},
++  {8, "\xFF\xFF", 3, "\x02\x00\xff"},
++  {9, "\xFF\xFF", 4, "\x03\x07\xff\x80"},
++  {10, "\xFF\xFF", 4, "\x03\x06\xff\xc0"},
++  {11, "\xFF\xFF", 4, "\x03\x05\xff\xe0"},
++  {12, "\xFF\xFF", 4, "\x03\x04\xff\xf0"},
++  {13, "\xFF\xFF", 4, "\x03\x03\xff\xf8"},
++  {14, "\xFF\xFF", 4, "\x03\x02\xff\xfc"},
++  {15, "\xFF\xFF", 4, "\x03\x01\xff\xfe"},
++  {16, "\xFF\xFF", 4, "\x03\x00\xff\xff"},
++  {17, "\xFF\xFF\xFF", 5, "\x04\x07\xff\xff\x80"},
++  {18, "\xFF\xFF\xFF", 5, "\x04\x06\xff\xff\xc0"},
++  {19, "\xFF\xFF\xFF", 5, "\x04\x05\xff\xff\xe0"},
++};
++
++void
++test_simple (void)
++{
++  int result;
++  unsigned char der[100];
++  unsigned char str[100];
++  int der_len = sizeof (der);
++  int str_size = sizeof (str);
++  int ret_len, bit_len;
++  grub_size_t i;
++
++  /* Dummy test */
++
++  asn1_bit_der (NULL, 0, der, &der_len);
++  result = asn1_get_bit_der (der, 0, &ret_len, str, str_size, &bit_len);
++  if (result != ASN1_GENERIC_ERROR)
++    {
++      grub_fatal ("asn1_get_bit_der zero\n");
++      return;
++    }
++
++  /* Encode short strings with increasing bit lengths */
++
++  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
++    {
++      /* Encode */
++
++      asn1_bit_der ((const unsigned char *) tv[i].bitstr, tv[i].bitlen,
++		    der, &der_len);
++
++#if 0
++      {
++	size_t j;
++	for (j = 0; j < der_len; j++)
++	  printf ("\\x%02x", der[j]);
++	printf ("\n");
++      }
++#endif
++
++      if (der_len != tv[i].derlen || grub_memcmp (der, tv[i].der, der_len) != 0)
++	{
++	  grub_fatal ("asn1_bit_der iter %lu\n", (unsigned long) i);
++	  return;
++	}
++
++      /* Decode it */
++
++      result = asn1_get_bit_der (der, der_len, &ret_len, str,
++				 str_size, &bit_len);
++      if (result != ASN1_SUCCESS || ret_len != tv[i].derlen
++	  || bit_len != tv[i].bitlen)
++	{
++	  grub_fatal ("asn1_get_bit_der iter %lu, err: %d\n", (unsigned long) i, result);
++	  return;
++	}
++    }
++
++
++  /* Decode sample from "A Layman's Guide to a Subset of ASN.1, BER,
++     and DER" section 5.4 "BIT STRING": "The BER encoding of the BIT
++     STRING value "011011100101110111" can be any of the following,
++     among others, depending on the choice of padding bits, the form
++     of length octets [...]".
++   */
++
++  /* 03 04 06 6e 5d c0  DER encoding */
++
++  grub_memcpy (der, "\x04\x06\x6e\x5d\xc0", 5);
++  der_len = 5;
++
++  result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
++  if (result != ASN1_SUCCESS || ret_len != 5
++      || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0)
++    {
++      grub_fatal ("asn1_get_bit_der example\n");
++      return;
++    }
++
++  der_len = sizeof (der);
++  asn1_bit_der (str, bit_len, der, &der_len);
++  if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
++    {
++      grub_fatal ("asn1_bit_der example roundtrip\n");
++      return;
++    }
++
++  /* 03 04 06 6e 5d e0 padded with "100000" */
++
++  grub_memcpy (der, "\x04\x06\x6e\x5d\xe0", 5);
++  der_len = 5;
++
++  result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
++  if (result != ASN1_SUCCESS || ret_len != 5
++      || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xe0", 3) != 0)
++    {
++      grub_fatal ("asn1_get_bit_der example padded\n");
++      return;
++    }
++
++  der_len = sizeof (der);
++  asn1_bit_der (str, bit_len, der, &der_len);
++  if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
++    {
++      grub_fatal ("asn1_bit_der example roundtrip\n");
++      return;
++    }
++
++  /* 03 81 04 06 6e 5d c0 long form of length octets */
++
++  grub_memcpy (der, "\x81\x04\x06\x6e\x5d\xc0", 6);
++  der_len = 6;
++
++  result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
++
++  if (result != ASN1_SUCCESS || ret_len != 6
++      || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0)
++    {
++      grub_fatal ("asn1_get_bit_der example long form\n");
++      return;
++    }
++
++  der_len = sizeof (der);
++  asn1_bit_der (str, bit_len, der, &der_len);
++  if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
++    {
++      grub_fatal ("asn1_bit_der example roundtrip\n");
++      return;
++    }
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_strings.c b/grub-core/lib/libtasn1_wrap/tests/Test_strings.c
+new file mode 100644
+index 0000000000..dbe1474b20
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/Test_strings.c
+@@ -0,0 +1,150 @@
++/*
++ * Copyright (C) 2012-2014 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * 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 3 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, see <http://www.gnu.org/licenses/>.
++ *
++ * Written by Simon Josefsson
++ *
++ */
++
++#include <grub/mm.h>
++#include <grub/err.h>
++#include <grub/misc.h>
++#include <grub/libtasn1.h>
++#include "../wrap_tests.h"
++
++struct tv
++{
++  unsigned int etype;
++  unsigned int str_len;
++  const void *str;
++  unsigned int der_len;
++  const void *der;
++};
++
++static const struct tv tv[] = {
++  {ASN1_ETYPE_IA5_STRING, 20,
++   "\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72",
++   22,
++   "\x16\x14\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72"},
++  {ASN1_ETYPE_PRINTABLE_STRING, 5, "\x4e\x69\x6b\x6f\x73",
++   7, "\x13\x05\x4e\x69\x6b\x6f\x73"},
++  {ASN1_ETYPE_UTF8_STRING, 12, "Αττική",
++   14, "\x0c\x0c\xce\x91\xcf\x84\xcf\x84\xce\xb9\xce\xba\xce\xae"},
++  {ASN1_ETYPE_TELETEX_STRING, 15,
++   "\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e",
++   17,
++   "\x14\x0f\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e"},
++  {ASN1_ETYPE_OCTET_STRING, 36,
++   "\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A",
++   38,
++   "\x04\x24\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A"}
++};
++
++#define SSTR(x) sizeof(x)-1,x
++static const struct tv ber[] = {
++  {ASN1_ETYPE_OCTET_STRING,
++   SSTR("\xa0\xa0"),
++   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x00\x00")},
++  {ASN1_ETYPE_OCTET_STRING,
++   SSTR("\xa0\xa0\xb0\xb0\xb0"),
++   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x00\x00")},
++  {ASN1_ETYPE_OCTET_STRING,
++   SSTR("\xa0\xa0\xb0\xb0\xb0\xa1\xa1"),
++   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x00\x00\x00\x00")},
++  {ASN1_ETYPE_OCTET_STRING,
++   SSTR("\xa0\xa0\xb0\xb0\xb0\xa1\xa1\xc1"),
++   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x04\x82\x00\x01\xc1\x00\x00\x00\x00")},
++};
++
++void
++test_strings ()
++{
++  int ret;
++  unsigned char tl[ASN1_MAX_TL_SIZE];
++  unsigned int tl_len, der_len, str_len;
++  const unsigned char *str;
++  unsigned char *b;
++  unsigned int i;
++
++  /* Dummy test */
++
++  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
++    {
++      /* Encode */
++      tl_len = sizeof (tl);
++      ret = asn1_encode_simple_der (tv[i].etype, tv[i].str, tv[i].str_len,
++				    tl, &tl_len);
++      if (ret != ASN1_SUCCESS)
++	{
++	  grub_fatal ("Encoding error in %u: %s\n", i,
++		   asn1_strerror (ret));
++	  return;
++	}
++      der_len = tl_len + tv[i].str_len;
++
++      if (der_len != tv[i].der_len || grub_memcmp (tl, tv[i].der, tl_len) != 0)
++	{
++	  grub_fatal (
++		   "DER encoding differs in %u! (size: %u, expected: %u)\n",
++		   i, der_len, tv[i].der_len);
++	  return;
++	}
++
++      /* decoding */
++      ret =
++	asn1_decode_simple_der (tv[i].etype, tv[i].der, tv[i].der_len, &str,
++				&str_len);
++      if (ret != ASN1_SUCCESS)
++	{
++	  grub_fatal ("Decoding error in %u: %s\n", i,
++		   asn1_strerror (ret));
++	  return;
++	}
++
++      if (str_len != tv[i].str_len || grub_memcmp (str, tv[i].str, str_len) != 0)
++	{
++	  grub_fatal (
++		   "DER decoded data differ in %u! (size: %u, expected: %u)\n",
++		   i, der_len, tv[i].str_len);
++	  return;
++	}
++    }
++
++  /* BER decoding */
++  for (i = 0; i < sizeof (ber) / sizeof (ber[0]); i++)
++    {
++      /* decoding */
++      ret =
++	asn1_decode_simple_ber (ber[i].etype, ber[i].der, ber[i].der_len, &b,
++				&str_len, NULL);
++      if (ret != ASN1_SUCCESS)
++	{
++	  grub_fatal ("BER decoding error in %u: %s\n", i,
++		   asn1_strerror (ret));
++	  return;
++	}
++
++      if (str_len != ber[i].str_len || grub_memcmp (b, ber[i].str, str_len) != 0)
++	{
++	  grub_fatal (
++		   "BER decoded data differ in %u! (size: %u, expected: %u)\n",
++		   i, str_len, ber[i].str_len);
++	  return;
++	}
++      grub_free(b);
++    }
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c b/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c
+new file mode 100644
+index 0000000000..d367bbfb5a
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c
+@@ -0,0 +1,116 @@
++/*
++ * Copyright (C) 2016 Red Hat, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * 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 3 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <grub/libtasn1.h>
++#include <grub/types.h>
++#include <grub/misc.h>
++#include <grub/err.h>
++#include "../wrap_tests.h"
++
++struct tv
++{
++  int der_len;
++  const unsigned char *der;
++  const char *oid;
++  int expected_error;
++};
++
++static const struct tv tv[] = {
++  {.der_len = 5,
++   .der = (void *) "\x06\x03\x80\x37\x03",
++   .oid = "2.999.3",
++   .expected_error = ASN1_DER_ERROR /* leading 0x80 */
++  },
++  {.der_len = 12,
++   .der = (void *) "\x06\x0a\x2b\x06\x01\x80\x01\x92\x08\x09\x05\x01",
++   .oid = "1.3.6.1.4.1.2312.9.5.1",
++   .expected_error = ASN1_DER_ERROR /* leading 0x80 */
++  },
++  {.der_len = 6,
++   .der = (void *) "\x06\x04\x01\x02\x03\x04",
++   .oid = "0.1.2.3.4",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 5,
++   .der = (void *) "\x06\x03\x51\x02\x03",
++   .oid = "2.1.2.3",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 5,
++   .der = (void *) "\x06\x03\x88\x37\x03",
++   .oid = "2.999.3",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 12,
++   .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01",
++   .oid = "1.3.6.1.4.1.2312.9.5.1",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 19,
++   .der = (void *) "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d",
++   .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 19,
++   .der =
++   (void *)
++   "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07",
++   .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7",
++   .expected_error = ASN1_SUCCESS},
++};
++
++void
++test_object_id_decoding (void)
++{
++  char str[128];
++  int ret, ret_len;
++  grub_size_t i;
++
++  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
++    {
++      /* decode */
++      ret =
++	asn1_get_object_id_der (tv[i].der+1,
++				tv[i].der_len-1, &ret_len, str,
++				sizeof (str));
++      if (ret != tv[i].expected_error)
++	{
++	  grub_fatal (
++		   "%d: asn1_get_object_id_der iter %lu: got '%s' expected %d\n",
++		   __LINE__, (unsigned long) i, asn1_strerror(ret), tv[i].expected_error);
++	  return;
++	}
++
++      if (tv[i].expected_error != ASN1_SUCCESS)
++        continue;
++
++      if (ret_len != tv[i].der_len-1)
++	{
++	  grub_fatal (
++		   "%d: iter %lu: error in DER, length returned is %d, had %d\n",
++		   __LINE__, (unsigned long)i, ret_len, tv[i].der_len-1);
++	  return;
++	}
++
++      if (grub_strcmp (tv[i].oid, str) != 0)
++	{
++	  grub_fatal (
++		   "%d: strcmp iter %lu: got invalid OID: %s, expected: %s\n",
++		   __LINE__, (unsigned long) i, str, tv[i].oid);
++	  return;
++	}
++
++    }
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c b/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c
+new file mode 100644
+index 0000000000..3a83b58c59
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c
+@@ -0,0 +1,120 @@
++/*
++ * Copyright (C) 2019 Nikos Mavrogiannopoulos
++ *
++ * This file is part of LIBTASN1.
++ *
++ * 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 3 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include <grub/libtasn1.h>
++#include <grub/types.h>
++#include <grub/misc.h>
++#include <grub/err.h>
++#include "../wrap_tests.h"
++
++struct tv
++{
++  int der_len;
++  const unsigned char *der;
++  const char *oid;
++  int expected_error;
++};
++
++static const struct tv tv[] = {
++  {.der_len = 0,
++   .der = (void *) "",
++   .oid = "5.999.3",
++   .expected_error = ASN1_VALUE_NOT_VALID /* cannot start with 5 */
++  },
++  {.der_len = 0,
++   .der = (void *) "",
++   .oid = "0.48.9",
++   .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 48 */
++  },
++  {.der_len = 0,
++   .der = (void *) "",
++   .oid = "1.40.9",
++   .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 40 */
++  },
++  {.der_len = 4,
++   .der = (void *) "\x06\x02\x4f\x63",
++   .oid = "1.39.99",
++   .expected_error = ASN1_SUCCESS,
++  },
++  {.der_len = 6,
++   .der = (void *) "\x06\x04\x01\x02\x03\x04",
++   .oid = "0.1.2.3.4",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 5,
++   .der = (void *) "\x06\x03\x51\x02\x03",
++   .oid = "2.1.2.3",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 5,
++   .der = (void *) "\x06\x03\x88\x37\x03",
++   .oid = "2.999.3",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 12,
++   .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01",
++   .oid = "1.3.6.1.4.1.2312.9.5.1",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 19,
++   .der = (void *) "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d",
++   .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109",
++   .expected_error = ASN1_SUCCESS},
++  {.der_len = 19,
++   .der =
++   (void *)
++   "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07",
++   .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7",
++   .expected_error = ASN1_SUCCESS},
++};
++
++void
++test_object_id_encoding(void)
++{
++  unsigned char der[128];
++  int ret, der_len, i;
++
++  for (i = 0; i < (int)(sizeof (tv) / sizeof (tv[0])); i++)
++    {
++      der_len = sizeof(der);
++      ret = asn1_object_id_der(tv[i].oid, der, &der_len, 0);
++      if (ret != ASN1_SUCCESS)
++	{
++	  if (ret == tv[i].expected_error)
++	    continue;
++	  grub_fatal (
++		   "%d: iter %lu, encoding of OID failed: %s\n",
++		   __LINE__, (unsigned long) i, asn1_strerror(ret));
++	  return;
++	}
++      else if (ret != tv[i].expected_error)
++        {
++	  grub_fatal (
++		   "%d: iter %lu, encoding of OID %s succeeded when expecting failure\n",
++		   __LINE__, (unsigned long) i, tv[i].oid);
++          return;
++        }
++
++      if (der_len != tv[i].der_len || grub_memcmp(der, tv[i].der, der_len) != 0)
++	{
++	  grub_fatal (
++		   "%d: iter %lu, re-encoding of OID %s resulted to different string (%d vs %d bytes)\n",
++		   __LINE__, (unsigned long) i, tv[i].oid, der_len, tv[i].der_len);
++
++	  return;
++	}
++    }
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/octet-string.c b/grub-core/lib/libtasn1_wrap/tests/octet-string.c
+new file mode 100644
+index 0000000000..d8a049e8df
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/octet-string.c
+@@ -0,0 +1,211 @@
++/*
++ * Copyright (C) 2011-2020 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * 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 3 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, see <http://www.gnu.org/licenses/>.
++ *
++ * Written by Simon Josefsson and Nikos Mavrogiannopoulos
++ *
++ */
++
++#include <grub/libtasn1.h>
++#include <grub/err.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include "../wrap_tests.h"
++
++
++struct tv
++{
++  const char *name;
++  int der_len;
++  const unsigned char *der_str;
++  int len;
++  const unsigned char *string;
++  int expected_error;
++  int ber;
++};
++
++static const struct tv tv[] = {
++  {.name = "primitive octet strings",
++   .der_len = 10,
++   .der_str =
++   (void*)"\x04\x08\x01\x23\x45\x67\x89\xab\xcd\xef",
++   .len = 8,
++   .string =
++   (void*)"\x01\x23\x45\x67\x89\xab\xcd\xef",
++   .ber = 0},
++  {.der_len = 22,
++   .der_str =
++   (void*)"\x04\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27",
++   .len = 20,
++   .string =
++   (void*)"\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27"},
++
++  {.name = "long type of length",
++   .der_len = 23,
++   .der_str =
++   (void*)"\x04\x81\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27",
++   .len = 20,
++   .string =
++   (void*)"\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27",
++   .ber = 1},
++  {.der_len = 11,
++   .der_str =
++   (void*)"\x04\x81\x08\x01\x23\x45\x67\x89\xab\xcd\xef",
++   .len = 8,
++   .string =
++   (void*)"\x01\x23\x45\x67\x89\xab\xcd\xef",
++   .ber = 1},
++
++  {.name = "constructed - indefinite",
++   .der_len = 11,
++   .der_str = (void*)"\x24\x80\x04\x05\x01\x02\x03\x04\x05\x00\x00",
++   .len = 5,
++   .string = (void*)"\x01\x02\x03\x04\x05",
++   .ber = 1,
++   },
++
++  {.name = "constructed - definite - concat",
++   .der_len = 12,
++   .der_str = (void*)"\x24\x0a\x04\x04\x0a\x0b\x0c\x0d\x04\x02\x0e\x0f",
++   .len = 6,
++   .string = (void*)"\x0a\x0b\x0c\x0d\x0e\x0f",
++   .ber = 1,
++   },
++  {.name = "constructed - definite - recursive",
++   .der_len = 15,
++   .der_str = (void*)"\x24\x0d\x04\x04\x0a\x0b\x0c\x0d\x24\x05\x04\x00\x04\x01\x0f",
++   .len = 5,
++   .string = (void*)"\x0a\x0b\x0c\x0d\x0f",
++   .ber = 1,
++   },
++  {.name = "constructed - definite - single",
++   .der_len = 7,
++   .der_str = (void*)"\x24\x05\x04\x03\x01\x02\x03",
++   .len = 3,
++   .string = (void*)"\x01\x02\x03",
++   .ber = 1,
++   },
++
++  /* a large amount of recursive indefinite encoding */
++  {.name = "a large amount of recursive indefinite encoding",
++   .der_len = 29325,
++   .der_str = (void*)"\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80",
++   .len = 0,
++   .ber = 1,
++   .expected_error = ASN1_DER_ERROR
++   }
++};
++
++void
++test_octet_string (void)
++{
++  unsigned char str[100];
++  unsigned char der[100];
++  int der_len = sizeof (der);
++  int str_size = sizeof (str);
++  unsigned char *tmp = NULL;
++  int ret, ret_len;
++  grub_size_t i;
++
++  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
++    {
++      /* Decode */
++
++      if (tv[i].ber == 0)
++	{
++	  str_size = sizeof (str);
++	  ret =
++	    asn1_get_octet_der (tv[i].der_str + 1,
++				tv[i].der_len - 1, &ret_len, str,
++				sizeof (str), &str_size);
++	  if (ret != tv[i].expected_error)
++	    {
++	      grub_fatal (
++		       "%d: asn1_get_octet_der: %s: got %d expected %d\n",
++		       __LINE__, tv[i].name, ret,
++		       tv[i].expected_error);
++	      return;
++	    }
++	  if (tv[i].expected_error)
++	    continue;
++
++	  if (ret_len != tv[i].der_len - 1)
++	    {
++	      grub_fatal (
++		       "%d: error in DER, length returned is %d, had %d\n",
++		       __LINE__, ret_len, tv[i].der_len - 1);
++	      return;
++	    }
++
++	  if (str_size != tv[i].len
++	      || grub_memcmp (tv[i].string, str, tv[i].len) != 0)
++	    {
++	      grub_fatal (
++		       "%d: memcmp: %s: got invalid decoding\n",
++		       __LINE__, tv[i].name);
++
++              return;
++	    }
++
++	  /* Encode */
++	  der_len = sizeof (der);
++	  asn1_octet_der (str, str_size, der, &der_len);
++
++	  if (der_len != tv[i].der_len - 1
++	      || grub_memcmp (tv[i].der_str + 1, der, tv[i].der_len - 1) != 0)
++	    {
++	      grub_fatal (
++		       "encoding: %s: got invalid encoding\n",
++		       tv[i].name);
++	      return;
++	    }
++	}
++
++      ret =
++	asn1_decode_simple_ber (ASN1_ETYPE_OCTET_STRING,
++				tv[i].der_str, tv[i].der_len,
++				&tmp, (unsigned int*)&str_size, (unsigned int*)&der_len);
++      if (ret != tv[i].expected_error)
++	{
++	  grub_fatal (
++		   "%d: asn1_decode_simple_ber: %s: got %s expected %s\n",
++		   __LINE__, tv[i].name, asn1_strerror(ret), asn1_strerror(tv[i].expected_error));
++	  return;
++	}
++      if (tv[i].expected_error)
++        continue;
++
++      if (der_len != tv[i].der_len)
++	{
++	  grub_fatal (
++		   "%d: error: %s: DER, length returned is %d, had %d\n",
++		   __LINE__, tv[i].name, der_len, tv[i].der_len);
++	  return;
++	}
++
++      if (str_size != tv[i].len || grub_memcmp (tv[i].string, tmp, tv[i].len) != 0)
++	{
++	  grub_fatal (
++		   "%d: memcmp: %s: got invalid decoding\n",
++		   __LINE__, tv[i].name);
++          return;
++	}
++      grub_free (tmp);
++      tmp = NULL;
++
++    }
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/reproducers.c b/grub-core/lib/libtasn1_wrap/tests/reproducers.c
+new file mode 100644
+index 0000000000..dc7268d4c6
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/reproducers.c
+@@ -0,0 +1,81 @@
++/*
++ * Copyright (C) 2019 Free Software Foundation, Inc.
++ *
++ * This file is part of LIBTASN1.
++ *
++ * 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 3 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, see <http://www.gnu.org/licenses/>.
++ *
++ */
++
++/****************************************************************/
++/* Description: run reproducers for several fixed issues        */
++/****************************************************************/
++
++#include <grub/libtasn1.h>
++#include <grub/err.h>
++#include <grub/mm.h>
++#include "../wrap_tests.h"
++
++#define CONST_DOWN        (1U<<29)
++
++/* produces endless loop (fixed by d4b624b2):
++ * The following translates into a single node with all pointers
++ * (right,left,down) set to NULL. */
++const asn1_static_node endless_asn1_tab[] = {
++  { "TEST_TREE", 536875024, NULL },
++  { NULL, 0, NULL }
++};
++
++/* produces memory leak (fixed by f16d1ff9):
++ * 152 bytes in 1 blocks are definitely lost in loss record 1 of 1
++ *    at 0x4837B65: calloc (vg_replace_malloc.c:762)
++ *    by 0x4851C0D: _asn1_add_static_node (parser_aux.c:71)
++ *    by 0x4853AAC: asn1_array2tree (structure.c:200)
++ *    by 0x10923B: main (single_node.c:67)
++ */
++const asn1_static_node tab[] = {
++{ "a", CONST_DOWN, "" },
++{ "b", 0, "" },
++{ "c", 0, "" },
++{ NULL, 0, NULL }
++};
++
++void
++test_reproducers (void)
++{
++  int result;
++  asn1_node definitions = NULL;
++  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
++
++  result = asn1_array2tree (endless_asn1_tab, &definitions, errorDescription);
++  if (result != ASN1_SUCCESS)
++    {
++      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
++		  asn1_strerror (result), errorDescription);
++      return;
++    }
++
++  asn1_delete_structure (&definitions);
++
++  definitions = NULL;
++  result = asn1_array2tree (tab, &definitions, errorDescription);
++  if (result != ASN1_SUCCESS)
++    {
++      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
++		  asn1_strerror (result), errorDescription);
++      return;
++    }
++
++  asn1_delete_structure (&definitions);
++}
+diff --git a/grub-core/lib/libtasn1_wrap/wrap_tests.c b/grub-core/lib/libtasn1_wrap/wrap_tests.c
+new file mode 100644
+index 0000000000..75fcd21f0d
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/wrap_tests.c
+@@ -0,0 +1,75 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020 IBM Corporation
++ *
++ *  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/mm.h>
++#include "wrap_tests.h"
++
++/*
++ * libtasn1 tests - from which this is derived - are provided under GPL3+.
++ */
++GRUB_MOD_LICENSE ("GPLv3+");
++
++static grub_command_t cmd;
++
++static grub_err_t
++grub_cmd_asn1test (grub_command_t cmdd __attribute__((unused)),
++		   int argc __attribute__((unused)),
++		   char **args __attribute__((unused)))
++{
++  grub_printf ("test_CVE_2018_1000654\n");
++  test_CVE_2018_1000654 ();
++
++  grub_printf ("test_object_id_decoding\n");
++  test_object_id_decoding ();
++
++  grub_printf ("test_object_id_encoding\n");
++  test_object_id_encoding ();
++
++  grub_printf ("test_octet_string\n");
++  test_octet_string ();
++
++  grub_printf ("test_overflow\n");
++  test_overflow ();
++
++  grub_printf ("test_reproducers\n");
++  test_overflow ();
++
++  grub_printf ("test_simple\n");
++  test_simple ();
++
++  grub_printf ("test_strings\n");
++  test_strings ();
++
++  grub_printf ("ASN.1 self-tests passed\n");
++
++  return GRUB_ERR_NONE;
++}
++
++
++GRUB_MOD_INIT(test_asn1)
++{
++  cmd = grub_register_command ("test_asn1", grub_cmd_asn1test, NULL,
++			       "Run self-tests for the ASN.1 parser.");
++}
++
++GRUB_MOD_FINI(test_asn1)
++{
++  grub_unregister_command (cmd);
++}
+diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h
+new file mode 100644
+index 0000000000..1e7d3d64f5
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h
+@@ -0,0 +1,32 @@
++#if HAVE_CONFIG_H
++# include "config.h"
++#endif
++
++#include <grub/libtasn1.h>
++
++const asn1_static_node CVE_2018_1000654_1_asn1_tab[] = {
++  { "TEST_TREE", 536875024, NULL },
++  { NULL, 1610612748, NULL },
++  { "iso", 1073741825, "1"},
++  { "identified-organization", 1073741825, "3"},
++  { "dod", 1073741825, "6"},
++  { "internet", 1073741825, "1"},
++  { "security", 1073741825, "5"},
++  { "mechanisms", 1073741825, "5"},
++  { "pkix", 1073741825, "7"},
++  { "id-mod", 1073741825, "0"},
++  { "id-pkix1-implicit-88", 1, "2"},
++  { "id-xnyTest", 1879048204, NULL },
++  { NULL, 1073741825, "id-ix"},
++  { NULL, 1073741825, "29"},
++  { NULL, 1, "1"},
++  { "id-ix", 1880096780, "OBJECR"},
++  { NULL, 1073741825, "id-ix"},
++  { NULL, 1073741825, "29"},
++  { NULL, 1, "2"},
++  { "id-xnyTest", 805306380, NULL },
++  { NULL, 1073741825, "id-ix"},
++  { NULL, 1073741825, "29"},
++  { NULL, 1, "1"},
++  { NULL, 0, NULL }
++};
+diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h
+new file mode 100644
+index 0000000000..e2561e5ec6
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h
+@@ -0,0 +1,36 @@
++#if HAVE_CONFIG_H
++# include "config.h"
++#endif
++
++#include <grub/libtasn1.h>
++
++const asn1_static_node CVE_2018_1000654_2_asn1_tab[] = {
++  { "TEST_TREE", 536875024, NULL },
++  { NULL, 1610612748, NULL },
++  { "iso", 1073741825, "1"},
++  { "identified-organization", 1073741825, "3"},
++  { "dod", 1073741825, "6"},
++  { "internet", 1073741825, "1"},
++  { "security", 1073741825, "5"},
++  { "mechanisms", 1073741825, "5"},
++  { "pkix", 1073741825, "7"},
++  { "id-mod", 1073741825, "0"},
++  { "id-pkix1-implicit-88", 1, "2"},
++  { "id-oneTest", 1879048204, NULL },
++  { NULL, 1073741825, "id-two"},
++  { NULL, 1073741825, "9"},
++  { NULL, 1, "1"},
++  { "id-two", 1879048204, NULL },
++  { NULL, 1073741825, "id-three"},
++  { NULL, 1073741825, "2"},
++  { NULL, 1, "2"},
++  { "id-three", 1879048204, NULL },
++  { NULL, 1073741825, "id-four"},
++  { NULL, 1073741825, "3"},
++  { NULL, 1, "3"},
++  { "id-four", 805306380, NULL },
++  { NULL, 1073741825, "id-two"},
++  { NULL, 1073741825, "3"},
++  { NULL, 1, "3"},
++  { NULL, 0, NULL }
++};
+diff --git a/grub-core/lib/libtasn1_wrap/wrap_tests.h b/grub-core/lib/libtasn1_wrap/wrap_tests.h
+new file mode 100644
+index 0000000000..555e56dd20
+--- /dev/null
++++ b/grub-core/lib/libtasn1_wrap/wrap_tests.h
+@@ -0,0 +1,38 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020 IBM Corporation
++ *
++ *  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/>.
++ */
++
++#ifndef LIBTASN1_WRAP_TESTS_H
++#define LIBTASN1_WRAP_TESTS_H
++
++void test_CVE_2018_1000654 (void);
++
++void test_object_id_encoding (void);
++
++void test_object_id_decoding (void);
++
++void test_octet_string (void);
++
++void test_overflow (void);
++
++void test_reproducers (void);
++
++void test_simple (void);
++
++void test_strings (void);
++
++#endif
+diff --git a/.gitignore b/.gitignore
+index 208d1d2325..1d005887e7 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -264,6 +264,7 @@ widthspec.bin
+ /stamp-h1
+ /syslinux_test
+ /tar_test
++/test_asn1
+ /test_sha512sum
+ /test_unset
+ /tests/syslinux/ubuntu10.04_grub.cfg
+diff --git a/tests/test_asn1.in b/tests/test_asn1.in
+new file mode 100644
+index 0000000000..8173c5c270
+--- /dev/null
++++ b/tests/test_asn1.in
+@@ -0,0 +1,12 @@
++#! @BUILD_SHEBANG@
++set -e
++
++. "@builddir@/grub-core/modinfo.sh"
++
++out=`echo test_asn1 | @builddir@/grub-shell`
++
++if [ "$(echo "$out" | tail -n 1)" != "ASN.1 self-tests passed" ]; then
++  echo "ASN.1 test failure: $out"
++  exit 1
++fi
++
diff --git a/SOURCES/0167-grub-install-support-embedding-x509-certificates.patch b/SOURCES/0167-grub-install-support-embedding-x509-certificates.patch
new file mode 100644
index 0000000..c4c35f4
--- /dev/null
+++ b/SOURCES/0167-grub-install-support-embedding-x509-certificates.patch
@@ -0,0 +1,253 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Alastair D'Silva <alastair@d-silva.org>
+Date: Mon, 6 Jul 2020 13:33:04 +1000
+Subject: [PATCH] grub-install: support embedding x509 certificates
+
+To support verification of appended signatures, we need a way to
+embed the necessary public keys. Existing appended signature schemes
+in the Linux kernel use X.509 certificates, so allow certificates to
+be embedded in the grub core image in the same way as PGP keys.
+
+Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/commands/pgp.c    |  2 +-
+ util/grub-install-common.c  | 23 ++++++++++++++++++++++-
+ util/grub-mkimage.c         | 15 +++++++++++++--
+ util/mkimage.c              | 38 ++++++++++++++++++++++++++++++++++++--
+ include/grub/kernel.h       |  4 +++-
+ include/grub/util/install.h |  7 +++++--
+ 6 files changed, 80 insertions(+), 9 deletions(-)
+
+diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
+index 355a43844a..b81ac0ae46 100644
+--- a/grub-core/commands/pgp.c
++++ b/grub-core/commands/pgp.c
+@@ -944,7 +944,7 @@ GRUB_MOD_INIT(pgp)
+     grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
+ 
+     /* Not an ELF module, skip.  */
+-    if (header->type != OBJ_TYPE_PUBKEY)
++    if (header->type != OBJ_TYPE_GPG_PUBKEY)
+       continue;
+ 
+     pseudo_file.fs = &pseudo_fs;
+diff --git a/util/grub-install-common.c b/util/grub-install-common.c
+index a74fee16e2..c603f5b308 100644
+--- a/util/grub-install-common.c
++++ b/util/grub-install-common.c
+@@ -460,6 +460,8 @@ static char **pubkeys;
+ static size_t npubkeys;
+ static char *sbat;
+ static int disable_shim_lock;
++static char **x509keys;
++static size_t nx509keys;
+ static grub_compression_t compression;
+ static size_t appsig_size;
+ 
+@@ -501,6 +503,12 @@ grub_install_parse (int key, char *arg)
+     case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK:
+       disable_shim_lock = 1;
+       return 1;
++    case 'x':
++      x509keys = xrealloc (x509keys,
++			  sizeof (x509keys[0])
++			  * (nx509keys + 1));
++      x509keys[nx509keys++] = xstrdup (arg);
++      return 1;
+ 
+     case GRUB_INSTALL_OPTIONS_VERBOSITY:
+       verbosity++;
+@@ -627,6 +635,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
+   for (pk = pubkeys; pk < pubkeys + npubkeys; pk++)
+     slen += 20 + grub_strlen (*pk);
+ 
++  for (pk = x509keys; pk < x509keys + nx509keys; pk++)
++    slen += 10 + grub_strlen (*pk);
++
+   for (md = modules.entries; *md; md++)
+     {
+       slen += 10 + grub_strlen (*md);
+@@ -655,6 +666,14 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
+       *p++ = ' ';
+     }
+ 
++  for (pk = x509keys; pk < x509keys + nx509keys; pk++)
++    {
++      p = grub_stpcpy (p, "--x509 '");
++      p = grub_stpcpy (p, *pk);
++      *p++ = '\'';
++      *p++ = ' ';
++    }
++
+   for (md = modules.entries; *md; md++)
+     {
+       *p++ = '\'';
+@@ -684,7 +703,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
+ 
+   grub_install_generate_image (dir, prefix, fp, outname,
+ 			       modules.entries, memdisk_path,
+-			       pubkeys, npubkeys, config_path, tgt,
++			       pubkeys, npubkeys,
++			       x509keys, nx509keys,
++			       config_path, tgt,
+ 			       note, appsig_size, compression, dtb, sbat,
+ 			       disable_shim_lock);
+   while (dc--)
+diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
+index 8a53310548..e1f1112784 100644
+--- a/util/grub-mkimage.c
++++ b/util/grub-mkimage.c
+@@ -75,7 +75,8 @@ static struct argp_option options[] = {
+    /* TRANSLATORS: "embed" is a verb (command description).  "*/
+   {"config",   'c', N_("FILE"), 0, N_("embed FILE as an early config"), 0},
+    /* TRANSLATORS: "embed" is a verb (command description).  "*/
+-  {"pubkey",   'k', N_("FILE"), 0, N_("embed FILE as public key for signature checking"), 0},
++  {"pubkey",   'k', N_("FILE"), 0, N_("embed FILE as public key for PGP signature checking"), 0},
++  {"x509",     'x', N_("FILE"), 0, N_("embed FILE as an x509 certificate for appended signature checking"), 0},
+   /* TRANSLATORS: NOTE is a name of segment.  */
+   {"note",   'n', 0, 0, N_("add NOTE segment for CHRP IEEE1275"), 0},
+   {"output",  'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0},
+@@ -124,6 +125,8 @@ struct arguments
+   char *dtb;
+   char **pubkeys;
+   size_t npubkeys;
++  char **x509keys;
++  size_t nx509keys;
+   char *font;
+   char *config;
+   char *sbat;
+@@ -206,6 +209,13 @@ argp_parser (int key, char *arg, struct argp_state *state)
+       arguments->pubkeys[arguments->npubkeys++] = xstrdup (arg);
+       break;
+ 
++    case 'x':
++      arguments->x509keys = xrealloc (arguments->x509keys,
++				      sizeof (arguments->x509keys[0])
++				      * (arguments->nx509keys + 1));
++      arguments->x509keys[arguments->nx509keys++] = xstrdup (arg);
++      break;
++
+     case 'c':
+       if (arguments->config)
+ 	free (arguments->config);
+@@ -332,7 +342,8 @@ main (int argc, char *argv[])
+   grub_install_generate_image (arguments.dir, arguments.prefix, fp,
+ 			       arguments.output, arguments.modules,
+ 			       arguments.memdisk, arguments.pubkeys,
+-			       arguments.npubkeys, arguments.config,
++			       arguments.npubkeys, arguments.x509keys,
++			       arguments.nx509keys, arguments.config,
+ 			       arguments.image_target, arguments.note,
+ 			       arguments.appsig_size, arguments.comp,
+ 			       arguments.dtb, arguments.sbat,
+diff --git a/util/mkimage.c b/util/mkimage.c
+index bab1227601..8319e8dfbd 100644
+--- a/util/mkimage.c
++++ b/util/mkimage.c
+@@ -867,7 +867,8 @@ void
+ grub_install_generate_image (const char *dir, const char *prefix,
+ 			     FILE *out, const char *outname, char *mods[],
+ 			     char *memdisk_path, char **pubkey_paths,
+-			     size_t npubkeys, char *config_path,
++			     size_t npubkeys, char **x509key_paths,
++			     size_t nx509keys, char *config_path,
+ 			     const struct grub_install_image_target_desc *image_target,
+ 			     int note, size_t appsig_size, grub_compression_t comp,
+ 			     const char *dtb_path, const char *sbat_path,
+@@ -913,6 +914,19 @@ grub_install_generate_image (const char *dir, const char *prefix,
+       }
+   }
+ 
++  {
++    size_t i;
++    for (i = 0; i < nx509keys; i++)
++      {
++	size_t curs;
++	curs = ALIGN_ADDR (grub_util_get_image_size (x509key_paths[i]));
++	grub_util_info ("the size of x509 public key %u is 0x%"
++			GRUB_HOST_PRIxLONG_LONG,
++			(unsigned) i, (unsigned long long) curs);
++	total_module_size += curs + sizeof (struct grub_module_header);
++      }
++  }
++
+   if (memdisk_path)
+     {
+       memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512);
+@@ -1034,7 +1048,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
+ 	curs = grub_util_get_image_size (pubkey_paths[i]);
+ 
+ 	header = (struct grub_module_header *) (kernel_img + offset);
+-	header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY);
++	header->type = grub_host_to_target32 (OBJ_TYPE_GPG_PUBKEY);
+ 	header->size = grub_host_to_target32 (curs + sizeof (*header));
+ 	offset += sizeof (*header);
+ 
+@@ -1043,6 +1057,26 @@ grub_install_generate_image (const char *dir, const char *prefix,
+       }
+   }
+ 
++  {
++    size_t i;
++    for (i = 0; i < nx509keys; i++)
++      {
++	size_t curs;
++	struct grub_module_header *header;
++
++	curs = grub_util_get_image_size (x509key_paths[i]);
++
++	header = (struct grub_module_header *) (kernel_img + offset);
++	header->type = grub_host_to_target32 (OBJ_TYPE_X509_PUBKEY);
++	header->size = grub_host_to_target32 (curs + sizeof (*header));
++	offset += sizeof (*header);
++
++	grub_util_load_image (x509key_paths[i], kernel_img + offset);
++	offset += ALIGN_ADDR (curs);
++      }
++  }
++
++
+   if (memdisk_path)
+     {
+       struct grub_module_header *header;
+diff --git a/include/grub/kernel.h b/include/grub/kernel.h
+index 55849777ea..98edc0863f 100644
+--- a/include/grub/kernel.h
++++ b/include/grub/kernel.h
+@@ -30,7 +30,9 @@ enum
+   OBJ_TYPE_PREFIX,
+   OBJ_TYPE_PUBKEY,
+   OBJ_TYPE_DTB,
+-  OBJ_TYPE_DISABLE_SHIM_LOCK
++  OBJ_TYPE_DISABLE_SHIM_LOCK,
++  OBJ_TYPE_GPG_PUBKEY,
++  OBJ_TYPE_X509_PUBKEY,
+ };
+ 
+ /* The module header.  */
+diff --git a/include/grub/util/install.h b/include/grub/util/install.h
+index cf4531e02b..51f3b13ac1 100644
+--- a/include/grub/util/install.h
++++ b/include/grub/util/install.h
+@@ -67,6 +67,8 @@
+       N_("SBAT metadata"), 0 },						\
+   { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0,	\
+       N_("disable shim_lock verifier"), 0 },				\
++  { "x509key",   'x', N_("FILE"), 0,					\
++      N_("embed FILE as an x509 certificate for signature checking"), 0}, \
+   { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\
+     "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \
+     1},                                                                 \
+@@ -188,8 +190,9 @@ void
+ grub_install_generate_image (const char *dir, const char *prefix,
+ 			     FILE *out,
+ 			     const char *outname, char *mods[],
+-			     char *memdisk_path, char **pubkey_paths,
+-			     size_t npubkeys,
++			     char *memdisk_path,
++			     char **pubkey_paths, size_t npubkeys,
++			     char **x509key_paths, size_t nx509keys,
+ 			     char *config_path,
+ 			     const struct grub_install_image_target_desc *image_target,
+ 			     int note, size_t appsig_size,
diff --git a/SOURCES/0167-systemd-integration.sh-Also-set-old-menu_show_once-g.patch b/SOURCES/0167-systemd-integration.sh-Also-set-old-menu_show_once-g.patch
deleted file mode 100644
index 9021de5..0000000
--- a/SOURCES/0167-systemd-integration.sh-Also-set-old-menu_show_once-g.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Hans de Goede <hdegoede@redhat.com>
-Date: Thu, 23 Jul 2020 09:27:36 +0200
-Subject: [PATCH] systemd-integration.sh: Also set old menu_show_once grubenv
- var
-
-Downstream RH / Fedora patch for compatibility with old, not (yet)
-regenerated grub.cfg files which miss the menu_show_once_timeout check.
-This older grubenv variable leads to a fixed timeout of 60 seconds.
-
-Note that the new menu_show_once_timeout will overrule these 60 seconds
-if both are set and the grub.cfg does have the menu_show_once_timeout
-check.
-
-Signed-off-by: Hans de Goede <hdegoede@redhat.com>
----
- util/systemd/systemd-integration.sh.in | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/util/systemd/systemd-integration.sh.in b/util/systemd/systemd-integration.sh.in
-index dc1218597bc..a4c071c5b0c 100644
---- a/util/systemd/systemd-integration.sh.in
-+++ b/util/systemd/systemd-integration.sh.in
-@@ -4,3 +4,8 @@ TIMEOUT_USEC=$(cat /run/systemd/reboot-to-boot-loader-menu)
- TIMEOUT=$(((TIMEOUT_USEC + 500000) / 1000000))
- 
- @grub_editenv@ - set menu_show_once_timeout=$TIMEOUT
-+
-+# Downstream RH / Fedora patch for compatibility with old, not (yet)
-+# regenerated grub.cfg files which miss the menu_show_once_timeout check
-+# this older grubenv variable leads to a fixed timeout of 60 seconds
-+@grub_editenv@ - set menu_show_once=1
diff --git a/SOURCES/0168-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch b/SOURCES/0168-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch
new file mode 100644
index 0000000..0ebc6c7
--- /dev/null
+++ b/SOURCES/0168-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch
@@ -0,0 +1,639 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 30 Jul 2020 01:35:10 +1000
+Subject: [PATCH] appended signatures: import GNUTLS's ASN.1 description files
+
+In order to parse PKCS#7 messages and X.509 certificates with libtasn1,
+we need some information about how they are encoded.
+
+We get these from GNUTLS, which has the benefit that they support the
+features we need and are well tested.
+
+The GNUTLS license is LGPLv2.1+, which is GPLv3 compatible, allowing
+us to import it without issue.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/commands/appendedsig/gnutls_asn1_tab.c | 121 ++++++
+ grub-core/commands/appendedsig/pkix_asn1_tab.c   | 484 +++++++++++++++++++++++
+ 2 files changed, 605 insertions(+)
+ create mode 100644 grub-core/commands/appendedsig/gnutls_asn1_tab.c
+ create mode 100644 grub-core/commands/appendedsig/pkix_asn1_tab.c
+
+diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
+new file mode 100644
+index 0000000000..ddd1314e63
+--- /dev/null
++++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
+@@ -0,0 +1,121 @@
++#include <grub/mm.h>
++#include <grub/libtasn1.h>
++
++const asn1_static_node gnutls_asn1_tab[] = {
++  { "GNUTLS", 536872976, NULL },
++  { NULL, 1073741836, NULL },
++  { "RSAPublicKey", 1610612741, NULL },
++  { "modulus", 1073741827, NULL },
++  { "publicExponent", 3, NULL },
++  { "RSAPrivateKey", 1610612741, NULL },
++  { "version", 1073741827, NULL },
++  { "modulus", 1073741827, NULL },
++  { "publicExponent", 1073741827, NULL },
++  { "privateExponent", 1073741827, NULL },
++  { "prime1", 1073741827, NULL },
++  { "prime2", 1073741827, NULL },
++  { "exponent1", 1073741827, NULL },
++  { "exponent2", 1073741827, NULL },
++  { "coefficient", 1073741827, NULL },
++  { "otherPrimeInfos", 16386, "OtherPrimeInfos"},
++  { "ProvableSeed", 1610612741, NULL },
++  { "algorithm", 1073741836, NULL },
++  { "seed", 7, NULL },
++  { "OtherPrimeInfos", 1612709899, NULL },
++  { "MAX", 1074266122, "1"},
++  { NULL, 2, "OtherPrimeInfo"},
++  { "OtherPrimeInfo", 1610612741, NULL },
++  { "prime", 1073741827, NULL },
++  { "exponent", 1073741827, NULL },
++  { "coefficient", 3, NULL },
++  { "AlgorithmIdentifier", 1610612741, NULL },
++  { "algorithm", 1073741836, NULL },
++  { "parameters", 541081613, NULL },
++  { "algorithm", 1, NULL },
++  { "DigestInfo", 1610612741, NULL },
++  { "digestAlgorithm", 1073741826, "DigestAlgorithmIdentifier"},
++  { "digest", 7, NULL },
++  { "DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"},
++  { "DSAPublicKey", 1073741827, NULL },
++  { "DSAParameters", 1610612741, NULL },
++  { "p", 1073741827, NULL },
++  { "q", 1073741827, NULL },
++  { "g", 3, NULL },
++  { "DSASignatureValue", 1610612741, NULL },
++  { "r", 1073741827, NULL },
++  { "s", 3, NULL },
++  { "DSAPrivateKey", 1610612741, NULL },
++  { "version", 1073741827, NULL },
++  { "p", 1073741827, NULL },
++  { "q", 1073741827, NULL },
++  { "g", 1073741827, NULL },
++  { "Y", 1073741827, NULL },
++  { "priv", 3, NULL },
++  { "DHParameter", 1610612741, NULL },
++  { "prime", 1073741827, NULL },
++  { "base", 1073741827, NULL },
++  { "privateValueLength", 16387, NULL },
++  { "ECParameters", 1610612754, NULL },
++  { "namedCurve", 12, NULL },
++  { "ECPrivateKey", 1610612741, NULL },
++  { "Version", 1073741827, NULL },
++  { "privateKey", 1073741831, NULL },
++  { "parameters", 1610637314, "ECParameters"},
++  { NULL, 2056, "0"},
++  { "publicKey", 536895494, NULL },
++  { NULL, 2056, "1"},
++  { "PrincipalName", 1610612741, NULL },
++  { "name-type", 1610620931, NULL },
++  { NULL, 2056, "0"},
++  { "name-string", 536879115, NULL },
++  { NULL, 1073743880, "1"},
++  { NULL, 27, NULL },
++  { "KRB5PrincipalName", 1610612741, NULL },
++  { "realm", 1610620955, NULL },
++  { NULL, 2056, "0"},
++  { "principalName", 536879106, "PrincipalName"},
++  { NULL, 2056, "1"},
++  { "RSAPSSParameters", 1610612741, NULL },
++  { "hashAlgorithm", 1610637314, "AlgorithmIdentifier"},
++  { NULL, 2056, "0"},
++  { "maskGenAlgorithm", 1610637314, "AlgorithmIdentifier"},
++  { NULL, 2056, "1"},
++  { "saltLength", 1610653699, NULL },
++  { NULL, 1073741833, "20"},
++  { NULL, 2056, "2"},
++  { "trailerField", 536911875, NULL },
++  { NULL, 1073741833, "1"},
++  { NULL, 2056, "3"},
++  { "GOSTParameters", 1610612741, NULL },
++  { "publicKeyParamSet", 1073741836, NULL },
++  { "digestParamSet", 16396, NULL },
++  { "GOSTParametersOld", 1610612741, NULL },
++  { "publicKeyParamSet", 1073741836, NULL },
++  { "digestParamSet", 1073741836, NULL },
++  { "encryptionParamSet", 16396, NULL },
++  { "GOSTPrivateKey", 1073741831, NULL },
++  { "GOSTPrivateKeyOld", 1073741827, NULL },
++  { "IssuerSignTool", 1610612741, NULL },
++  { "signTool", 1073741858, NULL },
++  { "cATool", 1073741858, NULL },
++  { "signToolCert", 1073741858, NULL },
++  { "cAToolCert", 34, NULL },
++  { "Gost28147-89-EncryptedKey", 1610612741, NULL },
++  { "encryptedKey", 1073741831, NULL },
++  { "maskKey", 1610637319, NULL },
++  { NULL, 4104, "0"},
++  { "macKey", 7, NULL },
++  { "SubjectPublicKeyInfo", 1610612741, NULL },
++  { "algorithm", 1073741826, "AlgorithmIdentifier"},
++  { "subjectPublicKey", 6, NULL },
++  { "GostR3410-TransportParameters", 1610612741, NULL },
++  { "encryptionParamSet", 1073741836, NULL },
++  { "ephemeralPublicKey", 1610637314, "SubjectPublicKeyInfo"},
++  { NULL, 4104, "0"},
++  { "ukm", 7, NULL },
++  { "GostR3410-KeyTransport", 536870917, NULL },
++  { "sessionEncryptedKey", 1073741826, "Gost28147-89-EncryptedKey"},
++  { "transportParameters", 536895490, "GostR3410-TransportParameters"},
++  { NULL, 4104, "0"},
++  { NULL, 0, NULL }
++};
+diff --git a/grub-core/commands/appendedsig/pkix_asn1_tab.c b/grub-core/commands/appendedsig/pkix_asn1_tab.c
+new file mode 100644
+index 0000000000..adef69d95c
+--- /dev/null
++++ b/grub-core/commands/appendedsig/pkix_asn1_tab.c
+@@ -0,0 +1,484 @@
++#include <grub/mm.h>
++#include <grub/libtasn1.h>
++
++const asn1_static_node pkix_asn1_tab[] = {
++  { "PKIX1", 536875024, NULL },
++  { NULL, 1073741836, NULL },
++  { "PrivateKeyUsagePeriod", 1610612741, NULL },
++  { "notBefore", 1610637349, NULL },
++  { NULL, 4104, "0"},
++  { "notAfter", 536895525, NULL },
++  { NULL, 4104, "1"},
++  { "AuthorityKeyIdentifier", 1610612741, NULL },
++  { "keyIdentifier", 1610637319, NULL },
++  { NULL, 4104, "0"},
++  { "authorityCertIssuer", 1610637314, "GeneralNames"},
++  { NULL, 4104, "1"},
++  { "authorityCertSerialNumber", 536895490, "CertificateSerialNumber"},
++  { NULL, 4104, "2"},
++  { "SubjectKeyIdentifier", 1073741831, NULL },
++  { "KeyUsage", 1073741830, NULL },
++  { "DirectoryString", 1610612754, NULL },
++  { "teletexString", 1612709918, NULL },
++  { "MAX", 524298, "1"},
++  { "printableString", 1612709919, NULL },
++  { "MAX", 524298, "1"},
++  { "universalString", 1612709920, NULL },
++  { "MAX", 524298, "1"},
++  { "utf8String", 1612709922, NULL },
++  { "MAX", 524298, "1"},
++  { "bmpString", 1612709921, NULL },
++  { "MAX", 524298, "1"},
++  { "ia5String", 538968093, NULL },
++  { "MAX", 524298, "1"},
++  { "SubjectAltName", 1073741826, "GeneralNames"},
++  { "GeneralNames", 1612709899, NULL },
++  { "MAX", 1074266122, "1"},
++  { NULL, 2, "GeneralName"},
++  { "GeneralName", 1610612754, NULL },
++  { "otherName", 1610620930, "AnotherName"},
++  { NULL, 4104, "0"},
++  { "rfc822Name", 1610620957, NULL },
++  { NULL, 4104, "1"},
++  { "dNSName", 1610620957, NULL },
++  { NULL, 4104, "2"},
++  { "x400Address", 1610620941, NULL },
++  { NULL, 4104, "3"},
++  { "directoryName", 1610620939, NULL },
++  { NULL, 1073743880, "4"},
++  { NULL, 2, "RelativeDistinguishedName"},
++  { "ediPartyName", 1610620941, NULL },
++  { NULL, 4104, "5"},
++  { "uniformResourceIdentifier", 1610620957, NULL },
++  { NULL, 4104, "6"},
++  { "iPAddress", 1610620935, NULL },
++  { NULL, 4104, "7"},
++  { "registeredID", 536879116, NULL },
++  { NULL, 4104, "8"},
++  { "AnotherName", 1610612741, NULL },
++  { "type-id", 1073741836, NULL },
++  { "value", 541073421, NULL },
++  { NULL, 1073743880, "0"},
++  { "type-id", 1, NULL },
++  { "IssuerAltName", 1073741826, "GeneralNames"},
++  { "BasicConstraints", 1610612741, NULL },
++  { "cA", 1610645508, NULL },
++  { NULL, 131081, NULL },
++  { "pathLenConstraint", 537411587, NULL },
++  { "0", 10, "MAX"},
++  { "CRLDistributionPoints", 1612709899, NULL },
++  { "MAX", 1074266122, "1"},
++  { NULL, 2, "DistributionPoint"},
++  { "DistributionPoint", 1610612741, NULL },
++  { "distributionPoint", 1610637314, "DistributionPointName"},
++  { NULL, 2056, "0"},
++  { "reasons", 1610637314, "ReasonFlags"},
++  { NULL, 4104, "1"},
++  { "cRLIssuer", 536895490, "GeneralNames"},
++  { NULL, 4104, "2"},
++  { "DistributionPointName", 1610612754, NULL },
++  { "fullName", 1610620930, "GeneralNames"},
++  { NULL, 4104, "0"},
++  { "nameRelativeToCRLIssuer", 536879106, "RelativeDistinguishedName"},
++  { NULL, 4104, "1"},
++  { "ReasonFlags", 1073741830, NULL },
++  { "ExtKeyUsageSyntax", 1612709899, NULL },
++  { "MAX", 1074266122, "1"},
++  { NULL, 12, NULL },
++  { "AuthorityInfoAccessSyntax", 1612709899, NULL },
++  { "MAX", 1074266122, "1"},
++  { NULL, 2, "AccessDescription"},
++  { "AccessDescription", 1610612741, NULL },
++  { "accessMethod", 1073741836, NULL },
++  { "accessLocation", 2, "GeneralName"},
++  { "Attribute", 1610612741, NULL },
++  { "type", 1073741836, NULL },
++  { "values", 536870927, NULL },
++  { NULL, 13, NULL },
++  { "AttributeTypeAndValue", 1610612741, NULL },
++  { "type", 1073741836, NULL },
++  { "value", 13, NULL },
++  { "Name", 1610612754, NULL },
++  { "rdnSequence", 536870923, NULL },
++  { NULL, 2, "RelativeDistinguishedName"},
++  { "DistinguishedName", 1610612747, NULL },
++  { NULL, 2, "RelativeDistinguishedName"},
++  { "RelativeDistinguishedName", 1612709903, NULL },
++  { "MAX", 1074266122, "1"},
++  { NULL, 2, "AttributeTypeAndValue"},
++  { "Certificate", 1610612741, NULL },
++  { "tbsCertificate", 1073741826, "TBSCertificate"},
++  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
++  { "signature", 6, NULL },
++  { "TBSCertificate", 1610612741, NULL },
++  { "version", 1610653699, NULL },
++  { NULL, 1073741833, "0"},
++  { NULL, 2056, "0"},
++  { "serialNumber", 1073741826, "CertificateSerialNumber"},
++  { "signature", 1073741826, "AlgorithmIdentifier"},
++  { "issuer", 1073741826, "Name"},
++  { "validity", 1073741826, "Validity"},
++  { "subject", 1073741826, "Name"},
++  { "subjectPublicKeyInfo", 1073741826, "SubjectPublicKeyInfo"},
++  { "issuerUniqueID", 1610637314, "UniqueIdentifier"},
++  { NULL, 4104, "1"},
++  { "subjectUniqueID", 1610637314, "UniqueIdentifier"},
++  { NULL, 4104, "2"},
++  { "extensions", 536895490, "Extensions"},
++  { NULL, 2056, "3"},
++  { "CertificateSerialNumber", 1073741827, NULL },
++  { "Validity", 1610612741, NULL },
++  { "notBefore", 1073741826, "Time"},
++  { "notAfter", 2, "Time"},
++  { "Time", 1610612754, NULL },
++  { "utcTime", 1073741860, NULL },
++  { "generalTime", 37, NULL },
++  { "UniqueIdentifier", 1073741830, NULL },
++  { "SubjectPublicKeyInfo", 1610612741, NULL },
++  { "algorithm", 1073741826, "AlgorithmIdentifier"},
++  { "subjectPublicKey", 6, NULL },
++  { "Extensions", 1612709899, NULL },
++  { "MAX", 1074266122, "1"},
++  { NULL, 2, "Extension"},
++  { "Extension", 1610612741, NULL },
++  { "extnID", 1073741836, NULL },
++  { "critical", 1610645508, NULL },
++  { NULL, 131081, NULL },
++  { "extnValue", 7, NULL },
++  { "CertificateList", 1610612741, NULL },
++  { "tbsCertList", 1073741826, "TBSCertList"},
++  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
++  { "signature", 6, NULL },
++  { "TBSCertList", 1610612741, NULL },
++  { "version", 1073758211, NULL },
++  { "signature", 1073741826, "AlgorithmIdentifier"},
++  { "issuer", 1073741826, "Name"},
++  { "thisUpdate", 1073741826, "Time"},
++  { "nextUpdate", 1073758210, "Time"},
++  { "revokedCertificates", 1610629131, NULL },
++  { NULL, 536870917, NULL },
++  { "userCertificate", 1073741826, "CertificateSerialNumber"},
++  { "revocationDate", 1073741826, "Time"},
++  { "crlEntryExtensions", 16386, "Extensions"},
++  { "crlExtensions", 536895490, "Extensions"},
++  { NULL, 2056, "0"},
++  { "AlgorithmIdentifier", 1610612741, NULL },
++  { "algorithm", 1073741836, NULL },
++  { "parameters", 541081613, NULL },
++  { "algorithm", 1, NULL },
++  { "Dss-Sig-Value", 1610612741, NULL },
++  { "r", 1073741827, NULL },
++  { "s", 3, NULL },
++  { "Dss-Parms", 1610612741, NULL },
++  { "p", 1073741827, NULL },
++  { "q", 1073741827, NULL },
++  { "g", 3, NULL },
++  { "pkcs-7-ContentInfo", 1610612741, NULL },
++  { "contentType", 1073741836, NULL },
++  { "content", 541073421, NULL },
++  { NULL, 1073743880, "0"},
++  { "contentType", 1, NULL },
++  { "pkcs-7-DigestInfo", 1610612741, NULL },
++  { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"},
++  { "digest", 7, NULL },
++  { "pkcs-7-SignedData", 1610612741, NULL },
++  { "version", 1073741827, NULL },
++  { "digestAlgorithms", 1073741826, "pkcs-7-DigestAlgorithmIdentifiers"},
++  { "encapContentInfo", 1073741826, "pkcs-7-EncapsulatedContentInfo"},
++  { "certificates", 1610637314, "pkcs-7-CertificateSet"},
++  { NULL, 4104, "0"},
++  { "crls", 1610637314, "pkcs-7-CertificateRevocationLists"},
++  { NULL, 4104, "1"},
++  { "signerInfos", 2, "pkcs-7-SignerInfos"},
++  { "pkcs-7-DigestAlgorithmIdentifiers", 1610612751, NULL },
++  { NULL, 2, "AlgorithmIdentifier"},
++  { "pkcs-7-EncapsulatedContentInfo", 1610612741, NULL },
++  { "eContentType", 1073741836, NULL },
++  { "eContent", 536895501, NULL },
++  { NULL, 2056, "0"},
++  { "pkcs-7-CertificateRevocationLists", 1610612751, NULL },
++  { NULL, 13, NULL },
++  { "pkcs-7-CertificateChoices", 1610612754, NULL },
++  { "certificate", 13, NULL },
++  { "pkcs-7-CertificateSet", 1610612751, NULL },
++  { NULL, 2, "pkcs-7-CertificateChoices"},
++  { "IssuerAndSerialNumber", 1610612741, NULL },
++  { "issuer", 1073741826, "Name"},
++  { "serialNumber", 2, "CertificateSerialNumber"},
++  { "pkcs-7-SignerInfo", 1610612741, NULL },
++  { "version", 1073741827, NULL },
++  { "sid", 1073741826, "SignerIdentifier"},
++  { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"},
++  { "signedAttrs", 1610637314, "SignedAttributes"},
++  { NULL, 4104, "0"},
++  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
++  { "signature", 1073741831, NULL },
++  { "unsignedAttrs", 536895490, "SignedAttributes"},
++  { NULL, 4104, "1"},
++  { "SignedAttributes", 1612709903, NULL },
++  { "MAX", 1074266122, "1"},
++  { NULL, 2, "Attribute"},
++  { "SignerIdentifier", 1610612754, NULL },
++  { "issuerAndSerialNumber", 1073741826, "IssuerAndSerialNumber"},
++  { "subjectKeyIdentifier", 536879111, NULL },
++  { NULL, 4104, "0"},
++  { "pkcs-7-SignerInfos", 1610612751, NULL },
++  { NULL, 2, "pkcs-7-SignerInfo"},
++  { "pkcs-10-CertificationRequestInfo", 1610612741, NULL },
++  { "version", 1073741827, NULL },
++  { "subject", 1073741826, "Name"},
++  { "subjectPKInfo", 1073741826, "SubjectPublicKeyInfo"},
++  { "attributes", 536879106, "Attributes"},
++  { NULL, 4104, "0"},
++  { "Attributes", 1610612751, NULL },
++  { NULL, 2, "Attribute"},
++  { "pkcs-10-CertificationRequest", 1610612741, NULL },
++  { "certificationRequestInfo", 1073741826, "pkcs-10-CertificationRequestInfo"},
++  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
++  { "signature", 6, NULL },
++  { "pkcs-9-at-challengePassword", 1879048204, NULL },
++  { "iso", 1073741825, "1"},
++  { "member-body", 1073741825, "2"},
++  { "us", 1073741825, "840"},
++  { "rsadsi", 1073741825, "113549"},
++  { "pkcs", 1073741825, "1"},
++  { NULL, 1073741825, "9"},
++  { NULL, 1, "7"},
++  { "pkcs-9-challengePassword", 1610612754, NULL },
++  { "printableString", 1073741855, NULL },
++  { "utf8String", 34, NULL },
++  { "pkcs-9-localKeyId", 1073741831, NULL },
++  { "pkcs-8-PrivateKeyInfo", 1610612741, NULL },
++  { "version", 1073741827, NULL },
++  { "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"},
++  { "privateKey", 1073741831, NULL },
++  { "attributes", 536895490, "Attributes"},
++  { NULL, 4104, "0"},
++  { "pkcs-8-EncryptedPrivateKeyInfo", 1610612741, NULL },
++  { "encryptionAlgorithm", 1073741826, "AlgorithmIdentifier"},
++  { "encryptedData", 2, "pkcs-8-EncryptedData"},
++  { "pkcs-8-EncryptedData", 1073741831, NULL },
++  { "pkcs-5-des-CBC-params", 1612709895, NULL },
++  { NULL, 1048586, "8"},
++  { "pkcs-5-des-EDE3-CBC-params", 1612709895, NULL },
++  { NULL, 1048586, "8"},
++  { "pkcs-5-aes128-CBC-params", 1612709895, NULL },
++  { NULL, 1048586, "16"},
++  { "pkcs-5-aes192-CBC-params", 1612709895, NULL },
++  { NULL, 1048586, "16"},
++  { "pkcs-5-aes256-CBC-params", 1612709895, NULL },
++  { NULL, 1048586, "16"},
++  { "Gost28147-89-Parameters", 1610612741, NULL },
++  { "iv", 1073741831, NULL },
++  { "encryptionParamSet", 12, NULL },
++  { "pkcs-5-PBE-params", 1610612741, NULL },
++  { "salt", 1073741831, NULL },
++  { "iterationCount", 3, NULL },
++  { "pkcs-5-PBES2-params", 1610612741, NULL },
++  { "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"},
++  { "encryptionScheme", 2, "AlgorithmIdentifier"},
++  { "pkcs-5-PBKDF2-params", 1610612741, NULL },
++  { "salt", 1610612754, NULL },
++  { "specified", 1073741831, NULL },
++  { "otherSource", 2, "AlgorithmIdentifier"},
++  { "iterationCount", 1611137027, NULL },
++  { "1", 10, "MAX"},
++  { "keyLength", 1611153411, NULL },
++  { "1", 10, "MAX"},
++  { "prf", 16386, "AlgorithmIdentifier"},
++  { "pkcs-12-PFX", 1610612741, NULL },
++  { "version", 1610874883, NULL },
++  { "v3", 1, "3"},
++  { "authSafe", 1073741826, "pkcs-7-ContentInfo"},
++  { "macData", 16386, "pkcs-12-MacData"},
++  { "pkcs-12-PbeParams", 1610612741, NULL },
++  { "salt", 1073741831, NULL },
++  { "iterations", 3, NULL },
++  { "pkcs-12-MacData", 1610612741, NULL },
++  { "mac", 1073741826, "pkcs-7-DigestInfo"},
++  { "macSalt", 1073741831, NULL },
++  { "iterations", 536903683, NULL },
++  { NULL, 9, "1"},
++  { "pkcs-12-AuthenticatedSafe", 1610612747, NULL },
++  { NULL, 2, "pkcs-7-ContentInfo"},
++  { "pkcs-12-SafeContents", 1610612747, NULL },
++  { NULL, 2, "pkcs-12-SafeBag"},
++  { "pkcs-12-SafeBag", 1610612741, NULL },
++  { "bagId", 1073741836, NULL },
++  { "bagValue", 1614815245, NULL },
++  { NULL, 1073743880, "0"},
++  { "badId", 1, NULL },
++  { "bagAttributes", 536887311, NULL },
++  { NULL, 2, "Attribute"},
++  { "pkcs-12-CertBag", 1610612741, NULL },
++  { "certId", 1073741836, NULL },
++  { "certValue", 541073421, NULL },
++  { NULL, 1073743880, "0"},
++  { "certId", 1, NULL },
++  { "pkcs-12-CRLBag", 1610612741, NULL },
++  { "crlId", 1073741836, NULL },
++  { "crlValue", 541073421, NULL },
++  { NULL, 1073743880, "0"},
++  { "crlId", 1, NULL },
++  { "pkcs-12-SecretBag", 1610612741, NULL },
++  { "secretTypeId", 1073741836, NULL },
++  { "secretValue", 541073421, NULL },
++  { NULL, 1073743880, "0"},
++  { "secretTypeId", 1, NULL },
++  { "pkcs-7-Data", 1073741831, NULL },
++  { "pkcs-7-EncryptedData", 1610612741, NULL },
++  { "version", 1073741827, NULL },
++  { "encryptedContentInfo", 1073741826, "pkcs-7-EncryptedContentInfo"},
++  { "unprotectedAttrs", 536895490, "pkcs-7-UnprotectedAttributes"},
++  { NULL, 4104, "1"},
++  { "pkcs-7-EncryptedContentInfo", 1610612741, NULL },
++  { "contentType", 1073741836, NULL },
++  { "contentEncryptionAlgorithm", 1073741826, "pkcs-7-ContentEncryptionAlgorithmIdentifier"},
++  { "encryptedContent", 536895495, NULL },
++  { NULL, 4104, "0"},
++  { "pkcs-7-ContentEncryptionAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"},
++  { "pkcs-7-UnprotectedAttributes", 1612709903, NULL },
++  { "MAX", 1074266122, "1"},
++  { NULL, 2, "Attribute"},
++  { "ProxyCertInfo", 1610612741, NULL },
++  { "pCPathLenConstraint", 1611153411, NULL },
++  { "0", 10, "MAX"},
++  { "proxyPolicy", 2, "ProxyPolicy"},
++  { "ProxyPolicy", 1610612741, NULL },
++  { "policyLanguage", 1073741836, NULL },
++  { "policy", 16391, NULL },
++  { "certificatePolicies", 1612709899, NULL },
++  { "MAX", 1074266122, "1"},
++  { NULL, 2, "PolicyInformation"},
++  { "PolicyInformation", 1610612741, NULL },
++  { "policyIdentifier", 1073741836, NULL },
++  { "policyQualifiers", 538984459, NULL },
++  { "MAX", 1074266122, "1"},
++  { NULL, 2, "PolicyQualifierInfo"},
++  { "PolicyQualifierInfo", 1610612741, NULL },
++  { "policyQualifierId", 1073741836, NULL },
++  { "qualifier", 541065229, NULL },
++  { "policyQualifierId", 1, NULL },
++  { "CPSuri", 1073741853, NULL },
++  { "UserNotice", 1610612741, NULL },
++  { "noticeRef", 1073758210, "NoticeReference"},
++  { "explicitText", 16386, "DisplayText"},
++  { "NoticeReference", 1610612741, NULL },
++  { "organization", 1073741826, "DisplayText"},
++  { "noticeNumbers", 536870923, NULL },
++  { NULL, 3, NULL },
++  { "DisplayText", 1610612754, NULL },
++  { "ia5String", 1612709917, NULL },
++  { "200", 524298, "1"},
++  { "visibleString", 1612709923, NULL },
++  { "200", 524298, "1"},
++  { "bmpString", 1612709921, NULL },
++  { "200", 524298, "1"},
++  { "utf8String", 538968098, NULL },
++  { "200", 524298, "1"},
++  { "OCSPRequest", 1610612741, NULL },
++  { "tbsRequest", 1073741826, "TBSRequest"},
++  { "optionalSignature", 536895490, "Signature"},
++  { NULL, 2056, "0"},
++  { "TBSRequest", 1610612741, NULL },
++  { "version", 1610653699, NULL },
++  { NULL, 1073741833, "0"},
++  { NULL, 2056, "0"},
++  { "requestorName", 1610637314, "GeneralName"},
++  { NULL, 2056, "1"},
++  { "requestList", 1610612747, NULL },
++  { NULL, 2, "Request"},
++  { "requestExtensions", 536895490, "Extensions"},
++  { NULL, 2056, "2"},
++  { "Signature", 1610612741, NULL },
++  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
++  { "signature", 1073741830, NULL },
++  { "certs", 536895499, NULL },
++  { NULL, 1073743880, "0"},
++  { NULL, 2, "Certificate"},
++  { "Request", 1610612741, NULL },
++  { "reqCert", 1073741826, "CertID"},
++  { "singleRequestExtensions", 536895490, "Extensions"},
++  { NULL, 2056, "0"},
++  { "CertID", 1610612741, NULL },
++  { "hashAlgorithm", 1073741826, "AlgorithmIdentifier"},
++  { "issuerNameHash", 1073741831, NULL },
++  { "issuerKeyHash", 1073741831, NULL },
++  { "serialNumber", 2, "CertificateSerialNumber"},
++  { "OCSPResponse", 1610612741, NULL },
++  { "responseStatus", 1073741826, "OCSPResponseStatus"},
++  { "responseBytes", 536895490, "ResponseBytes"},
++  { NULL, 2056, "0"},
++  { "OCSPResponseStatus", 1610874901, NULL },
++  { "successful", 1073741825, "0"},
++  { "malformedRequest", 1073741825, "1"},
++  { "internalError", 1073741825, "2"},
++  { "tryLater", 1073741825, "3"},
++  { "sigRequired", 1073741825, "5"},
++  { "unauthorized", 1, "6"},
++  { "ResponseBytes", 1610612741, NULL },
++  { "responseType", 1073741836, NULL },
++  { "response", 7, NULL },
++  { "BasicOCSPResponse", 1610612741, NULL },
++  { "tbsResponseData", 1073741826, "ResponseData"},
++  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
++  { "signature", 1073741830, NULL },
++  { "certs", 536895499, NULL },
++  { NULL, 1073743880, "0"},
++  { NULL, 2, "Certificate"},
++  { "ResponseData", 1610612741, NULL },
++  { "version", 1610653699, NULL },
++  { NULL, 1073741833, "0"},
++  { NULL, 2056, "0"},
++  { "responderID", 1073741826, "ResponderID"},
++  { "producedAt", 1073741861, NULL },
++  { "responses", 1610612747, NULL },
++  { NULL, 2, "SingleResponse"},
++  { "responseExtensions", 536895490, "Extensions"},
++  { NULL, 2056, "1"},
++  { "ResponderID", 1610612754, NULL },
++  { "byName", 1610620939, NULL },
++  { NULL, 1073743880, "1"},
++  { NULL, 2, "RelativeDistinguishedName"},
++  { "byKey", 536879111, NULL },
++  { NULL, 2056, "2"},
++  { "SingleResponse", 1610612741, NULL },
++  { "certID", 1073741826, "CertID"},
++  { "certStatus", 1073741826, "CertStatus"},
++  { "thisUpdate", 1073741861, NULL },
++  { "nextUpdate", 1610637349, NULL },
++  { NULL, 2056, "0"},
++  { "singleExtensions", 536895490, "Extensions"},
++  { NULL, 2056, "1"},
++  { "CertStatus", 1610612754, NULL },
++  { "good", 1610620948, NULL },
++  { NULL, 4104, "0"},
++  { "revoked", 1610620930, "RevokedInfo"},
++  { NULL, 4104, "1"},
++  { "unknown", 536879106, "UnknownInfo"},
++  { NULL, 4104, "2"},
++  { "RevokedInfo", 1610612741, NULL },
++  { "revocationTime", 1073741861, NULL },
++  { "revocationReason", 537157653, NULL },
++  { NULL, 1073743880, "0"},
++  { "unspecified", 1, "0"},
++  { "UnknownInfo", 1073741844, NULL },
++  { "NameConstraints", 1610612741, NULL },
++  { "permittedSubtrees", 1610637314, "GeneralSubtrees"},
++  { NULL, 4104, "0"},
++  { "excludedSubtrees", 536895490, "GeneralSubtrees"},
++  { NULL, 4104, "1"},
++  { "GeneralSubtrees", 1612709899, NULL },
++  { "MAX", 1074266122, "1"},
++  { NULL, 2, "GeneralSubtree"},
++  { "GeneralSubtree", 1610612741, NULL },
++  { "base", 1073741826, "GeneralName"},
++  { "minimum", 1610653699, NULL },
++  { NULL, 1073741833, "0"},
++  { NULL, 4104, "0"},
++  { "maximum", 536895491, NULL },
++  { NULL, 4104, "1"},
++  { "TlsFeatures", 536870923, NULL },
++  { NULL, 3, NULL },
++  { NULL, 0, NULL }
++};
diff --git a/SOURCES/0168-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch b/SOURCES/0168-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch
deleted file mode 100644
index c338840..0000000
--- a/SOURCES/0168-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch
+++ /dev/null
@@ -1,121 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
-Date: Thu, 3 Dec 2020 09:13:24 +0100
-Subject: [PATCH] at_keyboard: use set 1 when keyboard is in Translate mode
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-When keyboard controller acts in Translate mode (0x40 mask), then use
-set 1 since translation is done.
-Otherwise use the mode queried from the controller (usually set 2).
-
-Added "atkeyb" debugging messages in at_keyboard module as well.
-
-Resolves: rhbz#1897587
-
-Tested on:
-- Asus N53SN (set 1 used)
-- Dell Precision (set 1 used)
-- HP Elitebook (set 2 used)
-- HP G5430 (set 1 used, keyboard in XT mode!)
-- Lenovo P71 & Lenovo T460s (set 2 used)
-- QEMU/KVM (set 1 used)
-
-Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
----
- grub-core/term/at_keyboard.c | 29 ++++++++++++++++++++++++-----
- include/grub/at_keyboard.h   |  4 ++++
- 2 files changed, 28 insertions(+), 5 deletions(-)
-
-diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c
-index 597111077bd..26014382608 100644
---- a/grub-core/term/at_keyboard.c
-+++ b/grub-core/term/at_keyboard.c
-@@ -135,20 +135,28 @@ query_mode (void)
-   int e;
- 
-   e = write_mode (0);
--  if (!e)
-+  if (!e) {
-+    grub_dprintf("atkeyb", "query_mode: write_mode(0) failed\n");
-     return 0;
-+  }
- 
-   do {
-     keyboard_controller_wait_until_ready ();
-     ret = grub_inb (KEYBOARD_REG_DATA);
-   } while (ret == GRUB_AT_ACK);
-   /* QEMU translates the set even in no-translate mode.  */
--  if (ret == 0x43 || ret == 1)
-+  if (ret == 0x43 || ret == 1) {
-+    grub_dprintf("atkeyb", "query_mode: returning 1 (ret=0x%x)\n", ret);
-     return 1;
--  if (ret == 0x41 || ret == 2)
-+  }
-+  if (ret == 0x41 || ret == 2) {
-+    grub_dprintf("atkeyb", "query_mode: returning 2 (ret=0x%x)\n", ret);
-     return 2;
--  if (ret == 0x3f || ret == 3)
-+  }
-+  if (ret == 0x3f || ret == 3) {
-+    grub_dprintf("atkeyb", "query_mode: returning 3 (ret=0x%x)\n", ret);
-     return 3;
-+  }
-   return 0;
- }
- 
-@@ -165,7 +173,13 @@ set_scancodes (void)
-     }
- 
- #if !USE_SCANCODE_SET
--  ps2_state.current_set = 1;
-+  if ((grub_keyboard_controller_orig & KEYBOARD_AT_TRANSLATE) == KEYBOARD_AT_TRANSLATE) {
-+    grub_dprintf ("atkeyb", "queried set is %d but keyboard in Translate mode, so actually in set 1\n", grub_keyboard_orig_set);
-+    ps2_state.current_set = 1;
-+  } else {
-+    grub_dprintf ("atkeyb", "using queried set %d\n", grub_keyboard_orig_set);
-+    ps2_state.current_set = grub_keyboard_orig_set;
-+  }
-   return;
- #else
- 
-@@ -266,6 +280,7 @@ grub_keyboard_controller_init (void)
-   grub_keyboard_orig_set = 2;
- #else
-   grub_keyboard_controller_orig = grub_keyboard_controller_read ();
-+  grub_dprintf ("atkeyb", "grub_keyboard_controller_orig = 0x%x\n", grub_keyboard_controller_orig);
-   grub_keyboard_orig_set = query_mode ();
- #endif
-   set_scancodes ();
-@@ -275,11 +290,15 @@ grub_keyboard_controller_init (void)
- static grub_err_t
- grub_keyboard_controller_fini (struct grub_term_input *term __attribute__ ((unused)))
- {
-+/* In !USE_SCANCODE_SET mode, we didn't change anything, so nothing to restore */
-+#if USE_SCANCODE_SET
-   if (ps2_state.current_set == 0)
-     return GRUB_ERR_NONE;
-+  grub_dprintf ("atkeyb", "restoring set %d, controller 0x%x\n", grub_keyboard_orig_set, grub_keyboard_controller_orig);
-   if (grub_keyboard_orig_set)
-     write_mode (grub_keyboard_orig_set);
-   grub_keyboard_controller_write (grub_keyboard_controller_orig);
-+#endif
-   return GRUB_ERR_NONE;
- }
- 
-diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h
-index bcb4d9ba78f..9414dc1b996 100644
---- a/include/grub/at_keyboard.h
-+++ b/include/grub/at_keyboard.h
-@@ -19,6 +19,10 @@
- #ifndef GRUB_AT_KEYBOARD_HEADER
- #define GRUB_AT_KEYBOARD_HEADER	1
- 
-+/*
-+ * Refer to https://wiki.osdev.org/%228042%22_PS/2_Controller for details.
-+ */
-+
- /* Used for sending commands to the controller.  */
- #define KEYBOARD_COMMAND_ISREADY(x)	!((x) & 0x02)
- #define KEYBOARD_COMMAND_READ		0x20
diff --git a/SOURCES/0169-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch b/SOURCES/0169-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch
new file mode 100644
index 0000000..5a13d5b
--- /dev/null
+++ b/SOURCES/0169-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch
@@ -0,0 +1,1528 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 30 Jul 2020 01:33:46 +1000
+Subject: [PATCH] appended signatures: parse PKCS#7 signedData and X.509
+ certificates
+
+This code allows us to parse:
+
+ - PKCS#7 signedData messages. Only a single signerInfo is supported,
+   which is all that the Linux sign-file utility supports creating
+   out-of-the-box. Only RSA, SHA-256 and SHA-512 are supported.
+   Any certificate embedded in the PKCS#7 message will be ignored.
+
+ - X.509 certificates: at least enough to verify the signatures on the
+   PKCS#7 messages. We expect that the certificates embedded in grub will
+   be leaf certificates, not CA certificates. The parser enforces this.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/commands/appendedsig/asn1util.c    | 102 +++
+ grub-core/commands/appendedsig/pkcs7.c       | 305 +++++++++
+ grub-core/commands/appendedsig/x509.c        | 958 +++++++++++++++++++++++++++
+ grub-core/commands/appendedsig/appendedsig.h | 110 +++
+ 4 files changed, 1475 insertions(+)
+ create mode 100644 grub-core/commands/appendedsig/asn1util.c
+ create mode 100644 grub-core/commands/appendedsig/pkcs7.c
+ create mode 100644 grub-core/commands/appendedsig/x509.c
+ create mode 100644 grub-core/commands/appendedsig/appendedsig.h
+
+diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c
+new file mode 100644
+index 0000000000..eff095a9df
+--- /dev/null
++++ b/grub-core/commands/appendedsig/asn1util.c
+@@ -0,0 +1,102 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020  IBM Corporation.
++ *
++ *  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/libtasn1.h>
++#include <grub/types.h>
++#include <grub/err.h>
++#include <grub/mm.h>
++#include <grub/crypto.h>
++#include <grub/gcrypt/gcrypt.h>
++
++#include "appendedsig.h"
++
++asn1_node _gnutls_gnutls_asn = ASN1_TYPE_EMPTY;
++asn1_node _gnutls_pkix_asn = ASN1_TYPE_EMPTY;
++
++extern const ASN1_ARRAY_TYPE gnutls_asn1_tab[];
++extern const ASN1_ARRAY_TYPE pkix_asn1_tab[];
++
++/*
++ * Read a value from an ASN1 node, allocating memory to store it.
++ *
++ * It will work for anything where the size libtasn1 returns is right:
++ *  - Integers
++ *  - Octet strings
++ *  - DER encoding of other structures
++ * It will _not_ work for things where libtasn1 size requires adjustment:
++ *  - Strings that require an extra NULL byte at the end
++ *  - Bit strings because libtasn1 returns the length in bits, not bytes.
++ *
++ * If the function returns a non-NULL value, the caller must free it.
++ */
++void *
++grub_asn1_allocate_and_read (asn1_node node, const char *name,
++			     const char *friendly_name, int *content_size)
++{
++  int result;
++  grub_uint8_t *tmpstr = NULL;
++  int tmpstr_size = 0;
++
++  result = asn1_read_value (node, name, NULL, &tmpstr_size);
++  if (result != ASN1_MEM_ERROR)
++    {
++      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
++		     _
++		     ("Reading size of %s did not return expected status: %s"),
++		     friendly_name, asn1_strerror (result));
++      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
++      return NULL;
++    }
++
++  tmpstr = grub_malloc (tmpstr_size);
++  if (tmpstr == NULL)
++    {
++      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
++		     "Could not allocate memory to store %s", friendly_name);
++      grub_errno = GRUB_ERR_OUT_OF_MEMORY;
++      return NULL;
++    }
++
++  result = asn1_read_value (node, name, tmpstr, &tmpstr_size);
++  if (result != ASN1_SUCCESS)
++    {
++      grub_free (tmpstr);
++      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
++		     "Error reading %s: %s",
++		     friendly_name, asn1_strerror (result));
++      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
++      return NULL;
++    }
++
++  *content_size = tmpstr_size;
++
++  return tmpstr;
++}
++
++int
++asn1_init (void)
++{
++  int res;
++  res = asn1_array2tree (gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL);
++  if (res != ASN1_SUCCESS)
++    {
++      return res;
++    }
++  res = asn1_array2tree (pkix_asn1_tab, &_gnutls_pkix_asn, NULL);
++  return res;
++}
+diff --git a/grub-core/commands/appendedsig/pkcs7.c b/grub-core/commands/appendedsig/pkcs7.c
+new file mode 100644
+index 0000000000..dc6afe203f
+--- /dev/null
++++ b/grub-core/commands/appendedsig/pkcs7.c
+@@ -0,0 +1,305 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020  IBM Corporation.
++ *
++ *  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 "appendedsig.h"
++#include <grub/misc.h>
++#include <grub/crypto.h>
++#include <grub/gcrypt/gcrypt.h>
++
++
++static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
++
++/*
++ * RFC 5652 s 5.1
++ */
++const char *signedData_oid = "1.2.840.113549.1.7.2";
++
++/*
++ * RFC 4055 s 2.1
++ */
++const char *sha256_oid = "2.16.840.1.101.3.4.2.1";
++const char *sha512_oid = "2.16.840.1.101.3.4.2.3";
++
++static grub_err_t
++process_content (grub_uint8_t * content, int size,
++		 struct pkcs7_signedData *msg)
++{
++  int res;
++  asn1_node signed_part;
++  grub_err_t err = GRUB_ERR_NONE;
++  char algo_oid[MAX_OID_LEN];
++  int algo_oid_size = sizeof (algo_oid);
++  int algo_count;
++  char version;
++  int version_size = sizeof (version);
++  grub_uint8_t *result_buf;
++  int result_size = 0;
++  int crls_size = 0;
++  gcry_error_t gcry_err;
++
++  res = asn1_create_element (_gnutls_pkix_asn, "PKIX1.pkcs-7-SignedData",
++			     &signed_part);
++  if (res != ASN1_SUCCESS)
++    {
++      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			 "Could not create ASN.1 structure for PKCS#7 signed part.");
++    }
++
++  res = asn1_der_decoding2 (&signed_part, content, &size,
++			    ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
++  if (res != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_SIGNATURE,
++		    "Error reading PKCS#7 signed data: %s", asn1_error);
++      goto cleanup_signed_part;
++    }
++
++  /* SignedData ::= SEQUENCE {
++   *     version CMSVersion,
++   *     digestAlgorithms DigestAlgorithmIdentifiers,
++   *     encapContentInfo EncapsulatedContentInfo,
++   *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
++   *     crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
++   *     signerInfos SignerInfos }
++   */
++
++  /* version per the algo in 5.1, must be 1 */
++  res = asn1_read_value (signed_part, "version", &version, &version_size);
++  if (res != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_SIGNATURE,
++		    "Error reading signedData version: %s",
++		    asn1_strerror (res));
++      goto cleanup_signed_part;
++    }
++
++  if (version != 1)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_SIGNATURE,
++		    "Unexpected signature version v%d, only v1 supported",
++		    version);
++      goto cleanup_signed_part;
++    }
++
++  /*
++   * digestAlgorithms DigestAlgorithmIdentifiers
++   *
++   * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
++   * DigestAlgorithmIdentifer is an X.509 AlgorithmIdentifier (10.1.1)
++   * 
++   * RFC 4055 s 2.1:
++   * sha256Identifier  AlgorithmIdentifier  ::=  { id-sha256, NULL }
++   * sha512Identifier  AlgorithmIdentifier  ::=  { id-sha512, NULL }
++   *
++   * We only support 1 element in the set, and we do not check parameters atm.
++   */
++  res =
++    asn1_number_of_elements (signed_part, "digestAlgorithms", &algo_count);
++  if (res != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_SIGNATURE,
++		    "Error counting number of digest algorithms: %s",
++		    asn1_strerror (res));
++      goto cleanup_signed_part;
++    }
++
++  if (algo_count != 1)
++    {
++      err =
++	grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
++		    "Only 1 digest algorithm is supported");
++      goto cleanup_signed_part;
++    }
++
++  res =
++    asn1_read_value (signed_part, "digestAlgorithms.?1.algorithm", algo_oid,
++		     &algo_oid_size);
++  if (res != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_SIGNATURE,
++		    "Error reading digest algorithm: %s",
++		    asn1_strerror (res));
++      goto cleanup_signed_part;
++    }
++
++  if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
++    {
++      msg->hash = grub_crypto_lookup_md_by_name ("sha512");
++    }
++  else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
++    {
++      msg->hash = grub_crypto_lookup_md_by_name ("sha256");
++    }
++  else
++    {
++      err =
++	grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
++		    "Only SHA-256 and SHA-512 hashes are supported, found OID %s",
++		    algo_oid);
++      goto cleanup_signed_part;
++    }
++
++  if (!msg->hash)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_SIGNATURE,
++		    "Hash algorithm for OID %s not loaded", algo_oid);
++      goto cleanup_signed_part;
++    }
++
++  /*
++   * We ignore the certificates, but we don't permit CRLs.
++   * A CRL entry might be revoking the certificate we're using, and we have
++   * no way of dealing with that at the moment.
++   */
++  res = asn1_read_value (signed_part, "crls", NULL, &crls_size);
++  if (res != ASN1_ELEMENT_NOT_FOUND)
++    {
++      err =
++	grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
++		    "PKCS#7 messages with embedded CRLs are not supported");
++      goto cleanup_signed_part;
++    }
++
++  /* read the signature */
++  result_buf =
++    grub_asn1_allocate_and_read (signed_part, "signerInfos.?1.signature",
++				 "signature data", &result_size);
++  if (!result_buf)
++    {
++      err = grub_errno;
++      goto cleanup_signed_part;
++    }
++
++  gcry_err =
++    gcry_mpi_scan (&(msg->sig_mpi), GCRYMPI_FMT_USG, result_buf, result_size,
++		   NULL);
++  if (gcry_err != GPG_ERR_NO_ERROR)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_SIGNATURE,
++		    "Error loading signature into MPI structure: %d",
++		    gcry_err);
++      goto cleanup_result;
++    }
++
++cleanup_result:
++  grub_free (result_buf);
++cleanup_signed_part:
++  asn1_delete_structure (&signed_part);
++
++  return err;
++}
++
++grub_err_t
++parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size,
++			struct pkcs7_signedData *msg)
++{
++  int res;
++  asn1_node content_info;
++  grub_err_t err = GRUB_ERR_NONE;
++  char content_oid[MAX_OID_LEN];
++  grub_uint8_t *content;
++  int content_size;
++  int content_oid_size = sizeof (content_oid);
++  int size;
++
++  if (data_size > GRUB_INT_MAX)
++    return grub_error (GRUB_ERR_OUT_OF_RANGE,
++		       "Cannot parse a PKCS#7 message where data size > INT_MAX");
++  size = (int) data_size;
++
++  res = asn1_create_element (_gnutls_pkix_asn,
++			     "PKIX1.pkcs-7-ContentInfo", &content_info);
++  if (res != ASN1_SUCCESS)
++    {
++      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			 "Could not create ASN.1 structure for PKCS#7 data: %s",
++			 asn1_strerror (res));
++    }
++
++  res = asn1_der_decoding2 (&content_info, sigbuf, &size,
++			    ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
++  if (res != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_SIGNATURE,
++		    "Error decoding PKCS#7 message DER: %s", asn1_error);
++      goto cleanup;
++    }
++
++  /*
++   * ContentInfo ::= SEQUENCE {
++   *     contentType ContentType,
++   *     content [0] EXPLICIT ANY DEFINED BY contentType }
++   *
++   * ContentType ::= OBJECT IDENTIFIER
++   */
++  res =
++    asn1_read_value (content_info, "contentType", content_oid,
++		     &content_oid_size);
++  if (res != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_SIGNATURE,
++		    "Error reading PKCS#7 content type: %s",
++		    asn1_strerror (res));
++      goto cleanup;
++    }
++
++  /* OID for SignedData defined in 5.1 */
++  if (grub_strncmp (signedData_oid, content_oid, content_oid_size) != 0)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_SIGNATURE,
++		    "Unexpected content type in PKCS#7 message: OID %s",
++		    content_oid);
++      goto cleanup;
++    }
++
++  content =
++    grub_asn1_allocate_and_read (content_info, "content",
++				 "PKCS#7 message content", &content_size);
++  if (!content)
++    {
++      err = grub_errno;
++      goto cleanup;
++    }
++
++  err = process_content (content, content_size, msg);
++  grub_free (content);
++
++cleanup:
++  asn1_delete_structure (&content_info);
++  return err;
++}
++
++/*
++ * Release all the storage associated with the PKCS#7 message.
++ * If the caller dynamically allocated the message, it must free it.
++ */
++void
++pkcs7_signedData_release (struct pkcs7_signedData *msg)
++{
++  gcry_mpi_release (msg->sig_mpi);
++}
+diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c
+new file mode 100644
+index 0000000000..2b38b3670a
+--- /dev/null
++++ b/grub-core/commands/appendedsig/x509.c
+@@ -0,0 +1,958 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020  IBM Corporation.
++ *
++ *  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/libtasn1.h>
++#include <grub/types.h>
++#include <grub/err.h>
++#include <grub/mm.h>
++#include <grub/crypto.h>
++#include <grub/gcrypt/gcrypt.h>
++
++#include "appendedsig.h"
++
++static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
++
++/*
++ * RFC 3279 2.3.1  RSA Keys
++ */
++const char *rsaEncryption_oid = "1.2.840.113549.1.1.1";
++
++/*
++ * RFC 5280 Appendix A
++ */
++const char *commonName_oid = "2.5.4.3";
++
++/*
++ * RFC 5280 4.2.1.3 Key Usage
++ */
++const char *keyUsage_oid = "2.5.29.15";
++
++/*
++ * RFC 5280 4.2.1.9 Basic Constraints
++ */
++const char *basicConstraints_oid = "2.5.29.19";
++
++/*
++ * RFC 3279 2.3.1
++ *
++ *  The RSA public key MUST be encoded using the ASN.1 type RSAPublicKey:
++ *
++ *     RSAPublicKey ::= SEQUENCE {
++ *        modulus            INTEGER,    -- n
++ *        publicExponent     INTEGER  }  -- e
++ *
++ *  where modulus is the modulus n, and publicExponent is the public
++ *  exponent e.
++ */
++static grub_err_t
++grub_parse_rsa_pubkey (grub_uint8_t * der, int dersize,
++		       struct x509_certificate *certificate)
++{
++  int result;
++  asn1_node spk = ASN1_TYPE_EMPTY;
++  grub_uint8_t *m_data, *e_data;
++  int m_size, e_size;
++  grub_err_t err = GRUB_ERR_NONE;
++  gcry_error_t gcry_err;
++
++  result =
++    asn1_create_element (_gnutls_gnutls_asn, "GNUTLS.RSAPublicKey", &spk);
++  if (result != ASN1_SUCCESS)
++    {
++      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			 "Cannot create storage for public key ASN.1 data");
++    }
++
++  result = asn1_der_decoding2 (&spk, der, &dersize,
++			       ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
++  if (result != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Cannot decode certificate public key DER: %s",
++		    asn1_error);
++      goto cleanup;
++    }
++
++  m_data =
++    grub_asn1_allocate_and_read (spk, "modulus", "RSA modulus", &m_size);
++  if (!m_data)
++    {
++      err = grub_errno;
++      goto cleanup;
++    }
++
++  e_data =
++    grub_asn1_allocate_and_read (spk, "publicExponent", "RSA public exponent",
++				 &e_size);
++  if (!e_data)
++    {
++      err = grub_errno;
++      goto cleanup_m_data;
++    }
++
++  /*
++   * convert m, e to mpi
++   *
++   * nscanned is not set for FMT_USG, it's only set for FMT_PGP, 
++   * so we can't verify it
++   */
++  gcry_err =
++    gcry_mpi_scan (&certificate->mpis[0], GCRYMPI_FMT_USG, m_data, m_size,
++		   NULL);
++  if (gcry_err != GPG_ERR_NO_ERROR)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Error loading RSA modulus into MPI structure: %d",
++		    gcry_err);
++      goto cleanup_e_data;
++    }
++
++  gcry_err =
++    gcry_mpi_scan (&certificate->mpis[1], GCRYMPI_FMT_USG, e_data, e_size,
++		   NULL);
++  if (gcry_err != GPG_ERR_NO_ERROR)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Error loading RSA exponent into MPI structure: %d",
++		    gcry_err);
++      goto cleanup_m_mpi;
++    }
++
++  grub_free (e_data);
++  grub_free (m_data);
++  asn1_delete_structure (&spk);
++  return GRUB_ERR_NONE;
++
++cleanup_m_mpi:
++  gcry_mpi_release (certificate->mpis[0]);
++cleanup_e_data:
++  grub_free (e_data);
++cleanup_m_data:
++  grub_free (m_data);
++cleanup:
++  asn1_delete_structure (&spk);
++  return err;
++}
++
++
++/*
++ * RFC 5280:
++ *   SubjectPublicKeyInfo  ::=  SEQUENCE  {
++ *       algorithm            AlgorithmIdentifier,
++ *       subjectPublicKey     BIT STRING  }
++ *
++ * AlgorithmIdentifiers come from RFC 3279, we are not strictly compilant as we
++ * only support RSA Encryption.
++ */
++
++static grub_err_t
++grub_x509_read_subject_public_key (asn1_node asn,
++				   struct x509_certificate *results)
++{
++  int result;
++  grub_err_t err;
++  const char *algo_name =
++    "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm";
++  const char *params_name =
++    "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters";
++  const char *pk_name =
++    "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey";
++  char algo_oid[MAX_OID_LEN];
++  int algo_size = sizeof (algo_oid);
++  char params_value[2];
++  int params_size = sizeof (params_value);
++  grub_uint8_t *key_data = NULL;
++  int key_size = 0;
++  unsigned int key_type;
++
++  /* algorithm: see notes for rsaEncryption_oid */
++  result = asn1_read_value (asn, algo_name, algo_oid, &algo_size);
++  if (result != ASN1_SUCCESS)
++    {
++      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			 "Error reading x509 public key algorithm: %s",
++			 asn1_strerror (result));
++    }
++
++  if (grub_strncmp (algo_oid, rsaEncryption_oid, sizeof (rsaEncryption_oid))
++      != 0)
++    {
++      return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
++			 "Unsupported x509 public key algorithm: %s",
++			 algo_oid);
++    }
++
++  /* 
++   * RFC 3279 2.3.1
++   * The rsaEncryption OID is intended to be used in the algorithm field
++   * of a value of type AlgorithmIdentifier.  The parameters field MUST
++   * have ASN.1 type NULL for this algorithm identifier.
++   */
++  result = asn1_read_value (asn, params_name, params_value, &params_size);
++  if (result != ASN1_SUCCESS)
++    {
++      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			 "Error reading x509 public key parameters: %s",
++			 asn1_strerror (result));
++    }
++
++  if (params_value[0] != ASN1_TAG_NULL)
++    {
++      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			 "Invalid x509 public key parameters: expected NULL");
++    }
++
++  /*
++   * RFC 3279 2.3.1:  The DER encoded RSAPublicKey is the value of the BIT
++   * STRING subjectPublicKey.
++   */
++  result = asn1_read_value_type (asn, pk_name, NULL, &key_size, &key_type);
++  if (result != ASN1_MEM_ERROR)
++    {
++      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			 "Error reading size of x509 public key: %s",
++			 asn1_strerror (result));
++    }
++  if (key_type != ASN1_ETYPE_BIT_STRING)
++    {
++      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			 "Unexpected ASN.1 type when reading x509 public key: %x",
++			 key_type);
++    }
++
++  /* length is in bits */
++  key_size = (key_size + 7) / 8;
++
++  key_data = grub_malloc (key_size);
++  if (!key_data)
++    {
++      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			 "Out of memory for x509 public key");
++    }
++
++  result = asn1_read_value (asn, pk_name, key_data, &key_size);
++  if (result != ASN1_SUCCESS)
++    {
++      grub_free (key_data);
++      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			 "Error reading public key data");
++    }
++  key_size = (key_size + 7) / 8;
++
++  err = grub_parse_rsa_pubkey (key_data, key_size, results);
++  grub_free (key_data);
++
++  return err;
++}
++
++/* Decode a string as defined in Appendix A */
++static grub_err_t
++decode_string (char *der, int der_size, char **string,
++	       grub_size_t * string_size)
++{
++  asn1_node strasn;
++  int result;
++  char *choice;
++  int choice_size = 0;
++  int tmp_size = 0;
++  grub_err_t err = GRUB_ERR_NONE;
++
++  result =
++    asn1_create_element (_gnutls_pkix_asn, "PKIX1.DirectoryString", &strasn);
++  if (result != ASN1_SUCCESS)
++    {
++      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			 "Could not create ASN.1 structure for certificate: %s",
++			 asn1_strerror (result));
++    }
++
++  result = asn1_der_decoding2 (&strasn, der, &der_size,
++			       ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
++  if (result != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Could not parse DER for DirectoryString: %s",
++		    asn1_error);
++      goto cleanup;
++    }
++
++  choice =
++    grub_asn1_allocate_and_read (strasn, "", "DirectoryString choice",
++				 &choice_size);
++  if (!choice)
++    {
++      err = grub_errno;
++      goto cleanup;
++    }
++
++  if (grub_strncmp ("utf8String", choice, choice_size))
++    {
++      err =
++	grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
++		    "Only UTF-8 DirectoryStrings are supported, got %s",
++		    choice);
++      goto cleanup_choice;
++    }
++
++  result = asn1_read_value (strasn, "utf8String", NULL, &tmp_size);
++  if (result != ASN1_MEM_ERROR)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Error reading size of UTF-8 string: %s",
++		    asn1_strerror (result));
++      goto cleanup_choice;
++    }
++
++  /* read size does not include trailing null */
++  tmp_size++;
++
++  *string = grub_malloc (tmp_size);
++  if (!*string)
++    {
++      err =
++	grub_error (GRUB_ERR_OUT_OF_MEMORY,
++		    "Cannot allocate memory for DirectoryString contents");
++      goto cleanup_choice;
++    }
++
++  result = asn1_read_value (strasn, "utf8String", *string, &tmp_size);
++  if (result != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Error reading out UTF-8 string in DirectoryString: %s",
++		    asn1_strerror (result));
++      grub_free (*string);
++      goto cleanup_choice;
++    }
++  *string_size = tmp_size + 1;
++  (*string)[tmp_size] = '\0';
++
++cleanup_choice:
++  grub_free (choice);
++cleanup:
++  asn1_delete_structure (&strasn);
++  return err;
++}
++
++/*
++ * TBSCertificate  ::=  SEQUENCE  {
++ *       version         [0]  EXPLICIT Version DEFAULT v1,
++ * ...
++ * 
++ * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
++ */
++static grub_err_t
++check_version (asn1_node certificate)
++{
++  int rc;
++  const char *name = "tbsCertificate.version";
++  grub_uint8_t version;
++  int len = 1;
++
++  rc = asn1_read_value (certificate, name, &version, &len);
++
++  /* require version 3 */
++  if (rc != ASN1_SUCCESS || len != 1)
++    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		       "Error reading certificate version");
++
++  if (version != 0x02)
++    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		       "Invalid x509 certificate version, expected v3 (0x02), got 0x%02x",
++		       version);
++
++  return GRUB_ERR_NONE;
++}
++
++/*
++ * This is an X.501 Name, which is complex.
++ *
++ * For simplicity, we extract only the CN.
++ */
++static grub_err_t
++read_name (asn1_node asn, const char *name_path, char **name,
++	   grub_size_t * name_size)
++{
++  int seq_components, set_components;
++  int result;
++  int i, j;
++  char *top_path, *set_path, *type_path, *val_path;
++  char type[MAX_OID_LEN];
++  int type_len = sizeof (type);
++  int string_size = 0;
++  char *string_der;
++  grub_err_t err;
++
++  *name = NULL;
++
++  top_path = grub_xasprintf ("%s.rdnSequence", name_path);
++  if (!top_path)
++    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++		       "Could not allocate memory for %s name parsing path",
++		       name_path);
++
++  result = asn1_number_of_elements (asn, top_path, &seq_components);
++  if (result != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Error counting name components: %s",
++		    asn1_strerror (result));
++      goto cleanup;
++    }
++
++  for (i = 1; i <= seq_components; i++)
++    {
++      set_path = grub_xasprintf ("%s.?%d", top_path, i);
++      if (!set_path)
++	{
++	  err =
++	    grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			"Could not allocate memory for %s name set parsing path",
++			name_path);
++	  goto cleanup_set;
++	}
++      /* this brings us, hopefully, to a set */
++      result = asn1_number_of_elements (asn, set_path, &set_components);
++      if (result != ASN1_SUCCESS)
++	{
++	  err =
++	    grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			"Error counting name sub-components components (element %d): %s",
++			i, asn1_strerror (result));
++	  goto cleanup_set;
++	}
++      for (j = 1; j <= set_components; j++)
++	{
++	  type_path = grub_xasprintf ("%s.?%d.?%d.type", top_path, i, j);
++	  if (!type_path)
++	    {
++	      err =
++		grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			    "Could not allocate memory for %s name component type path",
++			    name_path);
++	      goto cleanup_set;
++	    }
++	  type_len = sizeof (type);
++	  result = asn1_read_value (asn, type_path, type, &type_len);
++	  if (result != ASN1_SUCCESS)
++	    {
++	      err =
++		grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			    "Error reading %s name component type: %s",
++			    name_path, asn1_strerror (result));
++	      goto cleanup_type;
++	    }
++
++	  if (grub_strncmp (type, commonName_oid, type_len) != 0)
++	    {
++	      grub_free (type_path);
++	      continue;
++	    }
++
++	  val_path = grub_xasprintf ("%s.?%d.?%d.value", top_path, i, j);
++	  if (!val_path)
++	    {
++	      err =
++		grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			    "Could not allocate memory for %s name component value path",
++			    name_path);
++	      goto cleanup_set;
++	    }
++
++	  string_der =
++	    grub_asn1_allocate_and_read (asn, val_path, name_path,
++					 &string_size);
++	  if (!string_der)
++	    {
++	      err = grub_errno;
++	      goto cleanup_val_path;
++	    }
++
++	  err = decode_string (string_der, string_size, name, name_size);
++	  if (err)
++	    goto cleanup_string;
++
++	  grub_free (string_der);
++	  grub_free (type_path);
++	  grub_free (val_path);
++	  break;
++	}
++      grub_free (set_path);
++
++      if (*name)
++	break;
++    }
++
++  return GRUB_ERR_NONE;
++
++cleanup_string:
++  grub_free (string_der);
++cleanup_val_path:
++  grub_free (val_path);
++cleanup_type:
++  grub_free (type_path);
++cleanup_set:
++  grub_free (set_path);
++cleanup:
++  grub_free (top_path);
++  return err;
++}
++
++/*
++ * details here
++ */
++static grub_err_t
++verify_key_usage (grub_uint8_t * value, int value_size)
++{
++  asn1_node usageasn;
++  int result;
++  grub_err_t err = GRUB_ERR_NONE;
++  grub_uint8_t usage = 0xff;
++  int usage_size = 1;
++
++  result =
++    asn1_create_element (_gnutls_pkix_asn, "PKIX1.KeyUsage", &usageasn);
++  if (result != ASN1_SUCCESS)
++    {
++      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			 "Could not create ASN.1 structure for key usage");
++    }
++
++  result = asn1_der_decoding2 (&usageasn, value, &value_size,
++			       ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
++  if (result != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Error parsing DER for Key Usage: %s", asn1_error);
++      goto cleanup;
++    }
++
++  result = asn1_read_value (usageasn, "", &usage, &usage_size);
++  if (result != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Error reading Key Usage value: %s",
++		    asn1_strerror (result));
++      goto cleanup;
++    }
++
++  /* Only the first bit is permitted to be set */
++  if (usage != 0x80)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected Key Usage value: %x",
++		    usage);
++      goto cleanup;
++    }
++
++cleanup:
++  asn1_delete_structure (&usageasn);
++  return err;
++}
++
++/*
++ * BasicConstraints ::= SEQUENCE {
++ *       cA                      BOOLEAN DEFAULT FALSE,
++ *       pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
++ */
++static grub_err_t
++verify_basic_constraints (grub_uint8_t * value, int value_size)
++{
++  asn1_node basicasn;
++  int result;
++  grub_err_t err = GRUB_ERR_NONE;
++  char cA[6];			/* FALSE or TRUE */
++  int cA_size = sizeof (cA);
++
++  result =
++    asn1_create_element (_gnutls_pkix_asn, "PKIX1.BasicConstraints",
++			 &basicasn);
++  if (result != ASN1_SUCCESS)
++    {
++      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			 "Could not create ASN.1 structure for Basic Constraints");
++    }
++
++  result = asn1_der_decoding2 (&basicasn, value, &value_size,
++			       ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
++  if (result != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Error parsing DER for Basic Constraints: %s",
++		    asn1_error);
++      goto cleanup;
++    }
++
++  result = asn1_read_value (basicasn, "cA", cA, &cA_size);
++  if (result == ASN1_ELEMENT_NOT_FOUND)
++    {
++      /* Not present, default is False, so this is OK */
++      err = GRUB_ERR_NONE;
++      goto cleanup;
++    }
++  else if (result != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Error reading Basic Constraints cA value: %s",
++		    asn1_strerror (result));
++      goto cleanup;
++    }
++
++  /* The certificate must not be a CA certificate */
++  if (grub_strncmp ("FALSE", cA, cA_size) != 0)
++    {
++      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected CA value: %s",
++			cA);
++      goto cleanup;
++    }
++
++cleanup:
++  asn1_delete_structure (&basicasn);
++  return err;
++}
++
++
++/*
++ * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
++ *
++ * Extension  ::=  SEQUENCE  {
++ *      extnID      OBJECT IDENTIFIER,
++ *      critical    BOOLEAN DEFAULT FALSE,
++ *      extnValue   OCTET STRING
++ *                  -- contains the DER encoding of an ASN.1 value
++ *                  -- corresponding to the extension type identified
++ *                  -- by extnID
++ * }
++ *
++ * We require that a certificate:
++ *  - contain the Digital Signature usage only
++ *  - not be a CA
++ *  - MUST not contain any other critical extensions (RFC 5280 s 4.2)
++ */
++static grub_err_t
++verify_extensions (asn1_node cert)
++{
++  int result;
++  int ext, num_extensions = 0;
++  int usage_present = 0, constraints_present = 0;
++  char *oid_path, *critical_path, *value_path;
++  char extnID[MAX_OID_LEN];
++  int extnID_size;
++  grub_err_t err;
++  char critical[6];		/* we get either "TRUE" or "FALSE" */
++  int critical_size;
++  grub_uint8_t *value;
++  int value_size;
++
++  result =
++    asn1_number_of_elements (cert, "tbsCertificate.extensions",
++			     &num_extensions);
++  if (result != ASN1_SUCCESS)
++    {
++      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			 "Error counting number of extensions: %s",
++			 asn1_strerror (result));
++    }
++
++  if (num_extensions < 2)
++    {
++      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			 "Insufficient number of extensions for certificate, need at least 2, got %d",
++			 num_extensions);
++    }
++
++  for (ext = 1; ext <= num_extensions; ext++)
++    {
++      oid_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnID", ext);
++
++      extnID_size = sizeof (extnID);
++      result = asn1_read_value (cert, oid_path, extnID, &extnID_size);
++      if (result != GRUB_ERR_NONE)
++	{
++	  err =
++	    grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			"Error reading extension OID: %s",
++			asn1_strerror (result));
++	  goto cleanup_oid_path;
++	}
++
++      critical_path =
++	grub_xasprintf ("tbsCertificate.extensions.?%d.critical", ext);
++      critical_size = sizeof (critical);
++      result =
++	asn1_read_value (cert, critical_path, critical, &critical_size);
++      if (result == ASN1_ELEMENT_NOT_FOUND)
++	{
++	  critical[0] = '\0';
++	}
++      else if (result != ASN1_SUCCESS)
++	{
++	  err =
++	    grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			"Error reading extension criticality: %s",
++			asn1_strerror (result));
++	  goto cleanup_critical_path;
++	}
++
++      value_path =
++	grub_xasprintf ("tbsCertificate.extensions.?%d.extnValue", ext);
++      value =
++	grub_asn1_allocate_and_read (cert, value_path,
++				     "certificate extension value",
++				     &value_size);
++      if (!value)
++	{
++	  err = grub_errno;
++	  goto cleanup_value_path;
++	}
++
++      /*
++       * Now we must see if we recognise the OID.
++       * If we have an unrecognised critical extension we MUST bail.
++       */
++      if (grub_strncmp (keyUsage_oid, extnID, extnID_size) == 0)
++	{
++	  err = verify_key_usage (value, value_size);
++	  if (err != GRUB_ERR_NONE)
++	    {
++	      goto cleanup_value;
++	    }
++	  usage_present++;
++	}
++      else if (grub_strncmp (basicConstraints_oid, extnID, extnID_size) == 0)
++	{
++	  err = verify_basic_constraints (value, value_size);
++	  if (err != GRUB_ERR_NONE)
++	    {
++	      goto cleanup_value;
++	    }
++	  constraints_present++;
++	}
++      else if (grub_strncmp ("TRUE", critical, critical_size) == 0)
++	{
++	  /*
++	   * per the RFC, we must not process a certificate with
++	   * a critical extension we do not understand.
++	   */
++	  err =
++	    grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			"Unhandled critical x509 extension with OID %s",
++			extnID);
++	  goto cleanup_value;
++	}
++
++      grub_free (value);
++      grub_free (value_path);
++      grub_free (critical_path);
++      grub_free (oid_path);
++    }
++
++  if (usage_present != 1)
++    {
++      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			 "Unexpected number of Key Usage extensions - expected 1, got %d",
++			 usage_present);
++    }
++  if (constraints_present != 1)
++    {
++      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			 "Unexpected number of basic constraints extensions - expected 1, got %d",
++			 constraints_present);
++    }
++  return GRUB_ERR_NONE;
++
++cleanup_value:
++  grub_free (value);
++cleanup_value_path:
++  grub_free (value_path);
++cleanup_critical_path:
++  grub_free (critical_path);
++cleanup_oid_path:
++  grub_free (oid_path);
++  return err;
++}
++
++/*
++ * Parse a certificate whose DER-encoded form is in @data, of size @data_size.
++ * Return the results in @results, which must point to an allocated x509 certificate.
++ */
++grub_err_t
++certificate_import (void *data, grub_size_t data_size,
++		    struct x509_certificate *results)
++{
++  int result = 0;
++  asn1_node cert;
++  grub_err_t err;
++  int size;
++  int tmp_size;
++
++  if (data_size > GRUB_INT_MAX)
++    return grub_error (GRUB_ERR_OUT_OF_RANGE,
++		       "Cannot parse a certificate where data size > INT_MAX");
++  size = (int) data_size;
++
++  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.Certificate", &cert);
++  if (result != ASN1_SUCCESS)
++    {
++      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			 "Could not create ASN.1 structure for certificate: %s",
++			 asn1_strerror (result));
++    }
++
++  result = asn1_der_decoding2 (&cert, data, &size,
++			       ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
++  if (result != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Could not parse DER for certificate: %s", asn1_error);
++      goto cleanup;
++    }
++
++  /* 
++   * TBSCertificate  ::=  SEQUENCE {
++   *     version         [0]  EXPLICIT Version DEFAULT v1
++   */
++  err = check_version (cert);
++  if (err != GRUB_ERR_NONE)
++    {
++      goto cleanup;
++    }
++
++  /*
++   * serialNumber         CertificateSerialNumber,
++   *
++   * CertificateSerialNumber  ::=  INTEGER
++   */
++  results->serial =
++    grub_asn1_allocate_and_read (cert, "tbsCertificate.serialNumber",
++				 "certificate serial number", &tmp_size);
++  if (!results->serial)
++    {
++      err = grub_errno;
++      goto cleanup;
++    }
++  /*
++   * It's safe to cast the signed int to an unsigned here, we know
++   * length is non-negative
++   */
++  results->serial_len = tmp_size;
++
++  /* 
++   * signature            AlgorithmIdentifier,
++   *
++   * We don't load the signature or issuer at the moment,
++   * as we don't attempt x509 verification.
++   */
++
++  /*
++   * issuer               Name,
++   *
++   * The RFC only requires the serial number to be unique within
++   * issuers, so to avoid ambiguity we _technically_ ought to make
++   * this available.
++   */
++
++  /*
++   * validity             Validity,
++   *
++   * Validity ::= SEQUENCE {
++   *     notBefore      Time,
++   *     notAfter       Time }
++   *
++   * We can't validate this reasonably, we have no true time source on several
++   * platforms. For now we do not parse them.
++   */
++
++  /*
++   * subject              Name,
++   * 
++   * This is an X501 name, we parse out just the CN.
++   */
++  err =
++    read_name (cert, "tbsCertificate.subject", &results->subject,
++	       &results->subject_len);
++  if (err != GRUB_ERR_NONE)
++    goto cleanup_serial;
++
++  /*
++   * TBSCertificate  ::=  SEQUENCE  {
++   *    ...
++   *    subjectPublicKeyInfo SubjectPublicKeyInfo,
++   *    ...
++   */
++  err = grub_x509_read_subject_public_key (cert, results);
++  if (err != GRUB_ERR_NONE)
++    goto cleanup_name;
++
++  /*
++   * TBSCertificate  ::=  SEQUENCE  {
++   *    ...
++   *    extensions      [3]  EXPLICIT Extensions OPTIONAL
++   *                         -- If present, version MUST be v3
++   * }
++   */
++
++  err = verify_extensions (cert);
++  if (err != GRUB_ERR_NONE)
++    goto cleanup_name;
++
++
++  /*
++   * We do not read or check the signature on the certificate:
++   * as discussed we do not try to validate the certificate but trust
++   * it implictly.
++   */
++
++  asn1_delete_structure (&cert);
++  return GRUB_ERR_NONE;
++
++
++cleanup_name:
++  grub_free (results->subject);
++cleanup_serial:
++  grub_free (results->serial);
++cleanup:
++  asn1_delete_structure (&cert);
++  return err;
++}
++
++/*
++ * Release all the storage associated with the x509 certificate.
++ * If the caller dynamically allocated the certificate, it must free it.
++ * The caller is also responsible for maintenance of the linked list.
++ */
++void
++certificate_release (struct x509_certificate *cert)
++{
++  grub_free (cert->subject);
++  grub_free (cert->serial);
++  gcry_mpi_release (cert->mpis[0]);
++  gcry_mpi_release (cert->mpis[1]);
++}
+diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h
+new file mode 100644
+index 0000000000..9792ef3901
+--- /dev/null
++++ b/grub-core/commands/appendedsig/appendedsig.h
+@@ -0,0 +1,110 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020  IBM Corporation.
++ *
++ *  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/crypto.h>
++#include <grub/libtasn1.h>
++
++extern asn1_node _gnutls_gnutls_asn;
++extern asn1_node _gnutls_pkix_asn;
++
++#define MAX_OID_LEN 32
++
++/*
++ * One or more x509 certificates.
++ *
++ * We do limited parsing: extracting only the serial, CN and RSA public key.
++ */
++struct x509_certificate
++{
++  struct x509_certificate *next;
++
++  grub_uint8_t *serial;
++  grub_size_t serial_len;
++
++  char *subject;
++  grub_size_t subject_len;
++
++  /* We only support RSA public keys. This encodes [modulus, publicExponent] */
++  gcry_mpi_t mpis[2];
++};
++
++/*
++ * A PKCS#7 signedData message.
++ *
++ * We make no attempt to match intelligently, so we don't save any info about
++ * the signer. We also support only 1 signerInfo, so we only store a single
++ * MPI for the signature.
++ */
++struct pkcs7_signedData
++{
++  const gcry_md_spec_t *hash;
++  gcry_mpi_t sig_mpi;
++};
++
++
++/* Do libtasn1 init */
++int asn1_init (void);
++
++/*
++ * Import a DER-encoded certificate at 'data', of size 'size'.
++ *
++ * Place the results into 'results', which must be already allocated.
++ */
++grub_err_t
++certificate_import (void *data, grub_size_t size,
++		    struct x509_certificate *results);
++
++/*
++ * Release all the storage associated with the x509 certificate.
++ * If the caller dynamically allocated the certificate, it must free it.
++ * The caller is also responsible for maintenance of the linked list.
++ */
++void certificate_release (struct x509_certificate *cert);
++
++/*
++ * Parse a PKCS#7 message, which must be a signedData message.
++ *
++ * The message must be in 'sigbuf' and of size 'data_size'. The result is
++ * placed in 'msg', which must already be allocated.
++ */
++grub_err_t
++parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size,
++			struct pkcs7_signedData *msg);
++
++/*
++ * Release all the storage associated with the PKCS#7 message.
++ * If the caller dynamically allocated the message, it must free it.
++ */
++void pkcs7_signedData_release (struct pkcs7_signedData *msg);
++
++/*
++ * Read a value from an ASN1 node, allocating memory to store it.
++ *
++ * It will work for anything where the size libtasn1 returns is right:
++ *  - Integers
++ *  - Octet strings
++ *  - DER encoding of other structures
++ * It will _not_ work for things where libtasn1 size requires adjustment:
++ *  - Strings that require an extra NULL byte at the end
++ *  - Bit strings because libtasn1 returns the length in bits, not bytes.
++ *
++ * If the function returns a non-NULL value, the caller must free it.
++ */
++void *grub_asn1_allocate_and_read (asn1_node node, const char *name,
++				   const char *friendly_name,
++				   int *content_size);
diff --git a/SOURCES/0169-grub-install-disable-support-for-EFI-platforms.patch b/SOURCES/0169-grub-install-disable-support-for-EFI-platforms.patch
deleted file mode 100644
index 41003e2..0000000
--- a/SOURCES/0169-grub-install-disable-support-for-EFI-platforms.patch
+++ /dev/null
@@ -1,120 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Jan Hlavac <jhlavac@redhat.com>
-Date: Fri, 20 Nov 2020 23:51:47 +0100
-Subject: [PATCH] grub-install: disable support for EFI platforms
-
-For each platform, GRUB is shipped as a kernel image and a set of
-modules. These files are then used by the grub-install utility to
-install GRUB on a specific device. However, in order to support UEFI
-Secure Boot, the resulting EFI binary must be signed by a recognized
-private key. For this reason, for EFI platforms, most distributions also
-ship prebuilt EFI binaries signed by a distribution-specific private
-key. In this case, however, the grub-install utility should not be used
-because it would overwrite the signed EFI binary.
-
-The current fix is suboptimal because it preserves all EFI-related code.
-A better solution could be to modularize the code and provide a
-build-time option.
-
-Resolves: rhbz#1737444
-
-Signed-off-by: Jan Hlavac <jhlavac@redhat.com>
----
- util/grub-install.c | 37 ++++++++++++++++---------------------
- docs/grub.texi      |  7 +++++++
- util/grub-install.8 |  4 +++-
- 3 files changed, 26 insertions(+), 22 deletions(-)
-
-diff --git a/util/grub-install.c b/util/grub-install.c
-index a2bec7446cb..5babc7af551 100644
---- a/util/grub-install.c
-+++ b/util/grub-install.c
-@@ -899,6 +899,22 @@ main (int argc, char *argv[])
- 
-   platform = grub_install_get_target (grub_install_source_directory);
- 
-+  switch (platform)
-+    {
-+    case GRUB_INSTALL_PLATFORM_ARM_EFI:
-+    case GRUB_INSTALL_PLATFORM_ARM64_EFI:
-+    case GRUB_INSTALL_PLATFORM_I386_EFI:
-+    case GRUB_INSTALL_PLATFORM_IA64_EFI:
-+    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
-+      is_efi = 1;
-+      grub_util_error (_("this utility cannot be used for EFI platforms"
-+                         " because it does not support UEFI Secure Boot"));
-+      break;
-+    default:
-+      is_efi = 0;
-+      break;
-+    }
-+
-   {
-     char *platname = grub_install_get_platform_name (platform);
-     fprintf (stderr, _("Installing for %s platform.\n"), platname);
-@@ -1011,28 +1027,7 @@ main (int argc, char *argv[])
-   grub_hostfs_init ();
-   grub_host_init ();
- 
--  switch (platform)
--    {
--    case GRUB_INSTALL_PLATFORM_I386_EFI:
--    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
--    case GRUB_INSTALL_PLATFORM_ARM_EFI:
--    case GRUB_INSTALL_PLATFORM_ARM64_EFI:
--    case GRUB_INSTALL_PLATFORM_RISCV32_EFI:
--    case GRUB_INSTALL_PLATFORM_RISCV64_EFI:
--    case GRUB_INSTALL_PLATFORM_IA64_EFI:
--      is_efi = 1;
--      break;
--    default:
--      is_efi = 0;
--      break;
--
--      /* pacify warning.  */
--    case GRUB_INSTALL_PLATFORM_MAX:
--      break;
--    }
--
-   /* Find the EFI System Partition.  */
--
-   if (is_efi)
-     {
-       grub_fs_t fs;
-diff --git a/docs/grub.texi b/docs/grub.texi
-index 04ed6ac1f07..4870faaa00a 100644
---- a/docs/grub.texi
-+++ b/docs/grub.texi
-@@ -6509,6 +6509,13 @@ grub2-install @var{install_device}
- The device name @var{install_device} is an OS device name or a GRUB
- device name.
- 
-+In order to support UEFI Secure Boot, the resulting GRUB EFI binary must
-+be signed by a recognized private key. For this reason, for EFI
-+platforms, most distributions also ship prebuilt GRUB EFI binaries
-+signed by a distribution-specific private key. In this case, however,
-+@command{grub2-install} should not be used because it would overwrite
-+the signed EFI binary.
-+
- @command{grub2-install} accepts the following options:
- 
- @table @option
-diff --git a/util/grub-install.8 b/util/grub-install.8
-index 1db89e94b3b..811d441b16c 100644
---- a/util/grub-install.8
-+++ b/util/grub-install.8
-@@ -1,4 +1,4 @@
--.TH GRUB-INSTALL 1 "Wed Feb 26 2014"
-+.TH GRUB-INSTALL 1 "Fri Nov 20 2020"
- .SH NAME
- \fBgrub-install\fR \(em Install GRUB on a device.
- 
-@@ -31,6 +31,8 @@
- .SH DESCRIPTION
- \fBgrub-install\fR installs GRUB onto a device.  This includes copying GRUB images into the target directory (generally \fI/boot/grub\fR), and on some platforms may also include installing GRUB onto a boot sector.
- 
-+In order to support UEFI Secure Boot, the resulting GRUB EFI binary must be signed by a recognized private key. For this reason, for EFI platforms, most distributions also ship prebuilt GRUB EFI binaries signed by a distribution-specific private key. In this case, however, the \fBgrub-install\fR utility should not be used because it would overwrite the signed EFI binary.
-+
- .SH OPTIONS
- .TP
- \fB--modules\fR=\fIMODULES\fR\!
diff --git a/SOURCES/0170-New-with-debug-timestamps-configure-flag-to-prepend-.patch b/SOURCES/0170-New-with-debug-timestamps-configure-flag-to-prepend-.patch
deleted file mode 100644
index 3eb0d00..0000000
--- a/SOURCES/0170-New-with-debug-timestamps-configure-flag-to-prepend-.patch
+++ /dev/null
@@ -1,112 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
-Date: Sat, 23 Nov 2019 14:57:41 +0100
-Subject: [PATCH] New --with-debug-timestamps configure flag to prepend debug
- traces with absolute and relative timestamp
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
----
- configure.ac          | 18 ++++++++++++++++++
- grub-core/kern/misc.c | 20 ++++++++++++++++++++
- config.h.in           |  1 +
- 3 files changed, 39 insertions(+)
-
-diff --git a/configure.ac b/configure.ac
-index 907477a585c..d5d2a28b4ef 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1613,6 +1613,17 @@ else
- fi
- AC_SUBST([BOOT_TIME_STATS])
- 
-+AC_ARG_WITH([debug-timestamps],
-+	   AS_HELP_STRING([--with-debug-timestamps],
-+                          [prepend debug traces with absolute and relative timestamps]))
-+
-+if test x$with_debug_timestamps = xyes; then
-+  DEBUG_WITH_TIMESTAMPS=1
-+else
-+  DEBUG_WITH_TIMESTAMPS=0
-+fi
-+AC_SUBST([DEBUG_WITH_TIMESTAMPS])
-+
- AC_ARG_ENABLE([grub-emu-sdl],
- 	      [AS_HELP_STRING([--enable-grub-emu-sdl],
-                              [build and install the `grub-emu' debugging utility with SDL support (default=guessed)])])
-@@ -2200,6 +2211,7 @@ AM_CONDITIONAL([COND_APPLE_LINKER], [test x$TARGET_APPLE_LINKER = x1])
- AM_CONDITIONAL([COND_ENABLE_EFIEMU], [test x$enable_efiemu = xyes])
- AM_CONDITIONAL([COND_ENABLE_CACHE_STATS], [test x$DISK_CACHE_STATS = x1])
- AM_CONDITIONAL([COND_ENABLE_BOOT_TIME_STATS], [test x$BOOT_TIME_STATS = x1])
-+AM_CONDITIONAL([COND_DEBUG_WITH_TIMESTAMPS], [test x$DEBUG_WITH_TIMESTAMPS = x1])
- 
- AM_CONDITIONAL([COND_HAVE_CXX], [test x$HAVE_CXX = xyes])
- 
-@@ -2295,6 +2307,12 @@ else
- echo With boot time statistics: No
- fi
- 
-+if [ x"$with_debug_timestamps" = xyes ]; then
-+echo Debug traces with timestamps: Yes
-+else
-+echo Debug traces with timestamps: No
-+fi
-+
- if [ x"$efiemu_excuse" = x ]; then
- echo efiemu runtime: Yes
- else
-diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
-index 578bf51a5fc..9f54b6b7d2d 100644
---- a/grub-core/kern/misc.c
-+++ b/grub-core/kern/misc.c
-@@ -25,6 +25,9 @@
- #include <grub/env.h>
- #include <grub/i18n.h>
- #include <grub/backtrace.h>
-+#if DEBUG_WITH_TIMESTAMPS
-+#include <grub/time.h>
-+#endif
- 
- union printf_arg
- {
-@@ -192,9 +195,26 @@ grub_real_dprintf (const char *file, const int line, const char *condition,
- 		   const char *fmt, ...)
- {
-   va_list args;
-+#if DEBUG_WITH_TIMESTAMPS
-+  static long unsigned int last_time = 0;
-+  static int last_had_cr = 1;
-+#endif
- 
-   if (grub_debug_enabled (condition))
-     {
-+#if DEBUG_WITH_TIMESTAMPS
-+      /* Don't print timestamp if last printed message isn't terminated yet */
-+      if (last_had_cr) {
-+        long unsigned int tmabs = (long unsigned int) grub_get_time_ms();
-+        long unsigned int tmrel = tmabs - last_time;
-+        last_time = tmabs;
-+        grub_printf ("%3lu.%03lus +%2lu.%03lus ", tmabs / 1000, tmabs % 1000, tmrel / 1000, tmrel % 1000);
-+      }
-+      if (fmt[grub_strlen(fmt)-1] == '\n')
-+        last_had_cr = 1;
-+      else
-+        last_had_cr = 0;
-+#endif
-       grub_printf ("%s:%d: ", file, line);
-       va_start (args, fmt);
-       grub_vprintf (fmt, args);
-diff --git a/config.h.in b/config.h.in
-index c7e316f0f1f..c80e3e0aba3 100644
---- a/config.h.in
-+++ b/config.h.in
-@@ -12,6 +12,7 @@
- /* Define to 1 to enable disk cache statistics.  */
- #define DISK_CACHE_STATS @DISK_CACHE_STATS@
- #define BOOT_TIME_STATS @BOOT_TIME_STATS@
-+#define DEBUG_WITH_TIMESTAMPS @DEBUG_WITH_TIMESTAMPS@
- 
- /* We don't need those.  */
- #define MINILZO_CFG_SKIP_LZO_PTR 1
diff --git a/SOURCES/0170-appended-signatures-support-verifying-appended-signa.patch b/SOURCES/0170-appended-signatures-support-verifying-appended-signa.patch
new file mode 100644
index 0000000..9e90d3b
--- /dev/null
+++ b/SOURCES/0170-appended-signatures-support-verifying-appended-signa.patch
@@ -0,0 +1,718 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 30 Jul 2020 01:35:43 +1000
+Subject: [PATCH] appended signatures: support verifying appended signatures
+
+Building on the parsers and the ability to embed x509 certificates, as
+well as the existing gcrypt functionality, add a module for verifying
+appended signatures.
+
+This includes a verifier that requires that Linux kernels and grub modules
+have appended signatures, and commands to manage the list of trusted
+certificates for verification.
+
+Verification must be enabled by setting check_appended_signatures. If
+GRUB is locked down when the module is loaded, verification will be
+enabled and locked automatically.
+
+As with the PGP verifier, it is not a complete secure-boot solution:
+other mechanisms, such as a password or lockdown, must be used to ensure
+that a user cannot drop to the grub shell and disable verification.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+[pjones: fix missing format specifier]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/Makefile.core.def                  |  12 +
+ grub-core/commands/appendedsig/appendedsig.c | 645 +++++++++++++++++++++++++++
+ include/grub/file.h                          |   2 +
+ 3 files changed, 659 insertions(+)
+ create mode 100644 grub-core/commands/appendedsig/appendedsig.c
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index a32e6ada59..6404384d90 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -980,6 +980,18 @@ module = {
+   cppflags = '-I$(srcdir)/lib/posix_wrap';
+ };
+ 
++module = {
++  name = appendedsig;
++  common = commands/appendedsig/appendedsig.c;
++  common = commands/appendedsig/x509.c;
++  common = commands/appendedsig/pkcs7.c;
++  common = commands/appendedsig/asn1util.c;
++  common = commands/appendedsig/gnutls_asn1_tab.c;
++  common = commands/appendedsig/pkix_asn1_tab.c;
++  cflags = '$(CFLAGS_POSIX)';
++  cppflags = '-I$(srcdir)/lib/posix_wrap';
++};
++
+ module = {
+   name = hdparm;
+   common = commands/hdparm.c;
+diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
+new file mode 100644
+index 0000000000..bf8b18b620
+--- /dev/null
++++ b/grub-core/commands/appendedsig/appendedsig.c
+@@ -0,0 +1,645 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020-2021  IBM Corporation.
++ *
++ *  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/file.h>
++#include <grub/command.h>
++#include <grub/crypto.h>
++#include <grub/pkcs1_v15.h>
++#include <grub/i18n.h>
++#include <grub/gcrypt/gcrypt.h>
++#include <grub/kernel.h>
++#include <grub/extcmd.h>
++#include <grub/verify.h>
++#include <grub/libtasn1.h>
++#include <grub/env.h>
++#include <grub/lockdown.h>
++
++#include "appendedsig.h"
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++const char magic[] = "~Module signature appended~\n";
++
++/*
++ * This structure is extracted from scripts/sign-file.c in the linux kernel
++ * source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible.
++ */
++struct module_signature
++{
++  grub_uint8_t algo;		/* Public-key crypto algorithm [0] */
++  grub_uint8_t hash;		/* Digest algorithm [0] */
++  grub_uint8_t id_type;		/* Key identifier type [PKEY_ID_PKCS7] */
++  grub_uint8_t signer_len;	/* Length of signer's name [0] */
++  grub_uint8_t key_id_len;	/* Length of key identifier [0] */
++  grub_uint8_t __pad[3];
++  grub_uint32_t sig_len;	/* Length of signature data */
++} GRUB_PACKED;
++
++
++/* This represents an entire, parsed, appended signature */
++struct grub_appended_signature
++{
++  grub_size_t signature_len;		/* Length of PKCS#7 data +
++                                         * metadata + magic */
++
++  struct module_signature sig_metadata;	/* Module signature metadata */
++  struct pkcs7_signedData pkcs7;	/* Parsed PKCS#7 data */
++};
++
++/* Trusted certificates for verifying appended signatures */
++struct x509_certificate *grub_trusted_key;
++
++/*
++ * Force gcry_rsa to be a module dependency.
++ *
++ * If we use grub_crypto_pk_rsa, then then the gcry_rsa module won't be built
++ * in if you add 'appendedsig' to grub-install --modules. You would need to
++ * add 'gcry_rsa' too. That's confusing and seems suboptimal, especially when
++ * we only support RSA.
++ *
++ * Dynamic loading also causes some concerns. We can't load gcry_rsa from the
++ * the filesystem after we install the verifier - we won't be able to verify
++ * it without having it already present. We also shouldn't load it before we
++ * install the verifier, because that would mean it wouldn't be verified - an
++ * attacker could insert any code they wanted into the module.
++ *
++ * So instead, reference the internal symbol from gcry_rsa. That creates a
++ * direct dependency on gcry_rsa, so it will be built in when this module
++ * is built in. Being built in (assuming the core image is itself signed!)
++ * also resolves our concerns about loading from the filesystem.
++ */
++extern gcry_pk_spec_t _gcry_pubkey_spec_rsa;
++
++static int check_sigs = 0;
++
++static const char *
++grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)),
++                   const char *val __attribute__ ((unused)))
++{
++  if (check_sigs == 2)
++    return "forced";
++  else if (check_sigs == 1)
++    return "enforce";
++  else
++    return "no";
++}
++
++static char *
++grub_env_write_sec (struct grub_env_var *var __attribute__((unused)),
++		    const char *val)
++{
++  /* Do not allow the value to be changed if set to forced */
++  if (check_sigs == 2)
++    return grub_strdup ("forced");
++
++  if ((*val == '2') || (*val == 'f'))
++    check_sigs = 2;
++  else if ((*val == '1') || (*val == 'e'))
++    check_sigs = 1;
++  else if ((*val == '0') || (*val == 'n'))
++    check_sigs = 0;
++
++  return grub_strdup (grub_env_read_sec (NULL, NULL));
++}
++
++static grub_err_t
++read_cert_from_file (grub_file_t f, struct x509_certificate *certificate)
++{
++  grub_err_t err;
++  grub_uint8_t *buf = NULL;
++  grub_ssize_t read_size;
++  grub_off_t total_read_size = 0;
++  grub_off_t file_size = grub_file_size (f);
++
++
++  if (file_size == GRUB_FILE_SIZE_UNKNOWN)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT,
++		       N_("Cannot parse a certificate file of unknown size"));
++
++  buf = grub_zalloc (file_size);
++  if (!buf)
++    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++		       N_("Could not allocate buffer for certificate file contents"));
++
++  while (total_read_size < file_size)
++    {
++      read_size =
++	grub_file_read (f, &buf[total_read_size],
++			file_size - total_read_size);
++      if (read_size < 0)
++	{
++	  err = grub_error (GRUB_ERR_READ_ERROR,
++			    N_("Error reading certificate file"));
++	  goto cleanup_buf;
++	}
++      total_read_size += read_size;
++    }
++
++  err = certificate_import (buf, total_read_size, certificate);
++  if (err != GRUB_ERR_NONE)
++    goto cleanup_buf;
++
++  return GRUB_ERR_NONE;
++
++cleanup_buf:
++  grub_free (buf);
++  return err;
++}
++
++static grub_err_t
++extract_appended_signature (grub_uint8_t * buf, grub_size_t bufsize,
++			    struct grub_appended_signature *sig)
++{
++  grub_err_t err;
++  grub_size_t pkcs7_size;
++  grub_size_t remaining_len;
++  grub_uint8_t *appsigdata = buf + bufsize - grub_strlen (magic);
++
++  if (bufsize < grub_strlen (magic))
++    return grub_error (GRUB_ERR_BAD_SIGNATURE,
++		       N_("File too short for signature magic"));
++
++  if (grub_memcmp (appsigdata, (grub_uint8_t *) magic, grub_strlen (magic)))
++    return grub_error (GRUB_ERR_BAD_SIGNATURE,
++		       N_("Missing or invalid signature magic"));
++
++  remaining_len = bufsize - grub_strlen (magic);
++
++  if (remaining_len < sizeof (struct module_signature))
++    return grub_error (GRUB_ERR_BAD_SIGNATURE,
++		       N_("File too short for signature metadata"));
++
++  appsigdata -= sizeof (struct module_signature);
++
++  /* extract the metadata */
++  grub_memcpy (&(sig->sig_metadata), appsigdata,
++	       sizeof (struct module_signature));
++
++  remaining_len -= sizeof (struct module_signature);
++
++  if (sig->sig_metadata.id_type != 2)
++    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Wrong signature type"));
++
++#ifdef GRUB_TARGET_WORDS_BIGENDIAN
++  pkcs7_size = sig->sig_metadata.sig_len;
++#else
++  pkcs7_size = __builtin_bswap32 (sig->sig_metadata.sig_len);
++#endif
++
++  if (pkcs7_size > remaining_len)
++    return grub_error (GRUB_ERR_BAD_SIGNATURE,
++		       N_("File too short for PKCS#7 message"));
++
++  grub_dprintf ("appendedsig", "sig len %" PRIuGRUB_SIZE "\n", pkcs7_size);
++
++  sig->signature_len =
++    grub_strlen (magic) + sizeof (struct module_signature) + pkcs7_size;
++
++  /* rewind pointer and parse pkcs7 data */
++  appsigdata -= pkcs7_size;
++
++  err = parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7);
++  if (err != GRUB_ERR_NONE)
++    return err;
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_verify_appended_signature (grub_uint8_t * buf, grub_size_t bufsize)
++{
++  grub_err_t err = GRUB_ERR_NONE;
++  grub_size_t datasize;
++  void *context;
++  unsigned char *hash;
++  gcry_mpi_t hashmpi;
++  gcry_err_code_t rc;
++  struct x509_certificate *pk;
++  struct grub_appended_signature sig;
++
++  if (!grub_trusted_key)
++    return grub_error (GRUB_ERR_BAD_SIGNATURE,
++		       N_("No trusted keys to verify against"));
++
++  err = extract_appended_signature (buf, bufsize, &sig);
++  if (err != GRUB_ERR_NONE)
++    return err;
++
++  datasize = bufsize - sig.signature_len;
++
++  context = grub_zalloc (sig.pkcs7.hash->contextsize);
++  if (!context)
++    return grub_errno;
++
++  sig.pkcs7.hash->init (context);
++  sig.pkcs7.hash->write (context, buf, datasize);
++  sig.pkcs7.hash->final (context);
++  hash = sig.pkcs7.hash->read (context);
++  grub_dprintf ("appendedsig",
++		"data size %" PRIxGRUB_SIZE ", hash %02x%02x%02x%02x...\n",
++		datasize, hash[0], hash[1], hash[2], hash[3]);
++
++  err = GRUB_ERR_BAD_SIGNATURE;
++  for (pk = grub_trusted_key; pk; pk = pk->next)
++    {
++      rc = grub_crypto_rsa_pad (&hashmpi, hash, sig.pkcs7.hash, pk->mpis[0]);
++      if (rc)
++	{
++	  err = grub_error (GRUB_ERR_BAD_SIGNATURE,
++			    N_("Error padding hash for RSA verification: %d"),
++			    rc);
++	  goto cleanup;
++	}
++
++      rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &sig.pkcs7.sig_mpi,
++					 pk->mpis, NULL, NULL);
++      gcry_mpi_release (hashmpi);
++
++      if (rc == 0)
++	{
++	  grub_dprintf ("appendedsig", "verify with key '%s' succeeded\n",
++			pk->subject);
++	  err = GRUB_ERR_NONE;
++	  break;
++	}
++
++      grub_dprintf ("appendedsig", "verify with key '%s' failed with %d\n",
++		    pk->subject, rc);
++    }
++
++  /* If we didn't verify, provide a neat message */
++  if (err != GRUB_ERR_NONE)
++      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
++			N_("Failed to verify signature against a trusted key"));
++
++cleanup:
++  grub_free (context);
++  pkcs7_signedData_release (&sig.pkcs7);
++
++  return err;
++}
++
++static grub_err_t
++grub_cmd_verify_signature (grub_command_t cmd __attribute__((unused)),
++			   int argc, char **args)
++{
++  grub_file_t f;
++  grub_err_t err = GRUB_ERR_NONE;
++  grub_uint8_t *data;
++  grub_ssize_t read_size;
++  grub_off_t file_size, total_read_size = 0;
++
++  if (argc < 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
++
++  grub_dprintf ("appendedsig", "verifying %s\n", args[0]);
++
++  f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
++  if (!f)
++    {
++      err = grub_errno;
++      goto cleanup;
++    }
++
++  file_size = grub_file_size (f);
++  if (file_size == GRUB_FILE_SIZE_UNKNOWN)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT,
++		       N_("Cannot verify the signature of a file of unknown size"));
++
++  data = grub_malloc (file_size);
++  if (!data)
++    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++		       N_("Could not allocate data buffer size %"
++		       PRIuGRUB_UINT64_T " for verification"), file_size);
++
++  while (total_read_size < file_size)
++    {
++      read_size =
++	grub_file_read (f, &data[total_read_size],
++			file_size - total_read_size);
++      if (read_size < 0)
++	{
++	  err = grub_error (GRUB_ERR_READ_ERROR,
++			    N_("Error reading file to verify"));
++	  goto cleanup_data;
++	}
++      total_read_size += read_size;
++    }
++
++  err = grub_verify_appended_signature (data, file_size);
++
++cleanup_data:
++  grub_free (data);
++cleanup:
++  if (f)
++    grub_file_close (f);
++  return err;
++}
++
++static grub_err_t
++grub_cmd_distrust (grub_command_t cmd __attribute__((unused)),
++		   int argc, char **args)
++{
++  unsigned long cert_num, i;
++  struct x509_certificate *cert, *prev;
++
++  if (argc != 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("One argument expected"));
++
++  grub_errno = GRUB_ERR_NONE;
++  cert_num = grub_strtoul (args[0], NULL, 10);
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
++
++  if (cert_num < 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT,
++		       N_("Certificate number too small - numbers start at 1"));
++
++  if (cert_num == 1)
++    {
++      cert = grub_trusted_key;
++      grub_trusted_key = cert->next;
++
++      certificate_release (cert);
++      grub_free (cert);
++      return GRUB_ERR_NONE;
++    }
++  i = 2;
++  prev = grub_trusted_key;
++  cert = grub_trusted_key->next;
++  while (cert)
++    {
++      if (i == cert_num)
++	{
++	  prev->next = cert->next;
++	  certificate_release (cert);
++	  grub_free (cert);
++	  return GRUB_ERR_NONE;
++	}
++      i++;
++      prev = cert;
++      cert = cert->next;
++    }
++
++  return grub_error (GRUB_ERR_BAD_ARGUMENT,
++		     N_("No certificate number %d found - only %d certificates in the store"),
++		     cert_num, i - 1);
++}
++
++static grub_err_t
++grub_cmd_trust (grub_command_t cmd __attribute__((unused)),
++		int argc, char **args)
++{
++  grub_file_t certf;
++  struct x509_certificate *cert = NULL;
++  grub_err_t err;
++
++  if (argc != 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
++
++  certf = grub_file_open (args[0],
++			  GRUB_FILE_TYPE_CERTIFICATE_TRUST
++			  | GRUB_FILE_TYPE_NO_DECOMPRESS);
++  if (!certf)
++    return grub_errno;
++
++
++  cert = grub_zalloc (sizeof (struct x509_certificate));
++  if (!cert)
++    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++		       N_("Could not allocate memory for certificate"));
++
++  err = read_cert_from_file (certf, cert);
++  grub_file_close (certf);
++  if (err != GRUB_ERR_NONE)
++    {
++      grub_free (cert);
++      return err;
++    }
++  grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n",
++		cert->subject);
++
++  cert->next = grub_trusted_key;
++  grub_trusted_key = cert;
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_cmd_list (grub_command_t cmd __attribute__((unused)),
++	       int argc __attribute__((unused)),
++	       char **args __attribute__((unused)))
++{
++  struct x509_certificate *cert;
++  int cert_num = 1;
++  grub_size_t i;
++
++  for (cert = grub_trusted_key; cert; cert = cert->next)
++    {
++      grub_printf (N_("Certificate %d:\n"), cert_num);
++
++      grub_printf (N_("\tSerial: "));
++      for (i = 0; i < cert->serial_len - 1; i++)
++	{
++	  grub_printf ("%02x:", cert->serial[i]);
++	}
++      grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]);
++
++      grub_printf ("\tCN: %s\n\n", cert->subject);
++      cert_num++;
++
++    }
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++appendedsig_init (grub_file_t io __attribute__((unused)),
++		  enum grub_file_type type,
++		  void **context __attribute__((unused)),
++		  enum grub_verify_flags *flags)
++{
++  if (!check_sigs)
++    {
++      *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
++      return GRUB_ERR_NONE;
++    }
++
++  switch (type & GRUB_FILE_TYPE_MASK)
++    {
++    case GRUB_FILE_TYPE_CERTIFICATE_TRUST:
++      /*
++       * This is a certificate to add to trusted keychain.
++       *
++       * This needs to be verified or blocked. Ideally we'd write an x509
++       * verifier, but we lack the hubris required to take this on. Instead,
++       * require that it have an appended signature.
++       */
++
++      /* Fall through */
++
++    case GRUB_FILE_TYPE_LINUX_KERNEL:
++    case GRUB_FILE_TYPE_GRUB_MODULE:
++      /*
++       * Appended signatures are only defined for ELF binaries.
++       * Out of an abundance of caution, we only verify Linux kernels and
++       * GRUB modules at this point.
++       */
++      *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
++      return GRUB_ERR_NONE;
++
++    case GRUB_FILE_TYPE_ACPI_TABLE:
++    case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE:
++      /*
++       * It is possible to use appended signature verification without
++       * lockdown - like the PGP verifier. When combined with an embedded
++       * config file in a signed grub binary, this could still be a meaningful
++       * secure-boot chain - so long as it isn't subverted by something like a
++       * rouge ACPI table or DT image. Defer them explicitly.
++       */
++      *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH;
++      return GRUB_ERR_NONE;
++
++    default:
++      *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
++      return GRUB_ERR_NONE;
++    }
++}
++
++static grub_err_t
++appendedsig_write (void *ctxt __attribute__((unused)),
++		   void *buf, grub_size_t size)
++{
++  return grub_verify_appended_signature (buf, size);
++}
++
++struct grub_file_verifier grub_appendedsig_verifier = {
++  .name = "appendedsig",
++  .init = appendedsig_init,
++  .write = appendedsig_write,
++};
++
++static grub_ssize_t
++pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
++{
++  grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
++  return len;
++}
++
++/* Filesystem descriptor.  */
++static struct grub_fs pseudo_fs = {
++  .name = "pseudo",
++  .fs_read = pseudo_read
++};
++
++static grub_command_t cmd_verify, cmd_list, cmd_distrust, cmd_trust;
++
++GRUB_MOD_INIT (appendedsig)
++{
++  int rc;
++  struct grub_module_header *header;
++
++  /* If in lockdown, immediately enter forced mode */
++  if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED)
++    check_sigs = 2;
++
++  grub_trusted_key = NULL;
++
++  grub_register_variable_hook ("check_appended_signatures",
++  			       grub_env_read_sec,
++			       grub_env_write_sec);
++  grub_env_export ("check_appended_signatures");
++
++  rc = asn1_init ();
++  if (rc)
++    grub_fatal ("Error initing ASN.1 data structures: %d: %s\n", rc,
++		asn1_strerror (rc));
++
++  FOR_MODULES (header)
++  {
++    struct grub_file pseudo_file;
++    struct x509_certificate *pk = NULL;
++    grub_err_t err;
++
++    /* Not an ELF module, skip.  */
++    if (header->type != OBJ_TYPE_X509_PUBKEY)
++      continue;
++
++    grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
++    pseudo_file.fs = &pseudo_fs;
++    pseudo_file.size = header->size - sizeof (struct grub_module_header);
++    pseudo_file.data = (char *) header + sizeof (struct grub_module_header);
++
++    grub_dprintf ("appendedsig",
++		  "Found an x509 key, size=%" PRIuGRUB_UINT64_T "\n",
++		  pseudo_file.size);
++
++    pk = grub_zalloc (sizeof (struct x509_certificate));
++    if (!pk)
++      {
++	grub_fatal ("Out of memory loading initial certificates");
++      }
++
++    err = read_cert_from_file (&pseudo_file, pk);
++    if (err != GRUB_ERR_NONE)
++      grub_fatal ("Error loading initial key: %s", grub_errmsg);
++
++    grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", pk->subject);
++
++    pk->next = grub_trusted_key;
++    grub_trusted_key = pk;
++  }
++
++  cmd_trust =
++    grub_register_command ("trust_certificate", grub_cmd_trust,
++			   N_("X509_CERTIFICATE"),
++			   N_("Add X509_CERTIFICATE to trusted certificates."));
++  cmd_list =
++    grub_register_command ("list_certificates", grub_cmd_list, 0,
++			   N_("Show the list of trusted x509 certificates."));
++  cmd_verify =
++    grub_register_command ("verify_appended", grub_cmd_verify_signature,
++			   N_("FILE"),
++			   N_("Verify FILE against the trusted x509 certificates."));
++  cmd_distrust =
++    grub_register_command ("distrust_certificate", grub_cmd_distrust,
++			   N_("CERT_NUMBER"),
++			   N_("Remove CERT_NUMBER (as listed by list_certificates) from trusted certificates."));
++
++  grub_verifier_register (&grub_appendedsig_verifier);
++  grub_dl_set_persistent (mod);
++}
++
++GRUB_MOD_FINI (appendedsig)
++{
++  /*
++   * grub_dl_set_persistent should prevent this from actually running, but
++   * it does still run under emu.
++   */
++
++  grub_verifier_unregister (&grub_appendedsig_verifier);
++  grub_unregister_command (cmd_verify);
++  grub_unregister_command (cmd_list);
++  grub_unregister_command (cmd_trust);
++  grub_unregister_command (cmd_distrust);
++}
+diff --git a/include/grub/file.h b/include/grub/file.h
+index 31567483cc..96827a4f89 100644
+--- a/include/grub/file.h
++++ b/include/grub/file.h
+@@ -80,6 +80,8 @@ enum grub_file_type
+     GRUB_FILE_TYPE_PUBLIC_KEY,
+     /* File holding public key to add to trused keys.  */
+     GRUB_FILE_TYPE_PUBLIC_KEY_TRUST,
++    /* File holding x509 certificiate to add to trusted keys.  */
++    GRUB_FILE_TYPE_CERTIFICATE_TRUST,
+     /* File of which we intend to print a blocklist to the user.  */
+     GRUB_FILE_TYPE_PRINT_BLOCKLIST,
+     /* File we intend to use for test loading or testing speed.  */
diff --git a/SOURCES/0171-Added-debug-statements-to-grub_disk_open-and-grub_di.patch b/SOURCES/0171-Added-debug-statements-to-grub_disk_open-and-grub_di.patch
deleted file mode 100644
index cbb1a38..0000000
--- a/SOURCES/0171-Added-debug-statements-to-grub_disk_open-and-grub_di.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
-Date: Sat, 23 Nov 2019 15:22:16 +0100
-Subject: [PATCH] Added debug statements to grub_disk_open() and
- grub_disk_close() on success
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
----
- grub-core/kern/disk.c | 6 +++++-
- 1 file changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c
-index e1b0e073e09..05a28ab1429 100644
---- a/grub-core/kern/disk.c
-+++ b/grub-core/kern/disk.c
-@@ -285,6 +285,8 @@ grub_disk_open (const char *name)
-       return 0;
-     }
- 
-+  grub_dprintf ("disk", "Opening `%s' succeeded.\n", name);
-+
-   return disk;
- }
- 
-@@ -292,7 +294,7 @@ void
- grub_disk_close (grub_disk_t disk)
- {
-   grub_partition_t part;
--  grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
-+  grub_dprintf ("disk", "Closing `%s'...\n", disk->name);
- 
-   if (disk->dev && disk->dev->disk_close)
-     (disk->dev->disk_close) (disk);
-@@ -306,8 +308,10 @@ grub_disk_close (grub_disk_t disk)
-       grub_free (disk->partition);
-       disk->partition = part;
-     }
-+  grub_dprintf ("disk", "Closing `%s' succeeded.\n", disk->name);
-   grub_free ((void *) disk->name);
-   grub_free (disk);
-+
- }
- 
- /* Small read (less than cache size and not pass across cache unit boundaries).
diff --git a/SOURCES/0171-appended-signatures-verification-tests.patch b/SOURCES/0171-appended-signatures-verification-tests.patch
new file mode 100644
index 0000000..b39a5af
--- /dev/null
+++ b/SOURCES/0171-appended-signatures-verification-tests.patch
@@ -0,0 +1,897 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 30 Jul 2020 01:31:02 +1000
+Subject: [PATCH] appended signatures: verification tests
+
+These tests are run through all_functional_test and test a range
+of commands and behaviours.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/Makefile.core.def               |   6 +
+ grub-core/tests/appended_signature_test.c | 281 +++++++++++++++
+ grub-core/tests/lib/functional_test.c     |   1 +
+ grub-core/tests/appended_signatures.h     | 557 ++++++++++++++++++++++++++++++
+ 4 files changed, 845 insertions(+)
+ create mode 100644 grub-core/tests/appended_signature_test.c
+ create mode 100644 grub-core/tests/appended_signatures.h
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 6404384d90..9ea5fb38f1 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -2162,6 +2162,12 @@ module = {
+   common = tests/setjmp_test.c;
+ };
+ 
++module = {
++  name = appended_signature_test;
++  common = tests/appended_signature_test.c;
++  common = tests/appended_signatures.h;
++};
++
+ module = {
+   name = signature_test;
+   common = tests/signature_test.c;
+diff --git a/grub-core/tests/appended_signature_test.c b/grub-core/tests/appended_signature_test.c
+new file mode 100644
+index 0000000000..88a485200d
+--- /dev/null
++++ b/grub-core/tests/appended_signature_test.c
+@@ -0,0 +1,281 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2020  IBM Corporation.
++ *
++ *  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/time.h>
++#include <grub/misc.h>
++#include <grub/dl.h>
++#include <grub/command.h>
++#include <grub/env.h>
++#include <grub/test.h>
++#include <grub/mm.h>
++#include <grub/procfs.h>
++#include <grub/file.h>
++
++#include "appended_signatures.h"
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++#define DEFINE_TEST_CASE(case_name) \
++static char * \
++get_ ## case_name (grub_size_t *sz) \
++{ \
++  char *ret; \
++  *sz = case_name ## _len; \
++  ret = grub_malloc (*sz); \
++  if (ret) \
++    grub_memcpy (ret, case_name, *sz); \
++  return ret; \
++} \
++\
++static struct grub_procfs_entry case_name ## _entry = \
++{ \
++  .name = #case_name, \
++  .get_contents = get_ ## case_name \
++}
++
++#define DO_TEST(case_name, is_valid) \
++{ \
++  grub_procfs_register (#case_name, &case_name ## _entry); \
++  do_verify ("(proc)/" #case_name, is_valid); \
++  grub_procfs_unregister (&case_name ## _entry); \
++}
++
++
++DEFINE_TEST_CASE (hi_signed);
++DEFINE_TEST_CASE (hi_signed_sha256);
++DEFINE_TEST_CASE (hj_signed);
++DEFINE_TEST_CASE (short_msg);
++DEFINE_TEST_CASE (unsigned_msg);
++DEFINE_TEST_CASE (hi_signed_2nd);
++
++static char *
++get_certificate_der (grub_size_t * sz)
++{
++  char *ret;
++  *sz = certificate_der_len;
++  ret = grub_malloc (*sz);
++  if (ret)
++    grub_memcpy (ret, certificate_der, *sz);
++  return ret;
++}
++
++static struct grub_procfs_entry certificate_der_entry = {
++  .name = "certificate.der",
++  .get_contents = get_certificate_der
++};
++
++static char *
++get_certificate2_der (grub_size_t * sz)
++{
++  char *ret;
++  *sz = certificate2_der_len;
++  ret = grub_malloc (*sz);
++  if (ret)
++    grub_memcpy (ret, certificate2_der, *sz);
++  return ret;
++}
++
++static struct grub_procfs_entry certificate2_der_entry = {
++  .name = "certificate2.der",
++  .get_contents = get_certificate2_der
++};
++
++static char *
++get_certificate_printable_der (grub_size_t * sz)
++{
++  char *ret;
++  *sz = certificate_printable_der_len;
++  ret = grub_malloc (*sz);
++  if (ret)
++    grub_memcpy (ret, certificate_printable_der, *sz);
++  return ret;
++}
++
++static struct grub_procfs_entry certificate_printable_der_entry = {
++  .name = "certificate_printable.der",
++  .get_contents = get_certificate_printable_der
++};
++
++
++static void
++do_verify (const char *f, int is_valid)
++{
++  grub_command_t cmd;
++  char *args[] = { (char *) f, NULL };
++  grub_err_t err;
++
++  cmd = grub_command_find ("verify_appended");
++  if (!cmd)
++    {
++      grub_test_assert (0, "can't find command `%s'", "verify_appended");
++      return;
++    }
++  err = (cmd->func) (cmd, 1, args);
++  if (is_valid)
++    {
++      grub_test_assert (err == GRUB_ERR_NONE,
++			"verification of %s failed: %d: %s", f, grub_errno,
++			grub_errmsg);
++    }
++  else
++    {
++      grub_test_assert (err == GRUB_ERR_BAD_SIGNATURE,
++			"verification of %s unexpectedly succeeded", f);
++    }
++  grub_errno = GRUB_ERR_NONE;
++
++}
++
++static void
++appended_signature_test (void)
++{
++  grub_command_t cmd_trust, cmd_distrust;
++  char *trust_args[] = { (char *) "(proc)/certificate.der", NULL };
++  char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL };
++  char *trust_args_printable[] = { (char *) "(proc)/certificate_printable.der",
++				   NULL };
++  char *distrust_args[] = { (char *) "1", NULL };
++  char *distrust2_args[] = { (char *) "2", NULL };
++  grub_err_t err;
++
++  grub_procfs_register ("certificate.der", &certificate_der_entry);
++  grub_procfs_register ("certificate2.der", &certificate2_der_entry);
++  grub_procfs_register ("certificate_printable.der",
++			&certificate_printable_der_entry);
++
++  cmd_trust = grub_command_find ("trust_certificate");
++  if (!cmd_trust)
++    {
++      grub_test_assert (0, "can't find command `%s'", "trust_certificate");
++      return;
++    }
++  err = (cmd_trust->func) (cmd_trust, 1, trust_args);
++
++  grub_test_assert (err == GRUB_ERR_NONE,
++		    "loading certificate failed: %d: %s", grub_errno,
++		    grub_errmsg);
++
++  /* If we have no certificate the remainder of the tests are meaningless */
++  if (err != GRUB_ERR_NONE)
++    return;
++
++  /*
++   * Reload the command: this works around some 'interesting' behaviour in the
++   * dynamic command dispatcher. The first time you call cmd->func you get a
++   * dispatcher that loads the module, finds the real cmd, calls it, and then
++   * releases some internal storage. This means it's not safe to call a second
++   * time and we need to reload it.
++   */
++  cmd_trust = grub_command_find ("trust_certificate");
++
++  DO_TEST (hi_signed, 1);
++  DO_TEST (hi_signed_sha256, 1);
++  DO_TEST (hj_signed, 0);
++  DO_TEST (short_msg, 0);
++  DO_TEST (unsigned_msg, 0);
++
++  /*
++   * in enforcing mode, we shouldn't be able to load a certificate that isn't
++   * signed by an existing trusted key.
++   *
++   * However, procfs files automatically skip the verification test, so we can't
++   * easily test this.
++   */
++
++  /*
++   * verify that testing with 2 trusted certs works
++   */
++  DO_TEST (hi_signed_2nd, 0);
++
++  err = (cmd_trust->func) (cmd_trust, 1, trust_args2);
++
++  grub_test_assert (err == GRUB_ERR_NONE,
++		    "loading certificate 2 failed: %d: %s", grub_errno,
++		    grub_errmsg);
++
++  if (err != GRUB_ERR_NONE)
++    return;
++
++  DO_TEST (hi_signed_2nd, 1);
++  DO_TEST (hi_signed, 1);
++
++  /*
++   * Check certificate removal. They're added to the _top_ of the list and
++   * removed by position in the list. Current the list looks like [#2, #1].
++   *
++   * First test removing the second certificate in the list, which is
++   * certificate #1, giving us just [#2].
++   */
++  cmd_distrust = grub_command_find ("distrust_certificate");
++  if (!cmd_distrust)
++    {
++      grub_test_assert (0, "can't find command `%s'", "distrust_certificate");
++      return;
++    }
++
++  err = (cmd_distrust->func) (cmd_distrust, 1, distrust2_args);
++  grub_test_assert (err == GRUB_ERR_NONE,
++		    "distrusting certificate 1 failed: %d: %s", grub_errno,
++		    grub_errmsg);
++  DO_TEST (hi_signed_2nd, 1);
++  DO_TEST (hi_signed, 0);
++
++  /*
++   * Now reload certificate #1. This will make the list look like [#1, #2]
++   */
++  err = (cmd_trust->func) (cmd_trust, 1, trust_args);
++
++  grub_test_assert (err == GRUB_ERR_NONE,
++		    "reloading certificate 1 failed: %d: %s", grub_errno,
++		    grub_errmsg);
++  DO_TEST (hi_signed, 1);
++
++  /* Remove the first certificate in the list, giving us just [#2] */
++  err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args);
++  grub_test_assert (err == GRUB_ERR_NONE,
++		    "distrusting certificate 1 (first time) failed: %d: %s",
++		    grub_errno, grub_errmsg);
++  DO_TEST (hi_signed_2nd, 1);
++  DO_TEST (hi_signed, 0);
++
++  /*
++   * Remove the first certificate again, giving an empty list.
++   *
++   * verify_appended should fail if there are no certificates to verify against.
++   */
++  err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args);
++  grub_test_assert (err == GRUB_ERR_NONE,
++		    "distrusting certificate 1 (second time) failed: %d: %s",
++		    grub_errno, grub_errmsg);
++  DO_TEST (hi_signed_2nd, 0);
++
++  /*
++   * Lastly, check a certificate that uses printableString rather than
++   * utf8String loads properly.
++   */
++  err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable);
++  grub_test_assert (err == GRUB_ERR_NONE,
++		    "distrusting printable certificate failed: %d: %s",
++		    grub_errno, grub_errmsg);
++
++  grub_procfs_unregister (&certificate_der_entry);
++  grub_procfs_unregister (&certificate2_der_entry);
++  grub_procfs_unregister (&certificate_printable_der_entry);
++}
++
++GRUB_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test);
+diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c
+index 96781fb39b..403fa5c789 100644
+--- a/grub-core/tests/lib/functional_test.c
++++ b/grub-core/tests/lib/functional_test.c
+@@ -73,6 +73,7 @@ grub_functional_all_tests (grub_extcmd_context_t ctxt __attribute__ ((unused)),
+   grub_dl_load ("xnu_uuid_test");
+   grub_dl_load ("pbkdf2_test");
+   grub_dl_load ("signature_test");
++  grub_dl_load ("appended_signature_test");
+   grub_dl_load ("sleep_test");
+   grub_dl_load ("bswap_test");
+   grub_dl_load ("ctz_test");
+diff --git a/grub-core/tests/appended_signatures.h b/grub-core/tests/appended_signatures.h
+new file mode 100644
+index 0000000000..aa3dc6278e
+--- /dev/null
++++ b/grub-core/tests/appended_signatures.h
+@@ -0,0 +1,557 @@
++unsigned char certificate_der[] = {
++  0x30, 0x82, 0x03, 0x88, 0x30, 0x82, 0x02, 0x70, 0xa0, 0x03, 0x02, 0x01,
++  0x02, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
++  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30,
++  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
++  0x05, 0x00, 0x30, 0x49, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04,
++  0x03, 0x0c, 0x1f, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65,
++  0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
++  0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d,
++  0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
++  0x01, 0x16, 0x0e, 0x64, 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e,
++  0x73, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30,
++  0x37, 0x30, 0x39, 0x30, 0x36, 0x32, 0x32, 0x30, 0x37, 0x5a, 0x18, 0x0f,
++  0x32, 0x31, 0x32, 0x30, 0x30, 0x36, 0x31, 0x35, 0x30, 0x36, 0x32, 0x32,
++  0x30, 0x37, 0x5a, 0x30, 0x52, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55,
++  0x04, 0x03, 0x0c, 0x28, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70,
++  0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74,
++  0x75, 0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x69, 0x67,
++  0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x31, 0x1d, 0x30, 0x1b,
++  0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
++  0x0e, 0x64, 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e,
++  0x6e, 0x65, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
++  0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
++  0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00,
++  0xcd, 0xe8, 0x1c, 0x08, 0x68, 0x2e, 0xcb, 0xfe, 0x8c, 0x4b, 0x3b, 0x61,
++  0xe7, 0x8e, 0x80, 0x58, 0x85, 0x85, 0xea, 0xc8, 0x3b, 0x42, 0xba, 0x72,
++  0x84, 0x65, 0x20, 0xbc, 0x48, 0xa2, 0x25, 0x49, 0x6e, 0x1c, 0xb9, 0x7d,
++  0xeb, 0xc1, 0x0c, 0xa8, 0xb7, 0xcc, 0x13, 0x78, 0xba, 0x11, 0xa4, 0x98,
++  0xd7, 0xd0, 0x7c, 0xdd, 0xf5, 0x5a, 0xb7, 0xcd, 0x31, 0x0e, 0xcd, 0x9e,
++  0xa7, 0x19, 0xf0, 0xbd, 0x0f, 0xa6, 0xfe, 0x8a, 0x11, 0x97, 0xed, 0x8b,
++  0xe5, 0x16, 0xa6, 0x21, 0x13, 0x36, 0xad, 0x05, 0x49, 0xec, 0x29, 0x12,
++  0x38, 0xa7, 0x4b, 0x0f, 0xa1, 0xfb, 0x72, 0xc0, 0xc0, 0x09, 0x67, 0x78,
++  0xa8, 0xb6, 0xd6, 0x1a, 0x39, 0xc0, 0xa8, 0xbf, 0x5f, 0x14, 0x89, 0x5c,
++  0xbc, 0x41, 0x0c, 0x0c, 0x5d, 0x42, 0x2e, 0x1c, 0xdf, 0x1f, 0x1d, 0xc9,
++  0x43, 0x94, 0x5b, 0x6e, 0x8f, 0x15, 0x8c, 0x8f, 0x94, 0x73, 0x4f, 0x97,
++  0x54, 0xf1, 0x86, 0x8a, 0xbc, 0xe4, 0xe4, 0x93, 0xc1, 0x5e, 0xc2, 0x3e,
++  0x31, 0x5e, 0xd4, 0x85, 0x57, 0x14, 0xd0, 0x11, 0x07, 0x65, 0xf4, 0x7c,
++  0x8f, 0x07, 0x57, 0xe1, 0x22, 0xd4, 0x78, 0x47, 0x65, 0x4e, 0xa9, 0xb3,
++  0xaa, 0xce, 0xc7, 0x36, 0xfe, 0xda, 0x66, 0x02, 0xb6, 0x8d, 0x18, 0x2f,
++  0x3b, 0x41, 0x8d, 0x02, 0x08, 0x72, 0x4b, 0x69, 0xbd, 0x1e, 0x58, 0xfc,
++  0x1b, 0x64, 0x04, 0x52, 0x35, 0x35, 0xe2, 0x3d, 0x3e, 0xde, 0xd6, 0x64,
++  0xf4, 0xec, 0x57, 0x7e, 0x65, 0x59, 0x00, 0xa6, 0xd3, 0x4b, 0x09, 0x93,
++  0x2a, 0x95, 0x0f, 0x30, 0xb6, 0xa1, 0x8c, 0xe7, 0x8b, 0x49, 0xa4, 0x1d,
++  0x25, 0x2d, 0x65, 0x48, 0x8a, 0x0f, 0xcf, 0x2a, 0xa2, 0xe1, 0xef, 0x72,
++  0x92, 0xc3, 0xf5, 0x21, 0x37, 0x83, 0x9b, 0x6d, 0x0b, 0x1b, 0xb3, 0xa2,
++  0x32, 0x38, 0x11, 0xb1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30,
++  0x5b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
++  0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04,
++  0x03, 0x02, 0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
++  0x16, 0x04, 0x14, 0xe5, 0x2a, 0x4f, 0xf2, 0x84, 0x91, 0x57, 0x91, 0xaf,
++  0x12, 0xd2, 0xf1, 0xa1, 0x87, 0x73, 0x0f, 0x90, 0x25, 0xa0, 0x7a, 0x30,
++  0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
++  0x56, 0xd1, 0xfd, 0xe2, 0x1e, 0x7e, 0x1c, 0x63, 0x4f, 0x47, 0xdb, 0xe4,
++  0xc4, 0x51, 0x04, 0x03, 0x9a, 0x48, 0x35, 0x6e, 0x30, 0x0d, 0x06, 0x09,
++  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
++  0x82, 0x01, 0x01, 0x00, 0x65, 0x82, 0xd5, 0x88, 0x30, 0xe2, 0x2c, 0x47,
++  0xf3, 0x31, 0x39, 0xa1, 0x75, 0x9a, 0xb0, 0x8a, 0x6c, 0x4b, 0xac, 0xdf,
++  0x09, 0x7b, 0x90, 0xb6, 0x9e, 0x76, 0x62, 0x94, 0xc1, 0x3a, 0x99, 0x49,
++  0x68, 0x29, 0x47, 0x42, 0xc3, 0x06, 0xcb, 0x88, 0x75, 0xe6, 0x79, 0x13,
++  0x8c, 0x4b, 0x49, 0x6a, 0xb5, 0x56, 0x95, 0xc0, 0x42, 0x21, 0x9b, 0xd4,
++  0x61, 0xd0, 0x02, 0x41, 0xdd, 0x20, 0x61, 0xe5, 0x91, 0xdf, 0x75, 0x00,
++  0x25, 0x0e, 0x99, 0x65, 0x5c, 0x54, 0x49, 0x32, 0xa3, 0xe2, 0xcd, 0xa1,
++  0x5f, 0x40, 0xf3, 0xc5, 0x81, 0xd9, 0x3c, 0xa3, 0x63, 0x5a, 0x38, 0x79,
++  0xab, 0x77, 0x98, 0xde, 0x8f, 0x4e, 0x9e, 0x26, 0xbc, 0x4e, 0x80, 0x9e,
++  0x8f, 0xbe, 0xf1, 0x00, 0xb3, 0x78, 0xb9, 0x4b, 0x1d, 0xc7, 0xa4, 0x83,
++  0x59, 0x56, 0x11, 0xd1, 0x11, 0x1e, 0x50, 0x39, 0xd5, 0x78, 0x14, 0xf3,
++  0xb9, 0x1d, 0xda, 0xe4, 0xc4, 0x63, 0x74, 0x26, 0xab, 0xa3, 0xfd, 0x9d,
++  0x58, 0xa2, 0xee, 0x7b, 0x28, 0x34, 0xa3, 0xbe, 0x85, 0x7e, 0xaa, 0x97,
++  0xb7, 0x5b, 0x9d, 0xa9, 0x4d, 0x96, 0xdb, 0x6b, 0x21, 0xe1, 0x96, 0x5d,
++  0xc7, 0xad, 0x23, 0x03, 0x9a, 0x16, 0xdb, 0xa4, 0x1f, 0x63, 0xef, 0xaf,
++  0x1e, 0x4f, 0xf8, 0x27, 0xdc, 0x4b, 0xfc, 0x2b, 0x68, 0x2e, 0xa0, 0xd3,
++  0xae, 0xf2, 0xce, 0xf5, 0xfc, 0x97, 0x92, 0xd2, 0x29, 0x0f, 0x4f, 0x4b,
++  0x29, 0xeb, 0x06, 0xcb, 0xf8, 0x21, 0x6e, 0xbc, 0x8b, 0x5c, 0xc5, 0xc9,
++  0xf7, 0xe2, 0x7c, 0x47, 0xcd, 0x43, 0x98, 0xc4, 0xa3, 0x9a, 0xd7, 0x3e,
++  0xdc, 0x01, 0x13, 0x28, 0x96, 0xc4, 0x60, 0x83, 0xe2, 0x79, 0xa1, 0x46,
++  0xef, 0xf5, 0xa4, 0x7b, 0x00, 0xe3, 0x3d, 0x7d, 0xbc, 0xa8, 0x98, 0x49,
++  0xa8, 0xcf, 0x3b, 0x41, 0xb6, 0x09, 0x97, 0x07
++};
++unsigned int certificate_der_len = 908;
++
++unsigned char hi_signed[] = {
++  0x68, 0x69, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48,
++  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82,
++  0x01, 0xad, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
++  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
++  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x01,
++  0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49,
++  0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x47,
++  0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64,
++  0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54,
++  0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09,
++  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64,
++  0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65,
++  0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
++  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30,
++  0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
++  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
++  0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xc7, 0x69, 0x35, 0x21, 0x66,
++  0x4d, 0x50, 0xd4, 0x73, 0xde, 0xbd, 0x3a, 0xf6, 0x45, 0xe3, 0xe4, 0xd0,
++  0xb6, 0xa1, 0xe7, 0xc0, 0xa2, 0xc9, 0xf4, 0xf0, 0x05, 0x8c, 0xa4, 0x16,
++  0x9e, 0x81, 0x0d, 0x21, 0x68, 0xf3, 0xfe, 0x03, 0x96, 0x77, 0x31, 0x69,
++  0x01, 0xd8, 0x26, 0xd9, 0x48, 0x95, 0xcf, 0xd1, 0x17, 0xb1, 0x0b, 0x6b,
++  0x2c, 0xf1, 0xb0, 0xab, 0x65, 0x65, 0x56, 0xf8, 0x0c, 0xa7, 0xf7, 0xbb,
++  0xf6, 0x5a, 0x55, 0x98, 0x14, 0x07, 0x8d, 0x2a, 0xbc, 0x16, 0x48, 0x94,
++  0xab, 0x2f, 0x85, 0x97, 0x90, 0x51, 0x78, 0xa0, 0xda, 0x60, 0xb5, 0x41,
++  0x4b, 0xe8, 0x78, 0xc5, 0xa6, 0x04, 0x9d, 0x54, 0x2a, 0x85, 0xfd, 0x86,
++  0x0b, 0x6d, 0xc2, 0xd2, 0xad, 0x07, 0xff, 0x16, 0x42, 0x82, 0xe3, 0x5c,
++  0xaa, 0x22, 0x59, 0x78, 0x92, 0xea, 0x94, 0xc3, 0x41, 0xb7, 0xa1, 0x86,
++  0x44, 0xea, 0xd1, 0xdb, 0xe5, 0xac, 0x30, 0x32, 0xfb, 0x7d, 0x3f, 0xf7,
++  0x8b, 0x11, 0x7f, 0x80, 0x3b, 0xe5, 0xc7, 0x82, 0x0f, 0x92, 0x07, 0x14,
++  0x66, 0x01, 0x6e, 0x85, 0xab, 0x3a, 0x14, 0xcf, 0x76, 0xd1, 0x7e, 0x14,
++  0x85, 0xca, 0x01, 0x73, 0x72, 0x38, 0xdc, 0xde, 0x30, 0x5c, 0xfb, 0xc0,
++  0x3d, 0x93, 0xef, 0x9c, 0xbc, 0xf8, 0xcc, 0xd2, 0xbf, 0x47, 0xec, 0xf8,
++  0x88, 0x9b, 0xe1, 0x43, 0xbe, 0xa7, 0x47, 0x96, 0xb6, 0x5d, 0x46, 0x0e,
++  0x7a, 0x78, 0x38, 0x19, 0xbc, 0xb5, 0xbc, 0x9b, 0x3c, 0x39, 0x92, 0x70,
++  0x0d, 0x9d, 0x8a, 0x35, 0xaf, 0xb4, 0x9e, 0xf4, 0xef, 0xc1, 0xb8, 0x25,
++  0xd0, 0x14, 0x91, 0xd6, 0xc2, 0xb6, 0xc7, 0x3c, 0x72, 0x91, 0x0f, 0xad,
++  0xde, 0xb2, 0x36, 0xf8, 0x4e, 0x59, 0xd4, 0xa4, 0x21, 0x9f, 0x03, 0x95,
++  0x48, 0x01, 0xb4, 0x05, 0xc3, 0x39, 0x60, 0x51, 0x08, 0xd0, 0xbe, 0x00,
++  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x7e,
++  0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61,
++  0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65,
++  0x64, 0x7e, 0x0a
++};
++unsigned int hi_signed_len = 495;
++
++unsigned char hj_signed[] = {
++  0x68, 0x6a, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48,
++  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82,
++  0x01, 0xad, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
++  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
++  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x01,
++  0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49,
++  0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x47,
++  0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64,
++  0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54,
++  0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09,
++  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64,
++  0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65,
++  0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
++  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30,
++  0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
++  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
++  0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xc7, 0x69, 0x35, 0x21, 0x66,
++  0x4d, 0x50, 0xd4, 0x73, 0xde, 0xbd, 0x3a, 0xf6, 0x45, 0xe3, 0xe4, 0xd0,
++  0xb6, 0xa1, 0xe7, 0xc0, 0xa2, 0xc9, 0xf4, 0xf0, 0x05, 0x8c, 0xa4, 0x16,
++  0x9e, 0x81, 0x0d, 0x21, 0x68, 0xf3, 0xfe, 0x03, 0x96, 0x77, 0x31, 0x69,
++  0x01, 0xd8, 0x26, 0xd9, 0x48, 0x95, 0xcf, 0xd1, 0x17, 0xb1, 0x0b, 0x6b,
++  0x2c, 0xf1, 0xb0, 0xab, 0x65, 0x65, 0x56, 0xf8, 0x0c, 0xa7, 0xf7, 0xbb,
++  0xf6, 0x5a, 0x55, 0x98, 0x14, 0x07, 0x8d, 0x2a, 0xbc, 0x16, 0x48, 0x94,
++  0xab, 0x2f, 0x85, 0x97, 0x90, 0x51, 0x78, 0xa0, 0xda, 0x60, 0xb5, 0x41,
++  0x4b, 0xe8, 0x78, 0xc5, 0xa6, 0x04, 0x9d, 0x54, 0x2a, 0x85, 0xfd, 0x86,
++  0x0b, 0x6d, 0xc2, 0xd2, 0xad, 0x07, 0xff, 0x16, 0x42, 0x82, 0xe3, 0x5c,
++  0xaa, 0x22, 0x59, 0x78, 0x92, 0xea, 0x94, 0xc3, 0x41, 0xb7, 0xa1, 0x86,
++  0x44, 0xea, 0xd1, 0xdb, 0xe5, 0xac, 0x30, 0x32, 0xfb, 0x7d, 0x3f, 0xf7,
++  0x8b, 0x11, 0x7f, 0x80, 0x3b, 0xe5, 0xc7, 0x82, 0x0f, 0x92, 0x07, 0x14,
++  0x66, 0x01, 0x6e, 0x85, 0xab, 0x3a, 0x14, 0xcf, 0x76, 0xd1, 0x7e, 0x14,
++  0x85, 0xca, 0x01, 0x73, 0x72, 0x38, 0xdc, 0xde, 0x30, 0x5c, 0xfb, 0xc0,
++  0x3d, 0x93, 0xef, 0x9c, 0xbc, 0xf8, 0xcc, 0xd2, 0xbf, 0x47, 0xec, 0xf8,
++  0x88, 0x9b, 0xe1, 0x43, 0xbe, 0xa7, 0x47, 0x96, 0xb6, 0x5d, 0x46, 0x0e,
++  0x7a, 0x78, 0x38, 0x19, 0xbc, 0xb5, 0xbc, 0x9b, 0x3c, 0x39, 0x92, 0x70,
++  0x0d, 0x9d, 0x8a, 0x35, 0xaf, 0xb4, 0x9e, 0xf4, 0xef, 0xc1, 0xb8, 0x25,
++  0xd0, 0x14, 0x91, 0xd6, 0xc2, 0xb6, 0xc7, 0x3c, 0x72, 0x91, 0x0f, 0xad,
++  0xde, 0xb2, 0x36, 0xf8, 0x4e, 0x59, 0xd4, 0xa4, 0x21, 0x9f, 0x03, 0x95,
++  0x48, 0x01, 0xb4, 0x05, 0xc3, 0x39, 0x60, 0x51, 0x08, 0xd0, 0xbe, 0x00,
++  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x7e,
++  0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61,
++  0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65,
++  0x64, 0x7e, 0x0a
++};
++unsigned int hj_signed_len = 495;
++
++unsigned char hi_signed_sha256[] = {
++  0x68, 0x69, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48,
++  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82,
++  0x01, 0xad, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
++  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0b, 0x06, 0x09,
++  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x01,
++  0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49,
++  0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x47,
++  0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64,
++  0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54,
++  0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09,
++  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64,
++  0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65,
++  0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
++  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30,
++  0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
++  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
++  0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x7b, 0x5e, 0x82, 0x1d, 0x21,
++  0xb6, 0x40, 0xd3, 0x33, 0x79, 0xa7, 0x52, 0x2b, 0xfc, 0x46, 0x51, 0x26,
++  0xfe, 0x0f, 0x81, 0x90, 0x81, 0xab, 0x57, 0x5e, 0xf6, 0x45, 0x41, 0xa3,
++  0x7b, 0x48, 0xdd, 0xd6, 0x59, 0x60, 0x51, 0x31, 0x14, 0x14, 0x7b, 0xb4,
++  0x55, 0x7b, 0x4d, 0xfe, 0x09, 0x7a, 0x5d, 0xae, 0xc4, 0x58, 0x50, 0x80,
++  0x75, 0xf2, 0x23, 0x20, 0x62, 0xe3, 0x7c, 0x26, 0x1d, 0x2a, 0x4d, 0x9f,
++  0x89, 0xf0, 0x4f, 0x95, 0x8a, 0x80, 0x6e, 0x1a, 0xea, 0x87, 0xdb, 0x1f,
++  0xf3, 0xda, 0x04, 0x91, 0x37, 0xea, 0x0a, 0xfb, 0x6c, 0xc9, 0x3d, 0x73,
++  0xf9, 0x58, 0x7c, 0x15, 0x6b, 0xa2, 0x52, 0x5a, 0x97, 0xff, 0xd6, 0xb0,
++  0xf1, 0xbf, 0xa5, 0x04, 0x6d, 0x91, 0xc1, 0x54, 0x05, 0xdc, 0x7f, 0x5d,
++  0x19, 0xaf, 0x55, 0xec, 0x51, 0xfb, 0x66, 0x0a, 0xa4, 0x4e, 0x96, 0x47,
++  0x43, 0x54, 0x7c, 0x64, 0xa8, 0xaa, 0xb4, 0x90, 0x02, 0xf3, 0xa7, 0x0b,
++  0xb7, 0xbf, 0x06, 0xdb, 0x5e, 0x9c, 0x32, 0x6d, 0x45, 0x14, 0x1c, 0xaf,
++  0x46, 0x30, 0x08, 0x55, 0x49, 0x78, 0xfa, 0x57, 0xda, 0x3d, 0xf5, 0xa0,
++  0xef, 0x11, 0x0a, 0x81, 0x0d, 0x82, 0xcd, 0xaf, 0xdb, 0xda, 0x0e, 0x1a,
++  0x44, 0xd1, 0xee, 0xc4, 0xb8, 0xde, 0x97, 0xb4, 0xda, 0xb4, 0x8b, 0x4f,
++  0x58, 0x24, 0x59, 0xc0, 0xe0, 0x08, 0x97, 0x14, 0x68, 0xbe, 0x31, 0x09,
++  0x5e, 0x67, 0x45, 0xf0, 0xcb, 0x81, 0x4f, 0x17, 0x44, 0x61, 0xe0, 0xe2,
++  0xf0, 0xfc, 0x1e, 0xb9, 0x73, 0xaf, 0x42, 0xff, 0x33, 0xde, 0x61, 0x6b,
++  0x7f, 0xc2, 0x69, 0x0d, 0x66, 0x54, 0xae, 0xf6, 0xde, 0x20, 0x47, 0x44,
++  0x9b, 0x73, 0xd1, 0x07, 0x6e, 0x77, 0x37, 0x0a, 0xbb, 0x7f, 0xa0, 0x93,
++  0x2d, 0x8d, 0x44, 0xba, 0xe2, 0xdd, 0x34, 0x32, 0xd7, 0x56, 0x71, 0x00,
++  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x7e,
++  0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61,
++  0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65,
++  0x64, 0x7e, 0x0a
++};
++unsigned int hi_signed_sha256_len = 495;
++
++unsigned char short_msg[] = {
++  0x68, 0x69, 0x0a
++};
++unsigned int short_msg_len = 3;
++
++unsigned char unsigned_msg[] = {
++  0x53, 0x65, 0x64, 0x20, 0x75, 0x74, 0x20, 0x70, 0x65, 0x72, 0x73, 0x70,
++  0x69, 0x63, 0x69, 0x61, 0x74, 0x69, 0x73, 0x20, 0x75, 0x6e, 0x64, 0x65,
++  0x20, 0x6f, 0x6d, 0x6e, 0x69, 0x73, 0x20, 0x69, 0x73, 0x74, 0x65, 0x20,
++  0x6e, 0x61, 0x74, 0x75, 0x73, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20,
++  0x73, 0x69, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74,
++  0x65, 0x6d, 0x20, 0x61, 0x63, 0x63, 0x75, 0x73, 0x61, 0x6e, 0x74, 0x69,
++  0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x71, 0x75,
++  0x65, 0x20, 0x6c, 0x61, 0x75, 0x64, 0x61, 0x6e, 0x74, 0x69, 0x75, 0x6d,
++  0x2c, 0x20, 0x74, 0x6f, 0x74, 0x61, 0x6d, 0x20, 0x72, 0x65, 0x6d, 0x20,
++  0x61, 0x70, 0x65, 0x72, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x65, 0x61, 0x71,
++  0x75, 0x65, 0x20, 0x69, 0x70, 0x73, 0x61, 0x20, 0x71, 0x75, 0x61, 0x65,
++  0x20, 0x61, 0x62, 0x20, 0x69, 0x6c, 0x6c, 0x6f, 0x20, 0x69, 0x6e, 0x76,
++  0x65, 0x6e, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x76, 0x65, 0x72, 0x69, 0x74,
++  0x61, 0x74, 0x69, 0x73, 0x20, 0x65, 0x74, 0x20, 0x71, 0x75, 0x61, 0x73,
++  0x69, 0x20, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x6f,
++  0x20, 0x62, 0x65, 0x61, 0x74, 0x61, 0x65, 0x20, 0x76, 0x69, 0x74, 0x61,
++  0x65, 0x20, 0x64, 0x69, 0x63, 0x74, 0x61, 0x20, 0x73, 0x75, 0x6e, 0x74,
++  0x20, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x62, 0x6f, 0x2e, 0x20,
++  0x4e, 0x65, 0x6d, 0x6f, 0x20, 0x65, 0x6e, 0x69, 0x6d, 0x20, 0x69, 0x70,
++  0x73, 0x61, 0x6d, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74,
++  0x65, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75,
++  0x70, 0x74, 0x61, 0x73, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x73, 0x70,
++  0x65, 0x72, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x20, 0x61, 0x75, 0x74, 0x20,
++  0x6f, 0x64, 0x69, 0x74, 0x20, 0x61, 0x75, 0x74, 0x20, 0x66, 0x75, 0x67,
++  0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x64, 0x20, 0x71, 0x75, 0x69, 0x61,
++  0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x75, 0x6e, 0x74, 0x75,
++  0x72, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f,
++  0x72, 0x65, 0x73, 0x20, 0x65, 0x6f, 0x73, 0x20, 0x71, 0x75, 0x69, 0x20,
++  0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x20, 0x76, 0x6f, 0x6c, 0x75,
++  0x70, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x20, 0x73, 0x65, 0x71, 0x75, 0x69,
++  0x20, 0x6e, 0x65, 0x73, 0x63, 0x69, 0x75, 0x6e, 0x74, 0x2e, 0x20, 0x4e,
++  0x65, 0x71, 0x75, 0x65, 0x20, 0x70, 0x6f, 0x72, 0x72, 0x6f, 0x20, 0x71,
++  0x75, 0x69, 0x73, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x73, 0x74, 0x2c,
++  0x20, 0x71, 0x75, 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d,
++  0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 0x20,
++  0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d,
++  0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 0x65,
++  0x74, 0x75, 0x72, 0x2c, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63,
++  0x69, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x64,
++  0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x6e, 0x6f, 0x6e, 0x20, 0x6e, 0x75,
++  0x6d, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x69, 0x75, 0x73, 0x20, 0x6d,
++  0x6f, 0x64, 0x69, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x20,
++  0x69, 0x6e, 0x63, 0x69, 0x64, 0x75, 0x6e, 0x74, 0x20, 0x75, 0x74, 0x20,
++  0x6c, 0x61, 0x62, 0x6f, 0x72, 0x65, 0x20, 0x65, 0x74, 0x20, 0x64, 0x6f,
++  0x6c, 0x6f, 0x72, 0x65, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x61, 0x6d, 0x20,
++  0x61, 0x6c, 0x69, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x71, 0x75, 0x61, 0x65,
++  0x72, 0x61, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74,
++  0x65, 0x6d, 0x2e, 0x20, 0x55, 0x74, 0x20, 0x65, 0x6e, 0x69, 0x6d, 0x20,
++  0x61, 0x64, 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x61, 0x20, 0x76, 0x65,
++  0x6e, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x71, 0x75, 0x69, 0x73, 0x20, 0x6e,
++  0x6f, 0x73, 0x74, 0x72, 0x75, 0x6d, 0x20, 0x65, 0x78, 0x65, 0x72, 0x63,
++  0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x6d, 0x20, 0x75, 0x6c,
++  0x6c, 0x61, 0x6d, 0x20, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x69, 0x73,
++  0x20, 0x73, 0x75, 0x73, 0x63, 0x69, 0x70, 0x69, 0x74, 0x20, 0x6c, 0x61,
++  0x62, 0x6f, 0x72, 0x69, 0x6f, 0x73, 0x61, 0x6d, 0x2c, 0x20, 0x6e, 0x69,
++  0x73, 0x69, 0x20, 0x75, 0x74, 0x20, 0x61, 0x6c, 0x69, 0x71, 0x75, 0x69,
++  0x64, 0x20, 0x65, 0x78, 0x20, 0x65, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x6d,
++  0x6f, 0x64, 0x69, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61,
++  0x74, 0x75, 0x72, 0x3f, 0x20, 0x51, 0x75, 0x69, 0x73, 0x20, 0x61, 0x75,
++  0x74, 0x65, 0x6d, 0x20, 0x76, 0x65, 0x6c, 0x20, 0x65, 0x75, 0x6d, 0x20,
++  0x69, 0x75, 0x72, 0x65, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x68, 0x65,
++  0x6e, 0x64, 0x65, 0x72, 0x69, 0x74, 0x20, 0x71, 0x75, 0x69, 0x20, 0x69,
++  0x6e, 0x20, 0x65, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61,
++  0x74, 0x65, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x20, 0x65, 0x73, 0x73,
++  0x65, 0x20, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x6e, 0x69, 0x68, 0x69, 0x6c,
++  0x20, 0x6d, 0x6f, 0x6c, 0x65, 0x73, 0x74, 0x69, 0x61, 0x65, 0x20, 0x63,
++  0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, 0x74, 0x75, 0x72, 0x2c, 0x20,
++  0x76, 0x65, 0x6c, 0x20, 0x69, 0x6c, 0x6c, 0x75, 0x6d, 0x20, 0x71, 0x75,
++  0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x65, 0x75,
++  0x6d, 0x20, 0x66, 0x75, 0x67, 0x69, 0x61, 0x74, 0x20, 0x71, 0x75, 0x6f,
++  0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x73, 0x20, 0x6e, 0x75,
++  0x6c, 0x6c, 0x61, 0x20, 0x70, 0x61, 0x72, 0x69, 0x61, 0x74, 0x75, 0x72,
++  0x3f, 0x0a
++};
++unsigned int unsigned_msg_len = 866;
++
++unsigned char certificate2_der[] = {
++  0x30, 0x82, 0x05, 0x52, 0x30, 0x82, 0x03, 0x3a, 0xa0, 0x03, 0x02, 0x01,
++  0x02, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5,
++  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30,
++  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
++  0x05, 0x00, 0x30, 0x3a, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04,
++  0x03, 0x0c, 0x2f, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20,
++  0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20,
++  0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
++  0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
++  0x74, 0x79, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x37, 0x32, 0x38,
++  0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x32,
++  0x30, 0x30, 0x37, 0x30, 0x34, 0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 0x5a,
++  0x30, 0x2b, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
++  0x20, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65,
++  0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x69,
++  0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x82, 0x02,
++  0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
++  0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02,
++  0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xb0, 0x2f, 0x50, 0x01, 0x9c, 0x0e,
++  0xd6, 0x8c, 0x07, 0xca, 0xc1, 0xcf, 0xbc, 0x03, 0xdd, 0xd3, 0xfa, 0xe3,
++  0x4f, 0x71, 0xc1, 0x30, 0xaa, 0x09, 0x96, 0xe4, 0xd0, 0x6c, 0x42, 0x93,
++  0xdb, 0x35, 0xf6, 0x7e, 0x1b, 0x67, 0xc0, 0xc2, 0x2d, 0x5b, 0xec, 0xca,
++  0x35, 0x06, 0x32, 0x6c, 0x7b, 0x2c, 0xd3, 0x71, 0x2b, 0xe9, 0x7a, 0x19,
++  0xd1, 0xf2, 0xa0, 0x7f, 0xd7, 0x4d, 0x6e, 0x28, 0xbb, 0xae, 0x49, 0x4a,
++  0xbc, 0xea, 0x47, 0x67, 0xb8, 0x36, 0xa6, 0xf5, 0x0d, 0x0e, 0x20, 0x14,
++  0x0c, 0x66, 0x67, 0x28, 0xb5, 0x97, 0x8b, 0x1f, 0x5e, 0x32, 0x06, 0x29,
++  0x9c, 0x99, 0x92, 0x0f, 0x73, 0xac, 0xfd, 0xd2, 0x1d, 0xf2, 0xa8, 0x55,
++  0x9d, 0x1b, 0xd8, 0x3d, 0xb0, 0x76, 0x9a, 0xb6, 0x6c, 0x9f, 0x62, 0x37,
++  0x2f, 0xc0, 0xef, 0x44, 0xb3, 0x0d, 0x4a, 0x3e, 0x4f, 0x7d, 0xbd, 0xdb,
++  0xd8, 0x75, 0x5f, 0x68, 0xe3, 0xf0, 0xec, 0x82, 0x66, 0x7c, 0x31, 0x70,
++  0xa9, 0xa1, 0x6f, 0x38, 0x9f, 0xdf, 0xf5, 0xf0, 0x7d, 0x23, 0x9d, 0x34,
++  0xa5, 0x85, 0xd3, 0xdf, 0x68, 0x41, 0xfc, 0x4f, 0x89, 0x45, 0x3c, 0x24,
++  0x81, 0xa6, 0xf2, 0x3c, 0x02, 0x26, 0x09, 0x48, 0xdd, 0xfe, 0x4b, 0xb6,
++  0x66, 0xbf, 0x8f, 0xe5, 0x5f, 0xf0, 0x5d, 0x8a, 0x61, 0x2e, 0x5f, 0x9f,
++  0x80, 0xd9, 0xd5, 0xe6, 0x41, 0xd8, 0x10, 0x5e, 0x7a, 0xc6, 0xdb, 0x89,
++  0xc7, 0xca, 0x6c, 0x5b, 0xb1, 0x4e, 0x7d, 0x0c, 0x03, 0xfd, 0x50, 0xca,
++  0xbf, 0xbb, 0xe2, 0x69, 0x4b, 0x4e, 0xc2, 0x3d, 0x75, 0xfa, 0xd1, 0xcc,
++  0xd6, 0xf9, 0x39, 0xb9, 0xdc, 0x53, 0xad, 0x62, 0xfb, 0x1b, 0x94, 0x26,
++  0x7f, 0x21, 0x54, 0x5c, 0xb7, 0xdc, 0xe7, 0x96, 0x8c, 0xce, 0x75, 0xe0,
++  0x17, 0x01, 0x3a, 0x3c, 0x77, 0x6e, 0xa4, 0x8b, 0x7a, 0x83, 0x28, 0x7a,
++  0xf7, 0xb0, 0x5f, 0xfc, 0x7f, 0x2d, 0x2e, 0xec, 0xf5, 0xeb, 0x9c, 0x63,
++  0x74, 0xd0, 0xe5, 0xdc, 0x19, 0xe4, 0x71, 0xc5, 0x4a, 0x8a, 0x54, 0xa4,
++  0xe0, 0x7d, 0x4e, 0xbf, 0x53, 0x30, 0xaf, 0xd0, 0xeb, 0x96, 0xc3, 0xbb,
++  0x65, 0xf7, 0x67, 0xf5, 0xae, 0xd3, 0x96, 0xf2, 0x63, 0xc8, 0x69, 0xf7,
++  0x47, 0xcb, 0x27, 0x79, 0xe1, 0xff, 0x2f, 0x68, 0xdf, 0x1e, 0xb3, 0xb8,
++  0x0c, 0xc5, 0x58, 0x73, 0xcc, 0xfe, 0x8c, 0xda, 0x4e, 0x3b, 0x01, 0x04,
++  0xcd, 0xcb, 0xb8, 0x3e, 0x06, 0xfd, 0x4c, 0x0a, 0x9f, 0x5e, 0x76, 0x8c,
++  0x0c, 0x83, 0x75, 0x09, 0x08, 0xb2, 0xdb, 0xf4, 0x49, 0x4e, 0xa0, 0xf2,
++  0x0c, 0x7b, 0x87, 0x38, 0x9e, 0x22, 0x67, 0xbd, 0xd1, 0x97, 0x57, 0x24,
++  0xf1, 0x46, 0x07, 0xf9, 0xd2, 0x1b, 0xec, 0x25, 0x5e, 0x67, 0xd9, 0x66,
++  0x23, 0x1b, 0xd3, 0xe4, 0xaa, 0xec, 0x88, 0xf0, 0x7e, 0x15, 0x83, 0x51,
++  0x31, 0x67, 0x51, 0x76, 0x5f, 0x55, 0xd7, 0x36, 0xdf, 0x4a, 0x84, 0x0b,
++  0x6f, 0x5c, 0xbb, 0x5b, 0x8f, 0x37, 0x23, 0x7f, 0xf8, 0x17, 0x84, 0xa2,
++  0x70, 0x20, 0x07, 0x0c, 0x90, 0x3a, 0x04, 0xfd, 0xf0, 0x08, 0x4a, 0xb1,
++  0x16, 0x0f, 0xe6, 0xf6, 0x40, 0x51, 0x83, 0xd2, 0x87, 0x40, 0x9c, 0x1c,
++  0x9f, 0x13, 0x38, 0x17, 0xd3, 0x34, 0x58, 0xad, 0x05, 0x71, 0xa0, 0x73,
++  0xca, 0x40, 0xa6, 0xa4, 0x81, 0x02, 0xee, 0xa8, 0x72, 0x41, 0xa1, 0x41,
++  0x18, 0x64, 0x8a, 0x86, 0x8a, 0x5d, 0xe6, 0x4f, 0x0a, 0xc5, 0x95, 0x98,
++  0xf9, 0x78, 0xfe, 0x19, 0x0d, 0xc9, 0xb3, 0x89, 0xc1, 0x2b, 0x09, 0xbe,
++  0xf1, 0xd2, 0x04, 0x5d, 0xcc, 0x28, 0xf5, 0x4b, 0xd2, 0x20, 0x4f, 0xc5,
++  0x41, 0x9d, 0x8c, 0x85, 0xd8, 0xb0, 0x68, 0x5e, 0xc1, 0x0c, 0xb7, 0x24,
++  0x4d, 0x67, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30,
++  0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30,
++  0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02,
++  0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
++  0x14, 0xac, 0xf5, 0x47, 0x17, 0xd9, 0x7d, 0xc1, 0xb1, 0xc4, 0x41, 0xe1,
++  0x41, 0x60, 0xcb, 0x37, 0x11, 0x60, 0x28, 0x78, 0x5f, 0x30, 0x1f, 0x06,
++  0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x21, 0x94,
++  0xfb, 0xf9, 0xb2, 0x43, 0xe9, 0x33, 0xd7, 0x50, 0x7d, 0xc7, 0x37, 0xdb,
++  0xd5, 0x82, 0x5a, 0x4e, 0xbe, 0x1b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
++  0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02,
++  0x01, 0x00, 0x96, 0x70, 0x65, 0x26, 0x42, 0xf8, 0xdc, 0x69, 0xde, 0xcf,
++  0x41, 0x3a, 0x2e, 0x7f, 0x5b, 0xf1, 0xf9, 0x3b, 0x9b, 0xd2, 0x4e, 0x64,
++  0x48, 0x81, 0xe4, 0x5d, 0x1e, 0x22, 0xce, 0x68, 0x63, 0x62, 0xe5, 0x1b,
++  0x9b, 0xf2, 0xc7, 0x12, 0xda, 0x1e, 0x9b, 0x90, 0x84, 0x79, 0x48, 0x12,
++  0xe6, 0x21, 0x6f, 0x2f, 0x7e, 0x18, 0x77, 0xdb, 0x8c, 0xc4, 0xd1, 0x0d,
++  0x91, 0xbf, 0x39, 0x22, 0x0f, 0x64, 0xcf, 0x25, 0x2e, 0x8c, 0x1f, 0x91,
++  0x81, 0xb5, 0xe9, 0x6c, 0x02, 0x3a, 0xf8, 0x07, 0xa2, 0x6f, 0x46, 0x5d,
++  0x7b, 0xfd, 0x43, 0xff, 0x41, 0x0f, 0xe2, 0x57, 0x1c, 0xbd, 0x48, 0x60,
++  0x53, 0x11, 0x48, 0x87, 0x88, 0x9d, 0x13, 0x82, 0x40, 0x68, 0x44, 0x2c,
++  0xc6, 0xc8, 0x95, 0x27, 0x4f, 0xb6, 0xb9, 0x4a, 0x22, 0x0a, 0xfd, 0xe4,
++  0x46, 0x8f, 0x35, 0x12, 0x98, 0x5a, 0x34, 0x6f, 0x2b, 0x57, 0x62, 0xa1,
++  0x4d, 0x8d, 0x79, 0x37, 0xe4, 0x6b, 0x8a, 0x32, 0x5b, 0xcb, 0xef, 0x79,
++  0x11, 0xed, 0xa7, 0xf8, 0x7a, 0x1c, 0xbd, 0x86, 0xdc, 0x0e, 0x2e, 0xfd,
++  0xd3, 0x51, 0xbb, 0x73, 0xad, 0x00, 0xa0, 0x1b, 0xf9, 0x1d, 0xd1, 0x4a,
++  0xe4, 0xd4, 0x02, 0x63, 0x2b, 0x39, 0x5f, 0x18, 0x08, 0x2f, 0x42, 0xb7,
++  0x23, 0x4b, 0x48, 0x46, 0x1f, 0x63, 0x87, 0xae, 0x6d, 0xd5, 0xdb, 0x60,
++  0xf8, 0x5f, 0xd3, 0x13, 0xec, 0xca, 0xdd, 0x60, 0x60, 0x79, 0x52, 0x70,
++  0x47, 0xae, 0x1d, 0x38, 0x78, 0x71, 0xcf, 0xb3, 0x04, 0x03, 0xbe, 0xba,
++  0x81, 0xba, 0x74, 0xb1, 0x30, 0x35, 0xdc, 0xea, 0x21, 0x4a, 0x9b, 0x70,
++  0xfb, 0xd6, 0x60, 0x59, 0x78, 0x0c, 0x4d, 0x39, 0x19, 0x1d, 0xe5, 0x75,
++  0xba, 0x07, 0xf4, 0x22, 0x37, 0x64, 0xb7, 0xf2, 0x9a, 0xc9, 0x11, 0x2d,
++  0x8e, 0x58, 0xa6, 0xcf, 0x83, 0xf1, 0xcb, 0x6c, 0x7f, 0x02, 0xbd, 0xda,
++  0x03, 0x92, 0xa9, 0x45, 0x24, 0x56, 0xc5, 0xbd, 0x41, 0xd1, 0x20, 0x86,
++  0xc0, 0xb6, 0xb7, 0xe8, 0xa7, 0xb2, 0x46, 0xf7, 0x8e, 0xa9, 0x38, 0x0e,
++  0x23, 0x77, 0x3c, 0x0d, 0x66, 0x83, 0x6a, 0x1a, 0x6b, 0x7f, 0x54, 0x11,
++  0x58, 0x0d, 0x4a, 0xb5, 0x74, 0x60, 0xca, 0xed, 0xff, 0x91, 0x47, 0xd9,
++  0x29, 0xe0, 0xaa, 0x8c, 0xa8, 0x8f, 0x10, 0x4c, 0x15, 0x7d, 0xce, 0x95,
++  0xf9, 0x87, 0x1e, 0x18, 0x38, 0x18, 0xfc, 0xcc, 0xaf, 0x91, 0x17, 0x3f,
++  0xfa, 0xf0, 0x8a, 0x09, 0x6f, 0xba, 0x4e, 0x53, 0xf7, 0xfa, 0x4f, 0x20,
++  0xa3, 0xf4, 0x4a, 0x5a, 0xde, 0x17, 0x1c, 0x29, 0x6a, 0x6f, 0x03, 0x48,
++  0xdf, 0xad, 0x4f, 0xe4, 0xbc, 0x71, 0xc4, 0x72, 0x32, 0x11, 0x84, 0xac,
++  0x09, 0xd2, 0x18, 0x44, 0x35, 0xf1, 0xcd, 0xaf, 0xa8, 0x98, 0xe0, 0x8b,
++  0xec, 0xa0, 0x83, 0x37, 0xc3, 0x35, 0x85, 0xd6, 0xd8, 0x1b, 0xe0, 0x75,
++  0xdc, 0xfd, 0xde, 0xc9, 0xeb, 0xd5, 0x18, 0x0f, 0xd3, 0x4c, 0x2f, 0x71,
++  0xdc, 0x48, 0xe3, 0x14, 0xeb, 0xda, 0x00, 0x24, 0x24, 0x9e, 0xa3, 0x8e,
++  0x3e, 0x08, 0x6f, 0x22, 0x24, 0xd6, 0xc4, 0x85, 0x8f, 0x68, 0x00, 0x4a,
++  0x82, 0x4c, 0x33, 0x6e, 0xa5, 0x35, 0x7b, 0xeb, 0x4b, 0xdc, 0xa0, 0xa6,
++  0x65, 0x6f, 0x5a, 0x7a, 0xdf, 0x8a, 0x01, 0x52, 0xa1, 0x6c, 0xff, 0x59,
++  0x22, 0x7f, 0xe1, 0x96, 0x1b, 0x19, 0xb8, 0xf9, 0x5d, 0x44, 0x9f, 0x91,
++  0x03, 0x3c, 0x3d, 0xa1, 0x2a, 0xb6, 0x5a, 0x51, 0xa0, 0xce, 0x4a, 0x88,
++  0x22, 0x72, 0x9c, 0xdc, 0xc0, 0x47, 0x76, 0x35, 0x84, 0x75, 0x9b, 0x87,
++  0x5c, 0xd3, 0xcf, 0xe7, 0xdd, 0xa3, 0x57, 0x14, 0xdf, 0x00, 0xfd, 0x19,
++  0x2a, 0x7d, 0x89, 0x27, 0x1c, 0x78, 0x97, 0x04, 0x58, 0x48
++};
++unsigned int certificate2_der_len = 1366;
++
++unsigned char hi_signed_2nd[] = {
++  0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb1, 0x06, 0x09, 0x2a, 0x86, 0x48,
++  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa2, 0x30, 0x82,
++  0x02, 0x9e, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
++  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
++  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02,
++  0x7b, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 0x3a,
++  0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x47,
++  0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 0x74,
++  0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74,
++  0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
++  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 0x14,
++  0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 0x07,
++  0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 0x09,
++  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 0x06,
++  0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
++  0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 0x90,
++  0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 0x99,
++  0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 0x07,
++  0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 0xfe,
++  0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 0x5f,
++  0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 0x4f,
++  0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 0x6f,
++  0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 0x53,
++  0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 0xd2,
++  0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 0xc0,
++  0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 0xdf,
++  0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 0x05,
++  0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 0x3d,
++  0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 0x7d,
++  0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 0x81,
++  0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 0x36,
++  0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 0xd5,
++  0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 0xcc,
++  0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 0x70,
++  0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 0x94,
++  0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 0xe3,
++  0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 0x20,
++  0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 0xc2,
++  0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 0xac,
++  0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 0xdb,
++  0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 0x49,
++  0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 0xb0,
++  0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 0xcb,
++  0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 0x76,
++  0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 0xa5,
++  0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 0x49,
++  0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 0x6b,
++  0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 0x25,
++  0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 0x2e,
++  0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 0xa0,
++  0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 0x98,
++  0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 0x8b,
++  0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 0x83,
++  0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 0x3e,
++  0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 0x8a,
++  0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 0xb7,
++  0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 0x26,
++  0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 0xac,
++  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xb5,
++  0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e,
++  0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64,
++  0x65, 0x64, 0x7e, 0x0a
++};
++unsigned int hi_signed_2nd_len = 736;
++
++unsigned char certificate_printable_der[] = {
++  0x30, 0x82, 0x03, 0x39, 0x30, 0x82, 0x02, 0x21, 0xa0, 0x03, 0x02, 0x01,
++  0x02, 0x02, 0x09, 0x00, 0xde, 0xf6, 0x22, 0xc4, 0xf2, 0xf1, 0x86, 0x02,
++  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
++  0x0b, 0x05, 0x00, 0x30, 0x2a, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55,
++  0x04, 0x03, 0x13, 0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20,
++  0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20,
++  0x43, 0x41, 0x20, 0x32, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 0x30,
++  0x1e, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x30, 0x33, 0x31, 0x31, 0x34, 0x31,
++  0x39, 0x32, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x37, 0x31, 0x30, 0x32, 0x35,
++  0x31, 0x34, 0x31, 0x39, 0x32, 0x33, 0x5a, 0x30, 0x2f, 0x31, 0x2d, 0x30,
++  0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x24, 0x52, 0x65, 0x64, 0x20,
++  0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42,
++  0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20,
++  0x33, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 0x30, 0x82, 0x01, 0x22,
++  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
++  0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
++  0x02, 0x82, 0x01, 0x01, 0x00, 0xbd, 0xda, 0xa1, 0xed, 0x8d, 0x8e, 0x15,
++  0x5c, 0xf8, 0x01, 0x77, 0x48, 0x4a, 0x60, 0x96, 0xf9, 0x27, 0xfa, 0xe2,
++  0xb1, 0x69, 0x0f, 0x51, 0x19, 0x52, 0x7e, 0xc4, 0x34, 0x8e, 0xe1, 0x9b,
++  0x9c, 0xa4, 0xb1, 0x5c, 0xd6, 0x81, 0x98, 0x78, 0xfe, 0xa9, 0xe5, 0x0b,
++  0x00, 0xba, 0x9c, 0x64, 0x7e, 0xc7, 0xcc, 0x72, 0xb1, 0x73, 0x4b, 0x11,
++  0x07, 0x52, 0xf0, 0x20, 0x96, 0x8b, 0x99, 0x39, 0xde, 0xdb, 0xfa, 0x3d,
++  0x45, 0xe2, 0x98, 0x7b, 0x0c, 0x41, 0xe4, 0x0c, 0xb5, 0x5d, 0x92, 0x74,
++  0x39, 0x96, 0xe1, 0x97, 0x97, 0xa1, 0xad, 0x2e, 0xcc, 0xd0, 0x1b, 0x4d,
++  0x9d, 0xbd, 0x3e, 0xa9, 0x36, 0x8e, 0xcc, 0xc7, 0x5f, 0x6a, 0x7d, 0x39,
++  0x5e, 0x0b, 0x8d, 0xca, 0xe4, 0x83, 0xe9, 0x3b, 0x5c, 0x86, 0x47, 0xd4,
++  0xba, 0x7d, 0x98, 0x26, 0xa1, 0xf4, 0xe8, 0x90, 0x6b, 0x0f, 0xf1, 0x6b,
++  0x8c, 0xe3, 0xa2, 0x80, 0x3c, 0x96, 0xf1, 0x0a, 0xb6, 0x66, 0xc0, 0x4b,
++  0x61, 0xf7, 0x74, 0xcd, 0xd3, 0x7b, 0x8e, 0x5e, 0x39, 0xda, 0x99, 0x20,
++  0x33, 0x93, 0xd3, 0xf0, 0x7f, 0xad, 0x35, 0xe9, 0x88, 0x8d, 0x9c, 0xbf,
++  0x65, 0xf1, 0x47, 0x02, 0xf9, 0x7c, 0xed, 0x27, 0x5f, 0x4a, 0x65, 0x3c,
++  0xcf, 0x5f, 0x0e, 0x88, 0x95, 0x74, 0xde, 0xfb, 0x9e, 0x2e, 0x91, 0x9b,
++  0x45, 0x37, 0xc8, 0x85, 0xff, 0xe3, 0x41, 0x70, 0xfe, 0xd5, 0xef, 0x0e,
++  0x82, 0x22, 0x08, 0xb7, 0x3b, 0x44, 0x3e, 0xdc, 0x5b, 0x7f, 0xba, 0xbf,
++  0xe6, 0x58, 0x9d, 0x02, 0x6e, 0x75, 0xbf, 0x50, 0xec, 0xcf, 0x3f, 0xa5,
++  0x91, 0x0a, 0xe2, 0x59, 0x2c, 0xc3, 0xe7, 0x05, 0x03, 0xe8, 0xf2, 0x6f,
++  0x2a, 0x04, 0x68, 0x9a, 0x31, 0x32, 0x8f, 0x04, 0x35, 0xcd, 0x1f, 0x34,
++  0xcc, 0x4f, 0x79, 0x5a, 0x99, 0x8d, 0x9d, 0x5c, 0xf5, 0x02, 0x03, 0x01,
++  0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d,
++  0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03,
++  0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x1d, 0x06,
++  0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x65, 0xc5, 0xbe, 0xca,
++  0xe6, 0x59, 0x6a, 0xfd, 0x6c, 0x71, 0xc4, 0xa7, 0x98, 0xc6, 0x25, 0x8d,
++  0x7b, 0x67, 0x05, 0xd0, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
++  0x18, 0x30, 0x16, 0x80, 0x14, 0x81, 0xf8, 0xee, 0x47, 0x5c, 0x3e, 0xed,
++  0xfb, 0xce, 0xa5, 0x84, 0xbe, 0xd7, 0xae, 0xdb, 0xd3, 0x7d, 0x64, 0xb3,
++  0x2a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
++  0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x66, 0x1e, 0x3d,
++  0x1d, 0x53, 0x33, 0xde, 0x4e, 0xc7, 0xc4, 0xf4, 0xdf, 0xda, 0x18, 0x19,
++  0x8a, 0xa9, 0xff, 0xe2, 0x63, 0x2b, 0xbe, 0xf2, 0x61, 0x63, 0xe2, 0xf6,
++  0xed, 0x47, 0x1a, 0x71, 0x02, 0xec, 0x2a, 0xef, 0x89, 0x77, 0xe3, 0xfd,
++  0x86, 0x69, 0xf1, 0x3f, 0x0d, 0xf9, 0x6e, 0xf9, 0x3b, 0xad, 0x26, 0x47,
++  0xb7, 0xf2, 0x0d, 0xad, 0x23, 0xa3, 0x67, 0x3b, 0xcb, 0x6d, 0x9e, 0x03,
++  0x0f, 0xbc, 0x69, 0x73, 0x9f, 0xd4, 0xa5, 0x0f, 0x6f, 0xf8, 0xab, 0x4d,
++  0x36, 0xd1, 0xe0, 0xe0, 0x5d, 0x20, 0x43, 0x90, 0xc4, 0x65, 0x61, 0x93,
++  0xe2, 0x0f, 0x51, 0x59, 0x0a, 0xf7, 0x88, 0x70, 0x57, 0xb9, 0x04, 0xa9,
++  0x32, 0x57, 0x9c, 0xb3, 0x57, 0x38, 0x8b, 0x8e, 0x46, 0xc8, 0x32, 0x6c,
++  0xb4, 0xf3, 0x96, 0x7f, 0x4b, 0xf0, 0x88, 0xf9, 0x7f, 0xe2, 0x71, 0xe1,
++  0x8b, 0xe2, 0x14, 0xf1, 0x4b, 0x25, 0x00, 0x48, 0x1c, 0x7e, 0xe5, 0x8d,
++  0x65, 0x2d, 0xeb, 0x72, 0x4f, 0x92, 0x44, 0xf3, 0xe6, 0xe0, 0xd0, 0xdf,
++  0x85, 0xa8, 0x13, 0x4a, 0xfb, 0x99, 0xca, 0x14, 0x2c, 0x97, 0x80, 0x93,
++  0x27, 0xd3, 0x20, 0xf8, 0x6d, 0x29, 0x28, 0x2c, 0xb9, 0x77, 0xea, 0xb1,
++  0x63, 0xbd, 0x7d, 0x53, 0xfd, 0x4a, 0x62, 0x64, 0x0b, 0x98, 0xa8, 0xae,
++  0x11, 0xfc, 0x6e, 0x8d, 0x63, 0xd4, 0x15, 0x55, 0xc6, 0x4c, 0x74, 0xf5,
++  0x5f, 0xa0, 0xb9, 0x2c, 0x2d, 0x9a, 0x7a, 0x87, 0x6e, 0xf0, 0x5e, 0x25,
++  0xed, 0xfc, 0xd8, 0xc4, 0x34, 0x33, 0x32, 0xad, 0x01, 0xd4, 0x4b, 0x49,
++  0x51, 0xc2, 0x07, 0x7f, 0x90, 0x6d, 0xea, 0xf5, 0x4c, 0x41, 0x71, 0x64,
++  0xeb, 0x1f, 0x29, 0xa3, 0x1f, 0x64, 0xa2, 0x1e, 0x0e, 0x6f, 0xa1, 0x67,
++  0x99, 0x8d, 0x98, 0x1c, 0xb8, 0x53, 0x9d, 0x30, 0x1d, 0xae, 0x32, 0x56,
++  0xd2
++};
++unsigned int certificate_printable_der_len = 829;
diff --git a/SOURCES/0172-Introduce-function-grub_debug_is_enabled-void-return.patch b/SOURCES/0172-Introduce-function-grub_debug_is_enabled-void-return.patch
deleted file mode 100644
index 4e4718b..0000000
--- a/SOURCES/0172-Introduce-function-grub_debug_is_enabled-void-return.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
-Date: Mon, 25 Nov 2019 09:29:53 +0100
-Subject: [PATCH] Introduce function grub_debug_is_enabled(void) returning 1 if
- 'debug' is in the environment and not empty
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
----
- grub-core/kern/misc.c | 13 +++++++++++++
- include/grub/misc.h   |  1 +
- 2 files changed, 14 insertions(+)
-
-diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
-index 9f54b6b7d2d..a186ad3dd41 100644
---- a/grub-core/kern/misc.c
-+++ b/grub-core/kern/misc.c
-@@ -163,6 +163,19 @@ int grub_err_printf (const char *fmt, ...)
- __attribute__ ((alias("grub_printf")));
- #endif
- 
-+/* Return 1 if 'debug' is set and not empty */
-+int
-+grub_debug_is_enabled (void)
-+{
-+  const char *debug;
-+
-+  debug = grub_env_get ("debug");
-+  if (!debug || debug[0] == '\0')
-+    return 0;
-+
-+  return 1;
-+}
-+
- int
- grub_debug_enabled (const char * condition)
- {
-diff --git a/include/grub/misc.h b/include/grub/misc.h
-index 3adc4036e3b..6c4aa85ac50 100644
---- a/include/grub/misc.h
-+++ b/include/grub/misc.h
-@@ -340,6 +340,7 @@ grub_puts (const char *s)
- }
- 
- int EXPORT_FUNC(grub_puts_) (const char *s);
-+int EXPORT_FUNC(grub_debug_is_enabled) (void);
- int EXPORT_FUNC(grub_debug_enabled) (const char *condition);
- void EXPORT_FUNC(grub_real_dprintf) (const char *file,
-                                      const int line,
diff --git a/SOURCES/0172-appended-signatures-documentation.patch b/SOURCES/0172-appended-signatures-documentation.patch
new file mode 100644
index 0000000..eb58046
--- /dev/null
+++ b/SOURCES/0172-appended-signatures-documentation.patch
@@ -0,0 +1,341 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 1 Oct 2020 13:02:09 +1000
+Subject: [PATCH] appended signatures: documentation
+
+This explains how appended signatures can be used to form part of
+a secure boot chain, and documents the commands and variables
+introduced.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ docs/grub.texi | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 182 insertions(+), 17 deletions(-)
+
+diff --git a/docs/grub.texi b/docs/grub.texi
+index afbde7c1f7..4816be8561 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -3214,6 +3214,7 @@ These variables have special meaning to GRUB.
+ 
+ @menu
+ * biosnum::
++* check_appended_signatures::
+ * check_signatures::
+ * chosen::
+ * cmdpath::
+@@ -3273,11 +3274,18 @@ For an alternative approach which also changes BIOS drive mappings for the
+ chain-loaded system, @pxref{drivemap}.
+ 
+ 
++@node check_appended_signatures
++@subsection check_appended_signatures
++
++This variable controls whether GRUB enforces appended signature validation on
++certain loaded files. @xref{Using appended signatures}.
++
++
+ @node check_signatures
+ @subsection check_signatures
+ 
+-This variable controls whether GRUB enforces digital signature
+-validation on loaded files. @xref{Using digital signatures}.
++This variable controls whether GRUB enforces GPG-style digital signature
++validation on loaded files. @xref{Using GPG-style digital signatures}.
+ 
+ @node chosen
+ @subsection chosen
+@@ -3994,6 +4002,7 @@ you forget a command, you can run the command @command{help}
+ * date::                        Display or set current date and time
+ * devicetree::                  Load a device tree blob
+ * distrust::                    Remove a pubkey from trusted keys
++* distrust_certificate::        Remove a certificate from the list of trusted certificates
+ * drivemap::                    Map a drive to another
+ * echo::                        Display a line of text
+ * eval::                        Evaluate agruments as GRUB commands
+@@ -4010,6 +4019,7 @@ you forget a command, you can run the command @command{help}
+ * keystatus::                   Check key modifier status
+ * linux::                       Load a Linux kernel
+ * linux16::                     Load a Linux kernel (16-bit mode)
++* list_certificates::           List trusted certificates
+ * list_env::                    List variables in environment block
+ * list_trusted::                List trusted public keys
+ * load_env::                    Load variables from environment block
+@@ -4047,8 +4057,10 @@ you forget a command, you can run the command @command{help}
+ * test::                        Check file types and compare values
+ * true::                        Do nothing, successfully
+ * trust::                       Add public key to list of trusted keys
++* trust_certificate::           Add an x509 certificate to the list of trusted certificates
+ * unset::                       Unset an environment variable
+ @comment * vbeinfo::                     List available video modes
++* verify_appended::             Verify appended digital signature
+ * verify_detached::             Verify detached digital signature
+ * videoinfo::                   List available video modes
+ @comment * xen_*::              Xen boot commands for AArch64
+@@ -4376,9 +4388,28 @@ These keys are used to validate signatures when environment variable
+ @code{check_signatures} is set to @code{enforce}
+ (@pxref{check_signatures}), and by some invocations of
+ @command{verify_detached} (@pxref{verify_detached}).  @xref{Using
+-digital signatures}, for more information.
++GPG-style digital signatures}, for more information.
+ @end deffn
+ 
++
++@node distrust_certificate
++@subsection distrust_certificate
++
++@deffn Command distrust_certificate cert_number
++Remove the x509 certificate numbered @var{cert_number} from GRUB's keyring of
++trusted x509 certificates for verifying appended signatures.
++
++@var{cert_number} is the certificate number as listed by
++@command{list_certificates} (@pxref{list_certificates}).
++
++These certificates are used to validate appended signatures when environment
++variable @code{check_appended_signatures} is set to @code{enforce} or
++@code{forced} (@pxref{check_appended_signatures}), and by
++@command{verify_appended} (@pxref{verify_appended}). See
++@xref{Using appended signatures} for more information.
++@end deffn
++
++
+ @node drivemap
+ @subsection drivemap
+ 
+@@ -4636,6 +4667,21 @@ This command is only available on x86 systems.
+ @end deffn
+ 
+ 
++@node list_certificates
++@subsection list_certificates
++
++@deffn Command list_certificates
++List all x509 certificates trusted by GRUB for validating appended signatures.
++The output is a numbered list of certificates, showing the certificate's serial
++number and Common Name.
++
++The certificate number can be used as an argument to
++@command{distrust_certificate} (@pxref{distrust_certificate}).
++
++See @xref{Using appended signatures} for more information.
++@end deffn
++
++
+ @node list_env
+ @subsection list_env
+ 
+@@ -4655,7 +4701,7 @@ The output is in GPG's v4 key fingerprint format (i.e., the output of
+ @code{gpg --fingerprint}).  The least significant four bytes (last
+ eight hexadecimal digits) can be used as an argument to
+ @command{distrust} (@pxref{distrust}).
+-@xref{Using digital signatures}, for more information about uses for
++@xref{Using GPG-style digital signatures}, for more information about uses for
+ these keys.
+ @end deffn
+ 
+@@ -4690,8 +4736,13 @@ When used with care, @option{--skip-sig} and the whitelist enable an
+ administrator to configure a system to boot only signed
+ configurations, but to allow the user to select from among multiple
+ configurations, and to enable ``one-shot'' boot attempts and
+-``savedefault'' behavior.  @xref{Using digital signatures}, for more
++``savedefault'' behavior.  @xref{Using GPG-style digital signatures}, for more
+ information.
++
++Extra care should be taken when combining this command with appended signatures
++(@pxref{Using appended signatures}), as this file is not validated by an
++appended signature and could set @code{check_appended_signatures=no} if GRUB is
++not in @pxref{Lockdown} mode.
+ @end deffn
+ 
+ 
+@@ -4987,7 +5038,7 @@ read.  It is possible to modify a digitally signed environment block
+ file from within GRUB using this command, such that its signature will
+ no longer be valid on subsequent boots.  Care should be taken in such
+ advanced configurations to avoid rendering the system
+-unbootable. @xref{Using digital signatures}, for more information.
++unbootable. @xref{Using GPG-style digital signatures}, for more information.
+ @end deffn
+ 
+ 
+@@ -5387,11 +5438,32 @@ signatures when environment variable @code{check_signatures} is set to
+ must itself be properly signed.  The @option{--skip-sig} option can be
+ used to disable signature-checking when reading @var{pubkey_file}
+ itself. It is expected that @option{--skip-sig} is useful for testing
+-and manual booting. @xref{Using digital signatures}, for more
++and manual booting. @xref{Using GPG-style digital signatures}, for more
+ information.
+ @end deffn
+ 
+ 
++@node trust_certificate
++@subsection trust_certificate
++
++@deffn Command trust_certificate x509_certificate
++Read an DER-formatted x509 certificate from the file @var{x509_certificate}
++and add it to GRUB's internal list of trusted x509 certificates. These
++certificates are used to validate appended signatures when the environment
++variable @code{check_appended_signatures} is set to @code{enforce} or
++@code{forced}.
++
++Note that if @code{check_appended_signatures} is set to @code{enforce} or
++@code{forced} when @command{trust_certificate} is executed, then
++@var{x509_certificate} must itself bear an appended signature. (It is not
++sufficient that @var{x509_certificate} be signed by a trusted certificate
++according to the x509 rules: grub does not include support for validating
++signatures within x509 certificates themselves.)
++
++See @xref{Using appended signatures} for more information.
++@end deffn
++
++
+ @node unset
+ @subsection unset
+ 
+@@ -5410,6 +5482,18 @@ only on PC BIOS platforms.
+ @end deffn
+ @end ignore
+ 
++@node verify_appended
++@subsection verify_appended
++
++@deffn Command verify_appended file
++Verifies an appended signature on @var{file} against the trusted certificates
++known to GRUB (See @pxref{list_certificates}, @pxref{trust_certificate}, and
++@pxref{distrust_certificate}).
++
++Exit code @code{$?} is set to 0 if the signature validates
++successfully.  If validation fails, it is set to a non-zero value.
++See @xref{Using appended signatures}, for more information.
++@end deffn
+ 
+ @node verify_detached
+ @subsection verify_detached
+@@ -5428,7 +5512,7 @@ tried.
+ 
+ Exit code @code{$?} is set to 0 if the signature validates
+ successfully.  If validation fails, it is set to a non-zero value.
+-@xref{Using digital signatures}, for more information.
++@xref{Using GPG-style digital signatures}, for more information.
+ @end deffn
+ 
+ @node videoinfo
+@@ -5811,13 +5895,14 @@ environment variables and commands are listed in the same order.
+ @chapter Security
+ 
+ @menu
+-* Authentication and authorisation:: Users and access control
+-* Using digital signatures::         Booting digitally signed code
+-* UEFI secure boot and shim::        Booting digitally signed PE files
+-* Secure Boot Advanced Targeting::   Embedded information for generation number based revocation
+-* Measured Boot::                    Measuring boot components
+-* Lockdown::                         Lockdown when booting on a secure setup
+-* Signing GRUB itself::              Ensuring the integrity of the GRUB core image
++* Authentication and authorisation::   Users and access control
++* Using GPG-style digital signatures:: Booting digitally signed code
++* Using appended signatures::          An alternative approach to booting digitally signed code
++* UEFI secure boot and shim::          Booting digitally signed PE files
++* Secure Boot Advanced Targeting::     Embedded information for generation number based revocation
++* Measured Boot::                      Measuring boot components
++* Lockdown::                           Lockdown when booting on a secure setup
++* Signing GRUB itself::                Ensuring the integrity of the GRUB core image
+ @end menu
+ 
+ @node Authentication and authorisation
+@@ -5891,8 +5976,8 @@ generating configuration files with authentication.  You can use
+ adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2}
+ commands.
+ 
+-@node Using digital signatures
+-@section Using digital signatures in GRUB
++@node Using GPG-style digital signatures
++@section Using GPG-style digital signatures in GRUB
+ 
+ GRUB's @file{core.img} can optionally provide enforcement that all files
+ subsequently read from disk are covered by a valid digital signature.
+@@ -5985,6 +6070,86 @@ or BIOS) configuration to cause the machine to boot from a different
+ (attacker-controlled) device.  GRUB is at best only one link in a
+ secure boot chain.
+ 
++@node Using appended signatures
++@section Using appended signatures in GRUB
++
++GRUB supports verifying Linux-style 'appended signatures' for secure boot.
++Appended signatures are PKCS#7 messages containing a signature over the
++contents of a file, plus some metadata, appended to the end of a file. A file
++with an appended signature ends with the magic string:
++
++@example
++~Module signature appended~\n
++@end example
++
++where @code{\n} represents the line-feed character, @code{0x0a}.
++
++Certificates can be managed at boot time using the @pxref{trust_certificate},
++@pxref{distrust_certificate} and @pxref{list_certificates} commands.
++Certificates can also be built in to the core image using the @code{--x509}
++parameter to @command{grub-install} or @command{grub-mkimage}.
++
++A file can be explictly verified using the @pxref{verify_appended} command.
++
++Only signatures made with the SHA-256 or SHA-512 hash algorithm are supported,
++and only RSA signatures are supported.
++
++A file can be signed with the @command{sign-file} utility supplied with the
++Linux kernel source. For example, if you have @code{signing.key} as the private
++key and @code{certificate.der} as the x509 certificate containing the public key:
++
++@example
++sign-file SHA256 signing.key certificate.der vmlinux vmlinux.signed
++@end example
++
++Enforcement of signature verification is controlled by the
++@code{check_appended_signatures} variable.
++
++@itemize
++@item @samp{no}: no verification is performed. This is the default when GRUB
++      is not in @pxref{Lockdown} mode.
++@item @samp{enforce}: verification is performed. Verification can be disabled
++      by setting the variable back to @samp{no}.
++@item @samp{forced}: verification is performed and cannot be disabled. This is
++      set when GRUB is in Lockdown when the appendedsig module is loaded.
++@end itemize
++
++Unlike GPG-style signatures, not all files loaded by GRUB are required to be
++signed. Once verification is turned on, the following file types will have
++appended signatures verified:
++
++@itemize
++@item Linux kernels
++@item GRUB modules, except those built into the core image
++@item Any new certificate files to be trusted
++@end itemize
++
++ACPI tables and Device Tree images will not be checked for appended signatures
++but must be verified by another mechanism such as GPG-style signatures before
++they will be loaded.
++
++Unless lockdown mode is enabled, signature checking does @strong{not}
++stop an attacker with console access from dropping manually to the GRUB
++console and executing:
++
++@example
++set check_appended_signatures=no
++@end example
++
++Refer to the section on password-protecting GRUB (@pxref{Authentication
++and authorisation}) for more information on preventing this.
++
++Additionally, unless lockdown mode is enabled:
++
++@itemize
++@item Special care must be taken around the @command{loadenv} command, which
++      can be used to turn off @code{check_appended_signature}.
++
++@item If the grub configuration file is loaded from the disk, anyone who can
++      modify the file on disk can turn off @code{check_appended_signature}.
++      Consider embedding the configuration into the core grub image.
++@end itemize
++
+ @node UEFI secure boot and shim
+ @section UEFI secure boot and shim support
+ 
diff --git a/SOURCES/0173-Don-t-clear-screen-when-debugging-is-enabled.patch b/SOURCES/0173-Don-t-clear-screen-when-debugging-is-enabled.patch
deleted file mode 100644
index d2a5988..0000000
--- a/SOURCES/0173-Don-t-clear-screen-when-debugging-is-enabled.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
-Date: Sat, 23 Nov 2019 16:23:54 +0100
-Subject: [PATCH] Don't clear screen when debugging is enabled
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
----
- grub-core/normal/main.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
-index e349303c29b..155bf366da2 100644
---- a/grub-core/normal/main.c
-+++ b/grub-core/normal/main.c
-@@ -210,7 +210,8 @@ void
- grub_normal_init_page (struct grub_term_output *term,
- 		       int y __attribute__((__unused__)))
- {
--  grub_term_cls (term);
-+  if (! grub_debug_is_enabled ())
-+    grub_term_cls (term);
- 
- #if 0
-   grub_ssize_t msg_len;
diff --git a/SOURCES/0173-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch b/SOURCES/0173-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch
new file mode 100644
index 0000000..c90cc7e
--- /dev/null
+++ b/SOURCES/0173-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch
@@ -0,0 +1,109 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 28 Sep 2020 11:11:17 +1000
+Subject: [PATCH] ieee1275: enter lockdown based on /ibm,secure-boot
+
+If the 'ibm,secure-boot' property of the root node is 2 or greater,
+enter lockdown.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/Makefile.core.def    |  1 +
+ grub-core/kern/ieee1275/init.c | 27 +++++++++++++++++++++++++++
+ include/grub/lockdown.h        |  3 ++-
+ docs/grub.texi                 |  4 ++--
+ 4 files changed, 32 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 9ea5fb38f1..4a57de975e 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -323,6 +323,7 @@ kernel = {
+   powerpc_ieee1275 = kern/powerpc/cache.S;
+   powerpc_ieee1275 = kern/powerpc/dl.c;
+   powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
++  powerpc_ieee1275 = kern/lockdown.c;
+ 
+   sparc64_ieee1275 = kern/sparc64/cache.S;
+   sparc64_ieee1275 = kern/sparc64/dl.c;
+diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
+index 937c1bc44c..fc7d971272 100644
+--- a/grub-core/kern/ieee1275/init.c
++++ b/grub-core/kern/ieee1275/init.c
+@@ -44,6 +44,7 @@
+ #ifdef __sparc__
+ #include <grub/machine/kernel.h>
+ #endif
++#include <grub/lockdown.h>
+ 
+ /* The minimal heap size we can live with. */
+ #define HEAP_MIN_SIZE		(unsigned long) (2 * 1024 * 1024)
+@@ -271,6 +272,30 @@ grub_parse_cmdline (void)
+     }
+ }
+ 
++static void
++grub_get_ieee1275_secure_boot (void)
++{
++  grub_ieee1275_phandle_t root;
++  int rc;
++  grub_uint32_t is_sb;
++
++  grub_ieee1275_finddevice ("/", &root);
++
++  rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", &is_sb,
++                                           sizeof (is_sb), 0);
++
++  /* ibm,secure-boot:
++   * 0 - disabled
++   * 1 - audit
++   * 2 - enforce
++   * 3 - enforce + OS-specific behaviour
++   *
++   * We only support enforce.
++   */
++  if (rc >= 0 && is_sb >= 2)
++    grub_lockdown ();
++}
++
+ grub_addr_t grub_modbase;
+ 
+ void
+@@ -296,6 +321,8 @@ grub_machine_init (void)
+ #else
+   grub_install_get_time_ms (grub_rtc_get_time_ms);
+ #endif
++
++  grub_get_ieee1275_secure_boot ();
+ }
+ 
+ void
+diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h
+index 40531fa823..ebfee4bf06 100644
+--- a/include/grub/lockdown.h
++++ b/include/grub/lockdown.h
+@@ -24,7 +24,8 @@
+ #define GRUB_LOCKDOWN_DISABLED       0
+ #define GRUB_LOCKDOWN_ENABLED        1
+ 
+-#ifdef GRUB_MACHINE_EFI
++#if defined(GRUB_MACHINE_EFI) || \
++    (defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275))
+ extern void
+ EXPORT_FUNC (grub_lockdown) (void);
+ extern int
+diff --git a/docs/grub.texi b/docs/grub.texi
+index 4816be8561..a4da9c2a1b 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -6227,8 +6227,8 @@ Measured boot is currently only supported on EFI platforms.
+ @section Lockdown when booting on a secure setup
+ 
+ The GRUB can be locked down when booted on a secure boot environment, for example
+-if the UEFI secure boot is enabled. On a locked down configuration, the GRUB will
+-be restricted and some operations/commands cannot be executed.
++if UEFI or Power secure boot is enabled. On a locked down configuration, the
++GRUB will be restricted and some operations/commands cannot be executed.
+ 
+ The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down.
+ Otherwise it does not exit.
diff --git a/SOURCES/0174-grub_file_-instrumentation-new-file-debug-tag.patch b/SOURCES/0174-grub_file_-instrumentation-new-file-debug-tag.patch
deleted file mode 100644
index 0cc6b8c..0000000
--- a/SOURCES/0174-grub_file_-instrumentation-new-file-debug-tag.patch
+++ /dev/null
@@ -1,71 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
-Date: Fri, 29 Nov 2019 11:02:00 +0100
-Subject: [PATCH] grub_file_* instrumentation (new 'file' debug tag)
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
----
- grub-core/kern/file.c | 14 ++++++++++++++
- 1 file changed, 14 insertions(+)
-
-diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
-index 58454458c47..e19aea3e514 100644
---- a/grub-core/kern/file.c
-+++ b/grub-core/kern/file.c
-@@ -66,6 +66,8 @@ grub_file_open (const char *name, enum grub_file_type type)
-   const char *file_name;
-   grub_file_filter_id_t filter;
- 
-+  grub_dprintf ("file", "Opening `%s' ...\n", name);
-+
-   device_name = grub_file_get_device_name (name);
-   if (grub_errno)
-     goto fail;
-@@ -128,6 +130,8 @@ grub_file_open (const char *name, enum grub_file_type type)
-   if (!file)
-     grub_file_close (last_file);
- 
-+  grub_dprintf ("file", "Opening `%s' succeeded.\n", name);
-+
-   return file;
- 
-  fail:
-@@ -138,6 +142,8 @@ grub_file_open (const char *name, enum grub_file_type type)
- 
-   grub_free (file);
- 
-+  grub_dprintf ("file", "Opening `%s' failed.\n", name);
-+
-   return 0;
- }
- 
-@@ -169,6 +175,7 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len)
- 
-   if (len == 0)
-     return 0;
-+
-   read_hook = file->read_hook;
-   read_hook_data = file->read_hook_data;
-   if (!file->read_hook)
-@@ -189,11 +196,18 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len)
- grub_err_t
- grub_file_close (grub_file_t file)
- {
-+  grub_dprintf ("file", "Closing `%s' ...\n", file->name);
-   if (file->fs->fs_close)
-     (file->fs->fs_close) (file);
- 
-   if (file->device)
-     grub_device_close (file->device);
-+
-+  if (grub_errno == GRUB_ERR_NONE)
-+    grub_dprintf ("file", "Closing `%s' succeeded.\n", file->name);
-+  else
-+    grub_dprintf ("file", "Closing `%s' failed with %d.\n", file->name, grub_errno);
-+
-   grub_free (file->name);
-   grub_free (file);
-   return grub_errno;
diff --git a/SOURCES/0174-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch b/SOURCES/0174-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch
new file mode 100644
index 0000000..a40caea
--- /dev/null
+++ b/SOURCES/0174-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch
@@ -0,0 +1,75 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Wed, 14 Apr 2021 20:10:23 +1000
+Subject: [PATCH] ieee1275: drop HEAP_MAX_ADDR, HEAP_MIN_SIZE
+
+HEAP_MAX_ADDR is confusing. Currently it is set to 32MB, except
+on ieee1275 on x86, where it is 64MB.
+
+There is a comment which purports to explain it:
+
+/* If possible, we will avoid claiming heap above this address, because it
+   seems to cause relocation problems with OSes that link at 4 MiB */
+
+This doesn't make a lot of sense when the constants are well above 4MB
+already. It was not always this way. Prior to
+commit 7b5d0fe4440c ("Increase heap limit") in 2010, HEAP_MAX_SIZE and
+HEAP_MAX_ADDR were indeed 4MB. However, when the constants were increased
+the comment was left unchanged.
+
+It's been over a decade. It doesn't seem like we have problems with
+claims over 4MB on powerpc or x86 ieee1275. (sparc does things completely
+differently and never used the constant.)
+
+Drop the constant and the check.
+
+The only use of HEAP_MIN_SIZE was to potentially override the
+HEAP_MAX_ADDR check. It is now unused. Remove it.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/kern/ieee1275/init.c | 17 -----------------
+ 1 file changed, 17 deletions(-)
+
+diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
+index fc7d971272..0dcd114ce5 100644
+--- a/grub-core/kern/ieee1275/init.c
++++ b/grub-core/kern/ieee1275/init.c
+@@ -46,9 +46,6 @@
+ #endif
+ #include <grub/lockdown.h>
+ 
+-/* The minimal heap size we can live with. */
+-#define HEAP_MIN_SIZE		(unsigned long) (2 * 1024 * 1024)
+-
+ /* The maximum heap size we're going to claim */
+ #ifdef __i386__
+ #define HEAP_MAX_SIZE		(unsigned long) (64 * 1024 * 1024)
+@@ -56,14 +53,6 @@
+ #define HEAP_MAX_SIZE		(unsigned long) (32 * 1024 * 1024)
+ #endif
+ 
+-/* If possible, we will avoid claiming heap above this address, because it
+-   seems to cause relocation problems with OSes that link at 4 MiB */
+-#ifdef __i386__
+-#define HEAP_MAX_ADDR		(unsigned long) (64 * 1024 * 1024)
+-#else
+-#define HEAP_MAX_ADDR		(unsigned long) (32 * 1024 * 1024)
+-#endif
+-
+ extern char _end[];
+ 
+ #ifdef __sparc__
+@@ -185,12 +174,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
+   if (*total + len > HEAP_MAX_SIZE)
+     len = HEAP_MAX_SIZE - *total;
+ 
+-  /* Avoid claiming anything above HEAP_MAX_ADDR, if possible. */
+-  if ((addr < HEAP_MAX_ADDR) &&				/* if it's too late, don't bother */
+-      (addr + len > HEAP_MAX_ADDR) &&				/* if it wasn't available anyway, don't bother */
+-      (*total + (HEAP_MAX_ADDR - addr) > HEAP_MIN_SIZE))	/* only limit ourselves when we can afford to */
+-     len = HEAP_MAX_ADDR - addr;
+-
+   /* In theory, firmware should already prevent this from happening by not
+      listing our own image in /memory/available.  The check below is intended
+      as a safeguard in case that doesn't happen.  However, it doesn't protect
diff --git a/SOURCES/0175-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch b/SOURCES/0175-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch
new file mode 100644
index 0000000..5728f26
--- /dev/null
+++ b/SOURCES/0175-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch
@@ -0,0 +1,315 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Sat, 8 May 2021 02:27:58 +0200
+Subject: [PATCH] appendedsig/x509: Also handle the Extended Key Usage
+ extension
+
+Red Hat certificates have both Key Usage and Extended Key Usage extensions
+present, but the appended signatures x509 parser doesn't handle the latter
+and so buils due finding an unrecognised critical extension:
+
+Error loading initial key:
+../../grub-core/commands/appendedsig/x509.c:780:Unhandled critical x509 extension with OID 2.5.29.37
+
+Fix this by also parsing the Extended Key Usage extension and handle it by
+verifying that the certificate has a single purpose, that is code signing.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/commands/appendedsig/x509.c     | 94 ++++++++++++++++++++++++++++++-
+ grub-core/tests/appended_signature_test.c | 29 +++++++++-
+ grub-core/tests/appended_signatures.h     | 81 ++++++++++++++++++++++++++
+ 3 files changed, 201 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c
+index 2b38b3670a..42ec65c54a 100644
+--- a/grub-core/commands/appendedsig/x509.c
++++ b/grub-core/commands/appendedsig/x509.c
+@@ -47,6 +47,12 @@ const char *keyUsage_oid = "2.5.29.15";
+  */
+ const char *basicConstraints_oid = "2.5.29.19";
+ 
++/*
++ * RFC 5280 4.2.1.12 Extended Key Usage
++ */
++const char *extendedKeyUsage_oid = "2.5.29.37";
++const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3";
++
+ /*
+  * RFC 3279 2.3.1
+  *
+@@ -637,6 +643,77 @@ cleanup:
+   return err;
+ }
+ 
++/*
++ * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
++ *
++ * KeyPurposeId ::= OBJECT IDENTIFIER
++ */
++static grub_err_t
++verify_extended_key_usage (grub_uint8_t * value, int value_size)
++{
++  asn1_node extendedasn;
++  int result, count;
++  grub_err_t err = GRUB_ERR_NONE;
++  char usage[MAX_OID_LEN];
++  int usage_size = sizeof (usage);
++
++  result =
++    asn1_create_element (_gnutls_pkix_asn, "PKIX1.ExtKeyUsageSyntax",
++			 &extendedasn);
++  if (result != ASN1_SUCCESS)
++    {
++      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			 "Could not create ASN.1 structure for Extended Key Usage");
++    }
++
++  result = asn1_der_decoding2 (&extendedasn, value, &value_size,
++			       ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
++  if (result != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Error parsing DER for Extended Key Usage: %s",
++		    asn1_error);
++      goto cleanup;
++    }
++
++  /*
++   * If EKUs are present, there must be exactly 1 and it must be a
++   * codeSigning usage.
++   */
++  result = asn1_number_of_elements(extendedasn, "", &count);
++  if (result != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Error counting number of Extended Key Usages: %s",
++		    asn1_strerror (result));
++      goto cleanup;
++    }
++
++  result = asn1_read_value (extendedasn, "?1", usage, &usage_size);
++  if (result != ASN1_SUCCESS)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Error reading Extended Key Usage: %s",
++		    asn1_strerror (result));
++      goto cleanup;
++    }
++
++  if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) != 0)
++    {
++      err =
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "Unexpected Extended Key Usage OID, got: %s",
++		    usage);
++      goto cleanup;
++    }
++
++cleanup:
++  asn1_delete_structure (&extendedasn);
++  return err;
++}
+ 
+ /*
+  * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
+@@ -660,7 +737,7 @@ verify_extensions (asn1_node cert)
+ {
+   int result;
+   int ext, num_extensions = 0;
+-  int usage_present = 0, constraints_present = 0;
++  int usage_present = 0, constraints_present = 0, extended_usage_present = 0;
+   char *oid_path, *critical_path, *value_path;
+   char extnID[MAX_OID_LEN];
+   int extnID_size;
+@@ -754,6 +831,15 @@ verify_extensions (asn1_node cert)
+ 	    }
+ 	  constraints_present++;
+ 	}
++      else if (grub_strncmp (extendedKeyUsage_oid, extnID, extnID_size) == 0)
++	{
++	  err = verify_extended_key_usage (value, value_size);
++	  if (err != GRUB_ERR_NONE)
++	    {
++	      goto cleanup_value;
++	    }
++	  extended_usage_present++;
++	}
+       else if (grub_strncmp ("TRUE", critical, critical_size) == 0)
+ 	{
+ 	  /*
+@@ -785,6 +871,12 @@ verify_extensions (asn1_node cert)
+ 			 "Unexpected number of basic constraints extensions - expected 1, got %d",
+ 			 constraints_present);
+     }
++  if (extended_usage_present > 1)
++    {
++      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			 "Unexpected number of Extended Key Usage extensions - expected 0 or 1, got %d",
++			 extended_usage_present);
++    }
+   return GRUB_ERR_NONE;
+ 
+ cleanup_value:
+diff --git a/grub-core/tests/appended_signature_test.c b/grub-core/tests/appended_signature_test.c
+index 88a485200d..dbba061662 100644
+--- a/grub-core/tests/appended_signature_test.c
++++ b/grub-core/tests/appended_signature_test.c
+@@ -111,6 +111,22 @@ static struct grub_procfs_entry certificate_printable_der_entry = {
+   .get_contents = get_certificate_printable_der
+ };
+ 
++static char *
++get_certificate_eku_der (grub_size_t * sz)
++{
++  char *ret;
++  *sz = certificate_eku_der_len;
++  ret = grub_malloc (*sz);
++  if (ret)
++    grub_memcpy (ret, certificate_eku_der, *sz);
++  return ret;
++}
++
++static struct grub_procfs_entry certificate_eku_der_entry = {
++  .name = "certificate_eku.der",
++  .get_contents = get_certificate_eku_der
++};
++
+ 
+ static void
+ do_verify (const char *f, int is_valid)
+@@ -149,6 +165,7 @@ appended_signature_test (void)
+   char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL };
+   char *trust_args_printable[] = { (char *) "(proc)/certificate_printable.der",
+ 				   NULL };
++  char *trust_args_eku[] = { (char *) "(proc)/certificate_eku.der", NULL };
+   char *distrust_args[] = { (char *) "1", NULL };
+   char *distrust2_args[] = { (char *) "2", NULL };
+   grub_err_t err;
+@@ -157,6 +174,7 @@ appended_signature_test (void)
+   grub_procfs_register ("certificate2.der", &certificate2_der_entry);
+   grub_procfs_register ("certificate_printable.der",
+ 			&certificate_printable_der_entry);
++  grub_procfs_register ("certificate_eku.der", &certificate_eku_der_entry);
+ 
+   cmd_trust = grub_command_find ("trust_certificate");
+   if (!cmd_trust)
+@@ -266,16 +284,23 @@ appended_signature_test (void)
+ 
+   /*
+    * Lastly, check a certificate that uses printableString rather than
+-   * utf8String loads properly.
++   * utf8String loads properly, and that a certificate with an appropriate
++   * extended key usage loads.
+    */
+   err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable);
+   grub_test_assert (err == GRUB_ERR_NONE,
+-		    "distrusting printable certificate failed: %d: %s",
++		    "trusting printable certificate failed: %d: %s",
++		    grub_errno, grub_errmsg);
++
++  err = (cmd_trust->func) (cmd_trust, 1, trust_args_eku);
++  grub_test_assert (err == GRUB_ERR_NONE,
++		    "trusting certificate with extended key usage failed: %d: %s",
+ 		    grub_errno, grub_errmsg);
+ 
+   grub_procfs_unregister (&certificate_der_entry);
+   grub_procfs_unregister (&certificate2_der_entry);
+   grub_procfs_unregister (&certificate_printable_der_entry);
++  grub_procfs_unregister (&certificate_eku_der_entry);
+ }
+ 
+ GRUB_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test);
+diff --git a/grub-core/tests/appended_signatures.h b/grub-core/tests/appended_signatures.h
+index aa3dc6278e..2e5ebd7d8b 100644
+--- a/grub-core/tests/appended_signatures.h
++++ b/grub-core/tests/appended_signatures.h
+@@ -555,3 +555,84 @@ unsigned char certificate_printable_der[] = {
+   0xd2
+ };
+ unsigned int certificate_printable_der_len = 829;
++
++unsigned char certificate_eku_der[] = {
++  0x30, 0x82, 0x03, 0x90, 0x30, 0x82, 0x02, 0x78, 0xa0, 0x03, 0x02, 0x01,
++  0x02, 0x02, 0x09, 0x00, 0xd3, 0x9c, 0x41, 0x33, 0xdd, 0x6b, 0x5f, 0x45,
++  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
++  0x0b, 0x05, 0x00, 0x30, 0x47, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
++  0x04, 0x03, 0x0c, 0x18, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20,
++  0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20,
++  0x43, 0x41, 0x20, 0x36, 0x31, 0x22, 0x30, 0x20, 0x06, 0x09, 0x2a, 0x86,
++  0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x13, 0x73, 0x65, 0x63,
++  0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65, 0x64, 0x68, 0x61, 0x74,
++  0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x32,
++  0x31, 0x35, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a, 0x17, 0x0d, 0x33,
++  0x38, 0x30, 0x31, 0x31, 0x37, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a,
++  0x30, 0x4e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
++  0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63,
++  0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67,
++  0x6e, 0x69, 0x6e, 0x67, 0x20, 0x36, 0x30, 0x32, 0x31, 0x22, 0x30, 0x20,
++  0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
++  0x13, 0x73, 0x65, 0x63, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65,
++  0x64, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22,
++  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
++  0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
++  0x02, 0x82, 0x01, 0x01, 0x00, 0xaa, 0x6f, 0xbb, 0x92, 0x77, 0xd7, 0x15,
++  0xef, 0x88, 0x80, 0x88, 0xc0, 0xe7, 0x89, 0xeb, 0x35, 0x76, 0xf4, 0x85,
++  0x05, 0x0f, 0x19, 0xe4, 0x5f, 0x25, 0xdd, 0xc1, 0xa2, 0xe5, 0x5c, 0x06,
++  0xfb, 0xf1, 0x06, 0xb5, 0x65, 0x45, 0xcb, 0xbd, 0x19, 0x33, 0x54, 0xb5,
++  0x1a, 0xcd, 0xe4, 0xa8, 0x35, 0x2a, 0xfe, 0x9c, 0x53, 0xf4, 0xc6, 0x76,
++  0xdb, 0x1f, 0x8a, 0xd4, 0x7b, 0x18, 0x11, 0xaf, 0xa3, 0x90, 0xd4, 0xdd,
++  0x4d, 0xd5, 0x42, 0xcc, 0x14, 0x9a, 0x64, 0x6b, 0xc0, 0x7f, 0xaa, 0x1c,
++  0x94, 0x47, 0x4d, 0x79, 0xbd, 0x57, 0x9a, 0xbf, 0x99, 0x4e, 0x96, 0xa9,
++  0x31, 0x2c, 0xa9, 0xe7, 0x14, 0x65, 0x86, 0xc8, 0xac, 0x79, 0x5e, 0x78,
++  0xa4, 0x3c, 0x00, 0x24, 0xd3, 0xf7, 0xe1, 0xf5, 0x12, 0xad, 0xa0, 0x29,
++  0xe5, 0xfe, 0x80, 0xae, 0xf8, 0xaa, 0x60, 0x36, 0xe7, 0xe8, 0x94, 0xcb,
++  0xe9, 0xd1, 0xcc, 0x0b, 0x4d, 0xf7, 0xde, 0xeb, 0x52, 0xd2, 0x73, 0x09,
++  0x28, 0xdf, 0x48, 0x99, 0x53, 0x9f, 0xc5, 0x9a, 0xd4, 0x36, 0xa3, 0xc6,
++  0x5e, 0x8d, 0xbe, 0xd5, 0xdc, 0x76, 0xb4, 0x74, 0xb8, 0x26, 0x18, 0x27,
++  0xfb, 0xf2, 0xfb, 0xd0, 0x9b, 0x3d, 0x7f, 0x10, 0xe2, 0xab, 0x44, 0xc7,
++  0x88, 0x7f, 0xb4, 0x3d, 0x3e, 0xa3, 0xff, 0x6d, 0x06, 0x4b, 0x3e, 0x55,
++  0xb2, 0x84, 0xf4, 0xad, 0x54, 0x88, 0x81, 0xc3, 0x9c, 0xf8, 0xb6, 0x68,
++  0x96, 0x38, 0x8b, 0xcd, 0x90, 0x6d, 0x25, 0x4b, 0xbf, 0x0c, 0x44, 0x90,
++  0xa5, 0x5b, 0x98, 0xd0, 0x40, 0x2f, 0xbb, 0x0d, 0xa8, 0x4b, 0x8a, 0x62,
++  0x82, 0x46, 0x46, 0x18, 0x38, 0xae, 0x82, 0x07, 0xd0, 0xb4, 0x2f, 0x16,
++  0x79, 0x55, 0x9f, 0x1b, 0xc5, 0x08, 0x6d, 0x85, 0xdf, 0x3f, 0xa9, 0x9b,
++  0x4b, 0xc6, 0x28, 0xd3, 0x58, 0x72, 0x3d, 0x37, 0x11, 0x02, 0x03, 0x01,
++  0x00, 0x01, 0xa3, 0x78, 0x30, 0x76, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d,
++  0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03,
++  0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80,
++  0x30, 0x16, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 0x0c,
++  0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03,
++  0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x6c,
++  0xe4, 0x6c, 0x27, 0xaa, 0xcd, 0x0d, 0x4b, 0x74, 0x21, 0xa4, 0xf6, 0x5f,
++  0x87, 0xb5, 0x31, 0xfe, 0x10, 0xbb, 0xa7, 0x30, 0x1f, 0x06, 0x03, 0x55,
++  0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe8, 0x6a, 0x1c, 0xab,
++  0x2c, 0x48, 0xf9, 0x60, 0x36, 0xa2, 0xf0, 0x7b, 0x8e, 0xd2, 0x9d, 0xb4,
++  0x2a, 0x28, 0x98, 0xc8, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
++  0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
++  0x55, 0x34, 0xe2, 0xfa, 0xf6, 0x89, 0x86, 0xad, 0x92, 0x21, 0xec, 0xb9,
++  0x54, 0x0e, 0x18, 0x47, 0x0d, 0x1b, 0xa7, 0x58, 0xad, 0x69, 0xe4, 0xef,
++  0x3b, 0xe6, 0x8d, 0xdd, 0xda, 0x0c, 0x45, 0xf6, 0xe8, 0x96, 0xa4, 0x29,
++  0x0f, 0xbb, 0xcf, 0x16, 0xae, 0x93, 0xd0, 0xcb, 0x2a, 0x26, 0x1a, 0x7b,
++  0xfc, 0x51, 0x22, 0x76, 0x98, 0x31, 0xa7, 0x0f, 0x29, 0x35, 0x79, 0xbf,
++  0xe2, 0x4f, 0x0f, 0x14, 0xf5, 0x1f, 0xcb, 0xbf, 0x87, 0x65, 0x13, 0x32,
++  0xa3, 0x19, 0x4a, 0xd1, 0x3f, 0x45, 0xd4, 0x4b, 0xe2, 0x00, 0x26, 0xa9,
++  0x3e, 0xd7, 0xa5, 0x37, 0x9f, 0xf5, 0xad, 0x61, 0xe2, 0x40, 0xa9, 0x74,
++  0x24, 0x53, 0xf2, 0x78, 0xeb, 0x10, 0x9b, 0x2c, 0x27, 0x88, 0x46, 0xcb,
++  0xe4, 0x60, 0xca, 0xf5, 0x06, 0x24, 0x40, 0x2a, 0x97, 0x3a, 0xcc, 0xd0,
++  0x81, 0xb1, 0x15, 0xa3, 0x4f, 0xd0, 0x2b, 0x4f, 0xca, 0x6e, 0xaa, 0x24,
++  0x31, 0xb3, 0xac, 0xa6, 0x75, 0x05, 0xfe, 0x8a, 0xf4, 0x41, 0xc4, 0x06,
++  0x8a, 0xc7, 0x0a, 0x83, 0x4e, 0x49, 0xd4, 0x3f, 0x83, 0x50, 0xec, 0x57,
++  0x04, 0x97, 0x14, 0x49, 0xf5, 0xe1, 0xb1, 0x7a, 0x9c, 0x09, 0x4f, 0x61,
++  0x87, 0xc3, 0x97, 0x22, 0x17, 0xc2, 0xeb, 0xcc, 0x32, 0x81, 0x31, 0x21,
++  0x3f, 0x10, 0x57, 0x5b, 0x43, 0xbe, 0xcd, 0x68, 0x82, 0xbe, 0xe5, 0xc1,
++  0x65, 0x94, 0x7e, 0xc2, 0x34, 0x76, 0x2b, 0xcf, 0x89, 0x3c, 0x2b, 0x81,
++  0x23, 0x72, 0x95, 0xcf, 0xc9, 0x67, 0x19, 0x2a, 0xd5, 0x5c, 0xca, 0xa3,
++  0x46, 0xbd, 0x48, 0x06, 0x0b, 0xa6, 0xa3, 0x96, 0x50, 0x28, 0xc7, 0x7e,
++  0xcf, 0x62, 0xf2, 0xfa, 0xc4, 0xf2, 0x53, 0xe3, 0xc9, 0xe8, 0x2e, 0xdd,
++  0x29, 0x37, 0x07, 0x47, 0xff, 0xff, 0x8a, 0x32, 0xbd, 0xa2, 0xb7, 0x21,
++  0x89, 0xa0, 0x55, 0xf7
++};
++unsigned int certificate_eku_der_len = 916;
diff --git a/SOURCES/0175-ieee1275-Avoiding-many-unecessary-open-close.patch b/SOURCES/0175-ieee1275-Avoiding-many-unecessary-open-close.patch
deleted file mode 100644
index 6a0ad75..0000000
--- a/SOURCES/0175-ieee1275-Avoiding-many-unecessary-open-close.patch
+++ /dev/null
@@ -1,136 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Diego Domingos <diegodo@br.ibm.com>
-Date: Mon, 14 Dec 2020 17:42:45 +0100
-Subject: [PATCH] ieee1275: Avoiding many unecessary open/close
-
-Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
----
- grub-core/disk/ieee1275/ofdisk.c | 64 ++++++++++++++++++++++------------------
- 1 file changed, 35 insertions(+), 29 deletions(-)
-
-diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c
-index 03674cb477e..ea7f78ac7d8 100644
---- a/grub-core/disk/ieee1275/ofdisk.c
-+++ b/grub-core/disk/ieee1275/ofdisk.c
-@@ -44,7 +44,7 @@ struct ofdisk_hash_ent
- };
- 
- static grub_err_t
--grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size,
-+grub_ofdisk_get_block_size (grub_uint32_t *block_size,
- 			    struct ofdisk_hash_ent *op);
- 
- #define OFDISK_HASH_SZ	8
-@@ -461,6 +461,7 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
-   grub_ssize_t actual;
-   grub_uint32_t block_size = 0;
-   grub_err_t err;
-+  struct ofdisk_hash_ent *op;
- 
-   if (grub_strncmp (name, "ieee1275/", sizeof ("ieee1275/") - 1) != 0)
-       return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
-@@ -471,6 +472,35 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
- 
-   grub_dprintf ("disk", "Opening `%s'.\n", devpath);
- 
-+  op = ofdisk_hash_find (devpath);
-+  if (!op)
-+    op = ofdisk_hash_add (devpath, NULL);
-+  if (!op)
-+    {
-+      grub_free (devpath);
-+      return grub_errno;
-+    }
-+
-+  /* Check if the call to open is the same to the last disk already opened */
-+  if (last_devpath && !grub_strcmp(op->open_path,last_devpath))
-+  {
-+      goto finish;
-+  }
-+
-+ /* If not, we need to close the previous disk and open the new one */
-+  else {
-+    if (last_ihandle){
-+        grub_ieee1275_close (last_ihandle);
-+    }
-+    last_ihandle = 0;
-+    last_devpath = NULL;
-+
-+    grub_ieee1275_open (op->open_path, &last_ihandle);
-+    if (! last_ihandle)
-+      return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
-+    last_devpath = op->open_path;
-+  }
-+
-   if (grub_ieee1275_finddevice (devpath, &dev))
-     {
-       grub_free (devpath);
-@@ -491,25 +521,18 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
-       return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a block device");
-     }
- 
-+
-+  finish:
-   /* XXX: There is no property to read the number of blocks.  There
-      should be a property `#blocks', but it is not there.  Perhaps it
-      is possible to use seek for this.  */
-   disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN;
- 
-   {
--    struct ofdisk_hash_ent *op;
--    op = ofdisk_hash_find (devpath);
--    if (!op)
--      op = ofdisk_hash_add (devpath, NULL);
--    if (!op)
--      {
--        grub_free (devpath);
--        return grub_errno;
--      }
-     disk->id = (unsigned long) op;
-     disk->data = op->open_path;
- 
--    err = grub_ofdisk_get_block_size (devpath, &block_size, op);
-+    err = grub_ofdisk_get_block_size (&block_size, op);
-     if (err)
-       {
-         grub_free (devpath);
-@@ -532,13 +555,6 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
- static void
- grub_ofdisk_close (grub_disk_t disk)
- {
--  if (disk->data == last_devpath)
--    {
--      if (last_ihandle)
--	grub_ieee1275_close (last_ihandle);
--      last_ihandle = 0;
--      last_devpath = NULL;
--    }
-   disk->data = 0;
- }
- 
-@@ -685,7 +701,7 @@ grub_ofdisk_init (void)
- }
- 
- static grub_err_t
--grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size,
-+grub_ofdisk_get_block_size (grub_uint32_t *block_size,
- 			    struct ofdisk_hash_ent *op)
- {
-   struct size_args_ieee1275
-@@ -698,16 +714,6 @@ grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size,
-       grub_ieee1275_cell_t size2;
-     } args_ieee1275;
- 
--  if (last_ihandle)
--    grub_ieee1275_close (last_ihandle);
--
--  last_ihandle = 0;
--  last_devpath = NULL;
--
--  grub_ieee1275_open (device, &last_ihandle);
--  if (! last_ihandle)
--    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
--
-   *block_size = 0;
- 
-   if (op->block_size_fails >= 2)
diff --git a/SOURCES/0176-ieee1275-ofdisk-retry-on-open-failure.patch b/SOURCES/0176-ieee1275-ofdisk-retry-on-open-failure.patch
new file mode 100644
index 0000000..9149773
--- /dev/null
+++ b/SOURCES/0176-ieee1275-ofdisk-retry-on-open-failure.patch
@@ -0,0 +1,103 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Diego Domingos <diegodo@br.ibm.com>
+Date: Wed, 10 Mar 2021 14:17:52 -0500
+Subject: [PATCH] ieee1275/ofdisk: retry on open failure
+
+This patch aims to make grub more robust when booting from SAN/Multipath disks.
+
+If a path is failing intermittently so grub will retry the OPEN and READ the
+disk (grub_ieee1275_open and grub_ieee1275_read) until the total amount of times
+specified in MAX_RETRIES.
+
+Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
+---
+ grub-core/disk/ieee1275/ofdisk.c | 25 ++++++++++++++++++++-----
+ include/grub/ieee1275/ofdisk.h   |  8 ++++++++
+ 2 files changed, 28 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c
+index ea7f78ac7d..55346849d3 100644
+--- a/grub-core/disk/ieee1275/ofdisk.c
++++ b/grub-core/disk/ieee1275/ofdisk.c
+@@ -225,7 +225,9 @@ dev_iterate (const struct grub_ieee1275_devalias *alias)
+       char *buf, *bufptr;
+       unsigned i;
+ 
+-      if (grub_ieee1275_open (alias->path, &ihandle))
++
++      RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle)
++      if (! ihandle)
+ 	return;
+ 
+       /* This method doesn't need memory allocation for the table. Open
+@@ -305,7 +307,9 @@ dev_iterate (const struct grub_ieee1275_devalias *alias)
+           return;
+         }
+ 
+-      if (grub_ieee1275_open (alias->path, &ihandle))
++      RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle);
++
++      if (! ihandle)
+         {
+           grub_free (buf);
+           grub_free (table);
+@@ -495,7 +499,7 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
+     last_ihandle = 0;
+     last_devpath = NULL;
+ 
+-    grub_ieee1275_open (op->open_path, &last_ihandle);
++    RETRY_IEEE1275_OFDISK_OPEN(op->open_path, &last_ihandle);
+     if (! last_ihandle)
+       return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
+     last_devpath = op->open_path;
+@@ -571,7 +575,7 @@ grub_ofdisk_prepare (grub_disk_t disk, grub_disk_addr_t sector)
+       last_ihandle = 0;
+       last_devpath = NULL;
+ 
+-      grub_ieee1275_open (disk->data, &last_ihandle);
++      RETRY_IEEE1275_OFDISK_OPEN(disk->data, &last_ihandle);
+       if (! last_ihandle)
+ 	return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
+       last_devpath = disk->data;      
+@@ -598,12 +602,23 @@ grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
+     return err;
+   grub_ieee1275_read (last_ihandle, buf, size  << disk->log_sector_size,
+ 		      &actual);
+-  if (actual != (grub_ssize_t) (size  << disk->log_sector_size))
++  int i = 0;
++  while(actual != (grub_ssize_t) (size  << disk->log_sector_size)){
++    if (i>MAX_RETRIES){
+     return grub_error (GRUB_ERR_READ_ERROR, N_("failure reading sector 0x%llx "
+ 					       "from `%s'"),
+ 		       (unsigned long long) sector,
+ 		       disk->name);
++    }
++    last_devpath = NULL;
++    err = grub_ofdisk_prepare (disk, sector);
++    if (err)
++      return err;
+ 
++    grub_ieee1275_read (last_ihandle, buf, size  << disk->log_sector_size,
++                      &actual);
++    i++;
++  }
+   return 0;
+ }
+ 
+diff --git a/include/grub/ieee1275/ofdisk.h b/include/grub/ieee1275/ofdisk.h
+index 2f69e3f191..7d2d540930 100644
+--- a/include/grub/ieee1275/ofdisk.h
++++ b/include/grub/ieee1275/ofdisk.h
+@@ -22,4 +22,12 @@
+ extern void grub_ofdisk_init (void);
+ extern void grub_ofdisk_fini (void);
+ 
++#define MAX_RETRIES 20
++
++
++#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) unsigned retry_i=0;for(retry_i=0; retry_i < MAX_RETRIES; retry_i++){ \
++						if(!grub_ieee1275_open(device, last_ihandle)) \
++						break; \
++						grub_dprintf("ofdisk","Opening disk %s failed. Retrying...\n",device); }
++
+ #endif /* ! GRUB_INIT_HEADER */
diff --git a/SOURCES/0176-ieee1275-powerpc-implements-fibre-channel-discovery-.patch b/SOURCES/0176-ieee1275-powerpc-implements-fibre-channel-discovery-.patch
deleted file mode 100644
index 9fa02bb..0000000
--- a/SOURCES/0176-ieee1275-powerpc-implements-fibre-channel-discovery-.patch
+++ /dev/null
@@ -1,90 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Diego Domingos <diegodo@br.ibm.com>
-Date: Mon, 14 Dec 2020 17:45:28 +0100
-Subject: [PATCH] ieee1275/powerpc: implements fibre channel discovery for
- ofpathname
-
-grub-ofpathname doesn't work with fibre channel because there is no
-function currently implemented for it.
-This patch enables it by prividing a function that looks for the port
-name, building the entire path for OF devices.
-
-Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
----
- grub-core/osdep/linux/ofpath.c | 49 ++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 49 insertions(+)
-
-diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c
-index a6153d35954..0f5d54e9f2d 100644
---- a/grub-core/osdep/linux/ofpath.c
-+++ b/grub-core/osdep/linux/ofpath.c
-@@ -350,6 +350,38 @@ of_path_of_ide(const char *sys_devname __attribute__((unused)), const char *devi
-   return ret;
- }
- 
-+
-+static void
-+of_fc_port_name(const char *path, const char *subpath, char *port_name)
-+{
-+  char *bname, *basepath, *p;
-+  int fd;
-+
-+  bname = xmalloc(sizeof(char)*150);
-+  basepath = xmalloc(strlen(path));
-+
-+  /* Generate the path to get port name information from the drive */
-+  strncpy(basepath,path,subpath-path);
-+  basepath[subpath-path-1] = '\0';
-+  p = get_basename(basepath);
-+  snprintf(bname,sizeof(char)*150,"%s/fc_transport/%s/port_name",basepath,p);
-+
-+  /* Read the information from the port name */
-+  fd = open (bname, O_RDONLY);
-+  if (fd < 0)
-+    grub_util_error (_("cannot open `%s': %s"), bname, strerror (errno));
-+
-+  if (read(fd,port_name,sizeof(char)*19) < 0)
-+    grub_util_error (_("cannot read `%s': %s"), bname, strerror (errno));
-+
-+  sscanf(port_name,"0x%s",port_name);
-+  
-+  close(fd);
-+
-+  free(bname);
-+  free(basepath);
-+}
-+
- #ifdef __sparc__
- static char *
- of_path_of_nvme(const char *sys_devname __attribute__((unused)),
-@@ -577,6 +609,16 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
-   digit_string = trailing_digits (device);
-   if (strncmp (of_path, "/vdevice/", sizeof ("/vdevice/") - 1) == 0)
-     {
-+      if(strstr(of_path,"vfc-client"))
-+      {
-+	char * port_name = xmalloc(sizeof(char)*17);
-+	of_fc_port_name(sysfs_path, p, port_name);
-+	
-+	snprintf(disk,sizeof(disk),"/%s@%s", disk_name, port_name);
-+	free(port_name);
-+      }
-+      else
-+      {
-       unsigned long id = 0x8000 | (tgt << 8) | (bus << 5) | lun;
-       if (*digit_string == '\0')
- 	{
-@@ -590,6 +632,13 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
- 	  snprintf(disk, sizeof (disk),
- 		   "/%s@%04lx000000000000:%c", disk_name, id, 'a' + (part - 1));
- 	}
-+	}
-+    } else if (strstr(of_path,"fibre-channel")||(strstr(of_path,"vfc-client"))){
-+	char * port_name = xmalloc(sizeof(char)*17);
-+	of_fc_port_name(sysfs_path, p, port_name);
-+	
-+	snprintf(disk,sizeof(disk),"/%s@%s", disk_name, port_name);
-+	free(port_name);
-     }
-   else
-     {
diff --git a/SOURCES/0177-Allow-chainloading-EFI-apps-from-loop-mounts.patch b/SOURCES/0177-Allow-chainloading-EFI-apps-from-loop-mounts.patch
new file mode 100644
index 0000000..c3101e1
--- /dev/null
+++ b/SOURCES/0177-Allow-chainloading-EFI-apps-from-loop-mounts.patch
@@ -0,0 +1,138 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dimitri John Ledkov <xnox@ubuntu.com>
+Date: Fri, 11 Jun 2021 13:51:20 +0200
+Subject: [PATCH] Allow chainloading EFI apps from loop mounts.
+
+Signed-off-by: Dimitri John Ledkov <Dimitri.ledkov@canonical.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/disk/loopback.c          |  9 +--------
+ grub-core/loader/efi/chainloader.c | 23 +++++++++++++++++++++++
+ include/grub/loopback.h            | 30 ++++++++++++++++++++++++++++++
+ 3 files changed, 54 insertions(+), 8 deletions(-)
+ create mode 100644 include/grub/loopback.h
+
+diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c
+index 41bebd14fe..99f47924ec 100644
+--- a/grub-core/disk/loopback.c
++++ b/grub-core/disk/loopback.c
+@@ -21,20 +21,13 @@
+ #include <grub/misc.h>
+ #include <grub/file.h>
+ #include <grub/disk.h>
++#include <grub/loopback.h>
+ #include <grub/mm.h>
+ #include <grub/extcmd.h>
+ #include <grub/i18n.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+-struct grub_loopback
+-{
+-  char *devname;
+-  grub_file_t file;
+-  struct grub_loopback *next;
+-  unsigned long id;
+-};
+-
+ static struct grub_loopback *loopback_list;
+ static unsigned long last_id = 0;
+ 
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index d41e8ea14a..3af6b12292 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -24,6 +24,7 @@
+ #include <grub/err.h>
+ #include <grub/device.h>
+ #include <grub/disk.h>
++#include <grub/loopback.h>
+ #include <grub/misc.h>
+ #include <grub/charset.h>
+ #include <grub/mm.h>
+@@ -901,6 +902,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+   grub_efi_status_t status;
+   grub_efi_boot_services_t *b;
+   grub_device_t dev = 0;
++  grub_device_t orig_dev = 0;
+   grub_efi_device_path_t *dp = 0;
+   char *filename;
+   void *boot_image = 0;
+@@ -958,6 +960,15 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+   if (! dev)
+     goto fail;
+ 
++  /* if device is loopback, use underlying dev */
++  if (dev->disk->dev->id == GRUB_DISK_DEVICE_LOOPBACK_ID)
++    {
++      struct grub_loopback *d;
++      orig_dev = dev;
++      d = dev->disk->data;
++      dev = d->file->device;
++    }
++
+   if (dev->disk)
+     dev_handle = grub_efidisk_get_device_handle (dev->disk);
+   else if (dev->net && dev->net->server)
+@@ -1065,6 +1076,12 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+     }
+ #endif
+ 
++  if (orig_dev)
++    {
++      dev = orig_dev;
++      orig_dev = 0;
++    }
++
+   rc = grub_linuxefi_secure_validate((void *)(unsigned long)address, fsize);
+   grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc);
+   if (rc > 0)
+@@ -1087,6 +1104,12 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+   // -1 fall-through to fail
+ 
+ fail:
++  if (orig_dev)
++    {
++      dev = orig_dev;
++      orig_dev = 0;
++    }
++
+   if (dev)
+     grub_device_close (dev);
+ 
+diff --git a/include/grub/loopback.h b/include/grub/loopback.h
+new file mode 100644
+index 0000000000..3b9a9e32e8
+--- /dev/null
++++ b/include/grub/loopback.h
+@@ -0,0 +1,30 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2019  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/>.
++ */
++
++#ifndef GRUB_LOOPBACK_HEADER
++#define GRUB_LOOPBACK_HEADER	1
++
++struct grub_loopback
++{
++  char *devname;
++  grub_file_t file;
++  struct grub_loopback *next;
++  unsigned long id;
++};
++
++#endif /* ! GRUB_LOOPBACK_HEADER */
diff --git a/SOURCES/0177-ieee1275-powerpc-enables-device-mapper-discovery.patch b/SOURCES/0177-ieee1275-powerpc-enables-device-mapper-discovery.patch
deleted file mode 100644
index 6f1c21b..0000000
--- a/SOURCES/0177-ieee1275-powerpc-enables-device-mapper-discovery.patch
+++ /dev/null
@@ -1,106 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Diego Domingos <diegodo@br.ibm.com>
-Date: Mon, 14 Dec 2020 17:47:16 +0100
-Subject: [PATCH] ieee1275/powerpc: enables device mapper discovery
-
-this patch enables the device mapper discovery on ofpath.c. Currently,
-when we are dealing with a device like /dev/dm-* the ofpath returns null
-since there is no function implemented to handle this case.
-
-This patch implements a function that will look into /sys/block/dm-*
-devices and search recursively inside slaves directory to find the root
-disk.
-
-Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
----
- grub-core/osdep/linux/ofpath.c | 64 +++++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 63 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c
-index 0f5d54e9f2d..cc849d9c94c 100644
---- a/grub-core/osdep/linux/ofpath.c
-+++ b/grub-core/osdep/linux/ofpath.c
-@@ -37,6 +37,7 @@
- #include <fcntl.h>
- #include <errno.h>
- #include <ctype.h>
-+#include <dirent.h>
- 
- #ifdef __sparc__
- typedef enum
-@@ -755,13 +756,74 @@ strip_trailing_digits (const char *p)
-   return new;
- }
- 
-+static char *
-+get_slave_from_dm(const char * device){
-+  char *curr_device, *tmp;
-+  char *directory;
-+  char *ret = NULL;
-+
-+  directory = grub_strdup (device);
-+  tmp = get_basename(directory);
-+  curr_device = grub_strdup (tmp);
-+  *tmp = '\0';
-+
-+  /* Recursively check for slaves devices so we can find the root device */
-+  while ((curr_device[0] == 'd') && (curr_device[1] == 'm') && (curr_device[2] == '-')){
-+    DIR *dp;
-+    struct dirent *ep;
-+    char* device_path;
-+
-+    device_path = grub_xasprintf ("/sys/block/%s/slaves", curr_device);
-+    dp = opendir(device_path);
-+    free(device_path);
-+
-+    if (dp != NULL)
-+    {
-+      ep = readdir (dp);
-+      while (ep != NULL){
-+
-+	/* avoid some system directories */
-+        if (!strcmp(ep->d_name,"."))
-+            goto next_dir;
-+        if (!strcmp(ep->d_name,".."))
-+            goto next_dir;
-+
-+	free (curr_device);
-+	free (ret);
-+	curr_device = grub_strdup (ep->d_name);
-+	ret = grub_xasprintf ("%s%s", directory, curr_device);
-+	break;
-+
-+        next_dir:
-+         ep = readdir (dp);
-+         continue;
-+      }
-+      closedir (dp);
-+    }
-+    else
-+      grub_util_warn (_("cannot open directory `%s'"), device_path);
-+  }
-+
-+  free (directory);
-+  free (curr_device);
-+
-+  return ret;
-+}
-+
- char *
- grub_util_devname_to_ofpath (const char *sys_devname)
- {
--  char *name_buf, *device, *devnode, *devicenode, *ofpath;
-+  char *name_buf, *device, *devnode, *devicenode, *ofpath, *realname;
- 
-   name_buf = xrealpath (sys_devname);
- 
-+  realname = get_slave_from_dm (name_buf);
-+  if (realname)
-+    {
-+      free (name_buf);
-+      name_buf = realname;
-+    }
-+
-   device = get_basename (name_buf);
-   devnode = strip_trailing_digits (name_buf);
-   devicenode = strip_trailing_digits (device);
diff --git a/SOURCES/0178-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch b/SOURCES/0178-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch
deleted file mode 100644
index 968a9c1..0000000
--- a/SOURCES/0178-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch
+++ /dev/null
@@ -1,239 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
-Date: Fri, 18 Dec 2020 15:39:26 +0100
-Subject: [PATCH] Add 'at_keyboard_fallback_set' var to force the set manually
-
-This seems required with HP DL380p Gen 8 systems.
-Indeed, with this system, we can see the following sequence:
-
-1. controller is queried to get current configuration (returns 0x30 which is quite standard)
-2. controller is queried to get the current keyboard set in used, using code 0xf0 (first part)
-3. controller answers with 0xfa which means "ACK" (== ok)
-4. then we send "0" to tell "we want to know which set your are supporting"
-5. controller answers with 0xfa ("ACK")
-6. controller should then give us 1, 2, 3 or 0x43, 0x41, 0x3f, but here it gives us 0xfe which means "NACK"
-
-Since there seems no way to determine the current set, and in fact the
-controller expects set2 to be used, we need to rely on an environment
-variable.
-Everything has been tested on this system: using 0xFE (resend command),
-making sure we wait for ACK in the 2 steps "write_mode", etc.
-
-Below is litterature I used to come up with "there is no other
-solution":
-- https://wiki.osdev.org/%228042%22_PS/2_Controller
-- http://www-ug.eecg.toronto.edu/msl/nios_devices/datasheets/PS2%20Keyboard%20Protocol.htm
-- http://www.s100computers.com/My%20System%20Pages/MSDOS%20Board/PC%20Keyboard.pdf
----
- grub-core/term/at_keyboard.c | 121 ++++++++++++++++++++++++++++++++++---------
- 1 file changed, 96 insertions(+), 25 deletions(-)
-
-diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c
-index 26014382608..dac0f946fe6 100644
---- a/grub-core/term/at_keyboard.c
-+++ b/grub-core/term/at_keyboard.c
-@@ -31,6 +31,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
- static grub_uint8_t grub_keyboard_controller_orig;
- static grub_uint8_t grub_keyboard_orig_set;
- struct grub_ps2_state ps2_state;
-+static int fallback_set;
- 
- static int ping_sent;
- 
-@@ -76,6 +77,8 @@ at_command (grub_uint8_t data)
- 	break;
-       return 0;
-     }
-+  if (i == GRUB_AT_TRIES)
-+    grub_dprintf ("atkeyb", "at_command() timed out! (stopped after %d tries)\n", i);
-   return (i != GRUB_AT_TRIES);
- }
- 
-@@ -105,6 +108,21 @@ grub_keyboard_controller_read (void)
- 
- #endif
- 
-+static int
-+resend_last_result (void)
-+{
-+  grub_uint8_t ret;
-+  keyboard_controller_wait_until_ready ();
-+  grub_dprintf ("atkeyb", "resend_last_result: sending 0xfe\n");
-+  grub_outb (0xfe, KEYBOARD_REG_DATA);
-+  ret = wait_ack ();
-+  grub_dprintf ("atkeyb", "resend_last_result: wait_ack() returned 0x%x\n", ret);
-+  keyboard_controller_wait_until_ready ();
-+  ret = grub_inb (KEYBOARD_REG_DATA);
-+  grub_dprintf ("atkeyb", "resend_last_result: read 0x%x from controller\n", ret);
-+  return ret;
-+}
-+
- static int
- write_mode (int mode)
- {
-@@ -113,11 +131,14 @@ write_mode (int mode)
-     {
-       grub_uint8_t ack;
-       keyboard_controller_wait_until_ready ();
-+      grub_dprintf ("atkeyb", "write_mode: sending 0xf0\n");
-       grub_outb (0xf0, KEYBOARD_REG_DATA);
-       keyboard_controller_wait_until_ready ();
-+      grub_dprintf ("atkeyb", "write_mode: sending mode %d\n", mode);
-       grub_outb (mode, KEYBOARD_REG_DATA);
-       keyboard_controller_wait_until_ready ();
-       ack = wait_ack ();
-+      grub_dprintf ("atkeyb", "write_mode: wait_ack() returned 0x%x\n", ack);
-       if (ack == GRUB_AT_NACK)
- 	continue;
-       if (ack == GRUB_AT_ACK)
-@@ -125,6 +146,9 @@ write_mode (int mode)
-       return 0;
-     }
- 
-+  if (i == GRUB_AT_TRIES)
-+    grub_dprintf ("atkeyb", "write_mode() timed out! (stopped after %d tries)\n", i);
-+
-   return (i != GRUB_AT_TRIES);
- }
- 
-@@ -132,31 +156,66 @@ static int
- query_mode (void)
- {
-   grub_uint8_t ret;
-+  grub_uint64_t endtime;
-+  unsigned i;
-   int e;
-+  char *envvar;
- 
--  e = write_mode (0);
--  if (!e) {
--    grub_dprintf("atkeyb", "query_mode: write_mode(0) failed\n");
--    return 0;
--  }
-+  for (i = 0; i < GRUB_AT_TRIES; i++) {
-+    grub_dprintf ("atkeyb", "query_mode: sending command to controller\n");
-+    e = write_mode (0);
-+    if (!e) {
-+      grub_dprintf ("atkeyb", "query_mode: write_mode(0) failed\n");
-+      return 0;
-+    }
- 
--  do {
--    keyboard_controller_wait_until_ready ();
--    ret = grub_inb (KEYBOARD_REG_DATA);
--  } while (ret == GRUB_AT_ACK);
--  /* QEMU translates the set even in no-translate mode.  */
--  if (ret == 0x43 || ret == 1) {
--    grub_dprintf("atkeyb", "query_mode: returning 1 (ret=0x%x)\n", ret);
--    return 1;
--  }
--  if (ret == 0x41 || ret == 2) {
--    grub_dprintf("atkeyb", "query_mode: returning 2 (ret=0x%x)\n", ret);
--    return 2;
-+    endtime = grub_get_time_ms () + 20;
-+    do {
-+      keyboard_controller_wait_until_ready ();
-+      ret = grub_inb (KEYBOARD_REG_DATA);
-+      grub_dprintf ("atkeyb", "query_mode/loop: read 0x%x from controller\n", ret);
-+    } while ((ret == GRUB_AT_ACK || ret == GRUB_AT_NACK) && grub_get_time_ms () < endtime);
-+    if (ret == 0xfe) {
-+      grub_dprintf ("atkeyb", "query_mode: asking controller to resend last result\n");
-+      ret = resend_last_result();
-+      grub_dprintf ("atkeyb", "query_mode: read 0x%x from controller\n", ret);
-+    }
-+    /* QEMU translates the set even in no-translate mode.  */
-+    if (ret == 0x43 || ret == 1) {
-+      grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 1\n", ret);
-+      return 1;
-+    }
-+    if (ret == 0x41 || ret == 2) {
-+      grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 2\n", ret);
-+      return 2;
-+    }
-+    if (ret == 0x3f || ret == 3) {
-+      grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 3\n", ret);
-+      return 3;
-+    }
-+    grub_dprintf ("atkeyb", "query_mode: controller returned unexpected value 0x%x, retrying\n", ret);
-   }
--  if (ret == 0x3f || ret == 3) {
--    grub_dprintf("atkeyb", "query_mode: returning 3 (ret=0x%x)\n", ret);
--    return 3;
-+
-+  /*
-+   * Falling here means we tried querying and the controller returned something
-+   * we don't understand, try to use 'at_keyboard_fallback_set' if it exists,
-+   * otherwise return 0.
-+   */
-+  envvar = grub_env_get ("at_keyboard_fallback_set");
-+  if (envvar) {
-+    fallback_set = grub_strtoul (envvar, 0, 10);
-+    if ((grub_errno) || (fallback_set < 1) || (fallback_set > 3)) {
-+      grub_dprintf ("atkeyb", "WARNING: ignoring unexpected value '%s' for '%s' variable\n",
-+		    envvar, "at_keyboard_fallback_set");
-+      fallback_set = 0;
-+    } else {
-+      grub_dprintf ("atkeyb", "query_mode: '%s' specified in environment, returning %d\n",
-+		    "at_keyboard_fallback_set", fallback_set);
-+    }
-+    return fallback_set;
-   }
-+  grub_dprintf ("atkeyb", "WARNING: no '%s' specified in environment, returning 0\n",
-+		"at_keyboard_fallback_set");
-   return 0;
- }
- 
-@@ -165,14 +224,25 @@ set_scancodes (void)
- {
-   /* You must have visited computer museum. Keyboard without scancode set
-      knowledge. Assume XT. */
--  if (!grub_keyboard_orig_set)
--    {
--      grub_dprintf ("atkeyb", "No sets support assumed\n");
--      ps2_state.current_set = 1;
-+  if (!grub_keyboard_orig_set) {
-+    if (fallback_set) {
-+      grub_dprintf ("atkeyb", "No sets support assumed but set forced to %d\n", fallback_set);
-+      ps2_state.current_set = fallback_set;
-       return;
-     }
-+    grub_dprintf ("atkeyb", "No sets support assumed, forcing to set 1\n");
-+    ps2_state.current_set = 1;
-+    return;
-+  }
- 
- #if !USE_SCANCODE_SET
-+  if (fallback_set) {
-+    grub_dprintf ("atkeyb", "queried set is %d but set forced to %d\n",
-+		  grub_keyboard_orig_set, fallback_set);
-+    ps2_state.current_set = fallback_set;
-+    return;
-+  }
-+
-   if ((grub_keyboard_controller_orig & KEYBOARD_AT_TRANSLATE) == KEYBOARD_AT_TRANSLATE) {
-     grub_dprintf ("atkeyb", "queried set is %d but keyboard in Translate mode, so actually in set 1\n", grub_keyboard_orig_set);
-     ps2_state.current_set = 1;
-@@ -261,6 +331,7 @@ grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused)))
- static void
- grub_keyboard_controller_init (void)
- {
-+  grub_dprintf ("atkeyb", "initializing the controller\n");
-   ps2_state.at_keyboard_status = 0;
-   /* Drain input buffer. */
-   while (1)
-@@ -282,6 +353,7 @@ grub_keyboard_controller_init (void)
-   grub_keyboard_controller_orig = grub_keyboard_controller_read ();
-   grub_dprintf ("atkeyb", "grub_keyboard_controller_orig = 0x%x\n", grub_keyboard_controller_orig);
-   grub_keyboard_orig_set = query_mode ();
-+  grub_dprintf ("atkeyb", "grub_keyboard_orig_set = %d\n", grub_keyboard_orig_set);
- #endif
-   set_scancodes ();
-   keyboard_controller_led (ps2_state.led_status);
-@@ -329,7 +401,6 @@ grub_at_restore_hw (void)
-   return GRUB_ERR_NONE;
- }
- 
--
- static struct grub_term_input grub_at_keyboard_term =
-   {
-     .name = "at_keyboard",
diff --git a/SOURCES/0178-efinet-Add-DHCP-proxy-support.patch b/SOURCES/0178-efinet-Add-DHCP-proxy-support.patch
new file mode 100644
index 0000000..eed2dbb
--- /dev/null
+++ b/SOURCES/0178-efinet-Add-DHCP-proxy-support.patch
@@ -0,0 +1,53 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ian Page Hands <iphands@gmail.com>
+Date: Tue, 8 Jun 2021 13:48:56 -0400
+Subject: [PATCH] efinet: Add DHCP proxy support
+
+If a proxyDHCP configuration is used, the server name, server IP and boot
+file values should be taken from the DHCP proxy offer instead of the DHCP
+server ack packet. Currently that case is not handled, add support for it.
+
+Signed-off-by: Ian Page Hands <iphands@gmail.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/net/drivers/efi/efinet.c | 25 +++++++++++++++++++++++--
+ 1 file changed, 23 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index e11d759f19..1a24f38a21 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -850,10 +850,31 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+     else
+       {
+ 	grub_dprintf ("efinet", "using ipv4 and dhcp\n");
++
++        struct grub_net_bootp_packet *dhcp_ack = &pxe_mode->dhcp_ack;
++
++        if (pxe_mode->proxy_offer_received)
++          {
++            grub_dprintf ("efinet", "proxy offer receive");
++            struct grub_net_bootp_packet *proxy_offer = &pxe_mode->proxy_offer;
++
++            if (proxy_offer && dhcp_ack->boot_file[0] == '\0')
++              {
++                grub_dprintf ("efinet", "setting values from proxy offer");
++                /* Here we got a proxy offer and the dhcp_ack has a nil boot_file
++                 * Copy the proxy DHCP offer details into the bootp_packet we are
++                 * sending forward as they are the deatils we need.
++                 */
++                *dhcp_ack->server_name = *proxy_offer->server_name;
++                *dhcp_ack->boot_file   = *proxy_offer->boot_file;
++                dhcp_ack->server_ip    = proxy_offer->server_ip;
++              }
++          }
++
+ 	grub_net_configure_by_dhcp_ack (card->name, card, 0,
+ 					(struct grub_net_bootp_packet *)
+-					packet_buf,
+-					packet_bufsz,
++					&pxe_mode->dhcp_ack,
++					sizeof (pxe_mode->dhcp_ack),
+ 					1, device, path);
+ 	grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
+       }
diff --git a/SOURCES/0179-Add-suport-for-signing-grub-with-an-appended-signatu.patch b/SOURCES/0179-Add-suport-for-signing-grub-with-an-appended-signatu.patch
deleted file mode 100644
index caab8d5..0000000
--- a/SOURCES/0179-Add-suport-for-signing-grub-with-an-appended-signatu.patch
+++ /dev/null
@@ -1,316 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Rashmica Gupta <rashmica.g@gmail.com>
-Date: Thu, 11 Jun 2020 11:26:23 +1000
-Subject: [PATCH] Add suport for signing grub with an appended signature
-
-Add infrastructure to allow firmware to verify the integrity of grub
-by use of a Linux-kernel-module-style appended signature. We initially
-target powerpc-ieee1275, but the code should be extensible to other
-platforms.
-
-Usually these signatures are appended to a file without modifying the
-ELF file itself. (This is what the 'sign-file' tool does, for example.)
-The verifier loads the signed file from the file system and looks at the
-end of the file for the appended signature. However, on powerpc-ieee1275
-platforms, the bootloader is often stored directly in the PReP partition
-as raw bytes without a file-system. This makes determining the location
-of an appended signature more difficult.
-
-To address this, we add a new ELF note.
-
-The name field of shall be the string "Appended-Signature", zero-padded
-to 4 byte alignment. The type field shall be 0x41536967 (the ASCII values
-for the string "ASig"). It must be the final section in the ELF binary.
-
-The description shall contain the appended signature structure as defined
-by the Linux kernel. The description will also be padded to be a multiple
-of 4 bytes. The padding shall be added before the appended signature
-structure (not at the end) so that the final bytes of a signed ELF file
-are the appended signature magic.
-
-A subsequent patch documents how to create a grub core.img validly signed
-under this scheme.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
-
----
-
-You can experiment with this code with a patched version of SLOF
-that verifies these signatures. You can find one at:
-   https://github.com/daxtens/SLOF
-
-I will be proposing this for inclusion in a future Power Architecture
-Platform Reference (PAPR).
----
- util/grub-install-common.c  | 18 ++++++++++++++++--
- util/grub-mkimage.c         | 15 +++++++++++++--
- util/grub-mkimagexx.c       | 39 ++++++++++++++++++++++++++++++++++++++-
- util/mkimage.c              | 13 +++++++------
- include/grub/util/install.h |  8 ++++++--
- include/grub/util/mkimage.h |  4 ++--
- 6 files changed, 82 insertions(+), 15 deletions(-)
-
-diff --git a/util/grub-install-common.c b/util/grub-install-common.c
-index 4e212e690c5..aab2a941f85 100644
---- a/util/grub-install-common.c
-+++ b/util/grub-install-common.c
-@@ -461,10 +461,12 @@ static size_t npubkeys;
- static char *sbat;
- static int disable_shim_lock;
- static grub_compression_t compression;
-+static size_t appsig_size;
- 
- int
- grub_install_parse (int key, char *arg)
- {
-+  const char *end;
-   switch (key)
-     {
-     case 'C':
-@@ -562,6 +564,12 @@ grub_install_parse (int key, char *arg)
-       grub_util_error (_("Unrecognized compression `%s'"), arg);
-     case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE:
-       return 1;
-+    case GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE:
-+      grub_errno = 0;
-+      appsig_size = grub_strtol(arg, &end, 10);
-+      if (grub_errno)
-+        return 0;
-+      return 1;
-     default:
-       return 0;
-     }
-@@ -665,7 +673,13 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
- 		  dir, prefix,
- 		  outname, dtb ? : "", sbat ? : "", mkimage_target,
- 		  compnames[compression], note ? "--note" : "",
--		  disable_shim_lock ? "--disable-shim-lock" : "", s);
-+		  disable_shim_lock ? "--disable-shim-lock" : "",
-+		  "--format '%s' --compression '%s' "
-+		  "--appended-signature-size %zu %s %s\n",
-+		  dir, prefix,
-+		  outname, dtb ? : "", mkimage_target,
-+		  compnames[compression], appsig_size,
-+		  note ? "--note" : "", s);
-   free (s);
- 
-   tgt = grub_install_get_image_target (mkimage_target);
-@@ -675,7 +689,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
-   grub_install_generate_image (dir, prefix, fp, outname,
- 			       modules.entries, memdisk_path,
- 			       pubkeys, npubkeys, config_path, tgt,
--			       note, compression, dtb, sbat,
-+			       note, appsig_size, compression, dtb, sbat,
- 			       disable_shim_lock);
-   while (dc--)
-     grub_install_pop_module ();
-diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
-index c0d55993702..8a53310548b 100644
---- a/util/grub-mkimage.c
-+++ b/util/grub-mkimage.c
-@@ -84,6 +84,7 @@ static struct argp_option options[] = {
-   {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0},
-   {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0},
-   {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
-+  {"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0},
-   { 0, 0, 0, 0, 0, 0 }
- };
- 
-@@ -128,6 +129,7 @@ struct arguments
-   char *sbat;
-   int note;
-   int disable_shim_lock;
-+  size_t appsig_size;
-   const struct grub_install_image_target_desc *image_target;
-   grub_compression_t comp;
- };
-@@ -138,6 +140,7 @@ argp_parser (int key, char *arg, struct argp_state *state)
-   /* Get the input argument from argp_parse, which we
-      know is a pointer to our arguments structure. */
-   struct arguments *arguments = state->input;
-+  const char* end;
- 
-   switch (key)
-     {
-@@ -170,6 +173,13 @@ argp_parser (int key, char *arg, struct argp_state *state)
-       arguments->note = 1;
-       break;
- 
-+    case 'S':
-+      grub_errno = 0;
-+      arguments->appsig_size = grub_strtol(arg, &end, 10);
-+      if (grub_errno)
-+        return 0;
-+      break;
-+
-     case 'm':
-       if (arguments->memdisk)
- 	free (arguments->memdisk);
-@@ -324,8 +334,9 @@ main (int argc, char *argv[])
- 			       arguments.memdisk, arguments.pubkeys,
- 			       arguments.npubkeys, arguments.config,
- 			       arguments.image_target, arguments.note,
--			       arguments.comp, arguments.dtb,
--			       arguments.sbat, arguments.disable_shim_lock);
-+			       arguments.appsig_size, arguments.comp,
-+			       arguments.dtb, arguments.sbat,
-+			       arguments.disable_shim_lock);
- 
-   if (grub_util_file_sync (fp) < 0)
-     grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout",
-diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
-index d78fa3e5330..393119486d3 100644
---- a/util/grub-mkimagexx.c
-+++ b/util/grub-mkimagexx.c
-@@ -84,6 +84,15 @@ struct grub_ieee1275_note
-   struct grub_ieee1275_note_desc descriptor;
- };
- 
-+#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature"
-+#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */
-+
-+struct grub_appended_signature_note
-+{
-+  Elf32_Nhdr header;
-+  char name[ALIGN_UP(sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 4)];
-+};
-+
- #define GRUB_XEN_NOTE_NAME "Xen"
- 
- struct fixup_block_list
-@@ -207,7 +216,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr)
- 
- void
- SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target,
--				    int note, char **core_img, size_t *core_size,
-+				    int note, size_t appsig_size, char **core_img, size_t *core_size,
- 				    Elf_Addr target_addr,
- 				    struct grub_mkimage_layout *layout)
- {
-@@ -221,6 +230,12 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
-   int shnum = 4;
-   int string_size = sizeof (".text") + sizeof ("mods") + 1;
- 
-+  if (appsig_size)
-+    {
-+      phnum++;
-+      footer_size += ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4);
-+    }
-+
-   if (image_target->id != IMAGE_LOONGSON_ELF)
-     phnum += 2;
- 
-@@ -484,6 +499,28 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
-       phdr->p_offset = grub_host_to_target32 (header_size + program_size);
-     }
- 
-+  if (appsig_size) {
-+    int note_size = ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4);
-+    struct grub_appended_signature_note *note_ptr = (struct grub_appended_signature_note *)
-+      (elf_img + program_size + header_size + (note ? sizeof (struct grub_ieee1275_note) : 0));
-+
-+    note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME));
-+    /* needs to sit at the end, so we round this up and sign some zero padding */
-+    note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP(appsig_size, 4));
-+    note_ptr->header.n_type = grub_host_to_target32 (GRUB_APPENDED_SIGNATURE_NOTE_TYPE);
-+    strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME);
-+
-+    phdr++;
-+    phdr->p_type = grub_host_to_target32 (PT_NOTE);
-+    phdr->p_flags = grub_host_to_target32 (PF_R);
-+    phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
-+    phdr->p_vaddr = 0;
-+    phdr->p_paddr = 0;
-+    phdr->p_filesz = grub_host_to_target32 (note_size);
-+    phdr->p_memsz = 0;
-+    phdr->p_offset = grub_host_to_target32 (header_size + program_size + (note ? sizeof (struct grub_ieee1275_note) : 0));
-+  }
-+
-   {
-     char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)
- 		       + shnum * sizeof (*shdr));
-diff --git a/util/mkimage.c b/util/mkimage.c
-index a26cf76f72f..bab12276010 100644
---- a/util/mkimage.c
-+++ b/util/mkimage.c
-@@ -869,8 +869,9 @@ grub_install_generate_image (const char *dir, const char *prefix,
- 			     char *memdisk_path, char **pubkey_paths,
- 			     size_t npubkeys, char *config_path,
- 			     const struct grub_install_image_target_desc *image_target,
--			     int note, grub_compression_t comp, const char *dtb_path,
--			     const char *sbat_path, int disable_shim_lock)
-+			     int note, size_t appsig_size, grub_compression_t comp,
-+			     const char *dtb_path, const char *sbat_path,
-+			     int disable_shim_lock)
- {
-   char *kernel_img, *core_img;
-   size_t total_module_size, core_size;
-@@ -1773,11 +1774,11 @@ grub_install_generate_image (const char *dir, const char *prefix,
- 	else
- 	  target_addr = image_target->link_addr;
- 	if (image_target->voidp_sizeof == 4)
--	  grub_mkimage_generate_elf32 (image_target, note, &core_img, &core_size,
--				       target_addr, &layout);
-+	  grub_mkimage_generate_elf32 (image_target, note, appsig_size, &core_img,
-+				       &core_size, target_addr, &layout);
- 	else
--	  grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size,
--				       target_addr, &layout);
-+	  grub_mkimage_generate_elf64 (image_target, note, appsig_size, &core_img,
-+				       &core_size, target_addr, &layout);
-       }
-       break;
-     }
-diff --git a/include/grub/util/install.h b/include/grub/util/install.h
-index 7df3191f47e..cf4531e02b6 100644
---- a/include/grub/util/install.h
-+++ b/include/grub/util/install.h
-@@ -67,6 +67,9 @@
-       N_("SBAT metadata"), 0 },						\
-   { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0,	\
-       N_("disable shim_lock verifier"), 0 },				\
-+  { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\
-+    "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \
-+    1},                                                                 \
-   { "verbose", 'v', 0, 0,						\
-     N_("print verbose messages."), 1 }
- 
-@@ -128,7 +131,8 @@ enum grub_install_options {
-   GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS,
-   GRUB_INSTALL_OPTIONS_DTB,
-   GRUB_INSTALL_OPTIONS_SBAT,
--  GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK
-+  GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK,
-+  GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE
- };
- 
- extern char *grub_install_source_directory;
-@@ -188,7 +192,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
- 			     size_t npubkeys,
- 			     char *config_path,
- 			     const struct grub_install_image_target_desc *image_target,
--			     int note,
-+			     int note, size_t appsig_size,
- 			     grub_compression_t comp, const char *dtb_file,
- 			     const char *sbat_path, const int disable_shim_lock);
- 
-diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h
-index 3819a67441c..6f1da89b9b6 100644
---- a/include/grub/util/mkimage.h
-+++ b/include/grub/util/mkimage.h
-@@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path,
- 			   const struct grub_install_image_target_desc *image_target);
- void
- grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target,
--			     int note, char **core_img, size_t *core_size,
-+			     int note, size_t appsig_size, char **core_img, size_t *core_size,
- 			     Elf32_Addr target_addr,
- 			     struct grub_mkimage_layout *layout);
- void
- grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target,
--			     int note, char **core_img, size_t *core_size,
-+			     int note, size_t appsig_size, char **core_img, size_t *core_size,
- 			     Elf64_Addr target_addr,
- 			     struct grub_mkimage_layout *layout);
- 
diff --git a/SOURCES/0179-fs-ext2-Ignore-checksum-seed-incompat-feature.patch b/SOURCES/0179-fs-ext2-Ignore-checksum-seed-incompat-feature.patch
new file mode 100644
index 0000000..3d7c641
--- /dev/null
+++ b/SOURCES/0179-fs-ext2-Ignore-checksum-seed-incompat-feature.patch
@@ -0,0 +1,54 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Fri, 11 Jun 2021 00:01:29 +0200
+Subject: [PATCH] fs/ext2: Ignore checksum seed incompat feature
+
+This incompat feature is used to denote that the filesystem stored its
+metadata checksum seed in the superblock. This is used to allow tune2fs
+to change the UUID on a mounted metadata_csum filesystem without having
+to rewrite all the disk metadata.
+
+But GRUB doesn't use the metadata checksum in anyway, so can just ignore
+this feature if is enabled. This is consistent with GRUB filesystem code
+in general which just does a best effort to access the filesystem's data.
+
+It may be removed from the ignored list in the future if supports to do
+metadata checksumming verification is added to the read-only FS driver.
+
+Suggested-by: Eric Sandeen <esandeen@redhat.com>
+Suggested-by: Lukas Czerner <lczerner@redhat.com>
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/fs/ext2.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c
+index e7dd78e663..731d346f88 100644
+--- a/grub-core/fs/ext2.c
++++ b/grub-core/fs/ext2.c
+@@ -103,6 +103,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ #define EXT4_FEATURE_INCOMPAT_64BIT		0x0080
+ #define EXT4_FEATURE_INCOMPAT_MMP		0x0100
+ #define EXT4_FEATURE_INCOMPAT_FLEX_BG		0x0200
++#define EXT4_FEATURE_INCOMPAT_CSUM_SEED		0x2000
+ #define EXT4_FEATURE_INCOMPAT_ENCRYPT          0x10000
+ 
+ /* The set of back-incompatible features this driver DOES support. Add (OR)
+@@ -123,9 +124,16 @@ GRUB_MOD_LICENSE ("GPLv3+");
+  * mmp:            Not really back-incompatible - was added as such to
+  *                 avoid multiple read-write mounts. Safe to ignore for this
+  *                 RO driver.
++ * checksum seed:  Not really back-incompatible - was added to allow tools
++ *                 such as tune2fs to change the UUID on a mounted metadata
++ *                 checksummed filesystem. Safe to ignore for now since the
++ *                 driver doesn't support checksum verification. But it must
++ *                 be removed from this list if that support is added later.
++ *
+  */
+ #define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER \
+-				     | EXT4_FEATURE_INCOMPAT_MMP)
++				     | EXT4_FEATURE_INCOMPAT_MMP \
++				     | EXT4_FEATURE_INCOMPAT_CSUM_SEED)
+ 
+ 
+ #define EXT3_JOURNAL_MAGIC_NUMBER	0xc03b3998U
diff --git a/SOURCES/0180-Don-t-update-the-cmdline-when-generating-legacy-menu.patch b/SOURCES/0180-Don-t-update-the-cmdline-when-generating-legacy-menu.patch
new file mode 100644
index 0000000..b2783d1
--- /dev/null
+++ b/SOURCES/0180-Don-t-update-the-cmdline-when-generating-legacy-menu.patch
@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Thu, 17 Jun 2021 14:31:42 +0200
+Subject: [PATCH] Don't update the cmdline when generating legacy menuentry
+ commands
+
+On OPAL ppc64le machines with an old petitboot version that doesn't have
+support to parse BLS snippets, the grub2-mkconfig script is executed to
+generate menuentry commands from the BLS snippets.
+
+In this case, the script is executed with the --no-grubenv-update option
+that indicates that no side effects should happen when running the script.
+
+But the options field in the BLS snippets are updated regardless, only do
+the update if --no-grubenv-update was not used.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub.d/10_linux.in | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index e490e1a43a..865af3d6c4 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -256,7 +256,9 @@ if [ -z "\${kernelopts}" ]; then
+ fi
+ EOF
+ 
+-  update_bls_cmdline
++  if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then
++      update_bls_cmdline
++  fi
+ 
+   if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then
+       populate_menu
diff --git a/SOURCES/0180-docs-grub-Document-signing-grub-under-UEFI.patch b/SOURCES/0180-docs-grub-Document-signing-grub-under-UEFI.patch
deleted file mode 100644
index 9b9b19a..0000000
--- a/SOURCES/0180-docs-grub-Document-signing-grub-under-UEFI.patch
+++ /dev/null
@@ -1,61 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Sat, 15 Aug 2020 02:00:57 +1000
-Subject: [PATCH] docs/grub: Document signing grub under UEFI
-
-Before adding information about how grub is signed with an appended
-signature scheme, it's worth adding some information about how it
-can currently be signed for UEFI.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- docs/grub.texi | 22 +++++++++++++++++++++-
- 1 file changed, 21 insertions(+), 1 deletion(-)
-
-diff --git a/docs/grub.texi b/docs/grub.texi
-index 4870faaa00a..365d1d6931b 100644
---- a/docs/grub.texi
-+++ b/docs/grub.texi
-@@ -5817,6 +5817,7 @@ environment variables and commands are listed in the same order.
- * Secure Boot Advanced Targeting::   Embedded information for generation number based revocation
- * Measured Boot::                    Measuring boot components
- * Lockdown::                         Lockdown when booting on a secure setup
-+* Signing GRUB itself::              Ensuring the integrity of the GRUB core image
- @end menu
- 
- @node Authentication and authorisation
-@@ -5895,7 +5896,7 @@ commands.
- 
- GRUB's @file{core.img} can optionally provide enforcement that all files
- subsequently read from disk are covered by a valid digital signature.
--This document does @strong{not} cover how to ensure that your
-+This section does @strong{not} cover how to ensure that your
- platform's firmware (e.g., Coreboot) validates @file{core.img}.
- 
- If environment variable @code{check_signatures}
-@@ -6067,6 +6068,25 @@ be restricted and some operations/commands cannot be executed.
- The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down.
- Otherwise it does not exit.
- 
-+@node Signing GRUB itself
-+@section Signing GRUB itself
-+
-+To ensure a complete secure-boot chain, there must be a way for the code that
-+loads GRUB to verify the integrity of the core image.
-+
-+This is ultimately platform-specific and individual platforms can define their
-+own mechanisms. However, there are general-purpose mechanisms that can be used
-+with GRUB.
-+
-+@section Signing GRUB for UEFI secure boot
-+
-+On UEFI platforms, @file{core.img} is a PE binary. Therefore, it can be signed
-+with a tool such as @command{pesign} or @command{sbsign}. Refer to the
-+suggestions in @pxref{UEFI secure boot and shim} to ensure that the final
-+image works under UEFI secure boot and can maintain the secure-boot chain. It
-+will also be necessary to enrol the public key used into a relevant firmware
-+key database.
-+
- @node Platform limitations
- @chapter Platform limitations
- 
diff --git a/SOURCES/0181-Suppress-gettext-error-message.patch b/SOURCES/0181-Suppress-gettext-error-message.patch
new file mode 100644
index 0000000..64b219a
--- /dev/null
+++ b/SOURCES/0181-Suppress-gettext-error-message.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
+Date: Tue, 29 Jun 2021 13:17:42 +0200
+Subject: [PATCH] Suppress gettext error message
+
+Colin Watson's patch from comment #11 on the upstream bug:
+https://savannah.gnu.org/bugs/?35880#comment11
+
+Resolves: rhbz#1592124
+
+Signed-off-by: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
+---
+ grub-core/gettext/gettext.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c
+index 4d02e62c10..7ec81ca0b4 100644
+--- a/grub-core/gettext/gettext.c
++++ b/grub-core/gettext/gettext.c
+@@ -424,6 +424,13 @@ grub_gettext_init_ext (struct grub_gettext_context *ctx,
+       grub_free (lang);
+     }
+ 
++  /* If no translations are available, fall back to untranslated text. */
++  if (err == GRUB_ERR_FILE_NOT_FOUND)
++    {
++      grub_errno = GRUB_ERR_NONE;
++      return 0;
++    }
++
+   if (locale[0] == 'e' && locale[1] == 'n'
+       && (locale[2] == '\0' || locale[2] == '_'))
+     grub_errno = err = GRUB_ERR_NONE;
diff --git a/SOURCES/0181-docs-grub-Document-signing-grub-with-an-appended-sig.patch b/SOURCES/0181-docs-grub-Document-signing-grub-with-an-appended-sig.patch
deleted file mode 100644
index 4d85d93..0000000
--- a/SOURCES/0181-docs-grub-Document-signing-grub-with-an-appended-sig.patch
+++ /dev/null
@@ -1,67 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Sat, 15 Aug 2020 02:19:36 +1000
-Subject: [PATCH] docs/grub: Document signing grub with an appended signature
-
-Signing grub for firmware that verifies an appended signature is a
-bit fiddly. I don't want people to have to figure it out from scratch
-so document it here.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- docs/grub.texi | 42 ++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 42 insertions(+)
-
-diff --git a/docs/grub.texi b/docs/grub.texi
-index 365d1d6931b..afbde7c1f7b 100644
---- a/docs/grub.texi
-+++ b/docs/grub.texi
-@@ -6087,6 +6087,48 @@ image works under UEFI secure boot and can maintain the secure-boot chain. It
- will also be necessary to enrol the public key used into a relevant firmware
- key database.
- 
-+@section Signing GRUB with an appended signature
-+
-+The @file{core.elf} itself can be signed with a Linux kernel module-style
-+appended signature.
-+
-+To support IEEE1275 platforms where the boot image is often loaded directly
-+from a disk partition rather than from a file system, the @file{core.elf}
-+can specify the size and location of the appended signature with an ELF
-+note added by @command{grub-install}.
-+
-+An image can be signed this way using the @command{sign-file} command from
-+the Linux kernel:
-+
-+@example
-+@group
-+# grub.key is your private key and certificate.der is your public key
-+
-+# Determine the size of the appended signature. It depends on the signing
-+# certificate and the hash algorithm
-+touch empty
-+sign-file SHA256 grub.key certificate.der empty empty.sig
-+SIG_SIZE=`stat -c '%s' empty.sig`
-+rm empty empty.sig
-+
-+# Build a grub image with $SIG_SIZE reserved for the signature
-+grub-install --appended-signature-size $SIG_SIZE --modules="..." ...
-+
-+# Replace the reserved size with a signature:
-+# cut off the last $SIG_SIZE bytes with truncate's minus modifier
-+truncate -s -$SIG_SIZE /boot/grub/powerpc-ieee1275/core.elf core.elf.unsigned
-+# sign the trimmed file with an appended signature, restoring the correct size
-+sign-file SHA256 grub.key certificate.der core.elf.unsigned core.elf.signed
-+
-+# Don't forget to install the signed image as required
-+# (e.g. on powerpc-ieee1275, to the PReP partition)
-+@end group
-+@end example
-+
-+As with UEFI secure boot, it is necessary to build in the required modules,
-+or sign them separately.
-+
-+
- @node Platform limitations
- @chapter Platform limitations
- 
diff --git a/SOURCES/0182-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch b/SOURCES/0182-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch
deleted file mode 100644
index 6e46db0..0000000
--- a/SOURCES/0182-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 30 Jul 2020 00:13:21 +1000
-Subject: [PATCH] dl: provide a fake grub_dl_set_persistent for the emu target
-
-Trying to start grub-emu with a module that calls grub_dl_set_persistent
-will crash because grub-emu fakes modules and passes NULL to the module
-init function.
-
-Provide an empty function for the emu case.
-
-Fixes: ee7808e2197c (dl: Add support for persistent modules)
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- include/grub/dl.h | 11 +++++++++++
- 1 file changed, 11 insertions(+)
-
-diff --git a/include/grub/dl.h b/include/grub/dl.h
-index 2f76e6b0437..20d870f2a47 100644
---- a/include/grub/dl.h
-+++ b/include/grub/dl.h
-@@ -245,11 +245,22 @@ grub_dl_get (const char *name)
-   return 0;
- }
- 
-+#ifdef GRUB_MACHINE_EMU
-+/*
-+ * Under grub-emu, modules are faked and NULL is passed to GRUB_MOD_INIT.
-+ * So we fake this out to avoid a NULL deref.
-+ */
-+static inline void
-+grub_dl_set_persistent (grub_dl_t mod __attribute__((unused)))
-+{
-+}
-+#else
- static inline void
- grub_dl_set_persistent (grub_dl_t mod)
- {
-   mod->persistent = 1;
- }
-+#endif
- 
- static inline int
- grub_dl_is_persistent (grub_dl_t mod)
diff --git a/SOURCES/0182-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch b/SOURCES/0182-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch
new file mode 100644
index 0000000..b5d5e5c
--- /dev/null
+++ b/SOURCES/0182-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch
@@ -0,0 +1,42 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Mon, 5 Jul 2021 18:24:22 +0200
+Subject: [PATCH] grub-set-password: Always use /boot/grub2/user.cfg as
+ password default
+
+The GRUB configuration file is always placed in /boot/grub2/ now, even for
+EFI. But the tool is still creating the user.cfg in the ESP and not there.
+
+Resolves: rhbz#1955294
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub-set-password.in | 9 +--------
+ 1 file changed, 1 insertion(+), 8 deletions(-)
+
+diff --git a/util/grub-set-password.in b/util/grub-set-password.in
+index c0b5ebbfdc..d8005e5a14 100644
+--- a/util/grub-set-password.in
++++ b/util/grub-set-password.in
+@@ -1,11 +1,6 @@
+ #!/bin/sh -e
+ 
+-EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g')
+-if [ -d /sys/firmware/efi/efivars/ ]; then
+-    grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'`
+-else
+-    grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`
+-fi
++grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`
+ 
+ PACKAGE_VERSION="@PACKAGE_VERSION@"
+ PACKAGE_NAME="@PACKAGE_NAME@"
+@@ -116,8 +111,6 @@ if [ -z "${MYPASS}" ]; then
+       exit 1
+ fi
+ 
+-# on the ESP, these will fail to set the permissions, but it's okay because
+-# the directory is protected.
+ install -m 0600 /dev/null "${OUTPUT_PATH}/user.cfg" 2>/dev/null || :
+ chmod 0600 "${OUTPUT_PATH}/user.cfg" 2>/dev/null || :
+ echo "GRUB2_PASSWORD=${MYPASS}" > "${OUTPUT_PATH}/user.cfg"
diff --git a/SOURCES/0183-pgp-factor-out-rsa_pad.patch b/SOURCES/0183-pgp-factor-out-rsa_pad.patch
deleted file mode 100644
index a8154e7..0000000
--- a/SOURCES/0183-pgp-factor-out-rsa_pad.patch
+++ /dev/null
@@ -1,191 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 1 Oct 2020 20:23:48 +1000
-Subject: [PATCH] pgp: factor out rsa_pad
-
-rsa_pad does the PKCS#1 v1.5 padding for the RSA signature scheme.
-We want to use it in other RSA signature verification applications.
-
-I considered and rejected putting it in lib/crypto.c. That file doesn't
-currently require any MPI functions, but rsa_pad does. That's not so
-much of a problem for the grub kernel and modules, but crypto.c also
-gets built into all the grub utilities. So - despite the utils not
-using any asymmetric ciphers -  we would need to built the entire MPI
-infrastructure in to them.
-
-A better and simpler solution is just to spin rsa_pad out into its own
-PKCS#1 v1.5 module.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/Makefile.core.def |  8 ++++++
- grub-core/commands/pgp.c    | 28 ++-------------------
- grub-core/lib/pkcs1_v15.c   | 59 +++++++++++++++++++++++++++++++++++++++++++++
- include/grub/pkcs1_v15.h    | 27 +++++++++++++++++++++
- 4 files changed, 96 insertions(+), 26 deletions(-)
- create mode 100644 grub-core/lib/pkcs1_v15.c
- create mode 100644 include/grub/pkcs1_v15.h
-
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 81fc274148e..97347ae76f9 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -2510,6 +2510,14 @@ module = {
-   cppflags = '$(CPPFLAGS_GCRY)';
- };
- 
-+module = {
-+  name = pkcs1_v15;
-+  common = lib/pkcs1_v15.c;
-+
-+  cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';
-+  cppflags = '$(CPPFLAGS_GCRY)';
-+};
-+
- module = {
-   name = all_video;
-   common = lib/fake_module.c;
-diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
-index 5daa1e9d00c..2408db4994f 100644
---- a/grub-core/commands/pgp.c
-+++ b/grub-core/commands/pgp.c
-@@ -24,6 +24,7 @@
- #include <grub/file.h>
- #include <grub/command.h>
- #include <grub/crypto.h>
-+#include <grub/pkcs1_v15.h>
- #include <grub/i18n.h>
- #include <grub/gcrypt/gcrypt.h>
- #include <grub/pubkey.h>
-@@ -411,32 +412,7 @@ static int
- rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
- 	 const gcry_md_spec_t *hash, struct grub_public_subkey *sk)
- {
--  grub_size_t tlen, emlen, fflen;
--  grub_uint8_t *em, *emptr;
--  unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]);
--  int ret;
--  tlen = hash->mdlen + hash->asnlen;
--  emlen = (nbits + 7) / 8;
--  if (emlen < tlen + 11)
--    return 1;
--
--  em = grub_malloc (emlen);
--  if (!em)
--    return 1;
--
--  em[0] = 0x00;
--  em[1] = 0x01;
--  fflen = emlen - tlen - 3;
--  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
--    *emptr = 0xff;
--  *emptr++ = 0x00;
--  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
--  emptr += hash->asnlen;
--  grub_memcpy (emptr, hval, hash->mdlen);
--
--  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
--  grub_free (em);
--  return ret;
-+  return grub_crypto_rsa_pad(hmpi, hval, hash, sk->mpis[0]);
- }
- 
- struct grub_pubkey_context
-diff --git a/grub-core/lib/pkcs1_v15.c b/grub-core/lib/pkcs1_v15.c
-new file mode 100644
-index 00000000000..dbacd563d01
---- /dev/null
-+++ b/grub-core/lib/pkcs1_v15.c
-@@ -0,0 +1,59 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2013  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/gcrypt/gcrypt.h>
-+
-+GRUB_MOD_LICENSE ("GPLv3+");
-+
-+/*
-+ * Given a hash value 'hval', of hash specification 'hash', perform
-+ * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
-+ * (see RFC 8017 s 9.2) and place the result in 'hmpi'.
-+ */
-+gcry_err_code_t
-+grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
-+		     const gcry_md_spec_t * hash, gcry_mpi_t mod)
-+{
-+  grub_size_t tlen, emlen, fflen;
-+  grub_uint8_t *em, *emptr;
-+  unsigned nbits = gcry_mpi_get_nbits (mod);
-+  int ret;
-+  tlen = hash->mdlen + hash->asnlen;
-+  emlen = (nbits + 7) / 8;
-+  if (emlen < tlen + 11)
-+    return GPG_ERR_TOO_SHORT;
-+
-+  em = grub_malloc (emlen);
-+  if (!em)
-+    return 1;
-+
-+  em[0] = 0x00;
-+  em[1] = 0x01;
-+  fflen = emlen - tlen - 3;
-+  for (emptr = em + 2; emptr < em + 2 + fflen; emptr++)
-+    *emptr = 0xff;
-+  *emptr++ = 0x00;
-+  grub_memcpy (emptr, hash->asnoid, hash->asnlen);
-+  emptr += hash->asnlen;
-+  grub_memcpy (emptr, hval, hash->mdlen);
-+
-+  ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0);
-+  grub_free (em);
-+  return ret;
-+}
-diff --git a/include/grub/pkcs1_v15.h b/include/grub/pkcs1_v15.h
-new file mode 100644
-index 00000000000..5c338c84a15
---- /dev/null
-+++ b/include/grub/pkcs1_v15.h
-@@ -0,0 +1,27 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2013  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/>.
-+ */
-+
-+/*
-+ * Given a hash value 'hval', of hash specification 'hash', perform
-+ * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod'
-+ * (See RFC 8017 s 9.2)
-+ */
-+gcry_err_code_t
-+grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval,
-+		     const gcry_md_spec_t * hash, gcry_mpi_t mod);
-+
diff --git a/SOURCES/0183-templates-Check-for-EFI-at-runtime-instead-of-config.patch b/SOURCES/0183-templates-Check-for-EFI-at-runtime-instead-of-config.patch
new file mode 100644
index 0000000..265b967
--- /dev/null
+++ b/SOURCES/0183-templates-Check-for-EFI-at-runtime-instead-of-config.patch
@@ -0,0 +1,63 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 6 Jul 2021 00:38:40 +0200
+Subject: [PATCH] templates: Check for EFI at runtime instead of config
+ generation time
+
+The 30_uefi-firmware template checks if an OsIndicationsSupported UEFI var
+exists and EFI_OS_INDICATIONS_BOOT_TO_FW_UI bit is set, to decide whether
+a "fwsetup" menu entry would be added or not to the GRUB menu.
+
+But this has the problem that it will only work if the configuration file
+was created on an UEFI machine that supports booting to a firmware UI.
+
+This for example doesn't support creating GRUB config files when executing
+on systems that support both UEFI and legacy BIOS booting. Since creating
+the config file from legacy BIOS wouldn't allow to access the firmware UI.
+
+To prevent this, make the template to unconditionally create the grub.cfg
+snippet but check at runtime if was booted through UEFI to decide if this
+entry should be added. That way it won't be added when booting with BIOS.
+
+There's no need to check if EFI_OS_INDICATIONS_BOOT_TO_FW_UI bit is set,
+since that's already done by the "fwsetup" command when is executed.
+
+Resolves: rhbz#1823864
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub.d/30_uefi-firmware.in | 21 ++++++++-------------
+ 1 file changed, 8 insertions(+), 13 deletions(-)
+
+diff --git a/util/grub.d/30_uefi-firmware.in b/util/grub.d/30_uefi-firmware.in
+index d344d3883d..b6041b55e2 100644
+--- a/util/grub.d/30_uefi-firmware.in
++++ b/util/grub.d/30_uefi-firmware.in
+@@ -26,19 +26,14 @@ export TEXTDOMAINDIR="@localedir@"
+ 
+ . "$pkgdatadir/grub-mkconfig_lib"
+ 
+-EFI_VARS_DIR=/sys/firmware/efi/efivars
+-EFI_GLOBAL_VARIABLE=8be4df61-93ca-11d2-aa0d-00e098032b8c
+-OS_INDICATIONS="$EFI_VARS_DIR/OsIndicationsSupported-$EFI_GLOBAL_VARIABLE"
++LABEL="UEFI Firmware Settings"
+ 
+-if [ -e "$OS_INDICATIONS" ] && \
+-   [ "$(( $(printf 0x%x \'"$(cat $OS_INDICATIONS | cut -b5)"\') & 1 ))" = 1 ]; then
+-  LABEL="UEFI Firmware Settings"
++gettext_printf "Adding boot menu entry for UEFI Firmware Settings ...\n" >&2
+ 
+-  gettext_printf "Adding boot menu entry for UEFI Firmware Settings ...\n" >&2
+-
+-  cat << EOF
+-menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' {
+-	fwsetup
+-}
+-EOF
++cat << EOF
++if [ "\$grub_platform" = "efi" ]; then
++	menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' {
++		fwsetup
++	}
+ fi
++EOF
diff --git a/SOURCES/0184-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch b/SOURCES/0184-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch
deleted file mode 100644
index 763cdc6..0000000
--- a/SOURCES/0184-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch
+++ /dev/null
@@ -1,71 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Fri, 2 Oct 2020 10:49:26 +1000
-Subject: [PATCH] crypto: move storage for grub_crypto_pk_* to crypto.c
-
-The way gcry_rsa and friends (the asymmetric ciphers) are loaded for the
-pgp module is a bit quirky.
-
-include/grub/crypto.h contains:
-  extern struct gcry_pk_spec *grub_crypto_pk_rsa;
-
-commands/pgp.c contains the actual storage:
-  struct gcry_pk_spec *grub_crypto_pk_rsa;
-
-And the module itself saves to the storage in pgp.c:
-  GRUB_MOD_INIT(gcry_rsa)
-  {
-    grub_crypto_pk_rsa = &_gcry_pubkey_spec_rsa;
-  }
-
-This is annoying: gcry_rsa now has a dependency on pgp!
-
-We want to be able to bring in gcry_rsa without bringing in PGP,
-so move the storage to crypto.c.
-
-Previously, gcry_rsa depended on pgp and mpi. Now it depends on
-crypto and mpi. As pgp depends on crypto, this doesn't add any new
-module dependencies using the PGP verfier.
-
-[FWIW, the story is different for the symmetric ciphers. cryptodisk
-and friends (zfs encryption etc) use grub_crypto_lookup_cipher_by_name()
-to get a cipher handle. That depends on grub_ciphers being populated
-by people calling grub_cipher_register. import_gcry.py ensures that the
-symmetric ciphers call it.]
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/commands/pgp.c | 4 ----
- grub-core/lib/crypto.c   | 4 ++++
- 2 files changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
-index 2408db4994f..355a43844ac 100644
---- a/grub-core/commands/pgp.c
-+++ b/grub-core/commands/pgp.c
-@@ -147,10 +147,6 @@ const char *hashes[] = {
-   [0x0b] = "sha224"
- };
- 
--struct gcry_pk_spec *grub_crypto_pk_dsa;
--struct gcry_pk_spec *grub_crypto_pk_ecdsa;
--struct gcry_pk_spec *grub_crypto_pk_rsa;
--
- static int
- dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval,
- 	 const gcry_md_spec_t *hash, struct grub_public_subkey *sk);
-diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c
-index ca334d5a40e..c578128a59d 100644
---- a/grub-core/lib/crypto.c
-+++ b/grub-core/lib/crypto.c
-@@ -121,6 +121,10 @@ grub_md_unregister (gcry_md_spec_t *cipher)
-       }
- }
- 
-+struct gcry_pk_spec *grub_crypto_pk_dsa;
-+struct gcry_pk_spec *grub_crypto_pk_ecdsa;
-+struct gcry_pk_spec *grub_crypto_pk_rsa;
-+
- void
- grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in,
- 		  grub_size_t inlen)
diff --git a/SOURCES/0184-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch b/SOURCES/0184-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch
new file mode 100644
index 0000000..3b1a219
--- /dev/null
+++ b/SOURCES/0184-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch
@@ -0,0 +1,92 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 6 Jul 2021 01:10:18 +0200
+Subject: [PATCH] efi: Print an error if boot to firmware setup is not
+ supported
+
+The "fwsetup" command is only registered if the firmware supports booting
+to the firmware setup UI. But it could be possible that the GRUB config
+already contains a "fwsetup" entry, because it was generated in a machine
+that has support for this feature.
+
+To prevent users getting a "can't find command `fwsetup`" error if it is
+not supported by the firmware, let's just always register the command but
+print a more accurate message if the firmware doesn't support this option.
+
+Resolves: rhbz#1823864
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/efi/efifwsetup.c | 43 ++++++++++++++++++++-----------------
+ 1 file changed, 23 insertions(+), 20 deletions(-)
+
+diff --git a/grub-core/commands/efi/efifwsetup.c b/grub-core/commands/efi/efifwsetup.c
+index eaca032838..328c45e82e 100644
+--- a/grub-core/commands/efi/efifwsetup.c
++++ b/grub-core/commands/efi/efifwsetup.c
+@@ -27,6 +27,25 @@
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
++static grub_efi_boolean_t
++efifwsetup_is_supported (void)
++{
++  grub_efi_uint64_t *os_indications_supported = NULL;
++  grub_size_t oi_size = 0;
++  grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
++
++  grub_efi_get_variable ("OsIndicationsSupported", &global, &oi_size,
++			 (void **) &os_indications_supported);
++
++  if (!os_indications_supported)
++    return 0;
++
++  if (*os_indications_supported & GRUB_EFI_OS_INDICATIONS_BOOT_TO_FW_UI)
++    return 1;
++
++  return 0;
++}
++
+ static grub_err_t
+ grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)),
+ 		  int argc __attribute__ ((unused)),
+@@ -38,6 +57,10 @@ grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)),
+   grub_size_t oi_size;
+   grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
+ 
++  if (!efifwsetup_is_supported ())
++	  return grub_error (GRUB_ERR_INVALID_COMMAND,
++			     N_("Reboot to firmware setup is not supported"));
++
+   grub_efi_get_variable ("OsIndications", &global, &oi_size,
+ 			 (void **) &old_os_indications);
+ 
+@@ -56,28 +79,8 @@ grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)),
+ 
+ static grub_command_t cmd = NULL;
+ 
+-static grub_efi_boolean_t
+-efifwsetup_is_supported (void)
+-{
+-  grub_efi_uint64_t *os_indications_supported = NULL;
+-  grub_size_t oi_size = 0;
+-  grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
+-
+-  grub_efi_get_variable ("OsIndicationsSupported", &global, &oi_size,
+-			 (void **) &os_indications_supported);
+-
+-  if (!os_indications_supported)
+-    return 0;
+-
+-  if (*os_indications_supported & GRUB_EFI_OS_INDICATIONS_BOOT_TO_FW_UI)
+-    return 1;
+-
+-  return 0;
+-}
+-
+ GRUB_MOD_INIT (efifwsetup)
+ {
+-  if (efifwsetup_is_supported ())
+     cmd = grub_register_command ("fwsetup", grub_cmd_fwsetup, NULL,
+ 				 N_("Reboot into firmware setup menu."));
+ 
diff --git a/SOURCES/0185-arm64-Fix-EFI-loader-kernel-image-allocation.patch b/SOURCES/0185-arm64-Fix-EFI-loader-kernel-image-allocation.patch
new file mode 100644
index 0000000..cc5458c
--- /dev/null
+++ b/SOURCES/0185-arm64-Fix-EFI-loader-kernel-image-allocation.patch
@@ -0,0 +1,218 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Date: Mon, 2 Aug 2021 23:10:01 +1000
+Subject: [PATCH] arm64: Fix EFI loader kernel image allocation
+
+We are currently allocating just enough memory for the file size,
+which means that the kernel BSS is in limbo (and not even zeroed).
+
+We are also not honoring the alignment specified in the image
+PE header.
+
+This makes us use the PE optional header in which the kernel puts the
+actual size it needs, including BSS, and make sure we clear it, and
+honors the specified alignment for the image.
+
+Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+[pjones: arm: check for the PE magic for the compiled arch]
+Signed-off-by: Peter Jones <pjones@redhat.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/loader/arm64/linux.c | 100 +++++++++++++++++++++++++++--------------
+ include/grub/arm/linux.h       |   1 +
+ include/grub/arm64/linux.h     |   1 +
+ 3 files changed, 68 insertions(+), 34 deletions(-)
+
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index 47f8cf0d84..f18d90bd74 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -41,6 +41,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ static grub_dl_t my_mod;
+ static int loaded;
+ 
++static void *kernel_alloc_addr;
++static grub_uint32_t kernel_alloc_pages;
+ static void *kernel_addr;
+ static grub_uint64_t kernel_size;
+ static grub_uint32_t handover_offset;
+@@ -204,9 +206,8 @@ grub_linux_unload (void)
+ 			 GRUB_EFI_BYTES_TO_PAGES (initrd_end - initrd_start));
+   initrd_start = initrd_end = 0;
+   grub_free (linux_args);
+-  if (kernel_addr)
+-    grub_efi_free_pages ((grub_addr_t) kernel_addr,
+-			 GRUB_EFI_BYTES_TO_PAGES (kernel_size));
++  if (kernel_alloc_addr)
++    grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages);
+   grub_fdt_unload ();
+   return GRUB_ERR_NONE;
+ }
+@@ -311,14 +312,35 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+   return grub_errno;
+ }
+ 
++static grub_err_t
++parse_pe_header (void *kernel, grub_uint64_t *total_size,
++		 grub_uint32_t *entry_offset,
++		 grub_uint32_t *alignment)
++{
++  struct linux_arch_kernel_header *lh = kernel;
++  struct grub_armxx_linux_pe_header *pe;
++
++  pe = (void *)((unsigned long)kernel + lh->hdr_offset);
++
++  if (pe->opt.magic != GRUB_PE32_PEXX_MAGIC)
++    return grub_error(GRUB_ERR_BAD_OS, "Invalid PE optional header magic");
++
++  *total_size   = pe->opt.image_size;
++  *entry_offset = pe->opt.entry_addr;
++  *alignment    = pe->opt.section_alignment;
++
++  return GRUB_ERR_NONE;
++}
++
+ static grub_err_t
+ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 		int argc, char *argv[])
+ {
+   grub_file_t file = 0;
+-  struct linux_arch_kernel_header lh;
+-  struct grub_armxx_linux_pe_header *pe;
+   grub_err_t err;
++  grub_off_t filelen;
++  grub_uint32_t align;
++  void *kernel = NULL;
+   int rc;
+ 
+   grub_dl_ref (my_mod);
+@@ -333,40 +355,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   if (!file)
+     goto fail;
+ 
+-  kernel_size = grub_file_size (file);
+-
+-  if (grub_file_read (file, &lh, sizeof (lh)) < (long) sizeof (lh))
+-    return grub_errno;
+-
+-  if (grub_arch_efi_linux_check_image (&lh) != GRUB_ERR_NONE)
+-    goto fail;
+-
+-  grub_loader_unset();
+-
+-  grub_dprintf ("linux", "kernel file size: %lld\n", (long long) kernel_size);
+-  kernel_addr = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (kernel_size));
+-  grub_dprintf ("linux", "kernel numpages: %lld\n",
+-		(long long) GRUB_EFI_BYTES_TO_PAGES (kernel_size));
+-  if (!kernel_addr)
++  filelen = grub_file_size (file);
++  kernel = grub_malloc(filelen);
++  if (!kernel)
+     {
+-      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel load buffer"));
+       goto fail;
+     }
+ 
+-  grub_file_seek (file, 0);
+-  if (grub_file_read (file, kernel_addr, kernel_size)
+-      < (grub_int64_t) kernel_size)
++  if (grub_file_read (file, kernel, filelen) < (grub_ssize_t)filelen)
+     {
+-      if (!grub_errno)
+-	grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]);
++      grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"),
++		  argv[0]);
+       goto fail;
+     }
+ 
+-  grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
+-
+   if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED)
+     {
+-      rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size);
++      rc = grub_linuxefi_secure_validate (kernel, filelen);
+       if (rc <= 0)
+ 	{
+ 	  grub_error (GRUB_ERR_INVALID_COMMAND,
+@@ -375,8 +381,32 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 	}
+     }
+ 
+-  pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset);
+-  handover_offset = pe->opt.entry_addr;
++  if (grub_arch_efi_linux_check_image (kernel) != GRUB_ERR_NONE)
++    goto fail;
++  if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align) != GRUB_ERR_NONE)
++    goto fail;
++  grub_dprintf ("linux", "kernel mem size     : %lld\n", (long long) kernel_size);
++  grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset);
++  grub_dprintf ("linux", "kernel alignment    : 0x%x\n", align);
++
++  grub_loader_unset();
++
++  kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1);
++  kernel_alloc_addr = grub_efi_allocate_any_pages (kernel_alloc_pages);
++  grub_dprintf ("linux", "kernel numpages: %d\n", kernel_alloc_pages);
++  if (!kernel_alloc_addr)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
++      goto fail;
++    }
++  kernel_addr = (void *)ALIGN_UP((grub_uint64_t)kernel_alloc_addr, align);
++
++  grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
++  grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size));
++  if (kernel_size > filelen)
++    grub_memset ((char *)kernel_addr + filelen, 0, kernel_size - filelen);
++  grub_free(kernel);
++  kernel = NULL;
+ 
+   cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE);
+   linux_args = grub_malloc (cmdline_size);
+@@ -400,6 +430,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+     }
+ 
+ fail:
++  if (kernel)
++    grub_free (kernel);
++
+   if (file)
+     grub_file_close (file);
+ 
+@@ -412,9 +445,8 @@ fail:
+   if (linux_args && !loaded)
+     grub_free (linux_args);
+ 
+-  if (kernel_addr && !loaded)
+-    grub_efi_free_pages ((grub_addr_t) kernel_addr,
+-			 GRUB_EFI_BYTES_TO_PAGES (kernel_size));
++  if (kernel_alloc_addr && !loaded)
++    grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages);
+ 
+   return grub_errno;
+ }
+diff --git a/include/grub/arm/linux.h b/include/grub/arm/linux.h
+index b582f67f66..966a5074f5 100644
+--- a/include/grub/arm/linux.h
++++ b/include/grub/arm/linux.h
+@@ -44,6 +44,7 @@ struct grub_arm_linux_pe_header
+ 
+ #if defined(__arm__)
+ # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM_MAGIC_SIGNATURE
++# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE32_MAGIC
+ # define linux_arch_kernel_header linux_arm_kernel_header
+ # define grub_armxx_linux_pe_header grub_arm_linux_pe_header
+ #endif
+diff --git a/include/grub/arm64/linux.h b/include/grub/arm64/linux.h
+index ea030312df..422bf2bf24 100644
+--- a/include/grub/arm64/linux.h
++++ b/include/grub/arm64/linux.h
+@@ -48,6 +48,7 @@ struct grub_arm64_linux_pe_header
+ 
+ #if defined(__aarch64__)
+ # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM64_MAGIC_SIGNATURE
++# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE64_MAGIC
+ # define linux_arch_kernel_header linux_arm64_kernel_header
+ # define grub_armxx_linux_pe_header grub_arm64_linux_pe_header
+ #endif
diff --git a/SOURCES/0185-posix_wrap-tweaks-in-preparation-for-libtasn1.patch b/SOURCES/0185-posix_wrap-tweaks-in-preparation-for-libtasn1.patch
deleted file mode 100644
index a09cab1..0000000
--- a/SOURCES/0185-posix_wrap-tweaks-in-preparation-for-libtasn1.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Sat, 2 May 2020 00:27:57 +1000
-Subject: [PATCH] posix_wrap: tweaks in preparation for libtasn1
-
- - Define SIZEOF_UNSIGNED_LONG_INT, it's the same as
-   SIZEOF_UNSIGNED_LONG.
-
- - Define WORD_BIT, the size in bits of an int. This is a defined
-   in the Single Unix Specification and in gnulib's limits.h. gnulib
-   assumes it's 32 bits on all our platforms, including 64 bit
-   platforms, so we also use that value.
-
- - Provide strto[u]l[l] preprocessor macros that resolve to
-   grub_strto[u]l[l]. To avoid gcrypt redefining strtoul, we
-   also define HAVE_STRTOUL here.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/lib/posix_wrap/limits.h    | 1 +
- grub-core/lib/posix_wrap/stdlib.h    | 8 ++++++++
- grub-core/lib/posix_wrap/sys/types.h | 1 +
- 3 files changed, 10 insertions(+)
-
-diff --git a/grub-core/lib/posix_wrap/limits.h b/grub-core/lib/posix_wrap/limits.h
-index 7217138ffd6..591dbf3289d 100644
---- a/grub-core/lib/posix_wrap/limits.h
-+++ b/grub-core/lib/posix_wrap/limits.h
-@@ -37,5 +37,6 @@
- #define LONG_MAX GRUB_LONG_MAX
- 
- #define CHAR_BIT 8
-+#define WORD_BIT 32
- 
- #endif
-diff --git a/grub-core/lib/posix_wrap/stdlib.h b/grub-core/lib/posix_wrap/stdlib.h
-index 7a8d385e973..4634db09f29 100644
---- a/grub-core/lib/posix_wrap/stdlib.h
-+++ b/grub-core/lib/posix_wrap/stdlib.h
-@@ -58,4 +58,12 @@ abs (int c)
-   return (c >= 0) ? c : -c;
- }
- 
-+#define strtol grub_strtol
-+
-+/* for libgcrypt */
-+#define HAVE_STRTOUL
-+#define strtoul grub_strtoul
-+
-+#define strtoull grub_strtoull
-+
- #endif
-diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h
-index 854eb0122ef..f63412c8da0 100644
---- a/grub-core/lib/posix_wrap/sys/types.h
-+++ b/grub-core/lib/posix_wrap/sys/types.h
-@@ -51,6 +51,7 @@ typedef grub_uint8_t byte;
- typedef grub_addr_t uintptr_t;
- 
- #define SIZEOF_UNSIGNED_LONG GRUB_CPU_SIZEOF_LONG
-+#define SIZEOF_UNSIGNED_LONG_INT GRUB_CPU_SIZEOF_LONG
- #define SIZEOF_UNSIGNED_INT 4
- #define SIZEOF_UNSIGNED_LONG_LONG 8
- #define SIZEOF_UNSIGNED_SHORT 2
diff --git a/SOURCES/0186-libtasn1-import-libtasn1-4.16.0.patch b/SOURCES/0186-libtasn1-import-libtasn1-4.16.0.patch
deleted file mode 100644
index 89552c8..0000000
--- a/SOURCES/0186-libtasn1-import-libtasn1-4.16.0.patch
+++ /dev/null
@@ -1,8934 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Wed, 10 Jun 2020 16:31:22 +1000
-Subject: [PATCH] libtasn1: import libtasn1-4.16.0
-
-Import a very trimmed-down set of libtasn1 files:
-
-pushd /tmp
-wget https://ftp.gnu.org/gnu/libtasn1/libtasn1-4.16.0.tar.gz
-popd
-pushd grub-core/lib
-mkdir libtasn1
-cp /tmp/libtasn1-4.16.0/{README.md,LICENSE} libtasn1/
-mkdir libtasn1/lib
-cp /tmp/libtasn1-4.16.0/lib/{coding.c,decoding.c,element.c,element.h,errors.c,gstr.c,gstr.h,int.h,parser_aux.c,parser_aux.h,structure.c,structure.h}  libtasn1/lib
-cp /tmp/libtasn1-4.16.0/lib/includes/libtasn1.h ../../include/grub/
-git add libtasn1/ ../../include/grub/libtasn1.h
-popd
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/lib/libtasn1/lib/coding.c     | 1415 ++++++++++++++++++
- grub-core/lib/libtasn1/lib/decoding.c   | 2478 +++++++++++++++++++++++++++++++
- grub-core/lib/libtasn1/lib/element.c    | 1111 ++++++++++++++
- grub-core/lib/libtasn1/lib/errors.c     |  100 ++
- grub-core/lib/libtasn1/lib/gstr.c       |   74 +
- grub-core/lib/libtasn1/lib/parser_aux.c | 1173 +++++++++++++++
- grub-core/lib/libtasn1/lib/structure.c  | 1220 +++++++++++++++
- grub-core/lib/libtasn1/lib/element.h    |   40 +
- grub-core/lib/libtasn1/lib/gstr.h       |   47 +
- grub-core/lib/libtasn1/lib/int.h        |  221 +++
- grub-core/lib/libtasn1/lib/parser_aux.h |  172 +++
- grub-core/lib/libtasn1/lib/structure.h  |   45 +
- include/grub/libtasn1.h                 |  588 ++++++++
- grub-core/lib/libtasn1/LICENSE          |   16 +
- grub-core/lib/libtasn1/README.md        |   91 ++
- 15 files changed, 8791 insertions(+)
- create mode 100644 grub-core/lib/libtasn1/lib/coding.c
- create mode 100644 grub-core/lib/libtasn1/lib/decoding.c
- create mode 100644 grub-core/lib/libtasn1/lib/element.c
- create mode 100644 grub-core/lib/libtasn1/lib/errors.c
- create mode 100644 grub-core/lib/libtasn1/lib/gstr.c
- create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.c
- create mode 100644 grub-core/lib/libtasn1/lib/structure.c
- create mode 100644 grub-core/lib/libtasn1/lib/element.h
- create mode 100644 grub-core/lib/libtasn1/lib/gstr.h
- create mode 100644 grub-core/lib/libtasn1/lib/int.h
- create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.h
- create mode 100644 grub-core/lib/libtasn1/lib/structure.h
- create mode 100644 include/grub/libtasn1.h
- create mode 100644 grub-core/lib/libtasn1/LICENSE
- create mode 100644 grub-core/lib/libtasn1/README.md
-
-diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c
-new file mode 100644
-index 00000000000..245ea64cf0a
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/coding.c
-@@ -0,0 +1,1415 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+
-+/*****************************************************/
-+/* File: coding.c                                    */
-+/* Description: Functions to create a DER coding of  */
-+/*   an ASN1 type.                                   */
-+/*****************************************************/
-+
-+#include <int.h>
-+#include "parser_aux.h"
-+#include <gstr.h>
-+#include "element.h"
-+#include "minmax.h"
-+#include <structure.h>
-+
-+#define MAX_TAG_LEN 16
-+
-+/******************************************************/
-+/* Function : _asn1_error_description_value_not_found */
-+/* Description: creates the ErrorDescription string   */
-+/* for the ASN1_VALUE_NOT_FOUND error.                */
-+/* Parameters:                                        */
-+/*   node: node of the tree where the value is NULL.  */
-+/*   ErrorDescription: string returned.               */
-+/* Return:                                            */
-+/******************************************************/
-+static void
-+_asn1_error_description_value_not_found (asn1_node node,
-+					 char *ErrorDescription)
-+{
-+
-+  if (ErrorDescription == NULL)
-+    return;
-+
-+  Estrcpy (ErrorDescription, ":: value of element '");
-+  _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription),
-+			   ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40);
-+  Estrcat (ErrorDescription, "' not found");
-+
-+}
-+
-+/**
-+ * asn1_length_der:
-+ * @len: value to convert.
-+ * @der: buffer to hold the returned encoding (may be %NULL).
-+ * @der_len: number of meaningful bytes of ANS (der[0]..der[der_len-1]).
-+ *
-+ * Creates the DER encoding of the provided length value.
-+ * The @der buffer must have enough room for the output. The maximum
-+ * length this function will encode is %ASN1_MAX_LENGTH_SIZE.
-+ *
-+ * To know the size of the DER encoding use a %NULL value for @der.
-+ **/
-+void
-+asn1_length_der (unsigned long int len, unsigned char *der, int *der_len)
-+{
-+  int k;
-+  unsigned char temp[ASN1_MAX_LENGTH_SIZE];
-+#if SIZEOF_UNSIGNED_LONG_INT > 8
-+  len &= 0xFFFFFFFFFFFFFFFF;
-+#endif
-+
-+  if (len < 128)
-+    {
-+      /* short form */
-+      if (der != NULL)
-+	der[0] = (unsigned char) len;
-+      *der_len = 1;
-+    }
-+  else
-+    {
-+      /* Long form */
-+      k = 0;
-+      while (len)
-+	{
-+	  temp[k++] = len & 0xFF;
-+	  len = len >> 8;
-+	}
-+      *der_len = k + 1;
-+      if (der != NULL)
-+	{
-+	  der[0] = ((unsigned char) k & 0x7F) + 128;
-+	  while (k--)
-+	    der[*der_len - 1 - k] = temp[k];
-+	}
-+    }
-+}
-+
-+/******************************************************/
-+/* Function : _asn1_tag_der                           */
-+/* Description: creates the DER coding for the CLASS  */
-+/* and TAG parameters.                                */
-+/* It is limited by the ASN1_MAX_TAG_SIZE variable    */
-+/* Parameters:                                        */
-+/*   class: value to convert.                         */
-+/*   tag_value: value to convert.                     */
-+/*   ans: string returned.                            */
-+/*   ans_len: number of meaningful bytes of ANS       */
-+/*            (ans[0]..ans[ans_len-1]).               */
-+/* Return:                                            */
-+/******************************************************/
-+static void
-+_asn1_tag_der (unsigned char class, unsigned int tag_value,
-+	       unsigned char ans[ASN1_MAX_TAG_SIZE], int *ans_len)
-+{
-+  int k;
-+  unsigned char temp[ASN1_MAX_TAG_SIZE];
-+
-+  if (tag_value < 31)
-+    {
-+      /* short form */
-+      ans[0] = (class & 0xE0) + ((unsigned char) (tag_value & 0x1F));
-+      *ans_len = 1;
-+    }
-+  else
-+    {
-+      /* Long form */
-+      ans[0] = (class & 0xE0) + 31;
-+      k = 0;
-+      while (tag_value != 0)
-+	{
-+	  temp[k++] = tag_value & 0x7F;
-+	  tag_value >>= 7;
-+
-+	  if (k > ASN1_MAX_TAG_SIZE - 1)
-+	    break;		/* will not encode larger tags */
-+	}
-+      *ans_len = k + 1;
-+      while (k--)
-+	ans[*ans_len - 1 - k] = temp[k] + 128;
-+      ans[*ans_len - 1] -= 128;
-+    }
-+}
-+
-+/**
-+ * asn1_octet_der:
-+ * @str: the input data.
-+ * @str_len: STR length (str[0]..str[*str_len-1]).
-+ * @der: encoded string returned.
-+ * @der_len: number of meaningful bytes of DER (der[0]..der[der_len-1]).
-+ *
-+ * Creates a length-value DER encoding for the input data.
-+ * The DER encoding of the input data will be placed in the @der variable.
-+ *
-+ * Note that the OCTET STRING tag is not included in the output.
-+ *
-+ * This function does not return any value because it is expected
-+ * that @der_len will contain enough bytes to store the string
-+ * plus the DER encoding. The DER encoding size can be obtained using
-+ * asn1_length_der().
-+ **/
-+void
-+asn1_octet_der (const unsigned char *str, int str_len,
-+		unsigned char *der, int *der_len)
-+{
-+  int len_len;
-+
-+  if (der == NULL || str_len < 0)
-+    return;
-+
-+  asn1_length_der (str_len, der, &len_len);
-+  memcpy (der + len_len, str, str_len);
-+  *der_len = str_len + len_len;
-+}
-+
-+
-+/**
-+ * asn1_encode_simple_der:
-+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
-+ * @str: the string data.
-+ * @str_len: the string length
-+ * @tl: the encoded tag and length
-+ * @tl_len: the bytes of the @tl field
-+ *
-+ * Creates the DER encoding for various simple ASN.1 types like strings etc.
-+ * It stores the tag and length in @tl, which should have space for at least
-+ * %ASN1_MAX_TL_SIZE bytes. Initially @tl_len should contain the size of @tl.
-+ *
-+ * The complete DER encoding should consist of the value in @tl appended
-+ * with the provided @str.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful or an error value.
-+ **/
-+int
-+asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
-+			unsigned int str_len, unsigned char *tl,
-+			unsigned int *tl_len)
-+{
-+  int tag_len, len_len;
-+  unsigned tlen;
-+  unsigned char der_tag[ASN1_MAX_TAG_SIZE];
-+  unsigned char der_length[ASN1_MAX_LENGTH_SIZE];
-+  unsigned char *p;
-+
-+  if (str == NULL)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  if (ETYPE_OK (etype) == 0)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  /* doesn't handle constructed classes */
-+  if (ETYPE_CLASS (etype) != ASN1_CLASS_UNIVERSAL)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  _asn1_tag_der (ETYPE_CLASS (etype), ETYPE_TAG (etype), der_tag, &tag_len);
-+
-+  asn1_length_der (str_len, der_length, &len_len);
-+
-+  if (tag_len <= 0 || len_len <= 0)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  tlen = tag_len + len_len;
-+
-+  if (*tl_len < tlen)
-+    return ASN1_MEM_ERROR;
-+
-+  p = tl;
-+  memcpy (p, der_tag, tag_len);
-+  p += tag_len;
-+  memcpy (p, der_length, len_len);
-+
-+  *tl_len = tlen;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/******************************************************/
-+/* Function : _asn1_time_der                          */
-+/* Description: creates the DER coding for a TIME     */
-+/* type (length included).                            */
-+/* Parameters:                                        */
-+/*   str: TIME null-terminated string.                */
-+/*   der: string returned.                            */
-+/*   der_len: number of meaningful bytes of DER       */
-+/*            (der[0]..der[ans_len-1]). Initially it  */
-+/*            if must store the lenght of DER.        */
-+/* Return:                                            */
-+/*   ASN1_MEM_ERROR when DER isn't big enough         */
-+/*   ASN1_SUCCESS otherwise                           */
-+/******************************************************/
-+static int
-+_asn1_time_der (unsigned char *str, int str_len, unsigned char *der,
-+		int *der_len)
-+{
-+  int len_len;
-+  int max_len;
-+
-+  if (der == NULL)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  max_len = *der_len;
-+
-+  asn1_length_der (str_len, (max_len > 0) ? der : NULL, &len_len);
-+
-+  if ((len_len + str_len) <= max_len)
-+    memcpy (der + len_len, str, str_len);
-+  *der_len = len_len + str_len;
-+
-+  if ((*der_len) > max_len)
-+    return ASN1_MEM_ERROR;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/*
-+void
-+_asn1_get_utctime_der(unsigned char *der,int *der_len,unsigned char *str)
-+{
-+  int len_len,str_len;
-+  char temp[20];
-+
-+  if(str==NULL) return;
-+  str_len=asn1_get_length_der(der,*der_len,&len_len);
-+  if (str_len<0) return;
-+  memcpy(temp,der+len_len,str_len);
-+  *der_len=str_len+len_len;
-+  switch(str_len)
-+  {
-+  case 11:
-+    temp[10]=0;
-+    strcat(temp,"00+0000");
-+    break;
-+  case 13:
-+    temp[12]=0;
-+    strcat(temp,"+0000");
-+    break;
-+  case 15:
-+    temp[15]=0;
-+    memmove(temp+12,temp+10,6);
-+    temp[10]=temp[11]='0';
-+    break;
-+  case 17:
-+    temp[17]=0;
-+    break;
-+  default:
-+    return;
-+  }
-+  strcpy(str,temp);
-+}
-+*/
-+
-+static
-+void encode_val(uint64_t val, unsigned char *der, int max_len, int *der_len)
-+{
-+  int first, k;
-+  unsigned char bit7;
-+
-+  first = 0;
-+  for (k = sizeof(val); k >= 0; k--)
-+    {
-+      bit7 = (val >> (k * 7)) & 0x7F;
-+      if (bit7 || first || !k)
-+	{
-+	  if (k)
-+	    bit7 |= 0x80;
-+	  if (max_len > (*der_len))
-+	    der[*der_len] = bit7;
-+	  (*der_len)++;
-+	  first = 1;
-+	}
-+    }
-+}
-+
-+/******************************************************/
-+/* Function : _asn1_object_id_der                     */
-+/* Description: creates the DER coding for an         */
-+/* OBJECT IDENTIFIER  type (length included).         */
-+/* Parameters:                                        */
-+/*   str: OBJECT IDENTIFIER null-terminated string.   */
-+/*   der: string returned.                            */
-+/*   der_len: number of meaningful bytes of DER       */
-+/*            (der[0]..der[ans_len-1]). Initially it  */
-+/*            must store the length of DER.           */
-+/* Return:                                            */
-+/*   ASN1_MEM_ERROR when DER isn't big enough         */
-+/*   ASN1_SUCCESS if succesful                        */
-+/*   or an error value.                               */
-+/******************************************************/
-+static int
-+_asn1_object_id_der (const char *str, unsigned char *der, int *der_len)
-+{
-+  int len_len, counter, max_len;
-+  char *temp, *n_end, *n_start;
-+  uint64_t val, val1 = 0;
-+  int str_len = _asn1_strlen (str);
-+
-+  max_len = *der_len;
-+  *der_len = 0;
-+
-+  if (der == NULL && max_len > 0)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  temp = malloc (str_len + 2);
-+  if (temp == NULL)
-+    return ASN1_MEM_ALLOC_ERROR;
-+
-+  memcpy (temp, str, str_len);
-+  temp[str_len] = '.';
-+  temp[str_len + 1] = 0;
-+
-+  counter = 0;
-+  n_start = temp;
-+  while ((n_end = strchr (n_start, '.')))
-+    {
-+      *n_end = 0;
-+      val = _asn1_strtou64 (n_start, NULL, 10);
-+      counter++;
-+
-+      if (counter == 1)
-+        {
-+	  val1 = val;
-+	}
-+      else if (counter == 2)
-+	{
-+	  uint64_t val0;
-+
-+          if (val1 > 2)
-+            {
-+              free(temp);
-+              return ASN1_VALUE_NOT_VALID;
-+            }
-+          else if ((val1 == 0 || val1 == 1) && val > 39)
-+            {
-+              free(temp);
-+              return ASN1_VALUE_NOT_VALID;
-+            }
-+
-+	  val0 = 40 * val1 + val;
-+	  encode_val(val0, der, max_len, der_len);
-+	}
-+      else
-+	{
-+	  encode_val(val, der, max_len, der_len);
-+	}
-+      n_start = n_end + 1;
-+    }
-+
-+  asn1_length_der (*der_len, NULL, &len_len);
-+  if (max_len >= (*der_len + len_len))
-+    {
-+      memmove (der + len_len, der, *der_len);
-+      asn1_length_der (*der_len, der, &len_len);
-+    }
-+  *der_len += len_len;
-+
-+  free (temp);
-+
-+  if (max_len < (*der_len))
-+    return ASN1_MEM_ERROR;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/**
-+ * asn1_object_id_der:
-+ * @str: An object identifier in numeric, dot format.
-+ * @der: buffer to hold the returned encoding (may be %NULL).
-+ * @der_len: initially the size of @der; will hold the final size.
-+ * @flags: must be zero
-+ *
-+ * Creates the DER encoding of the provided object identifier.
-+ *
-+ * Returns: %ASN1_SUCCESS if DER encoding was OK, %ASN1_VALUE_NOT_VALID
-+ *   if @str is not a valid OID, %ASN1_MEM_ERROR if the @der
-+ *   vector isn't big enough and in this case @der_len will contain the
-+ *   length needed.
-+ **/
-+int asn1_object_id_der(const char *str, unsigned char *der, int *der_len, unsigned flags)
-+{
-+  unsigned char tag_der[MAX_TAG_LEN];
-+  int tag_len = 0, r;
-+  int max_len = *der_len;
-+
-+  *der_len = 0;
-+
-+  _asn1_tag_der (ETYPE_CLASS (ASN1_ETYPE_OBJECT_ID), ETYPE_TAG (ASN1_ETYPE_OBJECT_ID),
-+                 tag_der, &tag_len);
-+
-+  if (max_len > tag_len)
-+    {
-+      memcpy(der, tag_der, tag_len);
-+    }
-+  max_len -= tag_len;
-+  der += tag_len;
-+
-+  r = _asn1_object_id_der (str, der, &max_len);
-+  if (r == ASN1_MEM_ERROR || r == ASN1_SUCCESS)
-+    {
-+      *der_len = max_len + tag_len;
-+    }
-+
-+  return r;
-+}
-+
-+static const unsigned char bit_mask[] =
-+  { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80 };
-+
-+/**
-+ * asn1_bit_der:
-+ * @str: BIT string.
-+ * @bit_len: number of meaningful bits in STR.
-+ * @der: string returned.
-+ * @der_len: number of meaningful bytes of DER
-+ *   (der[0]..der[ans_len-1]).
-+ *
-+ * Creates a length-value DER encoding for the input data
-+ * as it would have been for a BIT STRING.
-+ * The DER encoded data will be copied in @der.
-+ *
-+ * Note that the BIT STRING tag is not included in the output.
-+ *
-+ * This function does not return any value because it is expected
-+ * that @der_len will contain enough bytes to store the string
-+ * plus the DER encoding. The DER encoding size can be obtained using
-+ * asn1_length_der().
-+ **/
-+void
-+asn1_bit_der (const unsigned char *str, int bit_len,
-+	      unsigned char *der, int *der_len)
-+{
-+  int len_len, len_byte, len_pad;
-+
-+  if (der == NULL)
-+    return;
-+
-+  len_byte = bit_len >> 3;
-+  len_pad = 8 - (bit_len & 7);
-+  if (len_pad == 8)
-+    len_pad = 0;
-+  else
-+    len_byte++;
-+  asn1_length_der (len_byte + 1, der, &len_len);
-+  der[len_len] = len_pad;
-+
-+  if (str)
-+    memcpy (der + len_len + 1, str, len_byte);
-+  der[len_len + len_byte] &= bit_mask[len_pad];
-+  *der_len = len_byte + len_len + 1;
-+}
-+
-+
-+/******************************************************/
-+/* Function : _asn1_complete_explicit_tag             */
-+/* Description: add the length coding to the EXPLICIT */
-+/* tags.                                              */
-+/* Parameters:                                        */
-+/*   node: pointer to the tree element.               */
-+/*   der: string with the DER coding of the whole tree*/
-+/*   counter: number of meaningful bytes of DER       */
-+/*            (der[0]..der[*counter-1]).              */
-+/*   max_len: size of der vector                      */
-+/* Return:                                            */
-+/*   ASN1_MEM_ERROR if der vector isn't big enough,   */
-+/*   otherwise ASN1_SUCCESS.                          */
-+/******************************************************/
-+static int
-+_asn1_complete_explicit_tag (asn1_node node, unsigned char *der,
-+			     int *counter, int *max_len)
-+{
-+  asn1_node p;
-+  int is_tag_implicit, len2, len3;
-+  unsigned char temp[SIZEOF_UNSIGNED_INT];
-+
-+  if (der == NULL && *max_len > 0)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  is_tag_implicit = 0;
-+
-+  if (node->type & CONST_TAG)
-+    {
-+      p = node->down;
-+      if (p == NULL)
-+        return ASN1_DER_ERROR;
-+      /* When there are nested tags we must complete them reverse to
-+         the order they were created. This is because completing a tag
-+         modifies all data within it, including the incomplete tags
-+         which store buffer positions -- simon@josefsson.org 2002-09-06
-+       */
-+      while (p->right)
-+	p = p->right;
-+      while (p && p != node->down->left)
-+	{
-+	  if (type_field (p->type) == ASN1_ETYPE_TAG)
-+	    {
-+	      if (p->type & CONST_EXPLICIT)
-+		{
-+		  len2 = strtol (p->name, NULL, 10);
-+		  _asn1_set_name (p, NULL);
-+
-+		  asn1_length_der (*counter - len2, temp, &len3);
-+		  if (len3 <= (*max_len))
-+		    {
-+		      memmove (der + len2 + len3, der + len2,
-+			       *counter - len2);
-+		      memcpy (der + len2, temp, len3);
-+		    }
-+		  *max_len -= len3;
-+		  *counter += len3;
-+		  is_tag_implicit = 0;
-+		}
-+	      else
-+		{		/* CONST_IMPLICIT */
-+		  if (!is_tag_implicit)
-+		    {
-+		      is_tag_implicit = 1;
-+		    }
-+		}
-+	    }
-+	  p = p->left;
-+	}
-+    }
-+
-+  if (*max_len < 0)
-+    return ASN1_MEM_ERROR;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+const tag_and_class_st _asn1_tags[] = {
-+  [ASN1_ETYPE_GENERALSTRING] =
-+    {ASN1_TAG_GENERALSTRING, ASN1_CLASS_UNIVERSAL, "type:GENERALSTRING"},
-+  [ASN1_ETYPE_NUMERIC_STRING] =
-+    {ASN1_TAG_NUMERIC_STRING, ASN1_CLASS_UNIVERSAL, "type:NUMERIC_STR"},
-+  [ASN1_ETYPE_IA5_STRING] =
-+    {ASN1_TAG_IA5_STRING, ASN1_CLASS_UNIVERSAL, "type:IA5_STR"},
-+  [ASN1_ETYPE_TELETEX_STRING] =
-+    {ASN1_TAG_TELETEX_STRING, ASN1_CLASS_UNIVERSAL, "type:TELETEX_STR"},
-+  [ASN1_ETYPE_PRINTABLE_STRING] =
-+    {ASN1_TAG_PRINTABLE_STRING, ASN1_CLASS_UNIVERSAL, "type:PRINTABLE_STR"},
-+  [ASN1_ETYPE_UNIVERSAL_STRING] =
-+    {ASN1_TAG_UNIVERSAL_STRING, ASN1_CLASS_UNIVERSAL, "type:UNIVERSAL_STR"},
-+  [ASN1_ETYPE_BMP_STRING] =
-+    {ASN1_TAG_BMP_STRING, ASN1_CLASS_UNIVERSAL, "type:BMP_STR"},
-+  [ASN1_ETYPE_UTF8_STRING] =
-+    {ASN1_TAG_UTF8_STRING, ASN1_CLASS_UNIVERSAL, "type:UTF8_STR"},
-+  [ASN1_ETYPE_VISIBLE_STRING] =
-+    {ASN1_TAG_VISIBLE_STRING, ASN1_CLASS_UNIVERSAL, "type:VISIBLE_STR"},
-+  [ASN1_ETYPE_OCTET_STRING] =
-+    {ASN1_TAG_OCTET_STRING, ASN1_CLASS_UNIVERSAL, "type:OCT_STR"},
-+  [ASN1_ETYPE_BIT_STRING] =
-+    {ASN1_TAG_BIT_STRING, ASN1_CLASS_UNIVERSAL, "type:BIT_STR"},
-+  [ASN1_ETYPE_OBJECT_ID] =
-+    {ASN1_TAG_OBJECT_ID, ASN1_CLASS_UNIVERSAL, "type:OBJ_ID"},
-+  [ASN1_ETYPE_NULL] = {ASN1_TAG_NULL, ASN1_CLASS_UNIVERSAL, "type:NULL"},
-+  [ASN1_ETYPE_BOOLEAN] =
-+    {ASN1_TAG_BOOLEAN, ASN1_CLASS_UNIVERSAL, "type:BOOLEAN"},
-+  [ASN1_ETYPE_INTEGER] =
-+    {ASN1_TAG_INTEGER, ASN1_CLASS_UNIVERSAL, "type:INTEGER"},
-+  [ASN1_ETYPE_ENUMERATED] =
-+    {ASN1_TAG_ENUMERATED, ASN1_CLASS_UNIVERSAL, "type:ENUMERATED"},
-+  [ASN1_ETYPE_SEQUENCE] =
-+    {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED,
-+     "type:SEQUENCE"},
-+  [ASN1_ETYPE_SEQUENCE_OF] =
-+    {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED,
-+     "type:SEQ_OF"},
-+  [ASN1_ETYPE_SET] =
-+    {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, "type:SET"},
-+  [ASN1_ETYPE_SET_OF] =
-+    {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED,
-+     "type:SET_OF"},
-+  [ASN1_ETYPE_GENERALIZED_TIME] =
-+    {ASN1_TAG_GENERALIZEDTime, ASN1_CLASS_UNIVERSAL, "type:GENERALIZED_TIME"},
-+  [ASN1_ETYPE_UTC_TIME] =
-+    {ASN1_TAG_UTCTime, ASN1_CLASS_UNIVERSAL, "type:UTC_TIME"},
-+};
-+
-+unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]);
-+
-+/******************************************************/
-+/* Function : _asn1_insert_tag_der                    */
-+/* Description: creates the DER coding of tags of one */
-+/* NODE.                                              */
-+/* Parameters:                                        */
-+/*   node: pointer to the tree element.               */
-+/*   der: string returned                             */
-+/*   counter: number of meaningful bytes of DER       */
-+/*            (counter[0]..der[*counter-1]).          */
-+/*   max_len: size of der vector                      */
-+/* Return:                                            */
-+/*   ASN1_GENERIC_ERROR if the type is unknown,       */
-+/*   ASN1_MEM_ERROR if der vector isn't big enough,   */
-+/*   otherwise ASN1_SUCCESS.                          */
-+/******************************************************/
-+static int
-+_asn1_insert_tag_der (asn1_node node, unsigned char *der, int *counter,
-+		      int *max_len)
-+{
-+  asn1_node p;
-+  int tag_len, is_tag_implicit;
-+  unsigned char class, class_implicit = 0, temp[MAX(SIZEOF_UNSIGNED_INT * 3 + 1, LTOSTR_MAX_SIZE)];
-+  unsigned long tag_implicit = 0;
-+  unsigned char tag_der[MAX_TAG_LEN];
-+
-+  is_tag_implicit = 0;
-+
-+  if (node->type & CONST_TAG)
-+    {
-+      p = node->down;
-+      while (p)
-+	{
-+	  if (type_field (p->type) == ASN1_ETYPE_TAG)
-+	    {
-+	      if (p->type & CONST_APPLICATION)
-+		class = ASN1_CLASS_APPLICATION;
-+	      else if (p->type & CONST_UNIVERSAL)
-+		class = ASN1_CLASS_UNIVERSAL;
-+	      else if (p->type & CONST_PRIVATE)
-+		class = ASN1_CLASS_PRIVATE;
-+	      else
-+		class = ASN1_CLASS_CONTEXT_SPECIFIC;
-+
-+	      if (p->type & CONST_EXPLICIT)
-+		{
-+		  if (is_tag_implicit)
-+		    _asn1_tag_der (class_implicit, tag_implicit, tag_der,
-+				   &tag_len);
-+		  else
-+		    _asn1_tag_der (class | ASN1_CLASS_STRUCTURED,
-+				   _asn1_strtoul (p->value, NULL, 10),
-+				   tag_der, &tag_len);
-+
-+		  *max_len -= tag_len;
-+		  if (der && *max_len >= 0)
-+		    memcpy (der + *counter, tag_der, tag_len);
-+		  *counter += tag_len;
-+
-+		  _asn1_ltostr (*counter, (char *) temp);
-+		  _asn1_set_name (p, (const char *) temp);
-+
-+		  is_tag_implicit = 0;
-+		}
-+	      else
-+		{		/* CONST_IMPLICIT */
-+		  if (!is_tag_implicit)
-+		    {
-+		      if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) ||
-+			  (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF)
-+			  || (type_field (node->type) == ASN1_ETYPE_SET)
-+			  || (type_field (node->type) == ASN1_ETYPE_SET_OF))
-+			class |= ASN1_CLASS_STRUCTURED;
-+		      class_implicit = class;
-+		      tag_implicit = _asn1_strtoul (p->value, NULL, 10);
-+		      is_tag_implicit = 1;
-+		    }
-+		}
-+	    }
-+	  p = p->right;
-+	}
-+    }
-+
-+  if (is_tag_implicit)
-+    {
-+      _asn1_tag_der (class_implicit, tag_implicit, tag_der, &tag_len);
-+    }
-+  else
-+    {
-+      unsigned type = type_field (node->type);
-+      switch (type)
-+	{
-+	CASE_HANDLED_ETYPES:
-+	  _asn1_tag_der (_asn1_tags[type].class, _asn1_tags[type].tag,
-+			 tag_der, &tag_len);
-+	  break;
-+	case ASN1_ETYPE_TAG:
-+	case ASN1_ETYPE_CHOICE:
-+	case ASN1_ETYPE_ANY:
-+	  tag_len = 0;
-+	  break;
-+	default:
-+	  return ASN1_GENERIC_ERROR;
-+	}
-+    }
-+
-+  *max_len -= tag_len;
-+  if (der && *max_len >= 0)
-+    memcpy (der + *counter, tag_der, tag_len);
-+  *counter += tag_len;
-+
-+  if (*max_len < 0)
-+    return ASN1_MEM_ERROR;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/******************************************************/
-+/* Function : _asn1_ordering_set                      */
-+/* Description: puts the elements of a SET type in    */
-+/* the correct order according to DER rules.          */
-+/* Parameters:                                        */
-+/*   der: string with the DER coding.                 */
-+/*   node: pointer to the SET element.                */
-+/* Return:                                            */
-+/*    ASN1_SUCCESS if successful                      */
-+/*    or an error value.                              */
-+/******************************************************/
-+static int
-+_asn1_ordering_set (unsigned char *der, int der_len, asn1_node node)
-+{
-+  struct vet
-+  {
-+    int end;
-+    unsigned long value;
-+    struct vet *next, *prev;
-+  };
-+
-+  int counter, len, len2;
-+  struct vet *first, *last, *p_vet, *p2_vet;
-+  asn1_node p;
-+  unsigned char class, *temp;
-+  unsigned long tag, t;
-+  int err;
-+
-+  counter = 0;
-+
-+  if (type_field (node->type) != ASN1_ETYPE_SET)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  p = node->down;
-+  while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) ||
-+	 (type_field (p->type) == ASN1_ETYPE_SIZE)))
-+    p = p->right;
-+
-+  if ((p == NULL) || (p->right == NULL))
-+    return ASN1_SUCCESS;
-+
-+  first = last = NULL;
-+  while (p)
-+    {
-+      p_vet = malloc (sizeof (struct vet));
-+      if (p_vet == NULL)
-+        {
-+	  err = ASN1_MEM_ALLOC_ERROR;
-+	  goto error;
-+	}
-+
-+      p_vet->next = NULL;
-+      p_vet->prev = last;
-+      if (first == NULL)
-+	first = p_vet;
-+      else
-+	last->next = p_vet;
-+      last = p_vet;
-+
-+      /* tag value calculation */
-+      err = asn1_get_tag_der (der + counter, der_len - counter, &class, &len2,
-+			      &tag);
-+      if (err != ASN1_SUCCESS)
-+	goto error;
-+
-+      t = ((unsigned int)class) << 24;
-+      p_vet->value = t | tag;
-+      counter += len2;
-+
-+      /* extraction and length */
-+      len2 = asn1_get_length_der (der + counter, der_len - counter, &len);
-+      if (len2 < 0)
-+	{
-+	  err = ASN1_DER_ERROR;
-+	  goto error;
-+	}
-+      counter += len + len2;
-+
-+      p_vet->end = counter;
-+      p = p->right;
-+    }
-+
-+  p_vet = first;
-+
-+  while (p_vet)
-+    {
-+      p2_vet = p_vet->next;
-+      counter = 0;
-+      while (p2_vet)
-+	{
-+	  if (p_vet->value > p2_vet->value)
-+	    {
-+	      /* change position */
-+	      temp = malloc (p_vet->end - counter);
-+	      if (temp == NULL)
-+		{
-+		  err = ASN1_MEM_ALLOC_ERROR;
-+		  goto error;
-+		}
-+
-+	      memcpy (temp, der + counter, p_vet->end - counter);
-+	      memcpy (der + counter, der + p_vet->end,
-+		      p2_vet->end - p_vet->end);
-+	      memcpy (der + counter + p2_vet->end - p_vet->end, temp,
-+		      p_vet->end - counter);
-+	      free (temp);
-+
-+	      tag = p_vet->value;
-+	      p_vet->value = p2_vet->value;
-+	      p2_vet->value = tag;
-+
-+	      p_vet->end = counter + (p2_vet->end - p_vet->end);
-+	    }
-+	  counter = p_vet->end;
-+
-+	  p2_vet = p2_vet->next;
-+	  p_vet = p_vet->next;
-+	}
-+
-+      if (p_vet != first)
-+	p_vet->prev->next = NULL;
-+      else
-+	first = NULL;
-+      free (p_vet);
-+      p_vet = first;
-+    }
-+  return ASN1_SUCCESS;
-+
-+error:
-+  while (first != NULL)
-+    {
-+      p_vet = first;
-+      first = first->next;
-+      free(p_vet);
-+    }
-+  return err;
-+}
-+
-+struct vet
-+{
-+  unsigned char *ptr;
-+  int size;
-+};
-+
-+static int setof_compar(const void *_e1, const void *_e2)
-+{
-+  unsigned length;
-+  const struct vet *e1 = _e1, *e2 = _e2;
-+  int rval;
-+
-+  /* The encodings of the component values of a set-of value shall
-+   * appear in ascending order, the encodings being compared
-+   * as octet strings with the shorter components being
-+   * padded at their trailing end with 0-octets.
-+   * The padding octets are for comparison purposes and
-+   * do not appear in the encodings.
-+   */
-+  length = MIN(e1->size, e2->size);
-+
-+  rval = memcmp(e1->ptr, e2->ptr, length);
-+  if (rval == 0 && e1->size != e2->size)
-+    {
-+      if (e1->size > e2->size)
-+        rval = 1;
-+      else if (e2->size > e1->size)
-+        rval = -1;
-+    }
-+
-+  return rval;
-+}
-+
-+/******************************************************/
-+/* Function : _asn1_ordering_set_of                   */
-+/* Description: puts the elements of a SET OF type in */
-+/* the correct order according to DER rules.          */
-+/* Parameters:                                        */
-+/*   der: string with the DER coding.                 */
-+/*   node: pointer to the SET OF element.             */
-+/* Return:                                            */
-+/*    ASN1_SUCCESS if successful                      */
-+/*    or an error value.                              */
-+/******************************************************/
-+static int
-+_asn1_ordering_set_of (unsigned char *der, int der_len, asn1_node node)
-+{
-+  int counter, len, len2;
-+  struct vet *list = NULL, *tlist;
-+  unsigned list_size = 0;
-+  struct vet *p_vet;
-+  asn1_node p;
-+  unsigned char class;
-+  unsigned i;
-+  unsigned char *out = NULL;
-+  int err;
-+
-+  if (der == NULL)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  counter = 0;
-+
-+  if (type_field (node->type) != ASN1_ETYPE_SET_OF)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  p = node->down;
-+  while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) ||
-+	 (type_field (p->type) == ASN1_ETYPE_SIZE)))
-+    p = p->right;
-+  if (p == NULL)
-+    return ASN1_VALUE_NOT_VALID;
-+  p = p->right;
-+
-+  if ((p == NULL) || (p->right == NULL))
-+    return ASN1_SUCCESS;
-+
-+  while (p)
-+    {
-+      list_size++;
-+      tlist = realloc (list, list_size*sizeof(struct vet));
-+      if (tlist == NULL)
-+	{
-+	  err = ASN1_MEM_ALLOC_ERROR;
-+	  goto error;
-+	}
-+      list = tlist;
-+      p_vet = &list[list_size-1];
-+
-+      p_vet->ptr = der+counter;
-+      p_vet->size = 0;
-+
-+      /* extraction of tag and length */
-+      if (der_len - counter > 0)
-+	{
-+	  err = asn1_get_tag_der (der + counter, der_len - counter, &class,
-+	                          &len, NULL);
-+	  if (err != ASN1_SUCCESS)
-+	    goto error;
-+	  counter += len;
-+          p_vet->size += len;
-+
-+	  len2 = asn1_get_length_der (der + counter, der_len - counter, &len);
-+	  if (len2 < 0)
-+	    {
-+	      err = ASN1_DER_ERROR;
-+	      goto error;
-+	    }
-+	  counter += len + len2;
-+          p_vet->size += len + len2;
-+
-+	}
-+      else
-+	{
-+	  err = ASN1_DER_ERROR;
-+	  goto error;
-+	}
-+      p = p->right;
-+    }
-+
-+  if (counter > der_len)
-+    {
-+      err = ASN1_DER_ERROR;
-+      goto error;
-+    }
-+
-+  qsort(list, list_size, sizeof(struct vet), setof_compar);
-+
-+  out = malloc(der_len);
-+  if (out == NULL)
-+    {
-+      err = ASN1_MEM_ERROR;
-+      goto error;
-+    }
-+
-+  /* the sum of p_vet->size == der_len */
-+  counter = 0;
-+  for (i = 0; i < list_size; i++)
-+    {
-+      p_vet = &list[i];
-+      memcpy(out+counter, p_vet->ptr, p_vet->size);
-+      counter += p_vet->size;
-+    }
-+  memcpy(der, out, der_len);
-+  free(out);
-+
-+  err = ASN1_SUCCESS;
-+
-+error:
-+  free(list);
-+  return err;
-+}
-+
-+/**
-+ * asn1_der_coding:
-+ * @element: pointer to an ASN1 element
-+ * @name: the name of the structure you want to encode (it must be
-+ *   inside *POINTER).
-+ * @ider: vector that will contain the DER encoding. DER must be a
-+ *   pointer to memory cells already allocated.
-+ * @len: number of bytes of *@ider: @ider[0]..@ider[len-1], Initialy
-+ *   holds the sizeof of der vector.
-+ * @ErrorDescription: return the error description or an empty
-+ *   string if success.
-+ *
-+ * Creates the DER encoding for the NAME structure (inside *POINTER
-+ * structure).
-+ *
-+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
-+ *   if @name is not a valid element, %ASN1_VALUE_NOT_FOUND if there
-+ *   is an element without a value, %ASN1_MEM_ERROR if the @ider
-+ *   vector isn't big enough and in this case @len will contain the
-+ *   length needed.
-+ **/
-+int
-+asn1_der_coding (asn1_node_const element, const char *name, void *ider, int *len,
-+		 char *ErrorDescription)
-+{
-+  asn1_node node, p, p2;
-+  unsigned char temp[MAX(LTOSTR_MAX_SIZE, SIZEOF_UNSIGNED_LONG_INT * 3 + 1)];
-+  int counter, counter_old, len2, len3, move, max_len, max_len_old;
-+  int err;
-+  unsigned char *der = ider;
-+
-+  if (ErrorDescription)
-+    ErrorDescription[0] = 0;
-+
-+  node = asn1_find_node (element, name);
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  /* Node is now a locally allocated variable.
-+   * That is because in some point we modify the
-+   * structure, and I don't know why! --nmav
-+   */
-+  node = _asn1_copy_structure3 (node);
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  max_len = *len;
-+
-+  if (der == NULL && max_len > 0)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  counter = 0;
-+  move = DOWN;
-+  p = node;
-+
-+  while (1)
-+    {
-+
-+      counter_old = counter;
-+      max_len_old = max_len;
-+      if (move != UP)
-+	{
-+          p->start = counter;
-+	  err = _asn1_insert_tag_der (p, der, &counter, &max_len);
-+	  if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
-+	    goto error;
-+	}
-+      switch (type_field (p->type))
-+	{
-+	case ASN1_ETYPE_NULL:
-+	  max_len--;
-+	  if (der != NULL && max_len >= 0)
-+	    der[counter] = 0;
-+	  counter++;
-+	  move = RIGHT;
-+	  break;
-+	case ASN1_ETYPE_BOOLEAN:
-+	  if ((p->type & CONST_DEFAULT) && (p->value == NULL))
-+	    {
-+	      counter = counter_old;
-+	      max_len = max_len_old;
-+	    }
-+	  else
-+	    {
-+	      if (p->value == NULL)
-+		{
-+		  _asn1_error_description_value_not_found (p,
-+							   ErrorDescription);
-+		  err = ASN1_VALUE_NOT_FOUND;
-+		  goto error;
-+		}
-+	      max_len -= 2;
-+	      if (der != NULL && max_len >= 0)
-+		{
-+		  der[counter++] = 1;
-+		  if (p->value[0] == 'F')
-+		    der[counter++] = 0;
-+		  else
-+		    der[counter++] = 0xFF;
-+		}
-+	      else
-+		counter += 2;
-+	    }
-+	  move = RIGHT;
-+	  break;
-+	case ASN1_ETYPE_INTEGER:
-+	case ASN1_ETYPE_ENUMERATED:
-+	  if ((p->type & CONST_DEFAULT) && (p->value == NULL))
-+	    {
-+	      counter = counter_old;
-+	      max_len = max_len_old;
-+	    }
-+	  else
-+	    {
-+	      if (p->value == NULL)
-+		{
-+		  _asn1_error_description_value_not_found (p,
-+							   ErrorDescription);
-+		  err = ASN1_VALUE_NOT_FOUND;
-+		  goto error;
-+		}
-+	      len2 = asn1_get_length_der (p->value, p->value_len, &len3);
-+	      if (len2 < 0)
-+		{
-+		  err = ASN1_DER_ERROR;
-+		  goto error;
-+		}
-+	      max_len -= len2 + len3;
-+	      if (der != NULL && max_len >= 0)
-+		memcpy (der + counter, p->value, len3 + len2);
-+	      counter += len3 + len2;
-+	    }
-+	  move = RIGHT;
-+	  break;
-+	case ASN1_ETYPE_OBJECT_ID:
-+	  if ((p->type & CONST_DEFAULT) && (p->value == NULL))
-+	    {
-+	      counter = counter_old;
-+	      max_len = max_len_old;
-+	    }
-+	  else
-+	    {
-+	      if (p->value == NULL)
-+		{
-+		  _asn1_error_description_value_not_found (p,
-+							   ErrorDescription);
-+		  err = ASN1_VALUE_NOT_FOUND;
-+		  goto error;
-+		}
-+	      len2 = max_len;
-+	      err = _asn1_object_id_der ((char*)p->value, der + counter, &len2);
-+	      if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
-+		goto error;
-+
-+	      max_len -= len2;
-+	      counter += len2;
-+	    }
-+	  move = RIGHT;
-+	  break;
-+	case ASN1_ETYPE_GENERALIZED_TIME:
-+	case ASN1_ETYPE_UTC_TIME:
-+	  if (p->value == NULL)
-+	    {
-+	      _asn1_error_description_value_not_found (p, ErrorDescription);
-+	      err = ASN1_VALUE_NOT_FOUND;
-+	      goto error;
-+	    }
-+	  len2 = max_len;
-+	  err = _asn1_time_der (p->value, p->value_len, der + counter, &len2);
-+	  if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
-+	    goto error;
-+
-+	  max_len -= len2;
-+	  counter += len2;
-+	  move = RIGHT;
-+	  break;
-+	case ASN1_ETYPE_OCTET_STRING:
-+	case ASN1_ETYPE_GENERALSTRING:
-+	case ASN1_ETYPE_NUMERIC_STRING:
-+	case ASN1_ETYPE_IA5_STRING:
-+	case ASN1_ETYPE_TELETEX_STRING:
-+	case ASN1_ETYPE_PRINTABLE_STRING:
-+	case ASN1_ETYPE_UNIVERSAL_STRING:
-+	case ASN1_ETYPE_BMP_STRING:
-+	case ASN1_ETYPE_UTF8_STRING:
-+	case ASN1_ETYPE_VISIBLE_STRING:
-+	case ASN1_ETYPE_BIT_STRING:
-+	  if (p->value == NULL)
-+	    {
-+	      _asn1_error_description_value_not_found (p, ErrorDescription);
-+	      err = ASN1_VALUE_NOT_FOUND;
-+	      goto error;
-+	    }
-+	  len2 = asn1_get_length_der (p->value, p->value_len, &len3);
-+	  if (len2 < 0)
-+	    {
-+	      err = ASN1_DER_ERROR;
-+	      goto error;
-+	    }
-+	  max_len -= len2 + len3;
-+	  if (der != NULL && max_len >= 0)
-+	    memcpy (der + counter, p->value, len3 + len2);
-+	  counter += len3 + len2;
-+	  move = RIGHT;
-+	  break;
-+	case ASN1_ETYPE_SEQUENCE:
-+	case ASN1_ETYPE_SET:
-+	  if (move != UP)
-+	    {
-+	      p->tmp_ival = counter;
-+	      if (p->down == NULL)
-+		{
-+		  move = UP;
-+		  continue;
-+		}
-+	      else
-+		{
-+		  p2 = p->down;
-+		  while (p2 && (type_field (p2->type) == ASN1_ETYPE_TAG))
-+		    p2 = p2->right;
-+		  if (p2)
-+		    {
-+		      p = p2;
-+		      move = RIGHT;
-+		      continue;
-+		    }
-+		  move = UP;
-+		  continue;
-+		}
-+	    }
-+	  else
-+	    {			/* move==UP */
-+	      len2 = p->tmp_ival;
-+	      p->tmp_ival = 0;
-+	      if ((type_field (p->type) == ASN1_ETYPE_SET) && (max_len >= 0))
-+		{
-+		  err = _asn1_ordering_set (der + len2, counter - len2, p);
-+		  if (err != ASN1_SUCCESS)
-+		    goto error;
-+		}
-+	      asn1_length_der (counter - len2, temp, &len3);
-+	      max_len -= len3;
-+	      if (der != NULL && max_len >= 0)
-+		{
-+		  memmove (der + len2 + len3, der + len2, counter - len2);
-+		  memcpy (der + len2, temp, len3);
-+		}
-+	      counter += len3;
-+	      move = RIGHT;
-+	    }
-+	  break;
-+	case ASN1_ETYPE_SEQUENCE_OF:
-+	case ASN1_ETYPE_SET_OF:
-+	  if (move != UP)
-+	    {
-+	      p->tmp_ival = counter;
-+	      p = p->down;
-+	      while ((type_field (p->type) == ASN1_ETYPE_TAG)
-+		     || (type_field (p->type) == ASN1_ETYPE_SIZE))
-+		p = p->right;
-+	      if (p->right)
-+		{
-+		  p = p->right;
-+		  move = RIGHT;
-+		  continue;
-+		}
-+	      else
-+		p = _asn1_find_up (p);
-+	      move = UP;
-+	    }
-+	  if (move == UP)
-+	    {
-+	      len2 = p->tmp_ival;
-+	      p->tmp_ival = 0;
-+	      if ((type_field (p->type) == ASN1_ETYPE_SET_OF)
-+		  && (counter - len2 > 0) && (max_len >= 0))
-+		{
-+		  err = _asn1_ordering_set_of (der + len2, counter - len2, p);
-+		  if (err != ASN1_SUCCESS)
-+		    goto error;
-+		}
-+	      asn1_length_der (counter - len2, temp, &len3);
-+	      max_len -= len3;
-+	      if (der != NULL && max_len >= 0)
-+		{
-+		  memmove (der + len2 + len3, der + len2, counter - len2);
-+		  memcpy (der + len2, temp, len3);
-+		}
-+	      counter += len3;
-+	      move = RIGHT;
-+	    }
-+	  break;
-+	case ASN1_ETYPE_ANY:
-+	  if (p->value == NULL)
-+	    {
-+	      _asn1_error_description_value_not_found (p, ErrorDescription);
-+	      err = ASN1_VALUE_NOT_FOUND;
-+	      goto error;
-+	    }
-+	  len2 = asn1_get_length_der (p->value, p->value_len, &len3);
-+	  if (len2 < 0)
-+	    {
-+	      err = ASN1_DER_ERROR;
-+	      goto error;
-+	    }
-+	  max_len -= len2;
-+	  if (der != NULL && max_len >= 0)
-+	    memcpy (der + counter, p->value + len3, len2);
-+	  counter += len2;
-+	  move = RIGHT;
-+	  break;
-+	default:
-+	  move = (move == UP) ? RIGHT : DOWN;
-+	  break;
-+	}
-+
-+      if ((move != DOWN) && (counter != counter_old))
-+	{
-+          p->end = counter - 1;
-+	  err = _asn1_complete_explicit_tag (p, der, &counter, &max_len);
-+	  if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
-+	    goto error;
-+	}
-+
-+      if (p == node && move != DOWN)
-+	break;
-+
-+      if (move == DOWN)
-+	{
-+	  if (p->down)
-+	    p = p->down;
-+	  else
-+	    move = RIGHT;
-+	}
-+      if (move == RIGHT)
-+	{
-+	  if (p->right)
-+	    p = p->right;
-+	  else
-+	    move = UP;
-+	}
-+      if (move == UP)
-+	p = _asn1_find_up (p);
-+    }
-+
-+  *len = counter;
-+
-+  if (max_len < 0)
-+    {
-+      err = ASN1_MEM_ERROR;
-+      goto error;
-+    }
-+
-+  err = ASN1_SUCCESS;
-+
-+error:
-+  asn1_delete_structure (&node);
-+  return err;
-+}
-diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c
-new file mode 100644
-index 00000000000..ff04eb778cb
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/decoding.c
-@@ -0,0 +1,2478 @@
-+/*
-+ * Copyright (C) 2002-2016 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+
-+/*****************************************************/
-+/* File: decoding.c                                  */
-+/* Description: Functions to manage DER decoding     */
-+/*****************************************************/
-+
-+#include <int.h>
-+#include <parser_aux.h>
-+#include <gstr.h>
-+#include <structure.h>
-+#include <element.h>
-+#include <limits.h>
-+#include <intprops.h>
-+#include <c-ctype.h>
-+
-+#ifdef DEBUG
-+# define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__)
-+#else
-+# define warn()
-+#endif
-+
-+#define IS_ERR(len, flags) (len < -1 || ((flags & ASN1_DECODE_FLAG_STRICT_DER) && len < 0))
-+
-+#define HAVE_TWO(x) (x>=2?1:0)
-+
-+/* Decoding flags (dflags) used in several decoding functions.
-+ *  DECODE_FLAG_HAVE_TAG: The provided buffer includes a tag
-+ *  DECODE_FLAG_CONSTRUCTED: The provided buffer is of indefinite encoding (useful
-+ *                           when no tags are present).
-+ *  DECODE_FLAG_LEVEL1: Internal flag to indicate a level of recursion for BER strings.
-+ *  DECODE_FLAG_LEVEL2: Internal flag to indicate two levels of recursion for BER strings.
-+ *  DECODE_FLAG_LEVEL3: Internal flag to indicate three levels of recursion for BER strings.
-+ *                      This is the maximum levels of recursion possible to prevent stack
-+ *                      exhaustion.
-+ */
-+
-+#define DECODE_FLAG_HAVE_TAG 1
-+#define DECODE_FLAG_CONSTRUCTED (1<<1)
-+#define DECODE_FLAG_LEVEL1 (1<<2)
-+#define DECODE_FLAG_LEVEL2 (1<<3)
-+#define DECODE_FLAG_LEVEL3 (1<<4)
-+
-+#define DECR_LEN(l, s) do { \
-+	  l -= s; \
-+	  if (l < 0) { \
-+	    warn(); \
-+	    result = ASN1_DER_ERROR; \
-+	    goto cleanup; \
-+	  } \
-+	} while (0)
-+
-+static int
-+_asn1_get_indefinite_length_string (const unsigned char *der, int der_len, int *len);
-+
-+static int
-+_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
-+			unsigned int _der_len, unsigned char **str,
-+			unsigned int *str_len, unsigned int *ber_len,
-+			unsigned dflags);
-+
-+static int
-+_asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
-+			unsigned int _der_len, const unsigned char **str,
-+			unsigned int *str_len, unsigned dflags);
-+
-+static void
-+_asn1_error_description_tag_error (asn1_node node, char *ErrorDescription)
-+{
-+
-+  Estrcpy (ErrorDescription, ":: tag error near element '");
-+  _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription),
-+			   ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40);
-+  Estrcat (ErrorDescription, "'");
-+
-+}
-+
-+/**
-+ * asn1_get_length_der:
-+ * @der: DER data to decode.
-+ * @der_len: Length of DER data to decode.
-+ * @len: Output variable containing the length of the DER length field.
-+ *
-+ * Extract a length field from DER data.
-+ *
-+ * Returns: Return the decoded length value, or -1 on indefinite
-+ *   length, or -2 when the value was too big to fit in a int, or -4
-+ *   when the decoded length value plus @len would exceed @der_len.
-+ **/
-+long
-+asn1_get_length_der (const unsigned char *der, int der_len, int *len)
-+{
-+  unsigned int ans;
-+  int k, punt, sum;
-+
-+  *len = 0;
-+  if (der_len <= 0)
-+    return 0;
-+
-+  if (!(der[0] & 128))
-+    {
-+      /* short form */
-+      *len = 1;
-+      ans = der[0];
-+    }
-+  else
-+    {
-+      /* Long form */
-+      k = der[0] & 0x7F;
-+      punt = 1;
-+      if (k)
-+	{ /* definite length method */
-+	  ans = 0;
-+	  while (punt <= k && punt < der_len)
-+	    {
-+	      if (INT_MULTIPLY_OVERFLOW (ans, 256))
-+		return -2;
-+	      ans *= 256;
-+
-+	      if (INT_ADD_OVERFLOW (ans, ((unsigned) der[punt])))
-+		return -2;
-+	      ans += der[punt];
-+	      punt++;
-+	    }
-+	}
-+      else
-+	{			/* indefinite length method */
-+	  *len = punt;
-+	  return -1;
-+	}
-+
-+      *len = punt;
-+    }
-+
-+  sum = ans;
-+  if (ans >= INT_MAX || INT_ADD_OVERFLOW (sum, (*len)))
-+    return -2;
-+  sum += *len;
-+
-+  if (sum > der_len)
-+    return -4;
-+
-+  return ans;
-+}
-+
-+/**
-+ * asn1_get_tag_der:
-+ * @der: DER data to decode.
-+ * @der_len: Length of DER data to decode.
-+ * @cls: Output variable containing decoded class.
-+ * @len: Output variable containing the length of the DER TAG data.
-+ * @tag: Output variable containing the decoded tag (may be %NULL).
-+ *
-+ * Decode the class and TAG from DER code.
-+ *
-+ * Returns: Returns %ASN1_SUCCESS on success, or an error.
-+ **/
-+int
-+asn1_get_tag_der (const unsigned char *der, int der_len,
-+		  unsigned char *cls, int *len, unsigned long *tag)
-+{
-+  unsigned int ris;
-+  int punt;
-+
-+  if (der == NULL || der_len < 2 || len == NULL)
-+    return ASN1_DER_ERROR;
-+
-+  *cls = der[0] & 0xE0;
-+  if ((der[0] & 0x1F) != 0x1F)
-+    {
-+      /* short form */
-+      *len = 1;
-+      ris = der[0] & 0x1F;
-+    }
-+  else
-+    {
-+      /* Long form */
-+      punt = 1;
-+      ris = 0;
-+      while (punt < der_len && der[punt] & 128)
-+	{
-+
-+	  if (INT_MULTIPLY_OVERFLOW (ris, 128))
-+	    return ASN1_DER_ERROR;
-+	  ris *= 128;
-+
-+	  if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F))))
-+	    return ASN1_DER_ERROR;
-+	  ris += (der[punt] & 0x7F);
-+	  punt++;
-+	}
-+
-+      if (punt >= der_len)
-+	return ASN1_DER_ERROR;
-+
-+      if (INT_MULTIPLY_OVERFLOW (ris, 128))
-+	return ASN1_DER_ERROR;
-+      ris *= 128;
-+
-+      if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F))))
-+	return ASN1_DER_ERROR;
-+      ris += (der[punt] & 0x7F);
-+      punt++;
-+
-+      *len = punt;
-+    }
-+
-+  if (tag)
-+    *tag = ris;
-+  return ASN1_SUCCESS;
-+}
-+
-+/**
-+ * asn1_get_length_ber:
-+ * @ber: BER data to decode.
-+ * @ber_len: Length of BER data to decode.
-+ * @len: Output variable containing the length of the BER length field.
-+ *
-+ * Extract a length field from BER data.  The difference to
-+ * asn1_get_length_der() is that this function will return a length
-+ * even if the value has indefinite encoding.
-+ *
-+ * Returns: Return the decoded length value, or negative value when
-+ *   the value was too big.
-+ *
-+ * Since: 2.0
-+ **/
-+long
-+asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len)
-+{
-+  int ret;
-+  long err;
-+
-+  ret = asn1_get_length_der (ber, ber_len, len);
-+
-+  if (ret == -1 && ber_len > 1)
-+    {				/* indefinite length method */
-+      err = _asn1_get_indefinite_length_string (ber + 1, ber_len-1, &ret);
-+      if (err != ASN1_SUCCESS)
-+	return -3;
-+    }
-+
-+  return ret;
-+}
-+
-+/**
-+ * asn1_get_octet_der:
-+ * @der: DER data to decode containing the OCTET SEQUENCE.
-+ * @der_len: The length of the @der data to decode.
-+ * @ret_len: Output variable containing the encoded length of the DER data.
-+ * @str: Pre-allocated output buffer to put decoded OCTET SEQUENCE in.
-+ * @str_size: Length of pre-allocated output buffer.
-+ * @str_len: Output variable containing the length of the contents of the OCTET SEQUENCE.
-+ *
-+ * Extract an OCTET SEQUENCE from DER data. Note that this function
-+ * expects the DER data past the tag field, i.e., the length and
-+ * content octets.
-+ *
-+ * Returns: Returns %ASN1_SUCCESS on success, or an error.
-+ **/
-+int
-+asn1_get_octet_der (const unsigned char *der, int der_len,
-+		    int *ret_len, unsigned char *str, int str_size,
-+		    int *str_len)
-+{
-+  int len_len = 0;
-+
-+  if (der_len <= 0)
-+    return ASN1_GENERIC_ERROR;
-+
-+  *str_len = asn1_get_length_der (der, der_len, &len_len);
-+
-+  if (*str_len < 0)
-+    return ASN1_DER_ERROR;
-+
-+  *ret_len = *str_len + len_len;
-+  if (str_size >= *str_len)
-+    {
-+      if (*str_len > 0 && str != NULL)
-+        memcpy (str, der + len_len, *str_len);
-+    }
-+  else
-+    {
-+      return ASN1_MEM_ERROR;
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/*-
-+ * _asn1_get_time_der:
-+ * @type: %ASN1_ETYPE_GENERALIZED_TIME or %ASN1_ETYPE_UTC_TIME
-+ * @der: DER data to decode containing the time
-+ * @der_len: Length of DER data to decode.
-+ * @ret_len: Output variable containing the length of the DER data.
-+ * @str: Pre-allocated output buffer to put the textual time in.
-+ * @str_size: Length of pre-allocated output buffer.
-+ * @flags: Zero or %ASN1_DECODE_FLAG_STRICT_DER
-+ *
-+ * Performs basic checks in the DER encoded time object and returns its textual form.
-+ * The textual form will be in the YYYYMMDD000000Z format for GeneralizedTime
-+ * and YYMMDD000000Z for UTCTime.
-+ *
-+ * Returns: %ASN1_SUCCESS on success, or an error.
-+ -*/
-+static int
-+_asn1_get_time_der (unsigned type, const unsigned char *der, int der_len, int *ret_len,
-+		    char *str, int str_size, unsigned flags)
-+{
-+  int len_len, str_len;
-+  unsigned i;
-+  unsigned sign_count = 0;
-+  unsigned dot_count = 0;
-+  const unsigned char *p;
-+
-+  if (der_len <= 0 || str == NULL)
-+    return ASN1_DER_ERROR;
-+
-+  str_len = asn1_get_length_der (der, der_len, &len_len);
-+  if (str_len <= 0 || str_size < str_len)
-+    return ASN1_DER_ERROR;
-+
-+  /* perform some sanity checks on the data */
-+  if (str_len < 8)
-+    {
-+      warn();
-+      return ASN1_TIME_ENCODING_ERROR;
-+    }
-+
-+  if ((flags & ASN1_DECODE_FLAG_STRICT_DER) && !(flags & ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME))
-+    {
-+      p = &der[len_len];
-+      for (i=0;i<(unsigned)(str_len-1);i++)
-+         {
-+           if (c_isdigit(p[i]) == 0)
-+             {
-+               if (type == ASN1_ETYPE_GENERALIZED_TIME)
-+                 {
-+                   /* tolerate lax encodings */
-+                   if (p[i] == '.' && dot_count == 0)
-+                     {
-+                       dot_count++;
-+                       continue;
-+                     }
-+
-+               /* This is not really valid DER, but there are
-+                * structures using that */
-+                   if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) &&
-+                       (p[i] == '+' || p[i] == '-') && sign_count == 0)
-+                     {
-+                       sign_count++;
-+                       continue;
-+                     }
-+                 }
-+
-+               warn();
-+               return ASN1_TIME_ENCODING_ERROR;
-+             }
-+         }
-+
-+      if (sign_count == 0 && p[str_len-1] != 'Z')
-+        {
-+          warn();
-+          return ASN1_TIME_ENCODING_ERROR;
-+        }
-+    }
-+  memcpy (str, der + len_len, str_len);
-+  str[str_len] = 0;
-+  *ret_len = str_len + len_len;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/**
-+ * asn1_get_object_id_der:
-+ * @der: DER data to decode containing the OBJECT IDENTIFIER
-+ * @der_len: Length of DER data to decode.
-+ * @ret_len: Output variable containing the length of the DER data.
-+ * @str: Pre-allocated output buffer to put the textual object id in.
-+ * @str_size: Length of pre-allocated output buffer.
-+ *
-+ * Converts a DER encoded object identifier to its textual form. This
-+ * function expects the DER object identifier without the tag.
-+ *
-+ * Returns: %ASN1_SUCCESS on success, or an error.
-+ **/
-+int
-+asn1_get_object_id_der (const unsigned char *der, int der_len, int *ret_len,
-+			char *str, int str_size)
-+{
-+  int len_len, len, k;
-+  int leading, parsed;
-+  char temp[LTOSTR_MAX_SIZE];
-+  uint64_t val, val1, val0;
-+
-+  *ret_len = 0;
-+  if (str && str_size > 0)
-+    str[0] = 0;			/* no oid */
-+
-+  if (str == NULL || der_len <= 0)
-+    return ASN1_GENERIC_ERROR;
-+
-+  len = asn1_get_length_der (der, der_len, &len_len);
-+
-+  if (len <= 0 || len + len_len > der_len)
-+    return ASN1_DER_ERROR;
-+
-+  /* leading octet can never be 0x80 */
-+  if (der[len_len] == 0x80)
-+    return ASN1_DER_ERROR;
-+
-+  val0 = 0;
-+
-+  for (k = 0; k < len; k++)
-+    {
-+      if (INT_LEFT_SHIFT_OVERFLOW (val0, 7))
-+	return ASN1_DER_ERROR;
-+
-+      val0 <<= 7;
-+      val0 |= der[len_len + k] & 0x7F;
-+      if (!(der[len_len + k] & 0x80))
-+	break;
-+    }
-+  parsed = ++k;
-+
-+  /* val0 = (X*40) + Y, X={0,1,2}, Y<=39 when X={0,1} */
-+  /* X = val, Y = val1 */
-+
-+  /* check if X == 0  */
-+  val = 0;
-+  val1 = val0;
-+  if (val1 > 39)
-+    {
-+      val = 1;
-+      val1 = val0 - 40;
-+      if (val1  > 39)
-+        {
-+          val = 2;
-+          val1 = val0 - 80;
-+        }
-+    }
-+
-+  _asn1_str_cpy (str, str_size, _asn1_ltostr (val, temp));
-+  _asn1_str_cat (str, str_size, ".");
-+  _asn1_str_cat (str, str_size, _asn1_ltostr (val1, temp));
-+
-+  val = 0;
-+  leading = 1;
-+  for (k = parsed; k < len; k++)
-+    {
-+      /* X.690 mandates that the leading byte must never be 0x80
-+       */
-+      if (leading != 0 && der[len_len + k] == 0x80)
-+	return ASN1_DER_ERROR;
-+      leading = 0;
-+
-+      /* check for wrap around */
-+      if (INT_LEFT_SHIFT_OVERFLOW (val, 7))
-+	return ASN1_DER_ERROR;
-+
-+      val = val << 7;
-+      val |= der[len_len + k] & 0x7F;
-+
-+      if (!(der[len_len + k] & 0x80))
-+	{
-+	  _asn1_str_cat (str, str_size, ".");
-+	  _asn1_str_cat (str, str_size, _asn1_ltostr (val, temp));
-+	  val = 0;
-+	  leading = 1;
-+	}
-+    }
-+
-+  if (INT_ADD_OVERFLOW (len, len_len))
-+    return ASN1_DER_ERROR;
-+
-+  *ret_len = len + len_len;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/**
-+ * asn1_get_bit_der:
-+ * @der: DER data to decode containing the BIT SEQUENCE.
-+ * @der_len: Length of DER data to decode.
-+ * @ret_len: Output variable containing the length of the DER data.
-+ * @str: Pre-allocated output buffer to put decoded BIT SEQUENCE in.
-+ * @str_size: Length of pre-allocated output buffer.
-+ * @bit_len: Output variable containing the size of the BIT SEQUENCE.
-+ *
-+ * Extract a BIT SEQUENCE from DER data.
-+ *
-+ * Returns: %ASN1_SUCCESS on success, or an error.
-+ **/
-+int
-+asn1_get_bit_der (const unsigned char *der, int der_len,
-+		  int *ret_len, unsigned char *str, int str_size,
-+		  int *bit_len)
-+{
-+  int len_len = 0, len_byte;
-+
-+  if (der_len <= 0)
-+    return ASN1_GENERIC_ERROR;
-+
-+  len_byte = asn1_get_length_der (der, der_len, &len_len) - 1;
-+  if (len_byte < 0)
-+    return ASN1_DER_ERROR;
-+
-+  *ret_len = len_byte + len_len + 1;
-+  *bit_len = len_byte * 8 - der[len_len];
-+
-+  if (*bit_len < 0)
-+    return ASN1_DER_ERROR;
-+
-+  if (str_size >= len_byte)
-+    {
-+      if (len_byte > 0 && str)
-+        memcpy (str, der + len_len + 1, len_byte);
-+    }
-+  else
-+    {
-+      return ASN1_MEM_ERROR;
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/* tag_len: the total tag length (explicit+inner)
-+ * inner_tag_len: the inner_tag length
-+ */
-+static int
-+_asn1_extract_tag_der (asn1_node node, const unsigned char *der, int der_len,
-+		       int *tag_len, int *inner_tag_len, unsigned flags)
-+{
-+  asn1_node p;
-+  int counter, len2, len3, is_tag_implicit;
-+  int result;
-+  unsigned long tag, tag_implicit = 0;
-+  unsigned char class, class2, class_implicit = 0;
-+
-+  if (der_len <= 0)
-+    return ASN1_GENERIC_ERROR;
-+
-+  counter = is_tag_implicit = 0;
-+
-+  if (node->type & CONST_TAG)
-+    {
-+      p = node->down;
-+      while (p)
-+	{
-+	  if (type_field (p->type) == ASN1_ETYPE_TAG)
-+	    {
-+	      if (p->type & CONST_APPLICATION)
-+		class2 = ASN1_CLASS_APPLICATION;
-+	      else if (p->type & CONST_UNIVERSAL)
-+		class2 = ASN1_CLASS_UNIVERSAL;
-+	      else if (p->type & CONST_PRIVATE)
-+		class2 = ASN1_CLASS_PRIVATE;
-+	      else
-+		class2 = ASN1_CLASS_CONTEXT_SPECIFIC;
-+
-+	      if (p->type & CONST_EXPLICIT)
-+		{
-+		  if (asn1_get_tag_der
-+		      (der + counter, der_len, &class, &len2,
-+		       &tag) != ASN1_SUCCESS)
-+		    return ASN1_DER_ERROR;
-+
-+                  DECR_LEN(der_len, len2);
-+		  counter += len2;
-+
-+		  if (flags & ASN1_DECODE_FLAG_STRICT_DER)
-+		    len3 =
-+		      asn1_get_length_der (der + counter, der_len,
-+					 &len2);
-+		  else
-+		    len3 =
-+		      asn1_get_length_ber (der + counter, der_len,
-+					 &len2);
-+		  if (len3 < 0)
-+		    return ASN1_DER_ERROR;
-+
-+                  DECR_LEN(der_len, len2);
-+		  counter += len2;
-+
-+		  if (!is_tag_implicit)
-+		    {
-+		      if ((class != (class2 | ASN1_CLASS_STRUCTURED)) ||
-+			  (tag != strtoul ((char *) p->value, NULL, 10)))
-+			return ASN1_TAG_ERROR;
-+		    }
-+		  else
-+		    {		/* ASN1_TAG_IMPLICIT */
-+		      if ((class != class_implicit) || (tag != tag_implicit))
-+			return ASN1_TAG_ERROR;
-+		    }
-+		  is_tag_implicit = 0;
-+		}
-+	      else
-+		{		/* ASN1_TAG_IMPLICIT */
-+		  if (!is_tag_implicit)
-+		    {
-+		      if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) ||
-+			  (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF)
-+			  || (type_field (node->type) == ASN1_ETYPE_SET)
-+			  || (type_field (node->type) == ASN1_ETYPE_SET_OF))
-+			class2 |= ASN1_CLASS_STRUCTURED;
-+		      class_implicit = class2;
-+		      tag_implicit = strtoul ((char *) p->value, NULL, 10);
-+		      is_tag_implicit = 1;
-+		    }
-+		}
-+	    }
-+	  p = p->right;
-+	}
-+    }
-+
-+  if (is_tag_implicit)
-+    {
-+      if (asn1_get_tag_der
-+	  (der + counter, der_len, &class, &len2,
-+	   &tag) != ASN1_SUCCESS)
-+	return ASN1_DER_ERROR;
-+
-+      DECR_LEN(der_len, len2);
-+
-+      if ((class != class_implicit) || (tag != tag_implicit))
-+	{
-+	  if (type_field (node->type) == ASN1_ETYPE_OCTET_STRING)
-+	    {
-+	      class_implicit |= ASN1_CLASS_STRUCTURED;
-+	      if ((class != class_implicit) || (tag != tag_implicit))
-+		return ASN1_TAG_ERROR;
-+	    }
-+	  else
-+	    return ASN1_TAG_ERROR;
-+	}
-+    }
-+  else
-+    {
-+      unsigned type = type_field (node->type);
-+      if (type == ASN1_ETYPE_TAG)
-+	{
-+	  *tag_len = 0;
-+	  if (inner_tag_len)
-+	    *inner_tag_len = 0;
-+	  return ASN1_SUCCESS;
-+	}
-+
-+      if (asn1_get_tag_der
-+	  (der + counter, der_len, &class, &len2,
-+	   &tag) != ASN1_SUCCESS)
-+	return ASN1_DER_ERROR;
-+
-+      DECR_LEN(der_len, len2);
-+
-+      switch (type)
-+	{
-+	case ASN1_ETYPE_NULL:
-+	case ASN1_ETYPE_BOOLEAN:
-+	case ASN1_ETYPE_INTEGER:
-+	case ASN1_ETYPE_ENUMERATED:
-+	case ASN1_ETYPE_OBJECT_ID:
-+	case ASN1_ETYPE_GENERALSTRING:
-+	case ASN1_ETYPE_NUMERIC_STRING:
-+	case ASN1_ETYPE_IA5_STRING:
-+	case ASN1_ETYPE_TELETEX_STRING:
-+	case ASN1_ETYPE_PRINTABLE_STRING:
-+	case ASN1_ETYPE_UNIVERSAL_STRING:
-+	case ASN1_ETYPE_BMP_STRING:
-+	case ASN1_ETYPE_UTF8_STRING:
-+	case ASN1_ETYPE_VISIBLE_STRING:
-+	case ASN1_ETYPE_BIT_STRING:
-+	case ASN1_ETYPE_SEQUENCE:
-+	case ASN1_ETYPE_SEQUENCE_OF:
-+	case ASN1_ETYPE_SET:
-+	case ASN1_ETYPE_SET_OF:
-+	case ASN1_ETYPE_GENERALIZED_TIME:
-+	case ASN1_ETYPE_UTC_TIME:
-+	  if ((class != _asn1_tags[type].class)
-+	      || (tag != _asn1_tags[type].tag))
-+	    return ASN1_DER_ERROR;
-+	  break;
-+
-+	case ASN1_ETYPE_OCTET_STRING:
-+	  /* OCTET STRING is handled differently to allow
-+	   * BER encodings (structured class). */
-+	  if (((class != ASN1_CLASS_UNIVERSAL)
-+	       && (class != (ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED)))
-+	      || (tag != ASN1_TAG_OCTET_STRING))
-+	    return ASN1_DER_ERROR;
-+	  break;
-+	case ASN1_ETYPE_ANY:
-+	  counter -= len2;
-+	  break;
-+	case ASN1_ETYPE_CHOICE:
-+	  counter -= len2;
-+	  break;
-+	default:
-+	  return ASN1_DER_ERROR;
-+	  break;
-+	}
-+    }
-+
-+  counter += len2;
-+  *tag_len = counter;
-+  if (inner_tag_len)
-+    *inner_tag_len = len2;
-+  return ASN1_SUCCESS;
-+
-+cleanup:
-+  return result;
-+}
-+
-+static int
-+extract_tag_der_recursive(asn1_node node, const unsigned char *der, int der_len,
-+		       int *ret_len, int *inner_len, unsigned flags)
-+{
-+asn1_node p;
-+int ris = ASN1_DER_ERROR;
-+
-+  if (type_field (node->type) == ASN1_ETYPE_CHOICE)
-+    {
-+      p = node->down;
-+      while (p)
-+        {
-+          ris = _asn1_extract_tag_der (p, der, der_len, ret_len, inner_len, flags);
-+          if (ris == ASN1_SUCCESS)
-+            break;
-+          p = p->right;
-+	}
-+
-+      *ret_len = 0;
-+      return ris;
-+    }
-+  else
-+    return _asn1_extract_tag_der (node, der, der_len, ret_len, inner_len, flags);
-+}
-+
-+static int
-+_asn1_delete_not_used (asn1_node node)
-+{
-+  asn1_node p, p2;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node;
-+  while (p)
-+    {
-+      if (p->type & CONST_NOT_USED)
-+	{
-+	  p2 = NULL;
-+	  if (p != node)
-+	    {
-+	      p2 = _asn1_find_left (p);
-+	      if (!p2)
-+		p2 = _asn1_find_up (p);
-+	    }
-+	  asn1_delete_structure (&p);
-+	  p = p2;
-+	}
-+
-+      if (!p)
-+	break;			/* reach node */
-+
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	}
-+      else
-+	{
-+	  if (p == node)
-+	    p = NULL;
-+	  else if (p->right)
-+	    p = p->right;
-+	  else
-+	    {
-+	      while (1)
-+		{
-+		  p = _asn1_find_up (p);
-+		  if (p == node)
-+		    {
-+		      p = NULL;
-+		      break;
-+		    }
-+		  if (p->right)
-+		    {
-+		      p = p->right;
-+		      break;
-+		    }
-+		}
-+	    }
-+	}
-+    }
-+  return ASN1_SUCCESS;
-+}
-+
-+static int
-+_asn1_get_indefinite_length_string (const unsigned char *der,
-+				    int der_len, int *len)
-+{
-+  int len2, len3, counter, indefinite;
-+  int result;
-+  unsigned long tag;
-+  unsigned char class;
-+
-+  counter = indefinite = 0;
-+
-+  while (1)
-+    {
-+      if (HAVE_TWO(der_len) && (der[counter] == 0) && (der[counter + 1] == 0))
-+	{
-+	  counter += 2;
-+	  DECR_LEN(der_len, 2);
-+
-+	  indefinite--;
-+	  if (indefinite <= 0)
-+	    break;
-+	  else
-+	    continue;
-+	}
-+
-+      if (asn1_get_tag_der
-+	  (der + counter, der_len, &class, &len2,
-+	   &tag) != ASN1_SUCCESS)
-+	return ASN1_DER_ERROR;
-+
-+      DECR_LEN(der_len, len2);
-+      counter += len2;
-+
-+      len2 = asn1_get_length_der (der + counter, der_len, &len3);
-+      if (len2 < -1)
-+	return ASN1_DER_ERROR;
-+
-+      if (len2 == -1)
-+	{
-+	  indefinite++;
-+	  counter += 1;
-+          DECR_LEN(der_len, 1);
-+	}
-+      else
-+	{
-+	  counter += len2 + len3;
-+          DECR_LEN(der_len, len2+len3);
-+	}
-+    }
-+
-+  *len = counter;
-+  return ASN1_SUCCESS;
-+
-+cleanup:
-+  return result;
-+}
-+
-+static void delete_unneeded_choice_fields(asn1_node p)
-+{
-+  asn1_node p2;
-+
-+  while (p->right)
-+    {
-+      p2 = p->right;
-+      asn1_delete_structure (&p2);
-+    }
-+}
-+
-+
-+/**
-+ * asn1_der_decoding2
-+ * @element: pointer to an ASN1 structure.
-+ * @ider: vector that contains the DER encoding.
-+ * @max_ider_len: pointer to an integer giving the information about the
-+ *   maximal number of bytes occupied by *@ider. The real size of the DER
-+ *   encoding is returned through this pointer.
-+ * @flags: flags controlling the behaviour of the function.
-+ * @errorDescription: null-terminated string contains details when an
-+ *   error occurred.
-+ *
-+ * Fill the structure *@element with values of a DER encoding string. The
-+ * structure must just be created with function asn1_create_element().
-+ *
-+ * If %ASN1_DECODE_FLAG_ALLOW_PADDING flag is set then the function will ignore
-+ * padding after the decoded DER data. Upon a successful return the value of
-+ * *@max_ider_len will be set to the number of bytes decoded.
-+ *
-+ * If %ASN1_DECODE_FLAG_STRICT_DER flag is set then the function will
-+ * not decode any BER-encoded elements.
-+ *
-+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
-+ *   if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or
-+ *   %ASN1_DER_ERROR if the der encoding doesn't match the structure
-+ *   name (*@ELEMENT deleted).
-+ **/
-+int
-+asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len,
-+		    unsigned int flags, char *errorDescription)
-+{
-+  asn1_node node, p, p2, p3;
-+  char temp[128];
-+  int counter, len2, len3, len4, move, ris, tlen;
-+  struct node_tail_cache_st tcache = {NULL, NULL};
-+  unsigned char class;
-+  unsigned long tag;
-+  int tag_len;
-+  int indefinite, result, total_len = *max_ider_len, ider_len = *max_ider_len;
-+  int inner_tag_len;
-+  unsigned char *ptmp;
-+  const unsigned char *ptag;
-+  const unsigned char *der = ider;
-+
-+  node = *element;
-+
-+  if (errorDescription != NULL)
-+    errorDescription[0] = 0;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  if (node->type & CONST_OPTION)
-+    {
-+      result = ASN1_GENERIC_ERROR;
-+      warn();
-+      goto cleanup;
-+    }
-+
-+  counter = 0;
-+  move = DOWN;
-+  p = node;
-+  while (1)
-+    {
-+      tag_len = 0;
-+      inner_tag_len = 0;
-+      ris = ASN1_SUCCESS;
-+      if (move != UP)
-+	{
-+	  if (p->type & CONST_SET)
-+	    {
-+	      p2 = _asn1_find_up (p);
-+	      len2 = p2->tmp_ival;
-+	      if (len2 == -1)
-+		{
-+		  if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1])
-+		    {
-+		      p = p2;
-+		      move = UP;
-+		      counter += 2;
-+		      DECR_LEN(ider_len, 2);
-+		      continue;
-+		    }
-+		}
-+	      else if (counter == len2)
-+		{
-+		  p = p2;
-+		  move = UP;
-+		  continue;
-+		}
-+	      else if (counter > len2)
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+	      p2 = p2->down;
-+	      while (p2)
-+		{
-+		  if ((p2->type & CONST_SET) && (p2->type & CONST_NOT_USED))
-+		    {
-+		      ris =
-+			  extract_tag_der_recursive (p2, der + counter,
-+						     ider_len, &len2, NULL, flags);
-+		      if (ris == ASN1_SUCCESS)
-+			{
-+			  p2->type &= ~CONST_NOT_USED;
-+			  p = p2;
-+			  break;
-+			}
-+		    }
-+		  p2 = p2->right;
-+		}
-+	      if (p2 == NULL)
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+	    }
-+
-+	  /* the position in the DER structure this starts */
-+	  p->start = counter;
-+	  p->end = total_len - 1;
-+
-+	  if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT))
-+	    {
-+	      p2 = _asn1_find_up (p);
-+	      len2 = p2->tmp_ival;
-+	      if (counter == len2)
-+		{
-+		  if (p->right)
-+		    {
-+		      p2 = p->right;
-+		      move = RIGHT;
-+		    }
-+		  else
-+		    move = UP;
-+
-+		  if (p->type & CONST_OPTION)
-+		    asn1_delete_structure (&p);
-+
-+		  p = p2;
-+		  continue;
-+		}
-+	    }
-+
-+	  if (type_field (p->type) == ASN1_ETYPE_CHOICE)
-+	    {
-+	      while (p->down)
-+		{
-+		  ris =
-+		      extract_tag_der_recursive (p->down, der + counter,
-+					         ider_len, &len2, NULL, flags);
-+
-+		  if (ris == ASN1_SUCCESS)
-+		    {
-+		      delete_unneeded_choice_fields(p->down);
-+		      break;
-+		    }
-+		  else if (ris == ASN1_ERROR_TYPE_ANY)
-+		    {
-+		      result = ASN1_ERROR_TYPE_ANY;
-+                      warn();
-+		      goto cleanup;
-+		    }
-+		  else
-+		    {
-+		      p2 = p->down;
-+		      asn1_delete_structure (&p2);
-+		    }
-+		}
-+
-+	      if (p->down == NULL)
-+		{
-+		  if (!(p->type & CONST_OPTION))
-+		    {
-+		      result = ASN1_DER_ERROR;
-+                      warn();
-+		      goto cleanup;
-+		    }
-+		}
-+	      else if (type_field (p->type) != ASN1_ETYPE_CHOICE)
-+		p = p->down;
-+
-+	      p->start = counter;
-+	    }
-+
-+	  if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT))
-+	    {
-+	      p2 = _asn1_find_up (p);
-+	      len2 = p2->tmp_ival;
-+
-+	      if ((len2 != -1) && (counter > len2))
-+		ris = ASN1_TAG_ERROR;
-+	    }
-+
-+	  if (ris == ASN1_SUCCESS)
-+	    ris =
-+	      extract_tag_der_recursive (p, der + counter, ider_len,
-+	                                 &tag_len, &inner_tag_len, flags);
-+
-+	  if (ris != ASN1_SUCCESS)
-+	    {
-+	      if (p->type & CONST_OPTION)
-+		{
-+		  p->type |= CONST_NOT_USED;
-+		  move = RIGHT;
-+		}
-+	      else if (p->type & CONST_DEFAULT)
-+		{
-+		  _asn1_set_value (p, NULL, 0);
-+		  move = RIGHT;
-+		}
-+	      else
-+		{
-+		  if (errorDescription != NULL)
-+		    _asn1_error_description_tag_error (p, errorDescription);
-+
-+		  result = ASN1_TAG_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+	    }
-+	  else
-+	    {
-+	      DECR_LEN(ider_len, tag_len);
-+	      counter += tag_len;
-+	    }
-+	}
-+
-+      if (ris == ASN1_SUCCESS)
-+	{
-+	  switch (type_field (p->type))
-+	    {
-+	    case ASN1_ETYPE_NULL:
-+	      DECR_LEN(ider_len, 1);
-+	      if (der[counter])
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+	      counter++;
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_BOOLEAN:
-+	      DECR_LEN(ider_len, 2);
-+
-+	      if (der[counter++] != 1)
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+	      if (der[counter++] == 0)
-+		_asn1_set_value (p, "F", 1);
-+	      else
-+		_asn1_set_value (p, "T", 1);
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_INTEGER:
-+	    case ASN1_ETYPE_ENUMERATED:
-+	      len2 =
-+		asn1_get_length_der (der + counter, ider_len, &len3);
-+	      if (len2 < 0)
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+
-+	      DECR_LEN(ider_len, len3+len2);
-+
-+	      _asn1_set_value (p, der + counter, len3 + len2);
-+	      counter += len3 + len2;
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_OBJECT_ID:
-+	      result =
-+		asn1_get_object_id_der (der + counter, ider_len, &len2,
-+					temp, sizeof (temp));
-+	      if (result != ASN1_SUCCESS)
-+	        {
-+                  warn();
-+		  goto cleanup;
-+		}
-+
-+	      DECR_LEN(ider_len, len2);
-+
-+	      tlen = strlen (temp);
-+	      if (tlen > 0)
-+		_asn1_set_value (p, temp, tlen + 1);
-+
-+	      counter += len2;
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_GENERALIZED_TIME:
-+	    case ASN1_ETYPE_UTC_TIME:
-+	      result =
-+		_asn1_get_time_der (type_field (p->type), der + counter, ider_len, &len2, temp,
-+				    sizeof (temp) - 1, flags);
-+	      if (result != ASN1_SUCCESS)
-+	        {
-+                  warn();
-+                  goto cleanup;
-+                }
-+
-+	      DECR_LEN(ider_len, len2);
-+
-+	      tlen = strlen (temp);
-+	      if (tlen > 0)
-+		_asn1_set_value (p, temp, tlen);
-+
-+	      counter += len2;
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_OCTET_STRING:
-+	      if (counter < inner_tag_len)
-+	        {
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+	        }
-+
-+              ptag = der + counter - inner_tag_len;
-+              if ((flags & ASN1_DECODE_FLAG_STRICT_DER) || !(ptag[0] & ASN1_CLASS_STRUCTURED))
-+                {
-+	          if (ptag[0] & ASN1_CLASS_STRUCTURED)
-+		    {
-+		      result = ASN1_DER_ERROR;
-+                      warn();
-+		      goto cleanup;
-+		    }
-+
-+	          len2 =
-+		    asn1_get_length_der (der + counter, ider_len, &len3);
-+	          if (len2 < 0)
-+		    {
-+		      result = ASN1_DER_ERROR;
-+                      warn();
-+		      goto cleanup;
-+		    }
-+
-+	          DECR_LEN(ider_len, len3+len2);
-+
-+	          _asn1_set_value (p, der + counter, len3 + len2);
-+	          counter += len3 + len2;
-+                }
-+              else
-+                {
-+                  unsigned dflags = 0, vlen, ber_len;
-+
-+                  if (ptag[0] & ASN1_CLASS_STRUCTURED)
-+                    dflags |= DECODE_FLAG_CONSTRUCTED;
-+
-+                  result = _asn1_decode_simple_ber(type_field (p->type), der+counter, ider_len, &ptmp, &vlen, &ber_len, dflags);
-+                  if (result != ASN1_SUCCESS)
-+	            {
-+                      warn();
-+		      goto cleanup;
-+		    }
-+
-+		  DECR_LEN(ider_len, ber_len);
-+
-+		  _asn1_set_value_lv (p, ptmp, vlen);
-+
-+	          counter += ber_len;
-+	          free(ptmp);
-+                }
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_GENERALSTRING:
-+	    case ASN1_ETYPE_NUMERIC_STRING:
-+	    case ASN1_ETYPE_IA5_STRING:
-+	    case ASN1_ETYPE_TELETEX_STRING:
-+	    case ASN1_ETYPE_PRINTABLE_STRING:
-+	    case ASN1_ETYPE_UNIVERSAL_STRING:
-+	    case ASN1_ETYPE_BMP_STRING:
-+	    case ASN1_ETYPE_UTF8_STRING:
-+	    case ASN1_ETYPE_VISIBLE_STRING:
-+	    case ASN1_ETYPE_BIT_STRING:
-+	      len2 =
-+		asn1_get_length_der (der + counter, ider_len, &len3);
-+	      if (len2 < 0)
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+
-+	      DECR_LEN(ider_len, len3+len2);
-+
-+	      _asn1_set_value (p, der + counter, len3 + len2);
-+	      counter += len3 + len2;
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_SEQUENCE:
-+	    case ASN1_ETYPE_SET:
-+	      if (move == UP)
-+		{
-+		  len2 = p->tmp_ival;
-+		  p->tmp_ival = 0;
-+		  if (len2 == -1)
-+		    {		/* indefinite length method */
-+		      DECR_LEN(ider_len, 2);
-+		      if ((der[counter]) || der[counter + 1])
-+		        {
-+		          result = ASN1_DER_ERROR;
-+                          warn();
-+		          goto cleanup;
-+			}
-+		      counter += 2;
-+		    }
-+		  else
-+		    {		/* definite length method */
-+		      if (len2 != counter)
-+			{
-+			  result = ASN1_DER_ERROR;
-+                          warn();
-+			  goto cleanup;
-+			}
-+		    }
-+		  move = RIGHT;
-+		}
-+	      else
-+		{		/* move==DOWN || move==RIGHT */
-+		  len3 =
-+		    asn1_get_length_der (der + counter, ider_len, &len2);
-+                  if (IS_ERR(len3, flags))
-+		    {
-+		      result = ASN1_DER_ERROR;
-+                      warn();
-+		      goto cleanup;
-+		    }
-+
-+	          DECR_LEN(ider_len, len2);
-+		  counter += len2;
-+
-+		  if (len3 > 0)
-+		    {
-+		      p->tmp_ival = counter + len3;
-+		      move = DOWN;
-+		    }
-+		  else if (len3 == 0)
-+		    {
-+		      p2 = p->down;
-+		      while (p2)
-+			{
-+			  if (type_field (p2->type) != ASN1_ETYPE_TAG)
-+			    {
-+			      p3 = p2->right;
-+			      asn1_delete_structure (&p2);
-+			      p2 = p3;
-+			    }
-+			  else
-+			    p2 = p2->right;
-+			}
-+		      move = RIGHT;
-+		    }
-+		  else
-+		    {		/* indefinite length method */
-+		      p->tmp_ival = -1;
-+		      move = DOWN;
-+		    }
-+		}
-+	      break;
-+	    case ASN1_ETYPE_SEQUENCE_OF:
-+	    case ASN1_ETYPE_SET_OF:
-+	      if (move == UP)
-+		{
-+		  len2 = p->tmp_ival;
-+		  if (len2 == -1)
-+		    {		/* indefinite length method */
-+		      if (!HAVE_TWO(ider_len) || ((der[counter]) || der[counter + 1]))
-+			{
-+			  result = _asn1_append_sequence_set (p, &tcache);
-+			  if (result != 0)
-+			    {
-+                              warn();
-+		              goto cleanup;
-+		            }
-+			  p = tcache.tail;
-+			  move = RIGHT;
-+			  continue;
-+			}
-+
-+		      p->tmp_ival = 0;
-+		      tcache.tail = NULL; /* finished decoding this structure */
-+		      tcache.head = NULL;
-+		      DECR_LEN(ider_len, 2);
-+		      counter += 2;
-+		    }
-+		  else
-+		    {		/* definite length method */
-+		      if (len2 > counter)
-+			{
-+			  result = _asn1_append_sequence_set (p, &tcache);
-+			  if (result != 0)
-+			    {
-+                              warn();
-+		              goto cleanup;
-+		            }
-+			  p = tcache.tail;
-+			  move = RIGHT;
-+			  continue;
-+			}
-+
-+		      p->tmp_ival = 0;
-+		      tcache.tail = NULL; /* finished decoding this structure */
-+		      tcache.head = NULL;
-+
-+		      if (len2 != counter)
-+			{
-+			  result = ASN1_DER_ERROR;
-+                          warn();
-+			  goto cleanup;
-+			}
-+		    }
-+		}
-+	      else
-+		{		/* move==DOWN || move==RIGHT */
-+		  len3 =
-+		    asn1_get_length_der (der + counter, ider_len, &len2);
-+                  if (IS_ERR(len3, flags))
-+		    {
-+		      result = ASN1_DER_ERROR;
-+                      warn();
-+		      goto cleanup;
-+		    }
-+
-+		  DECR_LEN(ider_len, len2);
-+		  counter += len2;
-+		  if (len3)
-+		    {
-+		      if (len3 > 0)
-+			{	/* definite length method */
-+		          p->tmp_ival = counter + len3;
-+			}
-+		      else
-+			{	/* indefinite length method */
-+		          p->tmp_ival = -1;
-+			}
-+
-+		      p2 = p->down;
-+                      if (p2 == NULL)
-+		        {
-+		          result = ASN1_DER_ERROR;
-+                          warn();
-+		          goto cleanup;
-+		        }
-+
-+		      while ((type_field (p2->type) == ASN1_ETYPE_TAG)
-+			     || (type_field (p2->type) == ASN1_ETYPE_SIZE))
-+			p2 = p2->right;
-+		      if (p2->right == NULL)
-+		        {
-+			  result = _asn1_append_sequence_set (p, &tcache);
-+			  if (result != 0)
-+			    {
-+                              warn();
-+		              goto cleanup;
-+		            }
-+			}
-+		      p = p2;
-+		    }
-+		}
-+	      move = RIGHT;
-+	      break;
-+	    case ASN1_ETYPE_ANY:
-+	      /* Check indefinite lenth method in an EXPLICIT TAG */
-+
-+	      if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) && (p->type & CONST_TAG) &&
-+	          tag_len == 2 && (der[counter - 1] == 0x80))
-+		indefinite = 1;
-+	      else
-+	        indefinite = 0;
-+
-+	      if (asn1_get_tag_der
-+		  (der + counter, ider_len, &class, &len2,
-+		   &tag) != ASN1_SUCCESS)
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+
-+	      DECR_LEN(ider_len, len2);
-+
-+	      len4 =
-+		asn1_get_length_der (der + counter + len2,
-+				     ider_len, &len3);
-+              if (IS_ERR(len4, flags))
-+		{
-+		  result = ASN1_DER_ERROR;
-+                  warn();
-+		  goto cleanup;
-+		}
-+	      if (len4 != -1) /* definite */
-+		{
-+		  len2 += len4;
-+
-+	          DECR_LEN(ider_len, len4+len3);
-+		  _asn1_set_value_lv (p, der + counter, len2 + len3);
-+		  counter += len2 + len3;
-+		}
-+	      else /* == -1 */
-+		{		/* indefinite length */
-+		  ider_len += len2; /* undo DECR_LEN */
-+
-+		  if (counter == 0)
-+		    {
-+		      result = ASN1_DER_ERROR;
-+                      warn();
-+		      goto cleanup;
-+		    }
-+
-+		  result =
-+		    _asn1_get_indefinite_length_string (der + counter, ider_len, &len2);
-+		  if (result != ASN1_SUCCESS)
-+		    {
-+                      warn();
-+                      goto cleanup;
-+                    }
-+
-+	          DECR_LEN(ider_len, len2);
-+		  _asn1_set_value_lv (p, der + counter, len2);
-+		  counter += len2;
-+
-+		}
-+
-+	        /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with
-+	           an indefinite length method. */
-+	        if (indefinite)
-+		  {
-+	            DECR_LEN(ider_len, 2);
-+		    if (!der[counter] && !der[counter + 1])
-+		      {
-+		        counter += 2;
-+		      }
-+		    else
-+		      {
-+		        result = ASN1_DER_ERROR;
-+                        warn();
-+		        goto cleanup;
-+		      }
-+		  }
-+
-+	      move = RIGHT;
-+	      break;
-+	    default:
-+	      move = (move == UP) ? RIGHT : DOWN;
-+	      break;
-+	    }
-+	}
-+
-+      if (p)
-+        {
-+          p->end = counter - 1;
-+        }
-+
-+      if (p == node && move != DOWN)
-+	break;
-+
-+      if (move == DOWN)
-+	{
-+	  if (p->down)
-+	    p = p->down;
-+	  else
-+	    move = RIGHT;
-+	}
-+      if ((move == RIGHT) && !(p->type & CONST_SET))
-+	{
-+	  if (p->right)
-+	    p = p->right;
-+	  else
-+	    move = UP;
-+	}
-+      if (move == UP)
-+	p = _asn1_find_up (p);
-+    }
-+
-+  _asn1_delete_not_used (*element);
-+
-+  if ((ider_len < 0) ||
-+      (!(flags & ASN1_DECODE_FLAG_ALLOW_PADDING) && (ider_len != 0)))
-+    {
-+      warn();
-+      result = ASN1_DER_ERROR;
-+      goto cleanup;
-+    }
-+
-+  *max_ider_len = total_len - ider_len;
-+
-+  return ASN1_SUCCESS;
-+
-+cleanup:
-+  asn1_delete_structure (element);
-+  return result;
-+}
-+
-+
-+/**
-+ * asn1_der_decoding:
-+ * @element: pointer to an ASN1 structure.
-+ * @ider: vector that contains the DER encoding.
-+ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1].
-+ * @errorDescription: null-terminated string contains details when an
-+ *   error occurred.
-+ *
-+ * Fill the structure *@element with values of a DER encoding
-+ * string. The structure must just be created with function
-+ * asn1_create_element().
-+ *
-+ * Note that the *@element variable is provided as a pointer for
-+ * historical reasons.
-+ *
-+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
-+ *   if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or
-+ *   %ASN1_DER_ERROR if the der encoding doesn't match the structure
-+ *   name (*@ELEMENT deleted).
-+ **/
-+int
-+asn1_der_decoding (asn1_node * element, const void *ider, int ider_len,
-+		   char *errorDescription)
-+{
-+  return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription);
-+}
-+
-+/**
-+ * asn1_der_decoding_element:
-+ * @structure: pointer to an ASN1 structure
-+ * @elementName: name of the element to fill
-+ * @ider: vector that contains the DER encoding of the whole structure.
-+ * @len: number of bytes of *der: der[0]..der[len-1]
-+ * @errorDescription: null-terminated string contains details when an
-+ *   error occurred.
-+ *
-+ * Fill the element named @ELEMENTNAME with values of a DER encoding
-+ * string.  The structure must just be created with function
-+ * asn1_create_element().  The DER vector must contain the encoding
-+ * string of the whole @STRUCTURE.  If an error occurs during the
-+ * decoding procedure, the *@STRUCTURE is deleted and set equal to
-+ * %NULL.
-+ *
-+ * This function is deprecated and may just be an alias to asn1_der_decoding
-+ * in future versions. Use asn1_der_decoding() instead.
-+ *
-+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
-+ *   if ELEMENT is %NULL or @elementName == NULL, and
-+ *   %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding doesn't
-+ *   match the structure @structure (*ELEMENT deleted).
-+ **/
-+int
-+asn1_der_decoding_element (asn1_node * structure, const char *elementName,
-+			   const void *ider, int len, char *errorDescription)
-+{
-+  return asn1_der_decoding(structure, ider, len, errorDescription);
-+}
-+
-+/**
-+ * asn1_der_decoding_startEnd:
-+ * @element: pointer to an ASN1 element
-+ * @ider: vector that contains the DER encoding.
-+ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1]
-+ * @name_element: an element of NAME structure.
-+ * @start: the position of the first byte of NAME_ELEMENT decoding
-+ *   (@ider[*start])
-+ * @end: the position of the last byte of NAME_ELEMENT decoding
-+ *  (@ider[*end])
-+ *
-+ * Find the start and end point of an element in a DER encoding
-+ * string. I mean that if you have a der encoding and you have already
-+ * used the function asn1_der_decoding() to fill a structure, it may
-+ * happen that you want to find the piece of string concerning an
-+ * element of the structure.
-+ *
-+ * One example is the sequence "tbsCertificate" inside an X509
-+ * certificate.
-+ *
-+ * Note that since libtasn1 3.7 the @ider and @ider_len parameters
-+ * can be omitted, if the element is already decoded using asn1_der_decoding().
-+ *
-+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
-+ *   if ELEMENT is %asn1_node EMPTY or @name_element is not a valid
-+ *   element, %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding
-+ *   doesn't match the structure ELEMENT.
-+ **/
-+int
-+asn1_der_decoding_startEnd (asn1_node element, const void *ider, int ider_len,
-+			    const char *name_element, int *start, int *end)
-+{
-+  asn1_node node, node_to_find;
-+  int result = ASN1_DER_ERROR;
-+
-+  node = element;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  node_to_find = asn1_find_node (node, name_element);
-+
-+  if (node_to_find == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  *start = node_to_find->start;
-+  *end = node_to_find->end;
-+
-+  if (*start == 0 && *end == 0)
-+    {
-+      if (ider == NULL || ider_len == 0)
-+        return ASN1_GENERIC_ERROR;
-+
-+      /* it seems asn1_der_decoding() wasn't called before. Do it now */
-+      result = asn1_der_decoding (&node, ider, ider_len, NULL);
-+      if (result != ASN1_SUCCESS)
-+        {
-+          warn();
-+          return result;
-+        }
-+
-+      node_to_find = asn1_find_node (node, name_element);
-+      if (node_to_find == NULL)
-+        return ASN1_ELEMENT_NOT_FOUND;
-+
-+      *start = node_to_find->start;
-+      *end = node_to_find->end;
-+    }
-+
-+  if (*end < *start)
-+    return ASN1_GENERIC_ERROR;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/**
-+ * asn1_expand_any_defined_by:
-+ * @definitions: ASN1 definitions
-+ * @element: pointer to an ASN1 structure
-+ *
-+ * Expands every "ANY DEFINED BY" element of a structure created from
-+ * a DER decoding process (asn1_der_decoding function). The element
-+ * ANY must be defined by an OBJECT IDENTIFIER. The type used to
-+ * expand the element ANY is the first one following the definition of
-+ * the actual value of the OBJECT IDENTIFIER.
-+ *
-+ * Returns: %ASN1_SUCCESS if Substitution OK, %ASN1_ERROR_TYPE_ANY if
-+ *   some "ANY DEFINED BY" element couldn't be expanded due to a
-+ *   problem in OBJECT_ID -> TYPE association, or other error codes
-+ *   depending on DER decoding.
-+ **/
-+int
-+asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element)
-+{
-+  char name[2 * ASN1_MAX_NAME_SIZE + 2],
-+    value[ASN1_MAX_NAME_SIZE];
-+  int retCode = ASN1_SUCCESS, result;
-+  int len, len2, len3;
-+  asn1_node_const p2;
-+  asn1_node p, p3, aux = NULL;
-+  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
-+  const char *definitionsName;
-+
-+  if ((definitions == NULL) || (*element == NULL))
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  definitionsName = definitions->name;
-+
-+  p = *element;
-+  while (p)
-+    {
-+
-+      switch (type_field (p->type))
-+	{
-+	case ASN1_ETYPE_ANY:
-+	  if ((p->type & CONST_DEFINED_BY) && (p->value))
-+	    {
-+	      /* search the "DEF_BY" element */
-+	      p2 = p->down;
-+	      while ((p2) && (type_field (p2->type) != ASN1_ETYPE_CONSTANT))
-+		p2 = p2->right;
-+
-+	      if (!p2)
-+		{
-+		  retCode = ASN1_ERROR_TYPE_ANY;
-+		  break;
-+		}
-+
-+	      p3 = _asn1_find_up (p);
-+
-+	      if (!p3)
-+		{
-+		  retCode = ASN1_ERROR_TYPE_ANY;
-+		  break;
-+		}
-+
-+	      p3 = p3->down;
-+	      while (p3)
-+		{
-+		  if (!(strcmp (p3->name, p2->name)))
-+		    break;
-+		  p3 = p3->right;
-+		}
-+
-+	      if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ||
-+		  (p3->value == NULL))
-+		{
-+
-+		  p3 = _asn1_find_up (p);
-+		  p3 = _asn1_find_up (p3);
-+
-+		  if (!p3)
-+		    {
-+		      retCode = ASN1_ERROR_TYPE_ANY;
-+		      break;
-+		    }
-+
-+		  p3 = p3->down;
-+
-+		  while (p3)
-+		    {
-+		      if (!(strcmp (p3->name, p2->name)))
-+			break;
-+		      p3 = p3->right;
-+		    }
-+
-+		  if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID)
-+		      || (p3->value == NULL))
-+		    {
-+		      retCode = ASN1_ERROR_TYPE_ANY;
-+		      break;
-+		    }
-+		}
-+
-+	      /* search the OBJECT_ID into definitions */
-+	      p2 = definitions->down;
-+	      while (p2)
-+		{
-+		  if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) &&
-+		      (p2->type & CONST_ASSIGN))
-+		    {
-+		      snprintf(name, sizeof(name), "%s.%s", definitionsName, p2->name);
-+
-+		      len = ASN1_MAX_NAME_SIZE;
-+		      result =
-+			asn1_read_value (definitions, name, value, &len);
-+
-+		      if ((result == ASN1_SUCCESS)
-+			  && (!_asn1_strcmp (p3->value, value)))
-+			{
-+			  p2 = p2->right;	/* pointer to the structure to
-+						   use for expansion */
-+			  while ((p2) && (p2->type & CONST_ASSIGN))
-+			    p2 = p2->right;
-+
-+			  if (p2)
-+			    {
-+			      snprintf(name, sizeof(name), "%s.%s", definitionsName, p2->name);
-+
-+			      result =
-+				asn1_create_element (definitions, name, &aux);
-+			      if (result == ASN1_SUCCESS)
-+				{
-+				  _asn1_cpy_name (aux, p);
-+				  len2 =
-+				    asn1_get_length_der (p->value,
-+							 p->value_len, &len3);
-+				  if (len2 < 0)
-+				    return ASN1_DER_ERROR;
-+
-+				  result =
-+				    asn1_der_decoding (&aux, p->value + len3,
-+						       len2,
-+						       errorDescription);
-+				  if (result == ASN1_SUCCESS)
-+				    {
-+
-+				      _asn1_set_right (aux, p->right);
-+				      _asn1_set_right (p, aux);
-+
-+				      result = asn1_delete_structure (&p);
-+				      if (result == ASN1_SUCCESS)
-+					{
-+					  p = aux;
-+					  aux = NULL;
-+					  break;
-+					}
-+				      else
-+					{	/* error with asn1_delete_structure */
-+					  asn1_delete_structure (&aux);
-+					  retCode = result;
-+					  break;
-+					}
-+				    }
-+				  else
-+				    {	/* error with asn1_der_decoding */
-+				      retCode = result;
-+				      break;
-+				    }
-+				}
-+			      else
-+				{	/* error with asn1_create_element */
-+				  retCode = result;
-+				  break;
-+				}
-+			    }
-+			  else
-+			    {	/* error with the pointer to the structure to exapand */
-+			      retCode = ASN1_ERROR_TYPE_ANY;
-+			      break;
-+			    }
-+			}
-+		    }
-+		  p2 = p2->right;
-+		}		/* end while */
-+
-+	      if (!p2)
-+		{
-+		  retCode = ASN1_ERROR_TYPE_ANY;
-+		  break;
-+		}
-+
-+	    }
-+	  break;
-+	default:
-+	  break;
-+	}
-+
-+
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	}
-+      else if (p == *element)
-+	{
-+	  p = NULL;
-+	  break;
-+	}
-+      else if (p->right)
-+	p = p->right;
-+      else
-+	{
-+	  while (1)
-+	    {
-+	      p = _asn1_find_up (p);
-+	      if (p == *element)
-+		{
-+		  p = NULL;
-+		  break;
-+		}
-+	      if (p->right)
-+		{
-+		  p = p->right;
-+		  break;
-+		}
-+	    }
-+	}
-+    }
-+
-+  return retCode;
-+}
-+
-+/**
-+ * asn1_expand_octet_string:
-+ * @definitions: ASN1 definitions
-+ * @element: pointer to an ASN1 structure
-+ * @octetName: name of the OCTECT STRING field to expand.
-+ * @objectName: name of the OBJECT IDENTIFIER field to use to define
-+ *    the type for expansion.
-+ *
-+ * Expands an "OCTET STRING" element of a structure created from a DER
-+ * decoding process (the asn1_der_decoding() function).  The type used
-+ * for expansion is the first one following the definition of the
-+ * actual value of the OBJECT IDENTIFIER indicated by OBJECTNAME.
-+ *
-+ * Returns: %ASN1_SUCCESS if substitution OK, %ASN1_ELEMENT_NOT_FOUND
-+ *   if @objectName or @octetName are not correct,
-+ *   %ASN1_VALUE_NOT_VALID if it wasn't possible to find the type to
-+ *   use for expansion, or other errors depending on DER decoding.
-+ **/
-+int
-+asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element,
-+			  const char *octetName, const char *objectName)
-+{
-+  char name[2 * ASN1_MAX_NAME_SIZE + 1], value[ASN1_MAX_NAME_SIZE];
-+  int retCode = ASN1_SUCCESS, result;
-+  int len, len2, len3;
-+  asn1_node_const p2;
-+  asn1_node aux = NULL;
-+  asn1_node octetNode = NULL, objectNode = NULL;
-+  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
-+
-+  if ((definitions == NULL) || (*element == NULL))
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  octetNode = asn1_find_node (*element, octetName);
-+  if (octetNode == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+  if (type_field (octetNode->type) != ASN1_ETYPE_OCTET_STRING)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+  if (octetNode->value == NULL)
-+    return ASN1_VALUE_NOT_FOUND;
-+
-+  objectNode = asn1_find_node (*element, objectName);
-+  if (objectNode == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  if (type_field (objectNode->type) != ASN1_ETYPE_OBJECT_ID)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  if (objectNode->value == NULL)
-+    return ASN1_VALUE_NOT_FOUND;
-+
-+
-+  /* search the OBJECT_ID into definitions */
-+  p2 = definitions->down;
-+  while (p2)
-+    {
-+      if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) &&
-+	  (p2->type & CONST_ASSIGN))
-+	{
-+	  strcpy (name, definitions->name);
-+	  strcat (name, ".");
-+	  strcat (name, p2->name);
-+
-+	  len = sizeof (value);
-+	  result = asn1_read_value (definitions, name, value, &len);
-+
-+	  if ((result == ASN1_SUCCESS)
-+	      && (!_asn1_strcmp (objectNode->value, value)))
-+	    {
-+
-+	      p2 = p2->right;	/* pointer to the structure to
-+				   use for expansion */
-+	      while ((p2) && (p2->type & CONST_ASSIGN))
-+		p2 = p2->right;
-+
-+	      if (p2)
-+		{
-+		  strcpy (name, definitions->name);
-+		  strcat (name, ".");
-+		  strcat (name, p2->name);
-+
-+		  result = asn1_create_element (definitions, name, &aux);
-+		  if (result == ASN1_SUCCESS)
-+		    {
-+		      _asn1_cpy_name (aux, octetNode);
-+		      len2 =
-+			asn1_get_length_der (octetNode->value,
-+					     octetNode->value_len, &len3);
-+		      if (len2 < 0)
-+			return ASN1_DER_ERROR;
-+
-+		      result =
-+			asn1_der_decoding (&aux, octetNode->value + len3,
-+					   len2, errorDescription);
-+		      if (result == ASN1_SUCCESS)
-+			{
-+
-+			  _asn1_set_right (aux, octetNode->right);
-+			  _asn1_set_right (octetNode, aux);
-+
-+			  result = asn1_delete_structure (&octetNode);
-+			  if (result == ASN1_SUCCESS)
-+			    {
-+			      aux = NULL;
-+			      break;
-+			    }
-+			  else
-+			    {	/* error with asn1_delete_structure */
-+			      asn1_delete_structure (&aux);
-+			      retCode = result;
-+			      break;
-+			    }
-+			}
-+		      else
-+			{	/* error with asn1_der_decoding */
-+			  retCode = result;
-+			  break;
-+			}
-+		    }
-+		  else
-+		    {		/* error with asn1_create_element */
-+		      retCode = result;
-+		      break;
-+		    }
-+		}
-+	      else
-+		{		/* error with the pointer to the structure to exapand */
-+		  retCode = ASN1_VALUE_NOT_VALID;
-+		  break;
-+		}
-+	    }
-+	}
-+
-+      p2 = p2->right;
-+
-+    }
-+
-+  if (!p2)
-+    retCode = ASN1_VALUE_NOT_VALID;
-+
-+  return retCode;
-+}
-+
-+/*-
-+ * _asn1_decode_simple_der:
-+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
-+ * @der: the encoded string
-+ * @_der_len: the bytes of the encoded string
-+ * @str: a pointer to the data
-+ * @str_len: the length of the data
-+ * @dflags: DECODE_FLAG_*
-+ *
-+ * Decodes a simple DER encoded type (e.g. a string, which is not constructed).
-+ * The output is a pointer inside the @der.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful or an error value.
-+ -*/
-+static int
-+_asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
-+			unsigned int _der_len, const unsigned char **str,
-+			unsigned int *str_len, unsigned dflags)
-+{
-+  int tag_len, len_len;
-+  const unsigned char *p;
-+  int der_len = _der_len;
-+  unsigned char class;
-+  unsigned long tag;
-+  long ret;
-+
-+  if (der == NULL || der_len == 0)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  if (ETYPE_OK (etype) == 0 || ETYPE_IS_STRING(etype) == 0)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  /* doesn't handle constructed classes */
-+  class = ETYPE_CLASS(etype);
-+  if (class != ASN1_CLASS_UNIVERSAL)
-+    return ASN1_VALUE_NOT_VALID;
-+
-+  p = der;
-+
-+  if (dflags & DECODE_FLAG_HAVE_TAG)
-+    {
-+      ret = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag);
-+      if (ret != ASN1_SUCCESS)
-+        return ret;
-+
-+      if (class != ETYPE_CLASS (etype) || tag != ETYPE_TAG (etype))
-+        {
-+          warn();
-+          return ASN1_DER_ERROR;
-+        }
-+
-+      p += tag_len;
-+      der_len -= tag_len;
-+      if (der_len <= 0)
-+        return ASN1_DER_ERROR;
-+    }
-+
-+  ret = asn1_get_length_der (p, der_len, &len_len);
-+  if (ret < 0)
-+    return ASN1_DER_ERROR;
-+
-+  p += len_len;
-+  der_len -= len_len;
-+  if (der_len <= 0)
-+    return ASN1_DER_ERROR;
-+
-+  *str_len = ret;
-+  *str = p;
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/**
-+ * asn1_decode_simple_der:
-+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
-+ * @der: the encoded string
-+ * @_der_len: the bytes of the encoded string
-+ * @str: a pointer to the data
-+ * @str_len: the length of the data
-+ *
-+ * Decodes a simple DER encoded type (e.g. a string, which is not constructed).
-+ * The output is a pointer inside the @der.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful or an error value.
-+ **/
-+int
-+asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
-+			unsigned int _der_len, const unsigned char **str,
-+			unsigned int *str_len)
-+{
-+  return _asn1_decode_simple_der(etype, der, _der_len, str, str_len, DECODE_FLAG_HAVE_TAG);
-+}
-+
-+static int append(uint8_t **dst, unsigned *dst_size, const unsigned char *src, unsigned src_size)
-+{
-+  if (src_size == 0)
-+    return ASN1_SUCCESS;
-+
-+  *dst = _asn1_realloc(*dst, *dst_size+src_size);
-+  if (*dst == NULL)
-+    return ASN1_MEM_ALLOC_ERROR;
-+  memcpy(*dst + *dst_size, src, src_size);
-+  *dst_size += src_size;
-+  return ASN1_SUCCESS;
-+}
-+
-+/*-
-+ * _asn1_decode_simple_ber:
-+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
-+ * @der: the encoded string
-+ * @_der_len: the bytes of the encoded string
-+ * @str: a pointer to the data
-+ * @str_len: the length of the data
-+ * @ber_len: the total length occupied by BER (may be %NULL)
-+ * @have_tag: whether a DER tag is included
-+ *
-+ * Decodes a BER encoded type. The output is an allocated value
-+ * of the data. This decodes BER STRINGS only. Other types are
-+ * decoded as DER.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful or an error value.
-+ -*/
-+static int
-+_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
-+			unsigned int _der_len, unsigned char **str,
-+			unsigned int *str_len, unsigned int *ber_len,
-+			unsigned dflags)
-+{
-+  int tag_len, len_len;
-+  const unsigned char *p;
-+  int der_len = _der_len;
-+  uint8_t *total = NULL;
-+  unsigned total_size = 0;
-+  unsigned char class;
-+  unsigned long tag;
-+  unsigned char *out = NULL;
-+  const unsigned char *cout = NULL;
-+  unsigned out_len;
-+  long result;
-+
-+  if (ber_len) *ber_len = 0;
-+
-+  if (der == NULL || der_len == 0)
-+    {
-+      warn();
-+      return ASN1_VALUE_NOT_VALID;
-+    }
-+
-+  if (ETYPE_OK (etype) == 0)
-+    {
-+      warn();
-+      return ASN1_VALUE_NOT_VALID;
-+    }
-+
-+  /* doesn't handle constructed + definite classes */
-+  class = ETYPE_CLASS (etype);
-+  if (class != ASN1_CLASS_UNIVERSAL)
-+    {
-+      warn();
-+      return ASN1_VALUE_NOT_VALID;
-+    }
-+
-+  p = der;
-+
-+  if (dflags & DECODE_FLAG_HAVE_TAG)
-+    {
-+      result = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag);
-+        if (result != ASN1_SUCCESS)
-+          {
-+            warn();
-+            return result;
-+          }
-+
-+        if (tag != ETYPE_TAG (etype))
-+          {
-+            warn();
-+            return ASN1_DER_ERROR;
-+          }
-+
-+        p += tag_len;
-+
-+        DECR_LEN(der_len, tag_len);
-+
-+        if (ber_len) *ber_len += tag_len;
-+    }
-+
-+  /* indefinite constructed */
-+  if ((((dflags & DECODE_FLAG_CONSTRUCTED) || class == ASN1_CLASS_STRUCTURED) && ETYPE_IS_STRING(etype)) &&
-+      !(dflags & DECODE_FLAG_LEVEL3))
-+    {
-+      if (der_len == 0)
-+        {
-+          warn();
-+          result = ASN1_DER_ERROR;
-+          goto cleanup;
-+        }
-+
-+      if (der_len > 0 && p[0] == 0x80) /* indefinite */
-+        {
-+          len_len = 1;
-+          DECR_LEN(der_len, len_len);
-+          p += len_len;
-+
-+          if (ber_len) *ber_len += len_len;
-+
-+          /* decode the available octet strings */
-+          do
-+            {
-+              unsigned tmp_len;
-+              unsigned flags = DECODE_FLAG_HAVE_TAG;
-+
-+              if (dflags & DECODE_FLAG_LEVEL1)
-+                flags |= DECODE_FLAG_LEVEL2;
-+              else if (dflags & DECODE_FLAG_LEVEL2)
-+                flags |= DECODE_FLAG_LEVEL3;
-+              else
-+		flags |= DECODE_FLAG_LEVEL1;
-+
-+              result = _asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len,
-+                                               flags);
-+              if (result != ASN1_SUCCESS)
-+                {
-+                  warn();
-+                  goto cleanup;
-+                }
-+
-+              p += tmp_len;
-+              DECR_LEN(der_len, tmp_len);
-+
-+              if (ber_len) *ber_len += tmp_len;
-+
-+              DECR_LEN(der_len, 2); /* we need the EOC */
-+
-+              result = append(&total, &total_size, out, out_len);
-+              if (result != ASN1_SUCCESS)
-+                {
-+                  warn();
-+                  goto cleanup;
-+	        }
-+
-+              free(out);
-+              out = NULL;
-+
-+	      if (p[0] == 0 && p[1] == 0) /* EOC */
-+	        {
-+                  if (ber_len) *ber_len += 2;
-+                  break;
-+                }
-+
-+              /* no EOC */
-+              der_len += 2;
-+
-+              if (der_len == 2)
-+                {
-+                  warn();
-+                  result = ASN1_DER_ERROR;
-+                  goto cleanup;
-+                }
-+            }
-+          while(1);
-+        }
-+      else /* constructed */
-+        {
-+          long const_len;
-+
-+          result = asn1_get_length_ber(p, der_len, &len_len);
-+          if (result < 0)
-+            {
-+              warn();
-+              result = ASN1_DER_ERROR;
-+              goto cleanup;
-+            }
-+
-+          DECR_LEN(der_len, len_len);
-+          p += len_len;
-+
-+          const_len = result;
-+
-+          if (ber_len) *ber_len += len_len;
-+
-+          /* decode the available octet strings */
-+          while(const_len > 0)
-+            {
-+              unsigned tmp_len;
-+              unsigned flags = DECODE_FLAG_HAVE_TAG;
-+
-+              if (dflags & DECODE_FLAG_LEVEL1)
-+                flags |= DECODE_FLAG_LEVEL2;
-+              else if (dflags & DECODE_FLAG_LEVEL2)
-+                flags |= DECODE_FLAG_LEVEL3;
-+              else
-+		flags |= DECODE_FLAG_LEVEL1;
-+
-+              result = _asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len,
-+                                               flags);
-+              if (result != ASN1_SUCCESS)
-+                {
-+                  warn();
-+                  goto cleanup;
-+                }
-+
-+              p += tmp_len;
-+              DECR_LEN(der_len, tmp_len);
-+              DECR_LEN(const_len, tmp_len);
-+
-+              if (ber_len) *ber_len += tmp_len;
-+
-+              result = append(&total, &total_size, out, out_len);
-+              if (result != ASN1_SUCCESS)
-+                {
-+                  warn();
-+                  goto cleanup;
-+	        }
-+
-+              free(out);
-+              out = NULL;
-+            }
-+        }
-+    }
-+  else if (class == ETYPE_CLASS(etype))
-+    {
-+      if (ber_len)
-+        {
-+          result = asn1_get_length_der (p, der_len, &len_len);
-+          if (result < 0)
-+            {
-+              warn();
-+              result = ASN1_DER_ERROR;
-+              goto cleanup;
-+            }
-+          *ber_len += result + len_len;
-+        }
-+
-+      /* non-string values are decoded as DER */
-+      result = _asn1_decode_simple_der(etype, der, _der_len, &cout, &out_len, dflags);
-+      if (result != ASN1_SUCCESS)
-+        {
-+          warn();
-+          goto cleanup;
-+        }
-+
-+      result = append(&total, &total_size, cout, out_len);
-+      if (result != ASN1_SUCCESS)
-+        {
-+          warn();
-+          goto cleanup;
-+        }
-+    }
-+  else
-+    {
-+      warn();
-+      result = ASN1_DER_ERROR;
-+      goto cleanup;
-+    }
-+
-+  *str = total;
-+  *str_len = total_size;
-+
-+  return ASN1_SUCCESS;
-+cleanup:
-+  free(out);
-+  free(total);
-+  return result;
-+}
-+
-+/**
-+ * asn1_decode_simple_ber:
-+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
-+ * @der: the encoded string
-+ * @_der_len: the bytes of the encoded string
-+ * @str: a pointer to the data
-+ * @str_len: the length of the data
-+ * @ber_len: the total length occupied by BER (may be %NULL)
-+ *
-+ * Decodes a BER encoded type. The output is an allocated value
-+ * of the data. This decodes BER STRINGS only. Other types are
-+ * decoded as DER.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful or an error value.
-+ **/
-+int
-+asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
-+			unsigned int _der_len, unsigned char **str,
-+			unsigned int *str_len, unsigned int *ber_len)
-+{
-+  return _asn1_decode_simple_ber(etype, der, _der_len, str, str_len, ber_len, DECODE_FLAG_HAVE_TAG);
-+}
-diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c
-new file mode 100644
-index 00000000000..997eb2725dc
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/element.c
-@@ -0,0 +1,1111 @@
-+/*
-+ * Copyright (C) 2000-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+/*****************************************************/
-+/* File: element.c                                   */
-+/* Description: Functions with the read and write    */
-+/*   functions.                                      */
-+/*****************************************************/
-+
-+
-+#include <int.h>
-+#include "parser_aux.h"
-+#include <gstr.h>
-+#include "structure.h"
-+#include "c-ctype.h"
-+#include "element.h"
-+
-+void
-+_asn1_hierarchical_name (asn1_node_const node, char *name, int name_size)
-+{
-+  asn1_node_const p;
-+  char tmp_name[64];
-+
-+  p = node;
-+
-+  name[0] = 0;
-+
-+  while (p != NULL)
-+    {
-+      if (p->name[0] != 0)
-+	{
-+	  _asn1_str_cpy (tmp_name, sizeof (tmp_name), name),
-+	    _asn1_str_cpy (name, name_size, p->name);
-+	  _asn1_str_cat (name, name_size, ".");
-+	  _asn1_str_cat (name, name_size, tmp_name);
-+	}
-+      p = _asn1_find_up (p);
-+    }
-+
-+  if (name[0] == 0)
-+    _asn1_str_cpy (name, name_size, "ROOT");
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_convert_integer                               */
-+/* Description: converts an integer from a null terminated string */
-+/*              to der decoding. The convertion from a null       */
-+/*              terminated string to an integer is made with      */
-+/*              the 'strtol' function.                            */
-+/* Parameters:                                                    */
-+/*   value: null terminated string to convert.                    */
-+/*   value_out: convertion result (memory must be already         */
-+/*              allocated).                                       */
-+/*   value_out_size: number of bytes of value_out.                */
-+/*   len: number of significant byte of value_out.                */
-+/* Return: ASN1_MEM_ERROR or ASN1_SUCCESS                         */
-+/******************************************************************/
-+int
-+_asn1_convert_integer (const unsigned char *value, unsigned char *value_out,
-+		       int value_out_size, int *len)
-+{
-+  char negative;
-+  unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
-+  long valtmp;
-+  int k, k2;
-+
-+  valtmp = _asn1_strtol (value, NULL, 10);
-+
-+  for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++)
-+    {
-+      val[SIZEOF_UNSIGNED_LONG_INT - k - 1] = (valtmp >> (8 * k)) & 0xFF;
-+    }
-+
-+  if (val[0] & 0x80)
-+    negative = 1;
-+  else
-+    negative = 0;
-+
-+  for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT - 1; k++)
-+    {
-+      if (negative && (val[k] != 0xFF))
-+	break;
-+      else if (!negative && val[k])
-+	break;
-+    }
-+
-+  if ((negative && !(val[k] & 0x80)) || (!negative && (val[k] & 0x80)))
-+    k--;
-+
-+  *len = SIZEOF_UNSIGNED_LONG_INT - k;
-+
-+  if (SIZEOF_UNSIGNED_LONG_INT - k > value_out_size)
-+    /* VALUE_OUT is too short to contain the value conversion */
-+    return ASN1_MEM_ERROR;
-+
-+  if (value_out != NULL)
-+    {
-+      for (k2 = k; k2 < SIZEOF_UNSIGNED_LONG_INT; k2++)
-+        value_out[k2 - k] = val[k2];
-+    }
-+
-+#if 0
-+  printf ("_asn1_convert_integer: valueIn=%s, lenOut=%d", value, *len);
-+  for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++)
-+    printf (", vOut[%d]=%d", k, value_out[k]);
-+  printf ("\n");
-+#endif
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/* Appends a new element into the sequence (or set) defined by this
-+ * node. The new element will have a name of '?number', where number
-+ * is a monotonically increased serial number.
-+ *
-+ * The last element in the list may be provided in @pcache, to avoid
-+ * traversing the list, an expensive operation in long lists.
-+ *
-+ * On success it returns in @pcache the added element (which is the
-+ * tail in the list of added elements).
-+ */
-+int
-+_asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache)
-+{
-+  asn1_node p, p2;
-+  char temp[LTOSTR_MAX_SIZE];
-+  long n;
-+
-+  if (!node || !(node->down))
-+    return ASN1_GENERIC_ERROR;
-+
-+  p = node->down;
-+  while ((type_field (p->type) == ASN1_ETYPE_TAG)
-+	 || (type_field (p->type) == ASN1_ETYPE_SIZE))
-+    p = p->right;
-+
-+  p2 = _asn1_copy_structure3 (p);
-+  if (p2 == NULL)
-+    return ASN1_GENERIC_ERROR;
-+
-+  if (pcache == NULL || pcache->tail == NULL || pcache->head != node)
-+    {
-+      while (p->right)
-+        {
-+          p = p->right;
-+        }
-+    }
-+  else
-+    {
-+      p = pcache->tail;
-+    }
-+
-+  _asn1_set_right (p, p2);
-+  if (pcache)
-+    {
-+      pcache->head = node;
-+      pcache->tail = p2;
-+    }
-+
-+  if (p->name[0] == 0)
-+    _asn1_str_cpy (temp, sizeof (temp), "?1");
-+  else
-+    {
-+      n = strtol (p->name + 1, NULL, 0);
-+      n++;
-+      temp[0] = '?';
-+      _asn1_ltostr (n, temp + 1);
-+    }
-+  _asn1_set_name (p2, temp);
-+  /*  p2->type |= CONST_OPTION; */
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/**
-+ * asn1_write_value:
-+ * @node_root: pointer to a structure
-+ * @name: the name of the element inside the structure that you want to set.
-+ * @ivalue: vector used to specify the value to set. If len is >0,
-+ *   VALUE must be a two's complement form integer.  if len=0 *VALUE
-+ *   must be a null terminated string with an integer value.
-+ * @len: number of bytes of *value to use to set the value:
-+ *   value[0]..value[len-1] or 0 if value is a null terminated string
-+ *
-+ * Set the value of one element inside a structure.
-+ *
-+ * If an element is OPTIONAL and you want to delete it, you must use
-+ * the value=NULL and len=0.  Using "pkix.asn":
-+ *
-+ * result=asn1_write_value(cert, "tbsCertificate.issuerUniqueID",
-+ * NULL, 0);
-+ *
-+ * Description for each type:
-+ *
-+ * INTEGER: VALUE must contain a two's complement form integer.
-+ *
-+ *            value[0]=0xFF ,               len=1 -> integer=-1.
-+ *            value[0]=0xFF value[1]=0xFF , len=2 -> integer=-1.
-+ *            value[0]=0x01 ,               len=1 -> integer= 1.
-+ *            value[0]=0x00 value[1]=0x01 , len=2 -> integer= 1.
-+ *            value="123"                 , len=0 -> integer= 123.
-+ *
-+ * ENUMERATED: As INTEGER (but only with not negative numbers).
-+ *
-+ * BOOLEAN: VALUE must be the null terminated string "TRUE" or
-+ *   "FALSE" and LEN != 0.
-+ *
-+ *            value="TRUE" , len=1 -> boolean=TRUE.
-+ *            value="FALSE" , len=1 -> boolean=FALSE.
-+ *
-+ * OBJECT IDENTIFIER: VALUE must be a null terminated string with
-+ *   each number separated by a dot (e.g. "1.2.3.543.1").  LEN != 0.
-+ *
-+ *            value="1 2 840 10040 4 3" , len=1 -> OID=dsa-with-sha.
-+ *
-+ * UTCTime: VALUE must be a null terminated string in one of these
-+ *   formats: "YYMMDDhhmmssZ", "YYMMDDhhmmssZ",
-+ *   "YYMMDDhhmmss+hh'mm'", "YYMMDDhhmmss-hh'mm'",
-+ *   "YYMMDDhhmm+hh'mm'", or "YYMMDDhhmm-hh'mm'".  LEN != 0.
-+ *
-+ *            value="9801011200Z" , len=1 -> time=Jannuary 1st, 1998
-+ *            at 12h 00m Greenwich Mean Time
-+ *
-+ * GeneralizedTime: VALUE must be in one of this format:
-+ *   "YYYYMMDDhhmmss.sZ", "YYYYMMDDhhmmss.sZ",
-+ *   "YYYYMMDDhhmmss.s+hh'mm'", "YYYYMMDDhhmmss.s-hh'mm'",
-+ *   "YYYYMMDDhhmm+hh'mm'", or "YYYYMMDDhhmm-hh'mm'" where ss.s
-+ *   indicates the seconds with any precision like "10.1" or "01.02".
-+ *   LEN != 0
-+ *
-+ *            value="2001010112001.12-0700" , len=1 -> time=Jannuary
-+ *            1st, 2001 at 12h 00m 01.12s Pacific Daylight Time
-+ *
-+ * OCTET STRING: VALUE contains the octet string and LEN is the
-+ *   number of octets.
-+ *
-+ *            value="$\backslash$x01$\backslash$x02$\backslash$x03" ,
-+ *            len=3 -> three bytes octet string
-+ *
-+ * GeneralString: VALUE contains the generalstring and LEN is the
-+ *   number of octets.
-+ *
-+ *            value="$\backslash$x01$\backslash$x02$\backslash$x03" ,
-+ *            len=3 -> three bytes generalstring
-+ *
-+ * BIT STRING: VALUE contains the bit string organized by bytes and
-+ *   LEN is the number of bits.
-+ *
-+ *   value="$\backslash$xCF" , len=6 -> bit string="110011" (six
-+ *   bits)
-+ *
-+ * CHOICE: if NAME indicates a choice type, VALUE must specify one of
-+ *   the alternatives with a null terminated string. LEN != 0. Using
-+ *   "pkix.asn"\:
-+ *
-+ *           result=asn1_write_value(cert,
-+ *           "certificate1.tbsCertificate.subject", "rdnSequence",
-+ *           1);
-+ *
-+ * ANY: VALUE indicates the der encoding of a structure.  LEN != 0.
-+ *
-+ * SEQUENCE OF: VALUE must be the null terminated string "NEW" and
-+ *   LEN != 0. With this instruction another element is appended in
-+ *   the sequence. The name of this element will be "?1" if it's the
-+ *   first one, "?2" for the second and so on.
-+ *
-+ *   Using "pkix.asn"\:
-+ *
-+ *   result=asn1_write_value(cert,
-+ *   "certificate1.tbsCertificate.subject.rdnSequence", "NEW", 1);
-+ *
-+ * SET OF: the same as SEQUENCE OF.  Using "pkix.asn":
-+ *
-+ *           result=asn1_write_value(cert,
-+ *           "tbsCertificate.subject.rdnSequence.?LAST", "NEW", 1);
-+ *
-+ * Returns: %ASN1_SUCCESS if the value was set,
-+ *   %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, and
-+ *   %ASN1_VALUE_NOT_VALID if @ivalue has a wrong format.
-+ **/
-+int
-+asn1_write_value (asn1_node node_root, const char *name,
-+		  const void *ivalue, int len)
-+{
-+  asn1_node node, p, p2;
-+  unsigned char *temp, *value_temp = NULL, *default_temp = NULL;
-+  int len2, k, k2, negative;
-+  size_t i;
-+  const unsigned char *value = ivalue;
-+  unsigned int type;
-+
-+  node = asn1_find_node (node_root, name);
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  if ((node->type & CONST_OPTION) && (value == NULL) && (len == 0))
-+    {
-+      asn1_delete_structure (&node);
-+      return ASN1_SUCCESS;
-+    }
-+
-+  type = type_field (node->type);
-+
-+  if ((type == ASN1_ETYPE_SEQUENCE_OF || type == ASN1_ETYPE_SET_OF) && (value == NULL) && (len == 0))
-+    {
-+      p = node->down;
-+      while ((type_field (p->type) == ASN1_ETYPE_TAG)
-+	     || (type_field (p->type) == ASN1_ETYPE_SIZE))
-+	p = p->right;
-+
-+      while (p->right)
-+	asn1_delete_structure (&p->right);
-+
-+      return ASN1_SUCCESS;
-+    }
-+
-+  /* Don't allow element deletion for other types */
-+  if (value == NULL)
-+    {
-+      return ASN1_VALUE_NOT_VALID;
-+    }
-+
-+  switch (type)
-+    {
-+    case ASN1_ETYPE_BOOLEAN:
-+      if (!_asn1_strcmp (value, "TRUE"))
-+	{
-+	  if (node->type & CONST_DEFAULT)
-+	    {
-+	      p = node->down;
-+	      while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
-+		p = p->right;
-+	      if (p->type & CONST_TRUE)
-+		_asn1_set_value (node, NULL, 0);
-+	      else
-+		_asn1_set_value (node, "T", 1);
-+	    }
-+	  else
-+	    _asn1_set_value (node, "T", 1);
-+	}
-+      else if (!_asn1_strcmp (value, "FALSE"))
-+	{
-+	  if (node->type & CONST_DEFAULT)
-+	    {
-+	      p = node->down;
-+	      while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
-+		p = p->right;
-+	      if (p->type & CONST_FALSE)
-+		_asn1_set_value (node, NULL, 0);
-+	      else
-+		_asn1_set_value (node, "F", 1);
-+	    }
-+	  else
-+	    _asn1_set_value (node, "F", 1);
-+	}
-+      else
-+	return ASN1_VALUE_NOT_VALID;
-+      break;
-+    case ASN1_ETYPE_INTEGER:
-+    case ASN1_ETYPE_ENUMERATED:
-+      if (len == 0)
-+	{
-+	  if ((c_isdigit (value[0])) || (value[0] == '-'))
-+	    {
-+	      value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
-+	      if (value_temp == NULL)
-+		return ASN1_MEM_ALLOC_ERROR;
-+
-+	      _asn1_convert_integer (value, value_temp,
-+				     SIZEOF_UNSIGNED_LONG_INT, &len);
-+	    }
-+	  else
-+	    {			/* is an identifier like v1 */
-+	      if (!(node->type & CONST_LIST))
-+		return ASN1_VALUE_NOT_VALID;
-+	      p = node->down;
-+	      while (p)
-+		{
-+		  if (type_field (p->type) == ASN1_ETYPE_CONSTANT)
-+		    {
-+		      if (!_asn1_strcmp (p->name, value))
-+			{
-+			  value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
-+			  if (value_temp == NULL)
-+			    return ASN1_MEM_ALLOC_ERROR;
-+
-+			  _asn1_convert_integer (p->value,
-+						 value_temp,
-+						 SIZEOF_UNSIGNED_LONG_INT,
-+						 &len);
-+			  break;
-+			}
-+		    }
-+		  p = p->right;
-+		}
-+	      if (p == NULL)
-+		return ASN1_VALUE_NOT_VALID;
-+	    }
-+	}
-+      else
-+	{			/* len != 0 */
-+	  value_temp = malloc (len);
-+	  if (value_temp == NULL)
-+	    return ASN1_MEM_ALLOC_ERROR;
-+	  memcpy (value_temp, value, len);
-+	}
-+
-+      if (value_temp[0] & 0x80)
-+	negative = 1;
-+      else
-+	negative = 0;
-+
-+      if (negative && (type_field (node->type) == ASN1_ETYPE_ENUMERATED))
-+	{
-+	  free (value_temp);
-+	  return ASN1_VALUE_NOT_VALID;
-+	}
-+
-+      for (k = 0; k < len - 1; k++)
-+	if (negative && (value_temp[k] != 0xFF))
-+	  break;
-+	else if (!negative && value_temp[k])
-+	  break;
-+
-+      if ((negative && !(value_temp[k] & 0x80)) ||
-+	  (!negative && (value_temp[k] & 0x80)))
-+	k--;
-+
-+      _asn1_set_value_lv (node, value_temp + k, len - k);
-+
-+      if (node->type & CONST_DEFAULT)
-+	{
-+	  p = node->down;
-+	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
-+	    p = p->right;
-+	  if ((c_isdigit (p->value[0])) || (p->value[0] == '-'))
-+	    {
-+	      default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
-+	      if (default_temp == NULL)
-+		{
-+		  free (value_temp);
-+		  return ASN1_MEM_ALLOC_ERROR;
-+		}
-+
-+	      _asn1_convert_integer (p->value, default_temp,
-+				     SIZEOF_UNSIGNED_LONG_INT, &len2);
-+	    }
-+	  else
-+	    {			/* is an identifier like v1 */
-+	      if (!(node->type & CONST_LIST))
-+		{
-+		  free (value_temp);
-+		  return ASN1_VALUE_NOT_VALID;
-+		}
-+	      p2 = node->down;
-+	      while (p2)
-+		{
-+		  if (type_field (p2->type) == ASN1_ETYPE_CONSTANT)
-+		    {
-+		      if (!_asn1_strcmp (p2->name, p->value))
-+			{
-+			  default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
-+			  if (default_temp == NULL)
-+			    {
-+			      free (value_temp);
-+			      return ASN1_MEM_ALLOC_ERROR;
-+			    }
-+
-+			  _asn1_convert_integer (p2->value,
-+						 default_temp,
-+						 SIZEOF_UNSIGNED_LONG_INT,
-+						 &len2);
-+			  break;
-+			}
-+		    }
-+		  p2 = p2->right;
-+		}
-+	      if (p2 == NULL)
-+		{
-+		  free (value_temp);
-+		  return ASN1_VALUE_NOT_VALID;
-+		}
-+	    }
-+
-+
-+	  if ((len - k) == len2)
-+	    {
-+	      for (k2 = 0; k2 < len2; k2++)
-+		if (value_temp[k + k2] != default_temp[k2])
-+		  {
-+		    break;
-+		  }
-+	      if (k2 == len2)
-+		_asn1_set_value (node, NULL, 0);
-+	    }
-+	  free (default_temp);
-+	}
-+      free (value_temp);
-+      break;
-+    case ASN1_ETYPE_OBJECT_ID:
-+      for (i = 0; i < _asn1_strlen (value); i++)
-+	if ((!c_isdigit (value[i])) && (value[i] != '.') && (value[i] != '+'))
-+	  return ASN1_VALUE_NOT_VALID;
-+      if (node->type & CONST_DEFAULT)
-+	{
-+	  p = node->down;
-+	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
-+	    p = p->right;
-+	  if (!_asn1_strcmp (value, p->value))
-+	    {
-+	      _asn1_set_value (node, NULL, 0);
-+	      break;
-+	    }
-+	}
-+      _asn1_set_value (node, value, _asn1_strlen (value) + 1);
-+      break;
-+    case ASN1_ETYPE_UTC_TIME:
-+      {
-+	len = _asn1_strlen (value);
-+	if (len < 11)
-+	  return ASN1_VALUE_NOT_VALID;
-+	for (k = 0; k < 10; k++)
-+	  if (!c_isdigit (value[k]))
-+	    return ASN1_VALUE_NOT_VALID;
-+	switch (len)
-+	  {
-+	  case 11:
-+	    if (value[10] != 'Z')
-+	      return ASN1_VALUE_NOT_VALID;
-+	    break;
-+	  case 13:
-+	    if ((!c_isdigit (value[10])) || (!c_isdigit (value[11])) ||
-+		(value[12] != 'Z'))
-+	      return ASN1_VALUE_NOT_VALID;
-+	    break;
-+	  case 15:
-+	    if ((value[10] != '+') && (value[10] != '-'))
-+	      return ASN1_VALUE_NOT_VALID;
-+	    for (k = 11; k < 15; k++)
-+	      if (!c_isdigit (value[k]))
-+		return ASN1_VALUE_NOT_VALID;
-+	    break;
-+	  case 17:
-+	    if ((!c_isdigit (value[10])) || (!c_isdigit (value[11])))
-+	      return ASN1_VALUE_NOT_VALID;
-+	    if ((value[12] != '+') && (value[12] != '-'))
-+	      return ASN1_VALUE_NOT_VALID;
-+	    for (k = 13; k < 17; k++)
-+	      if (!c_isdigit (value[k]))
-+		return ASN1_VALUE_NOT_VALID;
-+	    break;
-+	  default:
-+	    return ASN1_VALUE_NOT_FOUND;
-+	  }
-+	_asn1_set_value (node, value, len);
-+      }
-+      break;
-+    case ASN1_ETYPE_GENERALIZED_TIME:
-+      len = _asn1_strlen (value);
-+      _asn1_set_value (node, value, len);
-+      break;
-+    case ASN1_ETYPE_OCTET_STRING:
-+    case ASN1_ETYPE_GENERALSTRING:
-+    case ASN1_ETYPE_NUMERIC_STRING:
-+    case ASN1_ETYPE_IA5_STRING:
-+    case ASN1_ETYPE_TELETEX_STRING:
-+    case ASN1_ETYPE_PRINTABLE_STRING:
-+    case ASN1_ETYPE_UNIVERSAL_STRING:
-+    case ASN1_ETYPE_BMP_STRING:
-+    case ASN1_ETYPE_UTF8_STRING:
-+    case ASN1_ETYPE_VISIBLE_STRING:
-+      if (len == 0)
-+	len = _asn1_strlen (value);
-+      _asn1_set_value_lv (node, value, len);
-+      break;
-+    case ASN1_ETYPE_BIT_STRING:
-+      if (len == 0)
-+	len = _asn1_strlen (value);
-+      asn1_length_der ((len >> 3) + 2, NULL, &len2);
-+      temp = malloc ((len >> 3) + 2 + len2);
-+      if (temp == NULL)
-+	return ASN1_MEM_ALLOC_ERROR;
-+
-+      asn1_bit_der (value, len, temp, &len2);
-+      _asn1_set_value_m (node, temp, len2);
-+      temp = NULL;
-+      break;
-+    case ASN1_ETYPE_CHOICE:
-+      p = node->down;
-+      while (p)
-+	{
-+	  if (!_asn1_strcmp (p->name, value))
-+	    {
-+	      p2 = node->down;
-+	      while (p2)
-+		{
-+		  if (p2 != p)
-+		    {
-+		      asn1_delete_structure (&p2);
-+		      p2 = node->down;
-+		    }
-+		  else
-+		    p2 = p2->right;
-+		}
-+	      break;
-+	    }
-+	  p = p->right;
-+	}
-+      if (!p)
-+	return ASN1_ELEMENT_NOT_FOUND;
-+      break;
-+    case ASN1_ETYPE_ANY:
-+      _asn1_set_value_lv (node, value, len);
-+      break;
-+    case ASN1_ETYPE_SEQUENCE_OF:
-+    case ASN1_ETYPE_SET_OF:
-+      if (_asn1_strcmp (value, "NEW"))
-+	return ASN1_VALUE_NOT_VALID;
-+      _asn1_append_sequence_set (node, NULL);
-+      break;
-+    default:
-+      return ASN1_ELEMENT_NOT_FOUND;
-+      break;
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+#define PUT_VALUE( ptr, ptr_size, data, data_size) \
-+	*len = data_size; \
-+	if (ptr_size < data_size) { \
-+		return ASN1_MEM_ERROR; \
-+	} else { \
-+		if (ptr && data_size > 0) \
-+		  memcpy (ptr, data, data_size); \
-+	}
-+
-+#define PUT_STR_VALUE( ptr, ptr_size, data) \
-+	*len = _asn1_strlen (data) + 1; \
-+	if (ptr_size < *len) { \
-+		return ASN1_MEM_ERROR; \
-+	} else { \
-+		/* this strcpy is checked */ \
-+		if (ptr) { \
-+		  _asn1_strcpy (ptr, data); \
-+		} \
-+	}
-+
-+#define PUT_AS_STR_VALUE( ptr, ptr_size, data, data_size) \
-+	*len = data_size + 1; \
-+	if (ptr_size < *len) { \
-+		return ASN1_MEM_ERROR; \
-+	} else { \
-+		/* this strcpy is checked */ \
-+		if (ptr) { \
-+		  if (data_size > 0) \
-+		    memcpy (ptr, data, data_size); \
-+		  ptr[data_size] = 0; \
-+		} \
-+	}
-+
-+#define ADD_STR_VALUE( ptr, ptr_size, data) \
-+        *len += _asn1_strlen(data); \
-+        if (ptr_size < (int) *len) { \
-+                (*len)++; \
-+                return ASN1_MEM_ERROR; \
-+        } else { \
-+                /* this strcat is checked */ \
-+                if (ptr) _asn1_strcat (ptr, data); \
-+        }
-+
-+/**
-+ * asn1_read_value:
-+ * @root: pointer to a structure.
-+ * @name: the name of the element inside a structure that you want to read.
-+ * @ivalue: vector that will contain the element's content, must be a
-+ *   pointer to memory cells already allocated (may be %NULL).
-+ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy
-+ *   holds the sizeof value.
-+ *
-+ * Returns the value of one element inside a structure.
-+ * If an element is OPTIONAL and this returns
-+ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present
-+ * in the der encoding that created the structure.  The first element
-+ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and
-+ * so on. If the @root provided is a node to specific sequence element,
-+ * then the keyword "?CURRENT" is also acceptable and indicates the
-+ * current sequence element of this node.
-+ *
-+ * Note that there can be valid values with length zero. In these case
-+ * this function will succeed and @len will be zero.
-+ *
-+ * INTEGER: VALUE will contain a two's complement form integer.
-+ *
-+ *            integer=-1  -> value[0]=0xFF , len=1.
-+ *            integer=1   -> value[0]=0x01 , len=1.
-+ *
-+ * ENUMERATED: As INTEGER (but only with not negative numbers).
-+ *
-+ * BOOLEAN: VALUE will be the null terminated string "TRUE" or
-+ *   "FALSE" and LEN=5 or LEN=6.
-+ *
-+ * OBJECT IDENTIFIER: VALUE will be a null terminated string with
-+ *   each number separated by a dot (i.e. "1.2.3.543.1").
-+ *
-+ *                      LEN = strlen(VALUE)+1
-+ *
-+ * UTCTime: VALUE will be a null terminated string in one of these
-+ *   formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'".
-+ *   LEN=strlen(VALUE)+1.
-+ *
-+ * GeneralizedTime: VALUE will be a null terminated string in the
-+ *   same format used to set the value.
-+ *
-+ * OCTET STRING: VALUE will contain the octet string and LEN will be
-+ *   the number of octets.
-+ *
-+ * GeneralString: VALUE will contain the generalstring and LEN will
-+ *   be the number of octets.
-+ *
-+ * BIT STRING: VALUE will contain the bit string organized by bytes
-+ *   and LEN will be the number of bits.
-+ *
-+ * CHOICE: If NAME indicates a choice type, VALUE will specify the
-+ *   alternative selected.
-+ *
-+ * ANY: If NAME indicates an any type, VALUE will indicate the DER
-+ *   encoding of the structure actually used.
-+ *
-+ * Returns: %ASN1_SUCCESS if value is returned,
-+ *   %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element,
-+ *   %ASN1_VALUE_NOT_FOUND if there isn't any value for the element
-+ *   selected, and %ASN1_MEM_ERROR if The value vector isn't big enough
-+ *   to store the result, and in this case @len will contain the number of
-+ *   bytes needed. On the occasion that the stored data are of zero-length
-+ *   this function may return %ASN1_SUCCESS even if the provided @len is zero.
-+ **/
-+int
-+asn1_read_value (asn1_node_const root, const char *name, void *ivalue, int *len)
-+{
-+  return asn1_read_value_type (root, name, ivalue, len, NULL);
-+}
-+
-+/**
-+ * asn1_read_value_type:
-+ * @root: pointer to a structure.
-+ * @name: the name of the element inside a structure that you want to read.
-+ * @ivalue: vector that will contain the element's content, must be a
-+ *   pointer to memory cells already allocated (may be %NULL).
-+ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy
-+ *   holds the sizeof value.
-+ * @etype: The type of the value read (ASN1_ETYPE)
-+ *
-+ * Returns the type and value of one element inside a structure.
-+ * If an element is OPTIONAL and this returns
-+ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present
-+ * in the der encoding that created the structure.  The first element
-+ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and
-+ * so on. If the @root provided is a node to specific sequence element,
-+ * then the keyword "?CURRENT" is also acceptable and indicates the
-+ * current sequence element of this node.
-+ *
-+ * Note that there can be valid values with length zero. In these case
-+ * this function will succeed and @len will be zero.
-+ *
-+ *
-+ * INTEGER: VALUE will contain a two's complement form integer.
-+ *
-+ *            integer=-1  -> value[0]=0xFF , len=1.
-+ *            integer=1   -> value[0]=0x01 , len=1.
-+ *
-+ * ENUMERATED: As INTEGER (but only with not negative numbers).
-+ *
-+ * BOOLEAN: VALUE will be the null terminated string "TRUE" or
-+ *   "FALSE" and LEN=5 or LEN=6.
-+ *
-+ * OBJECT IDENTIFIER: VALUE will be a null terminated string with
-+ *   each number separated by a dot (i.e. "1.2.3.543.1").
-+ *
-+ *                      LEN = strlen(VALUE)+1
-+ *
-+ * UTCTime: VALUE will be a null terminated string in one of these
-+ *   formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'".
-+ *   LEN=strlen(VALUE)+1.
-+ *
-+ * GeneralizedTime: VALUE will be a null terminated string in the
-+ *   same format used to set the value.
-+ *
-+ * OCTET STRING: VALUE will contain the octet string and LEN will be
-+ *   the number of octets.
-+ *
-+ * GeneralString: VALUE will contain the generalstring and LEN will
-+ *   be the number of octets.
-+ *
-+ * BIT STRING: VALUE will contain the bit string organized by bytes
-+ *   and LEN will be the number of bits.
-+ *
-+ * CHOICE: If NAME indicates a choice type, VALUE will specify the
-+ *   alternative selected.
-+ *
-+ * ANY: If NAME indicates an any type, VALUE will indicate the DER
-+ *   encoding of the structure actually used.
-+ *
-+ * Returns: %ASN1_SUCCESS if value is returned,
-+ *   %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element,
-+ *   %ASN1_VALUE_NOT_FOUND if there isn't any value for the element
-+ *   selected, and %ASN1_MEM_ERROR if The value vector isn't big enough
-+ *   to store the result, and in this case @len will contain the number of
-+ *   bytes needed. On the occasion that the stored data are of zero-length
-+ *   this function may return %ASN1_SUCCESS even if the provided @len is zero.
-+ **/
-+int
-+asn1_read_value_type (asn1_node_const root, const char *name, void *ivalue,
-+		      int *len, unsigned int *etype)
-+{
-+  asn1_node_const node, p, p2;
-+  int len2, len3, result;
-+  int value_size = *len;
-+  unsigned char *value = ivalue;
-+  unsigned type;
-+
-+  node = asn1_find_node (root, name);
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  type = type_field (node->type);
-+
-+  if ((type != ASN1_ETYPE_NULL) &&
-+      (type != ASN1_ETYPE_CHOICE) &&
-+      !(node->type & CONST_DEFAULT) && !(node->type & CONST_ASSIGN) &&
-+      (node->value == NULL))
-+    return ASN1_VALUE_NOT_FOUND;
-+
-+  if (etype)
-+    *etype = type;
-+  switch (type)
-+    {
-+    case ASN1_ETYPE_NULL:
-+      PUT_STR_VALUE (value, value_size, "NULL");
-+      break;
-+    case ASN1_ETYPE_BOOLEAN:
-+      if ((node->type & CONST_DEFAULT) && (node->value == NULL))
-+	{
-+	  p = node->down;
-+	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
-+	    p = p->right;
-+	  if (p->type & CONST_TRUE)
-+	    {
-+	      PUT_STR_VALUE (value, value_size, "TRUE");
-+	    }
-+	  else
-+	    {
-+	      PUT_STR_VALUE (value, value_size, "FALSE");
-+	    }
-+	}
-+      else if (node->value[0] == 'T')
-+	{
-+	  PUT_STR_VALUE (value, value_size, "TRUE");
-+	}
-+      else
-+	{
-+	  PUT_STR_VALUE (value, value_size, "FALSE");
-+	}
-+      break;
-+    case ASN1_ETYPE_INTEGER:
-+    case ASN1_ETYPE_ENUMERATED:
-+      if ((node->type & CONST_DEFAULT) && (node->value == NULL))
-+	{
-+	  p = node->down;
-+	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
-+	    p = p->right;
-+	  if ((c_isdigit (p->value[0])) || (p->value[0] == '-')
-+	      || (p->value[0] == '+'))
-+	    {
-+	      result = _asn1_convert_integer
-+		  (p->value, value, value_size, len);
-+              if (result != ASN1_SUCCESS)
-+		return result;
-+	    }
-+	  else
-+	    {			/* is an identifier like v1 */
-+	      p2 = node->down;
-+	      while (p2)
-+		{
-+		  if (type_field (p2->type) == ASN1_ETYPE_CONSTANT)
-+		    {
-+		      if (!_asn1_strcmp (p2->name, p->value))
-+			{
-+			  result = _asn1_convert_integer
-+			      (p2->value, value, value_size,
-+			       len);
-+			  if (result != ASN1_SUCCESS)
-+			    return result;
-+			  break;
-+			}
-+		    }
-+		  p2 = p2->right;
-+		}
-+	    }
-+	}
-+      else
-+	{
-+	  len2 = -1;
-+	  result = asn1_get_octet_der
-+	      (node->value, node->value_len, &len2, value, value_size,
-+	       len);
-+          if (result != ASN1_SUCCESS)
-+	    return result;
-+	}
-+      break;
-+    case ASN1_ETYPE_OBJECT_ID:
-+      if (node->type & CONST_ASSIGN)
-+	{
-+	  *len = 0;
-+	  if (value)
-+	    value[0] = 0;
-+	  p = node->down;
-+	  while (p)
-+	    {
-+	      if (type_field (p->type) == ASN1_ETYPE_CONSTANT)
-+		{
-+		  ADD_STR_VALUE (value, value_size, p->value);
-+		  if (p->right)
-+		    {
-+		      ADD_STR_VALUE (value, value_size, ".");
-+		    }
-+		}
-+	      p = p->right;
-+	    }
-+	  (*len)++;
-+	}
-+      else if ((node->type & CONST_DEFAULT) && (node->value == NULL))
-+	{
-+	  p = node->down;
-+	  while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
-+	    p = p->right;
-+	  PUT_STR_VALUE (value, value_size, p->value);
-+	}
-+      else
-+	{
-+	  PUT_STR_VALUE (value, value_size, node->value);
-+	}
-+      break;
-+    case ASN1_ETYPE_GENERALIZED_TIME:
-+    case ASN1_ETYPE_UTC_TIME:
-+      PUT_AS_STR_VALUE (value, value_size, node->value, node->value_len);
-+      break;
-+    case ASN1_ETYPE_OCTET_STRING:
-+    case ASN1_ETYPE_GENERALSTRING:
-+    case ASN1_ETYPE_NUMERIC_STRING:
-+    case ASN1_ETYPE_IA5_STRING:
-+    case ASN1_ETYPE_TELETEX_STRING:
-+    case ASN1_ETYPE_PRINTABLE_STRING:
-+    case ASN1_ETYPE_UNIVERSAL_STRING:
-+    case ASN1_ETYPE_BMP_STRING:
-+    case ASN1_ETYPE_UTF8_STRING:
-+    case ASN1_ETYPE_VISIBLE_STRING:
-+      len2 = -1;
-+      result = asn1_get_octet_der
-+	  (node->value, node->value_len, &len2, value, value_size,
-+	   len);
-+      if (result != ASN1_SUCCESS)
-+	return result;
-+      break;
-+    case ASN1_ETYPE_BIT_STRING:
-+      len2 = -1;
-+      result = asn1_get_bit_der
-+	  (node->value, node->value_len, &len2, value, value_size,
-+	   len);
-+      if (result != ASN1_SUCCESS)
-+	return result;
-+      break;
-+    case ASN1_ETYPE_CHOICE:
-+      PUT_STR_VALUE (value, value_size, node->down->name);
-+      break;
-+    case ASN1_ETYPE_ANY:
-+      len3 = -1;
-+      len2 = asn1_get_length_der (node->value, node->value_len, &len3);
-+      if (len2 < 0)
-+	return ASN1_DER_ERROR;
-+      PUT_VALUE (value, value_size, node->value + len3, len2);
-+      break;
-+    default:
-+      return ASN1_ELEMENT_NOT_FOUND;
-+      break;
-+    }
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/**
-+ * asn1_read_tag:
-+ * @root: pointer to a structure
-+ * @name: the name of the element inside a structure.
-+ * @tagValue:  variable that will contain the TAG value.
-+ * @classValue: variable that will specify the TAG type.
-+ *
-+ * Returns the TAG and the CLASS of one element inside a structure.
-+ * CLASS can have one of these constants: %ASN1_CLASS_APPLICATION,
-+ * %ASN1_CLASS_UNIVERSAL, %ASN1_CLASS_PRIVATE or
-+ * %ASN1_CLASS_CONTEXT_SPECIFIC.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
-+ *   @name is not a valid element.
-+ **/
-+int
-+asn1_read_tag (asn1_node_const root, const char *name, int *tagValue,
-+	       int *classValue)
-+{
-+  asn1_node node, p, pTag;
-+
-+  node = asn1_find_node (root, name);
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node->down;
-+
-+  /* pTag will points to the IMPLICIT TAG */
-+  pTag = NULL;
-+  if (node->type & CONST_TAG)
-+    {
-+      while (p)
-+	{
-+	  if (type_field (p->type) == ASN1_ETYPE_TAG)
-+	    {
-+	      if ((p->type & CONST_IMPLICIT) && (pTag == NULL))
-+		pTag = p;
-+	      else if (p->type & CONST_EXPLICIT)
-+		pTag = NULL;
-+	    }
-+	  p = p->right;
-+	}
-+    }
-+
-+  if (pTag)
-+    {
-+      *tagValue = _asn1_strtoul (pTag->value, NULL, 10);
-+
-+      if (pTag->type & CONST_APPLICATION)
-+	*classValue = ASN1_CLASS_APPLICATION;
-+      else if (pTag->type & CONST_UNIVERSAL)
-+	*classValue = ASN1_CLASS_UNIVERSAL;
-+      else if (pTag->type & CONST_PRIVATE)
-+	*classValue = ASN1_CLASS_PRIVATE;
-+      else
-+	*classValue = ASN1_CLASS_CONTEXT_SPECIFIC;
-+    }
-+  else
-+    {
-+      unsigned type = type_field (node->type);
-+      *classValue = ASN1_CLASS_UNIVERSAL;
-+
-+      switch (type)
-+	{
-+	CASE_HANDLED_ETYPES:
-+	  *tagValue = _asn1_tags[type].tag;
-+	  break;
-+	case ASN1_ETYPE_TAG:
-+	case ASN1_ETYPE_CHOICE:
-+	case ASN1_ETYPE_ANY:
-+	  *tagValue = -1;
-+	  break;
-+	default:
-+	  break;
-+	}
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+/**
-+ * asn1_read_node_value:
-+ * @node: pointer to a node.
-+ * @data: a point to a asn1_data_node_st
-+ *
-+ * Returns the value a data node inside a asn1_node structure.
-+ * The data returned should be handled as constant values.
-+ *
-+ * Returns: %ASN1_SUCCESS if the node exists.
-+ **/
-+int
-+asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data)
-+{
-+  data->name = node->name;
-+  data->value = node->value;
-+  data->value_len = node->value_len;
-+  data->type = type_field (node->type);
-+
-+  return ASN1_SUCCESS;
-+}
-diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c
-new file mode 100644
-index 00000000000..cee74daf795
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/errors.c
-@@ -0,0 +1,100 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+#include <int.h>
-+#ifdef STDC_HEADERS
-+#include <stdarg.h>
-+#endif
-+
-+#define LIBTASN1_ERROR_ENTRY(name) { #name, name }
-+
-+struct libtasn1_error_entry
-+{
-+  const char *name;
-+  int number;
-+};
-+typedef struct libtasn1_error_entry libtasn1_error_entry;
-+
-+static const libtasn1_error_entry error_algorithms[] = {
-+  LIBTASN1_ERROR_ENTRY (ASN1_SUCCESS),
-+  LIBTASN1_ERROR_ENTRY (ASN1_FILE_NOT_FOUND),
-+  LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_FOUND),
-+  LIBTASN1_ERROR_ENTRY (ASN1_IDENTIFIER_NOT_FOUND),
-+  LIBTASN1_ERROR_ENTRY (ASN1_DER_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_FOUND),
-+  LIBTASN1_ERROR_ENTRY (ASN1_GENERIC_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_VALID),
-+  LIBTASN1_ERROR_ENTRY (ASN1_TAG_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_TAG_IMPLICIT),
-+  LIBTASN1_ERROR_ENTRY (ASN1_ERROR_TYPE_ANY),
-+  LIBTASN1_ERROR_ENTRY (ASN1_SYNTAX_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_MEM_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_MEM_ALLOC_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_DER_OVERFLOW),
-+  LIBTASN1_ERROR_ENTRY (ASN1_NAME_TOO_LONG),
-+  LIBTASN1_ERROR_ENTRY (ASN1_ARRAY_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_EMPTY),
-+  LIBTASN1_ERROR_ENTRY (ASN1_TIME_ENCODING_ERROR),
-+  LIBTASN1_ERROR_ENTRY (ASN1_RECURSION),
-+  {0, 0}
-+};
-+
-+/**
-+ * asn1_perror:
-+ * @error: is an error returned by a libtasn1 function.
-+ *
-+ * Prints a string to stderr with a description of an error.  This
-+ * function is like perror().  The only difference is that it accepts
-+ * an error returned by a libtasn1 function.
-+ *
-+ * Since: 1.6
-+ **/
-+void
-+asn1_perror (int error)
-+{
-+  const char *str = asn1_strerror (error);
-+  fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)");
-+}
-+
-+/**
-+ * asn1_strerror:
-+ * @error: is an error returned by a libtasn1 function.
-+ *
-+ * Returns a string with a description of an error.  This function is
-+ * similar to strerror.  The only difference is that it accepts an
-+ * error (number) returned by a libtasn1 function.
-+ *
-+ * Returns: Pointer to static zero-terminated string describing error
-+ *   code.
-+ *
-+ * Since: 1.6
-+ **/
-+const char *
-+asn1_strerror (int error)
-+{
-+  const libtasn1_error_entry *p;
-+
-+  for (p = error_algorithms; p->name != NULL; p++)
-+    if (p->number == error)
-+      return p->name + sizeof ("ASN1_") - 1;
-+
-+  return NULL;
-+}
-diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c
-new file mode 100644
-index 00000000000..e91a3a151c0
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/gstr.c
-@@ -0,0 +1,74 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+#include <int.h>
-+#include "gstr.h"
-+
-+/* These function are like strcat, strcpy. They only
-+ * do bounds checking (they shouldn't cause buffer overruns),
-+ * and they always produce null terminated strings.
-+ *
-+ * They should be used only with null terminated strings.
-+ */
-+void
-+_asn1_str_cat (char *dest, size_t dest_tot_size, const char *src)
-+{
-+  size_t str_size = strlen (src);
-+  size_t dest_size = strlen (dest);
-+
-+  if (dest_tot_size - dest_size > str_size)
-+    {
-+      strcat (dest, src);
-+    }
-+  else
-+    {
-+      if (dest_tot_size - dest_size > 0)
-+	{
-+	  strncat (dest, src, (dest_tot_size - dest_size) - 1);
-+	  dest[dest_tot_size - 1] = 0;
-+	}
-+    }
-+}
-+
-+/* Returns the bytes copied (not including the null terminator) */
-+unsigned int
-+_asn1_str_cpy (char *dest, size_t dest_tot_size, const char *src)
-+{
-+  size_t str_size = strlen (src);
-+
-+  if (dest_tot_size > str_size)
-+    {
-+      strcpy (dest, src);
-+      return str_size;
-+    }
-+  else
-+    {
-+      if (dest_tot_size > 0)
-+	{
-+	  str_size = dest_tot_size - 1;
-+	  memcpy (dest, src, str_size);
-+	  dest[str_size] = 0;
-+	  return str_size;
-+	}
-+      else
-+	return 0;
-+    }
-+}
-diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c
-new file mode 100644
-index 00000000000..d5dbbf8765d
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/parser_aux.c
-@@ -0,0 +1,1173 @@
-+/*
-+ * Copyright (C) 2000-2016 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+#include <limits.h> // WORD_BIT
-+
-+#include "int.h"
-+#include "parser_aux.h"
-+#include "gstr.h"
-+#include "structure.h"
-+#include "element.h"
-+#include "c-ctype.h"
-+
-+char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1];	/* identifier name not found */
-+
-+/* Return a hash of the N bytes of X using the method described by
-+   Bruno Haible in https://www.haible.de/bruno/hashfunc.html.
-+   Note that while many hash functions reduce their result via modulo
-+   to a 0..table_size-1 range, this function does not do that.
-+
-+   This implementation has been changed from size_t -> unsigned int. */
-+
-+#ifdef __clang__
-+__attribute__((no_sanitize("integer")))
-+#endif
-+_GL_ATTRIBUTE_PURE
-+static unsigned int
-+_asn1_hash_name (const char *x)
-+{
-+  const unsigned char *s = (unsigned char *) x;
-+  unsigned h = 0;
-+
-+  while (*s)
-+    h = (*s++) + ((h << 9) | (h >> (WORD_BIT - 9)));
-+
-+  return h;
-+}
-+
-+/******************************************************/
-+/* Function : _asn1_add_static_node                   */
-+/* Description: creates a new NODE_ASN element and    */
-+/* puts it in the list pointed by e_list.       */
-+/* Parameters:                                        */
-+/*   e_list: of type list_type; must be NULL initially */
-+/*   type: type of the new element (see ASN1_ETYPE_   */
-+/*         and CONST_ constants).                     */
-+/* Return: pointer to the new element.                */
-+/******************************************************/
-+asn1_node
-+_asn1_add_static_node (list_type **e_list, unsigned int type)
-+{
-+  list_type *p;
-+  asn1_node punt;
-+
-+  punt = calloc (1, sizeof (struct asn1_node_st));
-+  if (punt == NULL)
-+    return NULL;
-+
-+  p = malloc (sizeof (list_type));
-+  if (p == NULL)
-+    {
-+      free (punt);
-+      return NULL;
-+    }
-+
-+  p->node = punt;
-+  p->next = *e_list;
-+  *e_list = p;
-+
-+  punt->type = type;
-+
-+  return punt;
-+}
-+
-+static
-+int _asn1_add_static_node2 (list_type **e_list, asn1_node node)
-+{
-+  list_type *p;
-+
-+  p = malloc (sizeof (list_type));
-+  if (p == NULL)
-+    {
-+      return -1;
-+    }
-+
-+  p->node = node;
-+  p->next = *e_list;
-+  *e_list = p;
-+
-+  return 0;
-+}
-+
-+/**
-+ * asn1_find_node:
-+ * @pointer: NODE_ASN element pointer.
-+ * @name: null terminated string with the element's name to find.
-+ *
-+ * Searches for an element called @name starting from @pointer.  The
-+ * name is composed by different identifiers separated by dots.  When
-+ * *@pointer has a name, the first identifier must be the name of
-+ * *@pointer, otherwise it must be the name of one child of *@pointer.
-+ *
-+ * Returns: the search result, or %NULL if not found.
-+ **/
-+asn1_node
-+asn1_find_node (asn1_node_const pointer, const char *name)
-+{
-+  asn1_node_const p;
-+  char *n_end, n[ASN1_MAX_NAME_SIZE + 1];
-+  const char *n_start;
-+  unsigned int nsize;
-+  unsigned int nhash;
-+
-+  if (pointer == NULL)
-+    return NULL;
-+
-+  if (name == NULL)
-+    return NULL;
-+
-+  p = pointer;
-+  n_start = name;
-+
-+  if (name[0] == '?' && name[1] == 'C' && p->name[0] == '?')
-+    { /* ?CURRENT */
-+      n_start = strchr(n_start, '.');
-+      if (n_start)
-+        n_start++;
-+    }
-+  else if (p->name[0] != 0)
-+    {				/* has *pointer got a name ? */
-+      n_end = strchr (n_start, '.');	/* search the first dot */
-+      if (n_end)
-+	{
-+	  nsize = n_end - n_start;
-+	  if (nsize >= sizeof(n))
-+		return NULL;
-+
-+	  memcpy (n, n_start, nsize);
-+	  n[nsize] = 0;
-+	  n_start = n_end;
-+	  n_start++;
-+
-+	  nhash = _asn1_hash_name (n);
-+	}
-+      else
-+	{
-+	  _asn1_str_cpy (n, sizeof (n), n_start);
-+	  nhash = _asn1_hash_name (n);
-+
-+	  n_start = NULL;
-+	}
-+
-+      while (p)
-+	{
-+	  if (nhash == p->name_hash && (!strcmp (p->name, n)))
-+	    break;
-+	  else
-+	    p = p->right;
-+	}			/* while */
-+
-+      if (p == NULL)
-+	return NULL;
-+    }
-+  else
-+    {				/* *pointer doesn't have a name */
-+      if (n_start[0] == 0)
-+	return (asn1_node) p;
-+    }
-+
-+  while (n_start)
-+    {				/* Has the end of NAME been reached? */
-+      n_end = strchr (n_start, '.');	/* search the next dot */
-+      if (n_end)
-+	{
-+	  nsize = n_end - n_start;
-+	  if (nsize >= sizeof(n))
-+		return NULL;
-+
-+	  memcpy (n, n_start, nsize);
-+	  n[nsize] = 0;
-+	  n_start = n_end;
-+	  n_start++;
-+
-+	  nhash = _asn1_hash_name (n);
-+	}
-+      else
-+	{
-+	  _asn1_str_cpy (n, sizeof (n), n_start);
-+	  nhash = _asn1_hash_name (n);
-+	  n_start = NULL;
-+	}
-+
-+      if (p->down == NULL)
-+	return NULL;
-+
-+      p = p->down;
-+      if (p == NULL)
-+        return NULL;
-+
-+      /* The identifier "?LAST" indicates the last element
-+         in the right chain. */
-+      if (n[0] == '?' && n[1] == 'L') /* ?LAST */
-+	{
-+	  while (p->right)
-+	    p = p->right;
-+	}
-+      else
-+	{			/* no "?LAST" */
-+	  while (p)
-+	    {
-+	      if (p->name_hash == nhash && !strcmp (p->name, n))
-+		break;
-+	      else
-+		p = p->right;
-+	    }
-+	}
-+      if (p == NULL)
-+        return NULL;
-+    }				/* while */
-+
-+  return (asn1_node) p;
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_set_value                                     */
-+/* Description: sets the field VALUE in a NODE_ASN element. The   */
-+/*              previous value (if exist) will be lost            */
-+/* Parameters:                                                    */
-+/*   node: element pointer.                                       */
-+/*   value: pointer to the value that you want to set.            */
-+/*   len: character number of value.                              */
-+/* Return: pointer to the NODE_ASN element.                       */
-+/******************************************************************/
-+asn1_node
-+_asn1_set_value (asn1_node node, const void *value, unsigned int len)
-+{
-+  if (node == NULL)
-+    return node;
-+  if (node->value)
-+    {
-+      if (node->value != node->small_value)
-+	free (node->value);
-+      node->value = NULL;
-+      node->value_len = 0;
-+    }
-+
-+  if (!len)
-+    return node;
-+
-+  if (len < sizeof (node->small_value))
-+    {
-+      node->value = node->small_value;
-+    }
-+  else
-+    {
-+      node->value = malloc (len);
-+      if (node->value == NULL)
-+	return NULL;
-+    }
-+  node->value_len = len;
-+
-+  memcpy (node->value, value, len);
-+  return node;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_set_value_lv                                  */
-+/* Description: sets the field VALUE in a NODE_ASN element. The   */
-+/*              previous value (if exist) will be lost. The value */
-+/*		given is stored as an length-value format (LV     */
-+/* Parameters:                                                    */
-+/*   node: element pointer.                                       */
-+/*   value: pointer to the value that you want to set.            */
-+/*   len: character number of value.                              */
-+/* Return: pointer to the NODE_ASN element.                       */
-+/******************************************************************/
-+asn1_node
-+_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len)
-+{
-+  int len2;
-+  void *temp;
-+
-+  if (node == NULL)
-+    return node;
-+
-+  asn1_length_der (len, NULL, &len2);
-+  temp = malloc (len + len2);
-+  if (temp == NULL)
-+    return NULL;
-+
-+  asn1_octet_der (value, len, temp, &len2);
-+  return _asn1_set_value_m (node, temp, len2);
-+}
-+
-+/* the same as _asn1_set_value except that it sets an already malloc'ed
-+ * value.
-+ */
-+asn1_node
-+_asn1_set_value_m (asn1_node node, void *value, unsigned int len)
-+{
-+  if (node == NULL)
-+    return node;
-+
-+  if (node->value)
-+    {
-+      if (node->value != node->small_value)
-+	free (node->value);
-+      node->value = NULL;
-+      node->value_len = 0;
-+    }
-+
-+  if (!len)
-+    return node;
-+
-+  node->value = value;
-+  node->value_len = len;
-+
-+  return node;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_append_value                                  */
-+/* Description: appends to the field VALUE in a NODE_ASN element. */
-+/*							          */
-+/* Parameters:                                                    */
-+/*   node: element pointer.                                       */
-+/*   value: pointer to the value that you want to be appended.    */
-+/*   len: character number of value.                              */
-+/* Return: pointer to the NODE_ASN element.                       */
-+/******************************************************************/
-+asn1_node
-+_asn1_append_value (asn1_node node, const void *value, unsigned int len)
-+{
-+  if (node == NULL)
-+    return node;
-+
-+  if (node->value == NULL)
-+    return _asn1_set_value (node, value, len);
-+
-+  if (len == 0)
-+    return node;
-+
-+  if (node->value == node->small_value)
-+    {
-+      /* value is in node */
-+      int prev_len = node->value_len;
-+      node->value_len += len;
-+      node->value = malloc (node->value_len);
-+      if (node->value == NULL)
-+	{
-+	  node->value_len = 0;
-+	  return NULL;
-+	}
-+
-+      if (prev_len > 0)
-+        memcpy (node->value, node->small_value, prev_len);
-+
-+      memcpy (&node->value[prev_len], value, len);
-+
-+      return node;
-+    }
-+  else /* if (node->value != NULL && node->value != node->small_value) */
-+    {
-+      /* value is allocated */
-+      int prev_len = node->value_len;
-+      node->value_len += len;
-+
-+      node->value = _asn1_realloc (node->value, node->value_len);
-+      if (node->value == NULL)
-+	{
-+	  node->value_len = 0;
-+	  return NULL;
-+	}
-+
-+      memcpy (&node->value[prev_len], value, len);
-+
-+      return node;
-+    }
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_set_name                                      */
-+/* Description: sets the field NAME in a NODE_ASN element. The    */
-+/*              previous value (if exist) will be lost            */
-+/* Parameters:                                                    */
-+/*   node: element pointer.                                       */
-+/*   name: a null terminated string with the name that you want   */
-+/*         to set.                                                */
-+/* Return: pointer to the NODE_ASN element.                       */
-+/******************************************************************/
-+asn1_node
-+_asn1_set_name (asn1_node node, const char *name)
-+{
-+  if (node == NULL)
-+    return node;
-+
-+  _asn1_str_cpy (node->name, sizeof (node->name), name ? name : "");
-+  node->name_hash = _asn1_hash_name (node->name);
-+
-+  return node;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_cpy_name                                      */
-+/* Description: copies the field NAME in a NODE_ASN element.      */
-+/* Parameters:                                                    */
-+/*   dst: a dest element pointer.                                 */
-+/*   src: a source element pointer.                               */
-+/* Return: pointer to the NODE_ASN element.                       */
-+/******************************************************************/
-+asn1_node
-+_asn1_cpy_name (asn1_node dst, asn1_node_const src)
-+{
-+  if (dst == NULL)
-+    return dst;
-+
-+  if (src == NULL)
-+    {
-+      dst->name[0] = 0;
-+      dst->name_hash = _asn1_hash_name (dst->name);
-+      return dst;
-+    }
-+
-+  _asn1_str_cpy (dst->name, sizeof (dst->name), src->name);
-+  dst->name_hash = src->name_hash;
-+
-+  return dst;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_set_right                                     */
-+/* Description: sets the field RIGHT in a NODE_ASN element.       */
-+/* Parameters:                                                    */
-+/*   node: element pointer.                                       */
-+/*   right: pointer to a NODE_ASN element that you want be pointed*/
-+/*          by NODE.                                              */
-+/* Return: pointer to *NODE.                                      */
-+/******************************************************************/
-+asn1_node
-+_asn1_set_right (asn1_node node, asn1_node right)
-+{
-+  if (node == NULL)
-+    return node;
-+  node->right = right;
-+  if (right)
-+    right->left = node;
-+  return node;
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_get_last_right                                */
-+/* Description: return the last element along the right chain.    */
-+/* Parameters:                                                    */
-+/*   node: starting element pointer.                              */
-+/* Return: pointer to the last element along the right chain.     */
-+/******************************************************************/
-+asn1_node
-+_asn1_get_last_right (asn1_node_const node)
-+{
-+  asn1_node_const p;
-+
-+  if (node == NULL)
-+    return NULL;
-+  p = node;
-+  while (p->right)
-+    p = p->right;
-+  return (asn1_node) p;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_remove_node                                   */
-+/* Description: gets free the memory allocated for an NODE_ASN    */
-+/*              element (not the elements pointed by it).         */
-+/* Parameters:                                                    */
-+/*   node: NODE_ASN element pointer.                              */
-+/*   flags: ASN1_DELETE_FLAG_*                                    */
-+/******************************************************************/
-+void
-+_asn1_remove_node (asn1_node node, unsigned int flags)
-+{
-+  if (node == NULL)
-+    return;
-+
-+  if (node->value != NULL)
-+    {
-+      if (flags & ASN1_DELETE_FLAG_ZEROIZE)
-+        {
-+          safe_memset(node->value, 0, node->value_len);
-+        }
-+
-+      if (node->value != node->small_value)
-+        free (node->value);
-+    }
-+  free (node);
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_find_up                                       */
-+/* Description: return the father of the NODE_ASN element.        */
-+/* Parameters:                                                    */
-+/*   node: NODE_ASN element pointer.                              */
-+/* Return: Null if not found.                                     */
-+/******************************************************************/
-+asn1_node
-+_asn1_find_up (asn1_node_const node)
-+{
-+  asn1_node_const p;
-+
-+  if (node == NULL)
-+    return NULL;
-+
-+  p = node;
-+
-+  while ((p->left != NULL) && (p->left->right == p))
-+    p = p->left;
-+
-+  return p->left;
-+}
-+
-+static
-+unsigned _asn1_is_up (asn1_node_const up_cand, asn1_node_const down)
-+{
-+  asn1_node_const d, u;
-+
-+  if (up_cand == NULL || down == NULL)
-+    return 0;
-+
-+  d = down;
-+
-+  while ((u = _asn1_find_up(d)) != NULL && u != d)
-+    {
-+      if (u == up_cand)
-+        return 1;
-+      d = u;
-+    }
-+
-+  return 0;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_delete_node_from_list                         */
-+/* Description: deletes the list element given                    */
-+/******************************************************************/
-+void
-+_asn1_delete_node_from_list (list_type *list, asn1_node node)
-+{
-+  list_type *p = list;
-+
-+  while (p)
-+    {
-+      if (p->node == node)
-+        p->node = NULL;
-+      p = p->next;
-+    }
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_delete_list                                   */
-+/* Description: deletes the list elements (not the elements       */
-+/*  pointed by them).                                             */
-+/******************************************************************/
-+void
-+_asn1_delete_list (list_type *e_list)
-+{
-+  list_type *p;
-+
-+  while (e_list)
-+    {
-+      p = e_list;
-+      e_list = e_list->next;
-+      free (p);
-+    }
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_delete_list_and nodes                         */
-+/* Description: deletes the list elements and the elements        */
-+/*  pointed by them.                                              */
-+/******************************************************************/
-+void
-+_asn1_delete_list_and_nodes (list_type *e_list)
-+{
-+  list_type *p;
-+
-+  while (e_list)
-+    {
-+      p = e_list;
-+      e_list = e_list->next;
-+      _asn1_remove_node (p->node, 0);
-+      free (p);
-+    }
-+}
-+
-+
-+char *
-+_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE])
-+{
-+  uint64_t d, r;
-+  char temp[LTOSTR_MAX_SIZE];
-+  int count, k, start;
-+  uint64_t val;
-+
-+  if (v < 0)
-+    {
-+      str[0] = '-';
-+      start = 1;
-+      val = -((uint64_t)v);
-+    }
-+  else
-+    {
-+      val = v;
-+      start = 0;
-+    }
-+
-+  count = 0;
-+  do
-+    {
-+      d = val / 10;
-+      r = val - d * 10;
-+      temp[start + count] = '0' + (char) r;
-+      count++;
-+      val = d;
-+    }
-+  while (val && ((start+count) < LTOSTR_MAX_SIZE-1));
-+
-+  for (k = 0; k < count; k++)
-+    str[k + start] = temp[start + count - k - 1];
-+  str[count + start] = 0;
-+  return str;
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_change_integer_value                          */
-+/* Description: converts into DER coding the value assign to an   */
-+/*   INTEGER constant.                                            */
-+/* Parameters:                                                    */
-+/*   node: root of an ASN1element.                                */
-+/* Return:                                                        */
-+/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                       */
-+/*   otherwise ASN1_SUCCESS                                             */
-+/******************************************************************/
-+int
-+_asn1_change_integer_value (asn1_node node)
-+{
-+  asn1_node p;
-+  unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
-+  unsigned char val2[SIZEOF_UNSIGNED_LONG_INT + 1];
-+  int len;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node;
-+  while (p)
-+    {
-+      if ((type_field (p->type) == ASN1_ETYPE_INTEGER)
-+	  && (p->type & CONST_ASSIGN))
-+	{
-+	  if (p->value)
-+	    {
-+	      _asn1_convert_integer (p->value, val, sizeof (val), &len);
-+	      asn1_octet_der (val, len, val2, &len);
-+	      _asn1_set_value (p, val2, len);
-+	    }
-+	}
-+
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	}
-+      else
-+	{
-+	  if (p == node)
-+	    p = NULL;
-+	  else if (p->right)
-+	    p = p->right;
-+	  else
-+	    {
-+	      while (1)
-+		{
-+		  p = _asn1_find_up (p);
-+		  if (p == node)
-+		    {
-+		      p = NULL;
-+		      break;
-+		    }
-+		  if (p && p->right)
-+		    {
-+		      p = p->right;
-+		      break;
-+		    }
-+		}
-+	    }
-+	}
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+#define MAX_CONSTANTS 1024
-+/******************************************************************/
-+/* Function : _asn1_expand_object_id                              */
-+/* Description: expand the IDs of an OBJECT IDENTIFIER constant.  */
-+/* Parameters:                                                    */
-+/*   list: root of an object list                                 */
-+/*   node: root of an ASN1 element.                               */
-+/* Return:                                                        */
-+/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                      */
-+/*   otherwise ASN1_SUCCESS                                       */
-+/******************************************************************/
-+int
-+_asn1_expand_object_id (list_type **list, asn1_node node)
-+{
-+  asn1_node p, p2, p3, p4, p5;
-+  char name_root[ASN1_MAX_NAME_SIZE], name2[2 * ASN1_MAX_NAME_SIZE + 1];
-+  int move, tlen, tries;
-+  unsigned max_constants;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  _asn1_str_cpy (name_root, sizeof (name_root), node->name);
-+
-+  p = node;
-+  move = DOWN;
-+  tries = 0;
-+
-+  while (!((p == node) && (move == UP)))
-+    {
-+      if (move != UP)
-+	{
-+	  if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID)
-+	      && (p->type & CONST_ASSIGN))
-+	    {
-+	      p2 = p->down;
-+	      if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT))
-+		{
-+		  if (p2->value && !c_isdigit (p2->value[0]))
-+		    {
-+		      _asn1_str_cpy (name2, sizeof (name2), name_root);
-+		      _asn1_str_cat (name2, sizeof (name2), ".");
-+		      _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
-+		      p3 = asn1_find_node (node, name2);
-+		      if (!p3 || _asn1_is_up(p2, p3) ||
-+			  (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ||
-+			  !(p3->type & CONST_ASSIGN))
-+			return ASN1_ELEMENT_NOT_FOUND;
-+
-+		      _asn1_set_down (p, p2->right);
-+		      if (p2->down)
-+			_asn1_delete_structure (*list, &p2->down, 0);
-+		      _asn1_delete_node_from_list(*list, p2);
-+		      _asn1_remove_node (p2, 0);
-+		      p2 = p;
-+		      p4 = p3->down;
-+		      max_constants = 0;
-+		      while (p4)
-+			{
-+			  if (type_field (p4->type) == ASN1_ETYPE_CONSTANT)
-+			    {
-+			      max_constants++;
-+			      if (max_constants == MAX_CONSTANTS)
-+                                return ASN1_RECURSION;
-+
-+			      p5 =
-+				_asn1_add_single_node (ASN1_ETYPE_CONSTANT);
-+			      _asn1_set_name (p5, p4->name);
-+			      if (p4->value)
-+			        {
-+			          tlen = _asn1_strlen (p4->value);
-+			          if (tlen > 0)
-+			            _asn1_set_value (p5, p4->value, tlen + 1);
-+			        }
-+			      _asn1_add_static_node2(list, p5);
-+
-+			      if (p2 == p)
-+				{
-+				  _asn1_set_right (p5, p->down);
-+				  _asn1_set_down (p, p5);
-+				}
-+			      else
-+				{
-+				  _asn1_set_right (p5, p2->right);
-+				  _asn1_set_right (p2, p5);
-+				}
-+			      p2 = p5;
-+			    }
-+			  p4 = p4->right;
-+			}
-+		      move = DOWN;
-+
-+		      tries++;
-+                      if (tries >= EXPAND_OBJECT_ID_MAX_RECURSION)
-+                        return ASN1_RECURSION;
-+
-+		      continue;
-+		    }
-+		}
-+	    }
-+	  move = DOWN;
-+	}
-+      else
-+	move = RIGHT;
-+
-+      tries = 0;
-+      if (move == DOWN)
-+	{
-+	  if (p->down)
-+	    p = p->down;
-+	  else
-+	    move = RIGHT;
-+	}
-+
-+      if (p == node)
-+	{
-+	  move = UP;
-+	  continue;
-+	}
-+
-+      if (move == RIGHT)
-+	{
-+	  if (p && p->right)
-+	    p = p->right;
-+	  else
-+	    move = UP;
-+	}
-+      if (move == UP)
-+	p = _asn1_find_up (p);
-+    }
-+
-+  /*******************************/
-+  /*       expand DEFAULT        */
-+  /*******************************/
-+  p = node;
-+  move = DOWN;
-+
-+  while (!((p == node) && (move == UP)))
-+    {
-+      if (move != UP)
-+	{
-+	  if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
-+	      (p->type & CONST_DEFAULT))
-+	    {
-+	      p2 = p->down;
-+	      if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT))
-+		{
-+		  _asn1_str_cpy (name2, sizeof (name2), name_root);
-+		  _asn1_str_cat (name2, sizeof (name2), ".");
-+		  if (p2->value)
-+		    _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
-+		  p3 = asn1_find_node (node, name2);
-+		  if (!p3 || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID)
-+		      || !(p3->type & CONST_ASSIGN))
-+		    return ASN1_ELEMENT_NOT_FOUND;
-+		  p4 = p3->down;
-+		  name2[0] = 0;
-+		  while (p4)
-+		    {
-+		      if (type_field (p4->type) == ASN1_ETYPE_CONSTANT)
-+			{
-+			  if (p4->value == NULL)
-+			    return ASN1_VALUE_NOT_FOUND;
-+
-+			  if (name2[0])
-+			    _asn1_str_cat (name2, sizeof (name2), ".");
-+			  _asn1_str_cat (name2, sizeof (name2),
-+					 (char *) p4->value);
-+			}
-+		      p4 = p4->right;
-+		    }
-+		  tlen = strlen (name2);
-+		  if (tlen > 0)
-+		    _asn1_set_value (p2, name2, tlen + 1);
-+		}
-+	    }
-+	  move = DOWN;
-+	}
-+      else
-+	move = RIGHT;
-+
-+      if (move == DOWN)
-+	{
-+	  if (p->down)
-+	    p = p->down;
-+	  else
-+	    move = RIGHT;
-+	}
-+
-+      if (p == node)
-+	{
-+	  move = UP;
-+	  continue;
-+	}
-+
-+      if (move == RIGHT)
-+	{
-+	  if (p && p->right)
-+	    p = p->right;
-+	  else
-+	    move = UP;
-+	}
-+      if (move == UP)
-+	p = _asn1_find_up (p);
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_type_set_config                               */
-+/* Description: sets the CONST_SET and CONST_NOT_USED properties  */
-+/*   in the fields of the SET elements.                           */
-+/* Parameters:                                                    */
-+/*   node: root of an ASN1 element.                               */
-+/* Return:                                                        */
-+/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                       */
-+/*   otherwise ASN1_SUCCESS                                             */
-+/******************************************************************/
-+int
-+_asn1_type_set_config (asn1_node node)
-+{
-+  asn1_node p, p2;
-+  int move;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node;
-+  move = DOWN;
-+
-+  while (!((p == node) && (move == UP)))
-+    {
-+      if (move != UP)
-+	{
-+	  if (type_field (p->type) == ASN1_ETYPE_SET)
-+	    {
-+	      p2 = p->down;
-+	      while (p2)
-+		{
-+		  if (type_field (p2->type) != ASN1_ETYPE_TAG)
-+		    p2->type |= CONST_SET | CONST_NOT_USED;
-+		  p2 = p2->right;
-+		}
-+	    }
-+	  move = DOWN;
-+	}
-+      else
-+	move = RIGHT;
-+
-+      if (move == DOWN)
-+	{
-+	  if (p->down)
-+	    p = p->down;
-+	  else
-+	    move = RIGHT;
-+	}
-+
-+      if (p == node)
-+	{
-+	  move = UP;
-+	  continue;
-+	}
-+
-+      if (move == RIGHT)
-+	{
-+	  if (p && p->right)
-+	    p = p->right;
-+	  else
-+	    move = UP;
-+	}
-+      if (move == UP)
-+	p = _asn1_find_up (p);
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_check_identifier                              */
-+/* Description: checks the definitions of all the identifiers     */
-+/*   and the first element of an OBJECT_ID (e.g. {pkix 0 4}).     */
-+/*   The _asn1_identifierMissing global variable is filled if     */
-+/*   necessary.                                                   */
-+/* Parameters:                                                    */
-+/*   node: root of an ASN1 element.                               */
-+/* Return:                                                        */
-+/*   ASN1_ELEMENT_NOT_FOUND      if NODE is NULL,                 */
-+/*   ASN1_IDENTIFIER_NOT_FOUND   if an identifier is not defined, */
-+/*   otherwise ASN1_SUCCESS                                       */
-+/******************************************************************/
-+int
-+_asn1_check_identifier (asn1_node_const node)
-+{
-+  asn1_node_const p, p2;
-+  char name2[ASN1_MAX_NAME_SIZE * 2 + 2];
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node;
-+  while (p)
-+    {
-+      if (p->value && type_field (p->type) == ASN1_ETYPE_IDENTIFIER)
-+	{
-+	  _asn1_str_cpy (name2, sizeof (name2), node->name);
-+	  _asn1_str_cat (name2, sizeof (name2), ".");
-+	  _asn1_str_cat (name2, sizeof (name2), (char *) p->value);
-+	  p2 = asn1_find_node (node, name2);
-+	  if (p2 == NULL)
-+	    {
-+	      if (p->value)
-+		_asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p->value);
-+	      else
-+		_asn1_strcpy (_asn1_identifierMissing, "(null)");
-+	      return ASN1_IDENTIFIER_NOT_FOUND;
-+	    }
-+	}
-+      else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
-+	       (p->type & CONST_DEFAULT))
-+	{
-+	  p2 = p->down;
-+	  if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT))
-+	    {
-+	      _asn1_str_cpy (name2, sizeof (name2), node->name);
-+	      if (p2->value)
-+	        {
-+	          _asn1_str_cat (name2, sizeof (name2), ".");
-+	          _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
-+	          _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value);
-+	        }
-+	      else
-+		_asn1_strcpy (_asn1_identifierMissing, "(null)");
-+
-+	      p2 = asn1_find_node (node, name2);
-+	      if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) ||
-+		  !(p2->type & CONST_ASSIGN))
-+		return ASN1_IDENTIFIER_NOT_FOUND;
-+	      else
-+		_asn1_identifierMissing[0] = 0;
-+	    }
-+	}
-+      else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
-+	       (p->type & CONST_ASSIGN))
-+	{
-+	  p2 = p->down;
-+	  if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT))
-+	    {
-+	      if (p2->value && !c_isdigit (p2->value[0]))
-+		{
-+		  _asn1_str_cpy (name2, sizeof (name2), node->name);
-+		  _asn1_str_cat (name2, sizeof (name2), ".");
-+		  _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
-+		  _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value);
-+
-+		  p2 = asn1_find_node (node, name2);
-+		  if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID)
-+		      || !(p2->type & CONST_ASSIGN))
-+		    return ASN1_IDENTIFIER_NOT_FOUND;
-+		  else
-+		    _asn1_identifierMissing[0] = 0;
-+		}
-+	    }
-+	}
-+
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	}
-+      else if (p->right)
-+	p = p->right;
-+      else
-+	{
-+	  while (p)
-+	    {
-+	      p = _asn1_find_up (p);
-+	      if (p == node)
-+		{
-+		  p = NULL;
-+		  break;
-+		}
-+	      if (p && p->right)
-+		{
-+		  p = p->right;
-+		  break;
-+		}
-+	    }
-+	}
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_set_default_tag                               */
-+/* Description: sets the default IMPLICIT or EXPLICIT property in */
-+/*   the tagged elements that don't have this declaration.        */
-+/* Parameters:                                                    */
-+/*   node: pointer to a DEFINITIONS element.                      */
-+/* Return:                                                        */
-+/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to   */
-+/*     a DEFINITIONS element,                                     */
-+/*   otherwise ASN1_SUCCESS                                       */
-+/******************************************************************/
-+int
-+_asn1_set_default_tag (asn1_node node)
-+{
-+  asn1_node p;
-+
-+  if ((node == NULL) || (type_field (node->type) != ASN1_ETYPE_DEFINITIONS))
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node;
-+  while (p)
-+    {
-+      if ((type_field (p->type) == ASN1_ETYPE_TAG) &&
-+	  !(p->type & CONST_EXPLICIT) && !(p->type & CONST_IMPLICIT))
-+	{
-+	  if (node->type & CONST_EXPLICIT)
-+	    p->type |= CONST_EXPLICIT;
-+	  else
-+	    p->type |= CONST_IMPLICIT;
-+	}
-+
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	}
-+      else if (p->right)
-+	p = p->right;
-+      else
-+	{
-+	  while (1)
-+	    {
-+	      p = _asn1_find_up (p);
-+	      if (p == node)
-+		{
-+		  p = NULL;
-+		  break;
-+		}
-+	      if (p && p->right)
-+		{
-+		  p = p->right;
-+		  break;
-+		}
-+	    }
-+	}
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c
-new file mode 100644
-index 00000000000..8189c56a4c9
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/structure.c
-@@ -0,0 +1,1220 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+
-+/*****************************************************/
-+/* File: structure.c                                 */
-+/* Description: Functions to create and delete an    */
-+/*  ASN1 tree.                                       */
-+/*****************************************************/
-+
-+
-+#include <int.h>
-+#include <structure.h>
-+#include "parser_aux.h"
-+#include <gstr.h>
-+
-+
-+extern char _asn1_identifierMissing[];
-+
-+
-+/******************************************************/
-+/* Function : _asn1_add_single_node                     */
-+/* Description: creates a new NODE_ASN element.       */
-+/* Parameters:                                        */
-+/*   type: type of the new element (see ASN1_ETYPE_         */
-+/*         and CONST_ constants).                     */
-+/* Return: pointer to the new element.                */
-+/******************************************************/
-+asn1_node
-+_asn1_add_single_node (unsigned int type)
-+{
-+  asn1_node punt;
-+
-+  punt = calloc (1, sizeof (struct asn1_node_st));
-+  if (punt == NULL)
-+    return NULL;
-+
-+  punt->type = type;
-+
-+  return punt;
-+}
-+
-+
-+/******************************************************************/
-+/* Function : _asn1_find_left                                     */
-+/* Description: returns the NODE_ASN element with RIGHT field that*/
-+/*              points the element NODE.                          */
-+/* Parameters:                                                    */
-+/*   node: NODE_ASN element pointer.                              */
-+/* Return: NULL if not found.                                     */
-+/******************************************************************/
-+asn1_node
-+_asn1_find_left (asn1_node_const node)
-+{
-+  if ((node == NULL) || (node->left == NULL) || (node->left->down == node))
-+    return NULL;
-+
-+  return node->left;
-+}
-+
-+
-+int
-+_asn1_create_static_structure (asn1_node_const pointer, char *output_file_name,
-+			       char *vector_name)
-+{
-+  FILE *file;
-+  asn1_node_const p;
-+  unsigned long t;
-+
-+  file = fopen (output_file_name, "w");
-+
-+  if (file == NULL)
-+    return ASN1_FILE_NOT_FOUND;
-+
-+  fprintf (file, "#if HAVE_CONFIG_H\n");
-+  fprintf (file, "# include \"config.h\"\n");
-+  fprintf (file, "#endif\n\n");
-+
-+  fprintf (file, "#include <libtasn1.h>\n\n");
-+
-+  fprintf (file, "const asn1_static_node %s[] = {\n", vector_name);
-+
-+  p = pointer;
-+
-+  while (p)
-+    {
-+      fprintf (file, "  { ");
-+
-+      if (p->name[0] != 0)
-+	fprintf (file, "\"%s\", ", p->name);
-+      else
-+	fprintf (file, "NULL, ");
-+
-+      t = p->type;
-+      if (p->down)
-+	t |= CONST_DOWN;
-+      if (p->right)
-+	t |= CONST_RIGHT;
-+
-+      fprintf (file, "%lu, ", t);
-+
-+      if (p->value)
-+	fprintf (file, "\"%s\"},\n", p->value);
-+      else
-+	fprintf (file, "NULL },\n");
-+
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	}
-+      else if (p->right)
-+	{
-+	  p = p->right;
-+	}
-+      else
-+	{
-+	  while (1)
-+	    {
-+	      p = _asn1_find_up (p);
-+	      if (p == pointer)
-+		{
-+		  p = NULL;
-+		  break;
-+		}
-+	      if (p->right)
-+		{
-+		  p = p->right;
-+		  break;
-+		}
-+	    }
-+	}
-+    }
-+
-+  fprintf (file, "  { NULL, 0, NULL }\n};\n");
-+
-+  fclose (file);
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/**
-+ * asn1_array2tree:
-+ * @array: specify the array that contains ASN.1 declarations
-+ * @definitions: return the pointer to the structure created by
-+ *   *ARRAY ASN.1 declarations
-+ * @errorDescription: return the error description.
-+ *
-+ * Creates the structures needed to manage the ASN.1 definitions.
-+ * @array is a vector created by asn1_parser2array().
-+ *
-+ * Returns: %ASN1_SUCCESS if structure was created correctly,
-+ *   %ASN1_ELEMENT_NOT_EMPTY if *@definitions not NULL,
-+ *   %ASN1_IDENTIFIER_NOT_FOUND if in the file there is an identifier
-+ *   that is not defined (see @errorDescription for more information),
-+ *   %ASN1_ARRAY_ERROR if the array pointed by @array is wrong.
-+ **/
-+int
-+asn1_array2tree (const asn1_static_node * array, asn1_node * definitions,
-+		 char *errorDescription)
-+{
-+  asn1_node p, p_last = NULL;
-+  unsigned long k;
-+  int move;
-+  int result;
-+  unsigned int type;
-+  list_type *e_list = NULL;
-+
-+  if (errorDescription)
-+    errorDescription[0] = 0;
-+
-+  if (*definitions != NULL)
-+    return ASN1_ELEMENT_NOT_EMPTY;
-+
-+  move = UP;
-+
-+  for (k = 0; array[k].value || array[k].type || array[k].name; k++)
-+    {
-+      type = convert_old_type (array[k].type);
-+
-+      p = _asn1_add_static_node (&e_list, type & (~CONST_DOWN));
-+      if (array[k].name)
-+	_asn1_set_name (p, array[k].name);
-+      if (array[k].value)
-+	_asn1_set_value (p, array[k].value, strlen (array[k].value) + 1);
-+
-+      if (*definitions == NULL)
-+	*definitions = p;
-+
-+      if (move == DOWN)
-+	{
-+	  if (p_last && p_last->down)
-+	      _asn1_delete_structure (e_list, &p_last->down, 0);
-+	  _asn1_set_down (p_last, p);
-+	}
-+      else if (move == RIGHT)
-+        {
-+	  if (p_last && p_last->right)
-+	      _asn1_delete_structure (e_list, &p_last->right, 0);
-+	  _asn1_set_right (p_last, p);
-+        }
-+
-+      p_last = p;
-+
-+      if (type & CONST_DOWN)
-+	move = DOWN;
-+      else if (type & CONST_RIGHT)
-+	move = RIGHT;
-+      else
-+	{
-+	  while (p_last != *definitions)
-+	    {
-+	      p_last = _asn1_find_up (p_last);
-+
-+	      if (p_last == NULL)
-+		break;
-+
-+	      if (p_last->type & CONST_RIGHT)
-+		{
-+		  p_last->type &= ~CONST_RIGHT;
-+		  move = RIGHT;
-+		  break;
-+		}
-+	    }			/* while */
-+	}
-+    }				/* while */
-+
-+  if (p_last == *definitions)
-+    {
-+      result = _asn1_check_identifier (*definitions);
-+      if (result == ASN1_SUCCESS)
-+	{
-+	  _asn1_change_integer_value (*definitions);
-+	  result = _asn1_expand_object_id (&e_list, *definitions);
-+	}
-+    }
-+  else
-+    {
-+      result = ASN1_ARRAY_ERROR;
-+    }
-+
-+  if (errorDescription != NULL)
-+    {
-+      if (result == ASN1_IDENTIFIER_NOT_FOUND)
-+	{
-+	  Estrcpy (errorDescription, ":: identifier '");
-+	  Estrcat (errorDescription, _asn1_identifierMissing);
-+	  Estrcat (errorDescription, "' not found");
-+	}
-+      else
-+	errorDescription[0] = 0;
-+    }
-+
-+  if (result != ASN1_SUCCESS)
-+    {
-+      _asn1_delete_list_and_nodes (e_list);
-+      *definitions = NULL;
-+    }
-+  else
-+    _asn1_delete_list (e_list);
-+
-+  return result;
-+}
-+
-+/**
-+ * asn1_delete_structure:
-+ * @structure: pointer to the structure that you want to delete.
-+ *
-+ * Deletes the structure *@structure.  At the end, *@structure is set
-+ * to NULL.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
-+ *   *@structure was NULL.
-+ **/
-+int
-+asn1_delete_structure (asn1_node * structure)
-+{
-+  return _asn1_delete_structure (NULL, structure, 0);
-+}
-+
-+/**
-+ * asn1_delete_structure2:
-+ * @structure: pointer to the structure that you want to delete.
-+ * @flags: additional flags (see %ASN1_DELETE_FLAG)
-+ *
-+ * Deletes the structure *@structure.  At the end, *@structure is set
-+ * to NULL.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
-+ *   *@structure was NULL.
-+ **/
-+int
-+asn1_delete_structure2 (asn1_node * structure, unsigned int flags)
-+{
-+  return _asn1_delete_structure (NULL, structure, flags);
-+}
-+
-+int
-+_asn1_delete_structure (list_type *e_list, asn1_node * structure, unsigned int flags)
-+{
-+  asn1_node p, p2, p3;
-+
-+  if (*structure == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = *structure;
-+  while (p)
-+    {
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	}
-+      else
-+	{			/* no down */
-+	  p2 = p->right;
-+	  if (p != *structure)
-+	    {
-+	      p3 = _asn1_find_up (p);
-+	      _asn1_set_down (p3, p2);
-+	      if (e_list)
-+		_asn1_delete_node_from_list (e_list, p);
-+	      _asn1_remove_node (p, flags);
-+	      p = p3;
-+	    }
-+	  else
-+	    {			/* p==root */
-+	      p3 = _asn1_find_left (p);
-+	      if (!p3)
-+		{
-+		  p3 = _asn1_find_up (p);
-+		  if (p3)
-+		    _asn1_set_down (p3, p2);
-+		  else
-+		    {
-+		      if (p->right)
-+			p->right->left = NULL;
-+		    }
-+		}
-+	      else
-+		_asn1_set_right (p3, p2);
-+	      if (e_list)
-+		_asn1_delete_node_from_list (e_list, p);
-+	      _asn1_remove_node (p, flags);
-+	      p = NULL;
-+	    }
-+	}
-+    }
-+
-+  *structure = NULL;
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/**
-+ * asn1_delete_element:
-+ * @structure: pointer to the structure that contains the element you
-+ *   want to delete.
-+ * @element_name: element's name you want to delete.
-+ *
-+ * Deletes the element named *@element_name inside *@structure.
-+ *
-+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
-+ *   the @element_name was not found.
-+ **/
-+int
-+asn1_delete_element (asn1_node structure, const char *element_name)
-+{
-+  asn1_node p2, p3, source_node;
-+
-+  source_node = asn1_find_node (structure, element_name);
-+
-+  if (source_node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p2 = source_node->right;
-+  p3 = _asn1_find_left (source_node);
-+  if (!p3)
-+    {
-+      p3 = _asn1_find_up (source_node);
-+      if (p3)
-+	_asn1_set_down (p3, p2);
-+      else if (source_node->right)
-+	source_node->right->left = NULL;
-+    }
-+  else
-+    _asn1_set_right (p3, p2);
-+
-+  return asn1_delete_structure (&source_node);
-+}
-+
-+#ifndef __clang_analyzer__
-+asn1_node
-+_asn1_copy_structure3 (asn1_node_const source_node)
-+{
-+  asn1_node_const p_s;
-+  asn1_node dest_node, p_d, p_d_prev;
-+  int move;
-+
-+  if (source_node == NULL)
-+    return NULL;
-+
-+  dest_node = _asn1_add_single_node (source_node->type);
-+
-+  p_s = source_node;
-+  p_d = dest_node;
-+
-+  move = DOWN;
-+
-+  do
-+    {
-+      if (move != UP)
-+	{
-+	  if (p_s->name[0] != 0)
-+	    _asn1_cpy_name (p_d, p_s);
-+	  if (p_s->value)
-+	    _asn1_set_value (p_d, p_s->value, p_s->value_len);
-+	  if (p_s->down)
-+	    {
-+	      p_s = p_s->down;
-+	      p_d_prev = p_d;
-+	      p_d = _asn1_add_single_node (p_s->type);
-+	      _asn1_set_down (p_d_prev, p_d);
-+	      continue;
-+	    }
-+	  p_d->start = p_s->start;
-+	  p_d->end = p_s->end;
-+	}
-+
-+      if (p_s == source_node)
-+	break;
-+
-+      if (p_s->right)
-+	{
-+	  move = RIGHT;
-+	  p_s = p_s->right;
-+	  p_d_prev = p_d;
-+	  p_d = _asn1_add_single_node (p_s->type);
-+	  _asn1_set_right (p_d_prev, p_d);
-+	}
-+      else
-+	{
-+	  move = UP;
-+	  p_s = _asn1_find_up (p_s);
-+	  p_d = _asn1_find_up (p_d);
-+	}
-+    }
-+  while (p_s != source_node);
-+  return dest_node;
-+}
-+#else
-+
-+/* Non-production code */
-+asn1_node
-+_asn1_copy_structure3 (asn1_node_const source_node)
-+{
-+  return NULL;
-+}
-+#endif /* __clang_analyzer__ */
-+
-+
-+static asn1_node
-+_asn1_copy_structure2 (asn1_node_const root, const char *source_name)
-+{
-+  asn1_node source_node;
-+
-+  source_node = asn1_find_node (root, source_name);
-+
-+  return _asn1_copy_structure3 (source_node);
-+
-+}
-+
-+
-+static int
-+_asn1_type_choice_config (asn1_node node)
-+{
-+  asn1_node p, p2, p3, p4;
-+  int move, tlen;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node;
-+  move = DOWN;
-+
-+  while (!((p == node) && (move == UP)))
-+    {
-+      if (move != UP)
-+	{
-+	  if ((type_field (p->type) == ASN1_ETYPE_CHOICE)
-+	      && (p->type & CONST_TAG))
-+	    {
-+	      p2 = p->down;
-+	      while (p2)
-+		{
-+		  if (type_field (p2->type) != ASN1_ETYPE_TAG)
-+		    {
-+		      p2->type |= CONST_TAG;
-+		      p3 = _asn1_find_left (p2);
-+		      while (p3)
-+			{
-+			  if (type_field (p3->type) == ASN1_ETYPE_TAG)
-+			    {
-+			      p4 = _asn1_add_single_node (p3->type);
-+			      tlen = _asn1_strlen (p3->value);
-+			      if (tlen > 0)
-+				_asn1_set_value (p4, p3->value, tlen + 1);
-+			      _asn1_set_right (p4, p2->down);
-+			      _asn1_set_down (p2, p4);
-+			    }
-+			  p3 = _asn1_find_left (p3);
-+			}
-+		    }
-+		  p2 = p2->right;
-+		}
-+	      p->type &= ~(CONST_TAG);
-+	      p2 = p->down;
-+	      while (p2)
-+		{
-+		  p3 = p2->right;
-+		  if (type_field (p2->type) == ASN1_ETYPE_TAG)
-+		    asn1_delete_structure (&p2);
-+		  p2 = p3;
-+		}
-+	    }
-+	  move = DOWN;
-+	}
-+      else
-+	move = RIGHT;
-+
-+      if (move == DOWN)
-+	{
-+	  if (p->down)
-+	    p = p->down;
-+	  else
-+	    move = RIGHT;
-+	}
-+
-+      if (p == node)
-+	{
-+	  move = UP;
-+	  continue;
-+	}
-+
-+      if (move == RIGHT)
-+	{
-+	  if (p->right)
-+	    p = p->right;
-+	  else
-+	    move = UP;
-+	}
-+      if (move == UP)
-+	p = _asn1_find_up (p);
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+static int
-+_asn1_expand_identifier (asn1_node * node, asn1_node_const root)
-+{
-+  asn1_node p, p2, p3;
-+  char name2[ASN1_MAX_NAME_SIZE + 2];
-+  int move;
-+
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = *node;
-+  move = DOWN;
-+
-+  while (!((p == *node) && (move == UP)))
-+    {
-+      if (move != UP)
-+	{
-+	  if (type_field (p->type) == ASN1_ETYPE_IDENTIFIER)
-+	    {
-+	      snprintf (name2, sizeof (name2), "%s.%s", root->name, p->value);
-+	      p2 = _asn1_copy_structure2 (root, name2);
-+	      if (p2 == NULL)
-+		{
-+		  return ASN1_IDENTIFIER_NOT_FOUND;
-+		}
-+	      _asn1_cpy_name (p2, p);
-+	      p2->right = p->right;
-+	      p2->left = p->left;
-+	      if (p->right)
-+		p->right->left = p2;
-+	      p3 = p->down;
-+	      if (p3)
-+		{
-+		  while (p3->right)
-+		    p3 = p3->right;
-+		  _asn1_set_right (p3, p2->down);
-+		  _asn1_set_down (p2, p->down);
-+		}
-+
-+	      p3 = _asn1_find_left (p);
-+	      if (p3)
-+		_asn1_set_right (p3, p2);
-+	      else
-+		{
-+		  p3 = _asn1_find_up (p);
-+		  if (p3)
-+		    _asn1_set_down (p3, p2);
-+		  else
-+		    {
-+		      p2->left = NULL;
-+		    }
-+		}
-+
-+	      if (p->type & CONST_SIZE)
-+		p2->type |= CONST_SIZE;
-+	      if (p->type & CONST_TAG)
-+		p2->type |= CONST_TAG;
-+	      if (p->type & CONST_OPTION)
-+		p2->type |= CONST_OPTION;
-+	      if (p->type & CONST_DEFAULT)
-+		p2->type |= CONST_DEFAULT;
-+	      if (p->type & CONST_SET)
-+		p2->type |= CONST_SET;
-+	      if (p->type & CONST_NOT_USED)
-+		p2->type |= CONST_NOT_USED;
-+
-+	      if (p == *node)
-+		*node = p2;
-+	      _asn1_remove_node (p, 0);
-+	      p = p2;
-+	      move = DOWN;
-+	      continue;
-+	    }
-+	  move = DOWN;
-+	}
-+      else
-+	move = RIGHT;
-+
-+      if (move == DOWN)
-+	{
-+	  if (p->down)
-+	    p = p->down;
-+	  else
-+	    move = RIGHT;
-+	}
-+
-+      if (p == *node)
-+	{
-+	  move = UP;
-+	  continue;
-+	}
-+
-+      if (move == RIGHT)
-+	{
-+	  if (p->right)
-+	    p = p->right;
-+	  else
-+	    move = UP;
-+	}
-+      if (move == UP)
-+	p = _asn1_find_up (p);
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/**
-+ * asn1_create_element:
-+ * @definitions: pointer to the structure returned by "parser_asn1" function
-+ * @source_name: the name of the type of the new structure (must be
-+ *   inside p_structure).
-+ * @element: pointer to the structure created.
-+ *
-+ * Creates a structure of type @source_name.  Example using
-+ *  "pkix.asn":
-+ *
-+ * rc = asn1_create_element(cert_def, "PKIX1.Certificate", certptr);
-+ *
-+ * Returns: %ASN1_SUCCESS if creation OK, %ASN1_ELEMENT_NOT_FOUND if
-+ *   @source_name is not known.
-+ **/
-+int
-+asn1_create_element (asn1_node_const definitions, const char *source_name,
-+		     asn1_node * element)
-+{
-+  asn1_node dest_node;
-+  int res;
-+
-+  dest_node = _asn1_copy_structure2 (definitions, source_name);
-+
-+  if (dest_node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  _asn1_set_name (dest_node, "");
-+
-+  res = _asn1_expand_identifier (&dest_node, definitions);
-+  _asn1_type_choice_config (dest_node);
-+
-+  *element = dest_node;
-+
-+  return res;
-+}
-+
-+
-+/**
-+ * asn1_print_structure:
-+ * @out: pointer to the output file (e.g. stdout).
-+ * @structure: pointer to the structure that you want to visit.
-+ * @name: an element of the structure
-+ * @mode: specify how much of the structure to print, can be
-+ *   %ASN1_PRINT_NAME, %ASN1_PRINT_NAME_TYPE,
-+ *   %ASN1_PRINT_NAME_TYPE_VALUE, or %ASN1_PRINT_ALL.
-+ *
-+ * Prints on the @out file descriptor the structure's tree starting
-+ * from the @name element inside the structure @structure.
-+ **/
-+void
-+asn1_print_structure (FILE * out, asn1_node_const structure, const char *name,
-+		      int mode)
-+{
-+  asn1_node_const p, root;
-+  int k, indent = 0, len, len2, len3;
-+
-+  if (out == NULL)
-+    return;
-+
-+  root = asn1_find_node (structure, name);
-+
-+  if (root == NULL)
-+    return;
-+
-+  p = root;
-+  while (p)
-+    {
-+      if (mode == ASN1_PRINT_ALL)
-+	{
-+	  for (k = 0; k < indent; k++)
-+	    fprintf (out, " ");
-+	  fprintf (out, "name:");
-+	  if (p->name[0] != 0)
-+	    fprintf (out, "%s  ", p->name);
-+	  else
-+	    fprintf (out, "NULL  ");
-+	}
-+      else
-+	{
-+	  switch (type_field (p->type))
-+	    {
-+	    case ASN1_ETYPE_CONSTANT:
-+	    case ASN1_ETYPE_TAG:
-+	    case ASN1_ETYPE_SIZE:
-+	      break;
-+	    default:
-+	      for (k = 0; k < indent; k++)
-+		fprintf (out, " ");
-+	      fprintf (out, "name:");
-+	      if (p->name[0] != 0)
-+		fprintf (out, "%s  ", p->name);
-+	      else
-+		fprintf (out, "NULL  ");
-+	    }
-+	}
-+
-+      if (mode != ASN1_PRINT_NAME)
-+	{
-+	  unsigned type = type_field (p->type);
-+	  switch (type)
-+	    {
-+	    case ASN1_ETYPE_CONSTANT:
-+	      if (mode == ASN1_PRINT_ALL)
-+		fprintf (out, "type:CONST");
-+	      break;
-+	    case ASN1_ETYPE_TAG:
-+	      if (mode == ASN1_PRINT_ALL)
-+		fprintf (out, "type:TAG");
-+	      break;
-+	    case ASN1_ETYPE_SIZE:
-+	      if (mode == ASN1_PRINT_ALL)
-+		fprintf (out, "type:SIZE");
-+	      break;
-+	    case ASN1_ETYPE_DEFAULT:
-+	      fprintf (out, "type:DEFAULT");
-+	      break;
-+	    case ASN1_ETYPE_IDENTIFIER:
-+	      fprintf (out, "type:IDENTIFIER");
-+	      break;
-+	    case ASN1_ETYPE_ANY:
-+	      fprintf (out, "type:ANY");
-+	      break;
-+	    case ASN1_ETYPE_CHOICE:
-+	      fprintf (out, "type:CHOICE");
-+	      break;
-+	    case ASN1_ETYPE_DEFINITIONS:
-+	      fprintf (out, "type:DEFINITIONS");
-+	      break;
-+	    CASE_HANDLED_ETYPES:
-+	      fprintf (out, "%s", _asn1_tags[type].desc);
-+	      break;
-+	    default:
-+	      break;
-+	    }
-+	}
-+
-+      if ((mode == ASN1_PRINT_NAME_TYPE_VALUE) || (mode == ASN1_PRINT_ALL))
-+	{
-+	  switch (type_field (p->type))
-+	    {
-+	    case ASN1_ETYPE_CONSTANT:
-+	      if (mode == ASN1_PRINT_ALL)
-+		if (p->value)
-+		  fprintf (out, "  value:%s", p->value);
-+	      break;
-+	    case ASN1_ETYPE_TAG:
-+	      if (mode == ASN1_PRINT_ALL)
-+		if (p->value)
-+		  fprintf (out, "  value:%s", p->value);
-+	      break;
-+	    case ASN1_ETYPE_SIZE:
-+	      if (mode == ASN1_PRINT_ALL)
-+		if (p->value)
-+		  fprintf (out, "  value:%s", p->value);
-+	      break;
-+	    case ASN1_ETYPE_DEFAULT:
-+	      if (p->value)
-+		fprintf (out, "  value:%s", p->value);
-+	      else if (p->type & CONST_TRUE)
-+		fprintf (out, "  value:TRUE");
-+	      else if (p->type & CONST_FALSE)
-+		fprintf (out, "  value:FALSE");
-+	      break;
-+	    case ASN1_ETYPE_IDENTIFIER:
-+	      if (p->value)
-+		fprintf (out, "  value:%s", p->value);
-+	      break;
-+	    case ASN1_ETYPE_INTEGER:
-+	      if (p->value)
-+		{
-+		  len2 = -1;
-+		  len = asn1_get_length_der (p->value, p->value_len, &len2);
-+		  fprintf (out, "  value:0x");
-+		  if (len > 0)
-+		    for (k = 0; k < len; k++)
-+		      fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
-+		}
-+	      break;
-+	    case ASN1_ETYPE_ENUMERATED:
-+	      if (p->value)
-+		{
-+		  len2 = -1;
-+		  len = asn1_get_length_der (p->value, p->value_len, &len2);
-+		  fprintf (out, "  value:0x");
-+		  if (len > 0)
-+		    for (k = 0; k < len; k++)
-+		      fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
-+		}
-+	      break;
-+	    case ASN1_ETYPE_BOOLEAN:
-+	      if (p->value)
-+		{
-+		  if (p->value[0] == 'T')
-+		    fprintf (out, "  value:TRUE");
-+		  else if (p->value[0] == 'F')
-+		    fprintf (out, "  value:FALSE");
-+		}
-+	      break;
-+	    case ASN1_ETYPE_BIT_STRING:
-+	      if (p->value)
-+		{
-+		  len2 = -1;
-+		  len = asn1_get_length_der (p->value, p->value_len, &len2);
-+		  if (len > 0)
-+		    {
-+		      fprintf (out, "  value(%i):",
-+			       (len - 1) * 8 - (p->value[len2]));
-+		      for (k = 1; k < len; k++)
-+			fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
-+		    }
-+		}
-+	      break;
-+	    case ASN1_ETYPE_GENERALIZED_TIME:
-+	    case ASN1_ETYPE_UTC_TIME:
-+	      if (p->value)
-+		{
-+		  fprintf (out, "  value:");
-+		  for (k = 0; k < p->value_len; k++)
-+		    fprintf (out, "%c", (p->value)[k]);
-+		}
-+	      break;
-+	    case ASN1_ETYPE_GENERALSTRING:
-+	    case ASN1_ETYPE_NUMERIC_STRING:
-+	    case ASN1_ETYPE_IA5_STRING:
-+	    case ASN1_ETYPE_TELETEX_STRING:
-+	    case ASN1_ETYPE_PRINTABLE_STRING:
-+	    case ASN1_ETYPE_UNIVERSAL_STRING:
-+	    case ASN1_ETYPE_UTF8_STRING:
-+	    case ASN1_ETYPE_VISIBLE_STRING:
-+	      if (p->value)
-+		{
-+		  len2 = -1;
-+		  len = asn1_get_length_der (p->value, p->value_len, &len2);
-+		  fprintf (out, "  value:");
-+		  if (len > 0)
-+		    for (k = 0; k < len; k++)
-+		      fprintf (out, "%c", (p->value)[k + len2]);
-+		}
-+	      break;
-+	    case ASN1_ETYPE_BMP_STRING:
-+	    case ASN1_ETYPE_OCTET_STRING:
-+	      if (p->value)
-+		{
-+		  len2 = -1;
-+		  len = asn1_get_length_der (p->value, p->value_len, &len2);
-+		  fprintf (out, "  value:");
-+		  if (len > 0)
-+		    for (k = 0; k < len; k++)
-+		      fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
-+		}
-+	      break;
-+	    case ASN1_ETYPE_OBJECT_ID:
-+	      if (p->value)
-+		fprintf (out, "  value:%s", p->value);
-+	      break;
-+	    case ASN1_ETYPE_ANY:
-+	      if (p->value)
-+		{
-+		  len3 = -1;
-+		  len2 = asn1_get_length_der (p->value, p->value_len, &len3);
-+		  fprintf (out, "  value:");
-+		  if (len2 > 0)
-+		    for (k = 0; k < len2; k++)
-+		      fprintf (out, "%02x", (unsigned) (p->value)[k + len3]);
-+		}
-+	      break;
-+	    case ASN1_ETYPE_SET:
-+	    case ASN1_ETYPE_SET_OF:
-+	    case ASN1_ETYPE_CHOICE:
-+	    case ASN1_ETYPE_DEFINITIONS:
-+	    case ASN1_ETYPE_SEQUENCE_OF:
-+	    case ASN1_ETYPE_SEQUENCE:
-+	    case ASN1_ETYPE_NULL:
-+	      break;
-+	    default:
-+	      break;
-+	    }
-+	}
-+
-+      if (mode == ASN1_PRINT_ALL)
-+	{
-+	  if (p->type & 0x1FFFFF00)
-+	    {
-+	      fprintf (out, "  attr:");
-+	      if (p->type & CONST_UNIVERSAL)
-+		fprintf (out, "UNIVERSAL,");
-+	      if (p->type & CONST_PRIVATE)
-+		fprintf (out, "PRIVATE,");
-+	      if (p->type & CONST_APPLICATION)
-+		fprintf (out, "APPLICATION,");
-+	      if (p->type & CONST_EXPLICIT)
-+		fprintf (out, "EXPLICIT,");
-+	      if (p->type & CONST_IMPLICIT)
-+		fprintf (out, "IMPLICIT,");
-+	      if (p->type & CONST_TAG)
-+		fprintf (out, "TAG,");
-+	      if (p->type & CONST_DEFAULT)
-+		fprintf (out, "DEFAULT,");
-+	      if (p->type & CONST_TRUE)
-+		fprintf (out, "TRUE,");
-+	      if (p->type & CONST_FALSE)
-+		fprintf (out, "FALSE,");
-+	      if (p->type & CONST_LIST)
-+		fprintf (out, "LIST,");
-+	      if (p->type & CONST_MIN_MAX)
-+		fprintf (out, "MIN_MAX,");
-+	      if (p->type & CONST_OPTION)
-+		fprintf (out, "OPTION,");
-+	      if (p->type & CONST_1_PARAM)
-+		fprintf (out, "1_PARAM,");
-+	      if (p->type & CONST_SIZE)
-+		fprintf (out, "SIZE,");
-+	      if (p->type & CONST_DEFINED_BY)
-+		fprintf (out, "DEF_BY,");
-+	      if (p->type & CONST_GENERALIZED)
-+		fprintf (out, "GENERALIZED,");
-+	      if (p->type & CONST_UTC)
-+		fprintf (out, "UTC,");
-+	      if (p->type & CONST_SET)
-+		fprintf (out, "SET,");
-+	      if (p->type & CONST_NOT_USED)
-+		fprintf (out, "NOT_USED,");
-+	      if (p->type & CONST_ASSIGN)
-+		fprintf (out, "ASSIGNMENT,");
-+	    }
-+	}
-+
-+      if (mode == ASN1_PRINT_ALL)
-+	{
-+	  fprintf (out, "\n");
-+	}
-+      else
-+	{
-+	  switch (type_field (p->type))
-+	    {
-+	    case ASN1_ETYPE_CONSTANT:
-+	    case ASN1_ETYPE_TAG:
-+	    case ASN1_ETYPE_SIZE:
-+	      break;
-+	    default:
-+	      fprintf (out, "\n");
-+	    }
-+	}
-+
-+      if (p->down)
-+	{
-+	  p = p->down;
-+	  indent += 2;
-+	}
-+      else if (p == root)
-+	{
-+	  p = NULL;
-+	  break;
-+	}
-+      else if (p->right)
-+	p = p->right;
-+      else
-+	{
-+	  while (1)
-+	    {
-+	      p = _asn1_find_up (p);
-+	      if (p == root)
-+		{
-+		  p = NULL;
-+		  break;
-+		}
-+	      indent -= 2;
-+	      if (p->right)
-+		{
-+		  p = p->right;
-+		  break;
-+		}
-+	    }
-+	}
-+    }
-+}
-+
-+
-+
-+/**
-+ * asn1_number_of_elements:
-+ * @element: pointer to the root of an ASN1 structure.
-+ * @name: the name of a sub-structure of ROOT.
-+ * @num: pointer to an integer where the result will be stored
-+ *
-+ * Counts the number of elements of a sub-structure called NAME with
-+ * names equal to "?1","?2", ...
-+ *
-+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
-+ *   @name is not known, %ASN1_GENERIC_ERROR if pointer @num is %NULL.
-+ **/
-+int
-+asn1_number_of_elements (asn1_node_const element, const char *name, int *num)
-+{
-+  asn1_node_const node, p;
-+
-+  if (num == NULL)
-+    return ASN1_GENERIC_ERROR;
-+
-+  *num = 0;
-+
-+  node = asn1_find_node (element, name);
-+  if (node == NULL)
-+    return ASN1_ELEMENT_NOT_FOUND;
-+
-+  p = node->down;
-+
-+  while (p)
-+    {
-+      if (p->name[0] == '?')
-+	(*num)++;
-+      p = p->right;
-+    }
-+
-+  return ASN1_SUCCESS;
-+}
-+
-+
-+/**
-+ * asn1_find_structure_from_oid:
-+ * @definitions: ASN1 definitions
-+ * @oidValue: value of the OID to search (e.g. "1.2.3.4").
-+ *
-+ * Search the structure that is defined just after an OID definition.
-+ *
-+ * Returns: %NULL when @oidValue not found, otherwise the pointer to a
-+ *   constant string that contains the element name defined just after
-+ *   the OID.
-+ **/
-+const char *
-+asn1_find_structure_from_oid (asn1_node_const definitions, const char *oidValue)
-+{
-+  char name[2 * ASN1_MAX_NAME_SIZE + 2];
-+  char value[ASN1_MAX_NAME_SIZE];
-+  asn1_node p;
-+  int len;
-+  int result;
-+  const char *definitionsName;
-+
-+  if ((definitions == NULL) || (oidValue == NULL))
-+    return NULL;		/* ASN1_ELEMENT_NOT_FOUND; */
-+
-+  definitionsName = definitions->name;
-+
-+  /* search the OBJECT_ID into definitions */
-+  p = definitions->down;
-+  while (p)
-+    {
-+      if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
-+	  (p->type & CONST_ASSIGN))
-+	{
-+          snprintf(name, sizeof(name), "%s.%s", definitionsName, p->name);
-+
-+	  len = ASN1_MAX_NAME_SIZE;
-+	  result = asn1_read_value (definitions, name, value, &len);
-+
-+	  if ((result == ASN1_SUCCESS) && (!strcmp (oidValue, value)))
-+	    {
-+	      p = p->right;
-+	      if (p == NULL)	/* reach the end of ASN1 definitions */
-+		return NULL;	/* ASN1_ELEMENT_NOT_FOUND; */
-+
-+	      return p->name;
-+	    }
-+	}
-+      p = p->right;
-+    }
-+
-+  return NULL;			/* ASN1_ELEMENT_NOT_FOUND; */
-+}
-+
-+/**
-+ * asn1_copy_node:
-+ * @dst: Destination asn1 node.
-+ * @dst_name: Field name in destination node.
-+ * @src: Source asn1 node.
-+ * @src_name: Field name in source node.
-+ *
-+ * Create a deep copy of a asn1_node variable. That
-+ * function requires @dst to be expanded using asn1_create_element().
-+ *
-+ * Returns: Return %ASN1_SUCCESS on success.
-+ **/
-+int
-+asn1_copy_node (asn1_node dst, const char *dst_name,
-+		asn1_node_const src, const char *src_name)
-+{
-+  int result;
-+  asn1_node dst_node;
-+  void *data = NULL;
-+  int size = 0;
-+
-+  result = asn1_der_coding (src, src_name, NULL, &size, NULL);
-+  if (result != ASN1_MEM_ERROR)
-+    return result;
-+
-+  data = malloc (size);
-+  if (data == NULL)
-+    return ASN1_MEM_ERROR;
-+
-+  result = asn1_der_coding (src, src_name, data, &size, NULL);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      free (data);
-+      return result;
-+    }
-+
-+  dst_node = asn1_find_node (dst, dst_name);
-+  if (dst_node == NULL)
-+    {
-+      free (data);
-+      return ASN1_ELEMENT_NOT_FOUND;
-+    }
-+
-+  result = asn1_der_decoding (&dst_node, data, size, NULL);
-+
-+  free (data);
-+
-+  return result;
-+}
-+
-+/**
-+ * asn1_dup_node:
-+ * @src: Source asn1 node.
-+ * @src_name: Field name in source node.
-+ *
-+ * Create a deep copy of a asn1_node variable. This function
-+ * will return an exact copy of the provided structure.
-+ *
-+ * Returns: Return %NULL on failure.
-+ **/
-+asn1_node
-+asn1_dup_node (asn1_node_const src, const char *src_name)
-+{
-+  return _asn1_copy_structure2(src, src_name);
-+}
-diff --git a/grub-core/lib/libtasn1/lib/element.h b/grub-core/lib/libtasn1/lib/element.h
-new file mode 100644
-index 00000000000..440a33f4bb1
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/element.h
-@@ -0,0 +1,40 @@
-+/*
-+ * Copyright (C) 2000-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+#ifndef _ELEMENT_H
-+#define _ELEMENT_H
-+
-+
-+struct node_tail_cache_st
-+{
-+	asn1_node head; /* the first element of the sequence */
-+	asn1_node tail;
-+};
-+
-+int _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcached);
-+
-+int _asn1_convert_integer (const unsigned char *value,
-+			   unsigned char *value_out,
-+			   int value_out_size, int *len);
-+
-+void _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size);
-+
-+#endif
-diff --git a/grub-core/lib/libtasn1/lib/gstr.h b/grub-core/lib/libtasn1/lib/gstr.h
-new file mode 100644
-index 00000000000..48229844ff3
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/gstr.h
-@@ -0,0 +1,47 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+#ifndef GSTR_H
-+# define GSTR_H
-+
-+unsigned int _asn1_str_cpy (char *dest, size_t dest_tot_size,
-+			    const char *src);
-+void _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src);
-+
-+#define Estrcpy(x,y) _asn1_str_cpy(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y)
-+#define Estrcat(x,y) _asn1_str_cat(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y)
-+
-+inline static
-+void safe_memset(void *data, int c, size_t size)
-+{
-+	volatile unsigned volatile_zero = 0;
-+	volatile char *vdata = (volatile char*)data;
-+
-+	/* This is based on a nice trick for safe memset,
-+	 * sent by David Jacobson in the openssl-dev mailing list.
-+	 */
-+
-+	if (size > 0) do {
-+		memset(data, c, size);
-+	} while(vdata[volatile_zero] != c);
-+}
-+
-+#endif /* GSTR_H */
-diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h
-new file mode 100644
-index 00000000000..ea1625786c1
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/int.h
-@@ -0,0 +1,221 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+#ifndef INT_H
-+#define INT_H
-+
-+#ifdef HAVE_CONFIG_H
-+#include <config.h>
-+#endif
-+
-+#include <string.h>
-+#include <stdlib.h>
-+#include <stdio.h>
-+#include <stdint.h>
-+
-+#ifdef HAVE_SYS_TYPES_H
-+#include <sys/types.h>
-+#endif
-+
-+#include <libtasn1.h>
-+
-+#define ASN1_SMALL_VALUE_SIZE 16
-+
-+/* This structure is also in libtasn1.h, but then contains less
-+   fields.  You cannot make any modifications to these first fields
-+   without breaking ABI.  */
-+struct asn1_node_st
-+{
-+  /* public fields: */
-+  char name[ASN1_MAX_NAME_SIZE + 1];	/* Node name */
-+  unsigned int name_hash;
-+  unsigned int type;		/* Node type */
-+  unsigned char *value;		/* Node value */
-+  int value_len;
-+  asn1_node down;		/* Pointer to the son node */
-+  asn1_node right;		/* Pointer to the brother node */
-+  asn1_node left;		/* Pointer to the next list element */
-+  /* private fields: */
-+  unsigned char small_value[ASN1_SMALL_VALUE_SIZE];	/* For small values */
-+
-+  /* values used during decoding/coding */
-+  int tmp_ival;
-+  unsigned start; /* the start of the DER sequence - if decoded */
-+  unsigned end; /* the end of the DER sequence - if decoded */
-+};
-+
-+typedef struct tag_and_class_st
-+{
-+  unsigned tag;
-+  unsigned class;
-+  const char *desc;
-+} tag_and_class_st;
-+
-+/* the types that are handled in _asn1_tags */
-+#define CASE_HANDLED_ETYPES \
-+	case ASN1_ETYPE_NULL: \
-+	case ASN1_ETYPE_BOOLEAN: \
-+	case ASN1_ETYPE_INTEGER: \
-+	case ASN1_ETYPE_ENUMERATED: \
-+	case ASN1_ETYPE_OBJECT_ID: \
-+	case ASN1_ETYPE_OCTET_STRING: \
-+	case ASN1_ETYPE_GENERALSTRING: \
-+        case ASN1_ETYPE_NUMERIC_STRING: \
-+        case ASN1_ETYPE_IA5_STRING: \
-+        case ASN1_ETYPE_TELETEX_STRING: \
-+        case ASN1_ETYPE_PRINTABLE_STRING: \
-+        case ASN1_ETYPE_UNIVERSAL_STRING: \
-+        case ASN1_ETYPE_BMP_STRING: \
-+        case ASN1_ETYPE_UTF8_STRING: \
-+        case ASN1_ETYPE_VISIBLE_STRING: \
-+	case ASN1_ETYPE_BIT_STRING: \
-+	case ASN1_ETYPE_SEQUENCE: \
-+	case ASN1_ETYPE_SEQUENCE_OF: \
-+	case ASN1_ETYPE_SET: \
-+	case ASN1_ETYPE_UTC_TIME: \
-+	case ASN1_ETYPE_GENERALIZED_TIME: \
-+	case ASN1_ETYPE_SET_OF
-+
-+#define ETYPE_TAG(etype) (_asn1_tags[etype].tag)
-+#define ETYPE_CLASS(etype) (_asn1_tags[etype].class)
-+#define ETYPE_OK(etype) (((etype) != ASN1_ETYPE_INVALID && \
-+                          (etype) <= _asn1_tags_size && \
-+                          _asn1_tags[(etype)].desc != NULL)?1:0)
-+
-+#define ETYPE_IS_STRING(etype) ((etype == ASN1_ETYPE_GENERALSTRING || \
-+	etype == ASN1_ETYPE_NUMERIC_STRING || etype == ASN1_ETYPE_IA5_STRING || \
-+	etype == ASN1_ETYPE_TELETEX_STRING || etype == ASN1_ETYPE_PRINTABLE_STRING || \
-+	etype == ASN1_ETYPE_UNIVERSAL_STRING || etype == ASN1_ETYPE_BMP_STRING || \
-+	etype == ASN1_ETYPE_UTF8_STRING || etype == ASN1_ETYPE_VISIBLE_STRING || \
-+	etype == ASN1_ETYPE_OCTET_STRING)?1:0)
-+
-+extern unsigned int _asn1_tags_size;
-+extern const tag_and_class_st _asn1_tags[];
-+
-+#define _asn1_strlen(s) strlen((const char *) s)
-+#define _asn1_strtol(n,e,b) strtol((const char *) n, e, b)
-+#define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b)
-+#define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b)
-+#define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b)
-+#define _asn1_strcat(a,b) strcat((char *)a, (const char *)b)
-+
-+#if SIZEOF_UNSIGNED_LONG_INT == 8
-+# define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b)
-+#else
-+# define _asn1_strtou64(n,e,b) strtoull((const char *) n, e, b)
-+#endif
-+
-+#define MAX_LOG_SIZE 1024	/* maximum number of characters of a log message */
-+
-+/* Define used for visiting trees. */
-+#define UP     1
-+#define RIGHT  2
-+#define DOWN   3
-+
-+/***********************************************************************/
-+/* List of constants to better specify the type of typedef asn1_node_st.   */
-+/***********************************************************************/
-+/*  Used with TYPE_TAG  */
-+#define CONST_UNIVERSAL   (1U<<8)
-+#define CONST_PRIVATE     (1U<<9)
-+#define CONST_APPLICATION (1U<<10)
-+#define CONST_EXPLICIT    (1U<<11)
-+#define CONST_IMPLICIT    (1U<<12)
-+
-+#define CONST_TAG         (1U<<13)	/*  Used in ASN.1 assignement  */
-+#define CONST_OPTION      (1U<<14)
-+#define CONST_DEFAULT     (1U<<15)
-+#define CONST_TRUE        (1U<<16)
-+#define CONST_FALSE       (1U<<17)
-+
-+#define CONST_LIST        (1U<<18)	/*  Used with TYPE_INTEGER and TYPE_BIT_STRING  */
-+#define CONST_MIN_MAX     (1U<<19)
-+
-+#define CONST_1_PARAM     (1U<<20)
-+
-+#define CONST_SIZE        (1U<<21)
-+
-+#define CONST_DEFINED_BY  (1U<<22)
-+
-+/* Those two are deprecated and used for backwards compatibility */
-+#define CONST_GENERALIZED (1U<<23)
-+#define CONST_UTC         (1U<<24)
-+
-+/* #define CONST_IMPORTS     (1U<<25) */
-+
-+#define CONST_NOT_USED    (1U<<26)
-+#define CONST_SET         (1U<<27)
-+#define CONST_ASSIGN      (1U<<28)
-+
-+#define CONST_DOWN        (1U<<29)
-+#define CONST_RIGHT       (1U<<30)
-+
-+
-+#define ASN1_ETYPE_TIME 17
-+/****************************************/
-+/* Returns the first 8 bits.            */
-+/* Used with the field type of asn1_node_st */
-+/****************************************/
-+inline static unsigned int
-+type_field (unsigned int ntype)
-+{
-+  return (ntype & 0xff);
-+}
-+
-+/* To convert old types from a static structure */
-+inline static unsigned int
-+convert_old_type (unsigned int ntype)
-+{
-+  unsigned int type = ntype & 0xff;
-+  if (type == ASN1_ETYPE_TIME)
-+    {
-+      if (ntype & CONST_UTC)
-+	type = ASN1_ETYPE_UTC_TIME;
-+      else
-+	type = ASN1_ETYPE_GENERALIZED_TIME;
-+
-+      ntype &= ~(CONST_UTC | CONST_GENERALIZED);
-+      ntype &= 0xffffff00;
-+      ntype |= type;
-+
-+      return ntype;
-+    }
-+  else
-+    return ntype;
-+}
-+
-+static inline
-+void *_asn1_realloc(void *ptr, size_t size)
-+{
-+  void *ret;
-+
-+  if (size == 0)
-+    return ptr;
-+
-+  ret = realloc(ptr, size);
-+  if (ret == NULL)
-+    {
-+      free(ptr);
-+    }
-+  return ret;
-+}
-+
-+#endif /* INT_H */
-diff --git a/grub-core/lib/libtasn1/lib/parser_aux.h b/grub-core/lib/libtasn1/lib/parser_aux.h
-new file mode 100644
-index 00000000000..598e684b355
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/parser_aux.h
-@@ -0,0 +1,172 @@
-+/*
-+ * Copyright (C) 2000-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+#ifndef _PARSER_AUX_H
-+#define _PARSER_AUX_H
-+
-+/***********************************************/
-+/* Type: list_type                             */
-+/* Description: type used in the list during   */
-+/* the structure creation.                     */
-+/***********************************************/
-+typedef struct list_struct
-+{
-+  asn1_node node;
-+  struct list_struct *next;
-+} list_type;
-+
-+/***************************************/
-+/*  Functions used by ASN.1 parser     */
-+/***************************************/
-+asn1_node _asn1_add_static_node (list_type **e_list, unsigned int type);
-+
-+void _asn1_delete_list (list_type *e_list);
-+
-+void _asn1_delete_list_and_nodes (list_type *e_list);
-+
-+void _asn1_delete_node_from_list (list_type *list, asn1_node node);
-+
-+asn1_node
-+_asn1_set_value (asn1_node node, const void *value, unsigned int len);
-+
-+asn1_node _asn1_set_value_m (asn1_node node, void *value, unsigned int len);
-+
-+asn1_node
-+_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len);
-+
-+asn1_node
-+_asn1_append_value (asn1_node node, const void *value, unsigned int len);
-+
-+asn1_node _asn1_set_name (asn1_node node, const char *name);
-+
-+asn1_node _asn1_cpy_name (asn1_node dst, asn1_node_const src);
-+
-+asn1_node _asn1_set_right (asn1_node node, asn1_node right);
-+
-+asn1_node _asn1_get_last_right (asn1_node_const node);
-+
-+void _asn1_remove_node (asn1_node node, unsigned int flags);
-+
-+/* Max 64-bit integer length is 20 chars + 1 for sign + 1 for null termination */
-+#define LTOSTR_MAX_SIZE 22
-+char *_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]);
-+
-+asn1_node _asn1_find_up (asn1_node_const node);
-+
-+int _asn1_change_integer_value (asn1_node node);
-+
-+#define EXPAND_OBJECT_ID_MAX_RECURSION 16
-+int _asn1_expand_object_id (list_type **list, asn1_node node);
-+
-+int _asn1_type_set_config (asn1_node node);
-+
-+int _asn1_check_identifier (asn1_node_const node);
-+
-+int _asn1_set_default_tag (asn1_node node);
-+
-+/******************************************************************/
-+/* Function : _asn1_get_right                                     */
-+/* Description: returns the element pointed by the RIGHT field of */
-+/*              a NODE_ASN element.                               */
-+/* Parameters:                                                    */
-+/*   node: NODE_ASN element pointer.                              */
-+/* Return: field RIGHT of NODE.                                   */
-+/******************************************************************/
-+inline static asn1_node
-+_asn1_get_right (asn1_node_const node)
-+{
-+  if (node == NULL)
-+    return NULL;
-+  return node->right;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_set_down                                      */
-+/* Description: sets the field DOWN in a NODE_ASN element.        */
-+/* Parameters:                                                    */
-+/*   node: element pointer.                                       */
-+/*   down: pointer to a NODE_ASN element that you want be pointed */
-+/*          by NODE.                                              */
-+/* Return: pointer to *NODE.                                      */
-+/******************************************************************/
-+inline static asn1_node
-+_asn1_set_down (asn1_node node, asn1_node down)
-+{
-+  if (node == NULL)
-+    return node;
-+  node->down = down;
-+  if (down)
-+    down->left = node;
-+  return node;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_get_down                                      */
-+/* Description: returns the element pointed by the DOWN field of  */
-+/*              a NODE_ASN element.                               */
-+/* Parameters:                                                    */
-+/*   node: NODE_ASN element pointer.                              */
-+/* Return: field DOWN of NODE.                                    */
-+/******************************************************************/
-+inline static asn1_node
-+_asn1_get_down (asn1_node_const node)
-+{
-+  if (node == NULL)
-+    return NULL;
-+  return node->down;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_get_name                                      */
-+/* Description: returns the name of a NODE_ASN element.           */
-+/* Parameters:                                                    */
-+/*   node: NODE_ASN element pointer.                              */
-+/* Return: a null terminated string.                              */
-+/******************************************************************/
-+inline static char *
-+_asn1_get_name (asn1_node_const node)
-+{
-+  if (node == NULL)
-+    return NULL;
-+  return (char *) node->name;
-+}
-+
-+/******************************************************************/
-+/* Function : _asn1_mod_type                                      */
-+/* Description: change the field TYPE of an NODE_ASN element.     */
-+/*              The new value is the old one | (bitwise or) the   */
-+/*              paramener VALUE.                                  */
-+/* Parameters:                                                    */
-+/*   node: NODE_ASN element pointer.                              */
-+/*   value: the integer value that must be or-ed with the current */
-+/*          value of field TYPE.                                  */
-+/* Return: NODE pointer.                                          */
-+/******************************************************************/
-+inline static asn1_node
-+_asn1_mod_type (asn1_node node, unsigned int value)
-+{
-+  if (node == NULL)
-+    return node;
-+  node->type |= value;
-+  return node;
-+}
-+
-+#endif
-diff --git a/grub-core/lib/libtasn1/lib/structure.h b/grub-core/lib/libtasn1/lib/structure.h
-new file mode 100644
-index 00000000000..99e685da07a
---- /dev/null
-+++ b/grub-core/lib/libtasn1/lib/structure.h
-@@ -0,0 +1,45 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * The LIBTASN1 library is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ */
-+
-+/*************************************************/
-+/* File: structure.h                             */
-+/* Description: list of exported object by       */
-+/*   "structure.c"                               */
-+/*************************************************/
-+
-+#ifndef _STRUCTURE_H
-+#define _STRUCTURE_H
-+
-+#include "parser_aux.h" // list_type
-+
-+int _asn1_create_static_structure (asn1_node_const pointer,
-+				   char *output_file_name, char *vector_name);
-+
-+asn1_node _asn1_copy_structure3 (asn1_node_const source_node);
-+
-+asn1_node _asn1_add_single_node (unsigned int type);
-+
-+asn1_node _asn1_find_left (asn1_node_const node);
-+
-+int
-+_asn1_delete_structure (list_type *e_list, asn1_node *structure, unsigned int flags);
-+
-+#endif
-diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h
-new file mode 100644
-index 00000000000..6fd7a30dc35
---- /dev/null
-+++ b/include/grub/libtasn1.h
-@@ -0,0 +1,588 @@
-+/*
-+ * Copyright (C) 2002-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * LIBTASN1 is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU Lesser General Public License as
-+ * published by the Free Software Foundation; either version 2.1 of
-+ * the License, or (at your option) any later version.
-+ *
-+ * LIBTASN1 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with LIBTASN1; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA
-+ *
-+ */
-+
-+/**
-+ * libtasn1:Short_Description:
-+ *
-+ * GNU ASN.1 library
-+ */
-+/**
-+ * libtasn1:Long_Description:
-+ *
-+ * The Libtasn1 library provides Abstract Syntax Notation One (ASN.1, as
-+ * specified by the X.680 ITU-T recommendation) parsing and structures
-+ * management, and Distinguished Encoding Rules (DER, as per X.690)
-+ * encoding and decoding functions.
-+ */
-+
-+
-+#ifndef LIBTASN1_H
-+#define LIBTASN1_H
-+
-+#ifndef ASN1_API
-+#if defined ASN1_BUILDING && defined HAVE_VISIBILITY && HAVE_VISIBILITY
-+#define ASN1_API __attribute__((__visibility__("default")))
-+#elif defined ASN1_BUILDING && defined _MSC_VER && ! defined ASN1_STATIC
-+#define ASN1_API __declspec(dllexport)
-+#elif defined _MSC_VER && ! defined ASN1_STATIC
-+#define ASN1_API __declspec(dllimport)
-+#else
-+#define ASN1_API
-+#endif
-+#endif
-+
-+#ifdef __GNUC__
-+# define __LIBTASN1_CONST__  __attribute__((const))
-+# define __LIBTASN1_PURE__  __attribute__((pure))
-+#else
-+# define __LIBTASN1_CONST__
-+# define __LIBTASN1_PURE__
-+#endif
-+
-+#include <sys/types.h>
-+#include <time.h>
-+#include <stdio.h>		/* for FILE* */
-+
-+#ifdef __cplusplus
-+extern "C"
-+{
-+#endif
-+
-+/**
-+ * ASN1_VERSION:
-+ *
-+ * Version of the library as a string.
-+ */
-+#define ASN1_VERSION "4.16.0"
-+
-+/**
-+ * ASN1_VERSION_MAJOR:
-+ *
-+ * Major version number of the library.
-+ */
-+#define ASN1_VERSION_MAJOR 4
-+
-+/**
-+ * ASN1_VERSION_MINOR:
-+ *
-+ * Minor version number of the library.
-+ */
-+#define ASN1_VERSION_MINOR 16
-+
-+/**
-+ * ASN1_VERSION_PATCH:
-+ *
-+ * Patch version number of the library.
-+ */
-+#define ASN1_VERSION_PATCH 0
-+
-+/**
-+ * ASN1_VERSION_NUMBER:
-+ *
-+ * Version number of the library as a number.
-+ */
-+#define ASN1_VERSION_NUMBER 0x041000
-+
-+
-+#if defined __GNUC__ && !defined ASN1_INTERNAL_BUILD
-+# define _ASN1_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
-+# if _ASN1_GCC_VERSION >= 30100
-+#  define _ASN1_GCC_ATTR_DEPRECATED __attribute__ ((__deprecated__))
-+# endif
-+#endif
-+
-+#ifndef _ASN1_GCC_ATTR_DEPRECATED
-+#define _ASN1_GCC_ATTR_DEPRECATED
-+#endif
-+
-+/*****************************************/
-+/* Errors returned by libtasn1 functions */
-+/*****************************************/
-+#define ASN1_SUCCESS			0
-+#define ASN1_FILE_NOT_FOUND		1
-+#define ASN1_ELEMENT_NOT_FOUND		2
-+#define ASN1_IDENTIFIER_NOT_FOUND	3
-+#define ASN1_DER_ERROR			4
-+#define ASN1_VALUE_NOT_FOUND		5
-+#define ASN1_GENERIC_ERROR		6
-+#define ASN1_VALUE_NOT_VALID		7
-+#define ASN1_TAG_ERROR			8
-+#define ASN1_TAG_IMPLICIT		9
-+#define ASN1_ERROR_TYPE_ANY		10
-+#define ASN1_SYNTAX_ERROR		11
-+#define ASN1_MEM_ERROR			12
-+#define ASN1_MEM_ALLOC_ERROR		13
-+#define ASN1_DER_OVERFLOW		14
-+#define ASN1_NAME_TOO_LONG		15
-+#define ASN1_ARRAY_ERROR		16
-+#define ASN1_ELEMENT_NOT_EMPTY		17
-+#define ASN1_TIME_ENCODING_ERROR	18
-+#define ASN1_RECURSION			19
-+
-+/*************************************/
-+/* Constants used in asn1_visit_tree */
-+/*************************************/
-+#define ASN1_PRINT_NAME			1
-+#define ASN1_PRINT_NAME_TYPE		2
-+#define ASN1_PRINT_NAME_TYPE_VALUE	3
-+#define ASN1_PRINT_ALL			4
-+
-+/*****************************************/
-+/* Constants returned by asn1_read_tag   */
-+/*****************************************/
-+#define ASN1_CLASS_UNIVERSAL		0x00	/* old: 1 */
-+#define ASN1_CLASS_APPLICATION		0x40	/* old: 2 */
-+#define ASN1_CLASS_CONTEXT_SPECIFIC	0x80	/* old: 3 */
-+#define ASN1_CLASS_PRIVATE		0xC0	/* old: 4 */
-+#define ASN1_CLASS_STRUCTURED		0x20
-+
-+/*****************************************/
-+/* Constants returned by asn1_read_tag   */
-+/*****************************************/
-+#define ASN1_TAG_BOOLEAN		0x01
-+#define ASN1_TAG_INTEGER		0x02
-+#define ASN1_TAG_SEQUENCE		0x10
-+#define ASN1_TAG_SET			0x11
-+#define ASN1_TAG_OCTET_STRING		0x04
-+#define ASN1_TAG_BIT_STRING		0x03
-+#define ASN1_TAG_UTCTime		0x17
-+#define ASN1_TAG_GENERALIZEDTime	0x18
-+#define ASN1_TAG_OBJECT_ID		0x06
-+#define ASN1_TAG_ENUMERATED		0x0A
-+#define ASN1_TAG_NULL			0x05
-+#define ASN1_TAG_GENERALSTRING		0x1B
-+#define ASN1_TAG_NUMERIC_STRING		0x12
-+#define ASN1_TAG_IA5_STRING		0x16
-+#define ASN1_TAG_TELETEX_STRING		0x14
-+#define ASN1_TAG_PRINTABLE_STRING	0x13
-+#define ASN1_TAG_UNIVERSAL_STRING	0x1C
-+#define ASN1_TAG_BMP_STRING		0x1E
-+#define ASN1_TAG_UTF8_STRING		0x0C
-+#define ASN1_TAG_VISIBLE_STRING		0x1A
-+
-+/**
-+ * asn1_node:
-+ *
-+ * Structure definition used for the node of the tree
-+ * that represents an ASN.1 DEFINITION.
-+ */
-+typedef struct asn1_node_st asn1_node_st;
-+
-+typedef asn1_node_st *asn1_node;
-+typedef const asn1_node_st *asn1_node_const;
-+
-+/**
-+ * ASN1_MAX_NAME_SIZE:
-+ *
-+ * Maximum number of characters of a name
-+ * inside a file with ASN1 definitions.
-+ */
-+#define ASN1_MAX_NAME_SIZE 64
-+
-+
-+/**
-+ * asn1_static_node:
-+ * @name: Node name
-+ * @type: Node typ
-+ * @value: Node value
-+ *
-+ * For the on-disk format of ASN.1 trees, created by asn1_parser2array().
-+ */
-+struct asn1_static_node_st
-+{
-+  const char *name;		/* Node name */
-+  unsigned int type;		/* Node type */
-+  const void *value;		/* Node value */
-+};
-+typedef struct asn1_static_node_st asn1_static_node;
-+
-+/* List of constants for field type of node_asn  */
-+#define ASN1_ETYPE_INVALID        0
-+#define ASN1_ETYPE_CONSTANT       1
-+#define ASN1_ETYPE_IDENTIFIER     2
-+#define ASN1_ETYPE_INTEGER        3
-+#define ASN1_ETYPE_BOOLEAN        4
-+#define ASN1_ETYPE_SEQUENCE       5
-+#define ASN1_ETYPE_BIT_STRING     6
-+#define ASN1_ETYPE_OCTET_STRING   7
-+#define ASN1_ETYPE_TAG            8
-+#define ASN1_ETYPE_DEFAULT        9
-+#define ASN1_ETYPE_SIZE          10
-+#define ASN1_ETYPE_SEQUENCE_OF   11
-+#define ASN1_ETYPE_OBJECT_ID     12
-+#define ASN1_ETYPE_ANY           13
-+#define ASN1_ETYPE_SET           14
-+#define ASN1_ETYPE_SET_OF        15
-+#define ASN1_ETYPE_DEFINITIONS   16
-+#define ASN1_ETYPE_CHOICE        18
-+#define ASN1_ETYPE_IMPORTS       19
-+#define ASN1_ETYPE_NULL          20
-+#define ASN1_ETYPE_ENUMERATED    21
-+#define ASN1_ETYPE_GENERALSTRING 27
-+#define ASN1_ETYPE_NUMERIC_STRING 28
-+#define ASN1_ETYPE_IA5_STRING     29
-+#define ASN1_ETYPE_TELETEX_STRING 30
-+#define ASN1_ETYPE_PRINTABLE_STRING 31
-+#define ASN1_ETYPE_UNIVERSAL_STRING 32
-+#define ASN1_ETYPE_BMP_STRING     33
-+#define ASN1_ETYPE_UTF8_STRING    34
-+#define ASN1_ETYPE_VISIBLE_STRING 35
-+#define ASN1_ETYPE_UTC_TIME       36
-+#define ASN1_ETYPE_GENERALIZED_TIME 37
-+
-+/**
-+ * ASN1_DELETE_FLAG_ZEROIZE:
-+ *
-+ * Used by: asn1_delete_structure2()
-+ *
-+ * Zeroize values prior to deinitialization.
-+ */
-+#define ASN1_DELETE_FLAG_ZEROIZE 1
-+
-+/**
-+ * ASN1_DECODE_FLAG_ALLOW_PADDING:
-+ *
-+ * Used by: asn1_der_decoding2()
-+ *
-+ * This flag would allow arbitrary data past the DER data.
-+ */
-+#define ASN1_DECODE_FLAG_ALLOW_PADDING 1
-+/**
-+ * ASN1_DECODE_FLAG_STRICT_DER:
-+ *
-+ * Used by: asn1_der_decoding2()
-+ *
-+ * This flag would ensure that no BER decoding takes place.
-+ */
-+#define ASN1_DECODE_FLAG_STRICT_DER (1<<1)
-+/**
-+ * ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME:
-+ *
-+ * Used by: asn1_der_decoding2()
-+ *
-+ * This flag will tolerate Time encoding errors when in strict DER.
-+ */
-+#define ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME (1<<2)
-+
-+
-+/**
-+ * asn1_data_node_st:
-+ * @name: Node name
-+ * @value: Node value
-+ * @value_len: Node value size
-+ * @type: Node value type (ASN1_ETYPE_*)
-+ *
-+ * Data node inside a #asn1_node structure.
-+ */
-+struct asn1_data_node_st
-+{
-+  const char *name;		/* Node name */
-+  const void *value;		/* Node value */
-+  unsigned int value_len;	/* Node value size */
-+  unsigned int type;		/* Node value type (ASN1_ETYPE_*) */
-+};
-+typedef struct asn1_data_node_st asn1_data_node_st;
-+
-+/***********************************/
-+/*  Fixed constants                */
-+/***********************************/
-+
-+/**
-+ * ASN1_MAX_ERROR_DESCRIPTION_SIZE:
-+ *
-+ * Maximum number of characters
-+ * of a description message
-+ * (null character included).
-+ */
-+#define ASN1_MAX_ERROR_DESCRIPTION_SIZE 128
-+
-+/***********************************/
-+/*  Functions definitions          */
-+/***********************************/
-+
-+extern ASN1_API int
-+  asn1_parser2tree (const char *file,
-+		      asn1_node * definitions, char *error_desc);
-+
-+extern ASN1_API int
-+  asn1_parser2array (const char *inputFileName,
-+		       const char *outputFileName,
-+		       const char *vectorName, char *error_desc);
-+
-+extern ASN1_API int
-+  asn1_array2tree (const asn1_static_node * array,
-+		     asn1_node * definitions, char *errorDescription);
-+
-+extern ASN1_API void
-+  asn1_print_structure (FILE * out, asn1_node_const structure,
-+			  const char *name, int mode);
-+
-+extern ASN1_API int
-+  asn1_create_element (asn1_node_const definitions,
-+			 const char *source_name, asn1_node * element);
-+
-+extern ASN1_API int asn1_delete_structure (asn1_node * structure);
-+
-+extern ASN1_API int asn1_delete_structure2 (asn1_node * structure, unsigned int flags);
-+
-+extern ASN1_API int
-+  asn1_delete_element (asn1_node structure, const char *element_name);
-+
-+extern ASN1_API int
-+  asn1_write_value (asn1_node node_root, const char *name,
-+		      const void *ivalue, int len);
-+
-+extern ASN1_API int
-+  asn1_read_value (asn1_node_const root, const char *name,
-+		     void *ivalue, int *len);
-+
-+extern ASN1_API int
-+  asn1_read_value_type (asn1_node_const root, const char *name,
-+			  void *ivalue, int *len, unsigned int *etype);
-+
-+extern ASN1_API int
-+  asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data);
-+
-+extern ASN1_API int
-+  asn1_number_of_elements (asn1_node_const element, const char *name, int *num);
-+
-+extern ASN1_API int
-+  asn1_der_coding (asn1_node_const element, const char *name,
-+		     void *ider, int *len, char *ErrorDescription);
-+
-+extern ASN1_API int
-+  asn1_der_decoding2 (asn1_node *element, const void *ider,
-+			int *max_ider_len, unsigned int flags,
-+			char *errorDescription);
-+
-+extern ASN1_API int
-+  asn1_der_decoding (asn1_node * element, const void *ider,
-+		       int ider_len, char *errorDescription);
-+
-+/* Do not use. Use asn1_der_decoding() instead. */
-+extern ASN1_API int
-+  asn1_der_decoding_element (asn1_node * structure,
-+			       const char *elementName,
-+			       const void *ider, int len,
-+			       char *errorDescription) _ASN1_GCC_ATTR_DEPRECATED;
-+
-+extern ASN1_API int
-+  asn1_der_decoding_startEnd (asn1_node element,
-+				const void *ider, int ider_len,
-+				const char *name_element,
-+				int *start, int *end);
-+
-+extern ASN1_API int
-+  asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element);
-+
-+extern ASN1_API int
-+  asn1_expand_octet_string (asn1_node_const definitions,
-+			      asn1_node * element,
-+			      const char *octetName, const char *objectName);
-+
-+extern ASN1_API int
-+  asn1_read_tag (asn1_node_const root, const char *name,
-+		   int *tagValue, int *classValue);
-+
-+extern ASN1_API const char *asn1_find_structure_from_oid (asn1_node_const
-+							    definitions,
-+							    const char
-+							    *oidValue);
-+
-+__LIBTASN1_PURE__
-+extern ASN1_API const char *asn1_check_version (const char *req_version);
-+
-+__LIBTASN1_PURE__
-+extern ASN1_API const char *asn1_strerror (int error);
-+
-+extern ASN1_API void asn1_perror (int error);
-+
-+#define ASN1_MAX_TAG_SIZE 4
-+#define ASN1_MAX_LENGTH_SIZE 9
-+#define ASN1_MAX_TL_SIZE (ASN1_MAX_TAG_SIZE+ASN1_MAX_LENGTH_SIZE)
-+extern ASN1_API long
-+  asn1_get_length_der (const unsigned char *der, int der_len, int *len);
-+
-+extern ASN1_API long
-+  asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len);
-+
-+extern ASN1_API void
-+  asn1_length_der (unsigned long int len, unsigned char *der, int *der_len);
-+
-+/* Other utility functions. */
-+
-+extern ASN1_API
-+  int asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
-+				unsigned int _der_len,
-+				const unsigned char **str,
-+				unsigned int *str_len);
-+
-+extern ASN1_API
-+  int asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
-+				unsigned int _der_len,
-+				unsigned char **str,
-+				unsigned int *str_len,
-+				unsigned int *ber_len);
-+
-+extern ASN1_API int
-+  asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
-+			    unsigned int str_len, unsigned char *tl,
-+			    unsigned int *tl_len);
-+
-+extern ASN1_API asn1_node
-+  asn1_find_node (asn1_node_const pointer, const char *name);
-+
-+extern ASN1_API int
-+  asn1_copy_node (asn1_node dst, const char *dst_name,
-+		    asn1_node_const src, const char *src_name);
-+extern ASN1_API asn1_node
-+  asn1_dup_node (asn1_node_const src, const char *src_name);
-+
-+/* Internal and low-level DER utility functions. */
-+
-+extern ASN1_API int
-+  asn1_get_tag_der (const unsigned char *der, int der_len,
-+		      unsigned char *cls, int *len, unsigned long *tag);
-+
-+extern ASN1_API void
-+  asn1_octet_der (const unsigned char *str, int str_len,
-+		    unsigned char *der, int *der_len);
-+
-+extern ASN1_API int
-+  asn1_get_octet_der (const unsigned char *der, int der_len,
-+			int *ret_len, unsigned char *str,
-+			int str_size, int *str_len);
-+
-+extern ASN1_API void asn1_bit_der (const unsigned char *str, int bit_len,
-+				     unsigned char *der, int *der_len);
-+
-+extern ASN1_API int
-+  asn1_get_bit_der (const unsigned char *der, int der_len,
-+		      int *ret_len, unsigned char *str,
-+		      int str_size, int *bit_len);
-+
-+extern ASN1_API int
-+  asn1_get_object_id_der (const unsigned char *der,
-+                          int der_len, int *ret_len,
-+                          char *str, int str_size);
-+
-+extern ASN1_API int
-+  asn1_object_id_der (const char *str, unsigned char *der, int *der_len,
-+                      unsigned flags);
-+
-+/* Compatibility types */
-+
-+/**
-+ * asn1_retCode:
-+ *
-+ * Type formerly returned by libtasn1 functions.
-+ *
-+ * Deprecated: 3.0: Use int instead.
-+ */
-+typedef int asn1_retCode;
-+
-+/**
-+ * node_asn_struct:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_node instead.
-+ */
-+#define node_asn_struct asn1_node_st
-+
-+/**
-+ * node_asn:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_node instead.
-+ */
-+#define node_asn asn1_node_st
-+
-+/**
-+ * ASN1_TYPE:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_node instead.
-+ */
-+#define ASN1_TYPE asn1_node
-+
-+/**
-+ * ASN1_TYPE_EMPTY:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use NULL instead.
-+ */
-+#define ASN1_TYPE_EMPTY NULL
-+
-+/**
-+ * static_struct_asn:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_static_node instead.
-+ */
-+#define static_struct_asn asn1_static_node_st
-+
-+/**
-+ * ASN1_ARRAY_TYPE:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_static_node instead.
-+ */
-+#define ASN1_ARRAY_TYPE asn1_static_node
-+
-+/**
-+ * asn1_static_node_t:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_static_node instead.
-+ */
-+#define asn1_static_node_t asn1_static_node
-+
-+/**
-+ * node_data_struct:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_data_node_st instead.
-+ */
-+#define node_data_struct asn1_data_node_st
-+
-+/**
-+ * ASN1_DATA_NODE:
-+ *
-+ * Compat #define.
-+ *
-+ * Deprecated: 3.0: Use #asn1_data_node_st instead.
-+ */
-+#define ASN1_DATA_NODE asn1_data_node_st
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif				/* LIBTASN1_H */
-diff --git a/grub-core/lib/libtasn1/LICENSE b/grub-core/lib/libtasn1/LICENSE
-new file mode 100644
-index 00000000000..e8b3628db9b
---- /dev/null
-+++ b/grub-core/lib/libtasn1/LICENSE
-@@ -0,0 +1,16 @@
-+LICENSING
-+=========
-+
-+The libtasn1 library is released under the GNU Lesser General Public
-+License (LGPL) version 2.1 or later; see [COPYING.LESSER](doc/COPYING.LESSER)
-+for the license terms.
-+
-+The GNU LGPL applies to the main libtasn1 library, while the
-+included applications library are under the GNU GPL version 3.
-+The libtasn1 library is located in the lib directory, while the applications
-+in src/.
-+
-+The documentation in doc/ is under the GNU FDL license 1.3.
-+
-+For any copyright year range specified as YYYY-ZZZZ in this package
-+note that the range specifies every single year in that closed interval.
-diff --git a/grub-core/lib/libtasn1/README.md b/grub-core/lib/libtasn1/README.md
-new file mode 100644
-index 00000000000..50a8642296c
---- /dev/null
-+++ b/grub-core/lib/libtasn1/README.md
-@@ -0,0 +1,91 @@
-+|Branch|CI system|Status|
-+|:----:|:-------:|-----:|
-+|Master|Gitlab|[![build status](https://gitlab.com/gnutls/libtasn1/badges/master/pipeline.svg)](https://gitlab.com/gnutls/libtasn1/commits/master)[![coverage report](https://gitlab.com/gnutls/libtasn1/badges/master/coverage.svg)](https://gnutls.gitlab.io/libtasn1/coverage)|
-+
-+# libtasn1
-+
-+This is GNU Libtasn1, a small ASN.1 library.
-+
-+The C library (libtasn1.*) is licensed under the GNU Lesser General
-+Public License version 2.1 or later.  See the file COPYING.LIB.
-+
-+The command line tool, self tests, examples, and other auxilliary
-+files, are licensed under the GNU General Public License version 3.0
-+or later.  See the file COPYING.
-+
-+## Building the library
-+
-+We require several tools to build the software, including:
-+
-+* [Make](https://www.gnu.org/software/make/)
-+* [Automake](https://www.gnu.org/software/automake/) (use 1.11.3 or later)
-+* [Autoconf](https://www.gnu.org/software/autoconf/)
-+* [Libtool](https://www.gnu.org/software/libtool/)
-+* [Texinfo](https://www.gnu.org/software/texinfo/)
-+* [help2man](http://www.gnu.org/software/help2man/)
-+* [Tar](https://www.gnu.org/software/tar/)
-+* [Gzip](https://www.gnu.org/software/gzip/)
-+* [bison](https://www.gnu.org/software/bison/)
-+* [Texlive & epsf](https://www.tug.org/texlive/) (for PDF manual)
-+* [GTK-DOC](https://www.gtk.org/gtk-doc/) (for API manual)
-+* [Git](https://git-scm.com/)
-+* [libabigail](https://pagure.io/libabigail/) (for abi comparison in make dist)
-+* [Valgrind](https://valgrind.org/) (optional)
-+
-+The required software is typically distributed with your operating
-+system, and the instructions for installing them differ.  Here are
-+some hints:
-+
-+gNewSense/Debian/Ubuntu:
-+```
-+sudo apt-get install make git-core autoconf automake libtool
-+sudo apt-get install texinfo texlive texlive-generic-recommended texlive-extra-utils
-+sudo apt-get install help2man gtk-doc-tools valgrind abigail-tools
-+```
-+
-+The next step is to run autoreconf, ./configure, etc:
-+
-+```
-+$ ./bootstrap
-+```
-+
-+Then build the project normally:
-+
-+```
-+$ make
-+$ make check
-+```
-+
-+Happy hacking!
-+
-+
-+## Manual
-+
-+The manual is in the `doc/` directory of the release.  You can also browse
-+the manual online at:
-+
-+ - https://gnutls.gitlab.io/libtasn1/
-+
-+
-+## Code coverage report
-+
-+The coverage report is at:
-+
-+ - https://gnutls.gitlab.io/libtasn1/coverage
-+
-+
-+## Issue trackers
-+
-+ - [Main issue tracker](https://gitlab.com/gnutls/libtasn1/issues)
-+ - [oss-fuzz found issues](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=libtasn1&can=2)
-+
-+
-+## Homepage
-+
-+The project homepage at the gnu site is at:
-+
-+http://www.gnu.org/software/libtasn1/
-+
-+
-+For any copyright year range specified as YYYY-ZZZZ in this package
-+note that the range specifies every single year in that closed interval.
diff --git a/SOURCES/0186-normal-main-Discover-the-device-to-read-the-config-f.patch b/SOURCES/0186-normal-main-Discover-the-device-to-read-the-config-f.patch
new file mode 100644
index 0000000..2c9ca3a
--- /dev/null
+++ b/SOURCES/0186-normal-main-Discover-the-device-to-read-the-config-f.patch
@@ -0,0 +1,123 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Mon, 30 Aug 2021 12:31:18 +0200
+Subject: [PATCH] normal/main: Discover the device to read the config from as a
+ fallback
+
+The GRUB core.img is generated locally, when this is done the grub2-probe
+tool figures out the device and partition that needs to be read to parse
+the GRUB configuration file.
+
+But in some cases the core.img can't be generated on the host and instead
+has to be done at package build time. For example, if needs to get signed
+with a key that's only available on the package building infrastructure.
+
+If that's the case, the prefix variable won't have a device and partition
+but only a directory path. So there's no way for GRUB to know from which
+device has to read the configuration file.
+
+To allow GRUB to continue working on that scenario, fallback to iterating
+over all the available devices, if reading the config failed when using
+the prefix and fw_path variables.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/normal/main.c | 58 +++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 51 insertions(+), 7 deletions(-)
+
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index 7de9e4c36d..8f5fd81003 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -337,18 +337,13 @@ grub_enter_normal_mode (const char *config)
+ }
+ 
+ static grub_err_t
+-grub_try_normal (const char *variable)
++grub_try_normal_prefix (const char *prefix)
+ {
+     char *config;
+-    const char *prefix;
+     grub_err_t err = GRUB_ERR_FILE_NOT_FOUND;
+     const char *net_search_cfg;
+     int disable_net_search = 0;
+ 
+-    prefix = grub_env_get (variable);
+-    if (!prefix)
+-      return GRUB_ERR_FILE_NOT_FOUND;
+-
+     net_search_cfg = grub_env_get ("feature_net_search_cfg");
+     if (net_search_cfg && net_search_cfg[0] == 'n')
+       disable_net_search = 1;
+@@ -362,7 +357,7 @@ grub_try_normal (const char *variable)
+        config = grub_malloc (config_len);
+ 
+        if (! config)
+-         return GRUB_ERR_FILE_NOT_FOUND;
++         return err;
+ 
+        grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
+        err = grub_net_search_config_file (config);
+@@ -391,6 +386,53 @@ grub_try_normal (const char *variable)
+     return err;
+ }
+ 
++static int
++grub_try_normal_dev (const char *name, void *data)
++{
++  grub_err_t err;
++  const char *prefix = grub_xasprintf ("(%s)%s", name, (char *)data);
++
++  if (!prefix)
++    return 0;
++
++  err = grub_try_normal_prefix (prefix);
++  if (err == GRUB_ERR_NONE)
++    return 1;
++
++  return 0;
++}
++
++static grub_err_t
++grub_try_normal_discover (void)
++{
++  char *prefix = grub_env_get ("prefix");
++  grub_err_t err = GRUB_ERR_FILE_NOT_FOUND;
++
++  if (!prefix)
++    return err;
++
++  if (grub_device_iterate (grub_try_normal_dev, (void *)prefix))
++    return GRUB_ERR_NONE;
++
++  return err;
++}
++
++static grub_err_t
++grub_try_normal (const char *variable)
++{
++  grub_err_t err = GRUB_ERR_FILE_NOT_FOUND;
++  const char *prefix;
++
++  if (!variable)
++    return err;
++
++  prefix = grub_env_get (variable);
++  if (!prefix)
++    return err;
++
++  return grub_try_normal_prefix (prefix);
++}
++
+ /* Enter normal mode from rescue mode.  */
+ static grub_err_t
+ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
+@@ -405,6 +447,8 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
+       err = grub_try_normal ("fw_path");
+       if (err == GRUB_ERR_FILE_NOT_FOUND)
+         err = grub_try_normal ("prefix");
++      if (err == GRUB_ERR_FILE_NOT_FOUND)
++        err = grub_try_normal_discover ();
+       if (err == GRUB_ERR_FILE_NOT_FOUND)
+         grub_enter_normal_mode (0);
+     }
diff --git a/SOURCES/0187-libtasn1-disable-code-not-needed-in-grub.patch b/SOURCES/0187-libtasn1-disable-code-not-needed-in-grub.patch
deleted file mode 100644
index 00f5588..0000000
--- a/SOURCES/0187-libtasn1-disable-code-not-needed-in-grub.patch
+++ /dev/null
@@ -1,307 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Fri, 1 May 2020 17:12:23 +1000
-Subject: [PATCH] libtasn1: disable code not needed in grub
-
-We don't expect to be able to write ASN.1, only read it,
-so we can disable some code.
-
-Do that with #if 0/#endif, rather than deletion. This means
-that the difference between upstream and grub is smaller,
-which should make updating libtasn1 easier in the future.
-
-With these exclusions we also avoid the need for minmax.h,
-which is convenient because it means we don't have to
-import it from gnulib.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/lib/libtasn1/lib/coding.c    | 12 ++++++++++--
- grub-core/lib/libtasn1/lib/decoding.c  |  2 ++
- grub-core/lib/libtasn1/lib/element.c   |  4 ++--
- grub-core/lib/libtasn1/lib/errors.c    |  3 +++
- grub-core/lib/libtasn1/lib/structure.c | 10 ++++++----
- include/grub/libtasn1.h                | 15 +++++++++++++++
- 6 files changed, 38 insertions(+), 8 deletions(-)
-
-diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c
-index 245ea64cf0a..52def598368 100644
---- a/grub-core/lib/libtasn1/lib/coding.c
-+++ b/grub-core/lib/libtasn1/lib/coding.c
-@@ -30,11 +30,11 @@
- #include "parser_aux.h"
- #include <gstr.h>
- #include "element.h"
--#include "minmax.h"
- #include <structure.h>
- 
- #define MAX_TAG_LEN 16
- 
-+#if 0
- /******************************************************/
- /* Function : _asn1_error_description_value_not_found */
- /* Description: creates the ErrorDescription string   */
-@@ -58,6 +58,7 @@ _asn1_error_description_value_not_found (asn1_node node,
-   Estrcat (ErrorDescription, "' not found");
- 
- }
-+#endif
- 
- /**
-  * asn1_length_der:
-@@ -244,6 +245,7 @@ asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
-   return ASN1_SUCCESS;
- }
- 
-+#if 0
- /******************************************************/
- /* Function : _asn1_time_der                          */
- /* Description: creates the DER coding for a TIME     */
-@@ -281,7 +283,7 @@ _asn1_time_der (unsigned char *str, int str_len, unsigned char *der,
- 
-   return ASN1_SUCCESS;
- }
--
-+#endif
- 
- /*
- void
-@@ -520,6 +522,7 @@ asn1_bit_der (const unsigned char *str, int bit_len,
- }
- 
- 
-+#if 0
- /******************************************************/
- /* Function : _asn1_complete_explicit_tag             */
- /* Description: add the length coding to the EXPLICIT */
-@@ -596,6 +599,7 @@ _asn1_complete_explicit_tag (asn1_node node, unsigned char *der,
- 
-   return ASN1_SUCCESS;
- }
-+#endif
- 
- const tag_and_class_st _asn1_tags[] = {
-   [ASN1_ETYPE_GENERALSTRING] =
-@@ -648,6 +652,8 @@ const tag_and_class_st _asn1_tags[] = {
- 
- unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]);
- 
-+
-+#if 0
- /******************************************************/
- /* Function : _asn1_insert_tag_der                    */
- /* Description: creates the DER coding of tags of one */
-@@ -1413,3 +1419,5 @@ error:
-   asn1_delete_structure (&node);
-   return err;
- }
-+
-+#endif
-\ No newline at end of file
-diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c
-index ff04eb778cb..42f9a92b5d4 100644
---- a/grub-core/lib/libtasn1/lib/decoding.c
-+++ b/grub-core/lib/libtasn1/lib/decoding.c
-@@ -1613,6 +1613,7 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len,
-   return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription);
- }
- 
-+#if 0
- /**
-  * asn1_der_decoding_element:
-  * @structure: pointer to an ASN1 structure
-@@ -1643,6 +1644,7 @@ asn1_der_decoding_element (asn1_node * structure, const char *elementName,
- {
-   return asn1_der_decoding(structure, ider, len, errorDescription);
- }
-+#endif
- 
- /**
-  * asn1_der_decoding_startEnd:
-diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c
-index 997eb2725dc..539008d8e94 100644
---- a/grub-core/lib/libtasn1/lib/element.c
-+++ b/grub-core/lib/libtasn1/lib/element.c
-@@ -191,7 +191,7 @@ _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache)
-   return ASN1_SUCCESS;
- }
- 
--
-+#if 0
- /**
-  * asn1_write_value:
-  * @node_root: pointer to a structure
-@@ -645,7 +645,7 @@ asn1_write_value (asn1_node node_root, const char *name,
- 
-   return ASN1_SUCCESS;
- }
--
-+#endif
- 
- #define PUT_VALUE( ptr, ptr_size, data, data_size) \
- 	*len = data_size; \
-diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c
-index cee74daf795..42785e8622b 100644
---- a/grub-core/lib/libtasn1/lib/errors.c
-+++ b/grub-core/lib/libtasn1/lib/errors.c
-@@ -57,6 +57,8 @@ static const libtasn1_error_entry error_algorithms[] = {
-   {0, 0}
- };
- 
-+
-+#if 0
- /**
-  * asn1_perror:
-  * @error: is an error returned by a libtasn1 function.
-@@ -73,6 +75,7 @@ asn1_perror (int error)
-   const char *str = asn1_strerror (error);
-   fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)");
- }
-+#endif
- 
- /**
-  * asn1_strerror:
-diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c
-index 8189c56a4c9..fcfde01a393 100644
---- a/grub-core/lib/libtasn1/lib/structure.c
-+++ b/grub-core/lib/libtasn1/lib/structure.c
-@@ -76,7 +76,7 @@ _asn1_find_left (asn1_node_const node)
-   return node->left;
- }
- 
--
-+#if 0
- int
- _asn1_create_static_structure (asn1_node_const pointer, char *output_file_name,
- 			       char *vector_name)
-@@ -155,7 +155,7 @@ _asn1_create_static_structure (asn1_node_const pointer, char *output_file_name,
- 
-   return ASN1_SUCCESS;
- }
--
-+#endif
- 
- /**
-  * asn1_array2tree:
-@@ -718,7 +718,7 @@ asn1_create_element (asn1_node_const definitions, const char *source_name,
-   return res;
- }
- 
--
-+#if 0
- /**
-  * asn1_print_structure:
-  * @out: pointer to the output file (e.g. stdout).
-@@ -1058,7 +1058,7 @@ asn1_print_structure (FILE * out, asn1_node_const structure, const char *name,
- 	}
-     }
- }
--
-+#endif
- 
- 
- /**
-@@ -1153,6 +1153,7 @@ asn1_find_structure_from_oid (asn1_node_const definitions, const char *oidValue)
-   return NULL;			/* ASN1_ELEMENT_NOT_FOUND; */
- }
- 
-+#if 0
- /**
-  * asn1_copy_node:
-  * @dst: Destination asn1 node.
-@@ -1202,6 +1203,7 @@ asn1_copy_node (asn1_node dst, const char *dst_name,
- 
-   return result;
- }
-+#endif
- 
- /**
-  * asn1_dup_node:
-diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h
-index 6fd7a30dc35..785eda2ae3f 100644
---- a/include/grub/libtasn1.h
-+++ b/include/grub/libtasn1.h
-@@ -319,6 +319,8 @@ typedef struct asn1_data_node_st asn1_data_node_st;
- /*  Functions definitions          */
- /***********************************/
- 
-+/* These functions are not used in grub and should not be referenced. */
-+#if 0
- extern ASN1_API int
-   asn1_parser2tree (const char *file,
- 		      asn1_node * definitions, char *error_desc);
-@@ -327,14 +329,17 @@ extern ASN1_API int
-   asn1_parser2array (const char *inputFileName,
- 		       const char *outputFileName,
- 		       const char *vectorName, char *error_desc);
-+#endif
- 
- extern ASN1_API int
-   asn1_array2tree (const asn1_static_node * array,
- 		     asn1_node * definitions, char *errorDescription);
- 
-+#if 0
- extern ASN1_API void
-   asn1_print_structure (FILE * out, asn1_node_const structure,
- 			  const char *name, int mode);
-+#endif
- 
- extern ASN1_API int
-   asn1_create_element (asn1_node_const definitions,
-@@ -347,9 +352,11 @@ extern ASN1_API int asn1_delete_structure2 (asn1_node * structure, unsigned int
- extern ASN1_API int
-   asn1_delete_element (asn1_node structure, const char *element_name);
- 
-+#if 0
- extern ASN1_API int
-   asn1_write_value (asn1_node node_root, const char *name,
- 		      const void *ivalue, int len);
-+#endif
- 
- extern ASN1_API int
-   asn1_read_value (asn1_node_const root, const char *name,
-@@ -365,9 +372,11 @@ extern ASN1_API int
- extern ASN1_API int
-   asn1_number_of_elements (asn1_node_const element, const char *name, int *num);
- 
-+#if 0
- extern ASN1_API int
-   asn1_der_coding (asn1_node_const element, const char *name,
- 		     void *ider, int *len, char *ErrorDescription);
-+#endif
- 
- extern ASN1_API int
-   asn1_der_decoding2 (asn1_node *element, const void *ider,
-@@ -378,12 +387,14 @@ extern ASN1_API int
-   asn1_der_decoding (asn1_node * element, const void *ider,
- 		       int ider_len, char *errorDescription);
- 
-+#if 0
- /* Do not use. Use asn1_der_decoding() instead. */
- extern ASN1_API int
-   asn1_der_decoding_element (asn1_node * structure,
- 			       const char *elementName,
- 			       const void *ider, int len,
- 			       char *errorDescription) _ASN1_GCC_ATTR_DEPRECATED;
-+#endif
- 
- extern ASN1_API int
-   asn1_der_decoding_startEnd (asn1_node element,
-@@ -408,13 +419,17 @@ extern ASN1_API const char *asn1_find_structure_from_oid (asn1_node_const
- 							    const char
- 							    *oidValue);
- 
-+#if 0
- __LIBTASN1_PURE__
- extern ASN1_API const char *asn1_check_version (const char *req_version);
-+#endif
- 
- __LIBTASN1_PURE__
- extern ASN1_API const char *asn1_strerror (int error);
- 
-+#if 0
- extern ASN1_API void asn1_perror (int error);
-+#endif
- 
- #define ASN1_MAX_TAG_SIZE 4
- #define ASN1_MAX_LENGTH_SIZE 9
diff --git a/SOURCES/0187-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch b/SOURCES/0187-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch
new file mode 100644
index 0000000..b9bc140
--- /dev/null
+++ b/SOURCES/0187-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch
@@ -0,0 +1,88 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 19 Jul 2021 14:35:55 +1000
+Subject: [PATCH] powerpc: adjust setting of prefix for signed binary case
+
+On RHEL-signed powerpc grub, we sign a grub with -p /grub2 and expect
+that there's a boot partition.
+
+Unfortunately grub_set_prefix_and_root tries to convert this to
+($fwdevice)/grub2. This ends up being (ieee1275/disk)/grub2 and that
+falls apart pretty quickly - there's no file-system on ieee1275/disk,
+and it makes the search routine try things like
+(ieee1275/disk,msdos2)(ieee1275/disk)/grub2 which also doesn't work.
+
+Detect if we would be about to create (ieee1275/disk)/path and don't:
+preserve a prefix of /path instead and hope the search later finds us.
+
+Related: rhbz#1899864
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+[rharwood@redhat.com: squash in fixup commit]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/kern/main.c | 49 ++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 44 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
+index b573be6650..3fc3401472 100644
+--- a/grub-core/kern/main.c
++++ b/grub-core/kern/main.c
+@@ -216,13 +216,52 @@ grub_set_prefix_and_root (void)
+   if (device)
+     {
+       char *prefix_set;
+-    
+-      prefix_set = grub_xasprintf ("(%s)%s", device, path ? : "");
+-      if (prefix_set)
++
++#ifdef __powerpc__
++      /* We have to be careful here on powerpc-ieee1275 + signed grub. We
++	 will have signed something with a prefix that doesn't have a device
++	 because we cannot know in advance what partition we're on.
++
++	 We will have had !device earlier, so we will have set device=fwdevice
++	 However, we want to make sure we do not end up setting prefix to be
++	 ($fwdevice)/path, because we will then end up trying to boot or search
++	 based on a prefix of (ieee1275/disk)/path, which will not work because
++	 it's missing a partition.
++
++	 Also:
++	  - You can end up with a device with an FS directly on it, without
++	    a partition, e.g. ieee1275/cdrom.
++
++	  - powerpc-ieee1275 + grub-install sets e.g. prefix=(,gpt2)/path,
++	    which will have now been extended to device=$fwdisk,partition
++	    and path=/path
++
++	  - PowerVM will give us device names like
++	    ieee1275//vdevice/v-scsi@3000006c/disk@8100000000000000
++	    and we don't want to try to encode some sort of truth table about
++	    what sorts of paths represent disks with partition tables and those
++	    without partition tables.
++
++	 So we act unless there is a comma in the device, which would indicate
++	 a partition has already been specified.
++
++	 (If we only have a path, the code in normal to discover config files
++	 will try both without partitions and then with any partitions so we
++	 will cover both CDs and HDs.)
++       */
++      if (grub_strchr (device, ',') == NULL)
++        grub_env_set ("prefix", path);
++      else
++#endif
+ 	{
+-	  grub_env_set ("prefix", prefix_set);
+-	  grub_free (prefix_set);
++	  prefix_set = grub_xasprintf ("(%s)%s", device, path ? : "");
++	  if (prefix_set)
++	  {
++	    grub_env_set ("prefix", prefix_set);
++	    grub_free (prefix_set);
++	  }
+ 	}
++
+       grub_env_set ("root", device);
+     }
+ 
diff --git a/SOURCES/0188-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch b/SOURCES/0188-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch
new file mode 100644
index 0000000..7fc40f1
--- /dev/null
+++ b/SOURCES/0188-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch
@@ -0,0 +1,118 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Erwan Velu <erwanaliasr1@gmail.com>
+Date: Wed, 25 Aug 2021 15:31:52 +0200
+Subject: [PATCH] fs/xfs: Fix unreadable filesystem with v4 superblock
+
+The commit 8b1e5d193 (fs/xfs: Add bigtime incompat feature support)
+introduced the bigtime support by adding some features in v3 inodes.
+This change extended grub_xfs_inode struct by 76 bytes but also changed
+the computation of XFS_V2_INODE_SIZE and XFS_V3_INODE_SIZE. Prior this
+commit, XFS_V2_INODE_SIZE was 100 bytes. After the commit it's 84 bytes
+XFS_V2_INODE_SIZE becomes 16 bytes too small.
+
+As a result, the data structures aren't properly aligned and the GRUB
+generates "attempt to read or write outside of partition" errors when
+trying to read the XFS filesystem:
+
+                             GNU GRUB  version 2.11
+	....
+	grub> set debug=efi,gpt,xfs
+	grub> insmod part_gpt
+	grub> ls (hd0,gpt1)/
+	partmap/gpt.c:93: Read a valid GPT header
+	partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125
+	fs/xfs.c:931: Reading sb
+	fs/xfs.c:270: Validating superblock
+	fs/xfs.c:295: XFS v4 superblock detected
+	fs/xfs.c:962: Reading root ino 128
+	fs/xfs.c:515: Reading inode (128) - 64, 0
+	fs/xfs.c:515: Reading inode (739521961424144223) - 344365866970255880, 3840
+	error: attempt to read or write outside of partition.
+
+This commit change the XFS_V2_INODE_SIZE computation by subtracting 76
+bytes instead of 92 bytes from the actual size of grub_xfs_inode struct.
+This 76 bytes value comes from added members:
+	20 grub_uint8_t   unused5
+	 1 grub_uint64_t  flags2
+        48 grub_uint8_t   unused6
+
+This patch explicitly splits the v2 and v3 parts of the structure.
+The unused4 is still ending of the v2 structures and the v3 starts
+at unused5. Thanks to this we will avoid future corruptions of v2
+or v3 inodes.
+
+The XFS_V2_INODE_SIZE is returning to its expected size and the
+filesystem is back to a readable state:
+
+                      GNU GRUB  version 2.11
+	....
+	grub> set debug=efi,gpt,xfs
+	grub> insmod part_gpt
+	grub> ls (hd0,gpt1)/
+	partmap/gpt.c:93: Read a valid GPT header
+	partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125
+	fs/xfs.c:931: Reading sb
+	fs/xfs.c:270: Validating superblock
+	fs/xfs.c:295: XFS v4 superblock detected
+	fs/xfs.c:962: Reading root ino 128
+	fs/xfs.c:515: Reading inode (128) - 64, 0
+	fs/xfs.c:515: Reading inode (128) - 64, 0
+	fs/xfs.c:931: Reading sb
+	fs/xfs.c:270: Validating superblock
+	fs/xfs.c:295: XFS v4 superblock detected
+	fs/xfs.c:962: Reading root ino 128
+	fs/xfs.c:515: Reading inode (128) - 64, 0
+	fs/xfs.c:515: Reading inode (128) - 64, 0
+	fs/xfs.c:515: Reading inode (128) - 64, 0
+	fs/xfs.c:515: Reading inode (131) - 64, 768
+	efi/ fs/xfs.c:515: Reading inode (3145856) - 1464904, 0
+	grub2/ fs/xfs.c:515: Reading inode (132) - 64, 1024
+	grub/ fs/xfs.c:515: Reading inode (139) - 64, 2816
+	grub>
+
+Fixes: 8b1e5d193 (fs/xfs: Add bigtime incompat feature support)
+
+Signed-off-by: Erwan Velu <e.velu@criteo.com>
+Tested-by: Carlos Maiolino <cmaiolino@redhat.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit a4b495520e4dc41a896a8b916a64eda9970c50ea)
+---
+ grub-core/fs/xfs.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
+index 0f524c3a8a..e3816d1ec4 100644
+--- a/grub-core/fs/xfs.c
++++ b/grub-core/fs/xfs.c
+@@ -192,6 +192,11 @@ struct grub_xfs_time_legacy
+   grub_uint32_t nanosec;
+ } GRUB_PACKED;
+ 
++/*
++ * The struct grub_xfs_inode layout was taken from the
++ * struct xfs_dinode_core which is described here:
++ * https://mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf
++ */
+ struct grub_xfs_inode
+ {
+   grub_uint8_t magic[2];
+@@ -208,14 +213,15 @@ struct grub_xfs_inode
+   grub_uint32_t nextents;
+   grub_uint16_t unused3;
+   grub_uint8_t fork_offset;
+-  grub_uint8_t unused4[37];
++  grub_uint8_t unused4[17]; /* Last member of inode v2. */
++  grub_uint8_t unused5[20]; /* First member of inode v3. */
+   grub_uint64_t flags2;
+-  grub_uint8_t unused5[48];
++  grub_uint8_t unused6[48]; /* Last member of inode v3. */
+ } GRUB_PACKED;
+ 
+ #define XFS_V3_INODE_SIZE	sizeof(struct grub_xfs_inode)
+-/* Size of struct grub_xfs_inode until fork_offset (included). */
+-#define XFS_V2_INODE_SIZE	(XFS_V3_INODE_SIZE - 92)
++/* Size of struct grub_xfs_inode v2, up to unused4 member included. */
++#define XFS_V2_INODE_SIZE	(XFS_V3_INODE_SIZE - 76)
+ 
+ struct grub_xfs_dirblock_tail
+ {
diff --git a/SOURCES/0188-libtasn1-changes-for-grub-compatibility.patch b/SOURCES/0188-libtasn1-changes-for-grub-compatibility.patch
deleted file mode 100644
index 9b2275c..0000000
--- a/SOURCES/0188-libtasn1-changes-for-grub-compatibility.patch
+++ /dev/null
@@ -1,202 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Fri, 1 May 2020 20:44:29 +1000
-Subject: [PATCH] libtasn1: changes for grub compatibility
-
-Do a few things to make libtasn1 compile as part of grub:
-
- - replace strcat. grub removed strcat so replace it with the appropriate
-   calls to memcpy and strlen.
-
- - replace c_isdigit with grub_isdigit (and don't import c-ctype from
-   gnulib) grub_isdigit provides the same functionality as c_isdigit: it
-   determines if the input is an ASCII digit without regard for locale.
-
- - replace GL_ATTRIBUTE_PURE with __attribute__((pure)) which been
-   supported since gcc-2.96. This avoids messing around with gnulib.
-
- - adjust libtasn1.h: drop the ASN1_API logic, it's not needed for our
-   modules. Unconditionally support const and pure attributes and adjust
-   header paths.
-
- - adjust header paths to "grub/libtasn1.h".
-
- - replace a 64 bit division with a call to grub_divmod64, preventing
-   creation of __udivdi3 calls on 32 bit platforms.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/lib/libtasn1/lib/decoding.c   | 11 ++++++-----
- grub-core/lib/libtasn1/lib/element.c    |  3 ++-
- grub-core/lib/libtasn1/lib/gstr.c       |  4 ++--
- grub-core/lib/libtasn1/lib/parser_aux.c |  7 ++++---
- grub-core/lib/libtasn1/lib/int.h        |  4 ++--
- include/grub/libtasn1.h                 | 26 ++++++--------------------
- 6 files changed, 22 insertions(+), 33 deletions(-)
-
-diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c
-index 42f9a92b5d4..7856858b272 100644
---- a/grub-core/lib/libtasn1/lib/decoding.c
-+++ b/grub-core/lib/libtasn1/lib/decoding.c
-@@ -32,7 +32,8 @@
- #include <element.h>
- #include <limits.h>
- #include <intprops.h>
--#include <c-ctype.h>
-+
-+#define c_isdigit grub_isdigit
- 
- #ifdef DEBUG
- # define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__)
-@@ -2008,8 +2009,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element,
- 	  (p2->type & CONST_ASSIGN))
- 	{
- 	  strcpy (name, definitions->name);
--	  strcat (name, ".");
--	  strcat (name, p2->name);
-+	  memcpy (name + strlen(name), ".", sizeof(" . "));
-+	  memcpy (name + strlen(name), p2->name, strlen(p2->name) + 1);
- 
- 	  len = sizeof (value);
- 	  result = asn1_read_value (definitions, name, value, &len);
-@@ -2026,8 +2027,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element,
- 	      if (p2)
- 		{
- 		  strcpy (name, definitions->name);
--		  strcat (name, ".");
--		  strcat (name, p2->name);
-+		  memcpy (name + strlen(name), ".", sizeof(" . "));
-+		  memcpy (name + strlen(name), p2->name, strlen(p2->name) + 1);
- 
- 		  result = asn1_create_element (definitions, name, &aux);
- 		  if (result == ASN1_SUCCESS)
-diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c
-index 539008d8e94..ed761ff56bd 100644
---- a/grub-core/lib/libtasn1/lib/element.c
-+++ b/grub-core/lib/libtasn1/lib/element.c
-@@ -30,9 +30,10 @@
- #include "parser_aux.h"
- #include <gstr.h>
- #include "structure.h"
--#include "c-ctype.h"
- #include "element.h"
- 
-+#define c_isdigit grub_isdigit
-+
- void
- _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size)
- {
-diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c
-index e91a3a151c0..e33875c2c7c 100644
---- a/grub-core/lib/libtasn1/lib/gstr.c
-+++ b/grub-core/lib/libtasn1/lib/gstr.c
-@@ -36,13 +36,13 @@ _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src)
- 
-   if (dest_tot_size - dest_size > str_size)
-     {
--      strcat (dest, src);
-+      memcpy (dest + dest_size, src, str_size + 1);
-     }
-   else
-     {
-       if (dest_tot_size - dest_size > 0)
- 	{
--	  strncat (dest, src, (dest_tot_size - dest_size) - 1);
-+	  memcpy (dest + dest_size, src, (dest_tot_size - dest_size) - 1);
- 	  dest[dest_tot_size - 1] = 0;
- 	}
-     }
-diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c
-index d5dbbf8765d..89c9be69dc2 100644
---- a/grub-core/lib/libtasn1/lib/parser_aux.c
-+++ b/grub-core/lib/libtasn1/lib/parser_aux.c
-@@ -26,7 +26,8 @@
- #include "gstr.h"
- #include "structure.h"
- #include "element.h"
--#include "c-ctype.h"
-+
-+#define c_isdigit grub_isdigit
- 
- char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1];	/* identifier name not found */
- 
-@@ -40,7 +41,7 @@ char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1];	/* identifier name not fou
- #ifdef __clang__
- __attribute__((no_sanitize("integer")))
- #endif
--_GL_ATTRIBUTE_PURE
-+__attribute__((__pure__))
- static unsigned int
- _asn1_hash_name (const char *x)
- {
-@@ -634,7 +635,7 @@ _asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE])
-   count = 0;
-   do
-     {
--      d = val / 10;
-+      d = grub_divmod64(val, 10, NULL);
-       r = val - d * 10;
-       temp[start + count] = '0' + (char) r;
-       count++;
-diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h
-index ea1625786c1..4a568efee9c 100644
---- a/grub-core/lib/libtasn1/lib/int.h
-+++ b/grub-core/lib/libtasn1/lib/int.h
-@@ -35,7 +35,7 @@
- #include <sys/types.h>
- #endif
- 
--#include <libtasn1.h>
-+#include "grub/libtasn1.h"
- 
- #define ASN1_SMALL_VALUE_SIZE 16
- 
-@@ -115,7 +115,7 @@ extern const tag_and_class_st _asn1_tags[];
- #define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b)
- #define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b)
- #define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b)
--#define _asn1_strcat(a,b) strcat((char *)a, (const char *)b)
-+#define _asn1_strcat(a,b) memcpy((char *)a + strlen((const char *)a), (const char *)b, strlen((const char *)b) + 1)
- 
- #if SIZEOF_UNSIGNED_LONG_INT == 8
- # define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b)
-diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h
-index 785eda2ae3f..28dbf16c4e0 100644
---- a/include/grub/libtasn1.h
-+++ b/include/grub/libtasn1.h
-@@ -38,29 +38,15 @@
- #ifndef LIBTASN1_H
- #define LIBTASN1_H
- 
--#ifndef ASN1_API
--#if defined ASN1_BUILDING && defined HAVE_VISIBILITY && HAVE_VISIBILITY
--#define ASN1_API __attribute__((__visibility__("default")))
--#elif defined ASN1_BUILDING && defined _MSC_VER && ! defined ASN1_STATIC
--#define ASN1_API __declspec(dllexport)
--#elif defined _MSC_VER && ! defined ASN1_STATIC
--#define ASN1_API __declspec(dllimport)
--#else
-+/* grub: ASN1_API is not used */
- #define ASN1_API
--#endif
--#endif
- 
--#ifdef __GNUC__
--# define __LIBTASN1_CONST__  __attribute__((const))
--# define __LIBTASN1_PURE__  __attribute__((pure))
--#else
--# define __LIBTASN1_CONST__
--# define __LIBTASN1_PURE__
--#endif
-+/* grub: all our supported compilers support these attributes */
-+#define __LIBTASN1_CONST__  __attribute__((const))
-+#define __LIBTASN1_PURE__  __attribute__((pure))
- 
--#include <sys/types.h>
--#include <time.h>
--#include <stdio.h>		/* for FILE* */
-+#include <grub/types.h>
-+#include <grub/time.h>
- 
- #ifdef __cplusplus
- extern "C"
diff --git a/SOURCES/0189-Print-module-name-on-license-check-failure.patch b/SOURCES/0189-Print-module-name-on-license-check-failure.patch
new file mode 100644
index 0000000..5c30859
--- /dev/null
+++ b/SOURCES/0189-Print-module-name-on-license-check-failure.patch
@@ -0,0 +1,48 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 12 Oct 2021 12:34:23 -0400
+Subject: [PATCH] Print module name on license check failure
+
+At the very least, this will make it easier to track down the problem
+module - or, if something else has gone wrong, provide more information
+for debugging.
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/kern/dl.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index 9557254035..f304494574 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -528,14 +528,16 @@ grub_dl_find_section_index (Elf_Ehdr *e, const char *name)
+    Be sure to understand your license obligations.
+ */
+ static grub_err_t
+-grub_dl_check_license (Elf_Ehdr *e)
++grub_dl_check_license (grub_dl_t mod, Elf_Ehdr *e)
+ {
+   Elf_Shdr *s = grub_dl_find_section (e, ".module_license");
+   if (s && (grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3") == 0
+ 	    || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3+") == 0
+ 	    || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv2+") == 0))
+     return GRUB_ERR_NONE;
+-  return grub_error (GRUB_ERR_BAD_MODULE, "incompatible license");
++  return grub_error (GRUB_ERR_BAD_MODULE,
++		     "incompatible license in module %s: %s", mod->name,
++		     (char *) e + s->sh_offset);
+ }
+ 
+ static grub_err_t
+@@ -743,8 +745,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
+      constitutes linking) and GRUB core being licensed under GPLv3+.
+      Be sure to understand your license obligations.
+   */
+-  if (grub_dl_check_license (e)
+-      || grub_dl_resolve_name (mod, e)
++  if (grub_dl_resolve_name (mod, e)
++      || grub_dl_check_license (mod, e)
+       || grub_dl_resolve_dependencies (mod, e)
+       || grub_dl_load_segments (mod, e)
+       || grub_dl_resolve_symbols (mod, e)
diff --git a/SOURCES/0189-libtasn1-compile-into-asn1-module.patch b/SOURCES/0189-libtasn1-compile-into-asn1-module.patch
deleted file mode 100644
index 67be4e8..0000000
--- a/SOURCES/0189-libtasn1-compile-into-asn1-module.patch
+++ /dev/null
@@ -1,70 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Fri, 5 Jun 2020 17:47:25 +1000
-Subject: [PATCH] libtasn1: compile into asn1 module
-
-Create a wrapper file that specifies the module license.
-Set up the makefile so it is built.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/Makefile.core.def        | 15 +++++++++++++++
- grub-core/lib/libtasn1_wrap/wrap.c | 26 ++++++++++++++++++++++++++
- 2 files changed, 41 insertions(+)
- create mode 100644 grub-core/lib/libtasn1_wrap/wrap.c
-
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 97347ae76f9..21d2c541850 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -2576,3 +2576,18 @@ module = {
-   common = commands/i386/wrmsr.c;
-   enable = x86;
- };
-+
-+module = {
-+  name = asn1;
-+  common = lib/libtasn1/lib/decoding.c;
-+  common = lib/libtasn1/lib/coding.c;
-+  common = lib/libtasn1/lib/element.c;
-+  common = lib/libtasn1/lib/structure.c;
-+  common = lib/libtasn1/lib/parser_aux.c;
-+  common = lib/libtasn1/lib/gstr.c;
-+  common = lib/libtasn1/lib/errors.c;
-+  common = lib/libtasn1_wrap/wrap.c;
-+  cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
-+  // -Wno-type-limits comes from libtasn1's configure.ac
-+  cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1/lib -Wno-type-limits';
-+};
-diff --git a/grub-core/lib/libtasn1_wrap/wrap.c b/grub-core/lib/libtasn1_wrap/wrap.c
-new file mode 100644
-index 00000000000..622ba942e33
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/wrap.c
-@@ -0,0 +1,26 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020 IBM Corporation
-+ *
-+ *  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>
-+
-+/*
-+ * libtasn1 is provided under LGPL2.1+, which is compatible
-+ * with GPL3+. As Grub as a whole is under GPL3+, this module
-+ * is therefore under GPL3+ also.
-+ */
-+GRUB_MOD_LICENSE ("GPLv3+");
diff --git a/SOURCES/0190-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch b/SOURCES/0190-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch
new file mode 100644
index 0000000..216418b
--- /dev/null
+++ b/SOURCES/0190-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch
@@ -0,0 +1,106 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Fri, 22 Oct 2021 09:53:15 +1100
+Subject: [PATCH] powerpc-ieee1275: load grub at 4MB, not 2MB
+
+This was first reported under PFW but reproduces under SLOF.
+
+ - The core.elf was 2126152 = 0x207148 bytes in size with the following
+   program headers (per readelf):
+
+Entry point 0x200000
+There are 4 program headers, starting at offset 52
+
+Program Headers:
+  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
+  LOAD           0x000160 0x00200000 0x00200000 0x21f98 0x2971c RWE 0x8
+  GNU_STACK      0x0220f8 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
+  LOAD           0x0220f8 0x00232000 0x00232000 0x1e4e50 0x1e4e50 RWE 0x4
+  NOTE           0x206f48 0x00000000 0x00000000 0x00200 0x00000 R   0x4
+
+ - SLOF places the ELF file at 0x4000 (after the reserved space for
+   interrupt handlers etc.) upwards. The image was 2126152 = 0x207148
+   bytes in size, so it runs from 0x4000 - 0x20b148. We'll call 0x4000 the
+   load address.
+
+0x0        0x4000         0x20b148
+ |----------|--------------|
+ | reserved | ELF contents |
+
+ - SLOF then copies the first LOAD program header (for .text). That runs
+   for 0x21f98 bytes. It runs from
+      (load addr + 0x160) to (load addr + 0x160 + 0x21f98)
+    = 0x4160 to 0x260f8
+   and we copy it to 0x200000 to 0x221f98. This overwrites the end of the
+   image:
+
+0x0       0x4000     0x200000        0x221f98
+ |----------|------------|---------------|
+ | reserved | ELF cont.. | .text section |
+
+ - SLOF zeros the bss up to PhysAddr + MemSize = 0x22971c
+
+0x0       0x4000      0x200000       0x221f98 0x22971c
+ |----------|------------|---------------|--------|
+ | reserved | ELF cont.. | .text section | bss 0s |
+
+ - SLOF then goes to fulfil the next LOAD header (for mods), which is
+   for 0x1e4e50 bytes. We copy from
+      (load addr + 0x220f8) to (load addr + 0x220f8 + 0x1e4e50)
+    = 0x260f8 to 0x20af48
+   and we copy it to 0x232000 to 0x416e50:
+
+0x0       0x4000      0x200000       0x221f98 0x22971c
+ |----------|------------|---------------|--------|
+ | reserved | ELF cont.. | .text section | bss 0s |
+               |-------------|
+               | copied area |
+            0x260f8      0x20af48
+
+   This goes poorly:
+
+0x0       0x4000      0x200000       0x221f98 0x22971c 0x232000 0x40bf08      0x416e50
+ |----------|------------|---------------|--------|-----|-----------|-------------|
+ | reserved | ELF cont.. | .text section | bss 0s | pad | some mods | .text start |
+
+This matches the observations on the running system - 0x40bf08 was where
+the contents of memory no longer matched the contents of the ELF file.
+
+This was reported as a license verification failure on SLOF as the
+last module's .module_license section fell past where the corruption
+began.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+[rharwood@redhat.com: trim very detailed commit message]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/Makefile.core.def | 2 +-
+ include/grub/offsets.h      | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 4a57de975e..08ac0fb15f 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -89,7 +89,7 @@ kernel = {
+   i386_xen_pvh_ldflags     = '$(TARGET_IMG_BASE_LDOPT),0x100000';
+ 
+   mips_loongson_ldflags    = '-Wl,-Ttext,0x80200000';
+-  powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x200000';
++  powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x400000';
+   sparc64_ieee1275_ldflags = '-Wl,-Ttext,0x4400';
+   mips_arc_ldflags    = '-Wl,-Ttext,$(TARGET_LINK_ADDR)';
+   mips_qemu_mips_ldflags    = '-Wl,-Ttext,0x80200000';
+diff --git a/include/grub/offsets.h b/include/grub/offsets.h
+index 871e1cd4c3..69211aa798 100644
+--- a/include/grub/offsets.h
++++ b/include/grub/offsets.h
+@@ -63,7 +63,7 @@
+ #define GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR 0x4400
+ 
+ #define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ALIGN 4
+-#define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x200000
++#define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x400000
+ 
+ #define GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR         0x80200000
+ 
diff --git a/SOURCES/0190-test_asn1-test-module-for-libtasn1.patch b/SOURCES/0190-test_asn1-test-module-for-libtasn1.patch
deleted file mode 100644
index 3a02b24..0000000
--- a/SOURCES/0190-test_asn1-test-module-for-libtasn1.patch
+++ /dev/null
@@ -1,1457 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Wed, 10 Jun 2020 17:48:42 +1000
-Subject: [PATCH] test_asn1: test module for libtasn1
-
-Import tests from libtasn1 that don't use functionality we don't
-import. I have put them here rather than in the libtasn1 directory
-because:
-
- -  They need much more significant changes to run in the grub
-    context.
-
- -  I don't expect they will need to be changed when updating
-    libtasn1: I expect the old tests will usually continue to pass on
-    new versions.
-
-This doesn't test the full decoder but that will be exercised in
-test suites for coming patch sets.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- Makefile.util.def                                  |   6 +
- grub-core/Makefile.core.def                        |  13 ++
- .../lib/libtasn1_wrap/tests/CVE-2018-1000654.c     |  61 ++++++
- grub-core/lib/libtasn1_wrap/tests/Test_overflow.c  | 138 ++++++++++++++
- grub-core/lib/libtasn1_wrap/tests/Test_simple.c    | 207 ++++++++++++++++++++
- grub-core/lib/libtasn1_wrap/tests/Test_strings.c   | 150 +++++++++++++++
- .../lib/libtasn1_wrap/tests/object-id-decoding.c   | 116 +++++++++++
- .../lib/libtasn1_wrap/tests/object-id-encoding.c   | 120 ++++++++++++
- grub-core/lib/libtasn1_wrap/tests/octet-string.c   | 211 +++++++++++++++++++++
- grub-core/lib/libtasn1_wrap/tests/reproducers.c    |  81 ++++++++
- grub-core/lib/libtasn1_wrap/wrap_tests.c           |  75 ++++++++
- .../tests/CVE-2018-1000654-1_asn1_tab.h            |  32 ++++
- .../tests/CVE-2018-1000654-2_asn1_tab.h            |  36 ++++
- grub-core/lib/libtasn1_wrap/wrap_tests.h           |  38 ++++
- .gitignore                                         |   1 +
- tests/test_asn1.in                                 |  12 ++
- 16 files changed, 1297 insertions(+)
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_overflow.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_simple.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_strings.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/octet-string.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/reproducers.c
- create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.c
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h
- create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h
- create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.h
- create mode 100644 tests/test_asn1.in
-
-diff --git a/Makefile.util.def b/Makefile.util.def
-index e1242f54022..8cfbe69a76e 100644
---- a/Makefile.util.def
-+++ b/Makefile.util.def
-@@ -1305,6 +1305,12 @@ script = {
-   common = tests/syslinux_test.in;
- };
- 
-+script = {
-+  testcase;
-+  name = test_asn1;
-+  common = tests/test_asn1.in;
-+};
-+
- program = {
-   testcase;
-   name = example_unit_test;
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 21d2c541850..b4aaccf7b57 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -2591,3 +2591,16 @@ module = {
-   // -Wno-type-limits comes from libtasn1's configure.ac
-   cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1/lib -Wno-type-limits';
- };
-+
-+module = {
-+  name = test_asn1;
-+  common = lib/libtasn1_wrap/tests/CVE-2018-1000654.c;
-+  common = lib/libtasn1_wrap/tests/object-id-decoding.c;
-+  common = lib/libtasn1_wrap/tests/object-id-encoding.c;
-+  common = lib/libtasn1_wrap/tests/octet-string.c;
-+  common = lib/libtasn1_wrap/tests/reproducers.c;
-+  common = lib/libtasn1_wrap/tests/Test_overflow.c;
-+  common = lib/libtasn1_wrap/tests/Test_simple.c;
-+  common = lib/libtasn1_wrap/tests/Test_strings.c;
-+  common = lib/libtasn1_wrap/wrap_tests.c;
-+};
-diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c
-new file mode 100644
-index 00000000000..534e304521e
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c
-@@ -0,0 +1,61 @@
-+/*
-+ * Copyright (C) 2002-2018 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * 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 3 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, see <http://www.gnu.org/licenses/>.
-+ *
-+ */
-+
-+/****************************************************************/
-+/* Description: reproducer for CVE-2018-1000654			*/
-+/****************************************************************/
-+
-+#include <grub/libtasn1.h>
-+#include <grub/err.h>
-+#include <grub/mm.h>
-+#include <grub/misc.h>
-+#include <grub/types.h>
-+#include "../wrap_tests.h"
-+
-+#include "CVE-2018-1000654-1_asn1_tab.h"
-+#include "CVE-2018-1000654-2_asn1_tab.h"
-+
-+void
-+test_CVE_2018_1000654 (void)
-+{
-+  int result;
-+  asn1_node definitions = NULL;
-+  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
-+
-+  result = asn1_array2tree (CVE_2018_1000654_1_asn1_tab, &definitions, errorDescription);
-+  if (result != ASN1_RECURSION)
-+    {
-+      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
-+		  asn1_strerror (result), errorDescription);
-+      return;
-+    }
-+
-+  asn1_delete_structure (&definitions);
-+
-+  result = asn1_array2tree (CVE_2018_1000654_2_asn1_tab, &definitions, errorDescription);
-+  if (result != ASN1_RECURSION)
-+    {
-+      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
-+		  asn1_strerror (result), errorDescription);
-+      return;
-+    }
-+
-+  asn1_delete_structure (&definitions);
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c b/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c
-new file mode 100644
-index 00000000000..f48aea0ef8b
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c
-@@ -0,0 +1,138 @@
-+/*
-+ * Copyright (C) 2012-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * 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 3 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, see <http://www.gnu.org/licenses/>.
-+ *
-+ */
-+
-+/* Written by Simon Josefsson */
-+
-+#include <grub/libtasn1.h>
-+#include <grub/err.h>
-+#include <grub/mm.h>
-+#include <grub/misc.h>
-+#include <grub/types.h>
-+#include "../wrap_tests.h"
-+
-+void
-+test_overflow(void)
-+{
-+  /* Test that values larger than long are rejected.  This has worked
-+     fine with all versions of libtasn1. */
-+
-+  {
-+    unsigned char der[] = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
-+    long l;
-+    int len;
-+
-+    l = asn1_get_length_der (der, sizeof der, &len);
-+
-+    if (l != -2L)
-+      {
-+	grub_fatal ("ERROR: asn1_get_length_der bignum (l %ld len %d)\n", l, len);
-+	return;
-+      }
-+  }
-+
-+  /* Test that values larger than int but smaller than long are
-+     rejected.  This limitation was introduced with libtasn1 2.12. */
-+#if (GRUB_LONG_MAX > GRUB_INT_MAX)
-+    {
-+      unsigned long num = ((long) GRUB_UINT_MAX) << 2;
-+      unsigned char der[20];
-+      int der_len;
-+      long l;
-+      int len;
-+
-+      asn1_length_der (num, der, &der_len);
-+
-+      l = asn1_get_length_der (der, der_len, &len);
-+
-+      if (l != -2L)
-+	{
-+	  grub_fatal ("ERROR: asn1_get_length_der intnum (l %ld len %d)\n", l,
-+		      len);
-+	  return;
-+	}
-+    }
-+#endif
-+
-+  /* Test that values larger than would fit in the input string are
-+     rejected.  This problem was fixed in libtasn1 2.12. */
-+  {
-+    unsigned long num = 64;
-+    unsigned char der[20];
-+    int der_len;
-+    long l;
-+    int len;
-+
-+    asn1_length_der (num, der, &der_len);
-+
-+    der_len = sizeof (der);
-+    l = asn1_get_length_der (der, der_len, &len);
-+
-+    if (l != -4L)
-+      {
-+	grub_fatal ("ERROR: asn1_get_length_der overflow-small (l %ld len %d)\n",
-+		    l, len);
-+	return;
-+      }
-+  }
-+
-+  /* Test that values larger than would fit in the input string are
-+     rejected.  This problem was fixed in libtasn1 2.12. */
-+  {
-+    unsigned long num = 1073741824;
-+    unsigned char der[20];
-+    int der_len;
-+    long l;
-+    int len;
-+
-+    asn1_length_der (num, der, &der_len);
-+
-+    der_len = sizeof (der);
-+    l = asn1_get_length_der (der, der_len, &len);
-+
-+    if (l != -4L)
-+      {
-+	grub_fatal ("ERROR: asn1_get_length_der overflow-large1 (l %ld len %d)\n",
-+		    l, len);
-+	return;
-+      }
-+  }
-+
-+  /* Test that values larger than would fit in the input string are
-+     rejected.  This problem was fixed in libtasn1 2.12. */
-+  {
-+    unsigned long num = 2147483649;
-+    unsigned char der[20];
-+    int der_len;
-+    long l;
-+    int len;
-+
-+    asn1_length_der (num, der, &der_len);
-+
-+    der_len = sizeof (der);
-+    l = asn1_get_length_der (der, der_len, &len);
-+
-+    if (l != -2L)
-+      {
-+	grub_fatal ("ERROR: asn1_get_length_der overflow-large2 (l %ld len %d)\n",
-+		    l, len);
-+	return;
-+      }
-+  }
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_simple.c b/grub-core/lib/libtasn1_wrap/tests/Test_simple.c
-new file mode 100644
-index 00000000000..9f01006ddf4
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/Test_simple.c
-@@ -0,0 +1,207 @@
-+/*
-+ * Copyright (C) 2011-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * 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 3 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, see <http://www.gnu.org/licenses/>.
-+ *
-+ * Written by Simon Josefsson
-+ *
-+ */
-+
-+#include <grub/libtasn1.h>
-+#include <grub/mm.h>
-+#include <grub/misc.h>
-+#include <grub/err.h>
-+#include "../wrap_tests.h"
-+
-+struct tv
-+{
-+  int bitlen;
-+  const char *bitstr;
-+  int derlen;
-+  const char *der;
-+};
-+
-+static const struct tv tv[] = {
-+  {0, "", 2, "\x01\x00"},
-+  {1, "\x00", 3, "\x02\x07\x00"},
-+  {2, "\x00", 3, "\x02\x06\x00"},
-+  {3, "\x00", 3, "\x02\x05\x00"},
-+  {4, "\x00", 3, "\x02\x04\x00"},
-+  {5, "\x00", 3, "\x02\x03\x00"},
-+  {6, "\x00", 3, "\x02\x02\x00"},
-+  {7, "\x00", 3, "\x02\x01\x00"},
-+  {8, "\x00\x00", 3, "\x02\x00\x00"},
-+  {9, "\x00\x00", 4, "\x03\x07\x00\x00"},
-+  {10, "\x00\x00", 4, "\x03\x06\x00\x00"},
-+  {11, "\x00\x00", 4, "\x03\x05\x00\x00"},
-+  {12, "\x00\x00", 4, "\x03\x04\x00\x00"},
-+  {13, "\x00\x00", 4, "\x03\x03\x00\x00"},
-+  {14, "\x00\x00", 4, "\x03\x02\x00\x00"},
-+  {15, "\x00\x00", 4, "\x03\x01\x00\x00"},
-+  {16, "\x00\x00", 4, "\x03\x00\x00\x00"},
-+  {17, "\x00\x00\x00", 5, "\x04\x07\x00\x00\x00"},
-+  {18, "\x00\x00\x00", 5, "\x04\x06\x00\x00\x00"},
-+  {19, "\x00\x00\x00", 5, "\x04\x05\x00\x00\x00"},
-+  {1, "\xFF", 3, "\x02\x07\x80"},
-+  {2, "\xFF", 3, "\x02\x06\xc0"},
-+  {3, "\xFF", 3, "\x02\x05\xe0"},
-+  {4, "\xFF", 3, "\x02\x04\xf0"},
-+  {5, "\xFF", 3, "\x02\x03\xf8"},
-+  {6, "\xFF", 3, "\x02\x02\xfc"},
-+  {7, "\xFF", 3, "\x02\x01\xfe"},
-+  {8, "\xFF\xFF", 3, "\x02\x00\xff"},
-+  {9, "\xFF\xFF", 4, "\x03\x07\xff\x80"},
-+  {10, "\xFF\xFF", 4, "\x03\x06\xff\xc0"},
-+  {11, "\xFF\xFF", 4, "\x03\x05\xff\xe0"},
-+  {12, "\xFF\xFF", 4, "\x03\x04\xff\xf0"},
-+  {13, "\xFF\xFF", 4, "\x03\x03\xff\xf8"},
-+  {14, "\xFF\xFF", 4, "\x03\x02\xff\xfc"},
-+  {15, "\xFF\xFF", 4, "\x03\x01\xff\xfe"},
-+  {16, "\xFF\xFF", 4, "\x03\x00\xff\xff"},
-+  {17, "\xFF\xFF\xFF", 5, "\x04\x07\xff\xff\x80"},
-+  {18, "\xFF\xFF\xFF", 5, "\x04\x06\xff\xff\xc0"},
-+  {19, "\xFF\xFF\xFF", 5, "\x04\x05\xff\xff\xe0"},
-+};
-+
-+void
-+test_simple (void)
-+{
-+  int result;
-+  unsigned char der[100];
-+  unsigned char str[100];
-+  int der_len = sizeof (der);
-+  int str_size = sizeof (str);
-+  int ret_len, bit_len;
-+  grub_size_t i;
-+
-+  /* Dummy test */
-+
-+  asn1_bit_der (NULL, 0, der, &der_len);
-+  result = asn1_get_bit_der (der, 0, &ret_len, str, str_size, &bit_len);
-+  if (result != ASN1_GENERIC_ERROR)
-+    {
-+      grub_fatal ("asn1_get_bit_der zero\n");
-+      return;
-+    }
-+
-+  /* Encode short strings with increasing bit lengths */
-+
-+  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
-+    {
-+      /* Encode */
-+
-+      asn1_bit_der ((const unsigned char *) tv[i].bitstr, tv[i].bitlen,
-+		    der, &der_len);
-+
-+#if 0
-+      {
-+	size_t j;
-+	for (j = 0; j < der_len; j++)
-+	  printf ("\\x%02x", der[j]);
-+	printf ("\n");
-+      }
-+#endif
-+
-+      if (der_len != tv[i].derlen || grub_memcmp (der, tv[i].der, der_len) != 0)
-+	{
-+	  grub_fatal ("asn1_bit_der iter %lu\n", (unsigned long) i);
-+	  return;
-+	}
-+
-+      /* Decode it */
-+
-+      result = asn1_get_bit_der (der, der_len, &ret_len, str,
-+				 str_size, &bit_len);
-+      if (result != ASN1_SUCCESS || ret_len != tv[i].derlen
-+	  || bit_len != tv[i].bitlen)
-+	{
-+	  grub_fatal ("asn1_get_bit_der iter %lu, err: %d\n", (unsigned long) i, result);
-+	  return;
-+	}
-+    }
-+
-+
-+  /* Decode sample from "A Layman's Guide to a Subset of ASN.1, BER,
-+     and DER" section 5.4 "BIT STRING": "The BER encoding of the BIT
-+     STRING value "011011100101110111" can be any of the following,
-+     among others, depending on the choice of padding bits, the form
-+     of length octets [...]".
-+   */
-+
-+  /* 03 04 06 6e 5d c0  DER encoding */
-+
-+  grub_memcpy (der, "\x04\x06\x6e\x5d\xc0", 5);
-+  der_len = 5;
-+
-+  result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
-+  if (result != ASN1_SUCCESS || ret_len != 5
-+      || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0)
-+    {
-+      grub_fatal ("asn1_get_bit_der example\n");
-+      return;
-+    }
-+
-+  der_len = sizeof (der);
-+  asn1_bit_der (str, bit_len, der, &der_len);
-+  if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
-+    {
-+      grub_fatal ("asn1_bit_der example roundtrip\n");
-+      return;
-+    }
-+
-+  /* 03 04 06 6e 5d e0 padded with "100000" */
-+
-+  grub_memcpy (der, "\x04\x06\x6e\x5d\xe0", 5);
-+  der_len = 5;
-+
-+  result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
-+  if (result != ASN1_SUCCESS || ret_len != 5
-+      || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xe0", 3) != 0)
-+    {
-+      grub_fatal ("asn1_get_bit_der example padded\n");
-+      return;
-+    }
-+
-+  der_len = sizeof (der);
-+  asn1_bit_der (str, bit_len, der, &der_len);
-+  if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
-+    {
-+      grub_fatal ("asn1_bit_der example roundtrip\n");
-+      return;
-+    }
-+
-+  /* 03 81 04 06 6e 5d c0 long form of length octets */
-+
-+  grub_memcpy (der, "\x81\x04\x06\x6e\x5d\xc0", 6);
-+  der_len = 6;
-+
-+  result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
-+
-+  if (result != ASN1_SUCCESS || ret_len != 6
-+      || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0)
-+    {
-+      grub_fatal ("asn1_get_bit_der example long form\n");
-+      return;
-+    }
-+
-+  der_len = sizeof (der);
-+  asn1_bit_der (str, bit_len, der, &der_len);
-+  if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
-+    {
-+      grub_fatal ("asn1_bit_der example roundtrip\n");
-+      return;
-+    }
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_strings.c b/grub-core/lib/libtasn1_wrap/tests/Test_strings.c
-new file mode 100644
-index 00000000000..dbe1474b204
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/Test_strings.c
-@@ -0,0 +1,150 @@
-+/*
-+ * Copyright (C) 2012-2014 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * 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 3 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, see <http://www.gnu.org/licenses/>.
-+ *
-+ * Written by Simon Josefsson
-+ *
-+ */
-+
-+#include <grub/mm.h>
-+#include <grub/err.h>
-+#include <grub/misc.h>
-+#include <grub/libtasn1.h>
-+#include "../wrap_tests.h"
-+
-+struct tv
-+{
-+  unsigned int etype;
-+  unsigned int str_len;
-+  const void *str;
-+  unsigned int der_len;
-+  const void *der;
-+};
-+
-+static const struct tv tv[] = {
-+  {ASN1_ETYPE_IA5_STRING, 20,
-+   "\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72",
-+   22,
-+   "\x16\x14\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72"},
-+  {ASN1_ETYPE_PRINTABLE_STRING, 5, "\x4e\x69\x6b\x6f\x73",
-+   7, "\x13\x05\x4e\x69\x6b\x6f\x73"},
-+  {ASN1_ETYPE_UTF8_STRING, 12, "Αττική",
-+   14, "\x0c\x0c\xce\x91\xcf\x84\xcf\x84\xce\xb9\xce\xba\xce\xae"},
-+  {ASN1_ETYPE_TELETEX_STRING, 15,
-+   "\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e",
-+   17,
-+   "\x14\x0f\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e"},
-+  {ASN1_ETYPE_OCTET_STRING, 36,
-+   "\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A",
-+   38,
-+   "\x04\x24\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A"}
-+};
-+
-+#define SSTR(x) sizeof(x)-1,x
-+static const struct tv ber[] = {
-+  {ASN1_ETYPE_OCTET_STRING,
-+   SSTR("\xa0\xa0"),
-+   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x00\x00")},
-+  {ASN1_ETYPE_OCTET_STRING,
-+   SSTR("\xa0\xa0\xb0\xb0\xb0"),
-+   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x00\x00")},
-+  {ASN1_ETYPE_OCTET_STRING,
-+   SSTR("\xa0\xa0\xb0\xb0\xb0\xa1\xa1"),
-+   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x00\x00\x00\x00")},
-+  {ASN1_ETYPE_OCTET_STRING,
-+   SSTR("\xa0\xa0\xb0\xb0\xb0\xa1\xa1\xc1"),
-+   SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x04\x82\x00\x01\xc1\x00\x00\x00\x00")},
-+};
-+
-+void
-+test_strings ()
-+{
-+  int ret;
-+  unsigned char tl[ASN1_MAX_TL_SIZE];
-+  unsigned int tl_len, der_len, str_len;
-+  const unsigned char *str;
-+  unsigned char *b;
-+  unsigned int i;
-+
-+  /* Dummy test */
-+
-+  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
-+    {
-+      /* Encode */
-+      tl_len = sizeof (tl);
-+      ret = asn1_encode_simple_der (tv[i].etype, tv[i].str, tv[i].str_len,
-+				    tl, &tl_len);
-+      if (ret != ASN1_SUCCESS)
-+	{
-+	  grub_fatal ("Encoding error in %u: %s\n", i,
-+		   asn1_strerror (ret));
-+	  return;
-+	}
-+      der_len = tl_len + tv[i].str_len;
-+
-+      if (der_len != tv[i].der_len || grub_memcmp (tl, tv[i].der, tl_len) != 0)
-+	{
-+	  grub_fatal (
-+		   "DER encoding differs in %u! (size: %u, expected: %u)\n",
-+		   i, der_len, tv[i].der_len);
-+	  return;
-+	}
-+
-+      /* decoding */
-+      ret =
-+	asn1_decode_simple_der (tv[i].etype, tv[i].der, tv[i].der_len, &str,
-+				&str_len);
-+      if (ret != ASN1_SUCCESS)
-+	{
-+	  grub_fatal ("Decoding error in %u: %s\n", i,
-+		   asn1_strerror (ret));
-+	  return;
-+	}
-+
-+      if (str_len != tv[i].str_len || grub_memcmp (str, tv[i].str, str_len) != 0)
-+	{
-+	  grub_fatal (
-+		   "DER decoded data differ in %u! (size: %u, expected: %u)\n",
-+		   i, der_len, tv[i].str_len);
-+	  return;
-+	}
-+    }
-+
-+  /* BER decoding */
-+  for (i = 0; i < sizeof (ber) / sizeof (ber[0]); i++)
-+    {
-+      /* decoding */
-+      ret =
-+	asn1_decode_simple_ber (ber[i].etype, ber[i].der, ber[i].der_len, &b,
-+				&str_len, NULL);
-+      if (ret != ASN1_SUCCESS)
-+	{
-+	  grub_fatal ("BER decoding error in %u: %s\n", i,
-+		   asn1_strerror (ret));
-+	  return;
-+	}
-+
-+      if (str_len != ber[i].str_len || grub_memcmp (b, ber[i].str, str_len) != 0)
-+	{
-+	  grub_fatal (
-+		   "BER decoded data differ in %u! (size: %u, expected: %u)\n",
-+		   i, str_len, ber[i].str_len);
-+	  return;
-+	}
-+      grub_free(b);
-+    }
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c b/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c
-new file mode 100644
-index 00000000000..d367bbfb5a7
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c
-@@ -0,0 +1,116 @@
-+/*
-+ * Copyright (C) 2016 Red Hat, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * 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 3 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, see <http://www.gnu.org/licenses/>.
-+ *
-+ */
-+
-+#include <grub/libtasn1.h>
-+#include <grub/types.h>
-+#include <grub/misc.h>
-+#include <grub/err.h>
-+#include "../wrap_tests.h"
-+
-+struct tv
-+{
-+  int der_len;
-+  const unsigned char *der;
-+  const char *oid;
-+  int expected_error;
-+};
-+
-+static const struct tv tv[] = {
-+  {.der_len = 5,
-+   .der = (void *) "\x06\x03\x80\x37\x03",
-+   .oid = "2.999.3",
-+   .expected_error = ASN1_DER_ERROR /* leading 0x80 */
-+  },
-+  {.der_len = 12,
-+   .der = (void *) "\x06\x0a\x2b\x06\x01\x80\x01\x92\x08\x09\x05\x01",
-+   .oid = "1.3.6.1.4.1.2312.9.5.1",
-+   .expected_error = ASN1_DER_ERROR /* leading 0x80 */
-+  },
-+  {.der_len = 6,
-+   .der = (void *) "\x06\x04\x01\x02\x03\x04",
-+   .oid = "0.1.2.3.4",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 5,
-+   .der = (void *) "\x06\x03\x51\x02\x03",
-+   .oid = "2.1.2.3",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 5,
-+   .der = (void *) "\x06\x03\x88\x37\x03",
-+   .oid = "2.999.3",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 12,
-+   .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01",
-+   .oid = "1.3.6.1.4.1.2312.9.5.1",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 19,
-+   .der = (void *) "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d",
-+   .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 19,
-+   .der =
-+   (void *)
-+   "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07",
-+   .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7",
-+   .expected_error = ASN1_SUCCESS},
-+};
-+
-+void
-+test_object_id_decoding (void)
-+{
-+  char str[128];
-+  int ret, ret_len;
-+  grub_size_t i;
-+
-+  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
-+    {
-+      /* decode */
-+      ret =
-+	asn1_get_object_id_der (tv[i].der+1,
-+				tv[i].der_len-1, &ret_len, str,
-+				sizeof (str));
-+      if (ret != tv[i].expected_error)
-+	{
-+	  grub_fatal (
-+		   "%d: asn1_get_object_id_der iter %lu: got '%s' expected %d\n",
-+		   __LINE__, (unsigned long) i, asn1_strerror(ret), tv[i].expected_error);
-+	  return;
-+	}
-+
-+      if (tv[i].expected_error != ASN1_SUCCESS)
-+        continue;
-+
-+      if (ret_len != tv[i].der_len-1)
-+	{
-+	  grub_fatal (
-+		   "%d: iter %lu: error in DER, length returned is %d, had %d\n",
-+		   __LINE__, (unsigned long)i, ret_len, tv[i].der_len-1);
-+	  return;
-+	}
-+
-+      if (grub_strcmp (tv[i].oid, str) != 0)
-+	{
-+	  grub_fatal (
-+		   "%d: strcmp iter %lu: got invalid OID: %s, expected: %s\n",
-+		   __LINE__, (unsigned long) i, str, tv[i].oid);
-+	  return;
-+	}
-+
-+    }
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c b/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c
-new file mode 100644
-index 00000000000..3a83b58c59f
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c
-@@ -0,0 +1,120 @@
-+/*
-+ * Copyright (C) 2019 Nikos Mavrogiannopoulos
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * 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 3 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, see <http://www.gnu.org/licenses/>.
-+ *
-+ */
-+
-+#include <grub/libtasn1.h>
-+#include <grub/types.h>
-+#include <grub/misc.h>
-+#include <grub/err.h>
-+#include "../wrap_tests.h"
-+
-+struct tv
-+{
-+  int der_len;
-+  const unsigned char *der;
-+  const char *oid;
-+  int expected_error;
-+};
-+
-+static const struct tv tv[] = {
-+  {.der_len = 0,
-+   .der = (void *) "",
-+   .oid = "5.999.3",
-+   .expected_error = ASN1_VALUE_NOT_VALID /* cannot start with 5 */
-+  },
-+  {.der_len = 0,
-+   .der = (void *) "",
-+   .oid = "0.48.9",
-+   .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 48 */
-+  },
-+  {.der_len = 0,
-+   .der = (void *) "",
-+   .oid = "1.40.9",
-+   .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 40 */
-+  },
-+  {.der_len = 4,
-+   .der = (void *) "\x06\x02\x4f\x63",
-+   .oid = "1.39.99",
-+   .expected_error = ASN1_SUCCESS,
-+  },
-+  {.der_len = 6,
-+   .der = (void *) "\x06\x04\x01\x02\x03\x04",
-+   .oid = "0.1.2.3.4",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 5,
-+   .der = (void *) "\x06\x03\x51\x02\x03",
-+   .oid = "2.1.2.3",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 5,
-+   .der = (void *) "\x06\x03\x88\x37\x03",
-+   .oid = "2.999.3",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 12,
-+   .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01",
-+   .oid = "1.3.6.1.4.1.2312.9.5.1",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 19,
-+   .der = (void *) "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d",
-+   .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109",
-+   .expected_error = ASN1_SUCCESS},
-+  {.der_len = 19,
-+   .der =
-+   (void *)
-+   "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07",
-+   .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7",
-+   .expected_error = ASN1_SUCCESS},
-+};
-+
-+void
-+test_object_id_encoding(void)
-+{
-+  unsigned char der[128];
-+  int ret, der_len, i;
-+
-+  for (i = 0; i < (int)(sizeof (tv) / sizeof (tv[0])); i++)
-+    {
-+      der_len = sizeof(der);
-+      ret = asn1_object_id_der(tv[i].oid, der, &der_len, 0);
-+      if (ret != ASN1_SUCCESS)
-+	{
-+	  if (ret == tv[i].expected_error)
-+	    continue;
-+	  grub_fatal (
-+		   "%d: iter %lu, encoding of OID failed: %s\n",
-+		   __LINE__, (unsigned long) i, asn1_strerror(ret));
-+	  return;
-+	}
-+      else if (ret != tv[i].expected_error)
-+        {
-+	  grub_fatal (
-+		   "%d: iter %lu, encoding of OID %s succeeded when expecting failure\n",
-+		   __LINE__, (unsigned long) i, tv[i].oid);
-+          return;
-+        }
-+
-+      if (der_len != tv[i].der_len || grub_memcmp(der, tv[i].der, der_len) != 0)
-+	{
-+	  grub_fatal (
-+		   "%d: iter %lu, re-encoding of OID %s resulted to different string (%d vs %d bytes)\n",
-+		   __LINE__, (unsigned long) i, tv[i].oid, der_len, tv[i].der_len);
-+
-+	  return;
-+	}
-+    }
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/octet-string.c b/grub-core/lib/libtasn1_wrap/tests/octet-string.c
-new file mode 100644
-index 00000000000..d8a049e8df0
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/octet-string.c
-@@ -0,0 +1,211 @@
-+/*
-+ * Copyright (C) 2011-2020 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * 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 3 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, see <http://www.gnu.org/licenses/>.
-+ *
-+ * Written by Simon Josefsson and Nikos Mavrogiannopoulos
-+ *
-+ */
-+
-+#include <grub/libtasn1.h>
-+#include <grub/err.h>
-+#include <grub/mm.h>
-+#include <grub/misc.h>
-+#include "../wrap_tests.h"
-+
-+
-+struct tv
-+{
-+  const char *name;
-+  int der_len;
-+  const unsigned char *der_str;
-+  int len;
-+  const unsigned char *string;
-+  int expected_error;
-+  int ber;
-+};
-+
-+static const struct tv tv[] = {
-+  {.name = "primitive octet strings",
-+   .der_len = 10,
-+   .der_str =
-+   (void*)"\x04\x08\x01\x23\x45\x67\x89\xab\xcd\xef",
-+   .len = 8,
-+   .string =
-+   (void*)"\x01\x23\x45\x67\x89\xab\xcd\xef",
-+   .ber = 0},
-+  {.der_len = 22,
-+   .der_str =
-+   (void*)"\x04\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27",
-+   .len = 20,
-+   .string =
-+   (void*)"\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27"},
-+
-+  {.name = "long type of length",
-+   .der_len = 23,
-+   .der_str =
-+   (void*)"\x04\x81\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27",
-+   .len = 20,
-+   .string =
-+   (void*)"\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27",
-+   .ber = 1},
-+  {.der_len = 11,
-+   .der_str =
-+   (void*)"\x04\x81\x08\x01\x23\x45\x67\x89\xab\xcd\xef",
-+   .len = 8,
-+   .string =
-+   (void*)"\x01\x23\x45\x67\x89\xab\xcd\xef",
-+   .ber = 1},
-+
-+  {.name = "constructed - indefinite",
-+   .der_len = 11,
-+   .der_str = (void*)"\x24\x80\x04\x05\x01\x02\x03\x04\x05\x00\x00",
-+   .len = 5,
-+   .string = (void*)"\x01\x02\x03\x04\x05",
-+   .ber = 1,
-+   },
-+
-+  {.name = "constructed - definite - concat",
-+   .der_len = 12,
-+   .der_str = (void*)"\x24\x0a\x04\x04\x0a\x0b\x0c\x0d\x04\x02\x0e\x0f",
-+   .len = 6,
-+   .string = (void*)"\x0a\x0b\x0c\x0d\x0e\x0f",
-+   .ber = 1,
-+   },
-+  {.name = "constructed - definite - recursive",
-+   .der_len = 15,
-+   .der_str = (void*)"\x24\x0d\x04\x04\x0a\x0b\x0c\x0d\x24\x05\x04\x00\x04\x01\x0f",
-+   .len = 5,
-+   .string = (void*)"\x0a\x0b\x0c\x0d\x0f",
-+   .ber = 1,
-+   },
-+  {.name = "constructed - definite - single",
-+   .der_len = 7,
-+   .der_str = (void*)"\x24\x05\x04\x03\x01\x02\x03",
-+   .len = 3,
-+   .string = (void*)"\x01\x02\x03",
-+   .ber = 1,
-+   },
-+
-+  /* a large amount of recursive indefinite encoding */
-+  {.name = "a large amount of recursive indefinite encoding",
-+   .der_len = 29325,
-+   .der_str = (void*)"\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80",
-+   .len = 0,
-+   .ber = 1,
-+   .expected_error = ASN1_DER_ERROR
-+   }
-+};
-+
-+void
-+test_octet_string (void)
-+{
-+  unsigned char str[100];
-+  unsigned char der[100];
-+  int der_len = sizeof (der);
-+  int str_size = sizeof (str);
-+  unsigned char *tmp = NULL;
-+  int ret, ret_len;
-+  grub_size_t i;
-+
-+  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
-+    {
-+      /* Decode */
-+
-+      if (tv[i].ber == 0)
-+	{
-+	  str_size = sizeof (str);
-+	  ret =
-+	    asn1_get_octet_der (tv[i].der_str + 1,
-+				tv[i].der_len - 1, &ret_len, str,
-+				sizeof (str), &str_size);
-+	  if (ret != tv[i].expected_error)
-+	    {
-+	      grub_fatal (
-+		       "%d: asn1_get_octet_der: %s: got %d expected %d\n",
-+		       __LINE__, tv[i].name, ret,
-+		       tv[i].expected_error);
-+	      return;
-+	    }
-+	  if (tv[i].expected_error)
-+	    continue;
-+
-+	  if (ret_len != tv[i].der_len - 1)
-+	    {
-+	      grub_fatal (
-+		       "%d: error in DER, length returned is %d, had %d\n",
-+		       __LINE__, ret_len, tv[i].der_len - 1);
-+	      return;
-+	    }
-+
-+	  if (str_size != tv[i].len
-+	      || grub_memcmp (tv[i].string, str, tv[i].len) != 0)
-+	    {
-+	      grub_fatal (
-+		       "%d: memcmp: %s: got invalid decoding\n",
-+		       __LINE__, tv[i].name);
-+
-+              return;
-+	    }
-+
-+	  /* Encode */
-+	  der_len = sizeof (der);
-+	  asn1_octet_der (str, str_size, der, &der_len);
-+
-+	  if (der_len != tv[i].der_len - 1
-+	      || grub_memcmp (tv[i].der_str + 1, der, tv[i].der_len - 1) != 0)
-+	    {
-+	      grub_fatal (
-+		       "encoding: %s: got invalid encoding\n",
-+		       tv[i].name);
-+	      return;
-+	    }
-+	}
-+
-+      ret =
-+	asn1_decode_simple_ber (ASN1_ETYPE_OCTET_STRING,
-+				tv[i].der_str, tv[i].der_len,
-+				&tmp, (unsigned int*)&str_size, (unsigned int*)&der_len);
-+      if (ret != tv[i].expected_error)
-+	{
-+	  grub_fatal (
-+		   "%d: asn1_decode_simple_ber: %s: got %s expected %s\n",
-+		   __LINE__, tv[i].name, asn1_strerror(ret), asn1_strerror(tv[i].expected_error));
-+	  return;
-+	}
-+      if (tv[i].expected_error)
-+        continue;
-+
-+      if (der_len != tv[i].der_len)
-+	{
-+	  grub_fatal (
-+		   "%d: error: %s: DER, length returned is %d, had %d\n",
-+		   __LINE__, tv[i].name, der_len, tv[i].der_len);
-+	  return;
-+	}
-+
-+      if (str_size != tv[i].len || grub_memcmp (tv[i].string, tmp, tv[i].len) != 0)
-+	{
-+	  grub_fatal (
-+		   "%d: memcmp: %s: got invalid decoding\n",
-+		   __LINE__, tv[i].name);
-+          return;
-+	}
-+      grub_free (tmp);
-+      tmp = NULL;
-+
-+    }
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/reproducers.c b/grub-core/lib/libtasn1_wrap/tests/reproducers.c
-new file mode 100644
-index 00000000000..dc7268d4c6c
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/reproducers.c
-@@ -0,0 +1,81 @@
-+/*
-+ * Copyright (C) 2019 Free Software Foundation, Inc.
-+ *
-+ * This file is part of LIBTASN1.
-+ *
-+ * 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 3 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, see <http://www.gnu.org/licenses/>.
-+ *
-+ */
-+
-+/****************************************************************/
-+/* Description: run reproducers for several fixed issues        */
-+/****************************************************************/
-+
-+#include <grub/libtasn1.h>
-+#include <grub/err.h>
-+#include <grub/mm.h>
-+#include "../wrap_tests.h"
-+
-+#define CONST_DOWN        (1U<<29)
-+
-+/* produces endless loop (fixed by d4b624b2):
-+ * The following translates into a single node with all pointers
-+ * (right,left,down) set to NULL. */
-+const asn1_static_node endless_asn1_tab[] = {
-+  { "TEST_TREE", 536875024, NULL },
-+  { NULL, 0, NULL }
-+};
-+
-+/* produces memory leak (fixed by f16d1ff9):
-+ * 152 bytes in 1 blocks are definitely lost in loss record 1 of 1
-+ *    at 0x4837B65: calloc (vg_replace_malloc.c:762)
-+ *    by 0x4851C0D: _asn1_add_static_node (parser_aux.c:71)
-+ *    by 0x4853AAC: asn1_array2tree (structure.c:200)
-+ *    by 0x10923B: main (single_node.c:67)
-+ */
-+const asn1_static_node tab[] = {
-+{ "a", CONST_DOWN, "" },
-+{ "b", 0, "" },
-+{ "c", 0, "" },
-+{ NULL, 0, NULL }
-+};
-+
-+void
-+test_reproducers (void)
-+{
-+  int result;
-+  asn1_node definitions = NULL;
-+  char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
-+
-+  result = asn1_array2tree (endless_asn1_tab, &definitions, errorDescription);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
-+		  asn1_strerror (result), errorDescription);
-+      return;
-+    }
-+
-+  asn1_delete_structure (&definitions);
-+
-+  definitions = NULL;
-+  result = asn1_array2tree (tab, &definitions, errorDescription);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      grub_fatal ("Error: %s\nErrorDescription = %s\n\n",
-+		  asn1_strerror (result), errorDescription);
-+      return;
-+    }
-+
-+  asn1_delete_structure (&definitions);
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/wrap_tests.c b/grub-core/lib/libtasn1_wrap/wrap_tests.c
-new file mode 100644
-index 00000000000..75fcd21f0d5
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/wrap_tests.c
-@@ -0,0 +1,75 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020 IBM Corporation
-+ *
-+ *  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/mm.h>
-+#include "wrap_tests.h"
-+
-+/*
-+ * libtasn1 tests - from which this is derived - are provided under GPL3+.
-+ */
-+GRUB_MOD_LICENSE ("GPLv3+");
-+
-+static grub_command_t cmd;
-+
-+static grub_err_t
-+grub_cmd_asn1test (grub_command_t cmdd __attribute__((unused)),
-+		   int argc __attribute__((unused)),
-+		   char **args __attribute__((unused)))
-+{
-+  grub_printf ("test_CVE_2018_1000654\n");
-+  test_CVE_2018_1000654 ();
-+
-+  grub_printf ("test_object_id_decoding\n");
-+  test_object_id_decoding ();
-+
-+  grub_printf ("test_object_id_encoding\n");
-+  test_object_id_encoding ();
-+
-+  grub_printf ("test_octet_string\n");
-+  test_octet_string ();
-+
-+  grub_printf ("test_overflow\n");
-+  test_overflow ();
-+
-+  grub_printf ("test_reproducers\n");
-+  test_overflow ();
-+
-+  grub_printf ("test_simple\n");
-+  test_simple ();
-+
-+  grub_printf ("test_strings\n");
-+  test_strings ();
-+
-+  grub_printf ("ASN.1 self-tests passed\n");
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+
-+GRUB_MOD_INIT(test_asn1)
-+{
-+  cmd = grub_register_command ("test_asn1", grub_cmd_asn1test, NULL,
-+			       "Run self-tests for the ASN.1 parser.");
-+}
-+
-+GRUB_MOD_FINI(test_asn1)
-+{
-+  grub_unregister_command (cmd);
-+}
-diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h
-new file mode 100644
-index 00000000000..1e7d3d64f55
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h
-@@ -0,0 +1,32 @@
-+#if HAVE_CONFIG_H
-+# include "config.h"
-+#endif
-+
-+#include <grub/libtasn1.h>
-+
-+const asn1_static_node CVE_2018_1000654_1_asn1_tab[] = {
-+  { "TEST_TREE", 536875024, NULL },
-+  { NULL, 1610612748, NULL },
-+  { "iso", 1073741825, "1"},
-+  { "identified-organization", 1073741825, "3"},
-+  { "dod", 1073741825, "6"},
-+  { "internet", 1073741825, "1"},
-+  { "security", 1073741825, "5"},
-+  { "mechanisms", 1073741825, "5"},
-+  { "pkix", 1073741825, "7"},
-+  { "id-mod", 1073741825, "0"},
-+  { "id-pkix1-implicit-88", 1, "2"},
-+  { "id-xnyTest", 1879048204, NULL },
-+  { NULL, 1073741825, "id-ix"},
-+  { NULL, 1073741825, "29"},
-+  { NULL, 1, "1"},
-+  { "id-ix", 1880096780, "OBJECR"},
-+  { NULL, 1073741825, "id-ix"},
-+  { NULL, 1073741825, "29"},
-+  { NULL, 1, "2"},
-+  { "id-xnyTest", 805306380, NULL },
-+  { NULL, 1073741825, "id-ix"},
-+  { NULL, 1073741825, "29"},
-+  { NULL, 1, "1"},
-+  { NULL, 0, NULL }
-+};
-diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h
-new file mode 100644
-index 00000000000..e2561e5ec6d
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h
-@@ -0,0 +1,36 @@
-+#if HAVE_CONFIG_H
-+# include "config.h"
-+#endif
-+
-+#include <grub/libtasn1.h>
-+
-+const asn1_static_node CVE_2018_1000654_2_asn1_tab[] = {
-+  { "TEST_TREE", 536875024, NULL },
-+  { NULL, 1610612748, NULL },
-+  { "iso", 1073741825, "1"},
-+  { "identified-organization", 1073741825, "3"},
-+  { "dod", 1073741825, "6"},
-+  { "internet", 1073741825, "1"},
-+  { "security", 1073741825, "5"},
-+  { "mechanisms", 1073741825, "5"},
-+  { "pkix", 1073741825, "7"},
-+  { "id-mod", 1073741825, "0"},
-+  { "id-pkix1-implicit-88", 1, "2"},
-+  { "id-oneTest", 1879048204, NULL },
-+  { NULL, 1073741825, "id-two"},
-+  { NULL, 1073741825, "9"},
-+  { NULL, 1, "1"},
-+  { "id-two", 1879048204, NULL },
-+  { NULL, 1073741825, "id-three"},
-+  { NULL, 1073741825, "2"},
-+  { NULL, 1, "2"},
-+  { "id-three", 1879048204, NULL },
-+  { NULL, 1073741825, "id-four"},
-+  { NULL, 1073741825, "3"},
-+  { NULL, 1, "3"},
-+  { "id-four", 805306380, NULL },
-+  { NULL, 1073741825, "id-two"},
-+  { NULL, 1073741825, "3"},
-+  { NULL, 1, "3"},
-+  { NULL, 0, NULL }
-+};
-diff --git a/grub-core/lib/libtasn1_wrap/wrap_tests.h b/grub-core/lib/libtasn1_wrap/wrap_tests.h
-new file mode 100644
-index 00000000000..555e56dd202
---- /dev/null
-+++ b/grub-core/lib/libtasn1_wrap/wrap_tests.h
-@@ -0,0 +1,38 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020 IBM Corporation
-+ *
-+ *  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/>.
-+ */
-+
-+#ifndef LIBTASN1_WRAP_TESTS_H
-+#define LIBTASN1_WRAP_TESTS_H
-+
-+void test_CVE_2018_1000654 (void);
-+
-+void test_object_id_encoding (void);
-+
-+void test_object_id_decoding (void);
-+
-+void test_octet_string (void);
-+
-+void test_overflow (void);
-+
-+void test_reproducers (void);
-+
-+void test_simple (void);
-+
-+void test_strings (void);
-+
-+#endif
-diff --git a/.gitignore b/.gitignore
-index 594d0134d33..856e69bc5c1 100644
---- a/.gitignore
-+++ b/.gitignore
-@@ -264,6 +264,7 @@ widthspec.bin
- /stamp-h1
- /syslinux_test
- /tar_test
-+/test_asn1
- /test_sha512sum
- /test_unset
- /tests/syslinux/ubuntu10.04_grub.cfg
-diff --git a/tests/test_asn1.in b/tests/test_asn1.in
-new file mode 100644
-index 00000000000..8173c5c270e
---- /dev/null
-+++ b/tests/test_asn1.in
-@@ -0,0 +1,12 @@
-+#! @BUILD_SHEBANG@
-+set -e
-+
-+. "@builddir@/grub-core/modinfo.sh"
-+
-+out=`echo test_asn1 | @builddir@/grub-shell`
-+
-+if [ "$(echo "$out" | tail -n 1)" != "ASN.1 self-tests passed" ]; then
-+  echo "ASN.1 test failure: $out"
-+  exit 1
-+fi
-+
diff --git a/SOURCES/0191-grub-install-support-embedding-x509-certificates.patch b/SOURCES/0191-grub-install-support-embedding-x509-certificates.patch
deleted file mode 100644
index bd02e6d..0000000
--- a/SOURCES/0191-grub-install-support-embedding-x509-certificates.patch
+++ /dev/null
@@ -1,252 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Alastair D'Silva <alastair@d-silva.org>
-Date: Mon, 6 Jul 2020 13:33:04 +1000
-Subject: [PATCH] grub-install: support embedding x509 certificates
-
-To support verification of appended signatures, we need a way to
-embed the necessary public keys. Existing appended signature schemes
-in the Linux kernel use X.509 certificates, so allow certificates to
-be embedded in the grub core image in the same way as PGP keys.
-
-Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/commands/pgp.c    |  2 +-
- util/grub-install-common.c  | 22 +++++++++++++++++++++-
- util/grub-mkimage.c         | 15 +++++++++++++--
- util/mkimage.c              | 38 ++++++++++++++++++++++++++++++++++++--
- include/grub/kernel.h       |  4 +++-
- include/grub/util/install.h |  7 +++++--
- 6 files changed, 79 insertions(+), 9 deletions(-)
-
-diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c
-index 355a43844ac..b81ac0ae46c 100644
---- a/grub-core/commands/pgp.c
-+++ b/grub-core/commands/pgp.c
-@@ -944,7 +944,7 @@ GRUB_MOD_INIT(pgp)
-     grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
- 
-     /* Not an ELF module, skip.  */
--    if (header->type != OBJ_TYPE_PUBKEY)
-+    if (header->type != OBJ_TYPE_GPG_PUBKEY)
-       continue;
- 
-     pseudo_file.fs = &pseudo_fs;
-diff --git a/util/grub-install-common.c b/util/grub-install-common.c
-index aab2a941f85..422f82362c7 100644
---- a/util/grub-install-common.c
-+++ b/util/grub-install-common.c
-@@ -460,6 +460,8 @@ static char **pubkeys;
- static size_t npubkeys;
- static char *sbat;
- static int disable_shim_lock;
-+static char **x509keys;
-+static size_t nx509keys;
- static grub_compression_t compression;
- static size_t appsig_size;
- 
-@@ -500,6 +502,11 @@ grub_install_parse (int key, char *arg)
-       return 1;
-     case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK:
-       disable_shim_lock = 1;
-+    case 'x':
-+      x509keys = xrealloc (x509keys,
-+			  sizeof (x509keys[0])
-+			  * (nx509keys + 1));
-+      x509keys[nx509keys++] = xstrdup (arg);
-       return 1;
- 
-     case GRUB_INSTALL_OPTIONS_VERBOSITY:
-@@ -627,6 +634,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
-   for (pk = pubkeys; pk < pubkeys + npubkeys; pk++)
-     slen += 20 + grub_strlen (*pk);
- 
-+  for (pk = x509keys; pk < x509keys + nx509keys; pk++)
-+    slen += 10 + grub_strlen (*pk);
-+
-   for (md = modules.entries; *md; md++)
-     {
-       slen += 10 + grub_strlen (*md);
-@@ -655,6 +665,14 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
-       *p++ = ' ';
-     }
- 
-+  for (pk = x509keys; pk < x509keys + nx509keys; pk++)
-+    {
-+      p = grub_stpcpy (p, "--x509 '");
-+      p = grub_stpcpy (p, *pk);
-+      *p++ = '\'';
-+      *p++ = ' ';
-+    }
-+
-   for (md = modules.entries; *md; md++)
-     {
-       *p++ = '\'';
-@@ -688,7 +706,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
- 
-   grub_install_generate_image (dir, prefix, fp, outname,
- 			       modules.entries, memdisk_path,
--			       pubkeys, npubkeys, config_path, tgt,
-+			       pubkeys, npubkeys,
-+			       x509keys, nx509keys,
-+			       config_path, tgt,
- 			       note, appsig_size, compression, dtb, sbat,
- 			       disable_shim_lock);
-   while (dc--)
-diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
-index 8a53310548b..e1f1112784a 100644
---- a/util/grub-mkimage.c
-+++ b/util/grub-mkimage.c
-@@ -75,7 +75,8 @@ static struct argp_option options[] = {
-    /* TRANSLATORS: "embed" is a verb (command description).  "*/
-   {"config",   'c', N_("FILE"), 0, N_("embed FILE as an early config"), 0},
-    /* TRANSLATORS: "embed" is a verb (command description).  "*/
--  {"pubkey",   'k', N_("FILE"), 0, N_("embed FILE as public key for signature checking"), 0},
-+  {"pubkey",   'k', N_("FILE"), 0, N_("embed FILE as public key for PGP signature checking"), 0},
-+  {"x509",     'x', N_("FILE"), 0, N_("embed FILE as an x509 certificate for appended signature checking"), 0},
-   /* TRANSLATORS: NOTE is a name of segment.  */
-   {"note",   'n', 0, 0, N_("add NOTE segment for CHRP IEEE1275"), 0},
-   {"output",  'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0},
-@@ -124,6 +125,8 @@ struct arguments
-   char *dtb;
-   char **pubkeys;
-   size_t npubkeys;
-+  char **x509keys;
-+  size_t nx509keys;
-   char *font;
-   char *config;
-   char *sbat;
-@@ -206,6 +209,13 @@ argp_parser (int key, char *arg, struct argp_state *state)
-       arguments->pubkeys[arguments->npubkeys++] = xstrdup (arg);
-       break;
- 
-+    case 'x':
-+      arguments->x509keys = xrealloc (arguments->x509keys,
-+				      sizeof (arguments->x509keys[0])
-+				      * (arguments->nx509keys + 1));
-+      arguments->x509keys[arguments->nx509keys++] = xstrdup (arg);
-+      break;
-+
-     case 'c':
-       if (arguments->config)
- 	free (arguments->config);
-@@ -332,7 +342,8 @@ main (int argc, char *argv[])
-   grub_install_generate_image (arguments.dir, arguments.prefix, fp,
- 			       arguments.output, arguments.modules,
- 			       arguments.memdisk, arguments.pubkeys,
--			       arguments.npubkeys, arguments.config,
-+			       arguments.npubkeys, arguments.x509keys,
-+			       arguments.nx509keys, arguments.config,
- 			       arguments.image_target, arguments.note,
- 			       arguments.appsig_size, arguments.comp,
- 			       arguments.dtb, arguments.sbat,
-diff --git a/util/mkimage.c b/util/mkimage.c
-index bab12276010..8319e8dfbde 100644
---- a/util/mkimage.c
-+++ b/util/mkimage.c
-@@ -867,7 +867,8 @@ void
- grub_install_generate_image (const char *dir, const char *prefix,
- 			     FILE *out, const char *outname, char *mods[],
- 			     char *memdisk_path, char **pubkey_paths,
--			     size_t npubkeys, char *config_path,
-+			     size_t npubkeys, char **x509key_paths,
-+			     size_t nx509keys, char *config_path,
- 			     const struct grub_install_image_target_desc *image_target,
- 			     int note, size_t appsig_size, grub_compression_t comp,
- 			     const char *dtb_path, const char *sbat_path,
-@@ -913,6 +914,19 @@ grub_install_generate_image (const char *dir, const char *prefix,
-       }
-   }
- 
-+  {
-+    size_t i;
-+    for (i = 0; i < nx509keys; i++)
-+      {
-+	size_t curs;
-+	curs = ALIGN_ADDR (grub_util_get_image_size (x509key_paths[i]));
-+	grub_util_info ("the size of x509 public key %u is 0x%"
-+			GRUB_HOST_PRIxLONG_LONG,
-+			(unsigned) i, (unsigned long long) curs);
-+	total_module_size += curs + sizeof (struct grub_module_header);
-+      }
-+  }
-+
-   if (memdisk_path)
-     {
-       memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512);
-@@ -1034,7 +1048,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
- 	curs = grub_util_get_image_size (pubkey_paths[i]);
- 
- 	header = (struct grub_module_header *) (kernel_img + offset);
--	header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY);
-+	header->type = grub_host_to_target32 (OBJ_TYPE_GPG_PUBKEY);
- 	header->size = grub_host_to_target32 (curs + sizeof (*header));
- 	offset += sizeof (*header);
- 
-@@ -1043,6 +1057,26 @@ grub_install_generate_image (const char *dir, const char *prefix,
-       }
-   }
- 
-+  {
-+    size_t i;
-+    for (i = 0; i < nx509keys; i++)
-+      {
-+	size_t curs;
-+	struct grub_module_header *header;
-+
-+	curs = grub_util_get_image_size (x509key_paths[i]);
-+
-+	header = (struct grub_module_header *) (kernel_img + offset);
-+	header->type = grub_host_to_target32 (OBJ_TYPE_X509_PUBKEY);
-+	header->size = grub_host_to_target32 (curs + sizeof (*header));
-+	offset += sizeof (*header);
-+
-+	grub_util_load_image (x509key_paths[i], kernel_img + offset);
-+	offset += ALIGN_ADDR (curs);
-+      }
-+  }
-+
-+
-   if (memdisk_path)
-     {
-       struct grub_module_header *header;
-diff --git a/include/grub/kernel.h b/include/grub/kernel.h
-index 55849777eaa..98edc0863f6 100644
---- a/include/grub/kernel.h
-+++ b/include/grub/kernel.h
-@@ -30,7 +30,9 @@ enum
-   OBJ_TYPE_PREFIX,
-   OBJ_TYPE_PUBKEY,
-   OBJ_TYPE_DTB,
--  OBJ_TYPE_DISABLE_SHIM_LOCK
-+  OBJ_TYPE_DISABLE_SHIM_LOCK,
-+  OBJ_TYPE_GPG_PUBKEY,
-+  OBJ_TYPE_X509_PUBKEY,
- };
- 
- /* The module header.  */
-diff --git a/include/grub/util/install.h b/include/grub/util/install.h
-index cf4531e02b6..51f3b13ac13 100644
---- a/include/grub/util/install.h
-+++ b/include/grub/util/install.h
-@@ -67,6 +67,8 @@
-       N_("SBAT metadata"), 0 },						\
-   { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0,	\
-       N_("disable shim_lock verifier"), 0 },				\
-+  { "x509key",   'x', N_("FILE"), 0,					\
-+      N_("embed FILE as an x509 certificate for signature checking"), 0}, \
-   { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\
-     "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \
-     1},                                                                 \
-@@ -188,8 +190,9 @@ void
- grub_install_generate_image (const char *dir, const char *prefix,
- 			     FILE *out,
- 			     const char *outname, char *mods[],
--			     char *memdisk_path, char **pubkey_paths,
--			     size_t npubkeys,
-+			     char *memdisk_path,
-+			     char **pubkey_paths, size_t npubkeys,
-+			     char **x509key_paths, size_t nx509keys,
- 			     char *config_path,
- 			     const struct grub_install_image_target_desc *image_target,
- 			     int note, size_t appsig_size,
diff --git a/SOURCES/0191-grub-mkconfig-restore-umask-for-grub.cfg.patch b/SOURCES/0191-grub-mkconfig-restore-umask-for-grub.cfg.patch
new file mode 100644
index 0000000..76b73f5
--- /dev/null
+++ b/SOURCES/0191-grub-mkconfig-restore-umask-for-grub.cfg.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang via Grub-devel <grub-devel@gnu.org>
+Date: Fri, 3 Dec 2021 16:13:28 +0800
+Subject: [PATCH] grub-mkconfig: restore umask for grub.cfg
+
+Since commit:
+
+  ab2e53c8a grub-mkconfig: Honor a symlink when generating configuration
+by grub-mkconfig
+
+has inadvertently discarded umask for creating grub.cfg in the process
+of grub-mkconfig. The resulting wrong permission (0644) would allow
+unprivileged users to read grub's configuration file content. This
+presents a low confidentiality risk as grub.cfg may contain non-secured
+plain-text passwords.
+
+This patch restores the missing umask and set the file mode of creation
+to 0600 preventing unprivileged access.
+
+Fixes: CVE-2021-3981
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+---
+ util/grub-mkconfig.in | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index f55339a3f6..520a672cd2 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -311,7 +311,9 @@ and /etc/grub.d/* files or please file a bug report with
+     exit 1
+   else
+     # none of the children aborted with error, install the new grub.cfg
++    oldumask=$(umask); umask 077
+     cat ${grub_cfg}.new > ${grub_cfg}
++    umask $oldumask
+     rm -f ${grub_cfg}.new
+   fi
+ fi
diff --git a/SOURCES/0192-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch b/SOURCES/0192-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch
deleted file mode 100644
index 7b7d70c..0000000
--- a/SOURCES/0192-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch
+++ /dev/null
@@ -1,639 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 30 Jul 2020 01:35:10 +1000
-Subject: [PATCH] appended signatures: import GNUTLS's ASN.1 description files
-
-In order to parse PKCS#7 messages and X.509 certificates with libtasn1,
-we need some information about how they are encoded.
-
-We get these from GNUTLS, which has the benefit that they support the
-features we need and are well tested.
-
-The GNUTLS license is LGPLv2.1+, which is GPLv3 compatible, allowing
-us to import it without issue.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/commands/appendedsig/gnutls_asn1_tab.c | 121 ++++++
- grub-core/commands/appendedsig/pkix_asn1_tab.c   | 484 +++++++++++++++++++++++
- 2 files changed, 605 insertions(+)
- create mode 100644 grub-core/commands/appendedsig/gnutls_asn1_tab.c
- create mode 100644 grub-core/commands/appendedsig/pkix_asn1_tab.c
-
-diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
-new file mode 100644
-index 00000000000..ddd1314e63b
---- /dev/null
-+++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
-@@ -0,0 +1,121 @@
-+#include <grub/mm.h>
-+#include <grub/libtasn1.h>
-+
-+const asn1_static_node gnutls_asn1_tab[] = {
-+  { "GNUTLS", 536872976, NULL },
-+  { NULL, 1073741836, NULL },
-+  { "RSAPublicKey", 1610612741, NULL },
-+  { "modulus", 1073741827, NULL },
-+  { "publicExponent", 3, NULL },
-+  { "RSAPrivateKey", 1610612741, NULL },
-+  { "version", 1073741827, NULL },
-+  { "modulus", 1073741827, NULL },
-+  { "publicExponent", 1073741827, NULL },
-+  { "privateExponent", 1073741827, NULL },
-+  { "prime1", 1073741827, NULL },
-+  { "prime2", 1073741827, NULL },
-+  { "exponent1", 1073741827, NULL },
-+  { "exponent2", 1073741827, NULL },
-+  { "coefficient", 1073741827, NULL },
-+  { "otherPrimeInfos", 16386, "OtherPrimeInfos"},
-+  { "ProvableSeed", 1610612741, NULL },
-+  { "algorithm", 1073741836, NULL },
-+  { "seed", 7, NULL },
-+  { "OtherPrimeInfos", 1612709899, NULL },
-+  { "MAX", 1074266122, "1"},
-+  { NULL, 2, "OtherPrimeInfo"},
-+  { "OtherPrimeInfo", 1610612741, NULL },
-+  { "prime", 1073741827, NULL },
-+  { "exponent", 1073741827, NULL },
-+  { "coefficient", 3, NULL },
-+  { "AlgorithmIdentifier", 1610612741, NULL },
-+  { "algorithm", 1073741836, NULL },
-+  { "parameters", 541081613, NULL },
-+  { "algorithm", 1, NULL },
-+  { "DigestInfo", 1610612741, NULL },
-+  { "digestAlgorithm", 1073741826, "DigestAlgorithmIdentifier"},
-+  { "digest", 7, NULL },
-+  { "DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"},
-+  { "DSAPublicKey", 1073741827, NULL },
-+  { "DSAParameters", 1610612741, NULL },
-+  { "p", 1073741827, NULL },
-+  { "q", 1073741827, NULL },
-+  { "g", 3, NULL },
-+  { "DSASignatureValue", 1610612741, NULL },
-+  { "r", 1073741827, NULL },
-+  { "s", 3, NULL },
-+  { "DSAPrivateKey", 1610612741, NULL },
-+  { "version", 1073741827, NULL },
-+  { "p", 1073741827, NULL },
-+  { "q", 1073741827, NULL },
-+  { "g", 1073741827, NULL },
-+  { "Y", 1073741827, NULL },
-+  { "priv", 3, NULL },
-+  { "DHParameter", 1610612741, NULL },
-+  { "prime", 1073741827, NULL },
-+  { "base", 1073741827, NULL },
-+  { "privateValueLength", 16387, NULL },
-+  { "ECParameters", 1610612754, NULL },
-+  { "namedCurve", 12, NULL },
-+  { "ECPrivateKey", 1610612741, NULL },
-+  { "Version", 1073741827, NULL },
-+  { "privateKey", 1073741831, NULL },
-+  { "parameters", 1610637314, "ECParameters"},
-+  { NULL, 2056, "0"},
-+  { "publicKey", 536895494, NULL },
-+  { NULL, 2056, "1"},
-+  { "PrincipalName", 1610612741, NULL },
-+  { "name-type", 1610620931, NULL },
-+  { NULL, 2056, "0"},
-+  { "name-string", 536879115, NULL },
-+  { NULL, 1073743880, "1"},
-+  { NULL, 27, NULL },
-+  { "KRB5PrincipalName", 1610612741, NULL },
-+  { "realm", 1610620955, NULL },
-+  { NULL, 2056, "0"},
-+  { "principalName", 536879106, "PrincipalName"},
-+  { NULL, 2056, "1"},
-+  { "RSAPSSParameters", 1610612741, NULL },
-+  { "hashAlgorithm", 1610637314, "AlgorithmIdentifier"},
-+  { NULL, 2056, "0"},
-+  { "maskGenAlgorithm", 1610637314, "AlgorithmIdentifier"},
-+  { NULL, 2056, "1"},
-+  { "saltLength", 1610653699, NULL },
-+  { NULL, 1073741833, "20"},
-+  { NULL, 2056, "2"},
-+  { "trailerField", 536911875, NULL },
-+  { NULL, 1073741833, "1"},
-+  { NULL, 2056, "3"},
-+  { "GOSTParameters", 1610612741, NULL },
-+  { "publicKeyParamSet", 1073741836, NULL },
-+  { "digestParamSet", 16396, NULL },
-+  { "GOSTParametersOld", 1610612741, NULL },
-+  { "publicKeyParamSet", 1073741836, NULL },
-+  { "digestParamSet", 1073741836, NULL },
-+  { "encryptionParamSet", 16396, NULL },
-+  { "GOSTPrivateKey", 1073741831, NULL },
-+  { "GOSTPrivateKeyOld", 1073741827, NULL },
-+  { "IssuerSignTool", 1610612741, NULL },
-+  { "signTool", 1073741858, NULL },
-+  { "cATool", 1073741858, NULL },
-+  { "signToolCert", 1073741858, NULL },
-+  { "cAToolCert", 34, NULL },
-+  { "Gost28147-89-EncryptedKey", 1610612741, NULL },
-+  { "encryptedKey", 1073741831, NULL },
-+  { "maskKey", 1610637319, NULL },
-+  { NULL, 4104, "0"},
-+  { "macKey", 7, NULL },
-+  { "SubjectPublicKeyInfo", 1610612741, NULL },
-+  { "algorithm", 1073741826, "AlgorithmIdentifier"},
-+  { "subjectPublicKey", 6, NULL },
-+  { "GostR3410-TransportParameters", 1610612741, NULL },
-+  { "encryptionParamSet", 1073741836, NULL },
-+  { "ephemeralPublicKey", 1610637314, "SubjectPublicKeyInfo"},
-+  { NULL, 4104, "0"},
-+  { "ukm", 7, NULL },
-+  { "GostR3410-KeyTransport", 536870917, NULL },
-+  { "sessionEncryptedKey", 1073741826, "Gost28147-89-EncryptedKey"},
-+  { "transportParameters", 536895490, "GostR3410-TransportParameters"},
-+  { NULL, 4104, "0"},
-+  { NULL, 0, NULL }
-+};
-diff --git a/grub-core/commands/appendedsig/pkix_asn1_tab.c b/grub-core/commands/appendedsig/pkix_asn1_tab.c
-new file mode 100644
-index 00000000000..adef69d95ce
---- /dev/null
-+++ b/grub-core/commands/appendedsig/pkix_asn1_tab.c
-@@ -0,0 +1,484 @@
-+#include <grub/mm.h>
-+#include <grub/libtasn1.h>
-+
-+const asn1_static_node pkix_asn1_tab[] = {
-+  { "PKIX1", 536875024, NULL },
-+  { NULL, 1073741836, NULL },
-+  { "PrivateKeyUsagePeriod", 1610612741, NULL },
-+  { "notBefore", 1610637349, NULL },
-+  { NULL, 4104, "0"},
-+  { "notAfter", 536895525, NULL },
-+  { NULL, 4104, "1"},
-+  { "AuthorityKeyIdentifier", 1610612741, NULL },
-+  { "keyIdentifier", 1610637319, NULL },
-+  { NULL, 4104, "0"},
-+  { "authorityCertIssuer", 1610637314, "GeneralNames"},
-+  { NULL, 4104, "1"},
-+  { "authorityCertSerialNumber", 536895490, "CertificateSerialNumber"},
-+  { NULL, 4104, "2"},
-+  { "SubjectKeyIdentifier", 1073741831, NULL },
-+  { "KeyUsage", 1073741830, NULL },
-+  { "DirectoryString", 1610612754, NULL },
-+  { "teletexString", 1612709918, NULL },
-+  { "MAX", 524298, "1"},
-+  { "printableString", 1612709919, NULL },
-+  { "MAX", 524298, "1"},
-+  { "universalString", 1612709920, NULL },
-+  { "MAX", 524298, "1"},
-+  { "utf8String", 1612709922, NULL },
-+  { "MAX", 524298, "1"},
-+  { "bmpString", 1612709921, NULL },
-+  { "MAX", 524298, "1"},
-+  { "ia5String", 538968093, NULL },
-+  { "MAX", 524298, "1"},
-+  { "SubjectAltName", 1073741826, "GeneralNames"},
-+  { "GeneralNames", 1612709899, NULL },
-+  { "MAX", 1074266122, "1"},
-+  { NULL, 2, "GeneralName"},
-+  { "GeneralName", 1610612754, NULL },
-+  { "otherName", 1610620930, "AnotherName"},
-+  { NULL, 4104, "0"},
-+  { "rfc822Name", 1610620957, NULL },
-+  { NULL, 4104, "1"},
-+  { "dNSName", 1610620957, NULL },
-+  { NULL, 4104, "2"},
-+  { "x400Address", 1610620941, NULL },
-+  { NULL, 4104, "3"},
-+  { "directoryName", 1610620939, NULL },
-+  { NULL, 1073743880, "4"},
-+  { NULL, 2, "RelativeDistinguishedName"},
-+  { "ediPartyName", 1610620941, NULL },
-+  { NULL, 4104, "5"},
-+  { "uniformResourceIdentifier", 1610620957, NULL },
-+  { NULL, 4104, "6"},
-+  { "iPAddress", 1610620935, NULL },
-+  { NULL, 4104, "7"},
-+  { "registeredID", 536879116, NULL },
-+  { NULL, 4104, "8"},
-+  { "AnotherName", 1610612741, NULL },
-+  { "type-id", 1073741836, NULL },
-+  { "value", 541073421, NULL },
-+  { NULL, 1073743880, "0"},
-+  { "type-id", 1, NULL },
-+  { "IssuerAltName", 1073741826, "GeneralNames"},
-+  { "BasicConstraints", 1610612741, NULL },
-+  { "cA", 1610645508, NULL },
-+  { NULL, 131081, NULL },
-+  { "pathLenConstraint", 537411587, NULL },
-+  { "0", 10, "MAX"},
-+  { "CRLDistributionPoints", 1612709899, NULL },
-+  { "MAX", 1074266122, "1"},
-+  { NULL, 2, "DistributionPoint"},
-+  { "DistributionPoint", 1610612741, NULL },
-+  { "distributionPoint", 1610637314, "DistributionPointName"},
-+  { NULL, 2056, "0"},
-+  { "reasons", 1610637314, "ReasonFlags"},
-+  { NULL, 4104, "1"},
-+  { "cRLIssuer", 536895490, "GeneralNames"},
-+  { NULL, 4104, "2"},
-+  { "DistributionPointName", 1610612754, NULL },
-+  { "fullName", 1610620930, "GeneralNames"},
-+  { NULL, 4104, "0"},
-+  { "nameRelativeToCRLIssuer", 536879106, "RelativeDistinguishedName"},
-+  { NULL, 4104, "1"},
-+  { "ReasonFlags", 1073741830, NULL },
-+  { "ExtKeyUsageSyntax", 1612709899, NULL },
-+  { "MAX", 1074266122, "1"},
-+  { NULL, 12, NULL },
-+  { "AuthorityInfoAccessSyntax", 1612709899, NULL },
-+  { "MAX", 1074266122, "1"},
-+  { NULL, 2, "AccessDescription"},
-+  { "AccessDescription", 1610612741, NULL },
-+  { "accessMethod", 1073741836, NULL },
-+  { "accessLocation", 2, "GeneralName"},
-+  { "Attribute", 1610612741, NULL },
-+  { "type", 1073741836, NULL },
-+  { "values", 536870927, NULL },
-+  { NULL, 13, NULL },
-+  { "AttributeTypeAndValue", 1610612741, NULL },
-+  { "type", 1073741836, NULL },
-+  { "value", 13, NULL },
-+  { "Name", 1610612754, NULL },
-+  { "rdnSequence", 536870923, NULL },
-+  { NULL, 2, "RelativeDistinguishedName"},
-+  { "DistinguishedName", 1610612747, NULL },
-+  { NULL, 2, "RelativeDistinguishedName"},
-+  { "RelativeDistinguishedName", 1612709903, NULL },
-+  { "MAX", 1074266122, "1"},
-+  { NULL, 2, "AttributeTypeAndValue"},
-+  { "Certificate", 1610612741, NULL },
-+  { "tbsCertificate", 1073741826, "TBSCertificate"},
-+  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
-+  { "signature", 6, NULL },
-+  { "TBSCertificate", 1610612741, NULL },
-+  { "version", 1610653699, NULL },
-+  { NULL, 1073741833, "0"},
-+  { NULL, 2056, "0"},
-+  { "serialNumber", 1073741826, "CertificateSerialNumber"},
-+  { "signature", 1073741826, "AlgorithmIdentifier"},
-+  { "issuer", 1073741826, "Name"},
-+  { "validity", 1073741826, "Validity"},
-+  { "subject", 1073741826, "Name"},
-+  { "subjectPublicKeyInfo", 1073741826, "SubjectPublicKeyInfo"},
-+  { "issuerUniqueID", 1610637314, "UniqueIdentifier"},
-+  { NULL, 4104, "1"},
-+  { "subjectUniqueID", 1610637314, "UniqueIdentifier"},
-+  { NULL, 4104, "2"},
-+  { "extensions", 536895490, "Extensions"},
-+  { NULL, 2056, "3"},
-+  { "CertificateSerialNumber", 1073741827, NULL },
-+  { "Validity", 1610612741, NULL },
-+  { "notBefore", 1073741826, "Time"},
-+  { "notAfter", 2, "Time"},
-+  { "Time", 1610612754, NULL },
-+  { "utcTime", 1073741860, NULL },
-+  { "generalTime", 37, NULL },
-+  { "UniqueIdentifier", 1073741830, NULL },
-+  { "SubjectPublicKeyInfo", 1610612741, NULL },
-+  { "algorithm", 1073741826, "AlgorithmIdentifier"},
-+  { "subjectPublicKey", 6, NULL },
-+  { "Extensions", 1612709899, NULL },
-+  { "MAX", 1074266122, "1"},
-+  { NULL, 2, "Extension"},
-+  { "Extension", 1610612741, NULL },
-+  { "extnID", 1073741836, NULL },
-+  { "critical", 1610645508, NULL },
-+  { NULL, 131081, NULL },
-+  { "extnValue", 7, NULL },
-+  { "CertificateList", 1610612741, NULL },
-+  { "tbsCertList", 1073741826, "TBSCertList"},
-+  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
-+  { "signature", 6, NULL },
-+  { "TBSCertList", 1610612741, NULL },
-+  { "version", 1073758211, NULL },
-+  { "signature", 1073741826, "AlgorithmIdentifier"},
-+  { "issuer", 1073741826, "Name"},
-+  { "thisUpdate", 1073741826, "Time"},
-+  { "nextUpdate", 1073758210, "Time"},
-+  { "revokedCertificates", 1610629131, NULL },
-+  { NULL, 536870917, NULL },
-+  { "userCertificate", 1073741826, "CertificateSerialNumber"},
-+  { "revocationDate", 1073741826, "Time"},
-+  { "crlEntryExtensions", 16386, "Extensions"},
-+  { "crlExtensions", 536895490, "Extensions"},
-+  { NULL, 2056, "0"},
-+  { "AlgorithmIdentifier", 1610612741, NULL },
-+  { "algorithm", 1073741836, NULL },
-+  { "parameters", 541081613, NULL },
-+  { "algorithm", 1, NULL },
-+  { "Dss-Sig-Value", 1610612741, NULL },
-+  { "r", 1073741827, NULL },
-+  { "s", 3, NULL },
-+  { "Dss-Parms", 1610612741, NULL },
-+  { "p", 1073741827, NULL },
-+  { "q", 1073741827, NULL },
-+  { "g", 3, NULL },
-+  { "pkcs-7-ContentInfo", 1610612741, NULL },
-+  { "contentType", 1073741836, NULL },
-+  { "content", 541073421, NULL },
-+  { NULL, 1073743880, "0"},
-+  { "contentType", 1, NULL },
-+  { "pkcs-7-DigestInfo", 1610612741, NULL },
-+  { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"},
-+  { "digest", 7, NULL },
-+  { "pkcs-7-SignedData", 1610612741, NULL },
-+  { "version", 1073741827, NULL },
-+  { "digestAlgorithms", 1073741826, "pkcs-7-DigestAlgorithmIdentifiers"},
-+  { "encapContentInfo", 1073741826, "pkcs-7-EncapsulatedContentInfo"},
-+  { "certificates", 1610637314, "pkcs-7-CertificateSet"},
-+  { NULL, 4104, "0"},
-+  { "crls", 1610637314, "pkcs-7-CertificateRevocationLists"},
-+  { NULL, 4104, "1"},
-+  { "signerInfos", 2, "pkcs-7-SignerInfos"},
-+  { "pkcs-7-DigestAlgorithmIdentifiers", 1610612751, NULL },
-+  { NULL, 2, "AlgorithmIdentifier"},
-+  { "pkcs-7-EncapsulatedContentInfo", 1610612741, NULL },
-+  { "eContentType", 1073741836, NULL },
-+  { "eContent", 536895501, NULL },
-+  { NULL, 2056, "0"},
-+  { "pkcs-7-CertificateRevocationLists", 1610612751, NULL },
-+  { NULL, 13, NULL },
-+  { "pkcs-7-CertificateChoices", 1610612754, NULL },
-+  { "certificate", 13, NULL },
-+  { "pkcs-7-CertificateSet", 1610612751, NULL },
-+  { NULL, 2, "pkcs-7-CertificateChoices"},
-+  { "IssuerAndSerialNumber", 1610612741, NULL },
-+  { "issuer", 1073741826, "Name"},
-+  { "serialNumber", 2, "CertificateSerialNumber"},
-+  { "pkcs-7-SignerInfo", 1610612741, NULL },
-+  { "version", 1073741827, NULL },
-+  { "sid", 1073741826, "SignerIdentifier"},
-+  { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"},
-+  { "signedAttrs", 1610637314, "SignedAttributes"},
-+  { NULL, 4104, "0"},
-+  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
-+  { "signature", 1073741831, NULL },
-+  { "unsignedAttrs", 536895490, "SignedAttributes"},
-+  { NULL, 4104, "1"},
-+  { "SignedAttributes", 1612709903, NULL },
-+  { "MAX", 1074266122, "1"},
-+  { NULL, 2, "Attribute"},
-+  { "SignerIdentifier", 1610612754, NULL },
-+  { "issuerAndSerialNumber", 1073741826, "IssuerAndSerialNumber"},
-+  { "subjectKeyIdentifier", 536879111, NULL },
-+  { NULL, 4104, "0"},
-+  { "pkcs-7-SignerInfos", 1610612751, NULL },
-+  { NULL, 2, "pkcs-7-SignerInfo"},
-+  { "pkcs-10-CertificationRequestInfo", 1610612741, NULL },
-+  { "version", 1073741827, NULL },
-+  { "subject", 1073741826, "Name"},
-+  { "subjectPKInfo", 1073741826, "SubjectPublicKeyInfo"},
-+  { "attributes", 536879106, "Attributes"},
-+  { NULL, 4104, "0"},
-+  { "Attributes", 1610612751, NULL },
-+  { NULL, 2, "Attribute"},
-+  { "pkcs-10-CertificationRequest", 1610612741, NULL },
-+  { "certificationRequestInfo", 1073741826, "pkcs-10-CertificationRequestInfo"},
-+  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
-+  { "signature", 6, NULL },
-+  { "pkcs-9-at-challengePassword", 1879048204, NULL },
-+  { "iso", 1073741825, "1"},
-+  { "member-body", 1073741825, "2"},
-+  { "us", 1073741825, "840"},
-+  { "rsadsi", 1073741825, "113549"},
-+  { "pkcs", 1073741825, "1"},
-+  { NULL, 1073741825, "9"},
-+  { NULL, 1, "7"},
-+  { "pkcs-9-challengePassword", 1610612754, NULL },
-+  { "printableString", 1073741855, NULL },
-+  { "utf8String", 34, NULL },
-+  { "pkcs-9-localKeyId", 1073741831, NULL },
-+  { "pkcs-8-PrivateKeyInfo", 1610612741, NULL },
-+  { "version", 1073741827, NULL },
-+  { "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"},
-+  { "privateKey", 1073741831, NULL },
-+  { "attributes", 536895490, "Attributes"},
-+  { NULL, 4104, "0"},
-+  { "pkcs-8-EncryptedPrivateKeyInfo", 1610612741, NULL },
-+  { "encryptionAlgorithm", 1073741826, "AlgorithmIdentifier"},
-+  { "encryptedData", 2, "pkcs-8-EncryptedData"},
-+  { "pkcs-8-EncryptedData", 1073741831, NULL },
-+  { "pkcs-5-des-CBC-params", 1612709895, NULL },
-+  { NULL, 1048586, "8"},
-+  { "pkcs-5-des-EDE3-CBC-params", 1612709895, NULL },
-+  { NULL, 1048586, "8"},
-+  { "pkcs-5-aes128-CBC-params", 1612709895, NULL },
-+  { NULL, 1048586, "16"},
-+  { "pkcs-5-aes192-CBC-params", 1612709895, NULL },
-+  { NULL, 1048586, "16"},
-+  { "pkcs-5-aes256-CBC-params", 1612709895, NULL },
-+  { NULL, 1048586, "16"},
-+  { "Gost28147-89-Parameters", 1610612741, NULL },
-+  { "iv", 1073741831, NULL },
-+  { "encryptionParamSet", 12, NULL },
-+  { "pkcs-5-PBE-params", 1610612741, NULL },
-+  { "salt", 1073741831, NULL },
-+  { "iterationCount", 3, NULL },
-+  { "pkcs-5-PBES2-params", 1610612741, NULL },
-+  { "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"},
-+  { "encryptionScheme", 2, "AlgorithmIdentifier"},
-+  { "pkcs-5-PBKDF2-params", 1610612741, NULL },
-+  { "salt", 1610612754, NULL },
-+  { "specified", 1073741831, NULL },
-+  { "otherSource", 2, "AlgorithmIdentifier"},
-+  { "iterationCount", 1611137027, NULL },
-+  { "1", 10, "MAX"},
-+  { "keyLength", 1611153411, NULL },
-+  { "1", 10, "MAX"},
-+  { "prf", 16386, "AlgorithmIdentifier"},
-+  { "pkcs-12-PFX", 1610612741, NULL },
-+  { "version", 1610874883, NULL },
-+  { "v3", 1, "3"},
-+  { "authSafe", 1073741826, "pkcs-7-ContentInfo"},
-+  { "macData", 16386, "pkcs-12-MacData"},
-+  { "pkcs-12-PbeParams", 1610612741, NULL },
-+  { "salt", 1073741831, NULL },
-+  { "iterations", 3, NULL },
-+  { "pkcs-12-MacData", 1610612741, NULL },
-+  { "mac", 1073741826, "pkcs-7-DigestInfo"},
-+  { "macSalt", 1073741831, NULL },
-+  { "iterations", 536903683, NULL },
-+  { NULL, 9, "1"},
-+  { "pkcs-12-AuthenticatedSafe", 1610612747, NULL },
-+  { NULL, 2, "pkcs-7-ContentInfo"},
-+  { "pkcs-12-SafeContents", 1610612747, NULL },
-+  { NULL, 2, "pkcs-12-SafeBag"},
-+  { "pkcs-12-SafeBag", 1610612741, NULL },
-+  { "bagId", 1073741836, NULL },
-+  { "bagValue", 1614815245, NULL },
-+  { NULL, 1073743880, "0"},
-+  { "badId", 1, NULL },
-+  { "bagAttributes", 536887311, NULL },
-+  { NULL, 2, "Attribute"},
-+  { "pkcs-12-CertBag", 1610612741, NULL },
-+  { "certId", 1073741836, NULL },
-+  { "certValue", 541073421, NULL },
-+  { NULL, 1073743880, "0"},
-+  { "certId", 1, NULL },
-+  { "pkcs-12-CRLBag", 1610612741, NULL },
-+  { "crlId", 1073741836, NULL },
-+  { "crlValue", 541073421, NULL },
-+  { NULL, 1073743880, "0"},
-+  { "crlId", 1, NULL },
-+  { "pkcs-12-SecretBag", 1610612741, NULL },
-+  { "secretTypeId", 1073741836, NULL },
-+  { "secretValue", 541073421, NULL },
-+  { NULL, 1073743880, "0"},
-+  { "secretTypeId", 1, NULL },
-+  { "pkcs-7-Data", 1073741831, NULL },
-+  { "pkcs-7-EncryptedData", 1610612741, NULL },
-+  { "version", 1073741827, NULL },
-+  { "encryptedContentInfo", 1073741826, "pkcs-7-EncryptedContentInfo"},
-+  { "unprotectedAttrs", 536895490, "pkcs-7-UnprotectedAttributes"},
-+  { NULL, 4104, "1"},
-+  { "pkcs-7-EncryptedContentInfo", 1610612741, NULL },
-+  { "contentType", 1073741836, NULL },
-+  { "contentEncryptionAlgorithm", 1073741826, "pkcs-7-ContentEncryptionAlgorithmIdentifier"},
-+  { "encryptedContent", 536895495, NULL },
-+  { NULL, 4104, "0"},
-+  { "pkcs-7-ContentEncryptionAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"},
-+  { "pkcs-7-UnprotectedAttributes", 1612709903, NULL },
-+  { "MAX", 1074266122, "1"},
-+  { NULL, 2, "Attribute"},
-+  { "ProxyCertInfo", 1610612741, NULL },
-+  { "pCPathLenConstraint", 1611153411, NULL },
-+  { "0", 10, "MAX"},
-+  { "proxyPolicy", 2, "ProxyPolicy"},
-+  { "ProxyPolicy", 1610612741, NULL },
-+  { "policyLanguage", 1073741836, NULL },
-+  { "policy", 16391, NULL },
-+  { "certificatePolicies", 1612709899, NULL },
-+  { "MAX", 1074266122, "1"},
-+  { NULL, 2, "PolicyInformation"},
-+  { "PolicyInformation", 1610612741, NULL },
-+  { "policyIdentifier", 1073741836, NULL },
-+  { "policyQualifiers", 538984459, NULL },
-+  { "MAX", 1074266122, "1"},
-+  { NULL, 2, "PolicyQualifierInfo"},
-+  { "PolicyQualifierInfo", 1610612741, NULL },
-+  { "policyQualifierId", 1073741836, NULL },
-+  { "qualifier", 541065229, NULL },
-+  { "policyQualifierId", 1, NULL },
-+  { "CPSuri", 1073741853, NULL },
-+  { "UserNotice", 1610612741, NULL },
-+  { "noticeRef", 1073758210, "NoticeReference"},
-+  { "explicitText", 16386, "DisplayText"},
-+  { "NoticeReference", 1610612741, NULL },
-+  { "organization", 1073741826, "DisplayText"},
-+  { "noticeNumbers", 536870923, NULL },
-+  { NULL, 3, NULL },
-+  { "DisplayText", 1610612754, NULL },
-+  { "ia5String", 1612709917, NULL },
-+  { "200", 524298, "1"},
-+  { "visibleString", 1612709923, NULL },
-+  { "200", 524298, "1"},
-+  { "bmpString", 1612709921, NULL },
-+  { "200", 524298, "1"},
-+  { "utf8String", 538968098, NULL },
-+  { "200", 524298, "1"},
-+  { "OCSPRequest", 1610612741, NULL },
-+  { "tbsRequest", 1073741826, "TBSRequest"},
-+  { "optionalSignature", 536895490, "Signature"},
-+  { NULL, 2056, "0"},
-+  { "TBSRequest", 1610612741, NULL },
-+  { "version", 1610653699, NULL },
-+  { NULL, 1073741833, "0"},
-+  { NULL, 2056, "0"},
-+  { "requestorName", 1610637314, "GeneralName"},
-+  { NULL, 2056, "1"},
-+  { "requestList", 1610612747, NULL },
-+  { NULL, 2, "Request"},
-+  { "requestExtensions", 536895490, "Extensions"},
-+  { NULL, 2056, "2"},
-+  { "Signature", 1610612741, NULL },
-+  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
-+  { "signature", 1073741830, NULL },
-+  { "certs", 536895499, NULL },
-+  { NULL, 1073743880, "0"},
-+  { NULL, 2, "Certificate"},
-+  { "Request", 1610612741, NULL },
-+  { "reqCert", 1073741826, "CertID"},
-+  { "singleRequestExtensions", 536895490, "Extensions"},
-+  { NULL, 2056, "0"},
-+  { "CertID", 1610612741, NULL },
-+  { "hashAlgorithm", 1073741826, "AlgorithmIdentifier"},
-+  { "issuerNameHash", 1073741831, NULL },
-+  { "issuerKeyHash", 1073741831, NULL },
-+  { "serialNumber", 2, "CertificateSerialNumber"},
-+  { "OCSPResponse", 1610612741, NULL },
-+  { "responseStatus", 1073741826, "OCSPResponseStatus"},
-+  { "responseBytes", 536895490, "ResponseBytes"},
-+  { NULL, 2056, "0"},
-+  { "OCSPResponseStatus", 1610874901, NULL },
-+  { "successful", 1073741825, "0"},
-+  { "malformedRequest", 1073741825, "1"},
-+  { "internalError", 1073741825, "2"},
-+  { "tryLater", 1073741825, "3"},
-+  { "sigRequired", 1073741825, "5"},
-+  { "unauthorized", 1, "6"},
-+  { "ResponseBytes", 1610612741, NULL },
-+  { "responseType", 1073741836, NULL },
-+  { "response", 7, NULL },
-+  { "BasicOCSPResponse", 1610612741, NULL },
-+  { "tbsResponseData", 1073741826, "ResponseData"},
-+  { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
-+  { "signature", 1073741830, NULL },
-+  { "certs", 536895499, NULL },
-+  { NULL, 1073743880, "0"},
-+  { NULL, 2, "Certificate"},
-+  { "ResponseData", 1610612741, NULL },
-+  { "version", 1610653699, NULL },
-+  { NULL, 1073741833, "0"},
-+  { NULL, 2056, "0"},
-+  { "responderID", 1073741826, "ResponderID"},
-+  { "producedAt", 1073741861, NULL },
-+  { "responses", 1610612747, NULL },
-+  { NULL, 2, "SingleResponse"},
-+  { "responseExtensions", 536895490, "Extensions"},
-+  { NULL, 2056, "1"},
-+  { "ResponderID", 1610612754, NULL },
-+  { "byName", 1610620939, NULL },
-+  { NULL, 1073743880, "1"},
-+  { NULL, 2, "RelativeDistinguishedName"},
-+  { "byKey", 536879111, NULL },
-+  { NULL, 2056, "2"},
-+  { "SingleResponse", 1610612741, NULL },
-+  { "certID", 1073741826, "CertID"},
-+  { "certStatus", 1073741826, "CertStatus"},
-+  { "thisUpdate", 1073741861, NULL },
-+  { "nextUpdate", 1610637349, NULL },
-+  { NULL, 2056, "0"},
-+  { "singleExtensions", 536895490, "Extensions"},
-+  { NULL, 2056, "1"},
-+  { "CertStatus", 1610612754, NULL },
-+  { "good", 1610620948, NULL },
-+  { NULL, 4104, "0"},
-+  { "revoked", 1610620930, "RevokedInfo"},
-+  { NULL, 4104, "1"},
-+  { "unknown", 536879106, "UnknownInfo"},
-+  { NULL, 4104, "2"},
-+  { "RevokedInfo", 1610612741, NULL },
-+  { "revocationTime", 1073741861, NULL },
-+  { "revocationReason", 537157653, NULL },
-+  { NULL, 1073743880, "0"},
-+  { "unspecified", 1, "0"},
-+  { "UnknownInfo", 1073741844, NULL },
-+  { "NameConstraints", 1610612741, NULL },
-+  { "permittedSubtrees", 1610637314, "GeneralSubtrees"},
-+  { NULL, 4104, "0"},
-+  { "excludedSubtrees", 536895490, "GeneralSubtrees"},
-+  { NULL, 4104, "1"},
-+  { "GeneralSubtrees", 1612709899, NULL },
-+  { "MAX", 1074266122, "1"},
-+  { NULL, 2, "GeneralSubtree"},
-+  { "GeneralSubtree", 1610612741, NULL },
-+  { "base", 1073741826, "GeneralName"},
-+  { "minimum", 1610653699, NULL },
-+  { NULL, 1073741833, "0"},
-+  { NULL, 4104, "0"},
-+  { "maximum", 536895491, NULL },
-+  { NULL, 4104, "1"},
-+  { "TlsFeatures", 536870923, NULL },
-+  { NULL, 3, NULL },
-+  { NULL, 0, NULL }
-+};
diff --git a/SOURCES/0192-fs-btrfs-Use-full-btrfs-bootloader-area.patch b/SOURCES/0192-fs-btrfs-Use-full-btrfs-bootloader-area.patch
new file mode 100644
index 0000000..3f7198f
--- /dev/null
+++ b/SOURCES/0192-fs-btrfs-Use-full-btrfs-bootloader-area.patch
@@ -0,0 +1,160 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Mon, 13 Dec 2021 14:25:49 +0800
+Subject: [PATCH] fs/btrfs: Use full btrfs bootloader area
+
+Up to now GRUB can only embed to the first 64 KiB before primary
+superblock of btrfs, effectively limiting the GRUB core size. That
+could consequently pose restrictions to feature enablement like
+advanced zstd compression.
+
+This patch attempts to utilize full unused area reserved by btrfs for
+the bootloader outlined in the document [1]:
+
+  The first 1MiB on each device is unused with the exception of primary
+  superblock that is on the offset 64KiB and spans 4KiB.
+
+Apart from that, adjacent sectors to superblock and first block group
+are not used for embedding in case of overflow and logged access to
+adjacent sectors could be useful for tracing it up.
+
+This patch has been tested to provide out of the box support for btrfs
+zstd compression with which GRUB has been installed to the partition.
+
+[1] https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)#BOOTLOADER_SUPPORT
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit b0f06a81c6f31b6fa20be67a96b6683bba8210c9)
+---
+ grub-core/fs/btrfs.c | 90 ++++++++++++++++++++++++++++++++++++++++++++--------
+ include/grub/disk.h  |  2 ++
+ 2 files changed, 79 insertions(+), 13 deletions(-)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index 4cc86e9b79..07c0ff874b 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -2476,6 +2476,33 @@ grub_btrfs_label (grub_device_t device, char **label)
+ }
+ 
+ #ifdef GRUB_UTIL
++
++struct embed_region {
++  unsigned int start;
++  unsigned int secs;
++};
++
++/*
++ * https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)#BOOTLOADER_SUPPORT
++ * The first 1 MiB on each device is unused with the exception of primary
++ * superblock that is on the offset 64 KiB and spans 4 KiB.
++ */
++
++static const struct {
++  struct embed_region available;
++  struct embed_region used[6];
++} btrfs_head = {
++  .available = {0, GRUB_DISK_KiB_TO_SECTORS (1024)}, /* The first 1 MiB. */
++  .used = {
++    {0, 1},                                                        /* boot.S. */
++    {GRUB_DISK_KiB_TO_SECTORS (64) - 1, 1},                        /* Overflow guard. */
++    {GRUB_DISK_KiB_TO_SECTORS (64), GRUB_DISK_KiB_TO_SECTORS (4)}, /* 4 KiB superblock. */
++    {GRUB_DISK_KiB_TO_SECTORS (68), 1},                            /* Overflow guard. */
++    {GRUB_DISK_KiB_TO_SECTORS (1024) - 1, 1},                      /* Overflow guard. */
++    {0, 0}                                                         /* Array terminator. */
++  }
++};
++
+ static grub_err_t
+ grub_btrfs_embed (grub_device_t device __attribute__ ((unused)),
+ 		  unsigned int *nsectors,
+@@ -2483,25 +2510,62 @@ grub_btrfs_embed (grub_device_t device __attribute__ ((unused)),
+ 		  grub_embed_type_t embed_type,
+ 		  grub_disk_addr_t **sectors)
+ {
+-  unsigned i;
++  unsigned int i, j, n = 0;
++  const struct embed_region *u;
++  grub_disk_addr_t *map;
+ 
+   if (embed_type != GRUB_EMBED_PCBIOS)
+     return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ 		       "BtrFS currently supports only PC-BIOS embedding");
+ 
+-  if (64 * 2 - 1 < *nsectors)
+-    return grub_error (GRUB_ERR_OUT_OF_RANGE,
+-		       N_("your core.img is unusually large.  "
+-			  "It won't fit in the embedding area"));
+-
+-  *nsectors = 64 * 2 - 1;
+-  if (*nsectors > max_nsectors)
+-    *nsectors = max_nsectors;
+-  *sectors = grub_calloc (*nsectors, sizeof (**sectors));
+-  if (!*sectors)
++  map = grub_calloc (btrfs_head.available.secs, sizeof (*map));
++  if (map == NULL)
+     return grub_errno;
+-  for (i = 0; i < *nsectors; i++)
+-    (*sectors)[i] = i + 1;
++
++  /*
++   * Populating the map array so that it can be used to index if a disk
++   * address is available to embed:
++   *   - 0: available,
++   *   - 1: unavailable.
++   */
++  for (u = btrfs_head.used; u->secs; ++u)
++    {
++      unsigned int end = u->start + u->secs;
++
++      if (end > btrfs_head.available.secs)
++        end = btrfs_head.available.secs;
++      for (i = u->start; i < end; ++i)
++        map[i] = 1;
++    }
++
++  /* Adding up n until it matches total size of available embedding area. */
++  for (i = 0; i < btrfs_head.available.secs; ++i)
++    if (map[i] == 0)
++      n++;
++
++  if (n < *nsectors)
++    {
++      grub_free (map);
++      return grub_error (GRUB_ERR_OUT_OF_RANGE,
++		         N_("your core.img is unusually large.  "
++			    "It won't fit in the embedding area"));
++    }
++
++  if (n > max_nsectors)
++    n = max_nsectors;
++
++  /*
++   * Populating the array so that it can used to index disk block address for
++   * an image file's offset to be embedded on disk (the unit is in sectors):
++   *   - i: The disk block address relative to btrfs_head.available.start,
++   *   - j: The offset in image file.
++   */
++  for (i = 0, j = 0; i < btrfs_head.available.secs && j < n; ++i)
++    if (map[i] == 0)
++      map[j++] = btrfs_head.available.start + i;
++
++  *nsectors = n;
++  *sectors = map;
+ 
+   return GRUB_ERR_NONE;
+ }
+diff --git a/include/grub/disk.h b/include/grub/disk.h
+index f95aca929a..06210a7049 100644
+--- a/include/grub/disk.h
++++ b/include/grub/disk.h
+@@ -182,6 +182,8 @@ typedef struct grub_disk_memberlist *grub_disk_memberlist_t;
+ /* Return value of grub_disk_native_sectors() in case disk size is unknown. */
+ #define GRUB_DISK_SIZE_UNKNOWN	 0xffffffffffffffffULL
+ 
++#define GRUB_DISK_KiB_TO_SECTORS(x) ((x) << (10 - GRUB_DISK_SECTOR_BITS))
++
+ /* Convert sector number from one sector size to another. */
+ static inline grub_disk_addr_t
+ grub_convert_sector (grub_disk_addr_t sector,
diff --git a/SOURCES/0193-Add-Fedora-location-of-DejaVu-SANS-font.patch b/SOURCES/0193-Add-Fedora-location-of-DejaVu-SANS-font.patch
new file mode 100644
index 0000000..070fc24
--- /dev/null
+++ b/SOURCES/0193-Add-Fedora-location-of-DejaVu-SANS-font.patch
@@ -0,0 +1,30 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: fluteze <fluteze@gmail.com>
+Date: Sat, 27 Nov 2021 10:54:44 -0600
+Subject: [PATCH] Add Fedora location of DejaVu SANS font
+
+In Fedora 35, and possibly earlier, grub would fail to configure with a
+complaint about DejaVu being "not found" even though it was installed.
+The DejaVu sans font search path is updated to reflect the
+distribution's current install path.
+
+Signed-off-by: Erik Edwards <fluteze@gmail.com>
+[rharwood@redhat.com: slight commit message edits]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ configure.ac | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index ab0d326f00..40c4338bce 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1784,7 +1784,7 @@ fi
+ 
+ if test x"$starfield_excuse" = x; then
+    for ext in pcf pcf.gz bdf bdf.gz ttf ttf.gz; do
+-     for dir in . /usr/src /usr/share/fonts/X11/misc /usr/share/fonts/truetype/ttf-dejavu /usr/share/fonts/dejavu /usr/share/fonts/truetype; do
++     for dir in . /usr/src /usr/share/fonts/X11/misc /usr/share/fonts/truetype/ttf-dejavu /usr/share/fonts/dejavu /usr/share/fonts/truetype /usr/share/fonts/dejavu-sans-fonts; do
+         if test -f "$dir/DejaVuSans.$ext"; then
+           DJVU_FONT_SOURCE="$dir/DejaVuSans.$ext"
+           break 2
diff --git a/SOURCES/0193-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch b/SOURCES/0193-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch
deleted file mode 100644
index 04bf1df..0000000
--- a/SOURCES/0193-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch
+++ /dev/null
@@ -1,1528 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 30 Jul 2020 01:33:46 +1000
-Subject: [PATCH] appended signatures: parse PKCS#7 signedData and X.509
- certificates
-
-This code allows us to parse:
-
- - PKCS#7 signedData messages. Only a single signerInfo is supported,
-   which is all that the Linux sign-file utility supports creating
-   out-of-the-box. Only RSA, SHA-256 and SHA-512 are supported.
-   Any certificate embedded in the PKCS#7 message will be ignored.
-
- - X.509 certificates: at least enough to verify the signatures on the
-   PKCS#7 messages. We expect that the certificates embedded in grub will
-   be leaf certificates, not CA certificates. The parser enforces this.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/commands/appendedsig/asn1util.c    | 102 +++
- grub-core/commands/appendedsig/pkcs7.c       | 305 +++++++++
- grub-core/commands/appendedsig/x509.c        | 958 +++++++++++++++++++++++++++
- grub-core/commands/appendedsig/appendedsig.h | 110 +++
- 4 files changed, 1475 insertions(+)
- create mode 100644 grub-core/commands/appendedsig/asn1util.c
- create mode 100644 grub-core/commands/appendedsig/pkcs7.c
- create mode 100644 grub-core/commands/appendedsig/x509.c
- create mode 100644 grub-core/commands/appendedsig/appendedsig.h
-
-diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c
-new file mode 100644
-index 00000000000..eff095a9df2
---- /dev/null
-+++ b/grub-core/commands/appendedsig/asn1util.c
-@@ -0,0 +1,102 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020  IBM Corporation.
-+ *
-+ *  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/libtasn1.h>
-+#include <grub/types.h>
-+#include <grub/err.h>
-+#include <grub/mm.h>
-+#include <grub/crypto.h>
-+#include <grub/gcrypt/gcrypt.h>
-+
-+#include "appendedsig.h"
-+
-+asn1_node _gnutls_gnutls_asn = ASN1_TYPE_EMPTY;
-+asn1_node _gnutls_pkix_asn = ASN1_TYPE_EMPTY;
-+
-+extern const ASN1_ARRAY_TYPE gnutls_asn1_tab[];
-+extern const ASN1_ARRAY_TYPE pkix_asn1_tab[];
-+
-+/*
-+ * Read a value from an ASN1 node, allocating memory to store it.
-+ *
-+ * It will work for anything where the size libtasn1 returns is right:
-+ *  - Integers
-+ *  - Octet strings
-+ *  - DER encoding of other structures
-+ * It will _not_ work for things where libtasn1 size requires adjustment:
-+ *  - Strings that require an extra NULL byte at the end
-+ *  - Bit strings because libtasn1 returns the length in bits, not bytes.
-+ *
-+ * If the function returns a non-NULL value, the caller must free it.
-+ */
-+void *
-+grub_asn1_allocate_and_read (asn1_node node, const char *name,
-+			     const char *friendly_name, int *content_size)
-+{
-+  int result;
-+  grub_uint8_t *tmpstr = NULL;
-+  int tmpstr_size = 0;
-+
-+  result = asn1_read_value (node, name, NULL, &tmpstr_size);
-+  if (result != ASN1_MEM_ERROR)
-+    {
-+      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
-+		     _
-+		     ("Reading size of %s did not return expected status: %s"),
-+		     friendly_name, asn1_strerror (result));
-+      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
-+      return NULL;
-+    }
-+
-+  tmpstr = grub_malloc (tmpstr_size);
-+  if (tmpstr == NULL)
-+    {
-+      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
-+		     "Could not allocate memory to store %s", friendly_name);
-+      grub_errno = GRUB_ERR_OUT_OF_MEMORY;
-+      return NULL;
-+    }
-+
-+  result = asn1_read_value (node, name, tmpstr, &tmpstr_size);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      grub_free (tmpstr);
-+      grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
-+		     "Error reading %s: %s",
-+		     friendly_name, asn1_strerror (result));
-+      grub_errno = GRUB_ERR_BAD_FILE_TYPE;
-+      return NULL;
-+    }
-+
-+  *content_size = tmpstr_size;
-+
-+  return tmpstr;
-+}
-+
-+int
-+asn1_init (void)
-+{
-+  int res;
-+  res = asn1_array2tree (gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL);
-+  if (res != ASN1_SUCCESS)
-+    {
-+      return res;
-+    }
-+  res = asn1_array2tree (pkix_asn1_tab, &_gnutls_pkix_asn, NULL);
-+  return res;
-+}
-diff --git a/grub-core/commands/appendedsig/pkcs7.c b/grub-core/commands/appendedsig/pkcs7.c
-new file mode 100644
-index 00000000000..dc6afe203f7
---- /dev/null
-+++ b/grub-core/commands/appendedsig/pkcs7.c
-@@ -0,0 +1,305 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020  IBM Corporation.
-+ *
-+ *  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 "appendedsig.h"
-+#include <grub/misc.h>
-+#include <grub/crypto.h>
-+#include <grub/gcrypt/gcrypt.h>
-+
-+
-+static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
-+
-+/*
-+ * RFC 5652 s 5.1
-+ */
-+const char *signedData_oid = "1.2.840.113549.1.7.2";
-+
-+/*
-+ * RFC 4055 s 2.1
-+ */
-+const char *sha256_oid = "2.16.840.1.101.3.4.2.1";
-+const char *sha512_oid = "2.16.840.1.101.3.4.2.3";
-+
-+static grub_err_t
-+process_content (grub_uint8_t * content, int size,
-+		 struct pkcs7_signedData *msg)
-+{
-+  int res;
-+  asn1_node signed_part;
-+  grub_err_t err = GRUB_ERR_NONE;
-+  char algo_oid[MAX_OID_LEN];
-+  int algo_oid_size = sizeof (algo_oid);
-+  int algo_count;
-+  char version;
-+  int version_size = sizeof (version);
-+  grub_uint8_t *result_buf;
-+  int result_size = 0;
-+  int crls_size = 0;
-+  gcry_error_t gcry_err;
-+
-+  res = asn1_create_element (_gnutls_pkix_asn, "PKIX1.pkcs-7-SignedData",
-+			     &signed_part);
-+  if (res != ASN1_SUCCESS)
-+    {
-+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+			 "Could not create ASN.1 structure for PKCS#7 signed part.");
-+    }
-+
-+  res = asn1_der_decoding2 (&signed_part, content, &size,
-+			    ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
-+  if (res != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		    "Error reading PKCS#7 signed data: %s", asn1_error);
-+      goto cleanup_signed_part;
-+    }
-+
-+  /* SignedData ::= SEQUENCE {
-+   *     version CMSVersion,
-+   *     digestAlgorithms DigestAlgorithmIdentifiers,
-+   *     encapContentInfo EncapsulatedContentInfo,
-+   *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
-+   *     crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
-+   *     signerInfos SignerInfos }
-+   */
-+
-+  /* version per the algo in 5.1, must be 1 */
-+  res = asn1_read_value (signed_part, "version", &version, &version_size);
-+  if (res != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		    "Error reading signedData version: %s",
-+		    asn1_strerror (res));
-+      goto cleanup_signed_part;
-+    }
-+
-+  if (version != 1)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		    "Unexpected signature version v%d, only v1 supported",
-+		    version);
-+      goto cleanup_signed_part;
-+    }
-+
-+  /*
-+   * digestAlgorithms DigestAlgorithmIdentifiers
-+   *
-+   * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
-+   * DigestAlgorithmIdentifer is an X.509 AlgorithmIdentifier (10.1.1)
-+   * 
-+   * RFC 4055 s 2.1:
-+   * sha256Identifier  AlgorithmIdentifier  ::=  { id-sha256, NULL }
-+   * sha512Identifier  AlgorithmIdentifier  ::=  { id-sha512, NULL }
-+   *
-+   * We only support 1 element in the set, and we do not check parameters atm.
-+   */
-+  res =
-+    asn1_number_of_elements (signed_part, "digestAlgorithms", &algo_count);
-+  if (res != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		    "Error counting number of digest algorithms: %s",
-+		    asn1_strerror (res));
-+      goto cleanup_signed_part;
-+    }
-+
-+  if (algo_count != 1)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
-+		    "Only 1 digest algorithm is supported");
-+      goto cleanup_signed_part;
-+    }
-+
-+  res =
-+    asn1_read_value (signed_part, "digestAlgorithms.?1.algorithm", algo_oid,
-+		     &algo_oid_size);
-+  if (res != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		    "Error reading digest algorithm: %s",
-+		    asn1_strerror (res));
-+      goto cleanup_signed_part;
-+    }
-+
-+  if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
-+    {
-+      msg->hash = grub_crypto_lookup_md_by_name ("sha512");
-+    }
-+  else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
-+    {
-+      msg->hash = grub_crypto_lookup_md_by_name ("sha256");
-+    }
-+  else
-+    {
-+      err =
-+	grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
-+		    "Only SHA-256 and SHA-512 hashes are supported, found OID %s",
-+		    algo_oid);
-+      goto cleanup_signed_part;
-+    }
-+
-+  if (!msg->hash)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		    "Hash algorithm for OID %s not loaded", algo_oid);
-+      goto cleanup_signed_part;
-+    }
-+
-+  /*
-+   * We ignore the certificates, but we don't permit CRLs.
-+   * A CRL entry might be revoking the certificate we're using, and we have
-+   * no way of dealing with that at the moment.
-+   */
-+  res = asn1_read_value (signed_part, "crls", NULL, &crls_size);
-+  if (res != ASN1_ELEMENT_NOT_FOUND)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
-+		    "PKCS#7 messages with embedded CRLs are not supported");
-+      goto cleanup_signed_part;
-+    }
-+
-+  /* read the signature */
-+  result_buf =
-+    grub_asn1_allocate_and_read (signed_part, "signerInfos.?1.signature",
-+				 "signature data", &result_size);
-+  if (!result_buf)
-+    {
-+      err = grub_errno;
-+      goto cleanup_signed_part;
-+    }
-+
-+  gcry_err =
-+    gcry_mpi_scan (&(msg->sig_mpi), GCRYMPI_FMT_USG, result_buf, result_size,
-+		   NULL);
-+  if (gcry_err != GPG_ERR_NO_ERROR)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		    "Error loading signature into MPI structure: %d",
-+		    gcry_err);
-+      goto cleanup_result;
-+    }
-+
-+cleanup_result:
-+  grub_free (result_buf);
-+cleanup_signed_part:
-+  asn1_delete_structure (&signed_part);
-+
-+  return err;
-+}
-+
-+grub_err_t
-+parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size,
-+			struct pkcs7_signedData *msg)
-+{
-+  int res;
-+  asn1_node content_info;
-+  grub_err_t err = GRUB_ERR_NONE;
-+  char content_oid[MAX_OID_LEN];
-+  grub_uint8_t *content;
-+  int content_size;
-+  int content_oid_size = sizeof (content_oid);
-+  int size;
-+
-+  if (data_size > GRUB_INT_MAX)
-+    return grub_error (GRUB_ERR_OUT_OF_RANGE,
-+		       "Cannot parse a PKCS#7 message where data size > INT_MAX");
-+  size = (int) data_size;
-+
-+  res = asn1_create_element (_gnutls_pkix_asn,
-+			     "PKIX1.pkcs-7-ContentInfo", &content_info);
-+  if (res != ASN1_SUCCESS)
-+    {
-+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+			 "Could not create ASN.1 structure for PKCS#7 data: %s",
-+			 asn1_strerror (res));
-+    }
-+
-+  res = asn1_der_decoding2 (&content_info, sigbuf, &size,
-+			    ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
-+  if (res != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		    "Error decoding PKCS#7 message DER: %s", asn1_error);
-+      goto cleanup;
-+    }
-+
-+  /*
-+   * ContentInfo ::= SEQUENCE {
-+   *     contentType ContentType,
-+   *     content [0] EXPLICIT ANY DEFINED BY contentType }
-+   *
-+   * ContentType ::= OBJECT IDENTIFIER
-+   */
-+  res =
-+    asn1_read_value (content_info, "contentType", content_oid,
-+		     &content_oid_size);
-+  if (res != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		    "Error reading PKCS#7 content type: %s",
-+		    asn1_strerror (res));
-+      goto cleanup;
-+    }
-+
-+  /* OID for SignedData defined in 5.1 */
-+  if (grub_strncmp (signedData_oid, content_oid, content_oid_size) != 0)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		    "Unexpected content type in PKCS#7 message: OID %s",
-+		    content_oid);
-+      goto cleanup;
-+    }
-+
-+  content =
-+    grub_asn1_allocate_and_read (content_info, "content",
-+				 "PKCS#7 message content", &content_size);
-+  if (!content)
-+    {
-+      err = grub_errno;
-+      goto cleanup;
-+    }
-+
-+  err = process_content (content, content_size, msg);
-+  grub_free (content);
-+
-+cleanup:
-+  asn1_delete_structure (&content_info);
-+  return err;
-+}
-+
-+/*
-+ * Release all the storage associated with the PKCS#7 message.
-+ * If the caller dynamically allocated the message, it must free it.
-+ */
-+void
-+pkcs7_signedData_release (struct pkcs7_signedData *msg)
-+{
-+  gcry_mpi_release (msg->sig_mpi);
-+}
-diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c
-new file mode 100644
-index 00000000000..2b38b3670a2
---- /dev/null
-+++ b/grub-core/commands/appendedsig/x509.c
-@@ -0,0 +1,958 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020  IBM Corporation.
-+ *
-+ *  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/libtasn1.h>
-+#include <grub/types.h>
-+#include <grub/err.h>
-+#include <grub/mm.h>
-+#include <grub/crypto.h>
-+#include <grub/gcrypt/gcrypt.h>
-+
-+#include "appendedsig.h"
-+
-+static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
-+
-+/*
-+ * RFC 3279 2.3.1  RSA Keys
-+ */
-+const char *rsaEncryption_oid = "1.2.840.113549.1.1.1";
-+
-+/*
-+ * RFC 5280 Appendix A
-+ */
-+const char *commonName_oid = "2.5.4.3";
-+
-+/*
-+ * RFC 5280 4.2.1.3 Key Usage
-+ */
-+const char *keyUsage_oid = "2.5.29.15";
-+
-+/*
-+ * RFC 5280 4.2.1.9 Basic Constraints
-+ */
-+const char *basicConstraints_oid = "2.5.29.19";
-+
-+/*
-+ * RFC 3279 2.3.1
-+ *
-+ *  The RSA public key MUST be encoded using the ASN.1 type RSAPublicKey:
-+ *
-+ *     RSAPublicKey ::= SEQUENCE {
-+ *        modulus            INTEGER,    -- n
-+ *        publicExponent     INTEGER  }  -- e
-+ *
-+ *  where modulus is the modulus n, and publicExponent is the public
-+ *  exponent e.
-+ */
-+static grub_err_t
-+grub_parse_rsa_pubkey (grub_uint8_t * der, int dersize,
-+		       struct x509_certificate *certificate)
-+{
-+  int result;
-+  asn1_node spk = ASN1_TYPE_EMPTY;
-+  grub_uint8_t *m_data, *e_data;
-+  int m_size, e_size;
-+  grub_err_t err = GRUB_ERR_NONE;
-+  gcry_error_t gcry_err;
-+
-+  result =
-+    asn1_create_element (_gnutls_gnutls_asn, "GNUTLS.RSAPublicKey", &spk);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+			 "Cannot create storage for public key ASN.1 data");
-+    }
-+
-+  result = asn1_der_decoding2 (&spk, der, &dersize,
-+			       ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Cannot decode certificate public key DER: %s",
-+		    asn1_error);
-+      goto cleanup;
-+    }
-+
-+  m_data =
-+    grub_asn1_allocate_and_read (spk, "modulus", "RSA modulus", &m_size);
-+  if (!m_data)
-+    {
-+      err = grub_errno;
-+      goto cleanup;
-+    }
-+
-+  e_data =
-+    grub_asn1_allocate_and_read (spk, "publicExponent", "RSA public exponent",
-+				 &e_size);
-+  if (!e_data)
-+    {
-+      err = grub_errno;
-+      goto cleanup_m_data;
-+    }
-+
-+  /*
-+   * convert m, e to mpi
-+   *
-+   * nscanned is not set for FMT_USG, it's only set for FMT_PGP, 
-+   * so we can't verify it
-+   */
-+  gcry_err =
-+    gcry_mpi_scan (&certificate->mpis[0], GCRYMPI_FMT_USG, m_data, m_size,
-+		   NULL);
-+  if (gcry_err != GPG_ERR_NO_ERROR)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Error loading RSA modulus into MPI structure: %d",
-+		    gcry_err);
-+      goto cleanup_e_data;
-+    }
-+
-+  gcry_err =
-+    gcry_mpi_scan (&certificate->mpis[1], GCRYMPI_FMT_USG, e_data, e_size,
-+		   NULL);
-+  if (gcry_err != GPG_ERR_NO_ERROR)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Error loading RSA exponent into MPI structure: %d",
-+		    gcry_err);
-+      goto cleanup_m_mpi;
-+    }
-+
-+  grub_free (e_data);
-+  grub_free (m_data);
-+  asn1_delete_structure (&spk);
-+  return GRUB_ERR_NONE;
-+
-+cleanup_m_mpi:
-+  gcry_mpi_release (certificate->mpis[0]);
-+cleanup_e_data:
-+  grub_free (e_data);
-+cleanup_m_data:
-+  grub_free (m_data);
-+cleanup:
-+  asn1_delete_structure (&spk);
-+  return err;
-+}
-+
-+
-+/*
-+ * RFC 5280:
-+ *   SubjectPublicKeyInfo  ::=  SEQUENCE  {
-+ *       algorithm            AlgorithmIdentifier,
-+ *       subjectPublicKey     BIT STRING  }
-+ *
-+ * AlgorithmIdentifiers come from RFC 3279, we are not strictly compilant as we
-+ * only support RSA Encryption.
-+ */
-+
-+static grub_err_t
-+grub_x509_read_subject_public_key (asn1_node asn,
-+				   struct x509_certificate *results)
-+{
-+  int result;
-+  grub_err_t err;
-+  const char *algo_name =
-+    "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm";
-+  const char *params_name =
-+    "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters";
-+  const char *pk_name =
-+    "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey";
-+  char algo_oid[MAX_OID_LEN];
-+  int algo_size = sizeof (algo_oid);
-+  char params_value[2];
-+  int params_size = sizeof (params_value);
-+  grub_uint8_t *key_data = NULL;
-+  int key_size = 0;
-+  unsigned int key_type;
-+
-+  /* algorithm: see notes for rsaEncryption_oid */
-+  result = asn1_read_value (asn, algo_name, algo_oid, &algo_size);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			 "Error reading x509 public key algorithm: %s",
-+			 asn1_strerror (result));
-+    }
-+
-+  if (grub_strncmp (algo_oid, rsaEncryption_oid, sizeof (rsaEncryption_oid))
-+      != 0)
-+    {
-+      return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
-+			 "Unsupported x509 public key algorithm: %s",
-+			 algo_oid);
-+    }
-+
-+  /* 
-+   * RFC 3279 2.3.1
-+   * The rsaEncryption OID is intended to be used in the algorithm field
-+   * of a value of type AlgorithmIdentifier.  The parameters field MUST
-+   * have ASN.1 type NULL for this algorithm identifier.
-+   */
-+  result = asn1_read_value (asn, params_name, params_value, &params_size);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			 "Error reading x509 public key parameters: %s",
-+			 asn1_strerror (result));
-+    }
-+
-+  if (params_value[0] != ASN1_TAG_NULL)
-+    {
-+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			 "Invalid x509 public key parameters: expected NULL");
-+    }
-+
-+  /*
-+   * RFC 3279 2.3.1:  The DER encoded RSAPublicKey is the value of the BIT
-+   * STRING subjectPublicKey.
-+   */
-+  result = asn1_read_value_type (asn, pk_name, NULL, &key_size, &key_type);
-+  if (result != ASN1_MEM_ERROR)
-+    {
-+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			 "Error reading size of x509 public key: %s",
-+			 asn1_strerror (result));
-+    }
-+  if (key_type != ASN1_ETYPE_BIT_STRING)
-+    {
-+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			 "Unexpected ASN.1 type when reading x509 public key: %x",
-+			 key_type);
-+    }
-+
-+  /* length is in bits */
-+  key_size = (key_size + 7) / 8;
-+
-+  key_data = grub_malloc (key_size);
-+  if (!key_data)
-+    {
-+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+			 "Out of memory for x509 public key");
-+    }
-+
-+  result = asn1_read_value (asn, pk_name, key_data, &key_size);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      grub_free (key_data);
-+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			 "Error reading public key data");
-+    }
-+  key_size = (key_size + 7) / 8;
-+
-+  err = grub_parse_rsa_pubkey (key_data, key_size, results);
-+  grub_free (key_data);
-+
-+  return err;
-+}
-+
-+/* Decode a string as defined in Appendix A */
-+static grub_err_t
-+decode_string (char *der, int der_size, char **string,
-+	       grub_size_t * string_size)
-+{
-+  asn1_node strasn;
-+  int result;
-+  char *choice;
-+  int choice_size = 0;
-+  int tmp_size = 0;
-+  grub_err_t err = GRUB_ERR_NONE;
-+
-+  result =
-+    asn1_create_element (_gnutls_pkix_asn, "PKIX1.DirectoryString", &strasn);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+			 "Could not create ASN.1 structure for certificate: %s",
-+			 asn1_strerror (result));
-+    }
-+
-+  result = asn1_der_decoding2 (&strasn, der, &der_size,
-+			       ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Could not parse DER for DirectoryString: %s",
-+		    asn1_error);
-+      goto cleanup;
-+    }
-+
-+  choice =
-+    grub_asn1_allocate_and_read (strasn, "", "DirectoryString choice",
-+				 &choice_size);
-+  if (!choice)
-+    {
-+      err = grub_errno;
-+      goto cleanup;
-+    }
-+
-+  if (grub_strncmp ("utf8String", choice, choice_size))
-+    {
-+      err =
-+	grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
-+		    "Only UTF-8 DirectoryStrings are supported, got %s",
-+		    choice);
-+      goto cleanup_choice;
-+    }
-+
-+  result = asn1_read_value (strasn, "utf8String", NULL, &tmp_size);
-+  if (result != ASN1_MEM_ERROR)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Error reading size of UTF-8 string: %s",
-+		    asn1_strerror (result));
-+      goto cleanup_choice;
-+    }
-+
-+  /* read size does not include trailing null */
-+  tmp_size++;
-+
-+  *string = grub_malloc (tmp_size);
-+  if (!*string)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+		    "Cannot allocate memory for DirectoryString contents");
-+      goto cleanup_choice;
-+    }
-+
-+  result = asn1_read_value (strasn, "utf8String", *string, &tmp_size);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Error reading out UTF-8 string in DirectoryString: %s",
-+		    asn1_strerror (result));
-+      grub_free (*string);
-+      goto cleanup_choice;
-+    }
-+  *string_size = tmp_size + 1;
-+  (*string)[tmp_size] = '\0';
-+
-+cleanup_choice:
-+  grub_free (choice);
-+cleanup:
-+  asn1_delete_structure (&strasn);
-+  return err;
-+}
-+
-+/*
-+ * TBSCertificate  ::=  SEQUENCE  {
-+ *       version         [0]  EXPLICIT Version DEFAULT v1,
-+ * ...
-+ * 
-+ * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
-+ */
-+static grub_err_t
-+check_version (asn1_node certificate)
-+{
-+  int rc;
-+  const char *name = "tbsCertificate.version";
-+  grub_uint8_t version;
-+  int len = 1;
-+
-+  rc = asn1_read_value (certificate, name, &version, &len);
-+
-+  /* require version 3 */
-+  if (rc != ASN1_SUCCESS || len != 1)
-+    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		       "Error reading certificate version");
-+
-+  if (version != 0x02)
-+    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		       "Invalid x509 certificate version, expected v3 (0x02), got 0x%02x",
-+		       version);
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+/*
-+ * This is an X.501 Name, which is complex.
-+ *
-+ * For simplicity, we extract only the CN.
-+ */
-+static grub_err_t
-+read_name (asn1_node asn, const char *name_path, char **name,
-+	   grub_size_t * name_size)
-+{
-+  int seq_components, set_components;
-+  int result;
-+  int i, j;
-+  char *top_path, *set_path, *type_path, *val_path;
-+  char type[MAX_OID_LEN];
-+  int type_len = sizeof (type);
-+  int string_size = 0;
-+  char *string_der;
-+  grub_err_t err;
-+
-+  *name = NULL;
-+
-+  top_path = grub_xasprintf ("%s.rdnSequence", name_path);
-+  if (!top_path)
-+    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+		       "Could not allocate memory for %s name parsing path",
-+		       name_path);
-+
-+  result = asn1_number_of_elements (asn, top_path, &seq_components);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Error counting name components: %s",
-+		    asn1_strerror (result));
-+      goto cleanup;
-+    }
-+
-+  for (i = 1; i <= seq_components; i++)
-+    {
-+      set_path = grub_xasprintf ("%s.?%d", top_path, i);
-+      if (!set_path)
-+	{
-+	  err =
-+	    grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+			"Could not allocate memory for %s name set parsing path",
-+			name_path);
-+	  goto cleanup_set;
-+	}
-+      /* this brings us, hopefully, to a set */
-+      result = asn1_number_of_elements (asn, set_path, &set_components);
-+      if (result != ASN1_SUCCESS)
-+	{
-+	  err =
-+	    grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			"Error counting name sub-components components (element %d): %s",
-+			i, asn1_strerror (result));
-+	  goto cleanup_set;
-+	}
-+      for (j = 1; j <= set_components; j++)
-+	{
-+	  type_path = grub_xasprintf ("%s.?%d.?%d.type", top_path, i, j);
-+	  if (!type_path)
-+	    {
-+	      err =
-+		grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+			    "Could not allocate memory for %s name component type path",
-+			    name_path);
-+	      goto cleanup_set;
-+	    }
-+	  type_len = sizeof (type);
-+	  result = asn1_read_value (asn, type_path, type, &type_len);
-+	  if (result != ASN1_SUCCESS)
-+	    {
-+	      err =
-+		grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			    "Error reading %s name component type: %s",
-+			    name_path, asn1_strerror (result));
-+	      goto cleanup_type;
-+	    }
-+
-+	  if (grub_strncmp (type, commonName_oid, type_len) != 0)
-+	    {
-+	      grub_free (type_path);
-+	      continue;
-+	    }
-+
-+	  val_path = grub_xasprintf ("%s.?%d.?%d.value", top_path, i, j);
-+	  if (!val_path)
-+	    {
-+	      err =
-+		grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+			    "Could not allocate memory for %s name component value path",
-+			    name_path);
-+	      goto cleanup_set;
-+	    }
-+
-+	  string_der =
-+	    grub_asn1_allocate_and_read (asn, val_path, name_path,
-+					 &string_size);
-+	  if (!string_der)
-+	    {
-+	      err = grub_errno;
-+	      goto cleanup_val_path;
-+	    }
-+
-+	  err = decode_string (string_der, string_size, name, name_size);
-+	  if (err)
-+	    goto cleanup_string;
-+
-+	  grub_free (string_der);
-+	  grub_free (type_path);
-+	  grub_free (val_path);
-+	  break;
-+	}
-+      grub_free (set_path);
-+
-+      if (*name)
-+	break;
-+    }
-+
-+  return GRUB_ERR_NONE;
-+
-+cleanup_string:
-+  grub_free (string_der);
-+cleanup_val_path:
-+  grub_free (val_path);
-+cleanup_type:
-+  grub_free (type_path);
-+cleanup_set:
-+  grub_free (set_path);
-+cleanup:
-+  grub_free (top_path);
-+  return err;
-+}
-+
-+/*
-+ * details here
-+ */
-+static grub_err_t
-+verify_key_usage (grub_uint8_t * value, int value_size)
-+{
-+  asn1_node usageasn;
-+  int result;
-+  grub_err_t err = GRUB_ERR_NONE;
-+  grub_uint8_t usage = 0xff;
-+  int usage_size = 1;
-+
-+  result =
-+    asn1_create_element (_gnutls_pkix_asn, "PKIX1.KeyUsage", &usageasn);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+			 "Could not create ASN.1 structure for key usage");
-+    }
-+
-+  result = asn1_der_decoding2 (&usageasn, value, &value_size,
-+			       ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Error parsing DER for Key Usage: %s", asn1_error);
-+      goto cleanup;
-+    }
-+
-+  result = asn1_read_value (usageasn, "", &usage, &usage_size);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Error reading Key Usage value: %s",
-+		    asn1_strerror (result));
-+      goto cleanup;
-+    }
-+
-+  /* Only the first bit is permitted to be set */
-+  if (usage != 0x80)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected Key Usage value: %x",
-+		    usage);
-+      goto cleanup;
-+    }
-+
-+cleanup:
-+  asn1_delete_structure (&usageasn);
-+  return err;
-+}
-+
-+/*
-+ * BasicConstraints ::= SEQUENCE {
-+ *       cA                      BOOLEAN DEFAULT FALSE,
-+ *       pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
-+ */
-+static grub_err_t
-+verify_basic_constraints (grub_uint8_t * value, int value_size)
-+{
-+  asn1_node basicasn;
-+  int result;
-+  grub_err_t err = GRUB_ERR_NONE;
-+  char cA[6];			/* FALSE or TRUE */
-+  int cA_size = sizeof (cA);
-+
-+  result =
-+    asn1_create_element (_gnutls_pkix_asn, "PKIX1.BasicConstraints",
-+			 &basicasn);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+			 "Could not create ASN.1 structure for Basic Constraints");
-+    }
-+
-+  result = asn1_der_decoding2 (&basicasn, value, &value_size,
-+			       ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Error parsing DER for Basic Constraints: %s",
-+		    asn1_error);
-+      goto cleanup;
-+    }
-+
-+  result = asn1_read_value (basicasn, "cA", cA, &cA_size);
-+  if (result == ASN1_ELEMENT_NOT_FOUND)
-+    {
-+      /* Not present, default is False, so this is OK */
-+      err = GRUB_ERR_NONE;
-+      goto cleanup;
-+    }
-+  else if (result != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Error reading Basic Constraints cA value: %s",
-+		    asn1_strerror (result));
-+      goto cleanup;
-+    }
-+
-+  /* The certificate must not be a CA certificate */
-+  if (grub_strncmp ("FALSE", cA, cA_size) != 0)
-+    {
-+      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected CA value: %s",
-+			cA);
-+      goto cleanup;
-+    }
-+
-+cleanup:
-+  asn1_delete_structure (&basicasn);
-+  return err;
-+}
-+
-+
-+/*
-+ * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
-+ *
-+ * Extension  ::=  SEQUENCE  {
-+ *      extnID      OBJECT IDENTIFIER,
-+ *      critical    BOOLEAN DEFAULT FALSE,
-+ *      extnValue   OCTET STRING
-+ *                  -- contains the DER encoding of an ASN.1 value
-+ *                  -- corresponding to the extension type identified
-+ *                  -- by extnID
-+ * }
-+ *
-+ * We require that a certificate:
-+ *  - contain the Digital Signature usage only
-+ *  - not be a CA
-+ *  - MUST not contain any other critical extensions (RFC 5280 s 4.2)
-+ */
-+static grub_err_t
-+verify_extensions (asn1_node cert)
-+{
-+  int result;
-+  int ext, num_extensions = 0;
-+  int usage_present = 0, constraints_present = 0;
-+  char *oid_path, *critical_path, *value_path;
-+  char extnID[MAX_OID_LEN];
-+  int extnID_size;
-+  grub_err_t err;
-+  char critical[6];		/* we get either "TRUE" or "FALSE" */
-+  int critical_size;
-+  grub_uint8_t *value;
-+  int value_size;
-+
-+  result =
-+    asn1_number_of_elements (cert, "tbsCertificate.extensions",
-+			     &num_extensions);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			 "Error counting number of extensions: %s",
-+			 asn1_strerror (result));
-+    }
-+
-+  if (num_extensions < 2)
-+    {
-+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			 "Insufficient number of extensions for certificate, need at least 2, got %d",
-+			 num_extensions);
-+    }
-+
-+  for (ext = 1; ext <= num_extensions; ext++)
-+    {
-+      oid_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnID", ext);
-+
-+      extnID_size = sizeof (extnID);
-+      result = asn1_read_value (cert, oid_path, extnID, &extnID_size);
-+      if (result != GRUB_ERR_NONE)
-+	{
-+	  err =
-+	    grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			"Error reading extension OID: %s",
-+			asn1_strerror (result));
-+	  goto cleanup_oid_path;
-+	}
-+
-+      critical_path =
-+	grub_xasprintf ("tbsCertificate.extensions.?%d.critical", ext);
-+      critical_size = sizeof (critical);
-+      result =
-+	asn1_read_value (cert, critical_path, critical, &critical_size);
-+      if (result == ASN1_ELEMENT_NOT_FOUND)
-+	{
-+	  critical[0] = '\0';
-+	}
-+      else if (result != ASN1_SUCCESS)
-+	{
-+	  err =
-+	    grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			"Error reading extension criticality: %s",
-+			asn1_strerror (result));
-+	  goto cleanup_critical_path;
-+	}
-+
-+      value_path =
-+	grub_xasprintf ("tbsCertificate.extensions.?%d.extnValue", ext);
-+      value =
-+	grub_asn1_allocate_and_read (cert, value_path,
-+				     "certificate extension value",
-+				     &value_size);
-+      if (!value)
-+	{
-+	  err = grub_errno;
-+	  goto cleanup_value_path;
-+	}
-+
-+      /*
-+       * Now we must see if we recognise the OID.
-+       * If we have an unrecognised critical extension we MUST bail.
-+       */
-+      if (grub_strncmp (keyUsage_oid, extnID, extnID_size) == 0)
-+	{
-+	  err = verify_key_usage (value, value_size);
-+	  if (err != GRUB_ERR_NONE)
-+	    {
-+	      goto cleanup_value;
-+	    }
-+	  usage_present++;
-+	}
-+      else if (grub_strncmp (basicConstraints_oid, extnID, extnID_size) == 0)
-+	{
-+	  err = verify_basic_constraints (value, value_size);
-+	  if (err != GRUB_ERR_NONE)
-+	    {
-+	      goto cleanup_value;
-+	    }
-+	  constraints_present++;
-+	}
-+      else if (grub_strncmp ("TRUE", critical, critical_size) == 0)
-+	{
-+	  /*
-+	   * per the RFC, we must not process a certificate with
-+	   * a critical extension we do not understand.
-+	   */
-+	  err =
-+	    grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			"Unhandled critical x509 extension with OID %s",
-+			extnID);
-+	  goto cleanup_value;
-+	}
-+
-+      grub_free (value);
-+      grub_free (value_path);
-+      grub_free (critical_path);
-+      grub_free (oid_path);
-+    }
-+
-+  if (usage_present != 1)
-+    {
-+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			 "Unexpected number of Key Usage extensions - expected 1, got %d",
-+			 usage_present);
-+    }
-+  if (constraints_present != 1)
-+    {
-+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			 "Unexpected number of basic constraints extensions - expected 1, got %d",
-+			 constraints_present);
-+    }
-+  return GRUB_ERR_NONE;
-+
-+cleanup_value:
-+  grub_free (value);
-+cleanup_value_path:
-+  grub_free (value_path);
-+cleanup_critical_path:
-+  grub_free (critical_path);
-+cleanup_oid_path:
-+  grub_free (oid_path);
-+  return err;
-+}
-+
-+/*
-+ * Parse a certificate whose DER-encoded form is in @data, of size @data_size.
-+ * Return the results in @results, which must point to an allocated x509 certificate.
-+ */
-+grub_err_t
-+certificate_import (void *data, grub_size_t data_size,
-+		    struct x509_certificate *results)
-+{
-+  int result = 0;
-+  asn1_node cert;
-+  grub_err_t err;
-+  int size;
-+  int tmp_size;
-+
-+  if (data_size > GRUB_INT_MAX)
-+    return grub_error (GRUB_ERR_OUT_OF_RANGE,
-+		       "Cannot parse a certificate where data size > INT_MAX");
-+  size = (int) data_size;
-+
-+  result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.Certificate", &cert);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+			 "Could not create ASN.1 structure for certificate: %s",
-+			 asn1_strerror (result));
-+    }
-+
-+  result = asn1_der_decoding2 (&cert, data, &size,
-+			       ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Could not parse DER for certificate: %s", asn1_error);
-+      goto cleanup;
-+    }
-+
-+  /* 
-+   * TBSCertificate  ::=  SEQUENCE {
-+   *     version         [0]  EXPLICIT Version DEFAULT v1
-+   */
-+  err = check_version (cert);
-+  if (err != GRUB_ERR_NONE)
-+    {
-+      goto cleanup;
-+    }
-+
-+  /*
-+   * serialNumber         CertificateSerialNumber,
-+   *
-+   * CertificateSerialNumber  ::=  INTEGER
-+   */
-+  results->serial =
-+    grub_asn1_allocate_and_read (cert, "tbsCertificate.serialNumber",
-+				 "certificate serial number", &tmp_size);
-+  if (!results->serial)
-+    {
-+      err = grub_errno;
-+      goto cleanup;
-+    }
-+  /*
-+   * It's safe to cast the signed int to an unsigned here, we know
-+   * length is non-negative
-+   */
-+  results->serial_len = tmp_size;
-+
-+  /* 
-+   * signature            AlgorithmIdentifier,
-+   *
-+   * We don't load the signature or issuer at the moment,
-+   * as we don't attempt x509 verification.
-+   */
-+
-+  /*
-+   * issuer               Name,
-+   *
-+   * The RFC only requires the serial number to be unique within
-+   * issuers, so to avoid ambiguity we _technically_ ought to make
-+   * this available.
-+   */
-+
-+  /*
-+   * validity             Validity,
-+   *
-+   * Validity ::= SEQUENCE {
-+   *     notBefore      Time,
-+   *     notAfter       Time }
-+   *
-+   * We can't validate this reasonably, we have no true time source on several
-+   * platforms. For now we do not parse them.
-+   */
-+
-+  /*
-+   * subject              Name,
-+   * 
-+   * This is an X501 name, we parse out just the CN.
-+   */
-+  err =
-+    read_name (cert, "tbsCertificate.subject", &results->subject,
-+	       &results->subject_len);
-+  if (err != GRUB_ERR_NONE)
-+    goto cleanup_serial;
-+
-+  /*
-+   * TBSCertificate  ::=  SEQUENCE  {
-+   *    ...
-+   *    subjectPublicKeyInfo SubjectPublicKeyInfo,
-+   *    ...
-+   */
-+  err = grub_x509_read_subject_public_key (cert, results);
-+  if (err != GRUB_ERR_NONE)
-+    goto cleanup_name;
-+
-+  /*
-+   * TBSCertificate  ::=  SEQUENCE  {
-+   *    ...
-+   *    extensions      [3]  EXPLICIT Extensions OPTIONAL
-+   *                         -- If present, version MUST be v3
-+   * }
-+   */
-+
-+  err = verify_extensions (cert);
-+  if (err != GRUB_ERR_NONE)
-+    goto cleanup_name;
-+
-+
-+  /*
-+   * We do not read or check the signature on the certificate:
-+   * as discussed we do not try to validate the certificate but trust
-+   * it implictly.
-+   */
-+
-+  asn1_delete_structure (&cert);
-+  return GRUB_ERR_NONE;
-+
-+
-+cleanup_name:
-+  grub_free (results->subject);
-+cleanup_serial:
-+  grub_free (results->serial);
-+cleanup:
-+  asn1_delete_structure (&cert);
-+  return err;
-+}
-+
-+/*
-+ * Release all the storage associated with the x509 certificate.
-+ * If the caller dynamically allocated the certificate, it must free it.
-+ * The caller is also responsible for maintenance of the linked list.
-+ */
-+void
-+certificate_release (struct x509_certificate *cert)
-+{
-+  grub_free (cert->subject);
-+  grub_free (cert->serial);
-+  gcry_mpi_release (cert->mpis[0]);
-+  gcry_mpi_release (cert->mpis[1]);
-+}
-diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h
-new file mode 100644
-index 00000000000..9792ef3901e
---- /dev/null
-+++ b/grub-core/commands/appendedsig/appendedsig.h
-@@ -0,0 +1,110 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020  IBM Corporation.
-+ *
-+ *  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/crypto.h>
-+#include <grub/libtasn1.h>
-+
-+extern asn1_node _gnutls_gnutls_asn;
-+extern asn1_node _gnutls_pkix_asn;
-+
-+#define MAX_OID_LEN 32
-+
-+/*
-+ * One or more x509 certificates.
-+ *
-+ * We do limited parsing: extracting only the serial, CN and RSA public key.
-+ */
-+struct x509_certificate
-+{
-+  struct x509_certificate *next;
-+
-+  grub_uint8_t *serial;
-+  grub_size_t serial_len;
-+
-+  char *subject;
-+  grub_size_t subject_len;
-+
-+  /* We only support RSA public keys. This encodes [modulus, publicExponent] */
-+  gcry_mpi_t mpis[2];
-+};
-+
-+/*
-+ * A PKCS#7 signedData message.
-+ *
-+ * We make no attempt to match intelligently, so we don't save any info about
-+ * the signer. We also support only 1 signerInfo, so we only store a single
-+ * MPI for the signature.
-+ */
-+struct pkcs7_signedData
-+{
-+  const gcry_md_spec_t *hash;
-+  gcry_mpi_t sig_mpi;
-+};
-+
-+
-+/* Do libtasn1 init */
-+int asn1_init (void);
-+
-+/*
-+ * Import a DER-encoded certificate at 'data', of size 'size'.
-+ *
-+ * Place the results into 'results', which must be already allocated.
-+ */
-+grub_err_t
-+certificate_import (void *data, grub_size_t size,
-+		    struct x509_certificate *results);
-+
-+/*
-+ * Release all the storage associated with the x509 certificate.
-+ * If the caller dynamically allocated the certificate, it must free it.
-+ * The caller is also responsible for maintenance of the linked list.
-+ */
-+void certificate_release (struct x509_certificate *cert);
-+
-+/*
-+ * Parse a PKCS#7 message, which must be a signedData message.
-+ *
-+ * The message must be in 'sigbuf' and of size 'data_size'. The result is
-+ * placed in 'msg', which must already be allocated.
-+ */
-+grub_err_t
-+parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size,
-+			struct pkcs7_signedData *msg);
-+
-+/*
-+ * Release all the storage associated with the PKCS#7 message.
-+ * If the caller dynamically allocated the message, it must free it.
-+ */
-+void pkcs7_signedData_release (struct pkcs7_signedData *msg);
-+
-+/*
-+ * Read a value from an ASN1 node, allocating memory to store it.
-+ *
-+ * It will work for anything where the size libtasn1 returns is right:
-+ *  - Integers
-+ *  - Octet strings
-+ *  - DER encoding of other structures
-+ * It will _not_ work for things where libtasn1 size requires adjustment:
-+ *  - Strings that require an extra NULL byte at the end
-+ *  - Bit strings because libtasn1 returns the length in bits, not bytes.
-+ *
-+ * If the function returns a non-NULL value, the caller must free it.
-+ */
-+void *grub_asn1_allocate_and_read (asn1_node node, const char *name,
-+				   const char *friendly_name,
-+				   int *content_size);
diff --git a/SOURCES/0194-appended-signatures-support-verifying-appended-signa.patch b/SOURCES/0194-appended-signatures-support-verifying-appended-signa.patch
deleted file mode 100644
index 262efc0..0000000
--- a/SOURCES/0194-appended-signatures-support-verifying-appended-signa.patch
+++ /dev/null
@@ -1,716 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 30 Jul 2020 01:35:43 +1000
-Subject: [PATCH] appended signatures: support verifying appended signatures
-
-Building on the parsers and the ability to embed x509 certificates, as
-well as the existing gcrypt functionality, add a module for verifying
-appended signatures.
-
-This includes a verifier that requires that Linux kernels and grub modules
-have appended signatures, and commands to manage the list of trusted
-certificates for verification.
-
-Verification must be enabled by setting check_appended_signatures. If
-GRUB is locked down when the module is loaded, verification will be
-enabled and locked automatically.
-
-As with the PGP verifier, it is not a complete secure-boot solution:
-other mechanisms, such as a password or lockdown, must be used to ensure
-that a user cannot drop to the grub shell and disable verification.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/Makefile.core.def                  |  12 +
- grub-core/commands/appendedsig/appendedsig.c | 645 +++++++++++++++++++++++++++
- include/grub/file.h                          |   2 +
- 3 files changed, 659 insertions(+)
- create mode 100644 grub-core/commands/appendedsig/appendedsig.c
-
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index b4aaccf7b57..77321d218c8 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -980,6 +980,18 @@ module = {
-   cppflags = '-I$(srcdir)/lib/posix_wrap';
- };
- 
-+module = {
-+  name = appendedsig;
-+  common = commands/appendedsig/appendedsig.c;
-+  common = commands/appendedsig/x509.c;
-+  common = commands/appendedsig/pkcs7.c;
-+  common = commands/appendedsig/asn1util.c;
-+  common = commands/appendedsig/gnutls_asn1_tab.c;
-+  common = commands/appendedsig/pkix_asn1_tab.c;
-+  cflags = '$(CFLAGS_POSIX)';
-+  cppflags = '-I$(srcdir)/lib/posix_wrap';
-+};
-+
- module = {
-   name = hdparm;
-   common = commands/hdparm.c;
-diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
-new file mode 100644
-index 00000000000..dc294cd339e
---- /dev/null
-+++ b/grub-core/commands/appendedsig/appendedsig.c
-@@ -0,0 +1,645 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020-2021  IBM Corporation.
-+ *
-+ *  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/file.h>
-+#include <grub/command.h>
-+#include <grub/crypto.h>
-+#include <grub/pkcs1_v15.h>
-+#include <grub/i18n.h>
-+#include <grub/gcrypt/gcrypt.h>
-+#include <grub/kernel.h>
-+#include <grub/extcmd.h>
-+#include <grub/verify.h>
-+#include <grub/libtasn1.h>
-+#include <grub/env.h>
-+#include <grub/lockdown.h>
-+
-+#include "appendedsig.h"
-+
-+GRUB_MOD_LICENSE ("GPLv3+");
-+
-+const char magic[] = "~Module signature appended~\n";
-+
-+/*
-+ * This structure is extracted from scripts/sign-file.c in the linux kernel
-+ * source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible.
-+ */
-+struct module_signature
-+{
-+  grub_uint8_t algo;		/* Public-key crypto algorithm [0] */
-+  grub_uint8_t hash;		/* Digest algorithm [0] */
-+  grub_uint8_t id_type;		/* Key identifier type [PKEY_ID_PKCS7] */
-+  grub_uint8_t signer_len;	/* Length of signer's name [0] */
-+  grub_uint8_t key_id_len;	/* Length of key identifier [0] */
-+  grub_uint8_t __pad[3];
-+  grub_uint32_t sig_len;	/* Length of signature data */
-+} GRUB_PACKED;
-+
-+
-+/* This represents an entire, parsed, appended signature */
-+struct grub_appended_signature
-+{
-+  grub_size_t signature_len;		/* Length of PKCS#7 data +
-+                                         * metadata + magic */
-+
-+  struct module_signature sig_metadata;	/* Module signature metadata */
-+  struct pkcs7_signedData pkcs7;	/* Parsed PKCS#7 data */
-+};
-+
-+/* Trusted certificates for verifying appended signatures */
-+struct x509_certificate *grub_trusted_key;
-+
-+/*
-+ * Force gcry_rsa to be a module dependency.
-+ *
-+ * If we use grub_crypto_pk_rsa, then then the gcry_rsa module won't be built
-+ * in if you add 'appendedsig' to grub-install --modules. You would need to
-+ * add 'gcry_rsa' too. That's confusing and seems suboptimal, especially when
-+ * we only support RSA.
-+ *
-+ * Dynamic loading also causes some concerns. We can't load gcry_rsa from the
-+ * the filesystem after we install the verifier - we won't be able to verify
-+ * it without having it already present. We also shouldn't load it before we
-+ * install the verifier, because that would mean it wouldn't be verified - an
-+ * attacker could insert any code they wanted into the module.
-+ *
-+ * So instead, reference the internal symbol from gcry_rsa. That creates a
-+ * direct dependency on gcry_rsa, so it will be built in when this module
-+ * is built in. Being built in (assuming the core image is itself signed!)
-+ * also resolves our concerns about loading from the filesystem.
-+ */
-+extern gcry_pk_spec_t _gcry_pubkey_spec_rsa;
-+
-+static int check_sigs = 0;
-+
-+static const char *
-+grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)),
-+                   const char *val __attribute__ ((unused)))
-+{
-+  if (check_sigs == 2)
-+    return "forced";
-+  else if (check_sigs == 1)
-+    return "enforce";
-+  else
-+    return "no";
-+}
-+
-+static char *
-+grub_env_write_sec (struct grub_env_var *var __attribute__((unused)),
-+		    const char *val)
-+{
-+  /* Do not allow the value to be changed if set to forced */
-+  if (check_sigs == 2)
-+    return grub_strdup ("forced");
-+
-+  if ((*val == '2') || (*val == 'f'))
-+    check_sigs = 2;
-+  else if ((*val == '1') || (*val == 'e'))
-+    check_sigs = 1;
-+  else if ((*val == '0') || (*val == 'n'))
-+    check_sigs = 0;
-+
-+  return grub_strdup (grub_env_read_sec (NULL, NULL));
-+}
-+
-+static grub_err_t
-+read_cert_from_file (grub_file_t f, struct x509_certificate *certificate)
-+{
-+  grub_err_t err;
-+  grub_uint8_t *buf = NULL;
-+  grub_ssize_t read_size;
-+  grub_off_t total_read_size = 0;
-+  grub_off_t file_size = grub_file_size (f);
-+
-+
-+  if (file_size == GRUB_FILE_SIZE_UNKNOWN)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
-+		       N_("Cannot parse a certificate file of unknown size"));
-+
-+  buf = grub_zalloc (file_size);
-+  if (!buf)
-+    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+		       N_("Could not allocate buffer for certificate file contents"));
-+
-+  while (total_read_size < file_size)
-+    {
-+      read_size =
-+	grub_file_read (f, &buf[total_read_size],
-+			file_size - total_read_size);
-+      if (read_size < 0)
-+	{
-+	  err = grub_error (GRUB_ERR_READ_ERROR,
-+			    N_("Error reading certificate file"));
-+	  goto cleanup_buf;
-+	}
-+      total_read_size += read_size;
-+    }
-+
-+  err = certificate_import (buf, total_read_size, certificate);
-+  if (err != GRUB_ERR_NONE)
-+    goto cleanup_buf;
-+
-+  return GRUB_ERR_NONE;
-+
-+cleanup_buf:
-+  grub_free (buf);
-+  return err;
-+}
-+
-+static grub_err_t
-+extract_appended_signature (grub_uint8_t * buf, grub_size_t bufsize,
-+			    struct grub_appended_signature *sig)
-+{
-+  grub_err_t err;
-+  grub_size_t pkcs7_size;
-+  grub_size_t remaining_len;
-+  grub_uint8_t *appsigdata = buf + bufsize - grub_strlen (magic);
-+
-+  if (bufsize < grub_strlen (magic))
-+    return grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		       N_("File too short for signature magic"));
-+
-+  if (grub_memcmp (appsigdata, (grub_uint8_t *) magic, grub_strlen (magic)))
-+    return grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		       N_("Missing or invalid signature magic"));
-+
-+  remaining_len = bufsize - grub_strlen (magic);
-+
-+  if (remaining_len < sizeof (struct module_signature))
-+    return grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		       N_("File too short for signature metadata"));
-+
-+  appsigdata -= sizeof (struct module_signature);
-+
-+  /* extract the metadata */
-+  grub_memcpy (&(sig->sig_metadata), appsigdata,
-+	       sizeof (struct module_signature));
-+
-+  remaining_len -= sizeof (struct module_signature);
-+
-+  if (sig->sig_metadata.id_type != 2)
-+    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Wrong signature type"));
-+
-+#ifdef GRUB_TARGET_WORDS_BIGENDIAN
-+  pkcs7_size = sig->sig_metadata.sig_len;
-+#else
-+  pkcs7_size = __builtin_bswap32 (sig->sig_metadata.sig_len);
-+#endif
-+
-+  if (pkcs7_size > remaining_len)
-+    return grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		       N_("File too short for PKCS#7 message"));
-+
-+  grub_dprintf ("appendedsig", "sig len %" PRIuGRUB_SIZE "\n", pkcs7_size);
-+
-+  sig->signature_len =
-+    grub_strlen (magic) + sizeof (struct module_signature) + pkcs7_size;
-+
-+  /* rewind pointer and parse pkcs7 data */
-+  appsigdata -= pkcs7_size;
-+
-+  err = parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7);
-+  if (err != GRUB_ERR_NONE)
-+    return err;
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+grub_verify_appended_signature (grub_uint8_t * buf, grub_size_t bufsize)
-+{
-+  grub_err_t err = GRUB_ERR_NONE;
-+  grub_size_t datasize;
-+  void *context;
-+  unsigned char *hash;
-+  gcry_mpi_t hashmpi;
-+  gcry_err_code_t rc;
-+  struct x509_certificate *pk;
-+  struct grub_appended_signature sig;
-+
-+  if (!grub_trusted_key)
-+    return grub_error (GRUB_ERR_BAD_SIGNATURE,
-+		       N_("No trusted keys to verify against"));
-+
-+  err = extract_appended_signature (buf, bufsize, &sig);
-+  if (err != GRUB_ERR_NONE)
-+    return err;
-+
-+  datasize = bufsize - sig.signature_len;
-+
-+  context = grub_zalloc (sig.pkcs7.hash->contextsize);
-+  if (!context)
-+    return grub_errno;
-+
-+  sig.pkcs7.hash->init (context);
-+  sig.pkcs7.hash->write (context, buf, datasize);
-+  sig.pkcs7.hash->final (context);
-+  hash = sig.pkcs7.hash->read (context);
-+  grub_dprintf ("appendedsig",
-+		"data size %" PRIxGRUB_SIZE ", hash %02x%02x%02x%02x...\n",
-+		datasize, hash[0], hash[1], hash[2], hash[3]);
-+
-+  err = GRUB_ERR_BAD_SIGNATURE;
-+  for (pk = grub_trusted_key; pk; pk = pk->next)
-+    {
-+      rc = grub_crypto_rsa_pad (&hashmpi, hash, sig.pkcs7.hash, pk->mpis[0]);
-+      if (rc)
-+	{
-+	  err = grub_error (GRUB_ERR_BAD_SIGNATURE,
-+			    N_("Error padding hash for RSA verification: %d"),
-+			    rc);
-+	  goto cleanup;
-+	}
-+
-+      rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &sig.pkcs7.sig_mpi,
-+					 pk->mpis, NULL, NULL);
-+      gcry_mpi_release (hashmpi);
-+
-+      if (rc == 0)
-+	{
-+	  grub_dprintf ("appendedsig", "verify with key '%s' succeeded\n",
-+			pk->subject);
-+	  err = GRUB_ERR_NONE;
-+	  break;
-+	}
-+
-+      grub_dprintf ("appendedsig", "verify with key '%s' failed with %d\n",
-+		    pk->subject, rc);
-+    }
-+
-+  /* If we didn't verify, provide a neat message */
-+  if (err != GRUB_ERR_NONE)
-+      err = grub_error (GRUB_ERR_BAD_SIGNATURE,
-+			N_("Failed to verify signature against a trusted key"));
-+
-+cleanup:
-+  grub_free (context);
-+  pkcs7_signedData_release (&sig.pkcs7);
-+
-+  return err;
-+}
-+
-+static grub_err_t
-+grub_cmd_verify_signature (grub_command_t cmd __attribute__((unused)),
-+			   int argc, char **args)
-+{
-+  grub_file_t f;
-+  grub_err_t err = GRUB_ERR_NONE;
-+  grub_uint8_t *data;
-+  grub_ssize_t read_size;
-+  grub_off_t file_size, total_read_size = 0;
-+
-+  if (argc < 1)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
-+
-+  grub_dprintf ("appendedsig", "verifying %s\n", args[0]);
-+
-+  f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
-+  if (!f)
-+    {
-+      err = grub_errno;
-+      goto cleanup;
-+    }
-+
-+  file_size = grub_file_size (f);
-+  if (file_size == GRUB_FILE_SIZE_UNKNOWN)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
-+		       N_("Cannot verify the signature of a file of unknown size"));
-+
-+  data = grub_malloc (file_size);
-+  if (!data)
-+    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+		       N_("Could not allocate data buffer size "
-+		       PRIuGRUB_UINT64_T " for verification"), file_size);
-+
-+  while (total_read_size < file_size)
-+    {
-+      read_size =
-+	grub_file_read (f, &data[total_read_size],
-+			file_size - total_read_size);
-+      if (read_size < 0)
-+	{
-+	  err = grub_error (GRUB_ERR_READ_ERROR,
-+			    N_("Error reading file to verify"));
-+	  goto cleanup_data;
-+	}
-+      total_read_size += read_size;
-+    }
-+
-+  err = grub_verify_appended_signature (data, file_size);
-+
-+cleanup_data:
-+  grub_free (data);
-+cleanup:
-+  if (f)
-+    grub_file_close (f);
-+  return err;
-+}
-+
-+static grub_err_t
-+grub_cmd_distrust (grub_command_t cmd __attribute__((unused)),
-+		   int argc, char **args)
-+{
-+  unsigned long cert_num, i;
-+  struct x509_certificate *cert, *prev;
-+
-+  if (argc != 1)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("One argument expected"));
-+
-+  grub_errno = GRUB_ERR_NONE;
-+  cert_num = grub_strtoul (args[0], NULL, 10);
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
-+
-+  if (cert_num < 1)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
-+		       N_("Certificate number too small - numbers start at 1"));
-+
-+  if (cert_num == 1)
-+    {
-+      cert = grub_trusted_key;
-+      grub_trusted_key = cert->next;
-+
-+      certificate_release (cert);
-+      grub_free (cert);
-+      return GRUB_ERR_NONE;
-+    }
-+  i = 2;
-+  prev = grub_trusted_key;
-+  cert = grub_trusted_key->next;
-+  while (cert)
-+    {
-+      if (i == cert_num)
-+	{
-+	  prev->next = cert->next;
-+	  certificate_release (cert);
-+	  grub_free (cert);
-+	  return GRUB_ERR_NONE;
-+	}
-+      i++;
-+      prev = cert;
-+      cert = cert->next;
-+    }
-+
-+  return grub_error (GRUB_ERR_BAD_ARGUMENT,
-+		     N_("No certificate number %d found - only %d certificates in the store"),
-+		     cert_num, i - 1);
-+}
-+
-+static grub_err_t
-+grub_cmd_trust (grub_command_t cmd __attribute__((unused)),
-+		int argc, char **args)
-+{
-+  grub_file_t certf;
-+  struct x509_certificate *cert = NULL;
-+  grub_err_t err;
-+
-+  if (argc != 1)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
-+
-+  certf = grub_file_open (args[0],
-+			  GRUB_FILE_TYPE_CERTIFICATE_TRUST
-+			  | GRUB_FILE_TYPE_NO_DECOMPRESS);
-+  if (!certf)
-+    return grub_errno;
-+
-+
-+  cert = grub_zalloc (sizeof (struct x509_certificate));
-+  if (!cert)
-+    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+		       N_("Could not allocate memory for certificate"));
-+
-+  err = read_cert_from_file (certf, cert);
-+  grub_file_close (certf);
-+  if (err != GRUB_ERR_NONE)
-+    {
-+      grub_free (cert);
-+      return err;
-+    }
-+  grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n",
-+		cert->subject);
-+
-+  cert->next = grub_trusted_key;
-+  grub_trusted_key = cert;
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+grub_cmd_list (grub_command_t cmd __attribute__((unused)),
-+	       int argc __attribute__((unused)),
-+	       char **args __attribute__((unused)))
-+{
-+  struct x509_certificate *cert;
-+  int cert_num = 1;
-+  grub_size_t i;
-+
-+  for (cert = grub_trusted_key; cert; cert = cert->next)
-+    {
-+      grub_printf (N_("Certificate %d:\n"), cert_num);
-+
-+      grub_printf (N_("\tSerial: "));
-+      for (i = 0; i < cert->serial_len - 1; i++)
-+	{
-+	  grub_printf ("%02x:", cert->serial[i]);
-+	}
-+      grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]);
-+
-+      grub_printf ("\tCN: %s\n\n", cert->subject);
-+      cert_num++;
-+
-+    }
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+appendedsig_init (grub_file_t io __attribute__((unused)),
-+		  enum grub_file_type type,
-+		  void **context __attribute__((unused)),
-+		  enum grub_verify_flags *flags)
-+{
-+  if (!check_sigs)
-+    {
-+      *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
-+      return GRUB_ERR_NONE;
-+    }
-+
-+  switch (type & GRUB_FILE_TYPE_MASK)
-+    {
-+    case GRUB_FILE_TYPE_CERTIFICATE_TRUST:
-+      /*
-+       * This is a certificate to add to trusted keychain.
-+       *
-+       * This needs to be verified or blocked. Ideally we'd write an x509
-+       * verifier, but we lack the hubris required to take this on. Instead,
-+       * require that it have an appended signature.
-+       */
-+
-+      /* Fall through */
-+
-+    case GRUB_FILE_TYPE_LINUX_KERNEL:
-+    case GRUB_FILE_TYPE_GRUB_MODULE:
-+      /*
-+       * Appended signatures are only defined for ELF binaries.
-+       * Out of an abundance of caution, we only verify Linux kernels and
-+       * GRUB modules at this point.
-+       */
-+      *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
-+      return GRUB_ERR_NONE;
-+
-+    case GRUB_FILE_TYPE_ACPI_TABLE:
-+    case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE:
-+      /*
-+       * It is possible to use appended signature verification without
-+       * lockdown - like the PGP verifier. When combined with an embedded
-+       * config file in a signed grub binary, this could still be a meaningful
-+       * secure-boot chain - so long as it isn't subverted by something like a
-+       * rouge ACPI table or DT image. Defer them explicitly.
-+       */
-+      *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH;
-+      return GRUB_ERR_NONE;
-+
-+    default:
-+      *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
-+      return GRUB_ERR_NONE;
-+    }
-+}
-+
-+static grub_err_t
-+appendedsig_write (void *ctxt __attribute__((unused)),
-+		   void *buf, grub_size_t size)
-+{
-+  return grub_verify_appended_signature (buf, size);
-+}
-+
-+struct grub_file_verifier grub_appendedsig_verifier = {
-+  .name = "appendedsig",
-+  .init = appendedsig_init,
-+  .write = appendedsig_write,
-+};
-+
-+static grub_ssize_t
-+pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
-+{
-+  grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
-+  return len;
-+}
-+
-+/* Filesystem descriptor.  */
-+static struct grub_fs pseudo_fs = {
-+  .name = "pseudo",
-+  .fs_read = pseudo_read
-+};
-+
-+static grub_command_t cmd_verify, cmd_list, cmd_distrust, cmd_trust;
-+
-+GRUB_MOD_INIT (appendedsig)
-+{
-+  int rc;
-+  struct grub_module_header *header;
-+
-+  /* If in lockdown, immediately enter forced mode */
-+  if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED)
-+    check_sigs = 2;
-+
-+  grub_trusted_key = NULL;
-+
-+  grub_register_variable_hook ("check_appended_signatures",
-+  			       grub_env_read_sec,
-+			       grub_env_write_sec);
-+  grub_env_export ("check_appended_signatures");
-+
-+  rc = asn1_init ();
-+  if (rc)
-+    grub_fatal ("Error initing ASN.1 data structures: %d: %s\n", rc,
-+		asn1_strerror (rc));
-+
-+  FOR_MODULES (header)
-+  {
-+    struct grub_file pseudo_file;
-+    struct x509_certificate *pk = NULL;
-+    grub_err_t err;
-+
-+    /* Not an ELF module, skip.  */
-+    if (header->type != OBJ_TYPE_X509_PUBKEY)
-+      continue;
-+
-+    grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
-+    pseudo_file.fs = &pseudo_fs;
-+    pseudo_file.size = header->size - sizeof (struct grub_module_header);
-+    pseudo_file.data = (char *) header + sizeof (struct grub_module_header);
-+
-+    grub_dprintf ("appendedsig",
-+		  "Found an x509 key, size=%" PRIuGRUB_UINT64_T "\n",
-+		  pseudo_file.size);
-+
-+    pk = grub_zalloc (sizeof (struct x509_certificate));
-+    if (!pk)
-+      {
-+	grub_fatal ("Out of memory loading initial certificates");
-+      }
-+
-+    err = read_cert_from_file (&pseudo_file, pk);
-+    if (err != GRUB_ERR_NONE)
-+      grub_fatal ("Error loading initial key: %s", grub_errmsg);
-+
-+    grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", pk->subject);
-+
-+    pk->next = grub_trusted_key;
-+    grub_trusted_key = pk;
-+  }
-+
-+  cmd_trust =
-+    grub_register_command ("trust_certificate", grub_cmd_trust,
-+			   N_("X509_CERTIFICATE"),
-+			   N_("Add X509_CERTIFICATE to trusted certificates."));
-+  cmd_list =
-+    grub_register_command ("list_certificates", grub_cmd_list, 0,
-+			   N_("Show the list of trusted x509 certificates."));
-+  cmd_verify =
-+    grub_register_command ("verify_appended", grub_cmd_verify_signature,
-+			   N_("FILE"),
-+			   N_("Verify FILE against the trusted x509 certificates."));
-+  cmd_distrust =
-+    grub_register_command ("distrust_certificate", grub_cmd_distrust,
-+			   N_("CERT_NUMBER"),
-+			   N_("Remove CERT_NUMBER (as listed by list_certificates) from trusted certificates."));
-+
-+  grub_verifier_register (&grub_appendedsig_verifier);
-+  grub_dl_set_persistent (mod);
-+}
-+
-+GRUB_MOD_FINI (appendedsig)
-+{
-+  /*
-+   * grub_dl_set_persistent should prevent this from actually running, but
-+   * it does still run under emu.
-+   */
-+
-+  grub_verifier_unregister (&grub_appendedsig_verifier);
-+  grub_unregister_command (cmd_verify);
-+  grub_unregister_command (cmd_list);
-+  grub_unregister_command (cmd_trust);
-+  grub_unregister_command (cmd_distrust);
-+}
-diff --git a/include/grub/file.h b/include/grub/file.h
-index 31567483ccf..96827a4f896 100644
---- a/include/grub/file.h
-+++ b/include/grub/file.h
-@@ -80,6 +80,8 @@ enum grub_file_type
-     GRUB_FILE_TYPE_PUBLIC_KEY,
-     /* File holding public key to add to trused keys.  */
-     GRUB_FILE_TYPE_PUBLIC_KEY_TRUST,
-+    /* File holding x509 certificiate to add to trusted keys.  */
-+    GRUB_FILE_TYPE_CERTIFICATE_TRUST,
-     /* File of which we intend to print a blocklist to the user.  */
-     GRUB_FILE_TYPE_PRINT_BLOCKLIST,
-     /* File we intend to use for test loading or testing speed.  */
diff --git a/SOURCES/0194-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch b/SOURCES/0194-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch
new file mode 100644
index 0000000..200cd51
--- /dev/null
+++ b/SOURCES/0194-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch
@@ -0,0 +1,90 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 28 Jan 2022 11:30:32 +0100
+Subject: [PATCH] normal/menu: Don't show "Booting `%s'" msg when auto-booting
+ with TIMEOUT_STYLE_HIDDEN
+
+When the user has asked the menu code to be hidden/quiet and the current
+entry is being autobooted because the timeout has expired don't show
+the "Booting `%s'" msg.
+
+This is necessary to let flicker-free boots really be flicker free,
+otherwise the "Booting `%s'" msg will kick the EFI fb into text mode
+and show the msg, breaking the flicker-free experience.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ grub-core/normal/menu.c | 24 ++++++++++++++++--------
+ 1 file changed, 16 insertions(+), 8 deletions(-)
+
+diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
+index ec0c92bade..c8516a5a08 100644
+--- a/grub-core/normal/menu.c
++++ b/grub-core/normal/menu.c
+@@ -606,13 +606,15 @@ print_countdown (struct grub_term_coordinate *pos, int n)
+    entry to be executed is a result of an automatic default selection because
+    of the timeout.  */
+ static int
+-run_menu (grub_menu_t menu, int nested, int *auto_boot)
++run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot)
+ {
+   grub_uint64_t saved_time;
+   int default_entry, current_entry;
+   int timeout;
+   enum timeout_style timeout_style;
+ 
++  *notify_boot = 1;
++
+   default_entry = get_entry_number (menu, "default");
+ 
+   /* If DEFAULT_ENTRY is not within the menu entries, fall back to
+@@ -687,6 +689,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
+   if (timeout == 0)
+     {
+       *auto_boot = 1;
++      *notify_boot = timeout_style != TIMEOUT_STYLE_HIDDEN;
+       return default_entry;
+     }
+ 
+@@ -840,12 +843,16 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
+ 
+ /* Callback invoked immediately before a menu entry is executed.  */
+ static void
+-notify_booting (grub_menu_entry_t entry,
+-		void *userdata __attribute__((unused)))
++notify_booting (grub_menu_entry_t entry, void *userdata)
+ {
+-  grub_printf ("  ");
+-  grub_printf_ (N_("Booting `%s'"), entry->title);
+-  grub_printf ("\n\n");
++  int *notify_boot = userdata;
++
++  if (*notify_boot)
++    {
++      grub_printf ("  ");
++      grub_printf_ (N_("Booting `%s'"), entry->title);
++      grub_printf ("\n\n");
++    }
+ }
+ 
+ /* Callback invoked when a default menu entry executed because of a timeout
+@@ -893,8 +900,9 @@ show_menu (grub_menu_t menu, int nested, int autobooted)
+       int boot_entry;
+       grub_menu_entry_t e;
+       int auto_boot;
++      int notify_boot;
+ 
+-      boot_entry = run_menu (menu, nested, &auto_boot);
++      boot_entry = run_menu (menu, nested, &auto_boot, &notify_boot);
+       if (boot_entry < 0)
+ 	break;
+ 
+@@ -906,7 +914,7 @@ show_menu (grub_menu_t menu, int nested, int autobooted)
+ 
+       if (auto_boot)
+ 	grub_menu_execute_with_fallback (menu, e, autobooted,
+-					 &execution_callback, 0);
++					 &execution_callback, &notify_boot);
+       else
+ 	grub_menu_execute_entry (e, 0);
+       if (autobooted)
diff --git a/SOURCES/0195-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch b/SOURCES/0195-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch
new file mode 100644
index 0000000..0f99c22
--- /dev/null
+++ b/SOURCES/0195-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 28 Jan 2022 11:30:33 +0100
+Subject: [PATCH] EFI: suppress the "Welcome to GRUB!" message in EFI builds
+
+Grub EFI builds are now often used in combination with flicker-free
+boot, but this breaks with upstream grub because the "Welcome to GRUB!"
+message will kick the EFI fb into text mode and show the msg,
+breaking the flicker-free experience.
+
+EFI systems are so fast, that when the menu or the countdown are enabled
+the message will be immediately overwritten, so in these cases not
+printing the message does not matter.
+
+And in case when the timeout_style is set to TIMEOUT_STYLE_HIDDEN,
+the user has asked grub to be quiet (for example to allow flickfree
+boot) annd thus the message should not be printed.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ grub-core/kern/main.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
+index 3fc3401472..993b8a8598 100644
+--- a/grub-core/kern/main.c
++++ b/grub-core/kern/main.c
+@@ -317,10 +317,13 @@ grub_main (void)
+ 
+   grub_boot_time ("After machine init.");
+ 
++  /* This breaks flicker-free boot on EFI systems, so disable it there. */
++#ifndef GRUB_MACHINE_EFI
+   /* Hello.  */
+   grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
+   grub_printf ("Welcome to GRUB!\n\n");
+   grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
++#endif
+ 
+   /* Init verifiers API. */
+   grub_verifiers_init ();
diff --git a/SOURCES/0195-appended-signatures-verification-tests.patch b/SOURCES/0195-appended-signatures-verification-tests.patch
deleted file mode 100644
index 9f6c3c6..0000000
--- a/SOURCES/0195-appended-signatures-verification-tests.patch
+++ /dev/null
@@ -1,897 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 30 Jul 2020 01:31:02 +1000
-Subject: [PATCH] appended signatures: verification tests
-
-These tests are run through all_functional_test and test a range
-of commands and behaviours.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/Makefile.core.def               |   6 +
- grub-core/tests/appended_signature_test.c | 281 +++++++++++++++
- grub-core/tests/lib/functional_test.c     |   1 +
- grub-core/tests/appended_signatures.h     | 557 ++++++++++++++++++++++++++++++
- 4 files changed, 845 insertions(+)
- create mode 100644 grub-core/tests/appended_signature_test.c
- create mode 100644 grub-core/tests/appended_signatures.h
-
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 77321d218c8..6bddc841b85 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -2161,6 +2161,12 @@ module = {
-   common = tests/setjmp_test.c;
- };
- 
-+module = {
-+  name = appended_signature_test;
-+  common = tests/appended_signature_test.c;
-+  common = tests/appended_signatures.h;
-+};
-+
- module = {
-   name = signature_test;
-   common = tests/signature_test.c;
-diff --git a/grub-core/tests/appended_signature_test.c b/grub-core/tests/appended_signature_test.c
-new file mode 100644
-index 00000000000..88a485200d8
---- /dev/null
-+++ b/grub-core/tests/appended_signature_test.c
-@@ -0,0 +1,281 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2020  IBM Corporation.
-+ *
-+ *  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/time.h>
-+#include <grub/misc.h>
-+#include <grub/dl.h>
-+#include <grub/command.h>
-+#include <grub/env.h>
-+#include <grub/test.h>
-+#include <grub/mm.h>
-+#include <grub/procfs.h>
-+#include <grub/file.h>
-+
-+#include "appended_signatures.h"
-+
-+GRUB_MOD_LICENSE ("GPLv3+");
-+
-+#define DEFINE_TEST_CASE(case_name) \
-+static char * \
-+get_ ## case_name (grub_size_t *sz) \
-+{ \
-+  char *ret; \
-+  *sz = case_name ## _len; \
-+  ret = grub_malloc (*sz); \
-+  if (ret) \
-+    grub_memcpy (ret, case_name, *sz); \
-+  return ret; \
-+} \
-+\
-+static struct grub_procfs_entry case_name ## _entry = \
-+{ \
-+  .name = #case_name, \
-+  .get_contents = get_ ## case_name \
-+}
-+
-+#define DO_TEST(case_name, is_valid) \
-+{ \
-+  grub_procfs_register (#case_name, &case_name ## _entry); \
-+  do_verify ("(proc)/" #case_name, is_valid); \
-+  grub_procfs_unregister (&case_name ## _entry); \
-+}
-+
-+
-+DEFINE_TEST_CASE (hi_signed);
-+DEFINE_TEST_CASE (hi_signed_sha256);
-+DEFINE_TEST_CASE (hj_signed);
-+DEFINE_TEST_CASE (short_msg);
-+DEFINE_TEST_CASE (unsigned_msg);
-+DEFINE_TEST_CASE (hi_signed_2nd);
-+
-+static char *
-+get_certificate_der (grub_size_t * sz)
-+{
-+  char *ret;
-+  *sz = certificate_der_len;
-+  ret = grub_malloc (*sz);
-+  if (ret)
-+    grub_memcpy (ret, certificate_der, *sz);
-+  return ret;
-+}
-+
-+static struct grub_procfs_entry certificate_der_entry = {
-+  .name = "certificate.der",
-+  .get_contents = get_certificate_der
-+};
-+
-+static char *
-+get_certificate2_der (grub_size_t * sz)
-+{
-+  char *ret;
-+  *sz = certificate2_der_len;
-+  ret = grub_malloc (*sz);
-+  if (ret)
-+    grub_memcpy (ret, certificate2_der, *sz);
-+  return ret;
-+}
-+
-+static struct grub_procfs_entry certificate2_der_entry = {
-+  .name = "certificate2.der",
-+  .get_contents = get_certificate2_der
-+};
-+
-+static char *
-+get_certificate_printable_der (grub_size_t * sz)
-+{
-+  char *ret;
-+  *sz = certificate_printable_der_len;
-+  ret = grub_malloc (*sz);
-+  if (ret)
-+    grub_memcpy (ret, certificate_printable_der, *sz);
-+  return ret;
-+}
-+
-+static struct grub_procfs_entry certificate_printable_der_entry = {
-+  .name = "certificate_printable.der",
-+  .get_contents = get_certificate_printable_der
-+};
-+
-+
-+static void
-+do_verify (const char *f, int is_valid)
-+{
-+  grub_command_t cmd;
-+  char *args[] = { (char *) f, NULL };
-+  grub_err_t err;
-+
-+  cmd = grub_command_find ("verify_appended");
-+  if (!cmd)
-+    {
-+      grub_test_assert (0, "can't find command `%s'", "verify_appended");
-+      return;
-+    }
-+  err = (cmd->func) (cmd, 1, args);
-+  if (is_valid)
-+    {
-+      grub_test_assert (err == GRUB_ERR_NONE,
-+			"verification of %s failed: %d: %s", f, grub_errno,
-+			grub_errmsg);
-+    }
-+  else
-+    {
-+      grub_test_assert (err == GRUB_ERR_BAD_SIGNATURE,
-+			"verification of %s unexpectedly succeeded", f);
-+    }
-+  grub_errno = GRUB_ERR_NONE;
-+
-+}
-+
-+static void
-+appended_signature_test (void)
-+{
-+  grub_command_t cmd_trust, cmd_distrust;
-+  char *trust_args[] = { (char *) "(proc)/certificate.der", NULL };
-+  char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL };
-+  char *trust_args_printable[] = { (char *) "(proc)/certificate_printable.der",
-+				   NULL };
-+  char *distrust_args[] = { (char *) "1", NULL };
-+  char *distrust2_args[] = { (char *) "2", NULL };
-+  grub_err_t err;
-+
-+  grub_procfs_register ("certificate.der", &certificate_der_entry);
-+  grub_procfs_register ("certificate2.der", &certificate2_der_entry);
-+  grub_procfs_register ("certificate_printable.der",
-+			&certificate_printable_der_entry);
-+
-+  cmd_trust = grub_command_find ("trust_certificate");
-+  if (!cmd_trust)
-+    {
-+      grub_test_assert (0, "can't find command `%s'", "trust_certificate");
-+      return;
-+    }
-+  err = (cmd_trust->func) (cmd_trust, 1, trust_args);
-+
-+  grub_test_assert (err == GRUB_ERR_NONE,
-+		    "loading certificate failed: %d: %s", grub_errno,
-+		    grub_errmsg);
-+
-+  /* If we have no certificate the remainder of the tests are meaningless */
-+  if (err != GRUB_ERR_NONE)
-+    return;
-+
-+  /*
-+   * Reload the command: this works around some 'interesting' behaviour in the
-+   * dynamic command dispatcher. The first time you call cmd->func you get a
-+   * dispatcher that loads the module, finds the real cmd, calls it, and then
-+   * releases some internal storage. This means it's not safe to call a second
-+   * time and we need to reload it.
-+   */
-+  cmd_trust = grub_command_find ("trust_certificate");
-+
-+  DO_TEST (hi_signed, 1);
-+  DO_TEST (hi_signed_sha256, 1);
-+  DO_TEST (hj_signed, 0);
-+  DO_TEST (short_msg, 0);
-+  DO_TEST (unsigned_msg, 0);
-+
-+  /*
-+   * in enforcing mode, we shouldn't be able to load a certificate that isn't
-+   * signed by an existing trusted key.
-+   *
-+   * However, procfs files automatically skip the verification test, so we can't
-+   * easily test this.
-+   */
-+
-+  /*
-+   * verify that testing with 2 trusted certs works
-+   */
-+  DO_TEST (hi_signed_2nd, 0);
-+
-+  err = (cmd_trust->func) (cmd_trust, 1, trust_args2);
-+
-+  grub_test_assert (err == GRUB_ERR_NONE,
-+		    "loading certificate 2 failed: %d: %s", grub_errno,
-+		    grub_errmsg);
-+
-+  if (err != GRUB_ERR_NONE)
-+    return;
-+
-+  DO_TEST (hi_signed_2nd, 1);
-+  DO_TEST (hi_signed, 1);
-+
-+  /*
-+   * Check certificate removal. They're added to the _top_ of the list and
-+   * removed by position in the list. Current the list looks like [#2, #1].
-+   *
-+   * First test removing the second certificate in the list, which is
-+   * certificate #1, giving us just [#2].
-+   */
-+  cmd_distrust = grub_command_find ("distrust_certificate");
-+  if (!cmd_distrust)
-+    {
-+      grub_test_assert (0, "can't find command `%s'", "distrust_certificate");
-+      return;
-+    }
-+
-+  err = (cmd_distrust->func) (cmd_distrust, 1, distrust2_args);
-+  grub_test_assert (err == GRUB_ERR_NONE,
-+		    "distrusting certificate 1 failed: %d: %s", grub_errno,
-+		    grub_errmsg);
-+  DO_TEST (hi_signed_2nd, 1);
-+  DO_TEST (hi_signed, 0);
-+
-+  /*
-+   * Now reload certificate #1. This will make the list look like [#1, #2]
-+   */
-+  err = (cmd_trust->func) (cmd_trust, 1, trust_args);
-+
-+  grub_test_assert (err == GRUB_ERR_NONE,
-+		    "reloading certificate 1 failed: %d: %s", grub_errno,
-+		    grub_errmsg);
-+  DO_TEST (hi_signed, 1);
-+
-+  /* Remove the first certificate in the list, giving us just [#2] */
-+  err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args);
-+  grub_test_assert (err == GRUB_ERR_NONE,
-+		    "distrusting certificate 1 (first time) failed: %d: %s",
-+		    grub_errno, grub_errmsg);
-+  DO_TEST (hi_signed_2nd, 1);
-+  DO_TEST (hi_signed, 0);
-+
-+  /*
-+   * Remove the first certificate again, giving an empty list.
-+   *
-+   * verify_appended should fail if there are no certificates to verify against.
-+   */
-+  err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args);
-+  grub_test_assert (err == GRUB_ERR_NONE,
-+		    "distrusting certificate 1 (second time) failed: %d: %s",
-+		    grub_errno, grub_errmsg);
-+  DO_TEST (hi_signed_2nd, 0);
-+
-+  /*
-+   * Lastly, check a certificate that uses printableString rather than
-+   * utf8String loads properly.
-+   */
-+  err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable);
-+  grub_test_assert (err == GRUB_ERR_NONE,
-+		    "distrusting printable certificate failed: %d: %s",
-+		    grub_errno, grub_errmsg);
-+
-+  grub_procfs_unregister (&certificate_der_entry);
-+  grub_procfs_unregister (&certificate2_der_entry);
-+  grub_procfs_unregister (&certificate_printable_der_entry);
-+}
-+
-+GRUB_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test);
-diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c
-index 96781fb39b5..403fa5c789a 100644
---- a/grub-core/tests/lib/functional_test.c
-+++ b/grub-core/tests/lib/functional_test.c
-@@ -73,6 +73,7 @@ grub_functional_all_tests (grub_extcmd_context_t ctxt __attribute__ ((unused)),
-   grub_dl_load ("xnu_uuid_test");
-   grub_dl_load ("pbkdf2_test");
-   grub_dl_load ("signature_test");
-+  grub_dl_load ("appended_signature_test");
-   grub_dl_load ("sleep_test");
-   grub_dl_load ("bswap_test");
-   grub_dl_load ("ctz_test");
-diff --git a/grub-core/tests/appended_signatures.h b/grub-core/tests/appended_signatures.h
-new file mode 100644
-index 00000000000..aa3dc6278e3
---- /dev/null
-+++ b/grub-core/tests/appended_signatures.h
-@@ -0,0 +1,557 @@
-+unsigned char certificate_der[] = {
-+  0x30, 0x82, 0x03, 0x88, 0x30, 0x82, 0x02, 0x70, 0xa0, 0x03, 0x02, 0x01,
-+  0x02, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
-+  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30,
-+  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
-+  0x05, 0x00, 0x30, 0x49, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04,
-+  0x03, 0x0c, 0x1f, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65,
-+  0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
-+  0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d,
-+  0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
-+  0x01, 0x16, 0x0e, 0x64, 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e,
-+  0x73, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30,
-+  0x37, 0x30, 0x39, 0x30, 0x36, 0x32, 0x32, 0x30, 0x37, 0x5a, 0x18, 0x0f,
-+  0x32, 0x31, 0x32, 0x30, 0x30, 0x36, 0x31, 0x35, 0x30, 0x36, 0x32, 0x32,
-+  0x30, 0x37, 0x5a, 0x30, 0x52, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55,
-+  0x04, 0x03, 0x0c, 0x28, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70,
-+  0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74,
-+  0x75, 0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x69, 0x67,
-+  0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x31, 0x1d, 0x30, 0x1b,
-+  0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
-+  0x0e, 0x64, 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e,
-+  0x6e, 0x65, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
-+  0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
-+  0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00,
-+  0xcd, 0xe8, 0x1c, 0x08, 0x68, 0x2e, 0xcb, 0xfe, 0x8c, 0x4b, 0x3b, 0x61,
-+  0xe7, 0x8e, 0x80, 0x58, 0x85, 0x85, 0xea, 0xc8, 0x3b, 0x42, 0xba, 0x72,
-+  0x84, 0x65, 0x20, 0xbc, 0x48, 0xa2, 0x25, 0x49, 0x6e, 0x1c, 0xb9, 0x7d,
-+  0xeb, 0xc1, 0x0c, 0xa8, 0xb7, 0xcc, 0x13, 0x78, 0xba, 0x11, 0xa4, 0x98,
-+  0xd7, 0xd0, 0x7c, 0xdd, 0xf5, 0x5a, 0xb7, 0xcd, 0x31, 0x0e, 0xcd, 0x9e,
-+  0xa7, 0x19, 0xf0, 0xbd, 0x0f, 0xa6, 0xfe, 0x8a, 0x11, 0x97, 0xed, 0x8b,
-+  0xe5, 0x16, 0xa6, 0x21, 0x13, 0x36, 0xad, 0x05, 0x49, 0xec, 0x29, 0x12,
-+  0x38, 0xa7, 0x4b, 0x0f, 0xa1, 0xfb, 0x72, 0xc0, 0xc0, 0x09, 0x67, 0x78,
-+  0xa8, 0xb6, 0xd6, 0x1a, 0x39, 0xc0, 0xa8, 0xbf, 0x5f, 0x14, 0x89, 0x5c,
-+  0xbc, 0x41, 0x0c, 0x0c, 0x5d, 0x42, 0x2e, 0x1c, 0xdf, 0x1f, 0x1d, 0xc9,
-+  0x43, 0x94, 0x5b, 0x6e, 0x8f, 0x15, 0x8c, 0x8f, 0x94, 0x73, 0x4f, 0x97,
-+  0x54, 0xf1, 0x86, 0x8a, 0xbc, 0xe4, 0xe4, 0x93, 0xc1, 0x5e, 0xc2, 0x3e,
-+  0x31, 0x5e, 0xd4, 0x85, 0x57, 0x14, 0xd0, 0x11, 0x07, 0x65, 0xf4, 0x7c,
-+  0x8f, 0x07, 0x57, 0xe1, 0x22, 0xd4, 0x78, 0x47, 0x65, 0x4e, 0xa9, 0xb3,
-+  0xaa, 0xce, 0xc7, 0x36, 0xfe, 0xda, 0x66, 0x02, 0xb6, 0x8d, 0x18, 0x2f,
-+  0x3b, 0x41, 0x8d, 0x02, 0x08, 0x72, 0x4b, 0x69, 0xbd, 0x1e, 0x58, 0xfc,
-+  0x1b, 0x64, 0x04, 0x52, 0x35, 0x35, 0xe2, 0x3d, 0x3e, 0xde, 0xd6, 0x64,
-+  0xf4, 0xec, 0x57, 0x7e, 0x65, 0x59, 0x00, 0xa6, 0xd3, 0x4b, 0x09, 0x93,
-+  0x2a, 0x95, 0x0f, 0x30, 0xb6, 0xa1, 0x8c, 0xe7, 0x8b, 0x49, 0xa4, 0x1d,
-+  0x25, 0x2d, 0x65, 0x48, 0x8a, 0x0f, 0xcf, 0x2a, 0xa2, 0xe1, 0xef, 0x72,
-+  0x92, 0xc3, 0xf5, 0x21, 0x37, 0x83, 0x9b, 0x6d, 0x0b, 0x1b, 0xb3, 0xa2,
-+  0x32, 0x38, 0x11, 0xb1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30,
-+  0x5b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
-+  0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04,
-+  0x03, 0x02, 0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
-+  0x16, 0x04, 0x14, 0xe5, 0x2a, 0x4f, 0xf2, 0x84, 0x91, 0x57, 0x91, 0xaf,
-+  0x12, 0xd2, 0xf1, 0xa1, 0x87, 0x73, 0x0f, 0x90, 0x25, 0xa0, 0x7a, 0x30,
-+  0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
-+  0x56, 0xd1, 0xfd, 0xe2, 0x1e, 0x7e, 0x1c, 0x63, 0x4f, 0x47, 0xdb, 0xe4,
-+  0xc4, 0x51, 0x04, 0x03, 0x9a, 0x48, 0x35, 0x6e, 0x30, 0x0d, 0x06, 0x09,
-+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
-+  0x82, 0x01, 0x01, 0x00, 0x65, 0x82, 0xd5, 0x88, 0x30, 0xe2, 0x2c, 0x47,
-+  0xf3, 0x31, 0x39, 0xa1, 0x75, 0x9a, 0xb0, 0x8a, 0x6c, 0x4b, 0xac, 0xdf,
-+  0x09, 0x7b, 0x90, 0xb6, 0x9e, 0x76, 0x62, 0x94, 0xc1, 0x3a, 0x99, 0x49,
-+  0x68, 0x29, 0x47, 0x42, 0xc3, 0x06, 0xcb, 0x88, 0x75, 0xe6, 0x79, 0x13,
-+  0x8c, 0x4b, 0x49, 0x6a, 0xb5, 0x56, 0x95, 0xc0, 0x42, 0x21, 0x9b, 0xd4,
-+  0x61, 0xd0, 0x02, 0x41, 0xdd, 0x20, 0x61, 0xe5, 0x91, 0xdf, 0x75, 0x00,
-+  0x25, 0x0e, 0x99, 0x65, 0x5c, 0x54, 0x49, 0x32, 0xa3, 0xe2, 0xcd, 0xa1,
-+  0x5f, 0x40, 0xf3, 0xc5, 0x81, 0xd9, 0x3c, 0xa3, 0x63, 0x5a, 0x38, 0x79,
-+  0xab, 0x77, 0x98, 0xde, 0x8f, 0x4e, 0x9e, 0x26, 0xbc, 0x4e, 0x80, 0x9e,
-+  0x8f, 0xbe, 0xf1, 0x00, 0xb3, 0x78, 0xb9, 0x4b, 0x1d, 0xc7, 0xa4, 0x83,
-+  0x59, 0x56, 0x11, 0xd1, 0x11, 0x1e, 0x50, 0x39, 0xd5, 0x78, 0x14, 0xf3,
-+  0xb9, 0x1d, 0xda, 0xe4, 0xc4, 0x63, 0x74, 0x26, 0xab, 0xa3, 0xfd, 0x9d,
-+  0x58, 0xa2, 0xee, 0x7b, 0x28, 0x34, 0xa3, 0xbe, 0x85, 0x7e, 0xaa, 0x97,
-+  0xb7, 0x5b, 0x9d, 0xa9, 0x4d, 0x96, 0xdb, 0x6b, 0x21, 0xe1, 0x96, 0x5d,
-+  0xc7, 0xad, 0x23, 0x03, 0x9a, 0x16, 0xdb, 0xa4, 0x1f, 0x63, 0xef, 0xaf,
-+  0x1e, 0x4f, 0xf8, 0x27, 0xdc, 0x4b, 0xfc, 0x2b, 0x68, 0x2e, 0xa0, 0xd3,
-+  0xae, 0xf2, 0xce, 0xf5, 0xfc, 0x97, 0x92, 0xd2, 0x29, 0x0f, 0x4f, 0x4b,
-+  0x29, 0xeb, 0x06, 0xcb, 0xf8, 0x21, 0x6e, 0xbc, 0x8b, 0x5c, 0xc5, 0xc9,
-+  0xf7, 0xe2, 0x7c, 0x47, 0xcd, 0x43, 0x98, 0xc4, 0xa3, 0x9a, 0xd7, 0x3e,
-+  0xdc, 0x01, 0x13, 0x28, 0x96, 0xc4, 0x60, 0x83, 0xe2, 0x79, 0xa1, 0x46,
-+  0xef, 0xf5, 0xa4, 0x7b, 0x00, 0xe3, 0x3d, 0x7d, 0xbc, 0xa8, 0x98, 0x49,
-+  0xa8, 0xcf, 0x3b, 0x41, 0xb6, 0x09, 0x97, 0x07
-+};
-+unsigned int certificate_der_len = 908;
-+
-+unsigned char hi_signed[] = {
-+  0x68, 0x69, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48,
-+  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82,
-+  0x01, 0xad, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
-+  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
-+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x01,
-+  0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49,
-+  0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x47,
-+  0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64,
-+  0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54,
-+  0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09,
-+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64,
-+  0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65,
-+  0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
-+  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30,
-+  0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
-+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-+  0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xc7, 0x69, 0x35, 0x21, 0x66,
-+  0x4d, 0x50, 0xd4, 0x73, 0xde, 0xbd, 0x3a, 0xf6, 0x45, 0xe3, 0xe4, 0xd0,
-+  0xb6, 0xa1, 0xe7, 0xc0, 0xa2, 0xc9, 0xf4, 0xf0, 0x05, 0x8c, 0xa4, 0x16,
-+  0x9e, 0x81, 0x0d, 0x21, 0x68, 0xf3, 0xfe, 0x03, 0x96, 0x77, 0x31, 0x69,
-+  0x01, 0xd8, 0x26, 0xd9, 0x48, 0x95, 0xcf, 0xd1, 0x17, 0xb1, 0x0b, 0x6b,
-+  0x2c, 0xf1, 0xb0, 0xab, 0x65, 0x65, 0x56, 0xf8, 0x0c, 0xa7, 0xf7, 0xbb,
-+  0xf6, 0x5a, 0x55, 0x98, 0x14, 0x07, 0x8d, 0x2a, 0xbc, 0x16, 0x48, 0x94,
-+  0xab, 0x2f, 0x85, 0x97, 0x90, 0x51, 0x78, 0xa0, 0xda, 0x60, 0xb5, 0x41,
-+  0x4b, 0xe8, 0x78, 0xc5, 0xa6, 0x04, 0x9d, 0x54, 0x2a, 0x85, 0xfd, 0x86,
-+  0x0b, 0x6d, 0xc2, 0xd2, 0xad, 0x07, 0xff, 0x16, 0x42, 0x82, 0xe3, 0x5c,
-+  0xaa, 0x22, 0x59, 0x78, 0x92, 0xea, 0x94, 0xc3, 0x41, 0xb7, 0xa1, 0x86,
-+  0x44, 0xea, 0xd1, 0xdb, 0xe5, 0xac, 0x30, 0x32, 0xfb, 0x7d, 0x3f, 0xf7,
-+  0x8b, 0x11, 0x7f, 0x80, 0x3b, 0xe5, 0xc7, 0x82, 0x0f, 0x92, 0x07, 0x14,
-+  0x66, 0x01, 0x6e, 0x85, 0xab, 0x3a, 0x14, 0xcf, 0x76, 0xd1, 0x7e, 0x14,
-+  0x85, 0xca, 0x01, 0x73, 0x72, 0x38, 0xdc, 0xde, 0x30, 0x5c, 0xfb, 0xc0,
-+  0x3d, 0x93, 0xef, 0x9c, 0xbc, 0xf8, 0xcc, 0xd2, 0xbf, 0x47, 0xec, 0xf8,
-+  0x88, 0x9b, 0xe1, 0x43, 0xbe, 0xa7, 0x47, 0x96, 0xb6, 0x5d, 0x46, 0x0e,
-+  0x7a, 0x78, 0x38, 0x19, 0xbc, 0xb5, 0xbc, 0x9b, 0x3c, 0x39, 0x92, 0x70,
-+  0x0d, 0x9d, 0x8a, 0x35, 0xaf, 0xb4, 0x9e, 0xf4, 0xef, 0xc1, 0xb8, 0x25,
-+  0xd0, 0x14, 0x91, 0xd6, 0xc2, 0xb6, 0xc7, 0x3c, 0x72, 0x91, 0x0f, 0xad,
-+  0xde, 0xb2, 0x36, 0xf8, 0x4e, 0x59, 0xd4, 0xa4, 0x21, 0x9f, 0x03, 0x95,
-+  0x48, 0x01, 0xb4, 0x05, 0xc3, 0x39, 0x60, 0x51, 0x08, 0xd0, 0xbe, 0x00,
-+  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x7e,
-+  0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61,
-+  0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65,
-+  0x64, 0x7e, 0x0a
-+};
-+unsigned int hi_signed_len = 495;
-+
-+unsigned char hj_signed[] = {
-+  0x68, 0x6a, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48,
-+  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82,
-+  0x01, 0xad, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
-+  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
-+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x01,
-+  0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49,
-+  0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x47,
-+  0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64,
-+  0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54,
-+  0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09,
-+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64,
-+  0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65,
-+  0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
-+  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30,
-+  0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
-+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-+  0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xc7, 0x69, 0x35, 0x21, 0x66,
-+  0x4d, 0x50, 0xd4, 0x73, 0xde, 0xbd, 0x3a, 0xf6, 0x45, 0xe3, 0xe4, 0xd0,
-+  0xb6, 0xa1, 0xe7, 0xc0, 0xa2, 0xc9, 0xf4, 0xf0, 0x05, 0x8c, 0xa4, 0x16,
-+  0x9e, 0x81, 0x0d, 0x21, 0x68, 0xf3, 0xfe, 0x03, 0x96, 0x77, 0x31, 0x69,
-+  0x01, 0xd8, 0x26, 0xd9, 0x48, 0x95, 0xcf, 0xd1, 0x17, 0xb1, 0x0b, 0x6b,
-+  0x2c, 0xf1, 0xb0, 0xab, 0x65, 0x65, 0x56, 0xf8, 0x0c, 0xa7, 0xf7, 0xbb,
-+  0xf6, 0x5a, 0x55, 0x98, 0x14, 0x07, 0x8d, 0x2a, 0xbc, 0x16, 0x48, 0x94,
-+  0xab, 0x2f, 0x85, 0x97, 0x90, 0x51, 0x78, 0xa0, 0xda, 0x60, 0xb5, 0x41,
-+  0x4b, 0xe8, 0x78, 0xc5, 0xa6, 0x04, 0x9d, 0x54, 0x2a, 0x85, 0xfd, 0x86,
-+  0x0b, 0x6d, 0xc2, 0xd2, 0xad, 0x07, 0xff, 0x16, 0x42, 0x82, 0xe3, 0x5c,
-+  0xaa, 0x22, 0x59, 0x78, 0x92, 0xea, 0x94, 0xc3, 0x41, 0xb7, 0xa1, 0x86,
-+  0x44, 0xea, 0xd1, 0xdb, 0xe5, 0xac, 0x30, 0x32, 0xfb, 0x7d, 0x3f, 0xf7,
-+  0x8b, 0x11, 0x7f, 0x80, 0x3b, 0xe5, 0xc7, 0x82, 0x0f, 0x92, 0x07, 0x14,
-+  0x66, 0x01, 0x6e, 0x85, 0xab, 0x3a, 0x14, 0xcf, 0x76, 0xd1, 0x7e, 0x14,
-+  0x85, 0xca, 0x01, 0x73, 0x72, 0x38, 0xdc, 0xde, 0x30, 0x5c, 0xfb, 0xc0,
-+  0x3d, 0x93, 0xef, 0x9c, 0xbc, 0xf8, 0xcc, 0xd2, 0xbf, 0x47, 0xec, 0xf8,
-+  0x88, 0x9b, 0xe1, 0x43, 0xbe, 0xa7, 0x47, 0x96, 0xb6, 0x5d, 0x46, 0x0e,
-+  0x7a, 0x78, 0x38, 0x19, 0xbc, 0xb5, 0xbc, 0x9b, 0x3c, 0x39, 0x92, 0x70,
-+  0x0d, 0x9d, 0x8a, 0x35, 0xaf, 0xb4, 0x9e, 0xf4, 0xef, 0xc1, 0xb8, 0x25,
-+  0xd0, 0x14, 0x91, 0xd6, 0xc2, 0xb6, 0xc7, 0x3c, 0x72, 0x91, 0x0f, 0xad,
-+  0xde, 0xb2, 0x36, 0xf8, 0x4e, 0x59, 0xd4, 0xa4, 0x21, 0x9f, 0x03, 0x95,
-+  0x48, 0x01, 0xb4, 0x05, 0xc3, 0x39, 0x60, 0x51, 0x08, 0xd0, 0xbe, 0x00,
-+  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x7e,
-+  0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61,
-+  0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65,
-+  0x64, 0x7e, 0x0a
-+};
-+unsigned int hj_signed_len = 495;
-+
-+unsigned char hi_signed_sha256[] = {
-+  0x68, 0x69, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48,
-+  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82,
-+  0x01, 0xad, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
-+  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0b, 0x06, 0x09,
-+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x01,
-+  0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49,
-+  0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x47,
-+  0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64,
-+  0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54,
-+  0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09,
-+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64,
-+  0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65,
-+  0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d,
-+  0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30,
-+  0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
-+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-+  0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x7b, 0x5e, 0x82, 0x1d, 0x21,
-+  0xb6, 0x40, 0xd3, 0x33, 0x79, 0xa7, 0x52, 0x2b, 0xfc, 0x46, 0x51, 0x26,
-+  0xfe, 0x0f, 0x81, 0x90, 0x81, 0xab, 0x57, 0x5e, 0xf6, 0x45, 0x41, 0xa3,
-+  0x7b, 0x48, 0xdd, 0xd6, 0x59, 0x60, 0x51, 0x31, 0x14, 0x14, 0x7b, 0xb4,
-+  0x55, 0x7b, 0x4d, 0xfe, 0x09, 0x7a, 0x5d, 0xae, 0xc4, 0x58, 0x50, 0x80,
-+  0x75, 0xf2, 0x23, 0x20, 0x62, 0xe3, 0x7c, 0x26, 0x1d, 0x2a, 0x4d, 0x9f,
-+  0x89, 0xf0, 0x4f, 0x95, 0x8a, 0x80, 0x6e, 0x1a, 0xea, 0x87, 0xdb, 0x1f,
-+  0xf3, 0xda, 0x04, 0x91, 0x37, 0xea, 0x0a, 0xfb, 0x6c, 0xc9, 0x3d, 0x73,
-+  0xf9, 0x58, 0x7c, 0x15, 0x6b, 0xa2, 0x52, 0x5a, 0x97, 0xff, 0xd6, 0xb0,
-+  0xf1, 0xbf, 0xa5, 0x04, 0x6d, 0x91, 0xc1, 0x54, 0x05, 0xdc, 0x7f, 0x5d,
-+  0x19, 0xaf, 0x55, 0xec, 0x51, 0xfb, 0x66, 0x0a, 0xa4, 0x4e, 0x96, 0x47,
-+  0x43, 0x54, 0x7c, 0x64, 0xa8, 0xaa, 0xb4, 0x90, 0x02, 0xf3, 0xa7, 0x0b,
-+  0xb7, 0xbf, 0x06, 0xdb, 0x5e, 0x9c, 0x32, 0x6d, 0x45, 0x14, 0x1c, 0xaf,
-+  0x46, 0x30, 0x08, 0x55, 0x49, 0x78, 0xfa, 0x57, 0xda, 0x3d, 0xf5, 0xa0,
-+  0xef, 0x11, 0x0a, 0x81, 0x0d, 0x82, 0xcd, 0xaf, 0xdb, 0xda, 0x0e, 0x1a,
-+  0x44, 0xd1, 0xee, 0xc4, 0xb8, 0xde, 0x97, 0xb4, 0xda, 0xb4, 0x8b, 0x4f,
-+  0x58, 0x24, 0x59, 0xc0, 0xe0, 0x08, 0x97, 0x14, 0x68, 0xbe, 0x31, 0x09,
-+  0x5e, 0x67, 0x45, 0xf0, 0xcb, 0x81, 0x4f, 0x17, 0x44, 0x61, 0xe0, 0xe2,
-+  0xf0, 0xfc, 0x1e, 0xb9, 0x73, 0xaf, 0x42, 0xff, 0x33, 0xde, 0x61, 0x6b,
-+  0x7f, 0xc2, 0x69, 0x0d, 0x66, 0x54, 0xae, 0xf6, 0xde, 0x20, 0x47, 0x44,
-+  0x9b, 0x73, 0xd1, 0x07, 0x6e, 0x77, 0x37, 0x0a, 0xbb, 0x7f, 0xa0, 0x93,
-+  0x2d, 0x8d, 0x44, 0xba, 0xe2, 0xdd, 0x34, 0x32, 0xd7, 0x56, 0x71, 0x00,
-+  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x7e,
-+  0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61,
-+  0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65,
-+  0x64, 0x7e, 0x0a
-+};
-+unsigned int hi_signed_sha256_len = 495;
-+
-+unsigned char short_msg[] = {
-+  0x68, 0x69, 0x0a
-+};
-+unsigned int short_msg_len = 3;
-+
-+unsigned char unsigned_msg[] = {
-+  0x53, 0x65, 0x64, 0x20, 0x75, 0x74, 0x20, 0x70, 0x65, 0x72, 0x73, 0x70,
-+  0x69, 0x63, 0x69, 0x61, 0x74, 0x69, 0x73, 0x20, 0x75, 0x6e, 0x64, 0x65,
-+  0x20, 0x6f, 0x6d, 0x6e, 0x69, 0x73, 0x20, 0x69, 0x73, 0x74, 0x65, 0x20,
-+  0x6e, 0x61, 0x74, 0x75, 0x73, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20,
-+  0x73, 0x69, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74,
-+  0x65, 0x6d, 0x20, 0x61, 0x63, 0x63, 0x75, 0x73, 0x61, 0x6e, 0x74, 0x69,
-+  0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x71, 0x75,
-+  0x65, 0x20, 0x6c, 0x61, 0x75, 0x64, 0x61, 0x6e, 0x74, 0x69, 0x75, 0x6d,
-+  0x2c, 0x20, 0x74, 0x6f, 0x74, 0x61, 0x6d, 0x20, 0x72, 0x65, 0x6d, 0x20,
-+  0x61, 0x70, 0x65, 0x72, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x65, 0x61, 0x71,
-+  0x75, 0x65, 0x20, 0x69, 0x70, 0x73, 0x61, 0x20, 0x71, 0x75, 0x61, 0x65,
-+  0x20, 0x61, 0x62, 0x20, 0x69, 0x6c, 0x6c, 0x6f, 0x20, 0x69, 0x6e, 0x76,
-+  0x65, 0x6e, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x76, 0x65, 0x72, 0x69, 0x74,
-+  0x61, 0x74, 0x69, 0x73, 0x20, 0x65, 0x74, 0x20, 0x71, 0x75, 0x61, 0x73,
-+  0x69, 0x20, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x6f,
-+  0x20, 0x62, 0x65, 0x61, 0x74, 0x61, 0x65, 0x20, 0x76, 0x69, 0x74, 0x61,
-+  0x65, 0x20, 0x64, 0x69, 0x63, 0x74, 0x61, 0x20, 0x73, 0x75, 0x6e, 0x74,
-+  0x20, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x62, 0x6f, 0x2e, 0x20,
-+  0x4e, 0x65, 0x6d, 0x6f, 0x20, 0x65, 0x6e, 0x69, 0x6d, 0x20, 0x69, 0x70,
-+  0x73, 0x61, 0x6d, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74,
-+  0x65, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75,
-+  0x70, 0x74, 0x61, 0x73, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x73, 0x70,
-+  0x65, 0x72, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x20, 0x61, 0x75, 0x74, 0x20,
-+  0x6f, 0x64, 0x69, 0x74, 0x20, 0x61, 0x75, 0x74, 0x20, 0x66, 0x75, 0x67,
-+  0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x64, 0x20, 0x71, 0x75, 0x69, 0x61,
-+  0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x75, 0x6e, 0x74, 0x75,
-+  0x72, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f,
-+  0x72, 0x65, 0x73, 0x20, 0x65, 0x6f, 0x73, 0x20, 0x71, 0x75, 0x69, 0x20,
-+  0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x20, 0x76, 0x6f, 0x6c, 0x75,
-+  0x70, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x20, 0x73, 0x65, 0x71, 0x75, 0x69,
-+  0x20, 0x6e, 0x65, 0x73, 0x63, 0x69, 0x75, 0x6e, 0x74, 0x2e, 0x20, 0x4e,
-+  0x65, 0x71, 0x75, 0x65, 0x20, 0x70, 0x6f, 0x72, 0x72, 0x6f, 0x20, 0x71,
-+  0x75, 0x69, 0x73, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x73, 0x74, 0x2c,
-+  0x20, 0x71, 0x75, 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d,
-+  0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 0x20,
-+  0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d,
-+  0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 0x65,
-+  0x74, 0x75, 0x72, 0x2c, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63,
-+  0x69, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x64,
-+  0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x6e, 0x6f, 0x6e, 0x20, 0x6e, 0x75,
-+  0x6d, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x69, 0x75, 0x73, 0x20, 0x6d,
-+  0x6f, 0x64, 0x69, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x20,
-+  0x69, 0x6e, 0x63, 0x69, 0x64, 0x75, 0x6e, 0x74, 0x20, 0x75, 0x74, 0x20,
-+  0x6c, 0x61, 0x62, 0x6f, 0x72, 0x65, 0x20, 0x65, 0x74, 0x20, 0x64, 0x6f,
-+  0x6c, 0x6f, 0x72, 0x65, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x61, 0x6d, 0x20,
-+  0x61, 0x6c, 0x69, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x71, 0x75, 0x61, 0x65,
-+  0x72, 0x61, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74,
-+  0x65, 0x6d, 0x2e, 0x20, 0x55, 0x74, 0x20, 0x65, 0x6e, 0x69, 0x6d, 0x20,
-+  0x61, 0x64, 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x61, 0x20, 0x76, 0x65,
-+  0x6e, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x71, 0x75, 0x69, 0x73, 0x20, 0x6e,
-+  0x6f, 0x73, 0x74, 0x72, 0x75, 0x6d, 0x20, 0x65, 0x78, 0x65, 0x72, 0x63,
-+  0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x6d, 0x20, 0x75, 0x6c,
-+  0x6c, 0x61, 0x6d, 0x20, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x69, 0x73,
-+  0x20, 0x73, 0x75, 0x73, 0x63, 0x69, 0x70, 0x69, 0x74, 0x20, 0x6c, 0x61,
-+  0x62, 0x6f, 0x72, 0x69, 0x6f, 0x73, 0x61, 0x6d, 0x2c, 0x20, 0x6e, 0x69,
-+  0x73, 0x69, 0x20, 0x75, 0x74, 0x20, 0x61, 0x6c, 0x69, 0x71, 0x75, 0x69,
-+  0x64, 0x20, 0x65, 0x78, 0x20, 0x65, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x6d,
-+  0x6f, 0x64, 0x69, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61,
-+  0x74, 0x75, 0x72, 0x3f, 0x20, 0x51, 0x75, 0x69, 0x73, 0x20, 0x61, 0x75,
-+  0x74, 0x65, 0x6d, 0x20, 0x76, 0x65, 0x6c, 0x20, 0x65, 0x75, 0x6d, 0x20,
-+  0x69, 0x75, 0x72, 0x65, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x68, 0x65,
-+  0x6e, 0x64, 0x65, 0x72, 0x69, 0x74, 0x20, 0x71, 0x75, 0x69, 0x20, 0x69,
-+  0x6e, 0x20, 0x65, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61,
-+  0x74, 0x65, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x20, 0x65, 0x73, 0x73,
-+  0x65, 0x20, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x6e, 0x69, 0x68, 0x69, 0x6c,
-+  0x20, 0x6d, 0x6f, 0x6c, 0x65, 0x73, 0x74, 0x69, 0x61, 0x65, 0x20, 0x63,
-+  0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, 0x74, 0x75, 0x72, 0x2c, 0x20,
-+  0x76, 0x65, 0x6c, 0x20, 0x69, 0x6c, 0x6c, 0x75, 0x6d, 0x20, 0x71, 0x75,
-+  0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x65, 0x75,
-+  0x6d, 0x20, 0x66, 0x75, 0x67, 0x69, 0x61, 0x74, 0x20, 0x71, 0x75, 0x6f,
-+  0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x73, 0x20, 0x6e, 0x75,
-+  0x6c, 0x6c, 0x61, 0x20, 0x70, 0x61, 0x72, 0x69, 0x61, 0x74, 0x75, 0x72,
-+  0x3f, 0x0a
-+};
-+unsigned int unsigned_msg_len = 866;
-+
-+unsigned char certificate2_der[] = {
-+  0x30, 0x82, 0x05, 0x52, 0x30, 0x82, 0x03, 0x3a, 0xa0, 0x03, 0x02, 0x01,
-+  0x02, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5,
-+  0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30,
-+  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
-+  0x05, 0x00, 0x30, 0x3a, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04,
-+  0x03, 0x0c, 0x2f, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20,
-+  0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20,
-+  0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
-+  0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
-+  0x74, 0x79, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x37, 0x32, 0x38,
-+  0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x32,
-+  0x30, 0x30, 0x37, 0x30, 0x34, 0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 0x5a,
-+  0x30, 0x2b, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
-+  0x20, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65,
-+  0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x69,
-+  0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x82, 0x02,
-+  0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-+  0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02,
-+  0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xb0, 0x2f, 0x50, 0x01, 0x9c, 0x0e,
-+  0xd6, 0x8c, 0x07, 0xca, 0xc1, 0xcf, 0xbc, 0x03, 0xdd, 0xd3, 0xfa, 0xe3,
-+  0x4f, 0x71, 0xc1, 0x30, 0xaa, 0x09, 0x96, 0xe4, 0xd0, 0x6c, 0x42, 0x93,
-+  0xdb, 0x35, 0xf6, 0x7e, 0x1b, 0x67, 0xc0, 0xc2, 0x2d, 0x5b, 0xec, 0xca,
-+  0x35, 0x06, 0x32, 0x6c, 0x7b, 0x2c, 0xd3, 0x71, 0x2b, 0xe9, 0x7a, 0x19,
-+  0xd1, 0xf2, 0xa0, 0x7f, 0xd7, 0x4d, 0x6e, 0x28, 0xbb, 0xae, 0x49, 0x4a,
-+  0xbc, 0xea, 0x47, 0x67, 0xb8, 0x36, 0xa6, 0xf5, 0x0d, 0x0e, 0x20, 0x14,
-+  0x0c, 0x66, 0x67, 0x28, 0xb5, 0x97, 0x8b, 0x1f, 0x5e, 0x32, 0x06, 0x29,
-+  0x9c, 0x99, 0x92, 0x0f, 0x73, 0xac, 0xfd, 0xd2, 0x1d, 0xf2, 0xa8, 0x55,
-+  0x9d, 0x1b, 0xd8, 0x3d, 0xb0, 0x76, 0x9a, 0xb6, 0x6c, 0x9f, 0x62, 0x37,
-+  0x2f, 0xc0, 0xef, 0x44, 0xb3, 0x0d, 0x4a, 0x3e, 0x4f, 0x7d, 0xbd, 0xdb,
-+  0xd8, 0x75, 0x5f, 0x68, 0xe3, 0xf0, 0xec, 0x82, 0x66, 0x7c, 0x31, 0x70,
-+  0xa9, 0xa1, 0x6f, 0x38, 0x9f, 0xdf, 0xf5, 0xf0, 0x7d, 0x23, 0x9d, 0x34,
-+  0xa5, 0x85, 0xd3, 0xdf, 0x68, 0x41, 0xfc, 0x4f, 0x89, 0x45, 0x3c, 0x24,
-+  0x81, 0xa6, 0xf2, 0x3c, 0x02, 0x26, 0x09, 0x48, 0xdd, 0xfe, 0x4b, 0xb6,
-+  0x66, 0xbf, 0x8f, 0xe5, 0x5f, 0xf0, 0x5d, 0x8a, 0x61, 0x2e, 0x5f, 0x9f,
-+  0x80, 0xd9, 0xd5, 0xe6, 0x41, 0xd8, 0x10, 0x5e, 0x7a, 0xc6, 0xdb, 0x89,
-+  0xc7, 0xca, 0x6c, 0x5b, 0xb1, 0x4e, 0x7d, 0x0c, 0x03, 0xfd, 0x50, 0xca,
-+  0xbf, 0xbb, 0xe2, 0x69, 0x4b, 0x4e, 0xc2, 0x3d, 0x75, 0xfa, 0xd1, 0xcc,
-+  0xd6, 0xf9, 0x39, 0xb9, 0xdc, 0x53, 0xad, 0x62, 0xfb, 0x1b, 0x94, 0x26,
-+  0x7f, 0x21, 0x54, 0x5c, 0xb7, 0xdc, 0xe7, 0x96, 0x8c, 0xce, 0x75, 0xe0,
-+  0x17, 0x01, 0x3a, 0x3c, 0x77, 0x6e, 0xa4, 0x8b, 0x7a, 0x83, 0x28, 0x7a,
-+  0xf7, 0xb0, 0x5f, 0xfc, 0x7f, 0x2d, 0x2e, 0xec, 0xf5, 0xeb, 0x9c, 0x63,
-+  0x74, 0xd0, 0xe5, 0xdc, 0x19, 0xe4, 0x71, 0xc5, 0x4a, 0x8a, 0x54, 0xa4,
-+  0xe0, 0x7d, 0x4e, 0xbf, 0x53, 0x30, 0xaf, 0xd0, 0xeb, 0x96, 0xc3, 0xbb,
-+  0x65, 0xf7, 0x67, 0xf5, 0xae, 0xd3, 0x96, 0xf2, 0x63, 0xc8, 0x69, 0xf7,
-+  0x47, 0xcb, 0x27, 0x79, 0xe1, 0xff, 0x2f, 0x68, 0xdf, 0x1e, 0xb3, 0xb8,
-+  0x0c, 0xc5, 0x58, 0x73, 0xcc, 0xfe, 0x8c, 0xda, 0x4e, 0x3b, 0x01, 0x04,
-+  0xcd, 0xcb, 0xb8, 0x3e, 0x06, 0xfd, 0x4c, 0x0a, 0x9f, 0x5e, 0x76, 0x8c,
-+  0x0c, 0x83, 0x75, 0x09, 0x08, 0xb2, 0xdb, 0xf4, 0x49, 0x4e, 0xa0, 0xf2,
-+  0x0c, 0x7b, 0x87, 0x38, 0x9e, 0x22, 0x67, 0xbd, 0xd1, 0x97, 0x57, 0x24,
-+  0xf1, 0x46, 0x07, 0xf9, 0xd2, 0x1b, 0xec, 0x25, 0x5e, 0x67, 0xd9, 0x66,
-+  0x23, 0x1b, 0xd3, 0xe4, 0xaa, 0xec, 0x88, 0xf0, 0x7e, 0x15, 0x83, 0x51,
-+  0x31, 0x67, 0x51, 0x76, 0x5f, 0x55, 0xd7, 0x36, 0xdf, 0x4a, 0x84, 0x0b,
-+  0x6f, 0x5c, 0xbb, 0x5b, 0x8f, 0x37, 0x23, 0x7f, 0xf8, 0x17, 0x84, 0xa2,
-+  0x70, 0x20, 0x07, 0x0c, 0x90, 0x3a, 0x04, 0xfd, 0xf0, 0x08, 0x4a, 0xb1,
-+  0x16, 0x0f, 0xe6, 0xf6, 0x40, 0x51, 0x83, 0xd2, 0x87, 0x40, 0x9c, 0x1c,
-+  0x9f, 0x13, 0x38, 0x17, 0xd3, 0x34, 0x58, 0xad, 0x05, 0x71, 0xa0, 0x73,
-+  0xca, 0x40, 0xa6, 0xa4, 0x81, 0x02, 0xee, 0xa8, 0x72, 0x41, 0xa1, 0x41,
-+  0x18, 0x64, 0x8a, 0x86, 0x8a, 0x5d, 0xe6, 0x4f, 0x0a, 0xc5, 0x95, 0x98,
-+  0xf9, 0x78, 0xfe, 0x19, 0x0d, 0xc9, 0xb3, 0x89, 0xc1, 0x2b, 0x09, 0xbe,
-+  0xf1, 0xd2, 0x04, 0x5d, 0xcc, 0x28, 0xf5, 0x4b, 0xd2, 0x20, 0x4f, 0xc5,
-+  0x41, 0x9d, 0x8c, 0x85, 0xd8, 0xb0, 0x68, 0x5e, 0xc1, 0x0c, 0xb7, 0x24,
-+  0x4d, 0x67, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30,
-+  0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30,
-+  0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02,
-+  0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
-+  0x14, 0xac, 0xf5, 0x47, 0x17, 0xd9, 0x7d, 0xc1, 0xb1, 0xc4, 0x41, 0xe1,
-+  0x41, 0x60, 0xcb, 0x37, 0x11, 0x60, 0x28, 0x78, 0x5f, 0x30, 0x1f, 0x06,
-+  0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x21, 0x94,
-+  0xfb, 0xf9, 0xb2, 0x43, 0xe9, 0x33, 0xd7, 0x50, 0x7d, 0xc7, 0x37, 0xdb,
-+  0xd5, 0x82, 0x5a, 0x4e, 0xbe, 0x1b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
-+  0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02,
-+  0x01, 0x00, 0x96, 0x70, 0x65, 0x26, 0x42, 0xf8, 0xdc, 0x69, 0xde, 0xcf,
-+  0x41, 0x3a, 0x2e, 0x7f, 0x5b, 0xf1, 0xf9, 0x3b, 0x9b, 0xd2, 0x4e, 0x64,
-+  0x48, 0x81, 0xe4, 0x5d, 0x1e, 0x22, 0xce, 0x68, 0x63, 0x62, 0xe5, 0x1b,
-+  0x9b, 0xf2, 0xc7, 0x12, 0xda, 0x1e, 0x9b, 0x90, 0x84, 0x79, 0x48, 0x12,
-+  0xe6, 0x21, 0x6f, 0x2f, 0x7e, 0x18, 0x77, 0xdb, 0x8c, 0xc4, 0xd1, 0x0d,
-+  0x91, 0xbf, 0x39, 0x22, 0x0f, 0x64, 0xcf, 0x25, 0x2e, 0x8c, 0x1f, 0x91,
-+  0x81, 0xb5, 0xe9, 0x6c, 0x02, 0x3a, 0xf8, 0x07, 0xa2, 0x6f, 0x46, 0x5d,
-+  0x7b, 0xfd, 0x43, 0xff, 0x41, 0x0f, 0xe2, 0x57, 0x1c, 0xbd, 0x48, 0x60,
-+  0x53, 0x11, 0x48, 0x87, 0x88, 0x9d, 0x13, 0x82, 0x40, 0x68, 0x44, 0x2c,
-+  0xc6, 0xc8, 0x95, 0x27, 0x4f, 0xb6, 0xb9, 0x4a, 0x22, 0x0a, 0xfd, 0xe4,
-+  0x46, 0x8f, 0x35, 0x12, 0x98, 0x5a, 0x34, 0x6f, 0x2b, 0x57, 0x62, 0xa1,
-+  0x4d, 0x8d, 0x79, 0x37, 0xe4, 0x6b, 0x8a, 0x32, 0x5b, 0xcb, 0xef, 0x79,
-+  0x11, 0xed, 0xa7, 0xf8, 0x7a, 0x1c, 0xbd, 0x86, 0xdc, 0x0e, 0x2e, 0xfd,
-+  0xd3, 0x51, 0xbb, 0x73, 0xad, 0x00, 0xa0, 0x1b, 0xf9, 0x1d, 0xd1, 0x4a,
-+  0xe4, 0xd4, 0x02, 0x63, 0x2b, 0x39, 0x5f, 0x18, 0x08, 0x2f, 0x42, 0xb7,
-+  0x23, 0x4b, 0x48, 0x46, 0x1f, 0x63, 0x87, 0xae, 0x6d, 0xd5, 0xdb, 0x60,
-+  0xf8, 0x5f, 0xd3, 0x13, 0xec, 0xca, 0xdd, 0x60, 0x60, 0x79, 0x52, 0x70,
-+  0x47, 0xae, 0x1d, 0x38, 0x78, 0x71, 0xcf, 0xb3, 0x04, 0x03, 0xbe, 0xba,
-+  0x81, 0xba, 0x74, 0xb1, 0x30, 0x35, 0xdc, 0xea, 0x21, 0x4a, 0x9b, 0x70,
-+  0xfb, 0xd6, 0x60, 0x59, 0x78, 0x0c, 0x4d, 0x39, 0x19, 0x1d, 0xe5, 0x75,
-+  0xba, 0x07, 0xf4, 0x22, 0x37, 0x64, 0xb7, 0xf2, 0x9a, 0xc9, 0x11, 0x2d,
-+  0x8e, 0x58, 0xa6, 0xcf, 0x83, 0xf1, 0xcb, 0x6c, 0x7f, 0x02, 0xbd, 0xda,
-+  0x03, 0x92, 0xa9, 0x45, 0x24, 0x56, 0xc5, 0xbd, 0x41, 0xd1, 0x20, 0x86,
-+  0xc0, 0xb6, 0xb7, 0xe8, 0xa7, 0xb2, 0x46, 0xf7, 0x8e, 0xa9, 0x38, 0x0e,
-+  0x23, 0x77, 0x3c, 0x0d, 0x66, 0x83, 0x6a, 0x1a, 0x6b, 0x7f, 0x54, 0x11,
-+  0x58, 0x0d, 0x4a, 0xb5, 0x74, 0x60, 0xca, 0xed, 0xff, 0x91, 0x47, 0xd9,
-+  0x29, 0xe0, 0xaa, 0x8c, 0xa8, 0x8f, 0x10, 0x4c, 0x15, 0x7d, 0xce, 0x95,
-+  0xf9, 0x87, 0x1e, 0x18, 0x38, 0x18, 0xfc, 0xcc, 0xaf, 0x91, 0x17, 0x3f,
-+  0xfa, 0xf0, 0x8a, 0x09, 0x6f, 0xba, 0x4e, 0x53, 0xf7, 0xfa, 0x4f, 0x20,
-+  0xa3, 0xf4, 0x4a, 0x5a, 0xde, 0x17, 0x1c, 0x29, 0x6a, 0x6f, 0x03, 0x48,
-+  0xdf, 0xad, 0x4f, 0xe4, 0xbc, 0x71, 0xc4, 0x72, 0x32, 0x11, 0x84, 0xac,
-+  0x09, 0xd2, 0x18, 0x44, 0x35, 0xf1, 0xcd, 0xaf, 0xa8, 0x98, 0xe0, 0x8b,
-+  0xec, 0xa0, 0x83, 0x37, 0xc3, 0x35, 0x85, 0xd6, 0xd8, 0x1b, 0xe0, 0x75,
-+  0xdc, 0xfd, 0xde, 0xc9, 0xeb, 0xd5, 0x18, 0x0f, 0xd3, 0x4c, 0x2f, 0x71,
-+  0xdc, 0x48, 0xe3, 0x14, 0xeb, 0xda, 0x00, 0x24, 0x24, 0x9e, 0xa3, 0x8e,
-+  0x3e, 0x08, 0x6f, 0x22, 0x24, 0xd6, 0xc4, 0x85, 0x8f, 0x68, 0x00, 0x4a,
-+  0x82, 0x4c, 0x33, 0x6e, 0xa5, 0x35, 0x7b, 0xeb, 0x4b, 0xdc, 0xa0, 0xa6,
-+  0x65, 0x6f, 0x5a, 0x7a, 0xdf, 0x8a, 0x01, 0x52, 0xa1, 0x6c, 0xff, 0x59,
-+  0x22, 0x7f, 0xe1, 0x96, 0x1b, 0x19, 0xb8, 0xf9, 0x5d, 0x44, 0x9f, 0x91,
-+  0x03, 0x3c, 0x3d, 0xa1, 0x2a, 0xb6, 0x5a, 0x51, 0xa0, 0xce, 0x4a, 0x88,
-+  0x22, 0x72, 0x9c, 0xdc, 0xc0, 0x47, 0x76, 0x35, 0x84, 0x75, 0x9b, 0x87,
-+  0x5c, 0xd3, 0xcf, 0xe7, 0xdd, 0xa3, 0x57, 0x14, 0xdf, 0x00, 0xfd, 0x19,
-+  0x2a, 0x7d, 0x89, 0x27, 0x1c, 0x78, 0x97, 0x04, 0x58, 0x48
-+};
-+unsigned int certificate2_der_len = 1366;
-+
-+unsigned char hi_signed_2nd[] = {
-+  0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb1, 0x06, 0x09, 0x2a, 0x86, 0x48,
-+  0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa2, 0x30, 0x82,
-+  0x02, 0x9e, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
-+  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09,
-+  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02,
-+  0x7b, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 0x3a,
-+  0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x47,
-+  0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 0x74,
-+  0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74,
-+  0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
-+  0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 0x14,
-+  0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 0x07,
-+  0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 0x09,
-+  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 0x06,
-+  0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
-+  0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 0x90,
-+  0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 0x99,
-+  0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 0x07,
-+  0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 0xfe,
-+  0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 0x5f,
-+  0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 0x4f,
-+  0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 0x6f,
-+  0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 0x53,
-+  0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 0xd2,
-+  0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 0xc0,
-+  0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 0xdf,
-+  0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 0x05,
-+  0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 0x3d,
-+  0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 0x7d,
-+  0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 0x81,
-+  0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 0x36,
-+  0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 0xd5,
-+  0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 0xcc,
-+  0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 0x70,
-+  0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 0x94,
-+  0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 0xe3,
-+  0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 0x20,
-+  0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 0xc2,
-+  0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 0xac,
-+  0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 0xdb,
-+  0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 0x49,
-+  0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 0xb0,
-+  0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 0xcb,
-+  0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 0x76,
-+  0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 0xa5,
-+  0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 0x49,
-+  0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 0x6b,
-+  0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 0x25,
-+  0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 0x2e,
-+  0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 0xa0,
-+  0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 0x98,
-+  0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 0x8b,
-+  0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 0x83,
-+  0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 0x3e,
-+  0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 0x8a,
-+  0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 0xb7,
-+  0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 0x26,
-+  0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 0xac,
-+  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xb5,
-+  0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e,
-+  0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64,
-+  0x65, 0x64, 0x7e, 0x0a
-+};
-+unsigned int hi_signed_2nd_len = 736;
-+
-+unsigned char certificate_printable_der[] = {
-+  0x30, 0x82, 0x03, 0x39, 0x30, 0x82, 0x02, 0x21, 0xa0, 0x03, 0x02, 0x01,
-+  0x02, 0x02, 0x09, 0x00, 0xde, 0xf6, 0x22, 0xc4, 0xf2, 0xf1, 0x86, 0x02,
-+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-+  0x0b, 0x05, 0x00, 0x30, 0x2a, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55,
-+  0x04, 0x03, 0x13, 0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20,
-+  0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20,
-+  0x43, 0x41, 0x20, 0x32, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 0x30,
-+  0x1e, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x30, 0x33, 0x31, 0x31, 0x34, 0x31,
-+  0x39, 0x32, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x37, 0x31, 0x30, 0x32, 0x35,
-+  0x31, 0x34, 0x31, 0x39, 0x32, 0x33, 0x5a, 0x30, 0x2f, 0x31, 0x2d, 0x30,
-+  0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x24, 0x52, 0x65, 0x64, 0x20,
-+  0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42,
-+  0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20,
-+  0x33, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 0x30, 0x82, 0x01, 0x22,
-+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-+  0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
-+  0x02, 0x82, 0x01, 0x01, 0x00, 0xbd, 0xda, 0xa1, 0xed, 0x8d, 0x8e, 0x15,
-+  0x5c, 0xf8, 0x01, 0x77, 0x48, 0x4a, 0x60, 0x96, 0xf9, 0x27, 0xfa, 0xe2,
-+  0xb1, 0x69, 0x0f, 0x51, 0x19, 0x52, 0x7e, 0xc4, 0x34, 0x8e, 0xe1, 0x9b,
-+  0x9c, 0xa4, 0xb1, 0x5c, 0xd6, 0x81, 0x98, 0x78, 0xfe, 0xa9, 0xe5, 0x0b,
-+  0x00, 0xba, 0x9c, 0x64, 0x7e, 0xc7, 0xcc, 0x72, 0xb1, 0x73, 0x4b, 0x11,
-+  0x07, 0x52, 0xf0, 0x20, 0x96, 0x8b, 0x99, 0x39, 0xde, 0xdb, 0xfa, 0x3d,
-+  0x45, 0xe2, 0x98, 0x7b, 0x0c, 0x41, 0xe4, 0x0c, 0xb5, 0x5d, 0x92, 0x74,
-+  0x39, 0x96, 0xe1, 0x97, 0x97, 0xa1, 0xad, 0x2e, 0xcc, 0xd0, 0x1b, 0x4d,
-+  0x9d, 0xbd, 0x3e, 0xa9, 0x36, 0x8e, 0xcc, 0xc7, 0x5f, 0x6a, 0x7d, 0x39,
-+  0x5e, 0x0b, 0x8d, 0xca, 0xe4, 0x83, 0xe9, 0x3b, 0x5c, 0x86, 0x47, 0xd4,
-+  0xba, 0x7d, 0x98, 0x26, 0xa1, 0xf4, 0xe8, 0x90, 0x6b, 0x0f, 0xf1, 0x6b,
-+  0x8c, 0xe3, 0xa2, 0x80, 0x3c, 0x96, 0xf1, 0x0a, 0xb6, 0x66, 0xc0, 0x4b,
-+  0x61, 0xf7, 0x74, 0xcd, 0xd3, 0x7b, 0x8e, 0x5e, 0x39, 0xda, 0x99, 0x20,
-+  0x33, 0x93, 0xd3, 0xf0, 0x7f, 0xad, 0x35, 0xe9, 0x88, 0x8d, 0x9c, 0xbf,
-+  0x65, 0xf1, 0x47, 0x02, 0xf9, 0x7c, 0xed, 0x27, 0x5f, 0x4a, 0x65, 0x3c,
-+  0xcf, 0x5f, 0x0e, 0x88, 0x95, 0x74, 0xde, 0xfb, 0x9e, 0x2e, 0x91, 0x9b,
-+  0x45, 0x37, 0xc8, 0x85, 0xff, 0xe3, 0x41, 0x70, 0xfe, 0xd5, 0xef, 0x0e,
-+  0x82, 0x22, 0x08, 0xb7, 0x3b, 0x44, 0x3e, 0xdc, 0x5b, 0x7f, 0xba, 0xbf,
-+  0xe6, 0x58, 0x9d, 0x02, 0x6e, 0x75, 0xbf, 0x50, 0xec, 0xcf, 0x3f, 0xa5,
-+  0x91, 0x0a, 0xe2, 0x59, 0x2c, 0xc3, 0xe7, 0x05, 0x03, 0xe8, 0xf2, 0x6f,
-+  0x2a, 0x04, 0x68, 0x9a, 0x31, 0x32, 0x8f, 0x04, 0x35, 0xcd, 0x1f, 0x34,
-+  0xcc, 0x4f, 0x79, 0x5a, 0x99, 0x8d, 0x9d, 0x5c, 0xf5, 0x02, 0x03, 0x01,
-+  0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d,
-+  0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03,
-+  0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x1d, 0x06,
-+  0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x65, 0xc5, 0xbe, 0xca,
-+  0xe6, 0x59, 0x6a, 0xfd, 0x6c, 0x71, 0xc4, 0xa7, 0x98, 0xc6, 0x25, 0x8d,
-+  0x7b, 0x67, 0x05, 0xd0, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-+  0x18, 0x30, 0x16, 0x80, 0x14, 0x81, 0xf8, 0xee, 0x47, 0x5c, 0x3e, 0xed,
-+  0xfb, 0xce, 0xa5, 0x84, 0xbe, 0xd7, 0xae, 0xdb, 0xd3, 0x7d, 0x64, 0xb3,
-+  0x2a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-+  0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x66, 0x1e, 0x3d,
-+  0x1d, 0x53, 0x33, 0xde, 0x4e, 0xc7, 0xc4, 0xf4, 0xdf, 0xda, 0x18, 0x19,
-+  0x8a, 0xa9, 0xff, 0xe2, 0x63, 0x2b, 0xbe, 0xf2, 0x61, 0x63, 0xe2, 0xf6,
-+  0xed, 0x47, 0x1a, 0x71, 0x02, 0xec, 0x2a, 0xef, 0x89, 0x77, 0xe3, 0xfd,
-+  0x86, 0x69, 0xf1, 0x3f, 0x0d, 0xf9, 0x6e, 0xf9, 0x3b, 0xad, 0x26, 0x47,
-+  0xb7, 0xf2, 0x0d, 0xad, 0x23, 0xa3, 0x67, 0x3b, 0xcb, 0x6d, 0x9e, 0x03,
-+  0x0f, 0xbc, 0x69, 0x73, 0x9f, 0xd4, 0xa5, 0x0f, 0x6f, 0xf8, 0xab, 0x4d,
-+  0x36, 0xd1, 0xe0, 0xe0, 0x5d, 0x20, 0x43, 0x90, 0xc4, 0x65, 0x61, 0x93,
-+  0xe2, 0x0f, 0x51, 0x59, 0x0a, 0xf7, 0x88, 0x70, 0x57, 0xb9, 0x04, 0xa9,
-+  0x32, 0x57, 0x9c, 0xb3, 0x57, 0x38, 0x8b, 0x8e, 0x46, 0xc8, 0x32, 0x6c,
-+  0xb4, 0xf3, 0x96, 0x7f, 0x4b, 0xf0, 0x88, 0xf9, 0x7f, 0xe2, 0x71, 0xe1,
-+  0x8b, 0xe2, 0x14, 0xf1, 0x4b, 0x25, 0x00, 0x48, 0x1c, 0x7e, 0xe5, 0x8d,
-+  0x65, 0x2d, 0xeb, 0x72, 0x4f, 0x92, 0x44, 0xf3, 0xe6, 0xe0, 0xd0, 0xdf,
-+  0x85, 0xa8, 0x13, 0x4a, 0xfb, 0x99, 0xca, 0x14, 0x2c, 0x97, 0x80, 0x93,
-+  0x27, 0xd3, 0x20, 0xf8, 0x6d, 0x29, 0x28, 0x2c, 0xb9, 0x77, 0xea, 0xb1,
-+  0x63, 0xbd, 0x7d, 0x53, 0xfd, 0x4a, 0x62, 0x64, 0x0b, 0x98, 0xa8, 0xae,
-+  0x11, 0xfc, 0x6e, 0x8d, 0x63, 0xd4, 0x15, 0x55, 0xc6, 0x4c, 0x74, 0xf5,
-+  0x5f, 0xa0, 0xb9, 0x2c, 0x2d, 0x9a, 0x7a, 0x87, 0x6e, 0xf0, 0x5e, 0x25,
-+  0xed, 0xfc, 0xd8, 0xc4, 0x34, 0x33, 0x32, 0xad, 0x01, 0xd4, 0x4b, 0x49,
-+  0x51, 0xc2, 0x07, 0x7f, 0x90, 0x6d, 0xea, 0xf5, 0x4c, 0x41, 0x71, 0x64,
-+  0xeb, 0x1f, 0x29, 0xa3, 0x1f, 0x64, 0xa2, 0x1e, 0x0e, 0x6f, 0xa1, 0x67,
-+  0x99, 0x8d, 0x98, 0x1c, 0xb8, 0x53, 0x9d, 0x30, 0x1d, 0xae, 0x32, 0x56,
-+  0xd2
-+};
-+unsigned int certificate_printable_der_len = 829;
diff --git a/SOURCES/0196-EFI-console-Do-not-set-colorstate-until-the-first-te.patch b/SOURCES/0196-EFI-console-Do-not-set-colorstate-until-the-first-te.patch
new file mode 100644
index 0000000..ade6aae
--- /dev/null
+++ b/SOURCES/0196-EFI-console-Do-not-set-colorstate-until-the-first-te.patch
@@ -0,0 +1,51 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 28 Jan 2022 12:43:48 +0100
+Subject: [PATCH] EFI: console: Do not set colorstate until the first text
+ output
+
+GRUB_MOD_INIT(normal) does an unconditional:
+
+grub_env_set ("color_normal", "light-gray/black");
+
+which triggers a grub_term_setcolorstate() call. The original version
+of the "efi/console: Do not set text-mode until we actually need it" patch:
+https://lists.gnu.org/archive/html/grub-devel/2018-03/msg00125.html
+
+Protected against this by caching the requested state in
+grub_console_setcolorstate () and then only applying it when the first
+text output actually happens. During refactoring to move the
+grub_console_setcolorstate () up higher in the grub-core/term/efi/console.c
+file the code to cache the color-state + bail early was accidentally
+dropped.
+
+Restore the cache the color-state + bail early behavior from the original.
+
+Cc: Javier Martinez Canillas <javierm@redhat.com>
+Fixes: 2d7c3abd871f ("efi/console: Do not set text-mode until we actually need it")
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ grub-core/term/efi/console.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c
+index 2f1ae85ba7..c44b2ac318 100644
+--- a/grub-core/term/efi/console.c
++++ b/grub-core/term/efi/console.c
+@@ -82,6 +82,16 @@ grub_console_setcolorstate (struct grub_term_output *term
+ {
+   grub_efi_simple_text_output_interface_t *o;
+ 
++  if (grub_efi_is_finished || text_mode != GRUB_TEXT_MODE_AVAILABLE)
++    {
++      /*
++       * Cache colorstate changes before the first text-output, this avoids
++       * "color_normal" environment writes causing a switch to textmode.
++       */
++      text_colorstate = state;
++      return;
++    }
++
+   if (grub_efi_is_finished)
+     return;
+ 
diff --git a/SOURCES/0196-appended-signatures-documentation.patch b/SOURCES/0196-appended-signatures-documentation.patch
deleted file mode 100644
index 864cfa3..0000000
--- a/SOURCES/0196-appended-signatures-documentation.patch
+++ /dev/null
@@ -1,341 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 1 Oct 2020 13:02:09 +1000
-Subject: [PATCH] appended signatures: documentation
-
-This explains how appended signatures can be used to form part of
-a secure boot chain, and documents the commands and variables
-introduced.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- docs/grub.texi | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
- 1 file changed, 182 insertions(+), 17 deletions(-)
-
-diff --git a/docs/grub.texi b/docs/grub.texi
-index afbde7c1f7b..4816be85611 100644
---- a/docs/grub.texi
-+++ b/docs/grub.texi
-@@ -3214,6 +3214,7 @@ These variables have special meaning to GRUB.
- 
- @menu
- * biosnum::
-+* check_appended_signatures::
- * check_signatures::
- * chosen::
- * cmdpath::
-@@ -3273,11 +3274,18 @@ For an alternative approach which also changes BIOS drive mappings for the
- chain-loaded system, @pxref{drivemap}.
- 
- 
-+@node check_appended_signatures
-+@subsection check_appended_signatures
-+
-+This variable controls whether GRUB enforces appended signature validation on
-+certain loaded files. @xref{Using appended signatures}.
-+
-+
- @node check_signatures
- @subsection check_signatures
- 
--This variable controls whether GRUB enforces digital signature
--validation on loaded files. @xref{Using digital signatures}.
-+This variable controls whether GRUB enforces GPG-style digital signature
-+validation on loaded files. @xref{Using GPG-style digital signatures}.
- 
- @node chosen
- @subsection chosen
-@@ -3994,6 +4002,7 @@ you forget a command, you can run the command @command{help}
- * date::                        Display or set current date and time
- * devicetree::                  Load a device tree blob
- * distrust::                    Remove a pubkey from trusted keys
-+* distrust_certificate::        Remove a certificate from the list of trusted certificates
- * drivemap::                    Map a drive to another
- * echo::                        Display a line of text
- * eval::                        Evaluate agruments as GRUB commands
-@@ -4010,6 +4019,7 @@ you forget a command, you can run the command @command{help}
- * keystatus::                   Check key modifier status
- * linux::                       Load a Linux kernel
- * linux16::                     Load a Linux kernel (16-bit mode)
-+* list_certificates::           List trusted certificates
- * list_env::                    List variables in environment block
- * list_trusted::                List trusted public keys
- * load_env::                    Load variables from environment block
-@@ -4047,8 +4057,10 @@ you forget a command, you can run the command @command{help}
- * test::                        Check file types and compare values
- * true::                        Do nothing, successfully
- * trust::                       Add public key to list of trusted keys
-+* trust_certificate::           Add an x509 certificate to the list of trusted certificates
- * unset::                       Unset an environment variable
- @comment * vbeinfo::                     List available video modes
-+* verify_appended::             Verify appended digital signature
- * verify_detached::             Verify detached digital signature
- * videoinfo::                   List available video modes
- @comment * xen_*::              Xen boot commands for AArch64
-@@ -4376,9 +4388,28 @@ These keys are used to validate signatures when environment variable
- @code{check_signatures} is set to @code{enforce}
- (@pxref{check_signatures}), and by some invocations of
- @command{verify_detached} (@pxref{verify_detached}).  @xref{Using
--digital signatures}, for more information.
-+GPG-style digital signatures}, for more information.
- @end deffn
- 
-+
-+@node distrust_certificate
-+@subsection distrust_certificate
-+
-+@deffn Command distrust_certificate cert_number
-+Remove the x509 certificate numbered @var{cert_number} from GRUB's keyring of
-+trusted x509 certificates for verifying appended signatures.
-+
-+@var{cert_number} is the certificate number as listed by
-+@command{list_certificates} (@pxref{list_certificates}).
-+
-+These certificates are used to validate appended signatures when environment
-+variable @code{check_appended_signatures} is set to @code{enforce} or
-+@code{forced} (@pxref{check_appended_signatures}), and by
-+@command{verify_appended} (@pxref{verify_appended}). See
-+@xref{Using appended signatures} for more information.
-+@end deffn
-+
-+
- @node drivemap
- @subsection drivemap
- 
-@@ -4636,6 +4667,21 @@ This command is only available on x86 systems.
- @end deffn
- 
- 
-+@node list_certificates
-+@subsection list_certificates
-+
-+@deffn Command list_certificates
-+List all x509 certificates trusted by GRUB for validating appended signatures.
-+The output is a numbered list of certificates, showing the certificate's serial
-+number and Common Name.
-+
-+The certificate number can be used as an argument to
-+@command{distrust_certificate} (@pxref{distrust_certificate}).
-+
-+See @xref{Using appended signatures} for more information.
-+@end deffn
-+
-+
- @node list_env
- @subsection list_env
- 
-@@ -4655,7 +4701,7 @@ The output is in GPG's v4 key fingerprint format (i.e., the output of
- @code{gpg --fingerprint}).  The least significant four bytes (last
- eight hexadecimal digits) can be used as an argument to
- @command{distrust} (@pxref{distrust}).
--@xref{Using digital signatures}, for more information about uses for
-+@xref{Using GPG-style digital signatures}, for more information about uses for
- these keys.
- @end deffn
- 
-@@ -4690,8 +4736,13 @@ When used with care, @option{--skip-sig} and the whitelist enable an
- administrator to configure a system to boot only signed
- configurations, but to allow the user to select from among multiple
- configurations, and to enable ``one-shot'' boot attempts and
--``savedefault'' behavior.  @xref{Using digital signatures}, for more
-+``savedefault'' behavior.  @xref{Using GPG-style digital signatures}, for more
- information.
-+
-+Extra care should be taken when combining this command with appended signatures
-+(@pxref{Using appended signatures}), as this file is not validated by an
-+appended signature and could set @code{check_appended_signatures=no} if GRUB is
-+not in @pxref{Lockdown} mode.
- @end deffn
- 
- 
-@@ -4987,7 +5038,7 @@ read.  It is possible to modify a digitally signed environment block
- file from within GRUB using this command, such that its signature will
- no longer be valid on subsequent boots.  Care should be taken in such
- advanced configurations to avoid rendering the system
--unbootable. @xref{Using digital signatures}, for more information.
-+unbootable. @xref{Using GPG-style digital signatures}, for more information.
- @end deffn
- 
- 
-@@ -5387,11 +5438,32 @@ signatures when environment variable @code{check_signatures} is set to
- must itself be properly signed.  The @option{--skip-sig} option can be
- used to disable signature-checking when reading @var{pubkey_file}
- itself. It is expected that @option{--skip-sig} is useful for testing
--and manual booting. @xref{Using digital signatures}, for more
-+and manual booting. @xref{Using GPG-style digital signatures}, for more
- information.
- @end deffn
- 
- 
-+@node trust_certificate
-+@subsection trust_certificate
-+
-+@deffn Command trust_certificate x509_certificate
-+Read an DER-formatted x509 certificate from the file @var{x509_certificate}
-+and add it to GRUB's internal list of trusted x509 certificates. These
-+certificates are used to validate appended signatures when the environment
-+variable @code{check_appended_signatures} is set to @code{enforce} or
-+@code{forced}.
-+
-+Note that if @code{check_appended_signatures} is set to @code{enforce} or
-+@code{forced} when @command{trust_certificate} is executed, then
-+@var{x509_certificate} must itself bear an appended signature. (It is not
-+sufficient that @var{x509_certificate} be signed by a trusted certificate
-+according to the x509 rules: grub does not include support for validating
-+signatures within x509 certificates themselves.)
-+
-+See @xref{Using appended signatures} for more information.
-+@end deffn
-+
-+
- @node unset
- @subsection unset
- 
-@@ -5410,6 +5482,18 @@ only on PC BIOS platforms.
- @end deffn
- @end ignore
- 
-+@node verify_appended
-+@subsection verify_appended
-+
-+@deffn Command verify_appended file
-+Verifies an appended signature on @var{file} against the trusted certificates
-+known to GRUB (See @pxref{list_certificates}, @pxref{trust_certificate}, and
-+@pxref{distrust_certificate}).
-+
-+Exit code @code{$?} is set to 0 if the signature validates
-+successfully.  If validation fails, it is set to a non-zero value.
-+See @xref{Using appended signatures}, for more information.
-+@end deffn
- 
- @node verify_detached
- @subsection verify_detached
-@@ -5428,7 +5512,7 @@ tried.
- 
- Exit code @code{$?} is set to 0 if the signature validates
- successfully.  If validation fails, it is set to a non-zero value.
--@xref{Using digital signatures}, for more information.
-+@xref{Using GPG-style digital signatures}, for more information.
- @end deffn
- 
- @node videoinfo
-@@ -5811,13 +5895,14 @@ environment variables and commands are listed in the same order.
- @chapter Security
- 
- @menu
--* Authentication and authorisation:: Users and access control
--* Using digital signatures::         Booting digitally signed code
--* UEFI secure boot and shim::        Booting digitally signed PE files
--* Secure Boot Advanced Targeting::   Embedded information for generation number based revocation
--* Measured Boot::                    Measuring boot components
--* Lockdown::                         Lockdown when booting on a secure setup
--* Signing GRUB itself::              Ensuring the integrity of the GRUB core image
-+* Authentication and authorisation::   Users and access control
-+* Using GPG-style digital signatures:: Booting digitally signed code
-+* Using appended signatures::          An alternative approach to booting digitally signed code
-+* UEFI secure boot and shim::          Booting digitally signed PE files
-+* Secure Boot Advanced Targeting::     Embedded information for generation number based revocation
-+* Measured Boot::                      Measuring boot components
-+* Lockdown::                           Lockdown when booting on a secure setup
-+* Signing GRUB itself::                Ensuring the integrity of the GRUB core image
- @end menu
- 
- @node Authentication and authorisation
-@@ -5891,8 +5976,8 @@ generating configuration files with authentication.  You can use
- adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2}
- commands.
- 
--@node Using digital signatures
--@section Using digital signatures in GRUB
-+@node Using GPG-style digital signatures
-+@section Using GPG-style digital signatures in GRUB
- 
- GRUB's @file{core.img} can optionally provide enforcement that all files
- subsequently read from disk are covered by a valid digital signature.
-@@ -5985,6 +6070,86 @@ or BIOS) configuration to cause the machine to boot from a different
- (attacker-controlled) device.  GRUB is at best only one link in a
- secure boot chain.
- 
-+@node Using appended signatures
-+@section Using appended signatures in GRUB
-+
-+GRUB supports verifying Linux-style 'appended signatures' for secure boot.
-+Appended signatures are PKCS#7 messages containing a signature over the
-+contents of a file, plus some metadata, appended to the end of a file. A file
-+with an appended signature ends with the magic string:
-+
-+@example
-+~Module signature appended~\n
-+@end example
-+
-+where @code{\n} represents the line-feed character, @code{0x0a}.
-+
-+Certificates can be managed at boot time using the @pxref{trust_certificate},
-+@pxref{distrust_certificate} and @pxref{list_certificates} commands.
-+Certificates can also be built in to the core image using the @code{--x509}
-+parameter to @command{grub-install} or @command{grub-mkimage}.
-+
-+A file can be explictly verified using the @pxref{verify_appended} command.
-+
-+Only signatures made with the SHA-256 or SHA-512 hash algorithm are supported,
-+and only RSA signatures are supported.
-+
-+A file can be signed with the @command{sign-file} utility supplied with the
-+Linux kernel source. For example, if you have @code{signing.key} as the private
-+key and @code{certificate.der} as the x509 certificate containing the public key:
-+
-+@example
-+sign-file SHA256 signing.key certificate.der vmlinux vmlinux.signed
-+@end example
-+
-+Enforcement of signature verification is controlled by the
-+@code{check_appended_signatures} variable.
-+
-+@itemize
-+@item @samp{no}: no verification is performed. This is the default when GRUB
-+      is not in @pxref{Lockdown} mode.
-+@item @samp{enforce}: verification is performed. Verification can be disabled
-+      by setting the variable back to @samp{no}.
-+@item @samp{forced}: verification is performed and cannot be disabled. This is
-+      set when GRUB is in Lockdown when the appendedsig module is loaded.
-+@end itemize
-+
-+Unlike GPG-style signatures, not all files loaded by GRUB are required to be
-+signed. Once verification is turned on, the following file types will have
-+appended signatures verified:
-+
-+@itemize
-+@item Linux kernels
-+@item GRUB modules, except those built into the core image
-+@item Any new certificate files to be trusted
-+@end itemize
-+
-+ACPI tables and Device Tree images will not be checked for appended signatures
-+but must be verified by another mechanism such as GPG-style signatures before
-+they will be loaded.
-+
-+Unless lockdown mode is enabled, signature checking does @strong{not}
-+stop an attacker with console access from dropping manually to the GRUB
-+console and executing:
-+
-+@example
-+set check_appended_signatures=no
-+@end example
-+
-+Refer to the section on password-protecting GRUB (@pxref{Authentication
-+and authorisation}) for more information on preventing this.
-+
-+Additionally, unless lockdown mode is enabled:
-+
-+@itemize
-+@item Special care must be taken around the @command{loadenv} command, which
-+      can be used to turn off @code{check_appended_signature}.
-+
-+@item If the grub configuration file is loaded from the disk, anyone who can
-+      modify the file on disk can turn off @code{check_appended_signature}.
-+      Consider embedding the configuration into the core grub image.
-+@end itemize
-+
- @node UEFI secure boot and shim
- @section UEFI secure boot and shim support
- 
diff --git a/SOURCES/0197-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch b/SOURCES/0197-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch
new file mode 100644
index 0000000..5fab5db
--- /dev/null
+++ b/SOURCES/0197-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch
@@ -0,0 +1,71 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 28 Jan 2022 12:43:49 +0100
+Subject: [PATCH] EFI: console: Do not set cursor until the first text output
+
+To allow flickerfree boot the EFI console code does not call
+grub_efi_set_text_mode (1) until some text is actually output.
+
+Depending on if the output text is because of an error loading
+e.g. the .cfg file; or because of showing the menu the cursor needs
+to be on or off when the first text is shown.
+
+So far the cursor was hardcoded to being on, but this is causing
+drawing artifacts + slow drawing of the menu as reported here:
+https://bugzilla.redhat.com/show_bug.cgi?id=1946969
+
+Handle the cursorstate in the same way as the colorstate to fix this,
+when no text has been output yet, just cache the cursorstate and
+then use the last set value when the first text is output.
+
+Fixes: 2d7c3abd871f ("efi/console: Do not set text-mode until we actually need it")
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ grub-core/term/efi/console.c | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c
+index c44b2ac318..a3622e4fe5 100644
+--- a/grub-core/term/efi/console.c
++++ b/grub-core/term/efi/console.c
+@@ -31,7 +31,15 @@ typedef enum {
+ }
+ grub_text_mode;
+ 
++typedef enum {
++    GRUB_CURSOR_MODE_UNDEFINED = -1,
++    GRUB_CURSOR_MODE_OFF = 0,
++    GRUB_CURSUR_MODE_ON
++}
++grub_cursor_mode;
++
+ static grub_text_mode text_mode = GRUB_TEXT_MODE_UNDEFINED;
++static grub_cursor_mode cursor_mode = GRUB_CURSOR_MODE_UNDEFINED;
+ static grub_term_color_state text_colorstate = GRUB_TERM_COLOR_UNDEFINED;
+ 
+ static grub_uint32_t
+@@ -119,8 +127,12 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)),
+ {
+   grub_efi_simple_text_output_interface_t *o;
+ 
+-  if (grub_efi_is_finished)
+-    return;
++  if (grub_efi_is_finished || text_mode != GRUB_TEXT_MODE_AVAILABLE)
++    {
++      /* Cache cursor changes before the first text-output */
++      cursor_mode = on;
++      return;
++    }
+ 
+   o = grub_efi_system_table->con_out;
+   efi_call_2 (o->enable_cursor, o, on);
+@@ -143,7 +155,8 @@ grub_prepare_for_text_output (struct grub_term_output *term)
+       return GRUB_ERR_BAD_DEVICE;
+     }
+ 
+-  grub_console_setcursor (term, 1);
++  if (cursor_mode != GRUB_CURSOR_MODE_UNDEFINED)
++    grub_console_setcursor (term, cursor_mode);
+   if (text_colorstate != GRUB_TERM_COLOR_UNDEFINED)
+     grub_console_setcolorstate (term, text_colorstate);
+   text_mode = GRUB_TEXT_MODE_AVAILABLE;
diff --git a/SOURCES/0197-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch b/SOURCES/0197-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch
deleted file mode 100644
index 40c3b3e..0000000
--- a/SOURCES/0197-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch
+++ /dev/null
@@ -1,109 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Mon, 28 Sep 2020 11:11:17 +1000
-Subject: [PATCH] ieee1275: enter lockdown based on /ibm,secure-boot
-
-If the 'ibm,secure-boot' property of the root node is 2 or greater,
-enter lockdown.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/Makefile.core.def    |  1 +
- grub-core/kern/ieee1275/init.c | 27 +++++++++++++++++++++++++++
- include/grub/lockdown.h        |  3 ++-
- docs/grub.texi                 |  4 ++--
- 4 files changed, 32 insertions(+), 3 deletions(-)
-
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 6bddc841b85..3f3459b2c70 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -323,6 +323,7 @@ kernel = {
-   powerpc_ieee1275 = kern/powerpc/cache.S;
-   powerpc_ieee1275 = kern/powerpc/dl.c;
-   powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
-+  powerpc_ieee1275 = kern/lockdown.c;
- 
-   sparc64_ieee1275 = kern/sparc64/cache.S;
-   sparc64_ieee1275 = kern/sparc64/dl.c;
-diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
-index 937c1bc44cb..fc7d9712729 100644
---- a/grub-core/kern/ieee1275/init.c
-+++ b/grub-core/kern/ieee1275/init.c
-@@ -44,6 +44,7 @@
- #ifdef __sparc__
- #include <grub/machine/kernel.h>
- #endif
-+#include <grub/lockdown.h>
- 
- /* The minimal heap size we can live with. */
- #define HEAP_MIN_SIZE		(unsigned long) (2 * 1024 * 1024)
-@@ -271,6 +272,30 @@ grub_parse_cmdline (void)
-     }
- }
- 
-+static void
-+grub_get_ieee1275_secure_boot (void)
-+{
-+  grub_ieee1275_phandle_t root;
-+  int rc;
-+  grub_uint32_t is_sb;
-+
-+  grub_ieee1275_finddevice ("/", &root);
-+
-+  rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", &is_sb,
-+                                           sizeof (is_sb), 0);
-+
-+  /* ibm,secure-boot:
-+   * 0 - disabled
-+   * 1 - audit
-+   * 2 - enforce
-+   * 3 - enforce + OS-specific behaviour
-+   *
-+   * We only support enforce.
-+   */
-+  if (rc >= 0 && is_sb >= 2)
-+    grub_lockdown ();
-+}
-+
- grub_addr_t grub_modbase;
- 
- void
-@@ -296,6 +321,8 @@ grub_machine_init (void)
- #else
-   grub_install_get_time_ms (grub_rtc_get_time_ms);
- #endif
-+
-+  grub_get_ieee1275_secure_boot ();
- }
- 
- void
-diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h
-index 40531fa823b..ebfee4bf06e 100644
---- a/include/grub/lockdown.h
-+++ b/include/grub/lockdown.h
-@@ -24,7 +24,8 @@
- #define GRUB_LOCKDOWN_DISABLED       0
- #define GRUB_LOCKDOWN_ENABLED        1
- 
--#ifdef GRUB_MACHINE_EFI
-+#if defined(GRUB_MACHINE_EFI) || \
-+    (defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275))
- extern void
- EXPORT_FUNC (grub_lockdown) (void);
- extern int
-diff --git a/docs/grub.texi b/docs/grub.texi
-index 4816be85611..a4da9c2a1b9 100644
---- a/docs/grub.texi
-+++ b/docs/grub.texi
-@@ -6227,8 +6227,8 @@ Measured boot is currently only supported on EFI platforms.
- @section Lockdown when booting on a secure setup
- 
- The GRUB can be locked down when booted on a secure boot environment, for example
--if the UEFI secure boot is enabled. On a locked down configuration, the GRUB will
--be restricted and some operations/commands cannot be executed.
-+if UEFI or Power secure boot is enabled. On a locked down configuration, the
-+GRUB will be restricted and some operations/commands cannot be executed.
- 
- The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down.
- Otherwise it does not exit.
diff --git a/SOURCES/0198-Use-visual-indentation-in-config.h.in.patch b/SOURCES/0198-Use-visual-indentation-in-config.h.in.patch
new file mode 100644
index 0000000..978eb07
--- /dev/null
+++ b/SOURCES/0198-Use-visual-indentation-in-config.h.in.patch
@@ -0,0 +1,93 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Wed, 15 Dec 2021 15:46:13 -0500
+Subject: [PATCH] Use visual indentation in config.h.in
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+(cherry picked from commit de8051f34de0aa55c921a510974e5bb27e39c17b)
+[rharwood: GRUB_RPM_CONFIG presence]
+---
+ config.h.in | 58 +++++++++++++++++++++++++++++-----------------------------
+ 1 file changed, 29 insertions(+), 29 deletions(-)
+
+diff --git a/config.h.in b/config.h.in
+index c80e3e0aba..f2ed0066ec 100644
+--- a/config.h.in
++++ b/config.h.in
+@@ -23,47 +23,47 @@
+ #define MINILZO_CFG_SKIP_LZO1X_DECOMPRESS 1
+ 
+ #if defined (GRUB_BUILD)
+-#undef ENABLE_NLS
+-#define BUILD_SIZEOF_LONG @BUILD_SIZEOF_LONG@
+-#define BUILD_SIZEOF_VOID_P @BUILD_SIZEOF_VOID_P@
+-#if defined __APPLE__
+-# if defined __BIG_ENDIAN__
+-#  define BUILD_WORDS_BIGENDIAN 1
+-# else
+-#  define BUILD_WORDS_BIGENDIAN 0
+-# endif
+-#else
+-#define BUILD_WORDS_BIGENDIAN @BUILD_WORDS_BIGENDIAN@
+-#endif
++#  undef ENABLE_NLS
++#  define BUILD_SIZEOF_LONG @BUILD_SIZEOF_LONG@
++#  define BUILD_SIZEOF_VOID_P @BUILD_SIZEOF_VOID_P@
++#  if defined __APPLE__
++#    if defined __BIG_ENDIAN__
++#      define BUILD_WORDS_BIGENDIAN 1
++#    else
++#      define BUILD_WORDS_BIGENDIAN 0
++#    endif
++#  else /* !defined __APPLE__ */
++#    define BUILD_WORDS_BIGENDIAN @BUILD_WORDS_BIGENDIAN@
++#  endif /* !defined __APPLE__ */
+ #elif defined (GRUB_UTIL) || !defined (GRUB_MACHINE)
+-#include <config-util.h>
+-#else
+-#define HAVE_FONT_SOURCE @HAVE_FONT_SOURCE@
++#  include <config-util.h>
++#else /* !defined GRUB_UTIL && defined GRUB_MACHINE */
++#  define HAVE_FONT_SOURCE @HAVE_FONT_SOURCE@
+ /* Define if C symbols get an underscore after compilation. */
+-#define HAVE_ASM_USCORE @HAVE_ASM_USCORE@
++#  define HAVE_ASM_USCORE @HAVE_ASM_USCORE@
+ /* Define it to one of __bss_start, edata and _edata.  */
+-#define BSS_START_SYMBOL @BSS_START_SYMBOL@
++#  define BSS_START_SYMBOL @BSS_START_SYMBOL@
+ /* Define it to either end or _end.  */
+-#define END_SYMBOL @END_SYMBOL@
++#  define END_SYMBOL @END_SYMBOL@
+ /* Name of package.  */
+-#define PACKAGE "@PACKAGE@"
++#  define PACKAGE "@PACKAGE@"
+ /* Version number of package.  */
+-#define VERSION "@VERSION@"
++#  define VERSION "@VERSION@"
+ /* Define to the full name and version of this package. */
+-#define PACKAGE_STRING "@PACKAGE_STRING@"
++#  define PACKAGE_STRING "@PACKAGE_STRING@"
+ /* Define to the version of this package. */
+-#define PACKAGE_VERSION "@PACKAGE_VERSION@"
++#  define PACKAGE_VERSION "@PACKAGE_VERSION@"
+ /* Define to the full name of this package. */
+-#define PACKAGE_NAME "@PACKAGE_NAME@"
++#  define PACKAGE_NAME "@PACKAGE_NAME@"
+ /* Define to the address where bug reports for this package should be sent. */
+-#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@"
++#  define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@"
+ 
+-#define GRUB_TARGET_CPU "@GRUB_TARGET_CPU@"
+-#define GRUB_PLATFORM "@GRUB_PLATFORM@"
+-#define GRUB_RPM_VERSION "@GRUB_RPM_VERSION@"
++#  define GRUB_TARGET_CPU "@GRUB_TARGET_CPU@"
++#  define GRUB_PLATFORM "@GRUB_PLATFORM@"
++#  define GRUB_RPM_VERSION "@GRUB_RPM_VERSION@"
+ 
+-#define RE_ENABLE_I18N 1
++#  define RE_ENABLE_I18N 1
+ 
+-#define _GNU_SOURCE 1
++#  define _GNU_SOURCE 1
+ 
+ #endif
diff --git a/SOURCES/0198-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch b/SOURCES/0198-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch
deleted file mode 100644
index 52fa9d2..0000000
--- a/SOURCES/0198-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch
+++ /dev/null
@@ -1,75 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Wed, 14 Apr 2021 20:10:23 +1000
-Subject: [PATCH] ieee1275: drop HEAP_MAX_ADDR, HEAP_MIN_SIZE
-
-HEAP_MAX_ADDR is confusing. Currently it is set to 32MB, except
-on ieee1275 on x86, where it is 64MB.
-
-There is a comment which purports to explain it:
-
-/* If possible, we will avoid claiming heap above this address, because it
-   seems to cause relocation problems with OSes that link at 4 MiB */
-
-This doesn't make a lot of sense when the constants are well above 4MB
-already. It was not always this way. Prior to
-commit 7b5d0fe4440c ("Increase heap limit") in 2010, HEAP_MAX_SIZE and
-HEAP_MAX_ADDR were indeed 4MB. However, when the constants were increased
-the comment was left unchanged.
-
-It's been over a decade. It doesn't seem like we have problems with
-claims over 4MB on powerpc or x86 ieee1275. (sparc does things completely
-differently and never used the constant.)
-
-Drop the constant and the check.
-
-The only use of HEAP_MIN_SIZE was to potentially override the
-HEAP_MAX_ADDR check. It is now unused. Remove it.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/kern/ieee1275/init.c | 17 -----------------
- 1 file changed, 17 deletions(-)
-
-diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
-index fc7d9712729..0dcd114ce54 100644
---- a/grub-core/kern/ieee1275/init.c
-+++ b/grub-core/kern/ieee1275/init.c
-@@ -46,9 +46,6 @@
- #endif
- #include <grub/lockdown.h>
- 
--/* The minimal heap size we can live with. */
--#define HEAP_MIN_SIZE		(unsigned long) (2 * 1024 * 1024)
--
- /* The maximum heap size we're going to claim */
- #ifdef __i386__
- #define HEAP_MAX_SIZE		(unsigned long) (64 * 1024 * 1024)
-@@ -56,14 +53,6 @@
- #define HEAP_MAX_SIZE		(unsigned long) (32 * 1024 * 1024)
- #endif
- 
--/* If possible, we will avoid claiming heap above this address, because it
--   seems to cause relocation problems with OSes that link at 4 MiB */
--#ifdef __i386__
--#define HEAP_MAX_ADDR		(unsigned long) (64 * 1024 * 1024)
--#else
--#define HEAP_MAX_ADDR		(unsigned long) (32 * 1024 * 1024)
--#endif
--
- extern char _end[];
- 
- #ifdef __sparc__
-@@ -185,12 +174,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
-   if (*total + len > HEAP_MAX_SIZE)
-     len = HEAP_MAX_SIZE - *total;
- 
--  /* Avoid claiming anything above HEAP_MAX_ADDR, if possible. */
--  if ((addr < HEAP_MAX_ADDR) &&				/* if it's too late, don't bother */
--      (addr + len > HEAP_MAX_ADDR) &&				/* if it wasn't available anyway, don't bother */
--      (*total + (HEAP_MAX_ADDR - addr) > HEAP_MIN_SIZE))	/* only limit ourselves when we can afford to */
--     len = HEAP_MAX_ADDR - addr;
--
-   /* In theory, firmware should already prevent this from happening by not
-      listing our own image in /memory/available.  The check below is intended
-      as a safeguard in case that doesn't happen.  However, it doesn't protect
diff --git a/SOURCES/0199-Where-present-ensure-config-util.h-precedes-config.h.patch b/SOURCES/0199-Where-present-ensure-config-util.h-precedes-config.h.patch
new file mode 100644
index 0000000..22c2d9c
--- /dev/null
+++ b/SOURCES/0199-Where-present-ensure-config-util.h-precedes-config.h.patch
@@ -0,0 +1,275 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 22 Feb 2022 16:57:54 -0500
+Subject: [PATCH] Where present, ensure config-util.h precedes config.h
+
+gnulib defines go in config-util.h, and we need to know whether to
+provide duplicates in config.h or not.
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+(cherry picked from commit 46e82b28e1a75703d0424c7e13d009171310c6cd)
+[rharwood: gensymlist isn't part of tarballs]
+---
+ grub-core/disk/host.c                | 2 +-
+ grub-core/kern/emu/argp_common.c     | 2 +-
+ grub-core/kern/emu/main.c            | 2 +-
+ grub-core/osdep/aros/config.c        | 2 +-
+ grub-core/osdep/basic/emunet.c       | 2 +-
+ grub-core/osdep/basic/init.c         | 2 +-
+ grub-core/osdep/haiku/getroot.c      | 2 +-
+ grub-core/osdep/linux/emunet.c       | 2 +-
+ grub-core/osdep/unix/config.c        | 2 +-
+ grub-core/osdep/unix/cputime.c       | 2 +-
+ grub-core/osdep/unix/dl.c            | 2 +-
+ grub-core/osdep/unix/emuconsole.c    | 2 +-
+ grub-core/osdep/unix/getroot.c       | 2 +-
+ grub-core/osdep/windows/config.c     | 2 +-
+ grub-core/osdep/windows/cputime.c    | 2 +-
+ grub-core/osdep/windows/dl.c         | 2 +-
+ grub-core/osdep/windows/emuconsole.c | 2 +-
+ grub-core/osdep/windows/init.c       | 2 +-
+ 18 files changed, 18 insertions(+), 18 deletions(-)
+
+diff --git a/grub-core/disk/host.c b/grub-core/disk/host.c
+index c151d225df..f34529f86a 100644
+--- a/grub-core/disk/host.c
++++ b/grub-core/disk/host.c
+@@ -20,8 +20,8 @@
+ /* When using the disk, make a reference to this module.  Otherwise
+    the user will end up with a useless module :-).  */
+ 
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ 
+ #include <grub/dl.h>
+ #include <grub/disk.h>
+diff --git a/grub-core/kern/emu/argp_common.c b/grub-core/kern/emu/argp_common.c
+index 1668858703..8cb4608c3d 100644
+--- a/grub-core/kern/emu/argp_common.c
++++ b/grub-core/kern/emu/argp_common.c
+@@ -17,8 +17,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ 
+ #pragma GCC diagnostic ignored "-Wmissing-prototypes"
+ #pragma GCC diagnostic ignored "-Wmissing-declarations"
+diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c
+index 55ea5a11cc..12277c34d2 100644
+--- a/grub-core/kern/emu/main.c
++++ b/grub-core/kern/emu/main.c
+@@ -16,8 +16,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ 
+ #include <time.h>
+ #include <stdio.h>
+diff --git a/grub-core/osdep/aros/config.c b/grub-core/osdep/aros/config.c
+index c82d0ea8e7..55f5728efc 100644
+--- a/grub-core/osdep/aros/config.c
++++ b/grub-core/osdep/aros/config.c
+@@ -16,8 +16,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ 
+ #include <grub/emu/hostdisk.h>
+ #include <grub/emu/exec.h>
+diff --git a/grub-core/osdep/basic/emunet.c b/grub-core/osdep/basic/emunet.c
+index 6362e5cfbb..dbfd316d61 100644
+--- a/grub-core/osdep/basic/emunet.c
++++ b/grub-core/osdep/basic/emunet.c
+@@ -16,8 +16,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ 
+ #include <grub/i18n.h>
+ #include <grub/emu/net.h>
+diff --git a/grub-core/osdep/basic/init.c b/grub-core/osdep/basic/init.c
+index c54c710dbc..b104c7e162 100644
+--- a/grub-core/osdep/basic/init.c
++++ b/grub-core/osdep/basic/init.c
+@@ -16,8 +16,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ 
+ #include <grub/util/misc.h>
+ #include <grub/i18n.h>
+diff --git a/grub-core/osdep/haiku/getroot.c b/grub-core/osdep/haiku/getroot.c
+index 4e123c0903..927a1ebc94 100644
+--- a/grub-core/osdep/haiku/getroot.c
++++ b/grub-core/osdep/haiku/getroot.c
+@@ -1,5 +1,5 @@
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <string.h>
+diff --git a/grub-core/osdep/linux/emunet.c b/grub-core/osdep/linux/emunet.c
+index 19b188f09e..d5a6417355 100644
+--- a/grub-core/osdep/linux/emunet.c
++++ b/grub-core/osdep/linux/emunet.c
+@@ -16,8 +16,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ 
+ #include <sys/socket.h>
+ #include <sys/types.h>
+diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c
+index 46a881530c..0ce0e309ac 100644
+--- a/grub-core/osdep/unix/config.c
++++ b/grub-core/osdep/unix/config.c
+@@ -16,8 +16,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ 
+ #include <grub/emu/hostdisk.h>
+ #include <grub/emu/exec.h>
+diff --git a/grub-core/osdep/unix/cputime.c b/grub-core/osdep/unix/cputime.c
+index cff359a3b9..fb6ff55a1a 100644
+--- a/grub-core/osdep/unix/cputime.c
++++ b/grub-core/osdep/unix/cputime.c
+@@ -1,5 +1,5 @@
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ 
+ #include <sys/times.h>
+ #include <unistd.h>
+diff --git a/grub-core/osdep/unix/dl.c b/grub-core/osdep/unix/dl.c
+index 562b101a28..99b189bc1c 100644
+--- a/grub-core/osdep/unix/dl.c
++++ b/grub-core/osdep/unix/dl.c
+@@ -16,8 +16,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ 
+ #include <grub/dl.h>
+ #include <grub/misc.h>
+diff --git a/grub-core/osdep/unix/emuconsole.c b/grub-core/osdep/unix/emuconsole.c
+index 7308798efe..cac159424d 100644
+--- a/grub-core/osdep/unix/emuconsole.c
++++ b/grub-core/osdep/unix/emuconsole.c
+@@ -17,8 +17,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ 
+ #include <grub/term.h>
+ #include <grub/types.h>
+diff --git a/grub-core/osdep/unix/getroot.c b/grub-core/osdep/unix/getroot.c
+index 46d7116c6e..4f436284ce 100644
+--- a/grub-core/osdep/unix/getroot.c
++++ b/grub-core/osdep/unix/getroot.c
+@@ -16,8 +16,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <config-util.h>
+ #include <config.h>
++#include <config-util.h>
+ 
+ #include <sys/stat.h>
+ #include <sys/types.h>
+diff --git a/grub-core/osdep/windows/config.c b/grub-core/osdep/windows/config.c
+index 928ab1a49b..2bb8a2fd88 100644
+--- a/grub-core/osdep/windows/config.c
++++ b/grub-core/osdep/windows/config.c
+@@ -16,8 +16,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ 
+ #include <grub/emu/hostfile.h>
+ #include <grub/emu/config.h>
+diff --git a/grub-core/osdep/windows/cputime.c b/grub-core/osdep/windows/cputime.c
+index 3568aa2d35..5d06d79dd5 100644
+--- a/grub-core/osdep/windows/cputime.c
++++ b/grub-core/osdep/windows/cputime.c
+@@ -1,5 +1,5 @@
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ 
+ #include <grub/emu/misc.h>
+ #include <windows.h>
+diff --git a/grub-core/osdep/windows/dl.c b/grub-core/osdep/windows/dl.c
+index eec6a24ad7..8eab7057e4 100644
+--- a/grub-core/osdep/windows/dl.c
++++ b/grub-core/osdep/windows/dl.c
+@@ -16,8 +16,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ 
+ #include <grub/dl.h>
+ #include <grub/misc.h>
+diff --git a/grub-core/osdep/windows/emuconsole.c b/grub-core/osdep/windows/emuconsole.c
+index 4fb3693cc0..17a44de469 100644
+--- a/grub-core/osdep/windows/emuconsole.c
++++ b/grub-core/osdep/windows/emuconsole.c
+@@ -16,8 +16,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ 
+ #include <grub/term.h>
+ #include <grub/misc.h>
+diff --git a/grub-core/osdep/windows/init.c b/grub-core/osdep/windows/init.c
+index 6297de6326..51a9647dde 100644
+--- a/grub-core/osdep/windows/init.c
++++ b/grub-core/osdep/windows/init.c
+@@ -16,8 +16,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <config.h>
+ #include <config-util.h>
++#include <config.h>
+ #include <grub/util/misc.h>
+ #include <grub/osdep/hostfile.h>
+ #include <grub/util/windows.h>
diff --git a/SOURCES/0199-ieee1275-claim-more-memory.patch b/SOURCES/0199-ieee1275-claim-more-memory.patch
deleted file mode 100644
index 001a9df..0000000
--- a/SOURCES/0199-ieee1275-claim-more-memory.patch
+++ /dev/null
@@ -1,252 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Wed, 15 Apr 2020 23:28:29 +1000
-Subject: [PATCH] ieee1275: claim more memory
-
-On powerpc-ieee1275, we are running out of memory trying to verify
-anything. This is because:
-
- - we have to load an entire file into memory to verify it. This is
-   extremely difficult to change with appended signatures.
- - We only have 32MB of heap.
- - Distro kernels are now often around 30MB.
-
-So we want to claim more memory from OpenFirmware for our heap.
-
-There are some complications:
-
- - The grub mm code isn't the only thing that will make claims on
-   memory from OpenFirmware:
-
-    * PFW/SLOF will have claimed some for their own use.
-
-    * The ieee1275 loader will try to find other bits of memory that we
-      haven't claimed to place the kernel and initrd when we go to boot.
-
-    * Once we load Linux, it will also try to claim memory. It claims
-      memory without any reference to /memory/available, it just starts
-      at min(top of RMO, 768MB) and works down. So we need to avoid this
-      area. See arch/powerpc/kernel/prom_init.c as of v5.11.
-
- - The smallest amount of memory a ppc64 KVM guest can have is 256MB.
-   It doesn't work with distro kernels but can work with custom kernels.
-   We should maintain support for that. (ppc32 can boot with even less,
-   and we shouldn't break that either.)
-
- - Even if a VM has more memory, the memory OpenFirmware makes available
-   as Real Memory Area can be restricted. A freshly created LPAR on a
-   PowerVM machine is likely to have only 256MB available to OpenFirmware
-   even if it has many gigabytes of memory allocated.
-
-EFI systems will attempt to allocate 1/4th of the available memory,
-clamped to between 1M and 1600M. That seems like a good sort of
-approach, we just need to figure out if 1/4 is the right fraction
-for us.
-
-We don't know in advance how big the kernel and initrd are going to be,
-which makes figuring out how much memory we can take a bit tricky.
-
-To figure out how much memory we should leave unused, I looked at:
-
- - an Ubuntu 20.04.1 ppc64le pseries KVM guest:
-    vmlinux: ~30MB
-    initrd:  ~50MB
-
- - a RHEL8.2 ppc64le pseries KVM guest:
-    vmlinux: ~30MB
-    initrd:  ~30MB
-
-Ubuntu VMs struggle to boot with just 256MB under SLOF.
-RHEL likewise has a higher minimum supported memory figure.
-So lets first consider a distro kernel and 512MB of addressible memory.
-(This is the default case for anything booting under PFW.) Say we lose
-131MB to PFW (based on some tests). This leaves us 381MB. 1/4 of 381MB
-is ~95MB. That should be enough to verify a 30MB vmlinux and should
-leave plenty of space to load Linux and the initrd.
-
-If we consider 256MB of RMA under PFW, we have just 125MB remaining. 1/4
-of that is a smidge under 32MB, which gives us very poor odds of verifying
-a distro-sized kernel. However, if we need 80MB just to put the kernel
-and initrd in memory, we can't claim any more than 45MB anyway. So 1/4
-will do. We'll come back to this later.
-
-grub is always built as a 32-bit binary, even if it's loading a ppc64
-kernel. So we can't address memory beyond 4GB. This gives a natural cap
-of 1GB for powerpc-ieee1275.
-
-Also apply this 1/4 approach to i386-ieee1275, but keep the 32MB cap.
-
-make check still works for both i386 and powerpc and I've booted
-powerpc grub with this change under SLOF and PFW.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/kern/ieee1275/init.c | 81 +++++++++++++++++++++++++++++++++---------
- docs/grub-dev.texi             |  6 ++--
- 2 files changed, 69 insertions(+), 18 deletions(-)
-
-diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
-index 0dcd114ce54..c61d91a0285 100644
---- a/grub-core/kern/ieee1275/init.c
-+++ b/grub-core/kern/ieee1275/init.c
-@@ -46,11 +46,12 @@
- #endif
- #include <grub/lockdown.h>
- 
--/* The maximum heap size we're going to claim */
-+/* The maximum heap size we're going to claim. Not used by sparc.
-+   We allocate 1/4 of the available memory under 4G, up to this limit. */
- #ifdef __i386__
- #define HEAP_MAX_SIZE		(unsigned long) (64 * 1024 * 1024)
--#else
--#define HEAP_MAX_SIZE		(unsigned long) (32 * 1024 * 1024)
-+#else // __powerpc__
-+#define HEAP_MAX_SIZE		(unsigned long) (1 * 1024 * 1024 * 1024)
- #endif
- 
- extern char _end[];
-@@ -147,16 +148,45 @@ grub_claim_heap (void)
- 				 + GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000);
- }
- #else
--/* Helper for grub_claim_heap.  */
-+/* Helper for grub_claim_heap on powerpc. */
-+static int
-+heap_size (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
-+	   void *data)
-+{
-+  grub_uint32_t total = *(grub_uint32_t *)data;
-+
-+  if (type != GRUB_MEMORY_AVAILABLE)
-+    return 0;
-+
-+  /* Do not consider memory beyond 4GB */
-+  if (addr > 0xffffffffUL)
-+    return 0;
-+
-+  if (addr + len > 0xffffffffUL)
-+    len = 0xffffffffUL - addr;
-+
-+  total += len;
-+  *(grub_uint32_t *)data = total;
-+
-+  return 0;
-+}
-+
- static int
- heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
- 	   void *data)
- {
--  unsigned long *total = data;
-+  grub_uint32_t total = *(grub_uint32_t *)data;
- 
-   if (type != GRUB_MEMORY_AVAILABLE)
-     return 0;
- 
-+  /* Do not consider memory beyond 4GB */
-+  if (addr > 0xffffffffUL)
-+    return 0;
-+
-+  if (addr + len > 0xffffffffUL)
-+    len = 0xffffffffUL - addr;
-+
-   if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM))
-     {
-       if (addr + len <= 0x180000)
-@@ -170,10 +200,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
-     }
-   len -= 1; /* Required for some firmware.  */
- 
--  /* Never exceed HEAP_MAX_SIZE  */
--  if (*total + len > HEAP_MAX_SIZE)
--    len = HEAP_MAX_SIZE - *total;
--
-   /* In theory, firmware should already prevent this from happening by not
-      listing our own image in /memory/available.  The check below is intended
-      as a safeguard in case that doesn't happen.  However, it doesn't protect
-@@ -185,6 +211,18 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
-       len = 0;
-     }
- 
-+  /* If this block contains 0x30000000 (768MB), do not claim below that.
-+     Linux likes to claim memory at min(RMO top, 768MB) and works down
-+     without reference to /memory/available. */
-+  if ((addr < 0x30000000) && ((addr + len) > 0x30000000))
-+    {
-+      len = len - (0x30000000 - addr);
-+      addr = 0x30000000;
-+    }
-+
-+  if (len > total)
-+    len = total;
-+
-   if (len)
-     {
-       grub_err_t err;
-@@ -193,10 +231,12 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
-       if (err)
- 	return err;
-       grub_mm_init_region ((void *) (grub_addr_t) addr, len);
-+      total -= len;
-     }
- 
--  *total += len;
--  if (*total >= HEAP_MAX_SIZE)
-+  *(grub_uint32_t *)data = total;
-+
-+  if (total == 0)
-     return 1;
- 
-   return 0;
-@@ -205,13 +245,22 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
- static void 
- grub_claim_heap (void)
- {
--  unsigned long total = 0;
-+  grub_uint32_t total = 0;
- 
-   if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM))
--    heap_init (GRUB_IEEE1275_STATIC_HEAP_START, GRUB_IEEE1275_STATIC_HEAP_LEN,
--	       1, &total);
--  else
--    grub_machine_mmap_iterate (heap_init, &total);
-+    {
-+      heap_init (GRUB_IEEE1275_STATIC_HEAP_START, GRUB_IEEE1275_STATIC_HEAP_LEN,
-+		 1, &total);
-+      return;
-+    }
-+
-+  grub_machine_mmap_iterate (heap_size, &total);
-+
-+  total = total / 4;
-+  if (total > HEAP_MAX_SIZE)
-+    total = HEAP_MAX_SIZE;
-+
-+  grub_machine_mmap_iterate (heap_init, &total);
- }
- #endif
- 
-diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
-index 19f708ee662..90083772c8a 100644
---- a/docs/grub-dev.texi
-+++ b/docs/grub-dev.texi
-@@ -1047,7 +1047,9 @@ space is limited to 4GiB. GRUB allocates pages from EFI for its heap, at most
- 1.6 GiB.
- 
- On i386-ieee1275 and powerpc-ieee1275 GRUB uses same stack as IEEE1275.
--It allocates at most 32MiB for its heap.
-+
-+On i386-ieee1275, GRUB allocates at most 32MiB for its heap. On
-+powerpc-ieee1275, GRUB allocates up to 1GiB.
- 
- On sparc64-ieee1275 stack is 256KiB and heap is 2MiB.
- 
-@@ -1075,7 +1077,7 @@ In short:
- @item i386-qemu               @tab 60 KiB  @tab < 4 GiB
- @item *-efi                   @tab ?       @tab < 1.6 GiB
- @item i386-ieee1275           @tab ?       @tab < 32 MiB
--@item powerpc-ieee1275        @tab ?       @tab < 32 MiB
-+@item powerpc-ieee1275        @tab ?       @tab < 1 GiB
- @item sparc64-ieee1275        @tab 256KiB  @tab 2 MiB
- @item arm-uboot               @tab 256KiB  @tab 2 MiB
- @item mips(el)-qemu_mips      @tab 2MiB    @tab 253 MiB
diff --git a/SOURCES/0200-Drop-gnulib-fix-base64.patch.patch b/SOURCES/0200-Drop-gnulib-fix-base64.patch.patch
new file mode 100644
index 0000000..054e476
--- /dev/null
+++ b/SOURCES/0200-Drop-gnulib-fix-base64.patch.patch
@@ -0,0 +1,140 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Thu, 28 Oct 2021 15:07:50 -0400
+Subject: [PATCH] Drop gnulib fix-base64.patch
+
+Originally added in 9fbdec2f6b4fa8b549daa4d49134d1fe89d95ef9 and
+subsequently modified in 552c9fd08122a3036c724ce96dfe68aa2f75705f,
+fix-base64.patch handled two problems we have using gnulib, which are
+exerciesd by the base64 module but not directly caused by it.
+
+First, grub2 defines its own bool type, while gnulib expects the
+equivalent of stdbool.h to be present.  Rather than patching gnulib,
+instead use gnulib's stdbool module to provide a bool type if needed.
+(Suggested by Simon Josefsson.)
+
+Second, our config.h doesn't always inherit config-util.h, which is
+where gnulib-related options like _GL_ATTRIBUTE_CONST end up.
+fix-base64.h worked around this by defining the attribute away, but this
+workaround is better placed in config.h itself, not a gnulib patch.
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+(cherry picked from commit 54fd1c3301dd15f6b6212c12887265e8a6cbc076)
+---
+ grub-core/lib/posix_wrap/sys/types.h          |  7 +++----
+ grub-core/lib/xzembed/xz.h                    |  5 +----
+ bootstrap.conf                                |  3 ++-
+ conf/Makefile.extra-dist                      |  1 -
+ config.h.in                                   |  4 ++++
+ grub-core/lib/gnulib-patches/fix-base64.patch | 21 ---------------------
+ 6 files changed, 10 insertions(+), 31 deletions(-)
+ delete mode 100644 grub-core/lib/gnulib-patches/fix-base64.patch
+
+diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h
+index f63412c8da..2f3e865495 100644
+--- a/grub-core/lib/posix_wrap/sys/types.h
++++ b/grub-core/lib/posix_wrap/sys/types.h
+@@ -23,11 +23,10 @@
+ 
+ #include <stddef.h>
+ 
++/* Provided by gnulib if not present. */
++#include <stdbool.h>
++
+ typedef grub_ssize_t ssize_t;
+-#ifndef GRUB_POSIX_BOOL_DEFINED
+-typedef enum { false = 0, true = 1 } bool;
+-#define GRUB_POSIX_BOOL_DEFINED 1
+-#endif
+ 
+ typedef grub_uint8_t uint8_t;
+ typedef grub_uint16_t uint16_t;
+diff --git a/grub-core/lib/xzembed/xz.h b/grub-core/lib/xzembed/xz.h
+index f7b32d8003..d1417039aa 100644
+--- a/grub-core/lib/xzembed/xz.h
++++ b/grub-core/lib/xzembed/xz.h
+@@ -29,10 +29,7 @@
+ #include <unistd.h>
+ #include <string.h>
+ #include <grub/misc.h>
+-
+-#ifndef GRUB_POSIX_BOOL_DEFINED
+-typedef enum { false = 0, true = 1 } bool;
+-#endif
++#include <stdbool.h>
+ 
+ /**
+  * enum xz_ret - Return codes
+diff --git a/bootstrap.conf b/bootstrap.conf
+index 52d4af44be..645e3a459c 100644
+--- a/bootstrap.conf
++++ b/bootstrap.conf
+@@ -35,6 +35,7 @@ gnulib_modules="
+   realloc-gnu
+   regex
+   save-cwd
++  stdbool
+ "
+ 
+ gnulib_tool_option_extras="\
+@@ -79,7 +80,7 @@ cp -a INSTALL INSTALL.grub
+ 
+ bootstrap_post_import_hook () {
+   set -e
+-  for patchname in fix-base64 fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \
++  for patchname in fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \
+       fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width no-abort; do
+     patch -d grub-core/lib/gnulib -p2 \
+       < "grub-core/lib/gnulib-patches/$patchname.patch"
+diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist
+index ad235de7fc..f4791dc6ca 100644
+--- a/conf/Makefile.extra-dist
++++ b/conf/Makefile.extra-dist
+@@ -31,7 +31,6 @@ EXTRA_DIST += grub-core/gensymlist.sh
+ EXTRA_DIST += grub-core/genemuinit.sh
+ EXTRA_DIST += grub-core/genemuinitheader.sh
+ 
+-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-base64.patch
+ EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-deref.patch
+ EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-state-deref.patch
+ EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch
+diff --git a/config.h.in b/config.h.in
+index f2ed0066ec..9c7b4afaaa 100644
+--- a/config.h.in
++++ b/config.h.in
+@@ -66,4 +66,8 @@
+ 
+ #  define _GNU_SOURCE 1
+ 
++#  ifndef _GL_INLINE_HEADER_BEGIN
++#    define _GL_ATTRIBUTE_CONST __attribute__ ((const))
++#  endif /* !_GL_INLINE_HEADER_BEGIN */
++
+ #endif
+diff --git a/grub-core/lib/gnulib-patches/fix-base64.patch b/grub-core/lib/gnulib-patches/fix-base64.patch
+deleted file mode 100644
+index 985db12797..0000000000
+--- a/grub-core/lib/gnulib-patches/fix-base64.patch
++++ /dev/null
+@@ -1,21 +0,0 @@
+-diff --git a/lib/base64.h b/lib/base64.h
+-index 9cd0183b8..185a2afa1 100644
+---- a/lib/base64.h
+-+++ b/lib/base64.h
+-@@ -21,8 +21,14 @@
+- /* Get size_t. */
+- # include <stddef.h>
+- 
+--/* Get bool. */
+--# include <stdbool.h>
+-+#ifndef GRUB_POSIX_BOOL_DEFINED
+-+typedef enum { false = 0, true = 1 } bool;
+-+#define GRUB_POSIX_BOOL_DEFINED 1
+-+#endif
+-+
+-+#ifndef _GL_ATTRIBUTE_CONST
+-+# define _GL_ATTRIBUTE_CONST /* empty */
+-+#endif
+- 
+- # ifdef __cplusplus
+- extern "C" {
diff --git a/SOURCES/0200-ieee1275-request-memory-with-ibm-client-architecture.patch b/SOURCES/0200-ieee1275-request-memory-with-ibm-client-architecture.patch
deleted file mode 100644
index 6e6c1f0..0000000
--- a/SOURCES/0200-ieee1275-request-memory-with-ibm-client-architecture.patch
+++ /dev/null
@@ -1,268 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Fri, 16 Apr 2021 11:48:46 +1000
-Subject: [PATCH] ieee1275: request memory with ibm,client-architecture-support
-
-On PowerVM, the first time we boot a Linux partition, we may only get
-256MB of real memory area, even if the partition has more memory.
-
-This isn't really enough. Fortunately, the Power Architecture Platform
-Reference (PAPR) defines a method we can call to ask for more memory.
-This is part of the broad and powerful ibm,client-architecture-support
-(CAS) method.
-
-CAS can do an enormous amount of things on a PAPR platform: as well as
-asking for memory, you can set the supported processor level, the interrupt
-controller, hash vs radix mmu, and so on. We want to touch as little of
-this as possible because we don't want to step on the toes of the future OS.
-
-If:
-
- - we are running under what we think is PowerVM (compatible property of /
-   begins with "IBM"), and
-
- - the full amount of RMA is less than 512MB (as determined by the reg
-   property of /memory)
-
-then call CAS as follows: (refer to the Linux on Power Architecture
-Reference, LoPAR, which is public, at B.5.2.3):
-
- - Use the "any" PVR value and supply 2 option vectors.
-
- - Set option vector 1 (PowerPC Server Processor Architecture Level)
-   to "ignore".
-
- - Set option vector 2 with default or Linux-like options, including a
-   min-rma-size of 512MB.
-
-This will cause a CAS reboot and the partition will restart with 512MB
-of RMA. Grub will notice the 512MB and not call CAS again.
-
-(A partition can be configured with only 256MB of memory, which would
-mean this request couldn't be satisfied, but PFW refuses to load with
-only 256MB of memory, so it's a bit moot. SLOF will run fine with 256MB,
-but we will never call CAS under qemu/SLOF because /compatible won't
-begin with "IBM".)
-
-One of the first things Linux does while still running under OpenFirmware
-is to call CAS with a much fuller set of options (including asking for
-512MB of memory). This includes a much more restrictive set of PVR values
-and processor support levels, and this will induce another reboot. On this
-reboot grub will again notice the higher RMA, and not call CAS. We will get
-to Linux, Linux will call CAS but because the values are now set for Linux
-this will not induce another CAS reboot and we will finally boot.
-
-On all subsequent boots, everything will be configured with 512MB of RMA
-and all the settings Linux likes, so there will be no further CAS reboots.
-
-(phyp is super sticky with the RMA size - it persists even on cold boots.
-So if you've ever booted Linux in a partition, you'll probably never have
-grub call CAS. It'll only ever fire the first time a partition loads grub,
-or if you deliberately lower the amount of memory your partition has below
-512MB.)
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/kern/ieee1275/cmain.c  |   3 +
- grub-core/kern/ieee1275/init.c   | 144 ++++++++++++++++++++++++++++++++++++++-
- include/grub/ieee1275/ieee1275.h |   8 ++-
- 3 files changed, 152 insertions(+), 3 deletions(-)
-
-diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c
-index 04df9d2c667..6435628ec57 100644
---- a/grub-core/kern/ieee1275/cmain.c
-+++ b/grub-core/kern/ieee1275/cmain.c
-@@ -127,6 +127,9 @@ grub_ieee1275_find_options (void)
- 	      break;
- 	    }
- 	}
-+
-+      if (grub_strncmp (tmp, "IBM,", 4) == 0)
-+	grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY);
-     }
- 
-   if (is_smartfirmware)
-diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
-index c61d91a0285..9704715c837 100644
---- a/grub-core/kern/ieee1275/init.c
-+++ b/grub-core/kern/ieee1275/init.c
-@@ -242,6 +242,135 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
-   return 0;
- }
- 
-+/* How much memory does OF believe it has? (regardless of whether
-+   it's accessible or not) */
-+static grub_err_t
-+grub_ieee1275_total_mem (grub_uint64_t *total)
-+{
-+  grub_ieee1275_phandle_t root;
-+  grub_ieee1275_phandle_t memory;
-+  grub_uint32_t reg[4];
-+  grub_ssize_t reg_size;
-+  grub_uint32_t address_cells = 1;
-+  grub_uint32_t size_cells = 1;
-+  grub_uint64_t size;
-+
-+  /* If we fail to get to the end, report 0. */
-+  *total = 0;
-+
-+  /* Determine the format of each entry in `reg'.  */
-+  grub_ieee1275_finddevice ("/", &root);
-+  grub_ieee1275_get_integer_property (root, "#address-cells", &address_cells,
-+				      sizeof address_cells, 0);
-+  grub_ieee1275_get_integer_property (root, "#size-cells", &size_cells,
-+				      sizeof size_cells, 0);
-+
-+  if (size_cells > address_cells)
-+    address_cells = size_cells;
-+
-+  /* Load `/memory/reg'.  */
-+  if (grub_ieee1275_finddevice ("/memory", &memory))
-+    return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
-+		       "couldn't find /memory node");
-+  if (grub_ieee1275_get_integer_property (memory, "reg", reg,
-+					  sizeof reg, &reg_size))
-+    return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
-+		       "couldn't examine /memory/reg property");
-+  if (reg_size < 0 || (grub_size_t) reg_size > sizeof (reg))
-+    return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
-+                       "/memory response buffer exceeded");
-+
-+  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS))
-+    {
-+      address_cells = 1;
-+      size_cells = 1;
-+    }
-+
-+  /* Decode only the size */
-+  size = reg[address_cells];
-+  if (size_cells == 2)
-+    size = (size << 32) | reg[address_cells + 1];
-+
-+  *total = size;
-+
-+  return grub_errno;
-+}
-+
-+/* Based on linux - arch/powerpc/kernel/prom_init.c */
-+struct option_vector2 {
-+	grub_uint8_t byte1;
-+	grub_uint16_t reserved;
-+	grub_uint32_t real_base;
-+	grub_uint32_t real_size;
-+	grub_uint32_t virt_base;
-+	grub_uint32_t virt_size;
-+	grub_uint32_t load_base;
-+	grub_uint32_t min_rma;
-+	grub_uint32_t min_load;
-+	grub_uint8_t min_rma_percent;
-+	grub_uint8_t max_pft_size;
-+} __attribute__((packed));
-+
-+struct pvr_entry {
-+	  grub_uint32_t mask;
-+	  grub_uint32_t entry;
-+};
-+
-+struct cas_vector {
-+    struct {
-+      struct pvr_entry terminal;
-+    } pvr_list;
-+    grub_uint8_t num_vecs;
-+    grub_uint8_t vec1_size;
-+    grub_uint8_t vec1;
-+    grub_uint8_t vec2_size;
-+    struct option_vector2 vec2;
-+} __attribute__((packed));
-+
-+/* Call ibm,client-architecture-support to try to get more RMA.
-+   We ask for 512MB which should be enough to verify a distro kernel.
-+   We ignore most errors: if we don't succeed we'll proceed with whatever
-+   memory we have. */
-+static void
-+grub_ieee1275_ibm_cas (void)
-+{
-+  int rc;
-+  grub_ieee1275_ihandle_t root;
-+  struct cas_args {
-+    struct grub_ieee1275_common_hdr common;
-+    grub_ieee1275_cell_t method;
-+    grub_ieee1275_ihandle_t ihandle;
-+    grub_ieee1275_cell_t cas_addr;
-+    grub_ieee1275_cell_t result;
-+  } args;
-+  struct cas_vector vector = {
-+    .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */
-+    .num_vecs = 2 - 1,
-+    .vec1_size = 0,
-+    .vec1 = 0x80, /* ignore */
-+    .vec2_size = 1 + sizeof(struct option_vector2) - 2,
-+    .vec2 = {
-+      0, 0, -1, -1, -1, -1, -1, 512, -1, 0, 48
-+    },
-+  };
-+
-+  INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2);
-+  args.method = (grub_ieee1275_cell_t)"ibm,client-architecture-support";
-+  rc = grub_ieee1275_open("/", &root);
-+  if (rc) {
-+	  grub_error (GRUB_ERR_IO, "could not open root when trying to call CAS");
-+	  return;
-+  }
-+  args.ihandle = root;
-+  args.cas_addr = (grub_ieee1275_cell_t)&vector;
-+
-+  grub_printf("Calling ibm,client-architecture-support...");
-+  IEEE1275_CALL_ENTRY_FN (&args);
-+  grub_printf("done\n");
-+
-+  grub_ieee1275_close(root);
-+}
-+
- static void 
- grub_claim_heap (void)
- {
-@@ -249,11 +378,22 @@ grub_claim_heap (void)
- 
-   if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM))
-     {
--      heap_init (GRUB_IEEE1275_STATIC_HEAP_START, GRUB_IEEE1275_STATIC_HEAP_LEN,
--		 1, &total);
-+      heap_init (GRUB_IEEE1275_STATIC_HEAP_START,
-+		 GRUB_IEEE1275_STATIC_HEAP_LEN, 1, &total);
-       return;
-     }
- 
-+  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY))
-+    {
-+      grub_uint64_t rma_size;
-+      grub_err_t err;
-+
-+      err = grub_ieee1275_total_mem (&rma_size);
-+      /* if we have an error, don't call CAS, just hope for the best */
-+      if (!err && rma_size < (512 * 1024 * 1024))
-+	grub_ieee1275_ibm_cas();
-+    }
-+
-   grub_machine_mmap_iterate (heap_size, &total);
- 
-   total = total / 4;
-diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
-index b5a1d49bbc3..e0a6c2ce1e6 100644
---- a/include/grub/ieee1275/ieee1275.h
-+++ b/include/grub/ieee1275/ieee1275.h
-@@ -149,7 +149,13 @@ enum grub_ieee1275_flag
- 
-   GRUB_IEEE1275_FLAG_RAW_DEVNAMES,
-   
--  GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT
-+  GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT,
-+
-+  /* On PFW, the first time we boot a Linux partition, we may only get 256MB
-+     of real memory area, even if the partition has more memory. Set this flag
-+     if we think we're running under PFW. Then, if this flag is set, and the
-+     RMA is only 256MB in size, try asking for more with CAS. */
-+  GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY,
- };
- 
- extern int EXPORT_FUNC(grub_ieee1275_test_flag) (enum grub_ieee1275_flag flag);
diff --git a/SOURCES/0201-Drop-gnulib-no-abort.patch.patch b/SOURCES/0201-Drop-gnulib-no-abort.patch.patch
new file mode 100644
index 0000000..a12789f
--- /dev/null
+++ b/SOURCES/0201-Drop-gnulib-no-abort.patch.patch
@@ -0,0 +1,97 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Wed, 5 Jan 2022 16:42:11 -0500
+Subject: [PATCH] Drop gnulib no-abort.patch
+
+Originally added in db7337a3d353a817ffe9eb4a3702120527100be9, this
+patched out all relevant invocations of abort() in gnulib.  While it was
+not documented why at the time, testing suggests that there's no abort()
+implementation available for gnulib to use.
+
+gnulib's position is that the use of abort() is correct here, since it
+happens when input violates a "shall" from POSIX.  Additionally, the
+code in question is probably not reachable.  Since abort() is more
+friendly to user-space, they prefer to make no change, so we can just
+carry a define instead.  (Suggested by Paul Eggert.)
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+(cherry picked from commit 5137c8eb3ec11c3217acea1a93a3f88f3fa4cbca)
+---
+ bootstrap.conf                              |  2 +-
+ conf/Makefile.extra-dist                    |  1 -
+ config.h.in                                 |  3 +++
+ grub-core/lib/gnulib-patches/no-abort.patch | 26 --------------------------
+ 4 files changed, 4 insertions(+), 28 deletions(-)
+ delete mode 100644 grub-core/lib/gnulib-patches/no-abort.patch
+
+diff --git a/bootstrap.conf b/bootstrap.conf
+index 645e3a459c..71ce943c7d 100644
+--- a/bootstrap.conf
++++ b/bootstrap.conf
+@@ -81,7 +81,7 @@ cp -a INSTALL INSTALL.grub
+ bootstrap_post_import_hook () {
+   set -e
+   for patchname in fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \
+-      fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width no-abort; do
++      fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width; do
+     patch -d grub-core/lib/gnulib -p2 \
+       < "grub-core/lib/gnulib-patches/$patchname.patch"
+   done
+diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist
+index f4791dc6ca..5eef708338 100644
+--- a/conf/Makefile.extra-dist
++++ b/conf/Makefile.extra-dist
+@@ -38,7 +38,6 @@ EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch
+ EXTRA_DIST += grub-core/lib/gnulib-patches/fix-uninit-structure.patch
+ EXTRA_DIST += grub-core/lib/gnulib-patches/fix-unused-value.patch
+ EXTRA_DIST += grub-core/lib/gnulib-patches/fix-width.patch
+-EXTRA_DIST += grub-core/lib/gnulib-patches/no-abort.patch
+ 
+ EXTRA_DIST += grub-core/lib/libgcrypt
+ EXTRA_DIST += grub-core/lib/libgcrypt-grub/mpi/generic
+diff --git a/config.h.in b/config.h.in
+index 9c7b4afaaa..c3134309c6 100644
+--- a/config.h.in
++++ b/config.h.in
+@@ -68,6 +68,9 @@
+ 
+ #  ifndef _GL_INLINE_HEADER_BEGIN
+ #    define _GL_ATTRIBUTE_CONST __attribute__ ((const))
++
++/* We don't have an abort() for gnulib to call in regexp. */
++#    define abort __builtin_unreachable
+ #  endif /* !_GL_INLINE_HEADER_BEGIN */
+ 
+ #endif
+diff --git a/grub-core/lib/gnulib-patches/no-abort.patch b/grub-core/lib/gnulib-patches/no-abort.patch
+deleted file mode 100644
+index e469c4762e..0000000000
+--- a/grub-core/lib/gnulib-patches/no-abort.patch
++++ /dev/null
+@@ -1,26 +0,0 @@
+-diff --git a/lib/regcomp.c b/lib/regcomp.c
+-index cc85f35ac..de45ebb5c 100644
+---- a/lib/regcomp.c
+-+++ b/lib/regcomp.c
+-@@ -528,9 +528,9 @@ regerror (int errcode, const regex_t *__restrict preg, char *__restrict errbuf,
+-        to this routine.  If we are given anything else, or if other regex
+-        code generates an invalid error code, then the program has a bug.
+-        Dump core so we can fix it.  */
+--    abort ();
+--
+--  msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]);
+-+    msg = gettext ("unknown regexp error");
+-+  else
+-+    msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]);
+- 
+-   msg_size = strlen (msg) + 1; /* Includes the null.  */
+- 
+-@@ -1136,7 +1136,7 @@ optimize_utf8 (re_dfa_t *dfa)
+- 	}
+- 	break;
+-       default:
+--	abort ();
+-+	break;
+-       }
+- 
+-   if (mb_chars || has_period)
diff --git a/SOURCES/0201-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch b/SOURCES/0201-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch
deleted file mode 100644
index a237a21..0000000
--- a/SOURCES/0201-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch
+++ /dev/null
@@ -1,315 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Sat, 8 May 2021 02:27:58 +0200
-Subject: [PATCH] appendedsig/x509: Also handle the Extended Key Usage
- extension
-
-Red Hat certificates have both Key Usage and Extended Key Usage extensions
-present, but the appended signatures x509 parser doesn't handle the latter
-and so buils due finding an unrecognised critical extension:
-
-Error loading initial key:
-../../grub-core/commands/appendedsig/x509.c:780:Unhandled critical x509 extension with OID 2.5.29.37
-
-Fix this by also parsing the Extended Key Usage extension and handle it by
-verifying that the certificate has a single purpose, that is code signing.
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/commands/appendedsig/x509.c     | 94 ++++++++++++++++++++++++++++++-
- grub-core/tests/appended_signature_test.c | 29 +++++++++-
- grub-core/tests/appended_signatures.h     | 81 ++++++++++++++++++++++++++
- 3 files changed, 201 insertions(+), 3 deletions(-)
-
-diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c
-index 2b38b3670a2..42ec65c54aa 100644
---- a/grub-core/commands/appendedsig/x509.c
-+++ b/grub-core/commands/appendedsig/x509.c
-@@ -47,6 +47,12 @@ const char *keyUsage_oid = "2.5.29.15";
-  */
- const char *basicConstraints_oid = "2.5.29.19";
- 
-+/*
-+ * RFC 5280 4.2.1.12 Extended Key Usage
-+ */
-+const char *extendedKeyUsage_oid = "2.5.29.37";
-+const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3";
-+
- /*
-  * RFC 3279 2.3.1
-  *
-@@ -637,6 +643,77 @@ cleanup:
-   return err;
- }
- 
-+/*
-+ * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
-+ *
-+ * KeyPurposeId ::= OBJECT IDENTIFIER
-+ */
-+static grub_err_t
-+verify_extended_key_usage (grub_uint8_t * value, int value_size)
-+{
-+  asn1_node extendedasn;
-+  int result, count;
-+  grub_err_t err = GRUB_ERR_NONE;
-+  char usage[MAX_OID_LEN];
-+  int usage_size = sizeof (usage);
-+
-+  result =
-+    asn1_create_element (_gnutls_pkix_asn, "PKIX1.ExtKeyUsageSyntax",
-+			 &extendedasn);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+			 "Could not create ASN.1 structure for Extended Key Usage");
-+    }
-+
-+  result = asn1_der_decoding2 (&extendedasn, value, &value_size,
-+			       ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Error parsing DER for Extended Key Usage: %s",
-+		    asn1_error);
-+      goto cleanup;
-+    }
-+
-+  /*
-+   * If EKUs are present, there must be exactly 1 and it must be a
-+   * codeSigning usage.
-+   */
-+  result = asn1_number_of_elements(extendedasn, "", &count);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Error counting number of Extended Key Usages: %s",
-+		    asn1_strerror (result));
-+      goto cleanup;
-+    }
-+
-+  result = asn1_read_value (extendedasn, "?1", usage, &usage_size);
-+  if (result != ASN1_SUCCESS)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Error reading Extended Key Usage: %s",
-+		    asn1_strerror (result));
-+      goto cleanup;
-+    }
-+
-+  if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) != 0)
-+    {
-+      err =
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "Unexpected Extended Key Usage OID, got: %s",
-+		    usage);
-+      goto cleanup;
-+    }
-+
-+cleanup:
-+  asn1_delete_structure (&extendedasn);
-+  return err;
-+}
- 
- /*
-  * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
-@@ -660,7 +737,7 @@ verify_extensions (asn1_node cert)
- {
-   int result;
-   int ext, num_extensions = 0;
--  int usage_present = 0, constraints_present = 0;
-+  int usage_present = 0, constraints_present = 0, extended_usage_present = 0;
-   char *oid_path, *critical_path, *value_path;
-   char extnID[MAX_OID_LEN];
-   int extnID_size;
-@@ -754,6 +831,15 @@ verify_extensions (asn1_node cert)
- 	    }
- 	  constraints_present++;
- 	}
-+      else if (grub_strncmp (extendedKeyUsage_oid, extnID, extnID_size) == 0)
-+	{
-+	  err = verify_extended_key_usage (value, value_size);
-+	  if (err != GRUB_ERR_NONE)
-+	    {
-+	      goto cleanup_value;
-+	    }
-+	  extended_usage_present++;
-+	}
-       else if (grub_strncmp ("TRUE", critical, critical_size) == 0)
- 	{
- 	  /*
-@@ -785,6 +871,12 @@ verify_extensions (asn1_node cert)
- 			 "Unexpected number of basic constraints extensions - expected 1, got %d",
- 			 constraints_present);
-     }
-+  if (extended_usage_present > 1)
-+    {
-+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			 "Unexpected number of Extended Key Usage extensions - expected 0 or 1, got %d",
-+			 extended_usage_present);
-+    }
-   return GRUB_ERR_NONE;
- 
- cleanup_value:
-diff --git a/grub-core/tests/appended_signature_test.c b/grub-core/tests/appended_signature_test.c
-index 88a485200d8..dbba0616621 100644
---- a/grub-core/tests/appended_signature_test.c
-+++ b/grub-core/tests/appended_signature_test.c
-@@ -111,6 +111,22 @@ static struct grub_procfs_entry certificate_printable_der_entry = {
-   .get_contents = get_certificate_printable_der
- };
- 
-+static char *
-+get_certificate_eku_der (grub_size_t * sz)
-+{
-+  char *ret;
-+  *sz = certificate_eku_der_len;
-+  ret = grub_malloc (*sz);
-+  if (ret)
-+    grub_memcpy (ret, certificate_eku_der, *sz);
-+  return ret;
-+}
-+
-+static struct grub_procfs_entry certificate_eku_der_entry = {
-+  .name = "certificate_eku.der",
-+  .get_contents = get_certificate_eku_der
-+};
-+
- 
- static void
- do_verify (const char *f, int is_valid)
-@@ -149,6 +165,7 @@ appended_signature_test (void)
-   char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL };
-   char *trust_args_printable[] = { (char *) "(proc)/certificate_printable.der",
- 				   NULL };
-+  char *trust_args_eku[] = { (char *) "(proc)/certificate_eku.der", NULL };
-   char *distrust_args[] = { (char *) "1", NULL };
-   char *distrust2_args[] = { (char *) "2", NULL };
-   grub_err_t err;
-@@ -157,6 +174,7 @@ appended_signature_test (void)
-   grub_procfs_register ("certificate2.der", &certificate2_der_entry);
-   grub_procfs_register ("certificate_printable.der",
- 			&certificate_printable_der_entry);
-+  grub_procfs_register ("certificate_eku.der", &certificate_eku_der_entry);
- 
-   cmd_trust = grub_command_find ("trust_certificate");
-   if (!cmd_trust)
-@@ -266,16 +284,23 @@ appended_signature_test (void)
- 
-   /*
-    * Lastly, check a certificate that uses printableString rather than
--   * utf8String loads properly.
-+   * utf8String loads properly, and that a certificate with an appropriate
-+   * extended key usage loads.
-    */
-   err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable);
-   grub_test_assert (err == GRUB_ERR_NONE,
--		    "distrusting printable certificate failed: %d: %s",
-+		    "trusting printable certificate failed: %d: %s",
-+		    grub_errno, grub_errmsg);
-+
-+  err = (cmd_trust->func) (cmd_trust, 1, trust_args_eku);
-+  grub_test_assert (err == GRUB_ERR_NONE,
-+		    "trusting certificate with extended key usage failed: %d: %s",
- 		    grub_errno, grub_errmsg);
- 
-   grub_procfs_unregister (&certificate_der_entry);
-   grub_procfs_unregister (&certificate2_der_entry);
-   grub_procfs_unregister (&certificate_printable_der_entry);
-+  grub_procfs_unregister (&certificate_eku_der_entry);
- }
- 
- GRUB_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test);
-diff --git a/grub-core/tests/appended_signatures.h b/grub-core/tests/appended_signatures.h
-index aa3dc6278e3..2e5ebd7d8bd 100644
---- a/grub-core/tests/appended_signatures.h
-+++ b/grub-core/tests/appended_signatures.h
-@@ -555,3 +555,84 @@ unsigned char certificate_printable_der[] = {
-   0xd2
- };
- unsigned int certificate_printable_der_len = 829;
-+
-+unsigned char certificate_eku_der[] = {
-+  0x30, 0x82, 0x03, 0x90, 0x30, 0x82, 0x02, 0x78, 0xa0, 0x03, 0x02, 0x01,
-+  0x02, 0x02, 0x09, 0x00, 0xd3, 0x9c, 0x41, 0x33, 0xdd, 0x6b, 0x5f, 0x45,
-+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-+  0x0b, 0x05, 0x00, 0x30, 0x47, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-+  0x04, 0x03, 0x0c, 0x18, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20,
-+  0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20,
-+  0x43, 0x41, 0x20, 0x36, 0x31, 0x22, 0x30, 0x20, 0x06, 0x09, 0x2a, 0x86,
-+  0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x13, 0x73, 0x65, 0x63,
-+  0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65, 0x64, 0x68, 0x61, 0x74,
-+  0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x32,
-+  0x31, 0x35, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a, 0x17, 0x0d, 0x33,
-+  0x38, 0x30, 0x31, 0x31, 0x37, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a,
-+  0x30, 0x4e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
-+  0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63,
-+  0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67,
-+  0x6e, 0x69, 0x6e, 0x67, 0x20, 0x36, 0x30, 0x32, 0x31, 0x22, 0x30, 0x20,
-+  0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
-+  0x13, 0x73, 0x65, 0x63, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65,
-+  0x64, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22,
-+  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-+  0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
-+  0x02, 0x82, 0x01, 0x01, 0x00, 0xaa, 0x6f, 0xbb, 0x92, 0x77, 0xd7, 0x15,
-+  0xef, 0x88, 0x80, 0x88, 0xc0, 0xe7, 0x89, 0xeb, 0x35, 0x76, 0xf4, 0x85,
-+  0x05, 0x0f, 0x19, 0xe4, 0x5f, 0x25, 0xdd, 0xc1, 0xa2, 0xe5, 0x5c, 0x06,
-+  0xfb, 0xf1, 0x06, 0xb5, 0x65, 0x45, 0xcb, 0xbd, 0x19, 0x33, 0x54, 0xb5,
-+  0x1a, 0xcd, 0xe4, 0xa8, 0x35, 0x2a, 0xfe, 0x9c, 0x53, 0xf4, 0xc6, 0x76,
-+  0xdb, 0x1f, 0x8a, 0xd4, 0x7b, 0x18, 0x11, 0xaf, 0xa3, 0x90, 0xd4, 0xdd,
-+  0x4d, 0xd5, 0x42, 0xcc, 0x14, 0x9a, 0x64, 0x6b, 0xc0, 0x7f, 0xaa, 0x1c,
-+  0x94, 0x47, 0x4d, 0x79, 0xbd, 0x57, 0x9a, 0xbf, 0x99, 0x4e, 0x96, 0xa9,
-+  0x31, 0x2c, 0xa9, 0xe7, 0x14, 0x65, 0x86, 0xc8, 0xac, 0x79, 0x5e, 0x78,
-+  0xa4, 0x3c, 0x00, 0x24, 0xd3, 0xf7, 0xe1, 0xf5, 0x12, 0xad, 0xa0, 0x29,
-+  0xe5, 0xfe, 0x80, 0xae, 0xf8, 0xaa, 0x60, 0x36, 0xe7, 0xe8, 0x94, 0xcb,
-+  0xe9, 0xd1, 0xcc, 0x0b, 0x4d, 0xf7, 0xde, 0xeb, 0x52, 0xd2, 0x73, 0x09,
-+  0x28, 0xdf, 0x48, 0x99, 0x53, 0x9f, 0xc5, 0x9a, 0xd4, 0x36, 0xa3, 0xc6,
-+  0x5e, 0x8d, 0xbe, 0xd5, 0xdc, 0x76, 0xb4, 0x74, 0xb8, 0x26, 0x18, 0x27,
-+  0xfb, 0xf2, 0xfb, 0xd0, 0x9b, 0x3d, 0x7f, 0x10, 0xe2, 0xab, 0x44, 0xc7,
-+  0x88, 0x7f, 0xb4, 0x3d, 0x3e, 0xa3, 0xff, 0x6d, 0x06, 0x4b, 0x3e, 0x55,
-+  0xb2, 0x84, 0xf4, 0xad, 0x54, 0x88, 0x81, 0xc3, 0x9c, 0xf8, 0xb6, 0x68,
-+  0x96, 0x38, 0x8b, 0xcd, 0x90, 0x6d, 0x25, 0x4b, 0xbf, 0x0c, 0x44, 0x90,
-+  0xa5, 0x5b, 0x98, 0xd0, 0x40, 0x2f, 0xbb, 0x0d, 0xa8, 0x4b, 0x8a, 0x62,
-+  0x82, 0x46, 0x46, 0x18, 0x38, 0xae, 0x82, 0x07, 0xd0, 0xb4, 0x2f, 0x16,
-+  0x79, 0x55, 0x9f, 0x1b, 0xc5, 0x08, 0x6d, 0x85, 0xdf, 0x3f, 0xa9, 0x9b,
-+  0x4b, 0xc6, 0x28, 0xd3, 0x58, 0x72, 0x3d, 0x37, 0x11, 0x02, 0x03, 0x01,
-+  0x00, 0x01, 0xa3, 0x78, 0x30, 0x76, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d,
-+  0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03,
-+  0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80,
-+  0x30, 0x16, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 0x0c,
-+  0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03,
-+  0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x6c,
-+  0xe4, 0x6c, 0x27, 0xaa, 0xcd, 0x0d, 0x4b, 0x74, 0x21, 0xa4, 0xf6, 0x5f,
-+  0x87, 0xb5, 0x31, 0xfe, 0x10, 0xbb, 0xa7, 0x30, 0x1f, 0x06, 0x03, 0x55,
-+  0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe8, 0x6a, 0x1c, 0xab,
-+  0x2c, 0x48, 0xf9, 0x60, 0x36, 0xa2, 0xf0, 0x7b, 0x8e, 0xd2, 0x9d, 0xb4,
-+  0x2a, 0x28, 0x98, 0xc8, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
-+  0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
-+  0x55, 0x34, 0xe2, 0xfa, 0xf6, 0x89, 0x86, 0xad, 0x92, 0x21, 0xec, 0xb9,
-+  0x54, 0x0e, 0x18, 0x47, 0x0d, 0x1b, 0xa7, 0x58, 0xad, 0x69, 0xe4, 0xef,
-+  0x3b, 0xe6, 0x8d, 0xdd, 0xda, 0x0c, 0x45, 0xf6, 0xe8, 0x96, 0xa4, 0x29,
-+  0x0f, 0xbb, 0xcf, 0x16, 0xae, 0x93, 0xd0, 0xcb, 0x2a, 0x26, 0x1a, 0x7b,
-+  0xfc, 0x51, 0x22, 0x76, 0x98, 0x31, 0xa7, 0x0f, 0x29, 0x35, 0x79, 0xbf,
-+  0xe2, 0x4f, 0x0f, 0x14, 0xf5, 0x1f, 0xcb, 0xbf, 0x87, 0x65, 0x13, 0x32,
-+  0xa3, 0x19, 0x4a, 0xd1, 0x3f, 0x45, 0xd4, 0x4b, 0xe2, 0x00, 0x26, 0xa9,
-+  0x3e, 0xd7, 0xa5, 0x37, 0x9f, 0xf5, 0xad, 0x61, 0xe2, 0x40, 0xa9, 0x74,
-+  0x24, 0x53, 0xf2, 0x78, 0xeb, 0x10, 0x9b, 0x2c, 0x27, 0x88, 0x46, 0xcb,
-+  0xe4, 0x60, 0xca, 0xf5, 0x06, 0x24, 0x40, 0x2a, 0x97, 0x3a, 0xcc, 0xd0,
-+  0x81, 0xb1, 0x15, 0xa3, 0x4f, 0xd0, 0x2b, 0x4f, 0xca, 0x6e, 0xaa, 0x24,
-+  0x31, 0xb3, 0xac, 0xa6, 0x75, 0x05, 0xfe, 0x8a, 0xf4, 0x41, 0xc4, 0x06,
-+  0x8a, 0xc7, 0x0a, 0x83, 0x4e, 0x49, 0xd4, 0x3f, 0x83, 0x50, 0xec, 0x57,
-+  0x04, 0x97, 0x14, 0x49, 0xf5, 0xe1, 0xb1, 0x7a, 0x9c, 0x09, 0x4f, 0x61,
-+  0x87, 0xc3, 0x97, 0x22, 0x17, 0xc2, 0xeb, 0xcc, 0x32, 0x81, 0x31, 0x21,
-+  0x3f, 0x10, 0x57, 0x5b, 0x43, 0xbe, 0xcd, 0x68, 0x82, 0xbe, 0xe5, 0xc1,
-+  0x65, 0x94, 0x7e, 0xc2, 0x34, 0x76, 0x2b, 0xcf, 0x89, 0x3c, 0x2b, 0x81,
-+  0x23, 0x72, 0x95, 0xcf, 0xc9, 0x67, 0x19, 0x2a, 0xd5, 0x5c, 0xca, 0xa3,
-+  0x46, 0xbd, 0x48, 0x06, 0x0b, 0xa6, 0xa3, 0x96, 0x50, 0x28, 0xc7, 0x7e,
-+  0xcf, 0x62, 0xf2, 0xfa, 0xc4, 0xf2, 0x53, 0xe3, 0xc9, 0xe8, 0x2e, 0xdd,
-+  0x29, 0x37, 0x07, 0x47, 0xff, 0xff, 0x8a, 0x32, 0xbd, 0xa2, 0xb7, 0x21,
-+  0x89, 0xa0, 0x55, 0xf7
-+};
-+unsigned int certificate_eku_der_len = 916;
diff --git a/SOURCES/0202-Update-gnulib-version-and-drop-most-gnulib-patches.patch b/SOURCES/0202-Update-gnulib-version-and-drop-most-gnulib-patches.patch
new file mode 100644
index 0000000..c2c50f1
--- /dev/null
+++ b/SOURCES/0202-Update-gnulib-version-and-drop-most-gnulib-patches.patch
@@ -0,0 +1,832 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Wed, 15 Dec 2021 15:07:50 -0500
+Subject: [PATCH] Update gnulib version and drop most gnulib patches
+
+In addition to the changes carried in our gnulib patches, several
+Coverity and code hygiene fixes that were previously downstream are also
+included in this 3-year gnulib increment.
+
+Unfortunately, fix-width.patch is retained.
+
+Bump minimum autoconf version from 2.63 to 2.64 and automake from 1.11
+to 1.14, as required by gnulib.
+
+Sync bootstrap script itself with gnulib.
+
+Update regexp module for new dynarray dependency.
+
+Fix various new warnings.
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+(cherry picked from commit deb18ff931c3133c2aa536a92bd92e50d6615303)
+[rharwood: backport around requirements in INSTALL]
+---
+ configure.ac                                       |   2 +-
+ grub-core/Makefile.core.def                        |   3 +
+ grub-core/disk/luks2.c                             |   4 +-
+ grub-core/lib/posix_wrap/limits.h                  |   6 +-
+ include/grub/compiler.h                            |   4 +-
+ include/grub/list.h                                |   2 +-
+ INSTALL                                            |   2 +-
+ bootstrap                                          | 291 ++++++++++++---------
+ bootstrap.conf                                     |  22 +-
+ conf/Makefile.extra-dist                           |   6 -
+ config.h.in                                        |  68 +++++
+ grub-core/lib/gnulib-patches/fix-null-deref.patch  |  13 -
+ .../lib/gnulib-patches/fix-null-state-deref.patch  |  12 -
+ .../gnulib-patches/fix-regcomp-uninit-token.patch  |  15 --
+ .../gnulib-patches/fix-regexec-null-deref.patch    |  12 -
+ .../lib/gnulib-patches/fix-uninit-structure.patch  |  11 -
+ .../lib/gnulib-patches/fix-unused-value.patch      |  14 -
+ 17 files changed, 262 insertions(+), 225 deletions(-)
+ delete mode 100644 grub-core/lib/gnulib-patches/fix-null-deref.patch
+ delete mode 100644 grub-core/lib/gnulib-patches/fix-null-state-deref.patch
+ delete mode 100644 grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch
+ delete mode 100644 grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch
+ delete mode 100644 grub-core/lib/gnulib-patches/fix-uninit-structure.patch
+ delete mode 100644 grub-core/lib/gnulib-patches/fix-unused-value.patch
+
+diff --git a/configure.ac b/configure.ac
+index 40c4338bce..79f45ef1e1 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -49,7 +49,7 @@ AC_CANONICAL_TARGET
+ program_prefix="${save_program_prefix}"
+ 
+ AM_INIT_AUTOMAKE([1.11])
+-AC_PREREQ(2.63)
++AC_PREREQ(2.64)
+ AC_CONFIG_SRCDIR([include/grub/dl.h])
+ AC_CONFIG_HEADER([config-util.h])
+ 
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 08ac0fb15f..ec1ec5083b 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -762,6 +762,9 @@ module = {
+   name = regexp;
+   common = commands/regexp.c;
+   common = commands/wildcard.c;
++  common = lib/gnulib/malloc/dynarray_finalize.c;
++  common = lib/gnulib/malloc/dynarray_emplace_enlarge.c;
++  common = lib/gnulib/malloc/dynarray_resize.c;
+   common = lib/gnulib/regex.c;
+   cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
+   cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)';
+diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
+index 371a53b837..c917a5f91e 100644
+--- a/grub-core/disk/luks2.c
++++ b/grub-core/disk/luks2.c
+@@ -389,7 +389,7 @@ luks2_verify_key (grub_luks2_digest_t *d, grub_uint8_t *candidate_key,
+ {
+   grub_uint8_t candidate_digest[GRUB_CRYPTODISK_MAX_KEYLEN];
+   grub_uint8_t digest[GRUB_CRYPTODISK_MAX_KEYLEN], salt[GRUB_CRYPTODISK_MAX_KEYLEN];
+-  grub_size_t saltlen = sizeof (salt), digestlen = sizeof (digest);
++  idx_t saltlen = sizeof (salt), digestlen = sizeof (digest);
+   const gcry_md_spec_t *hash;
+   gcry_err_code_t gcry_ret;
+ 
+@@ -428,7 +428,7 @@ luks2_decrypt_key (grub_uint8_t *out_key,
+   grub_uint8_t area_key[GRUB_CRYPTODISK_MAX_KEYLEN];
+   grub_uint8_t salt[GRUB_CRYPTODISK_MAX_KEYLEN];
+   grub_uint8_t *split_key = NULL;
+-  grub_size_t saltlen = sizeof (salt);
++  idx_t saltlen = sizeof (salt);
+   char cipher[32], *p;
+   const gcry_md_spec_t *hash;
+   gcry_err_code_t gcry_ret;
+diff --git a/grub-core/lib/posix_wrap/limits.h b/grub-core/lib/posix_wrap/limits.h
+index 591dbf3289..4be7b40806 100644
+--- a/grub-core/lib/posix_wrap/limits.h
++++ b/grub-core/lib/posix_wrap/limits.h
+@@ -25,7 +25,11 @@
+ #define USHRT_MAX GRUB_USHRT_MAX
+ #define UINT_MAX GRUB_UINT_MAX
+ #define ULONG_MAX GRUB_ULONG_MAX
+-#define SIZE_MAX GRUB_SIZE_MAX
++
++/* gnulib also defines this type */
++#ifndef SIZE_MAX
++#  define SIZE_MAX GRUB_SIZE_MAX
++#endif
+ 
+ #define SCHAR_MIN GRUB_SCHAR_MIN
+ #define SCHAR_MAX GRUB_SCHAR_MAX
+diff --git a/include/grub/compiler.h b/include/grub/compiler.h
+index ebafec6895..441a9eca07 100644
+--- a/include/grub/compiler.h
++++ b/include/grub/compiler.h
+@@ -30,10 +30,10 @@
+ 
+ /* Does this compiler support compile-time error attributes? */
+ #if GNUC_PREREQ(4,3)
+-#  define ATTRIBUTE_ERROR(msg) \
++#  define GRUB_ATTRIBUTE_ERROR(msg) \
+ 	__attribute__ ((__error__ (msg)))
+ #else
+-#  define ATTRIBUTE_ERROR(msg) __attribute__ ((noreturn))
++#  define GRUB_ATTRIBUTE_ERROR(msg) __attribute__ ((noreturn))
+ #endif
+ 
+ #if GNUC_PREREQ(4,4)
+diff --git a/include/grub/list.h b/include/grub/list.h
+index b13acb9624..21f4b4b44a 100644
+--- a/include/grub/list.h
++++ b/include/grub/list.h
+@@ -40,7 +40,7 @@ void EXPORT_FUNC(grub_list_remove) (grub_list_t item);
+ 
+ static inline void *
+ grub_bad_type_cast_real (int line, const char *file)
+-     ATTRIBUTE_ERROR ("bad type cast between incompatible grub types");
++     GRUB_ATTRIBUTE_ERROR ("bad type cast between incompatible grub types");
+ 
+ static inline void *
+ grub_bad_type_cast_real (int line, const char *file)
+diff --git a/INSTALL b/INSTALL
+index 79a0af7d93..ee9f536f76 100644
+--- a/INSTALL
++++ b/INSTALL
+@@ -42,7 +42,7 @@ If you use a development snapshot or want to hack on GRUB you may
+ need the following.
+ 
+ * Python 2.6 or later
+-* Autoconf 2.63 or later
++* Autoconf 2.64 or later
+ * Automake 1.11 or later
+ 
+ Prerequisites for make-check:
+diff --git a/bootstrap b/bootstrap
+index 5b08e7e2d4..dc2238f4ad 100755
+--- a/bootstrap
++++ b/bootstrap
+@@ -1,10 +1,10 @@
+ #! /bin/sh
+ # Print a version string.
+-scriptversion=2019-01-04.17; # UTC
++scriptversion=2022-01-26.05; # UTC
+ 
+ # Bootstrap this package from checked-out sources.
+ 
+-# Copyright (C) 2003-2019 Free Software Foundation, Inc.
++# Copyright (C) 2003-2022 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
+@@ -47,7 +47,7 @@ PERL="${PERL-perl}"
+ 
+ me=$0
+ 
+-default_gnulib_url=git://git.sv.gnu.org/gnulib
++default_gnulib_url=https://git.savannah.gnu.org/git/gnulib.git
+ 
+ usage() {
+   cat <<EOF
+@@ -71,7 +71,9 @@ Options:
+  --no-git                 do not use git to update gnulib.  Requires that
+                           --gnulib-srcdir point to a correct gnulib snapshot
+  --skip-po                do not download po files
+-
++EOF
++  bootstrap_print_option_usage_hook
++  cat <<EOF
+ If the file $me.conf exists in the same directory as this script, its
+ contents are read as shell variables to configure the bootstrap.
+ 
+@@ -113,6 +115,12 @@ Running without arguments will suffice in most cases.
+ EOF
+ }
+ 
++copyright_year=`echo "$scriptversion" | sed -e 's/[^0-9].*//'`
++copyright="Copyright (C) ${copyright_year} Free Software Foundation, Inc.
++License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
++This is free software: you are free to change and redistribute it.
++There is NO WARRANTY, to the extent permitted by law."
++
+ # warnf_ FORMAT-STRING ARG1...
+ warnf_ ()
+ {
+@@ -154,6 +162,18 @@ gnulib_files=
+ : ${AUTOPOINT=autopoint}
+ : ${AUTORECONF=autoreconf}
+ 
++# A function to be called for each unrecognized option.  Returns 0 if
++# the option in $1 has been processed by the function.  Returns 1 if
++# the option has not been processed by the function.  Override it via
++# your own definition in bootstrap.conf
++
++bootstrap_option_hook() { return 1; }
++
++# A function to be called in order to print the --help information
++# corresponding to user-defined command-line options.
++
++bootstrap_print_option_usage_hook() { :; }
++
+ # A function to be called right after gnulib-tool is run.
+ # Override it via your own definition in bootstrap.conf.
+ bootstrap_post_import_hook() { :; }
+@@ -166,11 +186,11 @@ bootstrap_epilogue() { :; }
+ # specified directory.  Fill in the first %s with the destination
+ # directory and the second with the domain name.
+ po_download_command_format=\
+-"wget --mirror --level=1 -nd -q -A.po -P '%s' \
++"wget --mirror --level=1 -nd -nv -A.po -P '%s' \
+  https://translationproject.org/latest/%s/"
+ 
+ # Prefer a non-empty tarname (4th argument of AC_INIT if given), else
+-# fall back to the package name (1st argument with munging)
++# fall back to the package name (1st argument with munging).
+ extract_package_name='
+   /^AC_INIT(\[*/{
+      s///
+@@ -187,8 +207,11 @@ extract_package_name='
+      p
+   }
+ '
+-package=$(sed -n "$extract_package_name" configure.ac) \
+-  || die 'cannot find package name in configure.ac'
++package=$(${AUTOCONF:-autoconf} --trace AC_INIT:\$4 configure.ac 2>/dev/null)
++if test -z "$package"; then
++  package=$(sed -n "$extract_package_name" configure.ac) \
++      || die 'cannot find package name in configure.ac'
++fi
+ gnulib_name=lib$package
+ 
+ build_aux=build-aux
+@@ -290,6 +313,116 @@ find_tool ()
+   eval "export $find_tool_envvar"
+ }
+ 
++# Strip blank and comment lines to leave significant entries.
++gitignore_entries() {
++  sed '/^#/d; /^$/d' "$@"
++}
++
++# If $STR is not already on a line by itself in $FILE, insert it at the start.
++# Entries are inserted at the start of the ignore list to ensure existing
++# entries starting with ! are not overridden.  Such entries support
++# whitelisting exceptions after a more generic blacklist pattern.
++insert_if_absent() {
++  file=$1
++  str=$2
++  test -f $file || touch $file
++  test -r $file || die "Error: failed to read ignore file: $file"
++  duplicate_entries=$(gitignore_entries $file | sort | uniq -d)
++  if [ "$duplicate_entries" ] ; then
++    die "Error: Duplicate entries in $file: " $duplicate_entries
++  fi
++  linesold=$(gitignore_entries $file | wc -l)
++  linesnew=$( { echo "$str"; cat $file; } | gitignore_entries | sort -u | wc -l)
++  if [ $linesold != $linesnew ] ; then
++    { echo "$str" | cat - $file > $file.bak && mv $file.bak $file; } \
++      || die "insert_if_absent $file $str: failed"
++  fi
++}
++
++# Adjust $PATTERN for $VC_IGNORE_FILE and insert it with
++# insert_if_absent.
++insert_vc_ignore() {
++  vc_ignore_file="$1"
++  pattern="$2"
++  case $vc_ignore_file in
++  *.gitignore)
++    # A .gitignore entry that does not start with '/' applies
++    # recursively to subdirectories, so prepend '/' to every
++    # .gitignore entry.
++    pattern=$(echo "$pattern" | sed s,^,/,);;
++  esac
++  insert_if_absent "$vc_ignore_file" "$pattern"
++}
++
++symlink_to_dir()
++{
++  src=$1/$2
++  dst=${3-$2}
++
++  test -f "$src" && {
++
++    # If the destination directory doesn't exist, create it.
++    # This is required at least for "lib/uniwidth/cjk.h".
++    dst_dir=$(dirname "$dst")
++    if ! test -d "$dst_dir"; then
++      mkdir -p "$dst_dir"
++
++      # If we've just created a directory like lib/uniwidth,
++      # tell version control system(s) it's ignorable.
++      # FIXME: for now, this does only one level
++      parent=$(dirname "$dst_dir")
++      for dot_ig in x $vc_ignore; do
++        test $dot_ig = x && continue
++        ig=$parent/$dot_ig
++        insert_vc_ignore $ig "${dst_dir##*/}"
++      done
++    fi
++
++    if $copy; then
++      {
++        test ! -h "$dst" || {
++          echo "$me: rm -f $dst" &&
++          rm -f "$dst"
++        }
++      } &&
++      test -f "$dst" &&
++      cmp -s "$src" "$dst" || {
++        echo "$me: cp -fp $src $dst" &&
++        cp -fp "$src" "$dst"
++      }
++    else
++      # Leave any existing symlink alone, if it already points to the source,
++      # so that broken build tools that care about symlink times
++      # aren't confused into doing unnecessary builds.  Conversely, if the
++      # existing symlink's timestamp is older than the source, make it afresh,
++      # so that broken tools aren't confused into skipping needed builds.  See
++      # <https://lists.gnu.org/r/bug-gnulib/2011-05/msg00326.html>.
++      test -h "$dst" &&
++      src_ls=$(ls -diL "$src" 2>/dev/null) && set $src_ls && src_i=$1 &&
++      dst_ls=$(ls -diL "$dst" 2>/dev/null) && set $dst_ls && dst_i=$1 &&
++      test "$src_i" = "$dst_i" &&
++      both_ls=$(ls -dt "$src" "$dst") &&
++      test "X$both_ls" = "X$dst$nl$src" || {
++        dot_dots=
++        case $src in
++        /*) ;;
++        *)
++          case /$dst/ in
++          *//* | */../* | */./* | /*/*/*/*/*/)
++             die "invalid symlink calculation: $src -> $dst";;
++          /*/*/*/*/)    dot_dots=../../../;;
++          /*/*/*/)      dot_dots=../../;;
++          /*/*/)        dot_dots=../;;
++          esac;;
++        esac
++
++        echo "$me: ln -fs $dot_dots$src $dst" &&
++        ln -fs "$dot_dots$src" "$dst"
++      }
++    fi
++  }
++}
++
+ # Override the default configuration, if necessary.
+ # Make sure that bootstrap.conf is sourced from the current directory
+ # if we were invoked as "sh bootstrap".
+@@ -320,6 +453,12 @@ do
+   --help)
+     usage
+     exit;;
++  --version)
++    set -e
++    echo "bootstrap $scriptversion"
++    echo "$copyright"
++    exit 0
++    ;;
+   --gnulib-srcdir=*)
+     GNULIB_SRCDIR=${option#--gnulib-srcdir=};;
+   --skip-po)
+@@ -335,7 +474,7 @@ do
+   --no-git)
+     use_git=false;;
+   *)
+-    die "$option: unknown option";;
++    bootstrap_option_hook $option || die "$option: unknown option";;
+   esac
+ done
+ 
+@@ -346,47 +485,6 @@ if test -n "$checkout_only_file" && test ! -r "$checkout_only_file"; then
+   die "Bootstrapping from a non-checked-out distribution is risky."
+ fi
+ 
+-# Strip blank and comment lines to leave significant entries.
+-gitignore_entries() {
+-  sed '/^#/d; /^$/d' "$@"
+-}
+-
+-# If $STR is not already on a line by itself in $FILE, insert it at the start.
+-# Entries are inserted at the start of the ignore list to ensure existing
+-# entries starting with ! are not overridden.  Such entries support
+-# whitelisting exceptions after a more generic blacklist pattern.
+-insert_if_absent() {
+-  file=$1
+-  str=$2
+-  test -f $file || touch $file
+-  test -r $file || die "Error: failed to read ignore file: $file"
+-  duplicate_entries=$(gitignore_entries $file | sort | uniq -d)
+-  if [ "$duplicate_entries" ] ; then
+-    die "Error: Duplicate entries in $file: " $duplicate_entries
+-  fi
+-  linesold=$(gitignore_entries $file | wc -l)
+-  linesnew=$( { echo "$str"; cat $file; } | gitignore_entries | sort -u | wc -l)
+-  if [ $linesold != $linesnew ] ; then
+-    { echo "$str" | cat - $file > $file.bak && mv $file.bak $file; } \
+-      || die "insert_if_absent $file $str: failed"
+-  fi
+-}
+-
+-# Adjust $PATTERN for $VC_IGNORE_FILE and insert it with
+-# insert_if_absent.
+-insert_vc_ignore() {
+-  vc_ignore_file="$1"
+-  pattern="$2"
+-  case $vc_ignore_file in
+-  *.gitignore)
+-    # A .gitignore entry that does not start with '/' applies
+-    # recursively to subdirectories, so prepend '/' to every
+-    # .gitignore entry.
+-    pattern=$(echo "$pattern" | sed s,^,/,);;
+-  esac
+-  insert_if_absent "$vc_ignore_file" "$pattern"
+-}
+-
+ # Die if there is no AC_CONFIG_AUX_DIR($build_aux) line in configure.ac.
+ found_aux_dir=no
+ grep '^[	 ]*AC_CONFIG_AUX_DIR(\['"$build_aux"'\])' configure.ac \
+@@ -665,9 +763,25 @@ if $use_gnulib; then
+       shallow=
+       if test -z "$GNULIB_REVISION"; then
+         git clone -h 2>&1 | grep -- --depth > /dev/null && shallow='--depth 2'
++        git clone $shallow ${GNULIB_URL:-$default_gnulib_url} "$gnulib_path" \
++          || cleanup_gnulib
++      else
++        git fetch -h 2>&1 | grep -- --depth > /dev/null && shallow='--depth 2'
++        mkdir -p "$gnulib_path"
++        # Only want a shallow checkout of $GNULIB_REVISION, but git does not
++        # support cloning by commit hash. So attempt a shallow fetch by commit
++        # hash to minimize the amount of data downloaded and changes needed to
++        # be processed, which can drastically reduce download and processing
++        # time for checkout. If the fetch by commit fails, a shallow fetch can
++        # not be performed because we do not know what the depth of the commit
++        # is without fetching all commits. So fallback to fetching all commits.
++        git -C "$gnulib_path" init
++        git -C "$gnulib_path" remote add origin ${GNULIB_URL:-$default_gnulib_url}
++        git -C "$gnulib_path" fetch $shallow origin "$GNULIB_REVISION" \
++          || git -C "$gnulib_path" fetch origin \
++          || cleanup_gnulib
++        git -C "$gnulib_path" reset --hard FETCH_HEAD
+       fi
+-      git clone $shallow ${GNULIB_URL:-$default_gnulib_url} "$gnulib_path" \
+-        || cleanup_gnulib
+ 
+       trap - 1 2 13 15
+     fi
+@@ -784,75 +898,6 @@ case $SKIP_PO in
+   fi;;
+ esac
+ 
+-symlink_to_dir()
+-{
+-  src=$1/$2
+-  dst=${3-$2}
+-
+-  test -f "$src" && {
+-
+-    # If the destination directory doesn't exist, create it.
+-    # This is required at least for "lib/uniwidth/cjk.h".
+-    dst_dir=$(dirname "$dst")
+-    if ! test -d "$dst_dir"; then
+-      mkdir -p "$dst_dir"
+-
+-      # If we've just created a directory like lib/uniwidth,
+-      # tell version control system(s) it's ignorable.
+-      # FIXME: for now, this does only one level
+-      parent=$(dirname "$dst_dir")
+-      for dot_ig in x $vc_ignore; do
+-        test $dot_ig = x && continue
+-        ig=$parent/$dot_ig
+-        insert_vc_ignore $ig "${dst_dir##*/}"
+-      done
+-    fi
+-
+-    if $copy; then
+-      {
+-        test ! -h "$dst" || {
+-          echo "$me: rm -f $dst" &&
+-          rm -f "$dst"
+-        }
+-      } &&
+-      test -f "$dst" &&
+-      cmp -s "$src" "$dst" || {
+-        echo "$me: cp -fp $src $dst" &&
+-        cp -fp "$src" "$dst"
+-      }
+-    else
+-      # Leave any existing symlink alone, if it already points to the source,
+-      # so that broken build tools that care about symlink times
+-      # aren't confused into doing unnecessary builds.  Conversely, if the
+-      # existing symlink's timestamp is older than the source, make it afresh,
+-      # so that broken tools aren't confused into skipping needed builds.  See
+-      # <https://lists.gnu.org/r/bug-gnulib/2011-05/msg00326.html>.
+-      test -h "$dst" &&
+-      src_ls=$(ls -diL "$src" 2>/dev/null) && set $src_ls && src_i=$1 &&
+-      dst_ls=$(ls -diL "$dst" 2>/dev/null) && set $dst_ls && dst_i=$1 &&
+-      test "$src_i" = "$dst_i" &&
+-      both_ls=$(ls -dt "$src" "$dst") &&
+-      test "X$both_ls" = "X$dst$nl$src" || {
+-        dot_dots=
+-        case $src in
+-        /*) ;;
+-        *)
+-          case /$dst/ in
+-          *//* | */../* | */./* | /*/*/*/*/*/)
+-             die "invalid symlink calculation: $src -> $dst";;
+-          /*/*/*/*/)    dot_dots=../../../;;
+-          /*/*/*/)      dot_dots=../../;;
+-          /*/*/)        dot_dots=../;;
+-          esac;;
+-        esac
+-
+-        echo "$me: ln -fs $dot_dots$src $dst" &&
+-        ln -fs "$dot_dots$src" "$dst"
+-      }
+-    fi
+-  }
+-}
+-
+ version_controlled_file() {
+   parent=$1
+   file=$2
+@@ -970,7 +1015,7 @@ bootstrap_post_import_hook \
+ # Uninitialized submodules are listed with an initial dash.
+ if $use_git && git submodule | grep '^-' >/dev/null; then
+   die "some git submodules are not initialized. "     \
+-      "Run 'git submodule init' and bootstrap again."
++      "Run 'git submodule update --init' and bootstrap again."
+ fi
+ 
+ # Remove any dangling symlink matching "*.m4" or "*.[ch]" in some
+@@ -1064,7 +1109,7 @@ bootstrap_epilogue
+ 
+ echo "$0: done.  Now you can run './configure'."
+ 
+-# Local variables:
++# Local Variables:
+ # eval: (add-hook 'before-save-hook 'time-stamp)
+ # time-stamp-start: "scriptversion="
+ # time-stamp-format: "%:y-%02m-%02d.%02H"
+diff --git a/bootstrap.conf b/bootstrap.conf
+index 71ce943c7d..e4e5f3750a 100644
+--- a/bootstrap.conf
++++ b/bootstrap.conf
+@@ -1,6 +1,6 @@
+ # Bootstrap configuration.
+ 
+-# Copyright (C) 2006-2019 Free Software Foundation, Inc.
++# Copyright (C) 2006-2022 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
+@@ -16,11 +16,10 @@
+ # along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ 
+ 
+-GNULIB_REVISION=d271f868a8df9bbec29049d01e056481b7a1a263
++GNULIB_REVISION=9f48fb992a3d7e96610c4ce8be969cff2d61a01b
+ 
+ # gnulib modules used by this package.
+-# mbswidth is used by gnulib-fix-width.diff's changes to argp rather than
+-# directly.
++# mbswidth is used by fix-width.diff's changes to argp rather than directly.
+ gnulib_modules="
+   argp
+   base64
+@@ -67,8 +66,8 @@ SKIP_PO=t
+ 
+ # Build prerequisites
+ buildreq="\
+-autoconf   2.63
+-automake   1.11
++autoconf   2.64
++automake   1.14
+ gettext    0.18.3
+ git        1.5.5
+ tar        -
+@@ -80,11 +79,12 @@ cp -a INSTALL INSTALL.grub
+ 
+ bootstrap_post_import_hook () {
+   set -e
+-  for patchname in fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \
+-      fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width; do
+-    patch -d grub-core/lib/gnulib -p2 \
+-      < "grub-core/lib/gnulib-patches/$patchname.patch"
+-  done
++
++  # Instead of patching our gnulib and therefore maintaining a fork, submit
++  # changes to gnulib and update the hash above when they've merged.  Do not
++  # add new patches here.
++  patch -d grub-core/lib/gnulib -p2 < grub-core/lib/gnulib-patches/fix-width.patch
++
+   for patchname in \
+       0001-Support-POTFILES-shell \
+       0002-Handle-gettext_printf-shell-function \
+diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist
+index 5eef708338..26ac8765e3 100644
+--- a/conf/Makefile.extra-dist
++++ b/conf/Makefile.extra-dist
+@@ -31,12 +31,6 @@ EXTRA_DIST += grub-core/gensymlist.sh
+ EXTRA_DIST += grub-core/genemuinit.sh
+ EXTRA_DIST += grub-core/genemuinitheader.sh
+ 
+-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-deref.patch
+-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-state-deref.patch
+-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch
+-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch
+-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-uninit-structure.patch
+-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-unused-value.patch
+ EXTRA_DIST += grub-core/lib/gnulib-patches/fix-width.patch
+ 
+ EXTRA_DIST += grub-core/lib/libgcrypt
+diff --git a/config.h.in b/config.h.in
+index c3134309c6..512d1bbe13 100644
+--- a/config.h.in
++++ b/config.h.in
+@@ -67,10 +67,78 @@
+ #  define _GNU_SOURCE 1
+ 
+ #  ifndef _GL_INLINE_HEADER_BEGIN
++/* gnulib gets configured against the host, not the target, and the rest of
++ * our buildsystem works around that.  This is difficult to avoid as gnulib's
++ * detection requires a more capable system than our target.  Instead, we
++ * reach in and set values appropriately - intentionally setting more than the
++ * bare minimum.  If, when updating gnulib, something breaks, there's probably
++ * a change needed here or in grub-core/Makefile.core.def. */
++#    define SIZE_MAX ((size_t) -1)
++#    define _GL_ATTRIBUTE_ALLOC_SIZE(args) \
++    __attribute__ ((__alloc_size__ args))
++#    define _GL_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((__always_inline__))
++#    define _GL_ATTRIBUTE_ARTIFICIAL __attribute__ ((__artificial__))
++#    define _GL_ATTRIBUTE_COLD __attribute__ ((cold))
+ #    define _GL_ATTRIBUTE_CONST __attribute__ ((const))
++#    define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute ((__malloc__ (f, i)))
++#    define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (free, 1)
++#    define _GL_ATTRIBUTE_DEPRECATED __attribute__ ((__deprecated__))
++#    define _GL_ATTRIBUTE_ERROR(msg) __attribute__ ((__error__ (msg)))
++#    define _GL_ATTRIBUTE_EXTERNALLY_VISIBLE \
++    __attribute__ ((externally_visible))
++#    define _GL_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec))
++#    define _GL_ATTRIBUTE_LEAF __attribute__ ((__leaf__))
++#    define _GL_ATTRIBUTE_MALLOC __attribute__ ((malloc))
++#    define _GL_ATTRIBUTE_MAYBE_UNUSED _GL_ATTRIBUTE_UNUSED
++#    define _GL_ATTRIBUTE_MAY_ALIAS __attribute__ ((__may_alias__))
++#    define _GL_ATTRIBUTE_NODISCARD __attribute__ ((__warn_unused_result__))
++#    define _GL_ATTRIBUTE_NOINLINE __attribute__ ((__noinline__))
++#    define _GL_ATTRIBUTE_NONNULL(args) __attribute__ ((__nonnull__ args))
++#    define _GL_ATTRIBUTE_NONSTRING __attribute__ ((__nonstring__))
++#    define _GL_ATTRIBUTE_PACKED __attribute__ ((__packed__))
++#    define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
++#    define _GL_ATTRIBUTE_RETURNS_NONNULL \
++    __attribute__ ((__returns_nonnull__))
++#    define _GL_ATTRIBUTE_SENTINEL(pos) __attribute__ ((__sentinel__ pos))
++#    define _GL_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
++#    define _GL_ATTRIBUTE_WARNING(msg) __attribute__ ((__warning__ (msg)))
++#    define _GL_CMP(n1, n2) (((n1) > (n2)) - ((n1) < (n2)))
++#    define _GL_GNUC_PREREQ GNUC_PREREQ
++#    define _GL_INLINE inline
++#    define _GL_UNUSED_LABEL _GL_ATTRIBUTE_UNUSED
++
++/* We can't use __has_attribute for these because gcc-5.1 is too old for
++ * that.  Everything above is present in that version, though. */
++#    if __GNUC__ >= 7
++#      define _GL_ATTRIBUTE_FALLTHROUGH __attribute__ ((fallthrough))
++#    else
++#      define _GL_ATTRIBUTE_FALLTHROUGH /* empty */
++#    endif
++
++#    ifndef ASM_FILE
++typedef __INT_FAST32_TYPE__ int_fast32_t;
++typedef __UINT_FAST32_TYPE__ uint_fast32_t;
++#    endif
++
++/* Ensure ialloc nests static/non-static inline properly. */
++#    define IALLOC_INLINE static inline
++
++/* gnulib uses these for blocking out warnings they can't/won't fix.  gnulib
++ * also makes the decision about whether to provide a declaration for
++ * reallocarray() at compile-time, so this is a convenient place to override -
++ * it's used by the ialloc module, which is used by base64. */
++#    define _GL_INLINE_HEADER_BEGIN _Pragma ("GCC diagnostic push")	\
++    void *								\
++    reallocarray (void *ptr, unsigned int nmemb, unsigned int size);
++#    define _GL_INLINE_HEADER_END   _Pragma ("GCC diagnostic pop")
+ 
+ /* We don't have an abort() for gnulib to call in regexp. */
+ #    define abort __builtin_unreachable
+ #  endif /* !_GL_INLINE_HEADER_BEGIN */
+ 
++/* gnulib doesn't build cleanly with older compilers. */
++#  if __GNUC__ < 11
++_Pragma ("GCC diagnostic ignored \"-Wtype-limits\"")
++#  endif
++
+ #endif
+diff --git a/grub-core/lib/gnulib-patches/fix-null-deref.patch b/grub-core/lib/gnulib-patches/fix-null-deref.patch
+deleted file mode 100644
+index 8fafa153a4..0000000000
+--- a/grub-core/lib/gnulib-patches/fix-null-deref.patch
++++ /dev/null
+@@ -1,13 +0,0 @@
+-diff --git a/lib/argp-parse.c b/lib/argp-parse.c
+-index 6dec57310..900adad54 100644
+---- a/lib/argp-parse.c
+-+++ b/lib/argp-parse.c
+-@@ -940,7 +940,7 @@ weak_alias (__argp_parse, argp_parse)
+- void *
+- __argp_input (const struct argp *argp, const struct argp_state *state)
+- {
+--  if (state)
+-+  if (state && state->pstate)
+-     {
+-       struct group *group;
+-       struct parser *parser = state->pstate;
+diff --git a/grub-core/lib/gnulib-patches/fix-null-state-deref.patch b/grub-core/lib/gnulib-patches/fix-null-state-deref.patch
+deleted file mode 100644
+index 813ec09c8a..0000000000
+--- a/grub-core/lib/gnulib-patches/fix-null-state-deref.patch
++++ /dev/null
+@@ -1,12 +0,0 @@
+---- a/lib/argp-help.c	2020-10-28 14:32:19.189215988 +0000
+-+++ b/lib/argp-help.c	2020-10-28 14:38:21.204673940 +0000
+-@@ -145,7 +145,8 @@
+-       if (*(int *)((char *)upptr + up->uparams_offs) >= upptr->rmargin)
+-         {
+-           __argp_failure (state, 0, 0,
+--                          dgettext (state->root_argp->argp_domain,
+-+                          dgettext (state == NULL ? NULL
+-+                                    : state->root_argp->argp_domain,
+-                                     "\
+- ARGP_HELP_FMT: %s value is less than or equal to %s"),
+-                           "rmargin", up->name);
+diff --git a/grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch b/grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch
+deleted file mode 100644
+index 02e06315df..0000000000
+--- a/grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch
++++ /dev/null
+@@ -1,15 +0,0 @@
+---- a/lib/regcomp.c	2020-11-24 17:06:08.159223858 +0000
+-+++ b/lib/regcomp.c	2020-11-24 17:06:15.630253923 +0000
+-@@ -3808,11 +3808,7 @@
+- create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
+- 	     re_token_type_t type)
+- {
+--  re_token_t t;
+--#if defined GCC_LINT || defined lint
+--  memset (&t, 0, sizeof t);
+--#endif
+--  t.type = type;
+-+  re_token_t t = { .type = type };
+-   return create_token_tree (dfa, left, right, &t);
+- }
+- 
+diff --git a/grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch b/grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch
+deleted file mode 100644
+index db6dac9c9e..0000000000
+--- a/grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch
++++ /dev/null
+@@ -1,12 +0,0 @@
+---- a/lib/regexec.c	2020-10-21 14:25:35.310195912 +0000
+-+++ b/lib/regexec.c	2020-11-05 10:55:09.621542984 +0000
+-@@ -1692,6 +1692,9 @@
+- {
+-   Idx top = mctx->state_log_top;
+-
+-+  if (mctx->state_log == NULL)
+-+    return REG_NOERROR;
+-+
+-   if ((next_state_log_idx >= mctx->input.bufs_len
+-        && mctx->input.bufs_len < mctx->input.len)
+-       || (next_state_log_idx >= mctx->input.valid_len
+diff --git a/grub-core/lib/gnulib-patches/fix-uninit-structure.patch b/grub-core/lib/gnulib-patches/fix-uninit-structure.patch
+deleted file mode 100644
+index 7b4d9f67af..0000000000
+--- a/grub-core/lib/gnulib-patches/fix-uninit-structure.patch
++++ /dev/null
+@@ -1,11 +0,0 @@
+---- a/lib/regcomp.c	2020-10-22 13:49:06.770168928 +0000
+-+++ b/lib/regcomp.c	2020-10-22 13:50:37.026528298 +0000
+-@@ -3662,7 +3662,7 @@
+-   Idx alloc = 0;
+- #endif /* not RE_ENABLE_I18N */
+-   reg_errcode_t ret;
+--  re_token_t br_token;
+-+  re_token_t br_token = {0};
+-   bin_tree_t *tree;
+- 
+-   sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
+diff --git a/grub-core/lib/gnulib-patches/fix-unused-value.patch b/grub-core/lib/gnulib-patches/fix-unused-value.patch
+deleted file mode 100644
+index ba51f1bf22..0000000000
+--- a/grub-core/lib/gnulib-patches/fix-unused-value.patch
++++ /dev/null
+@@ -1,14 +0,0 @@
+---- a/lib/regexec.c	2020-10-21 14:25:35.310195912 +0000
+-+++ b/lib/regexec.c	2020-10-21 14:32:07.961765604 +0000
+-@@ -828,7 +828,11 @@
+- 		    break;
+- 		  if (__glibc_unlikely (err != REG_NOMATCH))
+- 		    goto free_return;
+-+#ifdef DEBUG
+-+		  /* Only used for assertion below when DEBUG is set, otherwise
+-+		     it will be over-written when we loop around.  */
+- 		  match_last = -1;
+-+#endif
+- 		}
+- 	      else
+- 		break; /* We found a match.  */
diff --git a/SOURCES/0202-ieee1275-ofdisk-retry-on-open-failure.patch b/SOURCES/0202-ieee1275-ofdisk-retry-on-open-failure.patch
deleted file mode 100644
index 275d14f..0000000
--- a/SOURCES/0202-ieee1275-ofdisk-retry-on-open-failure.patch
+++ /dev/null
@@ -1,103 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Diego Domingos <diegodo@br.ibm.com>
-Date: Wed, 10 Mar 2021 14:17:52 -0500
-Subject: [PATCH] ieee1275/ofdisk: retry on open failure
-
-This patch aims to make grub more robust when booting from SAN/Multipath disks.
-
-If a path is failing intermittently so grub will retry the OPEN and READ the
-disk (grub_ieee1275_open and grub_ieee1275_read) until the total amount of times
-specified in MAX_RETRIES.
-
-Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
----
- grub-core/disk/ieee1275/ofdisk.c | 25 ++++++++++++++++++++-----
- include/grub/ieee1275/ofdisk.h   |  8 ++++++++
- 2 files changed, 28 insertions(+), 5 deletions(-)
-
-diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c
-index ea7f78ac7d8..55346849d35 100644
---- a/grub-core/disk/ieee1275/ofdisk.c
-+++ b/grub-core/disk/ieee1275/ofdisk.c
-@@ -225,7 +225,9 @@ dev_iterate (const struct grub_ieee1275_devalias *alias)
-       char *buf, *bufptr;
-       unsigned i;
- 
--      if (grub_ieee1275_open (alias->path, &ihandle))
-+
-+      RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle)
-+      if (! ihandle)
- 	return;
- 
-       /* This method doesn't need memory allocation for the table. Open
-@@ -305,7 +307,9 @@ dev_iterate (const struct grub_ieee1275_devalias *alias)
-           return;
-         }
- 
--      if (grub_ieee1275_open (alias->path, &ihandle))
-+      RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle);
-+
-+      if (! ihandle)
-         {
-           grub_free (buf);
-           grub_free (table);
-@@ -495,7 +499,7 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
-     last_ihandle = 0;
-     last_devpath = NULL;
- 
--    grub_ieee1275_open (op->open_path, &last_ihandle);
-+    RETRY_IEEE1275_OFDISK_OPEN(op->open_path, &last_ihandle);
-     if (! last_ihandle)
-       return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
-     last_devpath = op->open_path;
-@@ -571,7 +575,7 @@ grub_ofdisk_prepare (grub_disk_t disk, grub_disk_addr_t sector)
-       last_ihandle = 0;
-       last_devpath = NULL;
- 
--      grub_ieee1275_open (disk->data, &last_ihandle);
-+      RETRY_IEEE1275_OFDISK_OPEN(disk->data, &last_ihandle);
-       if (! last_ihandle)
- 	return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
-       last_devpath = disk->data;      
-@@ -598,12 +602,23 @@ grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
-     return err;
-   grub_ieee1275_read (last_ihandle, buf, size  << disk->log_sector_size,
- 		      &actual);
--  if (actual != (grub_ssize_t) (size  << disk->log_sector_size))
-+  int i = 0;
-+  while(actual != (grub_ssize_t) (size  << disk->log_sector_size)){
-+    if (i>MAX_RETRIES){
-     return grub_error (GRUB_ERR_READ_ERROR, N_("failure reading sector 0x%llx "
- 					       "from `%s'"),
- 		       (unsigned long long) sector,
- 		       disk->name);
-+    }
-+    last_devpath = NULL;
-+    err = grub_ofdisk_prepare (disk, sector);
-+    if (err)
-+      return err;
- 
-+    grub_ieee1275_read (last_ihandle, buf, size  << disk->log_sector_size,
-+                      &actual);
-+    i++;
-+  }
-   return 0;
- }
- 
-diff --git a/include/grub/ieee1275/ofdisk.h b/include/grub/ieee1275/ofdisk.h
-index 2f69e3f191d..7d2d5409305 100644
---- a/include/grub/ieee1275/ofdisk.h
-+++ b/include/grub/ieee1275/ofdisk.h
-@@ -22,4 +22,12 @@
- extern void grub_ofdisk_init (void);
- extern void grub_ofdisk_fini (void);
- 
-+#define MAX_RETRIES 20
-+
-+
-+#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) unsigned retry_i=0;for(retry_i=0; retry_i < MAX_RETRIES; retry_i++){ \
-+						if(!grub_ieee1275_open(device, last_ihandle)) \
-+						break; \
-+						grub_dprintf("ofdisk","Opening disk %s failed. Retrying...\n",device); }
-+
- #endif /* ! GRUB_INIT_HEADER */
diff --git a/SOURCES/0203-01_menu_auto_hide.in-fix-a-then-than-typo.patch b/SOURCES/0203-01_menu_auto_hide.in-fix-a-then-than-typo.patch
deleted file mode 100644
index 4847ef9..0000000
--- a/SOURCES/0203-01_menu_auto_hide.in-fix-a-then-than-typo.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@fedoraproject.org>
-Date: Fri, 11 Jun 2021 12:57:56 +0200
-Subject: [PATCH] 01_menu_auto_hide.in: fix a then/than typo
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Jan Pokorný <jpokorny@fedoraproject.org>
----
- util/grub.d/10_reset_boot_success.in | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/util/grub.d/10_reset_boot_success.in b/util/grub.d/10_reset_boot_success.in
-index 737e1ae5b68..e73f4137b36 100644
---- a/util/grub.d/10_reset_boot_success.in
-+++ b/util/grub.d/10_reset_boot_success.in
-@@ -15,7 +15,7 @@ fi
- # Reset boot_indeterminate after a successful boot
- if [ "\${boot_success}" = "1" ] ; then
-   set boot_indeterminate=0
--# Avoid boot_indeterminate causing the menu to be hidden more then once
-+# Avoid boot_indeterminate causing the menu to be hidden more than once
- elif [ "\${boot_indeterminate}" = "1" ]; then
-   set boot_indeterminate=2
- fi
diff --git a/SOURCES/0203-commands-search-Fix-bug-stopping-iteration-when-no-f.patch b/SOURCES/0203-commands-search-Fix-bug-stopping-iteration-when-no-f.patch
new file mode 100644
index 0000000..4f7feb9
--- /dev/null
+++ b/SOURCES/0203-commands-search-Fix-bug-stopping-iteration-when-no-f.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Tue, 8 Feb 2022 08:39:10 +0100
+Subject: [PATCH] commands/search: Fix bug stopping iteration when --no-floppy
+ is used
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When using --no-floppy and a floppy was encountered, iterate_device()
+was returning 1, causing the iteration to stop instead of continuing.
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 68ba54c2298604146be83cae144dafd1cfd1fe2d)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/commands/search.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c
+index ed090b3af8..51656e361c 100644
+--- a/grub-core/commands/search.c
++++ b/grub-core/commands/search.c
+@@ -64,7 +64,7 @@ iterate_device (const char *name, void *data)
+   /* Skip floppy drives when requested.  */
+   if (ctx->no_floppy &&
+       name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9')
+-    return 1;
++    return 0;
+ 
+ #ifdef DO_SEARCH_FS_UUID
+ #define compare_fn grub_strcasecmp
diff --git a/SOURCES/0204-Fix-disabling-grub-rpm-sort.patch b/SOURCES/0204-Fix-disabling-grub-rpm-sort.patch
deleted file mode 100644
index dccde3c..0000000
--- a/SOURCES/0204-Fix-disabling-grub-rpm-sort.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Tim Landscheidt <tim@tim-landscheidt.de>
-Date: Fri, 11 Jun 2021 13:02:37 +0200
-Subject: [PATCH] Fix disabling grub-rpm-sort
-
-Currently, grub-rpm-sort is unconditionally compiled whether
-./configure has been called with --disable-rpm-sort or not.  This adds
-the necessary logic to configure.ac and Makefile.util.def and some
-debug output to ./configure and fixes #44.
----
- configure.ac      | 8 ++++++++
- Makefile.util.def | 1 +
- 2 files changed, 9 insertions(+)
-
-diff --git a/configure.ac b/configure.ac
-index d5d2a28b4ef..c7842ec29d8 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1936,6 +1936,8 @@ AC_ARG_ENABLE([rpm-sort],
-                               [enable native rpm sorting of kernels in grub (default=guessed)])])
- if test x"$enable_rpm_sort" = xno ; then
-   rpm_sort_excuse="explicitly disabled"
-+else
-+  enable_rpm_sort=yes
- fi
- 
- if test x"$rpm_sort_excuse" = x ; then
-@@ -2200,6 +2202,7 @@ AM_CONDITIONAL([COND_GRUB_EMU_SDL], [test x$enable_grub_emu_sdl = xyes])
- AM_CONDITIONAL([COND_GRUB_EMU_PCI], [test x$enable_grub_emu_pci = xyes])
- AM_CONDITIONAL([COND_GRUB_MKFONT], [test x$enable_grub_mkfont = xyes])
- AM_CONDITIONAL([COND_GRUB_MOUNT], [test x$enable_grub_mount = xyes])
-+AM_CONDITIONAL([COND_GRUB_RPM_SORT], [test x$enable_rpm_sort = xyes])
- AM_CONDITIONAL([COND_HAVE_FONT_SOURCE], [test x$FONT_SOURCE != x])
- if test x$FONT_SOURCE != x ; then
-    HAVE_FONT_SOURCE=1
-@@ -2328,6 +2331,11 @@ echo grub-mount: Yes
- else
- echo grub-mount: No "($grub_mount_excuse)"
- fi
-+if [ x"$rpm_sort_excuse" = x ]; then
-+echo grub-rpm-sort: Yes
-+else
-+echo grub-rpm-sort: No "($rpm_sort_excuse)"
-+fi
- if [ x"$starfield_excuse" = x ]; then
- echo starfield theme: Yes
- echo With DejaVuSans font from $DJVU_FONT_SOURCE
-diff --git a/Makefile.util.def b/Makefile.util.def
-index 8cfbe69a76e..3f191aa8095 100644
---- a/Makefile.util.def
-+++ b/Makefile.util.def
-@@ -774,6 +774,7 @@ program = {
-   ldadd = libgrubkern.a;
-   ldadd = grub-core/lib/gnulib/libgnu.a;
-   ldadd = '$(LIBDEVMAPPER) $(LIBRPM)';
-+  condition = COND_GRUB_RPM_SORT;
- };
- 
- script = {
diff --git a/SOURCES/0204-search-new-efidisk-only-option-on-EFI-systems.patch b/SOURCES/0204-search-new-efidisk-only-option-on-EFI-systems.patch
new file mode 100644
index 0000000..3f6194a
--- /dev/null
+++ b/SOURCES/0204-search-new-efidisk-only-option-on-EFI-systems.patch
@@ -0,0 +1,168 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Tue, 8 Feb 2022 08:39:11 +0100
+Subject: [PATCH] search: new --efidisk-only option on EFI systems
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When using 'search' on EFI systems, we sometimes want to exclude devices
+that are not EFI disks (e.g. md, lvm).
+This is typically used when wanting to chainload when having a software
+raid (md) for EFI partition:
+with no option, 'search --file /EFI/redhat/shimx64.efi' sets root envvar
+to 'md/boot_efi' which cannot be used for chainloading since there is no
+effective EFI device behind.
+
+This commit also refactors handling of --no-floppy option.
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+[rharwood: apply rmetrich's flags initialization fix]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/commands/search.c      | 27 +++++++++++++++++++++++----
+ grub-core/commands/search_wrap.c | 18 ++++++++++++------
+ include/grub/search.h            | 15 ++++++++++++---
+ 3 files changed, 47 insertions(+), 13 deletions(-)
+
+diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c
+index 51656e361c..57d26ced8a 100644
+--- a/grub-core/commands/search.c
++++ b/grub-core/commands/search.c
+@@ -47,7 +47,7 @@ struct search_ctx
+ {
+   const char *key;
+   const char *var;
+-  int no_floppy;
++  enum search_flags flags;
+   char **hints;
+   unsigned nhints;
+   int count;
+@@ -62,10 +62,29 @@ iterate_device (const char *name, void *data)
+   int found = 0;
+ 
+   /* Skip floppy drives when requested.  */
+-  if (ctx->no_floppy &&
++  if (ctx->flags & SEARCH_FLAGS_NO_FLOPPY &&
+       name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9')
+     return 0;
+ 
++  /* Limit to EFI disks when requested.  */
++  if (ctx->flags & SEARCH_FLAGS_EFIDISK_ONLY)
++    {
++      grub_device_t dev;
++      dev = grub_device_open (name);
++      if (! dev)
++	{
++	  grub_errno = GRUB_ERR_NONE;
++	  return 0;
++	}
++      if (! dev->disk || dev->disk->dev->id != GRUB_DISK_DEVICE_EFIDISK_ID)
++	{
++	  grub_device_close (dev);
++	  grub_errno = GRUB_ERR_NONE;
++	  return 0;
++	}
++      grub_device_close (dev);
++    }
++
+ #ifdef DO_SEARCH_FS_UUID
+ #define compare_fn grub_strcasecmp
+ #else
+@@ -261,13 +280,13 @@ try (struct search_ctx *ctx)
+ }
+ 
+ void
+-FUNC_NAME (const char *key, const char *var, int no_floppy,
++FUNC_NAME (const char *key, const char *var, enum search_flags flags,
+ 	   char **hints, unsigned nhints)
+ {
+   struct search_ctx ctx = {
+     .key = key,
+     .var = var,
+-    .no_floppy = no_floppy,
++    .flags = flags,
+     .hints = hints,
+     .nhints = nhints,
+     .count = 0,
+diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c
+index 47fc8eb996..0b62acf853 100644
+--- a/grub-core/commands/search_wrap.c
++++ b/grub-core/commands/search_wrap.c
+@@ -40,6 +40,7 @@ static const struct grub_arg_option options[] =
+      N_("Set a variable to the first device found."), N_("VARNAME"),
+      ARG_TYPE_STRING},
+     {"no-floppy",	'n', 0, N_("Do not probe any floppy drive."), 0, 0},
++    {"efidisk-only",	0, 0, N_("Only probe EFI disks."), 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},
+@@ -73,6 +74,7 @@ enum options
+     SEARCH_FS_UUID,
+     SEARCH_SET,
+     SEARCH_NO_FLOPPY,
++    SEARCH_EFIDISK_ONLY,
+     SEARCH_HINT,
+     SEARCH_HINT_IEEE1275,
+     SEARCH_HINT_BIOS,
+@@ -89,6 +91,7 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
+   const char *id = 0;
+   int i = 0, j = 0, nhints = 0;
+   char **hints = NULL;
++  enum search_flags flags = 0;
+ 
+   if (state[SEARCH_HINT].set)
+     for (i = 0; state[SEARCH_HINT].args[i]; i++)
+@@ -180,15 +183,18 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
+       goto out;
+     }
+ 
++  if (state[SEARCH_NO_FLOPPY].set)
++    flags |= SEARCH_FLAGS_NO_FLOPPY;
++
++  if (state[SEARCH_EFIDISK_ONLY].set)
++    flags |= SEARCH_FLAGS_EFIDISK_ONLY;
++
+   if (state[SEARCH_LABEL].set)
+-    grub_search_label (id, var, state[SEARCH_NO_FLOPPY].set, 
+-		       hints, nhints);
++    grub_search_label (id, var, flags, hints, nhints);
+   else if (state[SEARCH_FS_UUID].set)
+-    grub_search_fs_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
+-			 hints, nhints);
++    grub_search_fs_uuid (id, var, flags, hints, nhints);
+   else if (state[SEARCH_FILE].set)
+-    grub_search_fs_file (id, var, state[SEARCH_NO_FLOPPY].set, 
+-			 hints, nhints);
++    grub_search_fs_file (id, var, flags, hints, nhints);
+   else
+     grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type");
+ 
+diff --git a/include/grub/search.h b/include/grub/search.h
+index d80347df34..4190aeb2cb 100644
+--- a/include/grub/search.h
++++ b/include/grub/search.h
+@@ -19,11 +19,20 @@
+ #ifndef GRUB_SEARCH_HEADER
+ #define GRUB_SEARCH_HEADER 1
+ 
+-void grub_search_fs_file (const char *key, const char *var, int no_floppy,
++enum search_flags
++  {
++    SEARCH_FLAGS_NO_FLOPPY	= 1,
++    SEARCH_FLAGS_EFIDISK_ONLY	= 2
++  };
++
++void grub_search_fs_file (const char *key, const char *var,
++			  enum search_flags flags,
+ 			  char **hints, unsigned nhints);
+-void grub_search_fs_uuid (const char *key, const char *var, int no_floppy,
++void grub_search_fs_uuid (const char *key, const char *var,
++			  enum search_flags flags,
+ 			  char **hints, unsigned nhints);
+-void grub_search_label (const char *key, const char *var, int no_floppy,
++void grub_search_label (const char *key, const char *var,
++			enum search_flags flags,
+ 			char **hints, unsigned nhints);
+ 
+ #endif
diff --git a/SOURCES/0205-Don-t-check-for-rpmvercmp-in-librpm.patch b/SOURCES/0205-Don-t-check-for-rpmvercmp-in-librpm.patch
deleted file mode 100644
index c21dca4..0000000
--- a/SOURCES/0205-Don-t-check-for-rpmvercmp-in-librpm.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Fri, 11 Jun 2021 13:13:27 +0200
-Subject: [PATCH] Don't check for rpmvercmp in librpm
-
-The rpmvercmp() function was moved from librpm to librpmio. The configure
-option had some logic to first check if the symbol is in librpm and then
-librpmio if this check didn't succeed.
-
-But the logic wasn't working and rpm sorting was always disabled. Instead
-of trying to fix this logic, let's just remove since the function already
-moved and there's no need to check librpm anymore. Now it's enabled again:
-
-  GRUB2 will be compiled with following components:
-  ...
-  grub-rpm-sort: Yes
-  ...
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- configure.ac | 19 +++++--------------
- 1 file changed, 5 insertions(+), 14 deletions(-)
-
-diff --git a/configure.ac b/configure.ac
-index c7842ec29d8..3c808a72230 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1947,24 +1947,15 @@ if test x"$rpm_sort_excuse" = x ; then
- fi
- 
- if test x"$rpm_sort_excuse" = x ; then
--  # Check for rpm library.
--  AC_CHECK_LIB([rpm], [rpmvercmp], [],
--               [rpm_sort_excuse="rpmlib missing rpmvercmp"])
--fi
--
--if test x"$rpm_sort_excuse" = x ; then
--   LIBRPM="-lrpm";
--   AC_DEFINE([HAVE_RPM], [1],
--             [Define to 1 if you have the rpm library.])
--fi
--
--if test x"$LIBRPM" = x ; then
--  # Check for rpm library.
-+  # Check for rpmio library.
-   AC_CHECK_LIB([rpmio], [rpmvercmp], [],
-                [rpm_sort_excuse="rpmio missing rpmvercmp"])
-+fi
-+
-+if test x"$rpm_sort_excuse" = x ; then
-    LIBRPM="-lrpmio";
-    AC_DEFINE([HAVE_RPMIO], [1],
--             [Define to 1 if you have the rpm library.])
-+             [Define to 1 if you have the rpmio library.])
- fi
- 
- AC_SUBST([LIBRPM])
diff --git a/SOURCES/0205-efi-new-connectefi-command.patch b/SOURCES/0205-efi-new-connectefi-command.patch
new file mode 100644
index 0000000..f80de22
--- /dev/null
+++ b/SOURCES/0205-efi-new-connectefi-command.patch
@@ -0,0 +1,395 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
+Date: Tue, 15 Feb 2022 14:05:22 +0100
+Subject: [PATCH] efi: new 'connectefi' command
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When efi.quickboot is enabled on VMWare (which is the default for
+hardware release 16 and later), it may happen that not all EFI devices
+are connected. Due to this, browsing the devices in make_devices() just
+fails to find devices, in particular disks or partitions for a given
+disk.
+This typically happens when network booting, then trying to chainload to
+local disk (this is used in deployment tools such as Red Hat Satellite),
+which is done through using the following grub.cfg snippet:
+-------- 8< ---------------- 8< ---------------- 8< --------
+unset prefix
+search --file --set=prefix /EFI/redhat/grubx64.efi
+if [ -n "$prefix" ]; then
+  chainloader ($prefix)/EFI/redhat/grubx64/efi
+...
+-------- 8< ---------------- 8< ---------------- 8< --------
+
+With efi.quickboot, none of the devices are connected, causing "search"
+to fail. Sometimes devices are connected but not the partition of the
+disk matching $prefix, causing partition to not be found by
+"chainloader".
+
+This patch introduces a new "connectefi pciroot|scsi" command which
+recursively connects all EFI devices starting from a given controller
+type:
+- if 'pciroot' is specified, recursion is performed for all PCI root
+  handles
+- if 'scsi' is specified, recursion is performed for all SCSI I/O
+  handles (recommended usage to avoid connecting unwanted handles which
+  may impact Grub performances)
+
+Typical grub.cfg snippet would then be:
+-------- 8< ---------------- 8< ---------------- 8< --------
+connectefi scsi
+unset prefix
+search --file --set=prefix /EFI/redhat/grubx64.efi
+if [ -n "$prefix" ]; then
+  chainloader ($prefix)/EFI/redhat/grubx64/efi
+...
+-------- 8< ---------------- 8< ---------------- 8< --------
+
+The code is easily extensible to handle other arguments in the future if
+needed.
+
+Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/Makefile.core.def         |   6 ++
+ grub-core/commands/efi/connectefi.c | 205 ++++++++++++++++++++++++++++++++++++
+ grub-core/commands/efi/lsefi.c      |   1 +
+ grub-core/disk/efi/efidisk.c        |  13 +++
+ grub-core/kern/efi/efi.c            |  13 +++
+ include/grub/efi/disk.h             |   2 +
+ include/grub/efi/efi.h              |   5 +
+ NEWS                                |   2 +-
+ 8 files changed, 246 insertions(+), 1 deletion(-)
+ create mode 100644 grub-core/commands/efi/connectefi.c
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index ec1ec5083b..741a033978 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -836,6 +836,12 @@ module = {
+   enable = efi;
+ };
+ 
++module = {
++  name = connectefi;
++  common = commands/efi/connectefi.c;
++  enable = efi;
++};
++
+ module = {
+   name = blocklist;
+   common = commands/blocklist.c;
+diff --git a/grub-core/commands/efi/connectefi.c b/grub-core/commands/efi/connectefi.c
+new file mode 100644
+index 0000000000..8ab75bd51b
+--- /dev/null
++++ b/grub-core/commands/efi/connectefi.c
+@@ -0,0 +1,205 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2022  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/pci.h>
++#include <grub/efi/efi.h>
++#include <grub/command.h>
++#include <grub/err.h>
++#include <grub/i18n.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++typedef struct handle_list
++{
++  grub_efi_handle_t handle;
++  struct handle_list *next;
++} handle_list_t;
++
++static handle_list_t *already_handled = NULL;
++
++static grub_err_t
++add_handle (grub_efi_handle_t handle)
++{
++  handle_list_t *e;
++  e = grub_malloc (sizeof (*e));
++  if (! e)
++    return grub_errno;
++  e->handle = handle;
++  e->next = already_handled;
++  already_handled = e;
++  return GRUB_ERR_NONE;
++}
++
++static int
++is_in_list (grub_efi_handle_t handle)
++{
++  handle_list_t *e;
++  for (e = already_handled; e != NULL; e = e->next)
++    if (e->handle == handle)
++      return 1;
++  return 0;
++}
++
++static void
++free_handle_list (void)
++{
++  handle_list_t *e;
++  while ((e = already_handled) != NULL)
++    {
++      already_handled = already_handled->next;
++      grub_free (e);
++    }
++}
++
++typedef enum searched_item_flag
++{
++  SEARCHED_ITEM_FLAG_LOOP = 1,
++  SEARCHED_ITEM_FLAG_RECURSIVE = 2
++} searched_item_flags;
++
++typedef struct searched_item
++{
++  grub_efi_guid_t guid;
++  const char *name;
++  searched_item_flags flags;
++} searched_items;
++
++static grub_err_t
++grub_cmd_connectefi (grub_command_t cmd __attribute__ ((unused)),
++		     int argc, char **args)
++{
++  unsigned s;
++  searched_items pciroot_items[] =
++    {
++      { GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root", SEARCHED_ITEM_FLAG_RECURSIVE }
++    };
++  searched_items scsi_items[] =
++    {
++      { GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root", 0 },
++      { GRUB_EFI_PCI_IO_GUID, "PCI", SEARCHED_ITEM_FLAG_LOOP },
++      { GRUB_EFI_SCSI_IO_PROTOCOL_GUID, "SCSI I/O", SEARCHED_ITEM_FLAG_RECURSIVE }
++    };
++  searched_items *items = NULL;
++  unsigned nitems = 0;
++  grub_err_t grub_err = GRUB_ERR_NONE;
++  unsigned total_connected = 0;
++
++  if (argc != 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
++
++  if (grub_strcmp(args[0], N_("pciroot")) == 0)
++    {
++      items = pciroot_items;
++      nitems = ARRAY_SIZE (pciroot_items);
++    }
++  else if (grub_strcmp(args[0], N_("scsi")) == 0)
++    {
++      items = scsi_items;
++      nitems = ARRAY_SIZE (scsi_items);
++    }
++  else
++    return grub_error (GRUB_ERR_BAD_ARGUMENT,
++		       N_("unexpected argument `%s'"), args[0]);
++
++  for (s = 0; s < nitems; s++)
++    {
++      grub_efi_handle_t *handles;
++      grub_efi_uintn_t num_handles;
++      unsigned i, connected = 0, loop = 0;
++
++loop:
++      loop++;
++      grub_dprintf ("efi", "step '%s' loop %d:\n", items[s].name, loop);
++
++      handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL,
++					&items[s].guid, 0, &num_handles);
++
++      if (!handles)
++	continue;
++
++      for (i = 0; i < num_handles; i++)
++	{
++	  grub_efi_handle_t handle = handles[i];
++	  grub_efi_status_t status;
++	  unsigned j;
++
++	  /* Skip already handled handles  */
++	  if (is_in_list (handle))
++	    {
++	      grub_dprintf ("efi", "  handle %p: already processed\n",
++				   handle);
++	      continue;
++	    }
++
++	  status = grub_efi_connect_controller(handle, NULL, NULL,
++			items[s].flags & SEARCHED_ITEM_FLAG_RECURSIVE ? 1 : 0);
++	  if (status == GRUB_EFI_SUCCESS)
++	    {
++	      connected++;
++	      total_connected++;
++	      grub_dprintf ("efi", "  handle %p: connected\n", handle);
++	    }
++	  else
++	    grub_dprintf ("efi", "  handle %p: failed to connect (%d)\n",
++				 handle, (grub_efi_int8_t) status);
++
++	  if ((grub_err = add_handle (handle)) != GRUB_ERR_NONE)
++	    break; /* fatal  */
++	}
++
++      grub_free (handles);
++      if (grub_err != GRUB_ERR_NONE)
++	break; /* fatal  */
++
++      if (items[s].flags & SEARCHED_ITEM_FLAG_LOOP && connected)
++	{
++	  connected = 0;
++	  goto loop;
++	}
++
++      free_handle_list ();
++    }
++
++  free_handle_list ();
++
++  if (total_connected)
++    grub_efidisk_reenumerate_disks ();
++
++  return grub_err;
++}
++
++static grub_command_t cmd;
++
++GRUB_MOD_INIT(connectefi)
++{
++  cmd = grub_register_command ("connectefi", grub_cmd_connectefi,
++			       N_("pciroot|scsi"),
++			       N_("Connect EFI handles."
++				  " If 'pciroot' is specified, connect PCI"
++				  " root EFI handles recursively."
++				  " If 'scsi' is specified, connect SCSI"
++				  " I/O EFI handles recursively."));
++}
++
++GRUB_MOD_FINI(connectefi)
++{
++  grub_unregister_command (cmd);
++}
+diff --git a/grub-core/commands/efi/lsefi.c b/grub-core/commands/efi/lsefi.c
+index d1ce99af43..f2d2430e66 100644
+--- a/grub-core/commands/efi/lsefi.c
++++ b/grub-core/commands/efi/lsefi.c
+@@ -19,6 +19,7 @@
+ #include <grub/mm.h>
+ #include <grub/misc.h>
+ #include <grub/efi/api.h>
++#include <grub/efi/disk.h>
+ #include <grub/efi/edid.h>
+ #include <grub/efi/pci.h>
+ #include <grub/efi/efi.h>
+diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c
+index fe8ba6e6c9..062143dfff 100644
+--- a/grub-core/disk/efi/efidisk.c
++++ b/grub-core/disk/efi/efidisk.c
+@@ -396,6 +396,19 @@ enumerate_disks (void)
+   free_devices (devices);
+ }
+ 
++void
++grub_efidisk_reenumerate_disks (void)
++{
++  free_devices (fd_devices);
++  free_devices (hd_devices);
++  free_devices (cd_devices);
++  fd_devices = 0;
++  hd_devices = 0;
++  cd_devices = 0;
++
++  enumerate_disks ();
++}
++
+ static int
+ grub_efidisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
+ 		      grub_disk_pull_t pull)
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index 14bc10eb56..7fcca69c17 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -95,6 +95,19 @@ grub_efi_locate_handle (grub_efi_locate_search_type_t search_type,
+   return buffer;
+ }
+ 
++grub_efi_status_t
++grub_efi_connect_controller (grub_efi_handle_t controller_handle,
++			     grub_efi_handle_t *driver_image_handle,
++			     grub_efi_device_path_protocol_t *remaining_device_path,
++			     grub_efi_boolean_t recursive)
++{
++  grub_efi_boot_services_t *b;
++
++  b = grub_efi_system_table->boot_services;
++  return efi_call_4 (b->connect_controller, controller_handle,
++		     driver_image_handle, remaining_device_path, recursive);
++}
++
+ void *
+ grub_efi_open_protocol (grub_efi_handle_t handle,
+ 			grub_efi_guid_t *protocol,
+diff --git a/include/grub/efi/disk.h b/include/grub/efi/disk.h
+index 254475c842..6845c2f1fd 100644
+--- a/include/grub/efi/disk.h
++++ b/include/grub/efi/disk.h
+@@ -27,6 +27,8 @@ grub_efi_handle_t
+ EXPORT_FUNC(grub_efidisk_get_device_handle) (grub_disk_t disk);
+ char *EXPORT_FUNC(grub_efidisk_get_device_name) (grub_efi_handle_t *handle);
+ 
++void EXPORT_FUNC(grub_efidisk_reenumerate_disks) (void);
++
+ void grub_efidisk_init (void);
+ void grub_efidisk_fini (void);
+ 
+diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
+index 8dfc89a33b..ec52083c49 100644
+--- a/include/grub/efi/efi.h
++++ b/include/grub/efi/efi.h
+@@ -41,6 +41,11 @@ EXPORT_FUNC(grub_efi_locate_handle) (grub_efi_locate_search_type_t search_type,
+ 				     grub_efi_guid_t *protocol,
+ 				     void *search_key,
+ 				     grub_efi_uintn_t *num_handles);
++grub_efi_status_t
++EXPORT_FUNC(grub_efi_connect_controller) (grub_efi_handle_t controller_handle,
++					  grub_efi_handle_t *driver_image_handle,
++					  grub_efi_device_path_protocol_t *remaining_device_path,
++					  grub_efi_boolean_t recursive);
+ void *EXPORT_FUNC(grub_efi_open_protocol) (grub_efi_handle_t handle,
+ 					   grub_efi_guid_t *protocol,
+ 					   grub_efi_uint32_t attributes);
+diff --git a/NEWS b/NEWS
+index 73b8492bc4..d7c1d23aed 100644
+--- a/NEWS
++++ b/NEWS
+@@ -98,7 +98,7 @@ New in 2.02:
+   * Prefer pmtimer for TSC calibration.
+ 
+ * New/improved platform support:
+-  * New `efifwsetup' and `lsefi' commands on EFI platforms.
++  * New `efifwsetup', `lsefi' and `connectefi` commands on EFI platforms.
+   * New `cmosdump' and `cmosset' commands on platforms with CMOS support.
+   * New command `pcidump' for PCI platforms.
+   * Improve opcode parsing in ACPI halt implementation.
diff --git a/SOURCES/0206-Allow-chainloading-EFI-apps-from-loop-mounts.patch b/SOURCES/0206-Allow-chainloading-EFI-apps-from-loop-mounts.patch
deleted file mode 100644
index e48f102..0000000
--- a/SOURCES/0206-Allow-chainloading-EFI-apps-from-loop-mounts.patch
+++ /dev/null
@@ -1,136 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Dimitri John Ledkov <xnox@ubuntu.com>
-Date: Fri, 11 Jun 2021 13:51:20 +0200
-Subject: [PATCH] Allow chainloading EFI apps from loop mounts.
-
----
- grub-core/disk/loopback.c          |  9 +--------
- grub-core/loader/efi/chainloader.c | 23 +++++++++++++++++++++++
- include/grub/loopback.h            | 30 ++++++++++++++++++++++++++++++
- 3 files changed, 54 insertions(+), 8 deletions(-)
- create mode 100644 include/grub/loopback.h
-
-diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c
-index 41bebd14fe3..99f47924ec2 100644
---- a/grub-core/disk/loopback.c
-+++ b/grub-core/disk/loopback.c
-@@ -21,20 +21,13 @@
- #include <grub/misc.h>
- #include <grub/file.h>
- #include <grub/disk.h>
-+#include <grub/loopback.h>
- #include <grub/mm.h>
- #include <grub/extcmd.h>
- #include <grub/i18n.h>
- 
- GRUB_MOD_LICENSE ("GPLv3+");
- 
--struct grub_loopback
--{
--  char *devname;
--  grub_file_t file;
--  struct grub_loopback *next;
--  unsigned long id;
--};
--
- static struct grub_loopback *loopback_list;
- static unsigned long last_id = 0;
- 
-diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
-index d41e8ea14a8..3af6b122926 100644
---- a/grub-core/loader/efi/chainloader.c
-+++ b/grub-core/loader/efi/chainloader.c
-@@ -24,6 +24,7 @@
- #include <grub/err.h>
- #include <grub/device.h>
- #include <grub/disk.h>
-+#include <grub/loopback.h>
- #include <grub/misc.h>
- #include <grub/charset.h>
- #include <grub/mm.h>
-@@ -901,6 +902,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
-   grub_efi_status_t status;
-   grub_efi_boot_services_t *b;
-   grub_device_t dev = 0;
-+  grub_device_t orig_dev = 0;
-   grub_efi_device_path_t *dp = 0;
-   char *filename;
-   void *boot_image = 0;
-@@ -958,6 +960,15 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
-   if (! dev)
-     goto fail;
- 
-+  /* if device is loopback, use underlying dev */
-+  if (dev->disk->dev->id == GRUB_DISK_DEVICE_LOOPBACK_ID)
-+    {
-+      struct grub_loopback *d;
-+      orig_dev = dev;
-+      d = dev->disk->data;
-+      dev = d->file->device;
-+    }
-+
-   if (dev->disk)
-     dev_handle = grub_efidisk_get_device_handle (dev->disk);
-   else if (dev->net && dev->net->server)
-@@ -1065,6 +1076,12 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
-     }
- #endif
- 
-+  if (orig_dev)
-+    {
-+      dev = orig_dev;
-+      orig_dev = 0;
-+    }
-+
-   rc = grub_linuxefi_secure_validate((void *)(unsigned long)address, fsize);
-   grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc);
-   if (rc > 0)
-@@ -1087,6 +1104,12 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
-   // -1 fall-through to fail
- 
- fail:
-+  if (orig_dev)
-+    {
-+      dev = orig_dev;
-+      orig_dev = 0;
-+    }
-+
-   if (dev)
-     grub_device_close (dev);
- 
-diff --git a/include/grub/loopback.h b/include/grub/loopback.h
-new file mode 100644
-index 00000000000..3b9a9e32e80
---- /dev/null
-+++ b/include/grub/loopback.h
-@@ -0,0 +1,30 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2019  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/>.
-+ */
-+
-+#ifndef GRUB_LOOPBACK_HEADER
-+#define GRUB_LOOPBACK_HEADER	1
-+
-+struct grub_loopback
-+{
-+  char *devname;
-+  grub_file_t file;
-+  struct grub_loopback *next;
-+  unsigned long id;
-+};
-+
-+#endif /* ! GRUB_LOOPBACK_HEADER */
diff --git a/SOURCES/0206-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch b/SOURCES/0206-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch
new file mode 100644
index 0000000..4fe8adf
--- /dev/null
+++ b/SOURCES/0206-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch
@@ -0,0 +1,73 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
+Date: Thu, 3 Mar 2022 13:10:56 +0100
+Subject: [PATCH] grub-core/loader/i386/efi/linux.c: do not validate kernels
+ twice
+
+On codebases that have shim-lock-verifier built into the grub core
+(like 2.06 upstream), shim-lock-verifier is in enforcing mode when
+booted with secureboot. It means that grub_cmd_linux() command
+attempts to perform shim validate upon opening linux kernel image,
+including kernel measurement. And the verifier correctly returns file
+open error when shim validate protocol is not present or shim fails to
+validate the kernel.
+
+This makes the call to grub_linuxefi_secure_validate() redundant, but
+also harmful. As validating the kernel image twice, extends the PCRs
+with the same measurement twice. Which breaks existing sealing
+policies when upgrading from grub2.04+rhboot+sb+linuxefi to
+grub2.06+rhboot+sb+linuxefi builds. It is also incorrect to measure
+the kernel twice.
+
+This patch must not be ported to older editions of grub code bases
+that do not have verifiers framework, or it is not builtin, or
+shim-lock-verifier is an optional module.
+
+This patch is tested to ensure that unsigned kernels are not possible
+to boot in secureboot mode when shim rejects kernel, or shim protocol
+is missing, and that the measurements become stable once again. The
+above also ensures that CVE-2020-15705 is not reintroduced.
+
+Signed-off-by: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
+---
+ grub-core/loader/i386/efi/linux.c | 13 -------------
+ 1 file changed, 13 deletions(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 3cf0f9b330..941df6400b 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -30,7 +30,6 @@
+ #include <grub/cpu/efi/memory.h>
+ #include <grub/tpm.h>
+ #include <grub/safemath.h>
+-#include <grub/efi/sb.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -278,7 +277,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_ssize_t start, filelen;
+   void *kernel = NULL;
+   int setup_header_end_offset;
+-  int rc;
+ 
+   grub_dl_ref (my_mod);
+ 
+@@ -308,17 +306,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED)
+-    {
+-      rc = grub_linuxefi_secure_validate (kernel, filelen);
+-      if (rc <= 0)
+-	{
+-	  grub_error (GRUB_ERR_INVALID_COMMAND,
+-		      N_("%s has invalid signature"), argv[0]);
+-	  goto fail;
+-	}
+-    }
+-
+   lh = (struct linux_i386_kernel_header *)kernel;
+   grub_dprintf ("linux", "original lh is at %p\n", kernel);
+ 
diff --git a/SOURCES/0207-efinet-Add-DHCP-proxy-support.patch b/SOURCES/0207-efinet-Add-DHCP-proxy-support.patch
deleted file mode 100644
index a8755a3..0000000
--- a/SOURCES/0207-efinet-Add-DHCP-proxy-support.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Ian Page Hands <iphands@gmail.com>
-Date: Tue, 8 Jun 2021 13:48:56 -0400
-Subject: [PATCH] efinet: Add DHCP proxy support
-
-If a proxyDHCP configuration is used, the server name, server IP and boot
-file values should be taken from the DHCP proxy offer instead of the DHCP
-server ack packet. Currently that case is not handled, add support for it.
----
- grub-core/net/drivers/efi/efinet.c | 25 +++++++++++++++++++++++--
- 1 file changed, 23 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
-index e11d759f19a..1a24f38a21a 100644
---- a/grub-core/net/drivers/efi/efinet.c
-+++ b/grub-core/net/drivers/efi/efinet.c
-@@ -850,10 +850,31 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
-     else
-       {
- 	grub_dprintf ("efinet", "using ipv4 and dhcp\n");
-+
-+        struct grub_net_bootp_packet *dhcp_ack = &pxe_mode->dhcp_ack;
-+
-+        if (pxe_mode->proxy_offer_received)
-+          {
-+            grub_dprintf ("efinet", "proxy offer receive");
-+            struct grub_net_bootp_packet *proxy_offer = &pxe_mode->proxy_offer;
-+
-+            if (proxy_offer && dhcp_ack->boot_file[0] == '\0')
-+              {
-+                grub_dprintf ("efinet", "setting values from proxy offer");
-+                /* Here we got a proxy offer and the dhcp_ack has a nil boot_file
-+                 * Copy the proxy DHCP offer details into the bootp_packet we are
-+                 * sending forward as they are the deatils we need.
-+                 */
-+                *dhcp_ack->server_name = *proxy_offer->server_name;
-+                *dhcp_ack->boot_file   = *proxy_offer->boot_file;
-+                dhcp_ack->server_ip    = proxy_offer->server_ip;
-+              }
-+          }
-+
- 	grub_net_configure_by_dhcp_ack (card->name, card, 0,
- 					(struct grub_net_bootp_packet *)
--					packet_buf,
--					packet_bufsz,
-+					&pxe_mode->dhcp_ack,
-+					sizeof (pxe_mode->dhcp_ack),
- 					1, device, path);
- 	grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
-       }
diff --git a/SOURCES/0207-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch b/SOURCES/0207-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch
new file mode 100644
index 0000000..5b450f9
--- /dev/null
+++ b/SOURCES/0207-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch
@@ -0,0 +1,58 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
+Date: Fri, 4 Mar 2022 11:29:31 +0100
+Subject: [PATCH] grub-core/loader/arm64/linux.c: do not validate kernel twice
+
+Call to grub_file_open(, GRUB_FILE_TYPE_LINUX_KERNEL) already passes
+the kernel file through shim-lock verifier when secureboot is on. Thus
+there is no need to validate the kernel image again. And when doing so
+again, duplicate PCR measurement is performed, breaking measurements
+compatibility with 2.04+linuxefi.
+
+This patch must not be ported to older editions of grub code bases
+that do not have verifiers framework, or it is not builtin, or
+shim-lock-verifier is an optional module.
+
+Signed-off-by: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
+---
+ grub-core/loader/arm64/linux.c | 13 -------------
+ 1 file changed, 13 deletions(-)
+
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index f18d90bd74..d2af47c2c0 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -34,7 +34,6 @@
+ #include <grub/i18n.h>
+ #include <grub/lib/cmdline.h>
+ #include <grub/verify.h>
+-#include <grub/efi/sb.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -341,7 +340,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_off_t filelen;
+   grub_uint32_t align;
+   void *kernel = NULL;
+-  int rc;
+ 
+   grub_dl_ref (my_mod);
+ 
+@@ -370,17 +368,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED)
+-    {
+-      rc = grub_linuxefi_secure_validate (kernel, filelen);
+-      if (rc <= 0)
+-	{
+-	  grub_error (GRUB_ERR_INVALID_COMMAND,
+-		      N_("%s has invalid signature"), argv[0]);
+-	  goto fail;
+-	}
+-    }
+-
+   if (grub_arch_efi_linux_check_image (kernel) != GRUB_ERR_NONE)
+     goto fail;
+   if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align) != GRUB_ERR_NONE)
diff --git a/SOURCES/0208-fs-ext2-Ignore-checksum-seed-incompat-feature.patch b/SOURCES/0208-fs-ext2-Ignore-checksum-seed-incompat-feature.patch
deleted file mode 100644
index b4a5fd4..0000000
--- a/SOURCES/0208-fs-ext2-Ignore-checksum-seed-incompat-feature.patch
+++ /dev/null
@@ -1,54 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Fri, 11 Jun 2021 00:01:29 +0200
-Subject: [PATCH] fs/ext2: Ignore checksum seed incompat feature
-
-This incompat feature is used to denote that the filesystem stored its
-metadata checksum seed in the superblock. This is used to allow tune2fs
-to change the UUID on a mounted metadata_csum filesystem without having
-to rewrite all the disk metadata.
-
-But GRUB doesn't use the metadata checksum in anyway, so can just ignore
-this feature if is enabled. This is consistent with GRUB filesystem code
-in general which just does a best effort to access the filesystem's data.
-
-It may be removed from the ignored list in the future if supports to do
-metadata checksumming verification is added to the read-only FS driver.
-
-Suggested-by: Eric Sandeen <esandeen@redhat.com>
-Suggested-by: Lukas Czerner <lczerner@redhat.com>
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/fs/ext2.c | 10 +++++++++-
- 1 file changed, 9 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c
-index e7dd78e6635..731d346f886 100644
---- a/grub-core/fs/ext2.c
-+++ b/grub-core/fs/ext2.c
-@@ -103,6 +103,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
- #define EXT4_FEATURE_INCOMPAT_64BIT		0x0080
- #define EXT4_FEATURE_INCOMPAT_MMP		0x0100
- #define EXT4_FEATURE_INCOMPAT_FLEX_BG		0x0200
-+#define EXT4_FEATURE_INCOMPAT_CSUM_SEED		0x2000
- #define EXT4_FEATURE_INCOMPAT_ENCRYPT          0x10000
- 
- /* The set of back-incompatible features this driver DOES support. Add (OR)
-@@ -123,9 +124,16 @@ GRUB_MOD_LICENSE ("GPLv3+");
-  * mmp:            Not really back-incompatible - was added as such to
-  *                 avoid multiple read-write mounts. Safe to ignore for this
-  *                 RO driver.
-+ * checksum seed:  Not really back-incompatible - was added to allow tools
-+ *                 such as tune2fs to change the UUID on a mounted metadata
-+ *                 checksummed filesystem. Safe to ignore for now since the
-+ *                 driver doesn't support checksum verification. But it must
-+ *                 be removed from this list if that support is added later.
-+ *
-  */
- #define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER \
--				     | EXT4_FEATURE_INCOMPAT_MMP)
-+				     | EXT4_FEATURE_INCOMPAT_MMP \
-+				     | EXT4_FEATURE_INCOMPAT_CSUM_SEED)
- 
- 
- #define EXT3_JOURNAL_MAGIC_NUMBER	0xc03b3998U
diff --git a/SOURCES/0208-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch b/SOURCES/0208-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch
new file mode 100644
index 0000000..4c56d60
--- /dev/null
+++ b/SOURCES/0208-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch
@@ -0,0 +1,80 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
+Date: Fri, 4 Mar 2022 09:31:43 +0100
+Subject: [PATCH] grub-core/loader/efi/chainloader.c: do not validate
+ chainloader twice
+
+On secureboot systems, with shimlock verifier, call to
+grub_file_open(, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE) will already
+pass the chainloader target through shim-lock protocol verify
+call. And create a TPM measurement. If verification fails,
+grub_cmd_chainloader will fail at file open time.
+
+This makes previous code paths for negative, and zero return codes
+from grub_linuxefi_secure_validate unreachable under secureboot. But
+also breaking measurements compatibility with 2.04+linuxefi codebases,
+as the chainloader file is passed through shim_lock->verify() twice
+(via verifier & direct call to grub_linuxefi_secure_validate)
+extending the PCRs twice.
+
+This reduces grub_loader options to perform
+grub_secureboot_chainloader when secureboot is on, and otherwise
+attempt grub_chainloader_boot.
+
+It means that booting with secureboot off, yet still with shim (which
+always verifies things successfully), will stop choosing
+grub_secureboot_chainloader, and opting for a more regular
+loadimage/startimage codepath. If we want to use the
+grub_secureboot_chainloader codepath in such scenarios we should adapt
+the code to simply check for shim_lock protocol presence /
+shim_lock->context() success?! But I am not sure if that is necessary.
+
+This patch must not be ported to older editions of grub code bases
+that do not have verifiers framework, or it is not builtin, or
+shim-lock-verifier is an optional module.
+
+Signed-off-by: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
+---
+ grub-core/loader/efi/chainloader.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index 3af6b12292..644cd2e56f 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -906,7 +906,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+   grub_efi_device_path_t *dp = 0;
+   char *filename;
+   void *boot_image = 0;
+-  int rc;
+ 
+   if (argc == 0)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+@@ -1082,9 +1081,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+       orig_dev = 0;
+     }
+ 
+-  rc = grub_linuxefi_secure_validate((void *)(unsigned long)address, fsize);
+-  grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc);
+-  if (rc > 0)
++  if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED)
+     {
+       grub_file_close (file);
+       grub_device_close (dev);
+@@ -1092,7 +1089,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+ 		       grub_secureboot_chainloader_unload, 0);
+       return 0;
+     }
+-  else if (rc == 0)
++  else
+     {
+       grub_load_and_start_image(boot_image);
+       grub_file_close (file);
+@@ -1101,7 +1098,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+ 
+       return 0;
+     }
+-  // -1 fall-through to fail
+ 
+ fail:
+   if (orig_dev)
diff --git a/SOURCES/0209-Don-t-update-the-cmdline-when-generating-legacy-menu.patch b/SOURCES/0209-Don-t-update-the-cmdline-when-generating-legacy-menu.patch
deleted file mode 100644
index c55b7e3..0000000
--- a/SOURCES/0209-Don-t-update-the-cmdline-when-generating-legacy-menu.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Thu, 17 Jun 2021 14:31:42 +0200
-Subject: [PATCH] Don't update the cmdline when generating legacy menuentry
- commands
-
-On OPAL ppc64le machines with an old petitboot version that doesn't have
-support to parse BLS snippets, the grub2-mkconfig script is executed to
-generate menuentry commands from the BLS snippets.
-
-In this case, the script is executed with the --no-grubenv-update option
-that indicates that no side effects should happen when running the script.
-
-But the options field in the BLS snippets are updated regardless, only do
-the update if --no-grubenv-update was not used.
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- util/grub.d/10_linux.in | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
-index 68adb55d893..c9296154f51 100644
---- a/util/grub.d/10_linux.in
-+++ b/util/grub.d/10_linux.in
-@@ -261,7 +261,9 @@ if [ -z "\${kernelopts}" ]; then
- fi
- EOF
- 
--  update_bls_cmdline
-+  if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then
-+      update_bls_cmdline
-+  fi
- 
-   if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then
-       populate_menu
diff --git a/SOURCES/0209-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch b/SOURCES/0209-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch
new file mode 100644
index 0000000..c683fcb
--- /dev/null
+++ b/SOURCES/0209-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch
@@ -0,0 +1,83 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
+Date: Fri, 4 Mar 2022 11:36:09 +0100
+Subject: [PATCH] grub-core/loader/efi/linux.c: drop now unused
+ grub_linuxefi_secure_validate
+
+Drop the now unused grub_linuxefi_secure_validate() as all prior users
+of this API now rely on the shim-lock-verifier codepath instead.
+
+This patch must not be ported to older editions of grub code bases
+that do not have verifiers framework, or it is not builtin, or
+shim-lock-verifier is an optional module.
+
+Signed-off-by: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
+---
+ grub-core/loader/efi/linux.c | 40 ----------------------------------------
+ include/grub/efi/linux.h     |  2 --
+ 2 files changed, 42 deletions(-)
+
+diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
+index 9260731c10..9265cf4200 100644
+--- a/grub-core/loader/efi/linux.c
++++ b/grub-core/loader/efi/linux.c
+@@ -24,46 +24,6 @@
+ #include <grub/efi/pe32.h>
+ #include <grub/efi/linux.h>
+ 
+-#define SHIM_LOCK_GUID \
+- { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
+-
+-struct grub_efi_shim_lock
+-{
+-  grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size);
+-};
+-typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
+-
+-// Returns 1 on success, -1 on error, 0 when not available
+-int
+-grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
+-{
+-  grub_efi_guid_t guid = SHIM_LOCK_GUID;
+-  grub_efi_shim_lock_t *shim_lock;
+-  grub_efi_status_t status;
+-
+-  shim_lock = grub_efi_locate_protocol(&guid, NULL);
+-  grub_dprintf ("secureboot", "shim_lock: %p\n", shim_lock);
+-  if (!shim_lock)
+-    {
+-      grub_dprintf ("secureboot", "shim not available\n");
+-      return 0;
+-    }
+-
+-  grub_dprintf ("secureboot", "Asking shim to verify kernel signature\n");
+-  status = shim_lock->verify (data, size);
+-  grub_dprintf ("secureboot", "shim_lock->verify(): %ld\n", (long int)status);
+-  if (status == GRUB_EFI_SUCCESS)
+-    {
+-      grub_dprintf ("secureboot", "Kernel signature verification passed\n");
+-      return 1;
+-    }
+-
+-  grub_dprintf ("secureboot", "Kernel signature verification failed (0x%lx)\n",
+-		(unsigned long) status);
+-
+-  return -1;
+-}
+-
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wcast-align"
+ 
+diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
+index 0033d9305a..887b02fd9f 100644
+--- a/include/grub/efi/linux.h
++++ b/include/grub/efi/linux.h
+@@ -22,8 +22,6 @@
+ #include <grub/err.h>
+ #include <grub/symbol.h>
+ 
+-int
+-EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size);
+ grub_err_t
+ EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset,
+ 				  void *kernel_param);
diff --git a/SOURCES/0210-Suppress-gettext-error-message.patch b/SOURCES/0210-Suppress-gettext-error-message.patch
deleted file mode 100644
index c57e7ff..0000000
--- a/SOURCES/0210-Suppress-gettext-error-message.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
-Date: Tue, 29 Jun 2021 13:17:42 +0200
-Subject: [PATCH] Suppress gettext error message
-
-Colin Watson's patch from comment #11 on the upstream bug:
-https://savannah.gnu.org/bugs/?35880#comment11
-
-Resolves: rhbz#1592124
-
-Signed-off-by: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
----
- grub-core/gettext/gettext.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
-diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c
-index 84d520cd494..87a912ac6e5 100644
---- a/grub-core/gettext/gettext.c
-+++ b/grub-core/gettext/gettext.c
-@@ -424,6 +424,13 @@ grub_gettext_init_ext (struct grub_gettext_context *ctx,
-       grub_free (lang);
-     }
- 
-+  /* If no translations are available, fall back to untranslated text. */
-+  if (err == GRUB_ERR_FILE_NOT_FOUND)
-+    {
-+      grub_errno = GRUB_ERR_NONE;
-+      return 0;
-+    }
-+
-   if (locale[0] == 'e' && locale[1] == 'n'
-       && (locale[2] == '\0' || locale[2] == '_'))
-     grub_errno = err = GRUB_ERR_NONE;
diff --git a/SOURCES/0210-powerpc-prefix-detection-support-device-names-with-c.patch b/SOURCES/0210-powerpc-prefix-detection-support-device-names-with-c.patch
new file mode 100644
index 0000000..1c16fd3
--- /dev/null
+++ b/SOURCES/0210-powerpc-prefix-detection-support-device-names-with-c.patch
@@ -0,0 +1,71 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 24 Mar 2022 14:34:32 +1100
+Subject: [PATCH] powerpc: prefix detection: support device names with commas
+
+Frustratingly, the device name itself can contain an embedded comma:
+e.g /pci@800000020000015/pci1014,034A@0/sas/disk@5000c50098a0ee8b
+
+So my previous approach was wrong: we cannot rely upon the presence
+of a comma to say that a partition has been specified!
+
+It turns out for prefixes like (,gpt2)/grub2 we really want to make
+up a full (device,partition)/patch prefix, because root discovery code
+in 10_linux will reset the root variable and use search to fill it again.
+If you have run grub-install, you probably don't have search built in,
+and if you don't have prefix containing (device,partition), grub will
+construct ($root)$prefix/powerpc-ieee1275/search.mod - but because $root
+has just been changed, this will no longer work, and the boot will fail!
+
+Retain the gist of the logic, but instead of looking for a comma, look for
+a leading '('. This matches the earlier code better anyway.
+
+There's certainly a better fix to be had. But any time you chose to build
+with a bare prefix like '/grub2', you're almost certainly going to build in
+search anyway, so this will do.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+---
+ grub-core/kern/main.c | 27 +++++++++++++++++++++------
+ 1 file changed, 21 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
+index 993b8a8598..e94a2f78fb 100644
+--- a/grub-core/kern/main.c
++++ b/grub-core/kern/main.c
+@@ -242,14 +242,29 @@ grub_set_prefix_and_root (void)
+ 	    what sorts of paths represent disks with partition tables and those
+ 	    without partition tables.
+ 
+-	 So we act unless there is a comma in the device, which would indicate
+-	 a partition has already been specified.
++          - Frustratingly, the device name itself can contain an embedded comma:
++            /pci@800000020000015/pci1014,034A@0/sas/disk@5000c50098a0ee8b
++            So we cannot even rely upon the presence of a comma to say that a
++            partition has been specified!
+ 
+-	 (If we only have a path, the code in normal to discover config files
+-	 will try both without partitions and then with any partitions so we
+-	 will cover both CDs and HDs.)
++         If we only have a path in $prefix, the code in normal to discover
++	 config files will try all disks, both without partitions and then with
++	 any partitions so we will cover both CDs and HDs.
++
++         However, it doesn't then set the prefix to be something like
++         (discovered partition)/path, and so it is fragile against runtime
++         changes to $root. For example some of the stuff done in 10_linux to
++         reload $root sets root differently and then uses search to find it
++         again. If the search module is not built in, when we change root, grub
++         will look in (new root)/path/powerpc-ieee1275, that won't work, and we
++         will not be able to load the search module and the boot will fail.
++
++         This is particularly likely to hit us in the grub-install
++         (,msdos2)/grub2 case, so we act unless the supplied prefix starts with
++         '(', which would likely indicate a partition has already been
++         specified.
+        */
+-      if (grub_strchr (device, ',') == NULL)
++      if (prefix && prefix[0] != '(')
+         grub_env_set ("prefix", path);
+       else
+ #endif
diff --git a/SOURCES/0211-grub-boot-success.timer-Only-run-if-not-in-a-contain.patch b/SOURCES/0211-grub-boot-success.timer-Only-run-if-not-in-a-contain.patch
deleted file mode 100644
index 61d0f6d..0000000
--- a/SOURCES/0211-grub-boot-success.timer-Only-run-if-not-in-a-contain.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Gena Makhomed <gmm@csdoc.com>
-Date: Thu, 1 Jul 2021 01:07:46 +0200
-Subject: [PATCH] grub-boot-success.timer: Only run if not in a container
-
-The grub-boot-success.timer should be disabled inside a container since it
-leads to the following error:
-
-Jan 09 22:56:38 test sshd[8786]: pam_unix(sshd:session): session opened for user www(uid=1000) by (uid=0)
-Jan 09 22:58:39 test systemd[8857]: Starting Mark boot as successful...
-Jan 09 22:58:39 test systemd[8857]: grub-boot-success.service: Main process exited, code=exited, status=1/FAILURE
-Jan 09 22:58:39 test systemd[8857]: grub-boot-success.service: Failed with result 'exit-code'.
-Jan 09 22:58:39 test systemd[8857]: Failed to start Mark boot as successful.
-Jan 09 22:58:39 test grub2-set-bootflag[10034]: Error canonicalizing /boot/grub2/grubenv filename: No such file or directory
-
-Resolves: rhbz#1914571
----
- docs/grub-boot-success.timer | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/docs/grub-boot-success.timer b/docs/grub-boot-success.timer
-index 5d8fcba21aa..406f1720056 100644
---- a/docs/grub-boot-success.timer
-+++ b/docs/grub-boot-success.timer
-@@ -1,6 +1,7 @@
- [Unit]
- Description=Mark boot as successful after the user session has run 2 minutes
- ConditionUser=!@system
-+ConditionVirtualization=!container
- 
- [Timer]
- OnActiveSec=2min
diff --git a/SOURCES/0211-make-ofdisk_retries-optional.patch b/SOURCES/0211-make-ofdisk_retries-optional.patch
new file mode 100644
index 0000000..fce9702
--- /dev/null
+++ b/SOURCES/0211-make-ofdisk_retries-optional.patch
@@ -0,0 +1,43 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Diego Domingos <diegdo@br.ibm.com>
+Date: Thu, 24 Mar 2022 13:14:42 -0400
+Subject: [PATCH] make ofdisk_retries optional
+
+The feature Retry on Fail added to GRUB can cause a LPM to take
+longer if the SAN is slow.
+
+When a LPM to external site occur, the path of the disk can change
+and thus the disk search function on grub can take some time since
+it is used as a hint. This can cause the Retry on Fail feature to
+try to access the disk 20x times (since this is hardcoded number)
+and, if the SAN is slow, the boot time can increase a lot.
+In some situations not acceptable.
+
+The following patch enables a configuration at user space of the
+maximum number of retries we want for this feature.
+
+The variable ofdisk_retries should be set using grub2-editenv
+and will be checked by retry function. If the variable is not set,
+so the default number of retries will be used instead.
+---
+ include/grub/ieee1275/ofdisk.h | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/include/grub/ieee1275/ofdisk.h b/include/grub/ieee1275/ofdisk.h
+index 7d2d540930..0074d55eee 100644
+--- a/include/grub/ieee1275/ofdisk.h
++++ b/include/grub/ieee1275/ofdisk.h
+@@ -25,7 +25,12 @@ extern void grub_ofdisk_fini (void);
+ #define MAX_RETRIES 20
+ 
+ 
+-#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) unsigned retry_i=0;for(retry_i=0; retry_i < MAX_RETRIES; retry_i++){ \
++#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) \
++	                                        unsigned max_retries = MAX_RETRIES; \
++                                                if(grub_env_get("ofdisk_retries") != NULL) \
++                                                     max_retries = grub_strtoul(grub_env_get("ofdisk_retries"), 0, 10)+1; \
++                                                grub_dprintf("ofdisk","MAX_RETRIES set to %u\n",max_retries); \
++                                                unsigned retry_i=0;for(retry_i=0; retry_i < max_retries; retry_i++){ \
+ 						if(!grub_ieee1275_open(device, last_ihandle)) \
+ 						break; \
+ 						grub_dprintf("ofdisk","Opening disk %s failed. Retrying...\n",device); }
diff --git a/SOURCES/0212-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch b/SOURCES/0212-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch
deleted file mode 100644
index 7ecea22..0000000
--- a/SOURCES/0212-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Mon, 5 Jul 2021 18:24:22 +0200
-Subject: [PATCH] grub-set-password: Always use /boot/grub2/user.cfg as
- password default
-
-The GRUB configuration file is always placed in /boot/grub2/ now, even for
-EFI. But the tool is still creating the user.cfg in the ESP and not there.
-
-Resolves: rhbz#1955294
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- util/grub-set-password.in | 9 +--------
- 1 file changed, 1 insertion(+), 8 deletions(-)
-
-diff --git a/util/grub-set-password.in b/util/grub-set-password.in
-index c0b5ebbfdc5..d8005e5a142 100644
---- a/util/grub-set-password.in
-+++ b/util/grub-set-password.in
-@@ -1,11 +1,6 @@
- #!/bin/sh -e
- 
--EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g')
--if [ -d /sys/firmware/efi/efivars/ ]; then
--    grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'`
--else
--    grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`
--fi
-+grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`
- 
- PACKAGE_VERSION="@PACKAGE_VERSION@"
- PACKAGE_NAME="@PACKAGE_NAME@"
-@@ -116,8 +111,6 @@ if [ -z "${MYPASS}" ]; then
-       exit 1
- fi
- 
--# on the ESP, these will fail to set the permissions, but it's okay because
--# the directory is protected.
- install -m 0600 /dev/null "${OUTPUT_PATH}/user.cfg" 2>/dev/null || :
- chmod 0600 "${OUTPUT_PATH}/user.cfg" 2>/dev/null || :
- echo "GRUB2_PASSWORD=${MYPASS}" > "${OUTPUT_PATH}/user.cfg"
diff --git a/SOURCES/0212-loader-efi-chainloader-grub_load_and_start_image-doe.patch b/SOURCES/0212-loader-efi-chainloader-grub_load_and_start_image-doe.patch
new file mode 100644
index 0000000..f61ed28
--- /dev/null
+++ b/SOURCES/0212-loader-efi-chainloader-grub_load_and_start_image-doe.patch
@@ -0,0 +1,69 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Chris Coulson <chris.coulson@canonical.com>
+Date: Thu, 28 Apr 2022 21:53:36 +0100
+Subject: [PATCH] loader/efi/chainloader: grub_load_and_start_image doesn't
+ load and start
+
+grub_load_and_start_image only loads an image - it still requires the
+caller to start it. This renames it to grub_load_image.
+
+It's called from 2 places:
+- grub_cmd_chainloader when not using the shim protocol.
+- grub_secureboot_chainloader_boot if handle_image returns an error.
+In this case, the image is loaded and then nothing else happens which
+seems strange. I assume the intention is that it falls back to LoadImage
+and StartImage if handle_image fails, so I've made it do that.
+
+Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
+(cherry picked from commit b4d70820a65c00561045856b7b8355461a9545f6)
+---
+ grub-core/loader/efi/chainloader.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index 644cd2e56f..d3bf02ed8a 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -841,7 +841,7 @@ grub_secureboot_chainloader_unload (void)
+ }
+ 
+ static grub_err_t
+-grub_load_and_start_image(void *boot_image)
++grub_load_image(void *boot_image)
+ {
+   grub_efi_boot_services_t *b;
+   grub_efi_status_t status;
+@@ -883,13 +883,23 @@ grub_load_and_start_image(void *boot_image)
+ static grub_err_t
+ grub_secureboot_chainloader_boot (void)
+ {
++  grub_efi_boot_services_t *b;
+   int rc;
++
+   rc = handle_image ((void *)(unsigned long)address, fsize);
+   if (rc == 0)
+     {
+-      grub_load_and_start_image((void *)(unsigned long)address);
++      /* We weren't able to attempt to execute the image, so fall back
++       * to LoadImage / StartImage.
++       */
++      rc = grub_load_image((void *)(unsigned long)address);
++      if (rc == 0)
++        grub_chainloader_boot ();
+     }
+ 
++  b = grub_efi_system_table->boot_services;
++  efi_call_1 (b->unload_image, image_handle);
++
+   grub_loader_unset ();
+   return grub_errno;
+ }
+@@ -1091,7 +1101,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+     }
+   else
+     {
+-      grub_load_and_start_image(boot_image);
++      grub_load_image(boot_image);
+       grub_file_close (file);
+       grub_device_close (dev);
+       grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
diff --git a/SOURCES/0213-Remove-outdated-URL-for-BLS-document.patch b/SOURCES/0213-Remove-outdated-URL-for-BLS-document.patch
deleted file mode 100644
index d380fe8..0000000
--- a/SOURCES/0213-Remove-outdated-URL-for-BLS-document.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Mon, 5 Jul 2021 19:00:25 +0200
-Subject: [PATCH] Remove outdated URL for BLS document
-
-The document was moved to https://systemd.io/BOOT_LOADER_SPECIFICATION/,
-update the URL accordingly to point to the current location.
-
-Resolves: rhbz#1926453
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- util/grub.d/10_linux.in | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
-index c9296154f51..6ee0a2cf3d0 100644
---- a/util/grub.d/10_linux.in
-+++ b/util/grub.d/10_linux.in
-@@ -96,7 +96,7 @@ cat <<EOF
- #
- # The $bls_parser parses the BootLoaderSpec files stored in /boot/loader/entries and
- # populates the boot menu. Please refer to the Boot Loader Specification documentation
--# for the files format: https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/.
-+# for the files format: https://systemd.io/BOOT_LOADER_SPECIFICATION/.
- 
- EOF
- }
diff --git a/SOURCES/0213-loader-efi-chainloader-simplify-the-loader-state.patch b/SOURCES/0213-loader-efi-chainloader-simplify-the-loader-state.patch
new file mode 100644
index 0000000..205124e
--- /dev/null
+++ b/SOURCES/0213-loader-efi-chainloader-simplify-the-loader-state.patch
@@ -0,0 +1,330 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Chris Coulson <chris.coulson@canonical.com>
+Date: Fri, 29 Apr 2022 21:13:08 +0100
+Subject: [PATCH] loader/efi/chainloader: simplify the loader state
+
+When not using the shim lock protocol, the chainloader command retains
+the source buffer and device path passed to LoadImage, requiring the
+unload hook passed to grub_loader_set to free them. It isn't required
+to retain this state though - they aren't required by StartImage or
+anything else in the boot hook, so clean them up before
+grub_cmd_chainloader finishes.
+
+This also wraps the loader state when using the shim lock protocol
+inside a struct.
+
+Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
+(cherry picked from commit fa39862933b3be1553a580a3a5c28073257d8046)
+[rharwood: fix unitialized handle and double-frees of file/dev]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/loader/efi/chainloader.c | 160 +++++++++++++++++++++++--------------
+ 1 file changed, 102 insertions(+), 58 deletions(-)
+
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index d3bf02ed8a..3342492ff1 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -48,38 +48,21 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+ static grub_dl_t my_mod;
+ 
+-static grub_efi_physical_address_t address;
+-static grub_efi_uintn_t pages;
+-static grub_ssize_t fsize;
+-static grub_efi_device_path_t *file_path;
+ static grub_efi_handle_t image_handle;
+-static grub_efi_char16_t *cmdline;
+-static grub_ssize_t cmdline_len;
+-static grub_efi_handle_t dev_handle;
+ 
+-static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table);
++struct grub_secureboot_chainloader_context {
++  grub_efi_physical_address_t address;
++  grub_efi_uintn_t pages;
++  grub_ssize_t fsize;
++  grub_efi_device_path_t *file_path;
++  grub_efi_char16_t *cmdline;
++  grub_ssize_t cmdline_len;
++  grub_efi_handle_t dev_handle;
++};
++static struct grub_secureboot_chainloader_context *sb_context;
+ 
+ static grub_err_t
+-grub_chainloader_unload (void)
+-{
+-  grub_efi_boot_services_t *b;
+-
+-  b = grub_efi_system_table->boot_services;
+-  efi_call_1 (b->unload_image, image_handle);
+-  grub_efi_free_pages (address, pages);
+-
+-  grub_free (file_path);
+-  grub_free (cmdline);
+-  cmdline = 0;
+-  file_path = 0;
+-  dev_handle = 0;
+-
+-  grub_dl_unref (my_mod);
+-  return GRUB_ERR_NONE;
+-}
+-
+-static grub_err_t
+-grub_chainloader_boot (void)
++grub_start_image (grub_efi_handle_t handle)
+ {
+   grub_efi_boot_services_t *b;
+   grub_efi_status_t status;
+@@ -87,7 +70,7 @@ grub_chainloader_boot (void)
+   grub_efi_char16_t *exit_data = NULL;
+ 
+   b = grub_efi_system_table->boot_services;
+-  status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data);
++  status = efi_call_3 (b->start_image, handle, &exit_data_size, &exit_data);
+   if (status != GRUB_EFI_SUCCESS)
+     {
+       if (exit_data)
+@@ -111,11 +94,37 @@ grub_chainloader_boot (void)
+   if (exit_data)
+     grub_efi_free_pool (exit_data);
+ 
+-  grub_loader_unset ();
+-
+   return grub_errno;
+ }
+ 
++static grub_err_t
++grub_chainloader_unload (void)
++{
++  grub_efi_loaded_image_t *loaded_image;
++  grub_efi_boot_services_t *b;
++
++  loaded_image = grub_efi_get_loaded_image (image_handle);
++  if (loaded_image != NULL)
++    grub_free (loaded_image->load_options);
++
++  b = grub_efi_system_table->boot_services;
++  efi_call_1 (b->unload_image, image_handle);
++
++  grub_dl_unref (my_mod);
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_chainloader_boot (void)
++{
++  grub_err_t err;
++
++  err = grub_start_image (image_handle);
++
++  grub_loader_unset ();
++  return err;
++}
++
+ static grub_err_t
+ copy_file_path (grub_efi_file_path_device_path_t *fp,
+ 		const char *str, grub_efi_uint16_t len)
+@@ -150,7 +159,7 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
+   char *dir_start;
+   char *dir_end;
+   grub_size_t size;
+-  grub_efi_device_path_t *d;
++  grub_efi_device_path_t *d, *file_path;
+ 
+   dir_start = grub_strchr (filename, ')');
+   if (! dir_start)
+@@ -526,10 +535,12 @@ grub_efi_get_media_file_path (grub_efi_device_path_t *dp)
+ }
+ 
+ static grub_efi_boolean_t
+-handle_image (void *data, grub_efi_uint32_t datasize)
++handle_image (struct grub_secureboot_chainloader_context *load_context)
+ {
+   grub_efi_loaded_image_t *li, li_bak;
+   grub_efi_status_t efi_status;
++  void *data = (void *)(unsigned long)load_context->address;
++  grub_efi_uint32_t datasize = load_context->fsize;
+   void *buffer = NULL;
+   char *buffer_aligned = NULL;
+   grub_efi_uint32_t i;
+@@ -540,6 +551,7 @@ handle_image (void *data, grub_efi_uint32_t datasize)
+   grub_uint32_t buffer_size;
+   int found_entry_point = 0;
+   int rc;
++  grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table);
+ 
+   rc = read_header (data, datasize, &context);
+   if (rc < 0)
+@@ -797,10 +809,10 @@ handle_image (void *data, grub_efi_uint32_t datasize)
+   grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t));
+   li->image_base = buffer_aligned;
+   li->image_size = context.image_size;
+-  li->load_options = cmdline;
+-  li->load_options_size = cmdline_len;
+-  li->file_path = grub_efi_get_media_file_path (file_path);
+-  li->device_handle = dev_handle;
++  li->load_options = load_context->cmdline;
++  li->load_options_size = load_context->cmdline_len;
++  li->file_path = grub_efi_get_media_file_path (load_context->file_path);
++  li->device_handle = load_context->dev_handle;
+   if (!li->file_path)
+     {
+       grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file path found");
+@@ -829,19 +841,22 @@ error_exit:
+ static grub_err_t
+ grub_secureboot_chainloader_unload (void)
+ {
+-  grub_efi_free_pages (address, pages);
+-  grub_free (file_path);
+-  grub_free (cmdline);
+-  cmdline = 0;
+-  file_path = 0;
+-  dev_handle = 0;
++  grub_efi_free_pages (sb_context->address, sb_context->pages);
++  grub_free (sb_context->file_path);
++  grub_free (sb_context->cmdline);
++  grub_free (sb_context);
++
++  sb_context = 0;
+ 
+   grub_dl_unref (my_mod);
+   return GRUB_ERR_NONE;
+ }
+ 
+ static grub_err_t
+-grub_load_image(void *boot_image)
++grub_load_image(grub_efi_device_path_t *file_path, void *boot_image,
++		grub_efi_uintn_t image_size, grub_efi_handle_t dev_handle,
++		grub_efi_char16_t *cmdline, grub_ssize_t cmdline_len,
++		grub_efi_handle_t *image_handle_out)
+ {
+   grub_efi_boot_services_t *b;
+   grub_efi_status_t status;
+@@ -850,7 +865,7 @@ grub_load_image(void *boot_image)
+   b = grub_efi_system_table->boot_services;
+ 
+   status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
+-		       boot_image, fsize, &image_handle);
++		       boot_image, image_size, image_handle_out);
+   if (status != GRUB_EFI_SUCCESS)
+     {
+       if (status == GRUB_EFI_OUT_OF_RESOURCES)
+@@ -863,7 +878,7 @@ grub_load_image(void *boot_image)
+   /* LoadImage does not set a device handler when the image is
+      loaded from memory, so it is necessary to set it explicitly here.
+      This is a mess.  */
+-  loaded_image = grub_efi_get_loaded_image (image_handle);
++  loaded_image = grub_efi_get_loaded_image (*image_handle_out);
+   if (! loaded_image)
+     {
+       grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
+@@ -885,20 +900,25 @@ grub_secureboot_chainloader_boot (void)
+ {
+   grub_efi_boot_services_t *b;
+   int rc;
++  grub_efi_handle_t handle = 0;
+ 
+-  rc = handle_image ((void *)(unsigned long)address, fsize);
++  rc = handle_image (sb_context);
+   if (rc == 0)
+     {
+       /* We weren't able to attempt to execute the image, so fall back
+        * to LoadImage / StartImage.
+        */
+-      rc = grub_load_image((void *)(unsigned long)address);
++      rc = grub_load_image(sb_context->file_path,
++			   (void *)(unsigned long)sb_context->address,
++			   sb_context->fsize, sb_context->dev_handle,
++			   sb_context->cmdline, sb_context->cmdline_len,
++			   &handle);
+       if (rc == 0)
+-        grub_chainloader_boot ();
++	grub_start_image (handle);
+     }
+ 
+   b = grub_efi_system_table->boot_services;
+-  efi_call_1 (b->unload_image, image_handle);
++  efi_call_1 (b->unload_image, handle);
+ 
+   grub_loader_unset ();
+   return grub_errno;
+@@ -913,9 +933,15 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+   grub_efi_boot_services_t *b;
+   grub_device_t dev = 0;
+   grub_device_t orig_dev = 0;
+-  grub_efi_device_path_t *dp = 0;
++  grub_efi_device_path_t *dp = 0, *file_path = 0;
+   char *filename;
+   void *boot_image = 0;
++  grub_efi_physical_address_t address = 0;
++  grub_ssize_t fsize;
++  grub_efi_uintn_t pages = 0;
++  grub_efi_char16_t *cmdline = 0;
++  grub_ssize_t cmdline_len = 0;
++  grub_efi_handle_t dev_handle = 0;
+ 
+   if (argc == 0)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+@@ -923,12 +949,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+ 
+   grub_dl_ref (my_mod);
+ 
+-  /* Initialize some global variables.  */
+-  address = 0;
+-  image_handle = 0;
+-  file_path = 0;
+-  dev_handle = 0;
+-
+   b = grub_efi_system_table->boot_services;
+ 
+   if (argc > 1)
+@@ -1093,17 +1113,35 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+ 
+   if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED)
+     {
++      sb_context = grub_malloc (sizeof (*sb_context));
++      if (sb_context == NULL)
++        goto fail;
++      sb_context->address = address;
++      sb_context->fsize = fsize;
++      sb_context->pages = pages;
++      sb_context->file_path = file_path;
++      sb_context->cmdline = cmdline;
++      sb_context->cmdline_len = cmdline_len;
++      sb_context->dev_handle = dev_handle;
++
+       grub_file_close (file);
+       grub_device_close (dev);
++
+       grub_loader_set (grub_secureboot_chainloader_boot,
+ 		       grub_secureboot_chainloader_unload, 0);
+       return 0;
+     }
+   else
+     {
+-      grub_load_image(boot_image);
++      grub_load_image(file_path, boot_image, fsize, dev_handle, cmdline,
++		      cmdline_len, &image_handle);
+       grub_file_close (file);
+       grub_device_close (dev);
++
++      /* We're finished with the source image buffer and file path now */
++      efi_call_2 (b->free_pages, address, pages);
++      grub_free (file_path);
++
+       grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
+ 
+       return 0;
+@@ -1130,6 +1168,12 @@ fail:
+   if (cmdline)
+     grub_free (cmdline);
+ 
++  if (image_handle != 0)
++    {
++      efi_call_1 (b->unload_image, image_handle);
++      image_handle = 0;
++    }
++
+   grub_dl_unref (my_mod);
+ 
+   return grub_errno;
diff --git a/SOURCES/0214-commands-boot-Add-API-to-pass-context-to-loader.patch b/SOURCES/0214-commands-boot-Add-API-to-pass-context-to-loader.patch
new file mode 100644
index 0000000..63a2d76
--- /dev/null
+++ b/SOURCES/0214-commands-boot-Add-API-to-pass-context-to-loader.patch
@@ -0,0 +1,158 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Chris Coulson <chris.coulson@canonical.com>
+Date: Fri, 29 Apr 2022 21:16:02 +0100
+Subject: [PATCH] commands/boot: Add API to pass context to loader
+
+Loaders rely on global variables for saving context which is consumed
+in the boot hook and freed in the unload hook. In the case where a loader
+command is executed twice, calling grub_loader_set a second time executes
+the unload hook, but in some cases this runs when the loader's global
+context has already been updated, resulting in the updated context being
+freed and potential use-after-free bugs when the boot hook is subsequently
+called.
+
+This adds a new API (grub_loader_set_ex) which allows a loader to specify
+context that is passed to its boot and unload hooks. This is an alternative
+to requiring that loaders call grub_loader_unset before mutating their
+global context.
+
+Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
+(cherry picked from commit 4322a64dde7e8fedb58e50b79408667129d45dd3)
+---
+ grub-core/commands/boot.c | 66 +++++++++++++++++++++++++++++++++++++++++------
+ include/grub/loader.h     |  5 ++++
+ 2 files changed, 63 insertions(+), 8 deletions(-)
+
+diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c
+index bbca81e947..53691a62d9 100644
+--- a/grub-core/commands/boot.c
++++ b/grub-core/commands/boot.c
+@@ -27,10 +27,20 @@
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+-static grub_err_t (*grub_loader_boot_func) (void);
+-static grub_err_t (*grub_loader_unload_func) (void);
++static grub_err_t (*grub_loader_boot_func) (void *);
++static grub_err_t (*grub_loader_unload_func) (void *);
++static void *grub_loader_context;
+ static int grub_loader_flags;
+ 
++struct grub_simple_loader_hooks
++{
++  grub_err_t (*boot) (void);
++  grub_err_t (*unload) (void);
++};
++
++/* Don't heap allocate this to avoid making grub_loader_set fallible. */
++static struct grub_simple_loader_hooks simple_loader_hooks;
++
+ struct grub_preboot
+ {
+   grub_err_t (*preboot_func) (int);
+@@ -44,6 +54,29 @@ static int grub_loader_loaded;
+ static struct grub_preboot *preboots_head = 0,
+   *preboots_tail = 0;
+ 
++static grub_err_t
++grub_simple_boot_hook (void *context)
++{
++  struct grub_simple_loader_hooks *hooks;
++
++  hooks = (struct grub_simple_loader_hooks *) context;
++  return hooks->boot ();
++}
++
++static grub_err_t
++grub_simple_unload_hook (void *context)
++{
++  struct grub_simple_loader_hooks *hooks;
++  grub_err_t ret;
++
++  hooks = (struct grub_simple_loader_hooks *) context;
++
++  ret = hooks->unload ();
++  grub_memset (hooks, 0, sizeof (*hooks));
++
++  return ret;
++}
++
+ int
+ grub_loader_is_loaded (void)
+ {
+@@ -110,28 +143,45 @@ grub_loader_unregister_preboot_hook (struct grub_preboot *hnd)
+ }
+ 
+ void
+-grub_loader_set (grub_err_t (*boot) (void),
+-		 grub_err_t (*unload) (void),
+-		 int flags)
++grub_loader_set_ex (grub_err_t (*boot) (void *),
++		    grub_err_t (*unload) (void *),
++		    void *context,
++		    int flags)
+ {
+   if (grub_loader_loaded && grub_loader_unload_func)
+-    grub_loader_unload_func ();
++    grub_loader_unload_func (grub_loader_context);
+ 
+   grub_loader_boot_func = boot;
+   grub_loader_unload_func = unload;
++  grub_loader_context = context;
+   grub_loader_flags = flags;
+ 
+   grub_loader_loaded = 1;
+ }
+ 
++void
++grub_loader_set (grub_err_t (*boot) (void),
++		 grub_err_t (*unload) (void),
++		 int flags)
++{
++  grub_loader_set_ex (grub_simple_boot_hook,
++		      grub_simple_unload_hook,
++		      &simple_loader_hooks,
++		      flags);
++
++  simple_loader_hooks.boot = boot;
++  simple_loader_hooks.unload = unload;
++}
++
+ void
+ grub_loader_unset(void)
+ {
+   if (grub_loader_loaded && grub_loader_unload_func)
+-    grub_loader_unload_func ();
++    grub_loader_unload_func (grub_loader_context);
+ 
+   grub_loader_boot_func = 0;
+   grub_loader_unload_func = 0;
++  grub_loader_context = 0;
+ 
+   grub_loader_loaded = 0;
+ }
+@@ -158,7 +208,7 @@ grub_loader_boot (void)
+ 	  return err;
+ 	}
+     }
+-  err = (grub_loader_boot_func) ();
++  err = (grub_loader_boot_func) (grub_loader_context);
+ 
+   for (cur = preboots_tail; cur; cur = cur->prev)
+     if (! err)
+diff --git a/include/grub/loader.h b/include/grub/loader.h
+index b208642821..1846fa6c5f 100644
+--- a/include/grub/loader.h
++++ b/include/grub/loader.h
+@@ -40,6 +40,11 @@ void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void),
+ 				    grub_err_t (*unload) (void),
+ 				    int flags);
+ 
++void EXPORT_FUNC (grub_loader_set_ex) (grub_err_t (*boot) (void *),
++				       grub_err_t (*unload) (void *),
++				       void *context,
++				       int flags);
++
+ /* Unset current loader, if any.  */
+ void EXPORT_FUNC (grub_loader_unset) (void);
+ 
diff --git a/SOURCES/0214-templates-Check-for-EFI-at-runtime-instead-of-config.patch b/SOURCES/0214-templates-Check-for-EFI-at-runtime-instead-of-config.patch
deleted file mode 100644
index e36afa1..0000000
--- a/SOURCES/0214-templates-Check-for-EFI-at-runtime-instead-of-config.patch
+++ /dev/null
@@ -1,63 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Tue, 6 Jul 2021 00:38:40 +0200
-Subject: [PATCH] templates: Check for EFI at runtime instead of config
- generation time
-
-The 30_uefi-firmware template checks if an OsIndicationsSupported UEFI var
-exists and EFI_OS_INDICATIONS_BOOT_TO_FW_UI bit is set, to decide whether
-a "fwsetup" menu entry would be added or not to the GRUB menu.
-
-But this has the problem that it will only work if the configuration file
-was created on an UEFI machine that supports booting to a firmware UI.
-
-This for example doesn't support creating GRUB config files when executing
-on systems that support both UEFI and legacy BIOS booting. Since creating
-the config file from legacy BIOS wouldn't allow to access the firmware UI.
-
-To prevent this, make the template to unconditionally create the grub.cfg
-snippet but check at runtime if was booted through UEFI to decide if this
-entry should be added. That way it won't be added when booting with BIOS.
-
-There's no need to check if EFI_OS_INDICATIONS_BOOT_TO_FW_UI bit is set,
-since that's already done by the "fwsetup" command when is executed.
-
-Resolves: rhbz#1823864
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- util/grub.d/30_uefi-firmware.in | 21 ++++++++-------------
- 1 file changed, 8 insertions(+), 13 deletions(-)
-
-diff --git a/util/grub.d/30_uefi-firmware.in b/util/grub.d/30_uefi-firmware.in
-index d344d3883d7..b6041b55e2a 100644
---- a/util/grub.d/30_uefi-firmware.in
-+++ b/util/grub.d/30_uefi-firmware.in
-@@ -26,19 +26,14 @@ export TEXTDOMAINDIR="@localedir@"
- 
- . "$pkgdatadir/grub-mkconfig_lib"
- 
--EFI_VARS_DIR=/sys/firmware/efi/efivars
--EFI_GLOBAL_VARIABLE=8be4df61-93ca-11d2-aa0d-00e098032b8c
--OS_INDICATIONS="$EFI_VARS_DIR/OsIndicationsSupported-$EFI_GLOBAL_VARIABLE"
-+LABEL="UEFI Firmware Settings"
- 
--if [ -e "$OS_INDICATIONS" ] && \
--   [ "$(( $(printf 0x%x \'"$(cat $OS_INDICATIONS | cut -b5)"\') & 1 ))" = 1 ]; then
--  LABEL="UEFI Firmware Settings"
-+gettext_printf "Adding boot menu entry for UEFI Firmware Settings ...\n" >&2
- 
--  gettext_printf "Adding boot menu entry for UEFI Firmware Settings ...\n" >&2
--
--  cat << EOF
--menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' {
--	fwsetup
--}
--EOF
-+cat << EOF
-+if [ "\$grub_platform" = "efi" ]; then
-+	menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' {
-+		fwsetup
-+	}
- fi
-+EOF
diff --git a/SOURCES/0215-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch b/SOURCES/0215-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch
deleted file mode 100644
index 65b4aec..0000000
--- a/SOURCES/0215-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch
+++ /dev/null
@@ -1,92 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Tue, 6 Jul 2021 01:10:18 +0200
-Subject: [PATCH] efi: Print an error if boot to firmware setup is not
- supported
-
-The "fwsetup" command is only registered if the firmware supports booting
-to the firmware setup UI. But it could be possible that the GRUB config
-already contains a "fwsetup" entry, because it was generated in a machine
-that has support for this feature.
-
-To prevent users getting a "can't find command `fwsetup`" error if it is
-not supported by the firmware, let's just always register the command but
-print a more accurate message if the firmware doesn't support this option.
-
-Resolves: rhbz#1823864
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/commands/efi/efifwsetup.c | 43 ++++++++++++++++++++-----------------
- 1 file changed, 23 insertions(+), 20 deletions(-)
-
-diff --git a/grub-core/commands/efi/efifwsetup.c b/grub-core/commands/efi/efifwsetup.c
-index eaca0328388..328c45e82e0 100644
---- a/grub-core/commands/efi/efifwsetup.c
-+++ b/grub-core/commands/efi/efifwsetup.c
-@@ -27,6 +27,25 @@
- 
- GRUB_MOD_LICENSE ("GPLv3+");
- 
-+static grub_efi_boolean_t
-+efifwsetup_is_supported (void)
-+{
-+  grub_efi_uint64_t *os_indications_supported = NULL;
-+  grub_size_t oi_size = 0;
-+  grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
-+
-+  grub_efi_get_variable ("OsIndicationsSupported", &global, &oi_size,
-+			 (void **) &os_indications_supported);
-+
-+  if (!os_indications_supported)
-+    return 0;
-+
-+  if (*os_indications_supported & GRUB_EFI_OS_INDICATIONS_BOOT_TO_FW_UI)
-+    return 1;
-+
-+  return 0;
-+}
-+
- static grub_err_t
- grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)),
- 		  int argc __attribute__ ((unused)),
-@@ -38,6 +57,10 @@ grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)),
-   grub_size_t oi_size;
-   grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
- 
-+  if (!efifwsetup_is_supported ())
-+	  return grub_error (GRUB_ERR_INVALID_COMMAND,
-+			     N_("Reboot to firmware setup is not supported"));
-+
-   grub_efi_get_variable ("OsIndications", &global, &oi_size,
- 			 (void **) &old_os_indications);
- 
-@@ -56,28 +79,8 @@ grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)),
- 
- static grub_command_t cmd = NULL;
- 
--static grub_efi_boolean_t
--efifwsetup_is_supported (void)
--{
--  grub_efi_uint64_t *os_indications_supported = NULL;
--  grub_size_t oi_size = 0;
--  grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
--
--  grub_efi_get_variable ("OsIndicationsSupported", &global, &oi_size,
--			 (void **) &os_indications_supported);
--
--  if (!os_indications_supported)
--    return 0;
--
--  if (*os_indications_supported & GRUB_EFI_OS_INDICATIONS_BOOT_TO_FW_UI)
--    return 1;
--
--  return 0;
--}
--
- GRUB_MOD_INIT (efifwsetup)
- {
--  if (efifwsetup_is_supported ())
-     cmd = grub_register_command ("fwsetup", grub_cmd_fwsetup, NULL,
- 				 N_("Reboot into firmware setup menu."));
- 
diff --git a/SOURCES/0215-loader-efi-chainloader-Use-grub_loader_set_ex.patch b/SOURCES/0215-loader-efi-chainloader-Use-grub_loader_set_ex.patch
new file mode 100644
index 0000000..fc15b84
--- /dev/null
+++ b/SOURCES/0215-loader-efi-chainloader-Use-grub_loader_set_ex.patch
@@ -0,0 +1,147 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Chris Coulson <chris.coulson@canonical.com>
+Date: Fri, 29 Apr 2022 21:30:56 +0100
+Subject: [PATCH] loader/efi/chainloader: Use grub_loader_set_ex
+
+This ports the EFI chainloader to use grub_loader_set_ex in order to fix
+a use-after-free bug that occurs when grub_cmd_chainloader is executed
+more than once before a boot attempt is performed.
+
+Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
+(cherry picked from commit 4b7f0402b7cb0f67a93be736f2b75b818d7f44c9)
+[rharwood: context sludge from other change]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/loader/efi/chainloader.c | 38 ++++++++++++++++++++++----------------
+ 1 file changed, 22 insertions(+), 16 deletions(-)
+
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index 3342492ff1..fb874f1855 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -48,8 +48,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+ static grub_dl_t my_mod;
+ 
+-static grub_efi_handle_t image_handle;
+-
+ struct grub_secureboot_chainloader_context {
+   grub_efi_physical_address_t address;
+   grub_efi_uintn_t pages;
+@@ -59,7 +57,6 @@ struct grub_secureboot_chainloader_context {
+   grub_ssize_t cmdline_len;
+   grub_efi_handle_t dev_handle;
+ };
+-static struct grub_secureboot_chainloader_context *sb_context;
+ 
+ static grub_err_t
+ grub_start_image (grub_efi_handle_t handle)
+@@ -98,11 +95,14 @@ grub_start_image (grub_efi_handle_t handle)
+ }
+ 
+ static grub_err_t
+-grub_chainloader_unload (void)
++grub_chainloader_unload (void *context)
+ {
++  grub_efi_handle_t image_handle;
+   grub_efi_loaded_image_t *loaded_image;
+   grub_efi_boot_services_t *b;
+ 
++  image_handle = (grub_efi_handle_t) context;
++
+   loaded_image = grub_efi_get_loaded_image (image_handle);
+   if (loaded_image != NULL)
+     grub_free (loaded_image->load_options);
+@@ -115,10 +115,12 @@ grub_chainloader_unload (void)
+ }
+ 
+ static grub_err_t
+-grub_chainloader_boot (void)
++grub_chainloader_boot (void *context)
+ {
++  grub_efi_handle_t image_handle;
+   grub_err_t err;
+ 
++  image_handle = (grub_efi_handle_t) context;
+   err = grub_start_image (image_handle);
+ 
+   grub_loader_unset ();
+@@ -839,15 +841,17 @@ error_exit:
+ }
+ 
+ static grub_err_t
+-grub_secureboot_chainloader_unload (void)
++grub_secureboot_chainloader_unload (void *context)
+ {
++  struct grub_secureboot_chainloader_context *sb_context;
++
++  sb_context = (struct grub_secureboot_chainloader_context *) context;
++
+   grub_efi_free_pages (sb_context->address, sb_context->pages);
+   grub_free (sb_context->file_path);
+   grub_free (sb_context->cmdline);
+   grub_free (sb_context);
+ 
+-  sb_context = 0;
+-
+   grub_dl_unref (my_mod);
+   return GRUB_ERR_NONE;
+ }
+@@ -896,12 +900,15 @@ grub_load_image(grub_efi_device_path_t *file_path, void *boot_image,
+ }
+ 
+ static grub_err_t
+-grub_secureboot_chainloader_boot (void)
++grub_secureboot_chainloader_boot (void *context)
+ {
++  struct grub_secureboot_chainloader_context *sb_context;
+   grub_efi_boot_services_t *b;
+   int rc;
+   grub_efi_handle_t handle = 0;
+ 
++  sb_context = (struct grub_secureboot_chainloader_context *) context;
++
+   rc = handle_image (sb_context);
+   if (rc == 0)
+     {
+@@ -942,6 +949,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+   grub_efi_char16_t *cmdline = 0;
+   grub_ssize_t cmdline_len = 0;
+   grub_efi_handle_t dev_handle = 0;
++  grub_efi_handle_t image_handle = 0;
++  struct grub_secureboot_chainloader_context *sb_context = 0;
+ 
+   if (argc == 0)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+@@ -1127,8 +1136,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+       grub_file_close (file);
+       grub_device_close (dev);
+ 
+-      grub_loader_set (grub_secureboot_chainloader_boot,
+-		       grub_secureboot_chainloader_unload, 0);
++      grub_loader_set_ex (grub_secureboot_chainloader_boot,
++			  grub_secureboot_chainloader_unload, sb_context, 0);
+       return 0;
+     }
+   else
+@@ -1142,7 +1151,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+       efi_call_2 (b->free_pages, address, pages);
+       grub_free (file_path);
+ 
+-      grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
++      grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0);
+ 
+       return 0;
+     }
+@@ -1169,10 +1178,7 @@ fail:
+     grub_free (cmdline);
+ 
+   if (image_handle != 0)
+-    {
+-      efi_call_1 (b->unload_image, image_handle);
+-      image_handle = 0;
+-    }
++    efi_call_1 (b->unload_image, image_handle);
+ 
+   grub_dl_unref (my_mod);
+ 
diff --git a/SOURCES/0216-arm64-Fix-EFI-loader-kernel-image-allocation.patch b/SOURCES/0216-arm64-Fix-EFI-loader-kernel-image-allocation.patch
deleted file mode 100644
index 600b461..0000000
--- a/SOURCES/0216-arm64-Fix-EFI-loader-kernel-image-allocation.patch
+++ /dev/null
@@ -1,189 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-Date: Mon, 2 Aug 2021 23:10:01 +1000
-Subject: [PATCH] arm64: Fix EFI loader kernel image allocation
-
-We are currently allocating just enough memory for the file size,
-which means that the kernel BSS is in limbo (and not even zeroed).
-
-We are also not honoring the alignment specified in the image
-PE header.
-
-This makes us use the PE optional header in which the kernel puts the
-actual size it needs, including BSS, and make sure we clear it, and
-honors the specified alignment for the image.
-
-Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
----
- grub-core/loader/arm64/linux.c | 100 +++++++++++++++++++++++++++--------------
- 1 file changed, 66 insertions(+), 34 deletions(-)
-
-diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
-index 47f8cf0d84b..4a252d5e7e9 100644
---- a/grub-core/loader/arm64/linux.c
-+++ b/grub-core/loader/arm64/linux.c
-@@ -41,6 +41,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
- static grub_dl_t my_mod;
- static int loaded;
- 
-+static void *kernel_alloc_addr;
-+static grub_uint32_t kernel_alloc_pages;
- static void *kernel_addr;
- static grub_uint64_t kernel_size;
- static grub_uint32_t handover_offset;
-@@ -204,9 +206,8 @@ grub_linux_unload (void)
- 			 GRUB_EFI_BYTES_TO_PAGES (initrd_end - initrd_start));
-   initrd_start = initrd_end = 0;
-   grub_free (linux_args);
--  if (kernel_addr)
--    grub_efi_free_pages ((grub_addr_t) kernel_addr,
--			 GRUB_EFI_BYTES_TO_PAGES (kernel_size));
-+  if (kernel_alloc_addr)
-+    grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages);
-   grub_fdt_unload ();
-   return GRUB_ERR_NONE;
- }
-@@ -311,14 +312,35 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
-   return grub_errno;
- }
- 
-+static grub_err_t
-+parse_pe_header (void *kernel, grub_uint64_t *total_size,
-+		 grub_uint32_t *entry_offset,
-+		 grub_uint32_t *alignment)
-+{
-+  struct linux_arch_kernel_header *lh = kernel;
-+  struct grub_armxx_linux_pe_header *pe;
-+
-+  pe = (void *)((unsigned long)kernel + lh->hdr_offset);
-+
-+  if (pe->opt.magic != GRUB_PE32_PE64_MAGIC)
-+    return grub_error(GRUB_ERR_BAD_OS, "Invalid PE optional header magic");
-+
-+  *total_size   = pe->opt.image_size;
-+  *entry_offset = pe->opt.entry_addr;
-+  *alignment    = pe->opt.section_alignment;
-+
-+  return GRUB_ERR_NONE;
-+}
-+
- static grub_err_t
- grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
- 		int argc, char *argv[])
- {
-   grub_file_t file = 0;
--  struct linux_arch_kernel_header lh;
--  struct grub_armxx_linux_pe_header *pe;
-   grub_err_t err;
-+  grub_off_t filelen;
-+  grub_uint32_t align;
-+  void *kernel = NULL;
-   int rc;
- 
-   grub_dl_ref (my_mod);
-@@ -333,40 +355,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   if (!file)
-     goto fail;
- 
--  kernel_size = grub_file_size (file);
--
--  if (grub_file_read (file, &lh, sizeof (lh)) < (long) sizeof (lh))
--    return grub_errno;
--
--  if (grub_arch_efi_linux_check_image (&lh) != GRUB_ERR_NONE)
--    goto fail;
--
--  grub_loader_unset();
--
--  grub_dprintf ("linux", "kernel file size: %lld\n", (long long) kernel_size);
--  kernel_addr = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (kernel_size));
--  grub_dprintf ("linux", "kernel numpages: %lld\n",
--		(long long) GRUB_EFI_BYTES_TO_PAGES (kernel_size));
--  if (!kernel_addr)
-+  filelen = grub_file_size (file);
-+  kernel = grub_malloc(filelen);
-+  if (!kernel)
-     {
--      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
-+      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel load buffer"));
-       goto fail;
-     }
- 
--  grub_file_seek (file, 0);
--  if (grub_file_read (file, kernel_addr, kernel_size)
--      < (grub_int64_t) kernel_size)
-+  if (grub_file_read (file, kernel, filelen) < (grub_ssize_t)filelen)
-     {
--      if (!grub_errno)
--	grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]);
-+      grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"),
-+		  argv[0]);
-       goto fail;
-     }
- 
--  grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
--
-   if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED)
-     {
--      rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size);
-+      rc = grub_linuxefi_secure_validate (kernel, filelen);
-       if (rc <= 0)
- 	{
- 	  grub_error (GRUB_ERR_INVALID_COMMAND,
-@@ -375,8 +381,32 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
- 	}
-     }
- 
--  pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset);
--  handover_offset = pe->opt.entry_addr;
-+  if (grub_arch_efi_linux_check_image (kernel) != GRUB_ERR_NONE)
-+    goto fail;
-+  if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align) != GRUB_ERR_NONE)
-+    goto fail;
-+  grub_dprintf ("linux", "kernel mem size     : %lld\n", (long long) kernel_size);
-+  grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset);
-+  grub_dprintf ("linux", "kernel alignment    : 0x%x\n", align);
-+
-+  grub_loader_unset();
-+
-+  kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1);
-+  kernel_alloc_addr = grub_efi_allocate_any_pages (kernel_alloc_pages);
-+  grub_dprintf ("linux", "kernel numpages: %d\n", kernel_alloc_pages);
-+  if (!kernel_alloc_addr)
-+    {
-+      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
-+      goto fail;
-+    }
-+  kernel_addr = (void *)ALIGN_UP((grub_uint64_t)kernel_alloc_addr, align);
-+
-+  grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
-+  grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size));
-+  if (kernel_size > filelen)
-+    grub_memset ((char *)kernel_addr + filelen, 0, kernel_size - filelen);
-+  grub_free(kernel);
-+  kernel = NULL;
- 
-   cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE);
-   linux_args = grub_malloc (cmdline_size);
-@@ -400,6 +430,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-     }
- 
- fail:
-+  if (kernel)
-+    grub_free (kernel);
-+
-   if (file)
-     grub_file_close (file);
- 
-@@ -412,9 +445,8 @@ fail:
-   if (linux_args && !loaded)
-     grub_free (linux_args);
- 
--  if (kernel_addr && !loaded)
--    grub_efi_free_pages ((grub_addr_t) kernel_addr,
--			 GRUB_EFI_BYTES_TO_PAGES (kernel_size));
-+  if (kernel_alloc_addr && !loaded)
-+    grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages);
- 
-   return grub_errno;
- }
diff --git a/SOURCES/0216-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch b/SOURCES/0216-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch
new file mode 100644
index 0000000..b79c78c
--- /dev/null
+++ b/SOURCES/0216-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Chris Coulson <chris.coulson@canonical.com>
+Date: Mon, 2 May 2022 14:39:31 +0200
+Subject: [PATCH] loader/i386/efi/linux: Avoid a use-after-free in the linuxefi
+ loader
+
+In some error paths in grub_cmd_linux, the pointer to lh may be
+dereferenced after the buffer it points to has been freed. There aren't
+any security implications from this because nothing else uses the
+allocator after the buffer is freed and before the pointer is
+dereferenced, but fix it anyway.
+
+Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
+(cherry picked from commit 8224f5a71af94bec8697de17e7e579792db9f9e2)
+---
+ grub-core/loader/i386/efi/linux.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 941df6400b..27bc2aa161 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -465,9 +465,6 @@ fail:
+   if (file)
+     grub_file_close (file);
+ 
+-  if (kernel)
+-    grub_free (kernel);
+-
+   if (grub_errno != GRUB_ERR_NONE)
+     {
+       grub_dl_unref (my_mod);
+@@ -483,6 +480,8 @@ fail:
+       kernel_free (params, sizeof(*params));
+     }
+ 
++  grub_free (kernel);
++
+   return grub_errno;
+ }
+ 
diff --git a/SOURCES/0217-loader-i386-efi-linux-Use-grub_loader_set_ex.patch b/SOURCES/0217-loader-i386-efi-linux-Use-grub_loader_set_ex.patch
new file mode 100644
index 0000000..1a129db
--- /dev/null
+++ b/SOURCES/0217-loader-i386-efi-linux-Use-grub_loader_set_ex.patch
@@ -0,0 +1,296 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Chris Coulson <chris.coulson@canonical.com>
+Date: Mon, 2 May 2022 17:04:23 +0200
+Subject: [PATCH] loader/i386/efi/linux: Use grub_loader_set_ex
+
+This ports the linuxefi loader to use grub_loader_set_ex in order to fix
+a use-after-fre bug that occurs when grub_cmd_linux is executed more than
+once before a boot attempt is performed.
+
+This is more complicated than for the chainloader command, as the initrd
+command needs access to the loader state. To solve this, the linuxefi
+module registers a dummy initrd command at startup that returns an error.
+The linuxefi command then registers a proper initrd command with a higher
+priority that is passed the loader state.
+
+Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
+(cherry picked from commit 7cf736436b4c934df5ddfa6f44b46a7e07d99fdc)
+[rharwood/pjones: set kernel_size in context]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/loader/i386/efi/linux.c | 146 +++++++++++++++++++++++---------------
+ 1 file changed, 87 insertions(+), 59 deletions(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 27bc2aa161..e3c2d6fe0b 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -34,13 +34,19 @@
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+ static grub_dl_t my_mod;
+-static int loaded;
+-static void *kernel_mem;
+-static grub_uint64_t kernel_size;
+-static void *initrd_mem;
+-static grub_uint32_t handover_offset;
+-struct linux_kernel_params *params;
+-static char *linux_cmdline;
++
++static grub_command_t cmd_linux, cmd_initrd;
++static grub_command_t cmd_linuxefi, cmd_initrdefi;
++
++struct grub_linuxefi_context {
++  void *kernel_mem;
++  grub_uint64_t kernel_size;
++  grub_uint32_t handover_offset;
++  struct linux_kernel_params *params;
++  char *cmdline;
++
++  void *initrd_mem;
++};
+ 
+ #define MIN(a, b) \
+   ({ typeof (a) _a = (a); \
+@@ -123,25 +129,32 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
+ }
+ 
+ static grub_err_t
+-grub_linuxefi_boot (void)
++grub_linuxefi_boot (void *data)
+ {
++  struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data;
++
+   asm volatile ("cli");
+ 
+-  return grub_efi_linux_boot ((char *)kernel_mem,
+-			      handover_offset,
+-			      params);
++  return grub_efi_linux_boot ((char *)context->kernel_mem,
++			      context->handover_offset,
++			      context->params);
+ }
+ 
+ static grub_err_t
+-grub_linuxefi_unload (void)
++grub_linuxefi_unload (void *data)
+ {
++  struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data;
++  struct linux_kernel_params *params = context->params;
++
+   grub_dl_unref (my_mod);
+-  loaded = 0;
+ 
+-  kernel_free(initrd_mem, params->ramdisk_size);
+-  kernel_free(linux_cmdline, params->cmdline_size + 1);
+-  kernel_free(kernel_mem, kernel_size);
+-  kernel_free(params, sizeof(*params));
++  kernel_free (context->initrd_mem, params->ramdisk_size);
++  kernel_free (context->cmdline, params->cmdline_size + 1);
++  kernel_free (context->kernel_mem, context->kernel_size);
++  kernel_free (params, sizeof(*params));
++  cmd_initrd->data = 0;
++  cmd_initrdefi->data = 0;
++  grub_free (context);
+ 
+   return GRUB_ERR_NONE;
+ }
+@@ -188,13 +201,14 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len)
+ #define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull))
+ 
+ static grub_err_t
+-grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+-                 int argc, char *argv[])
++grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
+ {
+   grub_file_t *files = 0;
+   int i, nfiles = 0;
+   grub_size_t size = 0;
+   grub_uint8_t *ptr;
++  struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data;
++  struct linux_kernel_params *params;
+ 
+   if (argc == 0)
+     {
+@@ -202,12 +216,14 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  if (!loaded)
++  if (!context)
+     {
+       grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
+       goto fail;
+     }
+ 
++  params = context->params;
++
+   files = grub_calloc (argc, sizeof (files[0]));
+   if (!files)
+     goto fail;
+@@ -225,19 +241,19 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+ 	}
+     }
+ 
+-  initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
+-  if (initrd_mem == NULL)
++  context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
++  if (context->initrd_mem == NULL)
+     goto fail;
+-  grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
++  grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem);
+ 
+   params->ramdisk_size = LOW_U32(size);
+-  params->ramdisk_image = LOW_U32(initrd_mem);
++  params->ramdisk_image = LOW_U32(context->initrd_mem);
+ #if defined(__x86_64__)
+   params->ext_ramdisk_size = HIGH_U32(size);
+-  params->ext_ramdisk_image = HIGH_U32(initrd_mem);
++  params->ext_ramdisk_image = HIGH_U32(context->initrd_mem);
+ #endif
+ 
+-  ptr = initrd_mem;
++  ptr = context->initrd_mem;
+ 
+   for (i = 0; i < nfiles; i++)
+     {
+@@ -261,8 +277,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+     grub_file_close (files[i]);
+   grub_free (files);
+ 
+-  if (initrd_mem && grub_errno)
+-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem,
++  if (context->initrd_mem && grub_errno)
++    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem,
+ 			 BYTES_TO_PAGES(size));
+ 
+   return grub_errno;
+@@ -277,6 +293,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_ssize_t start, filelen;
+   void *kernel = NULL;
+   int setup_header_end_offset;
++  void *kernel_mem = 0;
++  grub_uint64_t kernel_size = 0;
++  grub_uint32_t handover_offset;
++  struct linux_kernel_params *params = 0;
++  char *cmdline = 0;
++  struct grub_linuxefi_context *context = 0;
+ 
+   grub_dl_ref (my_mod);
+ 
+@@ -390,27 +412,27 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_dprintf ("linux", "new lh is at %p\n", lh);
+ 
+   grub_dprintf ("linux", "setting up cmdline\n");
+-  linux_cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline"));
+-  if (!linux_cmdline)
++  cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline"));
++  if (!cmdline)
+     goto fail;
+-  grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline);
++  grub_dprintf ("linux", "cmdline = %p\n", cmdline);
+ 
+-  grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
++  grub_memcpy (cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+   grub_create_loader_cmdline (argc, argv,
+-                              linux_cmdline + sizeof (LINUX_IMAGE) - 1,
++                              cmdline + sizeof (LINUX_IMAGE) - 1,
+ 			      lh->cmdline_size - (sizeof (LINUX_IMAGE) - 1),
+ 			      GRUB_VERIFY_KERNEL_CMDLINE);
+ 
+-  grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline);
++  grub_dprintf ("linux", "cmdline:%s\n", cmdline);
+   grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n",
+-		LOW_U32(linux_cmdline));
+-  lh->cmd_line_ptr = LOW_U32(linux_cmdline);
++		LOW_U32(cmdline));
++  lh->cmd_line_ptr = LOW_U32(cmdline);
+ #if defined(__x86_64__)
+-  if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull)
++  if ((grub_efi_uintn_t)cmdline > 0xffffffffull)
+     {
+       grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n",
+-		    HIGH_U32(linux_cmdline));
+-      params->ext_cmd_line_ptr = HIGH_U32(linux_cmdline);
++		    HIGH_U32(cmdline));
++      params->ext_cmd_line_ptr = HIGH_U32(cmdline);
+     }
+ #endif
+ 
+@@ -435,16 +457,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+     }
+   max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
+   max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
+-  kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel"));
++  kernel_size = lh->init_size;
++  kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel"));
+   restore_addresses();
+   if (!kernel_mem)
+     goto fail;
+   grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem);
+ 
+-  grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
+-
+-  loaded = 1;
+-
+   grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n",
+ 		LOW_U32(kernel_mem));
+   lh->code32_start = LOW_U32(kernel_mem);
+@@ -461,33 +480,42 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 		"setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n",
+ 		params->ext_loader_type, params->ext_loader_ver);
+ 
++  context = grub_zalloc (sizeof (*context));
++  if (!context)
++    goto fail;
++  context->kernel_mem = kernel_mem;
++  context->kernel_size = kernel_size;
++  context->handover_offset = handover_offset;
++  context->params = params;
++  context->cmdline = cmdline;
++
++  grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0);
++
++  cmd_initrd->data = context;
++  cmd_initrdefi->data = context;
++
++  grub_file_close (file);
++  grub_free (kernel);
++  return 0;
++
+ fail:
+   if (file)
+     grub_file_close (file);
+ 
+-  if (grub_errno != GRUB_ERR_NONE)
+-    {
+-      grub_dl_unref (my_mod);
+-      loaded = 0;
+-    }
++  grub_dl_unref (my_mod);
+ 
+-  if (!loaded)
+-    {
+-      if (lh)
+-	kernel_free (linux_cmdline, lh->cmdline_size + 1);
++  if (lh)
++    kernel_free (cmdline, lh->cmdline_size + 1);
+ 
+-      kernel_free (kernel_mem, kernel_size);
+-      kernel_free (params, sizeof(*params));
+-    }
++  kernel_free (kernel_mem, kernel_size);
++  kernel_free (params, sizeof(*params));
+ 
++  grub_free (context);
+   grub_free (kernel);
+ 
+   return grub_errno;
+ }
+ 
+-static grub_command_t cmd_linux, cmd_initrd;
+-static grub_command_t cmd_linuxefi, cmd_initrdefi;
+-
+ GRUB_MOD_INIT(linux)
+ {
+   cmd_linux =
diff --git a/SOURCES/0217-normal-main-Discover-the-device-to-read-the-config-f.patch b/SOURCES/0217-normal-main-Discover-the-device-to-read-the-config-f.patch
deleted file mode 100644
index cf12fd6..0000000
--- a/SOURCES/0217-normal-main-Discover-the-device-to-read-the-config-f.patch
+++ /dev/null
@@ -1,123 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Javier Martinez Canillas <javierm@redhat.com>
-Date: Mon, 30 Aug 2021 12:31:18 +0200
-Subject: [PATCH] normal/main: Discover the device to read the config from as a
- fallback
-
-The GRUB core.img is generated locally, when this is done the grub2-probe
-tool figures out the device and partition that needs to be read to parse
-the GRUB configuration file.
-
-But in some cases the core.img can't be generated on the host and instead
-has to be done at package build time. For example, if needs to get signed
-with a key that's only available on the package building infrastructure.
-
-If that's the case, the prefix variable won't have a device and partition
-but only a directory path. So there's no way for GRUB to know from which
-device has to read the configuration file.
-
-To allow GRUB to continue working on that scenario, fallback to iterating
-over all the available devices, if reading the config failed when using
-the prefix and fw_path variables.
-
-Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
----
- grub-core/normal/main.c | 58 +++++++++++++++++++++++++++++++++++++++++++------
- 1 file changed, 51 insertions(+), 7 deletions(-)
-
-diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
-index 155bf366da2..f9ccca502ee 100644
---- a/grub-core/normal/main.c
-+++ b/grub-core/normal/main.c
-@@ -339,18 +339,13 @@ grub_enter_normal_mode (const char *config)
- }
- 
- static grub_err_t
--grub_try_normal (const char *variable)
-+grub_try_normal_prefix (const char *prefix)
- {
-     char *config;
--    const char *prefix;
-     grub_err_t err = GRUB_ERR_FILE_NOT_FOUND;
-     const char *net_search_cfg;
-     int disable_net_search = 0;
- 
--    prefix = grub_env_get (variable);
--    if (!prefix)
--      return GRUB_ERR_FILE_NOT_FOUND;
--
-     net_search_cfg = grub_env_get ("feature_net_search_cfg");
-     if (net_search_cfg && net_search_cfg[0] == 'n')
-       disable_net_search = 1;
-@@ -364,7 +359,7 @@ grub_try_normal (const char *variable)
-        config = grub_malloc (config_len);
- 
-        if (! config)
--         return GRUB_ERR_FILE_NOT_FOUND;
-+         return err;
- 
-        grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
-        err = grub_net_search_config_file (config);
-@@ -393,6 +388,53 @@ grub_try_normal (const char *variable)
-     return err;
- }
- 
-+static int
-+grub_try_normal_dev (const char *name, void *data)
-+{
-+  grub_err_t err;
-+  const char *prefix = grub_xasprintf ("(%s)%s", name, (char *)data);
-+
-+  if (!prefix)
-+    return 0;
-+
-+  err = grub_try_normal_prefix (prefix);
-+  if (err == GRUB_ERR_NONE)
-+    return 1;
-+
-+  return 0;
-+}
-+
-+static grub_err_t
-+grub_try_normal_discover (void)
-+{
-+  char *prefix = grub_env_get ("prefix");
-+  grub_err_t err = GRUB_ERR_FILE_NOT_FOUND;
-+
-+  if (!prefix)
-+    return err;
-+
-+  if (grub_device_iterate (grub_try_normal_dev, (void *)prefix))
-+    return GRUB_ERR_NONE;
-+
-+  return err;
-+}
-+
-+static grub_err_t
-+grub_try_normal (const char *variable)
-+{
-+  grub_err_t err = GRUB_ERR_FILE_NOT_FOUND;
-+  const char *prefix;
-+
-+  if (!variable)
-+    return err;
-+
-+  prefix = grub_env_get (variable);
-+  if (!prefix)
-+    return err;
-+
-+  return grub_try_normal_prefix (prefix);
-+}
-+
- /* Enter normal mode from rescue mode.  */
- static grub_err_t
- grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
-@@ -407,6 +449,8 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
-       err = grub_try_normal ("fw_path");
-       if (err == GRUB_ERR_FILE_NOT_FOUND)
-         err = grub_try_normal ("prefix");
-+      if (err == GRUB_ERR_FILE_NOT_FOUND)
-+        err = grub_try_normal_discover ();
-       if (err == GRUB_ERR_FILE_NOT_FOUND)
-         grub_enter_normal_mode (0);
-     }
diff --git a/SOURCES/0218-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch b/SOURCES/0218-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch
new file mode 100644
index 0000000..51953fd
--- /dev/null
+++ b/SOURCES/0218-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch
@@ -0,0 +1,75 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Chris Coulson <chris.coulson@canonical.com>
+Date: Tue, 3 May 2022 09:47:35 +0200
+Subject: [PATCH] loader/i386/efi/linux: Fix a memory leak in the initrd
+ command
+
+Subsequent invocations of the initrd command result in the previous
+initrd being leaked, so fix that.
+
+Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
+(cherry picked from commit d98af31ce1e31bb22163960d53f5eb28c66582a0)
+---
+ grub-core/loader/i386/efi/linux.c | 21 ++++++++++++---------
+ 1 file changed, 12 insertions(+), 9 deletions(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index e3c2d6fe0b..9e5c11ac69 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -209,6 +209,7 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
+   grub_uint8_t *ptr;
+   struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data;
+   struct linux_kernel_params *params;
++  void *initrd_mem = 0;
+ 
+   if (argc == 0)
+     {
+@@ -241,19 +242,19 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
+ 	}
+     }
+ 
+-  context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
+-  if (context->initrd_mem == NULL)
++  initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
++  if (initrd_mem == NULL)
+     goto fail;
+-  grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem);
++  grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
+ 
+   params->ramdisk_size = LOW_U32(size);
+-  params->ramdisk_image = LOW_U32(context->initrd_mem);
++  params->ramdisk_image = LOW_U32(initrd_mem);
+ #if defined(__x86_64__)
+   params->ext_ramdisk_size = HIGH_U32(size);
+-  params->ext_ramdisk_image = HIGH_U32(context->initrd_mem);
++  params->ext_ramdisk_image = HIGH_U32(initrd_mem);
+ #endif
+ 
+-  ptr = context->initrd_mem;
++  ptr = initrd_mem;
+ 
+   for (i = 0; i < nfiles; i++)
+     {
+@@ -270,6 +271,9 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
+       ptr += ALIGN_UP_OVERHEAD (cursize, 4);
+     }
+ 
++  kernel_free(context->initrd_mem, params->ramdisk_size);
++
++  context->initrd_mem = initrd_mem;
+   params->ramdisk_size = size;
+ 
+  fail:
+@@ -277,9 +281,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
+     grub_file_close (files[i]);
+   grub_free (files);
+ 
+-  if (context->initrd_mem && grub_errno)
+-    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem,
+-			 BYTES_TO_PAGES(size));
++  if (initrd_mem && grub_errno)
++    kernel_free (initrd_mem, size);
+ 
+   return grub_errno;
+ }
diff --git a/SOURCES/0218-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch b/SOURCES/0218-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch
deleted file mode 100644
index 70b021d..0000000
--- a/SOURCES/0218-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch
+++ /dev/null
@@ -1,75 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Mon, 19 Jul 2021 14:35:55 +1000
-Subject: [PATCH] powerpc: adjust setting of prefix for signed binary case
-
-On RHEL-signed powerpc grub, we sign a grub with -p /grub2 and expect
-that there's a boot partition.
-
-Unfortunately grub_set_prefix_and_root tries to convert this to
-($fwdevice)/grub2. This ends up being (ieee1275/disk)/grub2 and that
-falls apart pretty quickly - there's no file-system on ieee1275/disk,
-and it makes the search routine try things like
-(ieee1275/disk,msdos2)(ieee1275/disk)/grub2 which also doesn't work.
-
-Detect if we would be about to create (ieee1275/disk)/path and don't:
-preserve a prefix of /path instead and hope the search later finds us.
-
-Related: rhbz#1899864
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/kern/main.c | 38 +++++++++++++++++++++++++++++++++-----
- 1 file changed, 33 insertions(+), 5 deletions(-)
-
-diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
-index 0285e95a2bb..e809a5edec1 100644
---- a/grub-core/kern/main.c
-+++ b/grub-core/kern/main.c
-@@ -216,13 +216,41 @@ grub_set_prefix_and_root (void)
-   if (device)
-     {
-       char *prefix_set;
--    
--      prefix_set = grub_xasprintf ("(%s)%s", device, path ? : "");
--      if (prefix_set)
-+
-+#ifdef __powerpc__
-+      /* We have to be careful here on powerpc-ieee1275 + signed grub. We
-+	 will have signed something with a prefix that doesn't have a device
-+	 because we cannot know in advance what partition we're on.
-+
-+	 We will have had !device earlier, so we will have set device=fwdevice
-+	 However, we want to make sure we do not end up setting prefix to be
-+	 ($fwdevice)/path, because we will then end up trying to boot or search
-+	 based on a prefix of (ieee1275/disk)/path, which will not work because
-+	 it's missing a partition.
-+
-+	 Also:
-+	  - You can end up with a device with an FS directly on it, without
-+	    a partition, e.g. ieee1275/cdrom.
-+
-+	  - powerpc-ieee1275 + grub-install sets e.g. prefix=(,gpt2)/path,
-+	    which will have now been extended to device=$fwdisk,partition
-+	    and path=/path
-+
-+	 So we only need to act if device = ieee1275/disk exactly.
-+       */
-+      if (grub_strncmp (device, "ieee1275/disk", 14) == 0)
-+        grub_env_set ("prefix", path);
-+      else
-+#endif
- 	{
--	  grub_env_set ("prefix", prefix_set);
--	  grub_free (prefix_set);
-+	  prefix_set = grub_xasprintf ("(%s)%s", device, path ? : "");
-+	  if (prefix_set)
-+	  {
-+	    grub_env_set ("prefix", prefix_set);
-+	    grub_free (prefix_set);
-+	  }
- 	}
-+
-       grub_env_set ("root", device);
-     }
- 
diff --git a/SOURCES/0219-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch b/SOURCES/0219-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch
new file mode 100644
index 0000000..715e6e1
--- /dev/null
+++ b/SOURCES/0219-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch
@@ -0,0 +1,101 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Julian Andres Klode <julian.klode@canonical.com>
+Date: Thu, 2 Dec 2021 15:03:53 +0100
+Subject: [PATCH] kern/efi/sb: Reject non-kernel files in the shim_lock
+ verifier
+
+We must not allow other verifiers to pass things like the GRUB modules.
+Instead of maintaining a blocklist, maintain an allowlist of things
+that we do not care about.
+
+This allowlist really should be made reusable, and shared by the
+lockdown verifier, but this is the minimal patch addressing
+security concerns where the TPM verifier was able to mark modules
+as verified (or the OpenPGP verifier for that matter), when it
+should not do so on shim-powered secure boot systems.
+
+Fixes: CVE-2022-28735
+
+Signed-off-by: Julian Andres Klode <julian.klode@canonical.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit fa61ad69861c1cb3f68bf853d78fae7fd93986a0)
+---
+ grub-core/kern/efi/sb.c | 39 ++++++++++++++++++++++++++++++++++++---
+ include/grub/verify.h   |  1 +
+ 2 files changed, 37 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c
+index c52ec6226a..89c4bb3fd1 100644
+--- a/grub-core/kern/efi/sb.c
++++ b/grub-core/kern/efi/sb.c
+@@ -119,10 +119,11 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)),
+ 			 void **context __attribute__ ((unused)),
+ 			 enum grub_verify_flags *flags)
+ {
+-  *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
++  *flags = GRUB_VERIFY_FLAGS_NONE;
+ 
+   switch (type & GRUB_FILE_TYPE_MASK)
+     {
++    /* Files we check. */
+     case GRUB_FILE_TYPE_LINUX_KERNEL:
+     case GRUB_FILE_TYPE_MULTIBOOT_KERNEL:
+     case GRUB_FILE_TYPE_BSD_KERNEL:
+@@ -130,11 +131,43 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)),
+     case GRUB_FILE_TYPE_PLAN9_KERNEL:
+     case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE:
+       *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
++      return GRUB_ERR_NONE;
+ 
+-      /* Fall through. */
++    /* Files that do not affect secureboot state. */
++    case GRUB_FILE_TYPE_NONE:
++    case GRUB_FILE_TYPE_LOOPBACK:
++    case GRUB_FILE_TYPE_LINUX_INITRD:
++    case GRUB_FILE_TYPE_OPENBSD_RAMDISK:
++    case GRUB_FILE_TYPE_XNU_RAMDISK:
++    case GRUB_FILE_TYPE_SIGNATURE:
++    case GRUB_FILE_TYPE_PUBLIC_KEY:
++    case GRUB_FILE_TYPE_PUBLIC_KEY_TRUST:
++    case GRUB_FILE_TYPE_PRINT_BLOCKLIST:
++    case GRUB_FILE_TYPE_TESTLOAD:
++    case GRUB_FILE_TYPE_GET_SIZE:
++    case GRUB_FILE_TYPE_FONT:
++    case GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY:
++    case GRUB_FILE_TYPE_CAT:
++    case GRUB_FILE_TYPE_HEXCAT:
++    case GRUB_FILE_TYPE_CMP:
++    case GRUB_FILE_TYPE_HASHLIST:
++    case GRUB_FILE_TYPE_TO_HASH:
++    case GRUB_FILE_TYPE_KEYBOARD_LAYOUT:
++    case GRUB_FILE_TYPE_PIXMAP:
++    case GRUB_FILE_TYPE_GRUB_MODULE_LIST:
++    case GRUB_FILE_TYPE_CONFIG:
++    case GRUB_FILE_TYPE_THEME:
++    case GRUB_FILE_TYPE_GETTEXT_CATALOG:
++    case GRUB_FILE_TYPE_FS_SEARCH:
++    case GRUB_FILE_TYPE_LOADENV:
++    case GRUB_FILE_TYPE_SAVEENV:
++    case GRUB_FILE_TYPE_VERIFY_SIGNATURE:
++      *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
++      return GRUB_ERR_NONE;
+ 
++    /* Other files. */
+     default:
+-      return GRUB_ERR_NONE;
++      return grub_error (GRUB_ERR_ACCESS_DENIED, N_("prohibited by secure boot policy"));
+     }
+ }
+ 
+diff --git a/include/grub/verify.h b/include/grub/verify.h
+index cd129c398f..672ae16924 100644
+--- a/include/grub/verify.h
++++ b/include/grub/verify.h
+@@ -24,6 +24,7 @@
+ 
+ enum grub_verify_flags
+   {
++    GRUB_VERIFY_FLAGS_NONE		= 0,
+     GRUB_VERIFY_FLAGS_SKIP_VERIFICATION	= 1,
+     GRUB_VERIFY_FLAGS_SINGLE_CHUNK	= 2,
+     /* Defer verification to another authority. */
diff --git a/SOURCES/0219-powerpc-fix-prefix-signed-grub-special-case-for-Powe.patch b/SOURCES/0219-powerpc-fix-prefix-signed-grub-special-case-for-Powe.patch
deleted file mode 100644
index 1cb21ef..0000000
--- a/SOURCES/0219-powerpc-fix-prefix-signed-grub-special-case-for-Powe.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Mon, 16 Aug 2021 16:01:47 +1000
-Subject: [PATCH] powerpc: fix prefix + signed grub special case for PowerVM
-
-Mea culpa: when testing the PowerPC special case for signed grub, I
-assumed qemu and PowerVM would behave identically. This was wrong, and
-with hindsight a pretty dumb error.
-
-This fixes it. This time, I am actually testing on PowerVM.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
----
- grub-core/kern/main.c | 15 +++++++++++++--
- 1 file changed, 13 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
-index e809a5edec1..2d0d2bbd4cf 100644
---- a/grub-core/kern/main.c
-+++ b/grub-core/kern/main.c
-@@ -236,9 +236,20 @@ grub_set_prefix_and_root (void)
- 	    which will have now been extended to device=$fwdisk,partition
- 	    and path=/path
- 
--	 So we only need to act if device = ieee1275/disk exactly.
-+	  - PowerVM will give us device names like
-+	    ieee1275//vdevice/v-scsi@3000006c/disk@8100000000000000
-+	    and we don't want to try to encode some sort of truth table about
-+	    what sorts of paths represent disks with partition tables and those
-+	    without partition tables.
-+
-+	 So we act unless there is a comma in the device, which would indicate
-+	 a partition has already been specified.
-+
-+	 (If we only have a path, the code in normal to discover config files
-+	 will try both without partitions and then with any partitions so we
-+	 will cover both CDs and HDs.)
-        */
--      if (grub_strncmp (device, "ieee1275/disk", 14) == 0)
-+      if (grub_strchr (device, ',') == NULL)
-         grub_env_set ("prefix", path);
-       else
- #endif
diff --git a/SOURCES/0220-Arm-check-for-the-PE-magic-for-the-compiled-arch.patch b/SOURCES/0220-Arm-check-for-the-PE-magic-for-the-compiled-arch.patch
deleted file mode 100644
index 8b5170b..0000000
--- a/SOURCES/0220-Arm-check-for-the-PE-magic-for-the-compiled-arch.patch
+++ /dev/null
@@ -1,63 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 9 Sep 2021 10:59:28 -0400
-Subject: [PATCH] Arm: check for the PE magic for the compiled arch
-
-In "arm64: Fix EFI loader kernel image allocation", Ben fixed the kernel
-alignment to match the alignment given in the PE header.  In doing so, a
-check for valid PE magic was added, which was hard-coded to the value
-seen on Aarch64 (GRUB_PE32_PE64_MAGIC).
-
-Unfortunately, this code is shared between 64-bit and 32-bit, and so
-that value broke 32-bit Arm systems.
-
-This patch adds a constant definition for GRUB_PE32_PEXX_MAGIC, which is
-either GRUB_PE32_PE64_MAGIC or GRUB_PE32_PE32_MAGIC, depending on which
-platform is being built, and uses it in the header magic check.
-
-Resolves: rhbz#2000756
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
----
- grub-core/loader/arm64/linux.c | 2 +-
- include/grub/arm/linux.h       | 1 +
- include/grub/arm64/linux.h     | 1 +
- 3 files changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
-index 4a252d5e7e9..f18d90bd749 100644
---- a/grub-core/loader/arm64/linux.c
-+++ b/grub-core/loader/arm64/linux.c
-@@ -322,7 +322,7 @@ parse_pe_header (void *kernel, grub_uint64_t *total_size,
- 
-   pe = (void *)((unsigned long)kernel + lh->hdr_offset);
- 
--  if (pe->opt.magic != GRUB_PE32_PE64_MAGIC)
-+  if (pe->opt.magic != GRUB_PE32_PEXX_MAGIC)
-     return grub_error(GRUB_ERR_BAD_OS, "Invalid PE optional header magic");
- 
-   *total_size   = pe->opt.image_size;
-diff --git a/include/grub/arm/linux.h b/include/grub/arm/linux.h
-index b582f67f661..966a5074f53 100644
---- a/include/grub/arm/linux.h
-+++ b/include/grub/arm/linux.h
-@@ -44,6 +44,7 @@ struct grub_arm_linux_pe_header
- 
- #if defined(__arm__)
- # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM_MAGIC_SIGNATURE
-+# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE32_MAGIC
- # define linux_arch_kernel_header linux_arm_kernel_header
- # define grub_armxx_linux_pe_header grub_arm_linux_pe_header
- #endif
-diff --git a/include/grub/arm64/linux.h b/include/grub/arm64/linux.h
-index ea030312df3..422bf2bf24b 100644
---- a/include/grub/arm64/linux.h
-+++ b/include/grub/arm64/linux.h
-@@ -48,6 +48,7 @@ struct grub_arm64_linux_pe_header
- 
- #if defined(__aarch64__)
- # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM64_MAGIC_SIGNATURE
-+# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE64_MAGIC
- # define linux_arch_kernel_header linux_arm64_kernel_header
- # define grub_armxx_linux_pe_header grub_arm64_linux_pe_header
- #endif
diff --git a/SOURCES/0220-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch b/SOURCES/0220-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch
new file mode 100644
index 0000000..59f9471
--- /dev/null
+++ b/SOURCES/0220-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch
@@ -0,0 +1,39 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Fri, 25 Jun 2021 02:19:05 +1000
+Subject: [PATCH] kern/file: Do not leak device_name on error in
+ grub_file_open()
+
+If we have an error in grub_file_open() before we free device_name, we
+will leak it.
+
+Free device_name in the error path and null out the pointer in the good
+path once we free it there.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 1499a5068839fa37cb77ecef4b5bdacbd1ed12ea)
+---
+ grub-core/kern/file.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
+index ec10e54fc0..db938e099d 100644
+--- a/grub-core/kern/file.c
++++ b/grub-core/kern/file.c
+@@ -84,6 +84,7 @@ grub_file_open (const char *name, enum grub_file_type type)
+ 
+   device = grub_device_open (device_name);
+   grub_free (device_name);
++  device_name = NULL;
+   if (! device)
+     goto fail;
+ 
+@@ -138,6 +139,7 @@ grub_file_open (const char *name, enum grub_file_type type)
+   return file;
+ 
+  fail:
++  grub_free (device_name);
+   if (device)
+     grub_device_close (device);
+ 
diff --git a/SOURCES/0221-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch b/SOURCES/0221-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch
deleted file mode 100644
index 893d8b4..0000000
--- a/SOURCES/0221-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch
+++ /dev/null
@@ -1,118 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Erwan Velu <erwanaliasr1@gmail.com>
-Date: Wed, 25 Aug 2021 15:31:52 +0200
-Subject: [PATCH] fs/xfs: Fix unreadable filesystem with v4 superblock
-
-The commit 8b1e5d193 (fs/xfs: Add bigtime incompat feature support)
-introduced the bigtime support by adding some features in v3 inodes.
-This change extended grub_xfs_inode struct by 76 bytes but also changed
-the computation of XFS_V2_INODE_SIZE and XFS_V3_INODE_SIZE. Prior this
-commit, XFS_V2_INODE_SIZE was 100 bytes. After the commit it's 84 bytes
-XFS_V2_INODE_SIZE becomes 16 bytes too small.
-
-As a result, the data structures aren't properly aligned and the GRUB
-generates "attempt to read or write outside of partition" errors when
-trying to read the XFS filesystem:
-
-                             GNU GRUB  version 2.11
-	....
-	grub> set debug=efi,gpt,xfs
-	grub> insmod part_gpt
-	grub> ls (hd0,gpt1)/
-	partmap/gpt.c:93: Read a valid GPT header
-	partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125
-	fs/xfs.c:931: Reading sb
-	fs/xfs.c:270: Validating superblock
-	fs/xfs.c:295: XFS v4 superblock detected
-	fs/xfs.c:962: Reading root ino 128
-	fs/xfs.c:515: Reading inode (128) - 64, 0
-	fs/xfs.c:515: Reading inode (739521961424144223) - 344365866970255880, 3840
-	error: attempt to read or write outside of partition.
-
-This commit change the XFS_V2_INODE_SIZE computation by subtracting 76
-bytes instead of 92 bytes from the actual size of grub_xfs_inode struct.
-This 76 bytes value comes from added members:
-	20 grub_uint8_t   unused5
-	 1 grub_uint64_t  flags2
-        48 grub_uint8_t   unused6
-
-This patch explicitly splits the v2 and v3 parts of the structure.
-The unused4 is still ending of the v2 structures and the v3 starts
-at unused5. Thanks to this we will avoid future corruptions of v2
-or v3 inodes.
-
-The XFS_V2_INODE_SIZE is returning to its expected size and the
-filesystem is back to a readable state:
-
-                      GNU GRUB  version 2.11
-	....
-	grub> set debug=efi,gpt,xfs
-	grub> insmod part_gpt
-	grub> ls (hd0,gpt1)/
-	partmap/gpt.c:93: Read a valid GPT header
-	partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125
-	fs/xfs.c:931: Reading sb
-	fs/xfs.c:270: Validating superblock
-	fs/xfs.c:295: XFS v4 superblock detected
-	fs/xfs.c:962: Reading root ino 128
-	fs/xfs.c:515: Reading inode (128) - 64, 0
-	fs/xfs.c:515: Reading inode (128) - 64, 0
-	fs/xfs.c:931: Reading sb
-	fs/xfs.c:270: Validating superblock
-	fs/xfs.c:295: XFS v4 superblock detected
-	fs/xfs.c:962: Reading root ino 128
-	fs/xfs.c:515: Reading inode (128) - 64, 0
-	fs/xfs.c:515: Reading inode (128) - 64, 0
-	fs/xfs.c:515: Reading inode (128) - 64, 0
-	fs/xfs.c:515: Reading inode (131) - 64, 768
-	efi/ fs/xfs.c:515: Reading inode (3145856) - 1464904, 0
-	grub2/ fs/xfs.c:515: Reading inode (132) - 64, 1024
-	grub/ fs/xfs.c:515: Reading inode (139) - 64, 2816
-	grub>
-
-Fixes: 8b1e5d193 (fs/xfs: Add bigtime incompat feature support)
-
-Signed-off-by: Erwan Velu <e.velu@criteo.com>
-Tested-by: Carlos Maiolino <cmaiolino@redhat.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit a4b495520e4dc41a896a8b916a64eda9970c50ea)
----
- grub-core/fs/xfs.c | 14 ++++++++++----
- 1 file changed, 10 insertions(+), 4 deletions(-)
-
-diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
-index 0f524c3a8a6..e3816d1ec4a 100644
---- a/grub-core/fs/xfs.c
-+++ b/grub-core/fs/xfs.c
-@@ -192,6 +192,11 @@ struct grub_xfs_time_legacy
-   grub_uint32_t nanosec;
- } GRUB_PACKED;
- 
-+/*
-+ * The struct grub_xfs_inode layout was taken from the
-+ * struct xfs_dinode_core which is described here:
-+ * https://mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf
-+ */
- struct grub_xfs_inode
- {
-   grub_uint8_t magic[2];
-@@ -208,14 +213,15 @@ struct grub_xfs_inode
-   grub_uint32_t nextents;
-   grub_uint16_t unused3;
-   grub_uint8_t fork_offset;
--  grub_uint8_t unused4[37];
-+  grub_uint8_t unused4[17]; /* Last member of inode v2. */
-+  grub_uint8_t unused5[20]; /* First member of inode v3. */
-   grub_uint64_t flags2;
--  grub_uint8_t unused5[48];
-+  grub_uint8_t unused6[48]; /* Last member of inode v3. */
- } GRUB_PACKED;
- 
- #define XFS_V3_INODE_SIZE	sizeof(struct grub_xfs_inode)
--/* Size of struct grub_xfs_inode until fork_offset (included). */
--#define XFS_V2_INODE_SIZE	(XFS_V3_INODE_SIZE - 92)
-+/* Size of struct grub_xfs_inode v2, up to unused4 member included. */
-+#define XFS_V2_INODE_SIZE	(XFS_V3_INODE_SIZE - 76)
- 
- struct grub_xfs_dirblock_tail
- {
diff --git a/SOURCES/0221-video-readers-png-Abort-sooner-if-a-read-operation-f.patch b/SOURCES/0221-video-readers-png-Abort-sooner-if-a-read-operation-f.patch
new file mode 100644
index 0000000..385d3ed
--- /dev/null
+++ b/SOURCES/0221-video-readers-png-Abort-sooner-if-a-read-operation-f.patch
@@ -0,0 +1,198 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 6 Jul 2021 14:02:55 +1000
+Subject: [PATCH] video/readers/png: Abort sooner if a read operation fails
+
+Fuzzing revealed some inputs that were taking a long time, potentially
+forever, because they did not bail quickly upon encountering an I/O error.
+
+Try to catch I/O errors sooner and bail out.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 882be97d1df6449b9fd4d593f0cb70005fde3494)
+---
+ grub-core/video/readers/png.c | 55 ++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 47 insertions(+), 8 deletions(-)
+
+diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
+index 0157ff7420..e2a6b1cf3c 100644
+--- a/grub-core/video/readers/png.c
++++ b/grub-core/video/readers/png.c
+@@ -142,6 +142,7 @@ static grub_uint8_t
+ grub_png_get_byte (struct grub_png_data *data)
+ {
+   grub_uint8_t r;
++  grub_ssize_t bytes_read = 0;
+ 
+   if ((data->inside_idat) && (data->idat_remain == 0))
+     {
+@@ -175,7 +176,14 @@ grub_png_get_byte (struct grub_png_data *data)
+     }
+ 
+   r = 0;
+-  grub_file_read (data->file, &r, 1);
++  bytes_read = grub_file_read (data->file, &r, 1);
++
++  if (bytes_read != 1)
++    {
++      grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		  "png: unexpected end of data");
++      return 0;
++    }
+ 
+   if (data->inside_idat)
+     data->idat_remain--;
+@@ -231,15 +239,16 @@ grub_png_decode_image_palette (struct grub_png_data *data,
+   if (len == 0)
+     return GRUB_ERR_NONE;
+ 
+-  for (i = 0; 3 * i < len && i < 256; i++)
++  grub_errno = GRUB_ERR_NONE;
++  for (i = 0; 3 * i < len && i < 256 && grub_errno == GRUB_ERR_NONE; i++)
+     for (j = 0; j < 3; j++)
+       data->palette[i][j] = grub_png_get_byte (data);
+-  for (i *= 3; i < len; i++)
++  for (i *= 3; i < len && grub_errno == GRUB_ERR_NONE; i++)
+     grub_png_get_byte (data);
+ 
+   grub_png_get_dword (data);
+ 
+-  return GRUB_ERR_NONE;
++  return grub_errno;
+ }
+ 
+ static grub_err_t
+@@ -256,9 +265,13 @@ grub_png_decode_image_header (struct grub_png_data *data)
+     return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size");
+ 
+   color_bits = grub_png_get_byte (data);
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
+   data->is_16bit = (color_bits == 16);
+ 
+   color_type = grub_png_get_byte (data);
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
+ 
+   /* According to PNG spec, no other types are valid.  */
+   if ((color_type & ~(PNG_COLOR_MASK_ALPHA | PNG_COLOR_MASK_COLOR))
+@@ -340,14 +353,20 @@ grub_png_decode_image_header (struct grub_png_data *data)
+   if (grub_png_get_byte (data) != PNG_COMPRESSION_BASE)
+     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ 		       "png: compression method not supported");
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
+ 
+   if (grub_png_get_byte (data) != PNG_FILTER_TYPE_BASE)
+     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ 		       "png: filter method not supported");
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
+ 
+   if (grub_png_get_byte (data) != PNG_INTERLACE_NONE)
+     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ 		       "png: interlace method not supported");
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
+ 
+   /* Skip crc checksum.  */
+   grub_png_get_dword (data);
+@@ -449,7 +468,7 @@ grub_png_get_huff_code (struct grub_png_data *data, struct huff_table *ht)
+   int code, i;
+ 
+   code = 0;
+-  for (i = 0; i < ht->max_length; i++)
++  for (i = 0; i < ht->max_length && grub_errno == GRUB_ERR_NONE; i++)
+     {
+       code = (code << 1) + grub_png_get_bits (data, 1);
+       if (code < ht->maxval[i])
+@@ -504,8 +523,14 @@ grub_png_init_dynamic_block (struct grub_png_data *data)
+   grub_uint8_t lens[DEFLATE_HCLEN_MAX];
+ 
+   nl = DEFLATE_HLIT_BASE + grub_png_get_bits (data, 5);
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
+   nd = DEFLATE_HDIST_BASE + grub_png_get_bits (data, 5);
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
+   nb = DEFLATE_HCLEN_BASE + grub_png_get_bits (data, 4);
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
+ 
+   if ((nl > DEFLATE_HLIT_MAX) || (nd > DEFLATE_HDIST_MAX) ||
+       (nb > DEFLATE_HCLEN_MAX))
+@@ -533,7 +558,7 @@ grub_png_init_dynamic_block (struct grub_png_data *data)
+ 			    data->dist_offset);
+ 
+   prev = 0;
+-  for (i = 0; i < nl + nd; i++)
++  for (i = 0; i < nl + nd && grub_errno == GRUB_ERR_NONE; i++)
+     {
+       int n, code;
+       struct huff_table *ht;
+@@ -721,17 +746,21 @@ grub_png_read_dynamic_block (struct grub_png_data *data)
+ 	  len = cplens[n];
+ 	  if (cplext[n])
+ 	    len += grub_png_get_bits (data, cplext[n]);
++	  if (grub_errno != GRUB_ERR_NONE)
++	    return grub_errno;
+ 
+ 	  n = grub_png_get_huff_code (data, &data->dist_table);
+ 	  dist = cpdist[n];
+ 	  if (cpdext[n])
+ 	    dist += grub_png_get_bits (data, cpdext[n]);
++	  if (grub_errno != GRUB_ERR_NONE)
++	    return grub_errno;
+ 
+ 	  pos = data->wp - dist;
+ 	  if (pos < 0)
+ 	    pos += WSIZE;
+ 
+-	  while (len > 0)
++	  while (len > 0 && grub_errno == GRUB_ERR_NONE)
+ 	    {
+ 	      data->slide[data->wp] = data->slide[pos];
+ 	      grub_png_output_byte (data, data->slide[data->wp]);
+@@ -759,7 +788,11 @@ grub_png_decode_image_data (struct grub_png_data *data)
+   int final;
+ 
+   cmf = grub_png_get_byte (data);
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
+   flg = grub_png_get_byte (data);
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
+ 
+   if ((cmf & 0xF) != Z_DEFLATED)
+     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+@@ -774,7 +807,11 @@ grub_png_decode_image_data (struct grub_png_data *data)
+       int block_type;
+ 
+       final = grub_png_get_bits (data, 1);
++      if (grub_errno != GRUB_ERR_NONE)
++	return grub_errno;
+       block_type = grub_png_get_bits (data, 2);
++      if (grub_errno != GRUB_ERR_NONE)
++	return grub_errno;
+ 
+       switch (block_type)
+ 	{
+@@ -790,7 +827,7 @@ grub_png_decode_image_data (struct grub_png_data *data)
+ 	    grub_png_get_byte (data);
+ 	    grub_png_get_byte (data);
+ 
+-	    for (i = 0; i < len; i++)
++	    for (i = 0; i < len && grub_errno == GRUB_ERR_NONE; i++)
+ 	      grub_png_output_byte (data, grub_png_get_byte (data));
+ 
+ 	    break;
+@@ -1045,6 +1082,8 @@ grub_png_decode_png (struct grub_png_data *data)
+ 
+       len = grub_png_get_dword (data);
+       type = grub_png_get_dword (data);
++      if (grub_errno != GRUB_ERR_NONE)
++	break;
+       data->next_offset = data->file->offset + len + 4;
+ 
+       switch (type)
diff --git a/SOURCES/0222-Print-module-name-on-license-check-failure.patch b/SOURCES/0222-Print-module-name-on-license-check-failure.patch
deleted file mode 100644
index c4b9a13..0000000
--- a/SOURCES/0222-Print-module-name-on-license-check-failure.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Robbie Harwood <rharwood@redhat.com>
-Date: Tue, 12 Oct 2021 12:34:23 -0400
-Subject: [PATCH] Print module name on license check failure
-
-At the very least, this will make it easier to track down the problem
-module - or, if something else has gone wrong, provide more information
-for debugging.
-
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
----
- grub-core/kern/dl.c | 10 ++++++----
- 1 file changed, 6 insertions(+), 4 deletions(-)
-
-diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
-index 9557254035e..f3044945742 100644
---- a/grub-core/kern/dl.c
-+++ b/grub-core/kern/dl.c
-@@ -528,14 +528,16 @@ grub_dl_find_section_index (Elf_Ehdr *e, const char *name)
-    Be sure to understand your license obligations.
- */
- static grub_err_t
--grub_dl_check_license (Elf_Ehdr *e)
-+grub_dl_check_license (grub_dl_t mod, Elf_Ehdr *e)
- {
-   Elf_Shdr *s = grub_dl_find_section (e, ".module_license");
-   if (s && (grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3") == 0
- 	    || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3+") == 0
- 	    || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv2+") == 0))
-     return GRUB_ERR_NONE;
--  return grub_error (GRUB_ERR_BAD_MODULE, "incompatible license");
-+  return grub_error (GRUB_ERR_BAD_MODULE,
-+		     "incompatible license in module %s: %s", mod->name,
-+		     (char *) e + s->sh_offset);
- }
- 
- static grub_err_t
-@@ -743,8 +745,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
-      constitutes linking) and GRUB core being licensed under GPLv3+.
-      Be sure to understand your license obligations.
-   */
--  if (grub_dl_check_license (e)
--      || grub_dl_resolve_name (mod, e)
-+  if (grub_dl_resolve_name (mod, e)
-+      || grub_dl_check_license (mod, e)
-       || grub_dl_resolve_dependencies (mod, e)
-       || grub_dl_load_segments (mod, e)
-       || grub_dl_resolve_symbols (mod, e)
diff --git a/SOURCES/0222-video-readers-png-Refuse-to-handle-multiple-image-he.patch b/SOURCES/0222-video-readers-png-Refuse-to-handle-multiple-image-he.patch
new file mode 100644
index 0000000..9168fe5
--- /dev/null
+++ b/SOURCES/0222-video-readers-png-Refuse-to-handle-multiple-image-he.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 6 Jul 2021 14:13:40 +1000
+Subject: [PATCH] video/readers/png: Refuse to handle multiple image headers
+
+This causes the bitmap to be leaked. Do not permit multiple image headers.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 8ce433557adeadbc46429aabb9f850b02ad2bdfb)
+---
+ grub-core/video/readers/png.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
+index e2a6b1cf3c..8955b8ecfd 100644
+--- a/grub-core/video/readers/png.c
++++ b/grub-core/video/readers/png.c
+@@ -258,6 +258,9 @@ grub_png_decode_image_header (struct grub_png_data *data)
+   int color_bits;
+   enum grub_video_blit_format blt;
+ 
++  if (data->image_width || data->image_height)
++    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: two image headers found");
++
+   data->image_width = grub_png_get_dword (data);
+   data->image_height = grub_png_get_dword (data);
+ 
diff --git a/SOURCES/0223-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch b/SOURCES/0223-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch
deleted file mode 100644
index a80727e..0000000
--- a/SOURCES/0223-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch
+++ /dev/null
@@ -1,106 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Fri, 22 Oct 2021 09:53:15 +1100
-Subject: [PATCH] powerpc-ieee1275: load grub at 4MB, not 2MB
-
-This was first reported under PFW but reproduces under SLOF.
-
- - The core.elf was 2126152 = 0x207148 bytes in size with the following
-   program headers (per readelf):
-
-Entry point 0x200000
-There are 4 program headers, starting at offset 52
-
-Program Headers:
-  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
-  LOAD           0x000160 0x00200000 0x00200000 0x21f98 0x2971c RWE 0x8
-  GNU_STACK      0x0220f8 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
-  LOAD           0x0220f8 0x00232000 0x00232000 0x1e4e50 0x1e4e50 RWE 0x4
-  NOTE           0x206f48 0x00000000 0x00000000 0x00200 0x00000 R   0x4
-
- - SLOF places the ELF file at 0x4000 (after the reserved space for
-   interrupt handlers etc.) upwards. The image was 2126152 = 0x207148
-   bytes in size, so it runs from 0x4000 - 0x20b148. We'll call 0x4000 the
-   load address.
-
-0x0        0x4000         0x20b148
- |----------|--------------|
- | reserved | ELF contents |
-
- - SLOF then copies the first LOAD program header (for .text). That runs
-   for 0x21f98 bytes. It runs from
-      (load addr + 0x160) to (load addr + 0x160 + 0x21f98)
-    = 0x4160 to 0x260f8
-   and we copy it to 0x200000 to 0x221f98. This overwrites the end of the
-   image:
-
-0x0       0x4000     0x200000        0x221f98
- |----------|------------|---------------|
- | reserved | ELF cont.. | .text section |
-
- - SLOF zeros the bss up to PhysAddr + MemSize = 0x22971c
-
-0x0       0x4000      0x200000       0x221f98 0x22971c
- |----------|------------|---------------|--------|
- | reserved | ELF cont.. | .text section | bss 0s |
-
- - SLOF then goes to fulfil the next LOAD header (for mods), which is
-   for 0x1e4e50 bytes. We copy from
-      (load addr + 0x220f8) to (load addr + 0x220f8 + 0x1e4e50)
-    = 0x260f8 to 0x20af48
-   and we copy it to 0x232000 to 0x416e50:
-
-0x0       0x4000      0x200000       0x221f98 0x22971c
- |----------|------------|---------------|--------|
- | reserved | ELF cont.. | .text section | bss 0s |
-               |-------------|
-               | copied area |
-            0x260f8      0x20af48
-
-   This goes poorly:
-
-0x0       0x4000      0x200000       0x221f98 0x22971c 0x232000 0x40bf08      0x416e50
- |----------|------------|---------------|--------|-----|-----------|-------------|
- | reserved | ELF cont.. | .text section | bss 0s | pad | some mods | .text start |
-
-This matches the observations on the running system - 0x40bf08 was where
-the contents of memory no longer matched the contents of the ELF file.
-
-This was reported as a license verification failure on SLOF as the
-last module's .module_license section fell past where the corruption
-began.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-[rharwood@redhat.com: trim very detailed commit message]
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
----
- grub-core/Makefile.core.def | 2 +-
- include/grub/offsets.h      | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 3f3459b2c70..6b00eb55575 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -89,7 +89,7 @@ kernel = {
-   i386_xen_pvh_ldflags     = '$(TARGET_IMG_BASE_LDOPT),0x100000';
- 
-   mips_loongson_ldflags    = '-Wl,-Ttext,0x80200000';
--  powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x200000';
-+  powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x400000';
-   sparc64_ieee1275_ldflags = '-Wl,-Ttext,0x4400';
-   mips_arc_ldflags    = '-Wl,-Ttext,$(TARGET_LINK_ADDR)';
-   mips_qemu_mips_ldflags    = '-Wl,-Ttext,0x80200000';
-diff --git a/include/grub/offsets.h b/include/grub/offsets.h
-index 871e1cd4c38..69211aa798b 100644
---- a/include/grub/offsets.h
-+++ b/include/grub/offsets.h
-@@ -63,7 +63,7 @@
- #define GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR 0x4400
- 
- #define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ALIGN 4
--#define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x200000
-+#define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x400000
- 
- #define GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR         0x80200000
- 
diff --git a/SOURCES/0223-video-readers-png-Drop-greyscale-support-to-fix-heap.patch b/SOURCES/0223-video-readers-png-Drop-greyscale-support-to-fix-heap.patch
new file mode 100644
index 0000000..4529cb8
--- /dev/null
+++ b/SOURCES/0223-video-readers-png-Drop-greyscale-support-to-fix-heap.patch
@@ -0,0 +1,170 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 6 Jul 2021 18:51:35 +1000
+Subject: [PATCH] video/readers/png: Drop greyscale support to fix heap
+ out-of-bounds write
+
+A 16-bit greyscale PNG without alpha is processed in the following loop:
+
+      for (i = 0; i < (data->image_width * data->image_height);
+	   i++, d1 += 4, d2 += 2)
+	{
+	  d1[R3] = d2[1];
+	  d1[G3] = d2[1];
+	  d1[B3] = d2[1];
+	}
+
+The increment of d1 is wrong. d1 is incremented by 4 bytes per iteration,
+but there are only 3 bytes allocated for storage. This means that image
+data will overwrite somewhat-attacker-controlled parts of memory - 3 bytes
+out of every 4 following the end of the image.
+
+This has existed since greyscale support was added in 2013 in commit
+3ccf16dff98f (grub-core/video/readers/png.c: Support grayscale).
+
+Saving starfield.png as a 16-bit greyscale image without alpha in the gimp
+and attempting to load it causes grub-emu to crash - I don't think this code
+has ever worked.
+
+Delete all PNG greyscale support.
+
+Fixes: CVE-2021-3695
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 0e1d163382669bd734439d8864ee969616d971d9)
+[rharwood: context conflict]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/video/readers/png.c | 85 +++----------------------------------------
+ 1 file changed, 6 insertions(+), 79 deletions(-)
+
+diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
+index 8955b8ecfd..a3161e25b6 100644
+--- a/grub-core/video/readers/png.c
++++ b/grub-core/video/readers/png.c
+@@ -100,7 +100,7 @@ struct grub_png_data
+ 
+   unsigned image_width, image_height;
+   int bpp, is_16bit;
+-  int raw_bytes, is_gray, is_alpha, is_palette;
++  int raw_bytes, is_alpha, is_palette;
+   int row_bytes, color_bits;
+   grub_uint8_t *image_data;
+ 
+@@ -296,13 +296,13 @@ grub_png_decode_image_header (struct grub_png_data *data)
+     data->bpp = 3;
+   else
+     {
+-      data->is_gray = 1;
+-      data->bpp = 1;
++      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			 "png: color type not supported");
+     }
+ 
+   if ((color_bits != 8) && (color_bits != 16)
+       && (color_bits != 4
+-	  || !(data->is_gray || data->is_palette)))
++	  || !data->is_palette))
+     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+                        "png: bit depth must be 8 or 16");
+ 
+@@ -331,7 +331,7 @@ grub_png_decode_image_header (struct grub_png_data *data)
+     }
+ 
+ #ifndef GRUB_CPU_WORDS_BIGENDIAN
+-  if (data->is_16bit || data->is_gray || data->is_palette)
++  if (data->is_16bit || data->is_palette)
+ #endif
+     {
+       data->image_data = grub_calloc (data->image_height, data->row_bytes);
+@@ -899,27 +899,8 @@ grub_png_convert_image (struct grub_png_data *data)
+       int shift;
+       int mask = (1 << data->color_bits) - 1;
+       unsigned j;
+-      if (data->is_gray)
+-	{
+-	  /* Generic formula is
+-	     (0xff * i) / ((1U << data->color_bits) - 1)
+-	     but for allowed bit depth of 1, 2 and for it's
+-	     equivalent to
+-	     (0xff / ((1U << data->color_bits) - 1)) * i
+-	     Precompute the multipliers to avoid division.
+-	  */
+ 
+-	  const grub_uint8_t multipliers[5] = { 0xff, 0xff, 0x55, 0x24, 0x11 };
+-	  for (i = 0; i < (1U << data->color_bits); i++)
+-	    {
+-	      grub_uint8_t col = multipliers[data->color_bits] * i;
+-	      palette[i][0] = col;
+-	      palette[i][1] = col;
+-	      palette[i][2] = col;
+-	    }
+-	}
+-      else
+-	grub_memcpy (palette, data->palette, 3 << data->color_bits);
++      grub_memcpy (palette, data->palette, 3 << data->color_bits);
+       d1c = d1;
+       d2c = d2;
+       for (j = 0; j < data->image_height; j++, d1c += data->image_width * 3,
+@@ -956,60 +937,6 @@ grub_png_convert_image (struct grub_png_data *data)
+ 	}
+       return;
+     }
+-  
+-  if (data->is_gray)
+-    {
+-      switch (data->bpp)
+-	{
+-	case 4:
+-	  /* 16-bit gray with alpha.  */
+-	  for (i = 0; i < (data->image_width * data->image_height);
+-	       i++, d1 += 4, d2 += 4)
+-	    {
+-	      d1[R4] = d2[3];
+-	      d1[G4] = d2[3];
+-	      d1[B4] = d2[3];
+-	      d1[A4] = d2[1];
+-	    }
+-	  break;
+-	case 2:
+-	  if (data->is_16bit)
+-	    /* 16-bit gray without alpha.  */
+-	    {
+-	      for (i = 0; i < (data->image_width * data->image_height);
+-		   i++, d1 += 4, d2 += 2)
+-		{
+-		  d1[R3] = d2[1];
+-		  d1[G3] = d2[1];
+-		  d1[B3] = d2[1];
+-		}
+-	    }
+-	  else
+-	    /* 8-bit gray with alpha.  */
+-	    {
+-	      for (i = 0; i < (data->image_width * data->image_height);
+-		   i++, d1 += 4, d2 += 2)
+-		{
+-		  d1[R4] = d2[1];
+-		  d1[G4] = d2[1];
+-		  d1[B4] = d2[1];
+-		  d1[A4] = d2[0];
+-		}
+-	    }
+-	  break;
+-	  /* 8-bit gray without alpha.  */
+-	case 1:
+-	  for (i = 0; i < (data->image_width * data->image_height);
+-	       i++, d1 += 3, d2++)
+-	    {
+-	      d1[R3] = d2[0];
+-	      d1[G3] = d2[0];
+-	      d1[B3] = d2[0];
+-	    }
+-	  break;
+-	}
+-      return;
+-    }
+ 
+     {
+   /* Only copy the upper 8 bit.  */
diff --git a/SOURCES/0224-grub-mkconfig-restore-umask-for-grub.cfg.patch b/SOURCES/0224-grub-mkconfig-restore-umask-for-grub.cfg.patch
deleted file mode 100644
index bd1bd0c..0000000
--- a/SOURCES/0224-grub-mkconfig-restore-umask-for-grub.cfg.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Michael Chang via Grub-devel <grub-devel@gnu.org>
-Date: Fri, 3 Dec 2021 16:13:28 +0800
-Subject: [PATCH] grub-mkconfig: restore umask for grub.cfg
-
-Since commit:
-
-  ab2e53c8a grub-mkconfig: Honor a symlink when generating configuration
-by grub-mkconfig
-
-has inadvertently discarded umask for creating grub.cfg in the process
-of grub-mkconfig. The resulting wrong permission (0644) would allow
-unprivileged users to read grub's configuration file content. This
-presents a low confidentiality risk as grub.cfg may contain non-secured
-plain-text passwords.
-
-This patch restores the missing umask and set the file mode of creation
-to 0600 preventing unprivileged access.
-
-Fixes: CVE-2021-3981
-
-Signed-off-by: Michael Chang <mchang@suse.com>
-(cherry picked from commit 2acad06610da1488bfa387f56a847119ab758766)
----
- util/grub-mkconfig.in | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
-index f55339a3f64..520a672cd2c 100644
---- a/util/grub-mkconfig.in
-+++ b/util/grub-mkconfig.in
-@@ -311,7 +311,9 @@ and /etc/grub.d/* files or please file a bug report with
-     exit 1
-   else
-     # none of the children aborted with error, install the new grub.cfg
-+    oldumask=$(umask); umask 077
-     cat ${grub_cfg}.new > ${grub_cfg}
-+    umask $oldumask
-     rm -f ${grub_cfg}.new
-   fi
- fi
diff --git a/SOURCES/0224-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch b/SOURCES/0224-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch
new file mode 100644
index 0000000..51dddfe
--- /dev/null
+++ b/SOURCES/0224-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 6 Jul 2021 23:25:07 +1000
+Subject: [PATCH] video/readers/png: Avoid heap OOB R/W inserting huff table
+ items
+
+In fuzzing we observed crashes where a code would attempt to be inserted
+into a huffman table before the start, leading to a set of heap OOB reads
+and writes as table entries with negative indices were shifted around and
+the new code written in.
+
+Catch the case where we would underflow the array and bail.
+
+Fixes: CVE-2021-3696
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 1ae9a91d42cb40da8a6f11fac65541858e340afa)
+---
+ grub-core/video/readers/png.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
+index a3161e25b6..d7ed5aa6cf 100644
+--- a/grub-core/video/readers/png.c
++++ b/grub-core/video/readers/png.c
+@@ -438,6 +438,13 @@ grub_png_insert_huff_item (struct huff_table *ht, int code, int len)
+   for (i = len; i < ht->max_length; i++)
+     n += ht->maxval[i];
+ 
++  if (n > ht->num_values)
++    {
++      grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		  "png: out of range inserting huffman table item");
++      return;
++    }
++
+   for (i = 0; i < n; i++)
+     ht->values[ht->num_values - i] = ht->values[ht->num_values - i - 1];
+ 
diff --git a/SOURCES/0225-commands-search-Fix-bug-stopping-iteration-when-no-f.patch b/SOURCES/0225-commands-search-Fix-bug-stopping-iteration-when-no-f.patch
deleted file mode 100644
index c5971ac..0000000
--- a/SOURCES/0225-commands-search-Fix-bug-stopping-iteration-when-no-f.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
-Date: Tue, 8 Feb 2022 08:39:10 +0100
-Subject: [PATCH] commands/search: Fix bug stopping iteration when --no-floppy
- is used
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-When using --no-floppy and a floppy was encountered, iterate_device()
-was returning 1, causing the iteration to stop instead of continuing.
-
-Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 68ba54c2298604146be83cae144dafd1cfd1fe2d)
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
-(cherry picked from commit 7ada55e3fcd16e00773d3918955b2b945b7f063a)
----
- grub-core/commands/search.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c
-index ed090b3af8b..51656e361cc 100644
---- a/grub-core/commands/search.c
-+++ b/grub-core/commands/search.c
-@@ -64,7 +64,7 @@ iterate_device (const char *name, void *data)
-   /* Skip floppy drives when requested.  */
-   if (ctx->no_floppy &&
-       name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9')
--    return 1;
-+    return 0;
- 
- #ifdef DO_SEARCH_FS_UUID
- #define compare_fn grub_strcasecmp
diff --git a/SOURCES/0225-video-readers-png-Sanity-check-some-huffman-codes.patch b/SOURCES/0225-video-readers-png-Sanity-check-some-huffman-codes.patch
new file mode 100644
index 0000000..c9cef25
--- /dev/null
+++ b/SOURCES/0225-video-readers-png-Sanity-check-some-huffman-codes.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 6 Jul 2021 19:19:11 +1000
+Subject: [PATCH] video/readers/png: Sanity check some huffman codes
+
+ASAN picked up two OOB global reads: we weren't checking if some code
+values fit within the cplens or cpdext arrays. Check and throw an error
+if not.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit c3a8ab0cbd24153ec7b1f84a96ddfdd72ef8d117)
+---
+ grub-core/video/readers/png.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
+index d7ed5aa6cf..7f2ba7849b 100644
+--- a/grub-core/video/readers/png.c
++++ b/grub-core/video/readers/png.c
+@@ -753,6 +753,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data)
+ 	  int len, dist, pos;
+ 
+ 	  n -= 257;
++	  if (((unsigned int) n) >= ARRAY_SIZE (cplens))
++	    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			       "png: invalid huff code");
+ 	  len = cplens[n];
+ 	  if (cplext[n])
+ 	    len += grub_png_get_bits (data, cplext[n]);
+@@ -760,6 +763,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data)
+ 	    return grub_errno;
+ 
+ 	  n = grub_png_get_huff_code (data, &data->dist_table);
++	  if (((unsigned int) n) >= ARRAY_SIZE (cpdist))
++	    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			       "png: invalid huff code");
+ 	  dist = cpdist[n];
+ 	  if (cpdext[n])
+ 	    dist += grub_png_get_bits (data, cpdext[n]);
diff --git a/SOURCES/0226-search-new-efidisk-only-option-on-EFI-systems.patch b/SOURCES/0226-search-new-efidisk-only-option-on-EFI-systems.patch
deleted file mode 100644
index 8e24dac..0000000
--- a/SOURCES/0226-search-new-efidisk-only-option-on-EFI-systems.patch
+++ /dev/null
@@ -1,169 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
-Date: Tue, 8 Feb 2022 08:39:11 +0100
-Subject: [PATCH] search: new --efidisk-only option on EFI systems
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-When using 'search' on EFI systems, we sometimes want to exclude devices
-that are not EFI disks (e.g. md, lvm).
-This is typically used when wanting to chainload when having a software
-raid (md) for EFI partition:
-with no option, 'search --file /EFI/redhat/shimx64.efi' sets root envvar
-to 'md/boot_efi' which cannot be used for chainloading since there is no
-effective EFI device behind.
-
-This commit also refactors handling of --no-floppy option.
-
-Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
-[rharwood: apply rmetrich's flags initialization fix]
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
-(cherry picked from commit fdd8396f4fa750bbbabd4298f2593942f2b84710)
----
- grub-core/commands/search.c      | 27 +++++++++++++++++++++++----
- grub-core/commands/search_wrap.c | 18 ++++++++++++------
- include/grub/search.h            | 15 ++++++++++++---
- 3 files changed, 47 insertions(+), 13 deletions(-)
-
-diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c
-index 51656e361cc..57d26ced8a8 100644
---- a/grub-core/commands/search.c
-+++ b/grub-core/commands/search.c
-@@ -47,7 +47,7 @@ struct search_ctx
- {
-   const char *key;
-   const char *var;
--  int no_floppy;
-+  enum search_flags flags;
-   char **hints;
-   unsigned nhints;
-   int count;
-@@ -62,10 +62,29 @@ iterate_device (const char *name, void *data)
-   int found = 0;
- 
-   /* Skip floppy drives when requested.  */
--  if (ctx->no_floppy &&
-+  if (ctx->flags & SEARCH_FLAGS_NO_FLOPPY &&
-       name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9')
-     return 0;
- 
-+  /* Limit to EFI disks when requested.  */
-+  if (ctx->flags & SEARCH_FLAGS_EFIDISK_ONLY)
-+    {
-+      grub_device_t dev;
-+      dev = grub_device_open (name);
-+      if (! dev)
-+	{
-+	  grub_errno = GRUB_ERR_NONE;
-+	  return 0;
-+	}
-+      if (! dev->disk || dev->disk->dev->id != GRUB_DISK_DEVICE_EFIDISK_ID)
-+	{
-+	  grub_device_close (dev);
-+	  grub_errno = GRUB_ERR_NONE;
-+	  return 0;
-+	}
-+      grub_device_close (dev);
-+    }
-+
- #ifdef DO_SEARCH_FS_UUID
- #define compare_fn grub_strcasecmp
- #else
-@@ -261,13 +280,13 @@ try (struct search_ctx *ctx)
- }
- 
- void
--FUNC_NAME (const char *key, const char *var, int no_floppy,
-+FUNC_NAME (const char *key, const char *var, enum search_flags flags,
- 	   char **hints, unsigned nhints)
- {
-   struct search_ctx ctx = {
-     .key = key,
-     .var = var,
--    .no_floppy = no_floppy,
-+    .flags = flags,
-     .hints = hints,
-     .nhints = nhints,
-     .count = 0,
-diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c
-index 47fc8eb9966..0b62acf8535 100644
---- a/grub-core/commands/search_wrap.c
-+++ b/grub-core/commands/search_wrap.c
-@@ -40,6 +40,7 @@ static const struct grub_arg_option options[] =
-      N_("Set a variable to the first device found."), N_("VARNAME"),
-      ARG_TYPE_STRING},
-     {"no-floppy",	'n', 0, N_("Do not probe any floppy drive."), 0, 0},
-+    {"efidisk-only",	0, 0, N_("Only probe EFI disks."), 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},
-@@ -73,6 +74,7 @@ enum options
-     SEARCH_FS_UUID,
-     SEARCH_SET,
-     SEARCH_NO_FLOPPY,
-+    SEARCH_EFIDISK_ONLY,
-     SEARCH_HINT,
-     SEARCH_HINT_IEEE1275,
-     SEARCH_HINT_BIOS,
-@@ -89,6 +91,7 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
-   const char *id = 0;
-   int i = 0, j = 0, nhints = 0;
-   char **hints = NULL;
-+  enum search_flags flags = 0;
- 
-   if (state[SEARCH_HINT].set)
-     for (i = 0; state[SEARCH_HINT].args[i]; i++)
-@@ -180,15 +183,18 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
-       goto out;
-     }
- 
-+  if (state[SEARCH_NO_FLOPPY].set)
-+    flags |= SEARCH_FLAGS_NO_FLOPPY;
-+
-+  if (state[SEARCH_EFIDISK_ONLY].set)
-+    flags |= SEARCH_FLAGS_EFIDISK_ONLY;
-+
-   if (state[SEARCH_LABEL].set)
--    grub_search_label (id, var, state[SEARCH_NO_FLOPPY].set, 
--		       hints, nhints);
-+    grub_search_label (id, var, flags, hints, nhints);
-   else if (state[SEARCH_FS_UUID].set)
--    grub_search_fs_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
--			 hints, nhints);
-+    grub_search_fs_uuid (id, var, flags, hints, nhints);
-   else if (state[SEARCH_FILE].set)
--    grub_search_fs_file (id, var, state[SEARCH_NO_FLOPPY].set, 
--			 hints, nhints);
-+    grub_search_fs_file (id, var, flags, hints, nhints);
-   else
-     grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type");
- 
-diff --git a/include/grub/search.h b/include/grub/search.h
-index d80347df34b..4190aeb2cbf 100644
---- a/include/grub/search.h
-+++ b/include/grub/search.h
-@@ -19,11 +19,20 @@
- #ifndef GRUB_SEARCH_HEADER
- #define GRUB_SEARCH_HEADER 1
- 
--void grub_search_fs_file (const char *key, const char *var, int no_floppy,
-+enum search_flags
-+  {
-+    SEARCH_FLAGS_NO_FLOPPY	= 1,
-+    SEARCH_FLAGS_EFIDISK_ONLY	= 2
-+  };
-+
-+void grub_search_fs_file (const char *key, const char *var,
-+			  enum search_flags flags,
- 			  char **hints, unsigned nhints);
--void grub_search_fs_uuid (const char *key, const char *var, int no_floppy,
-+void grub_search_fs_uuid (const char *key, const char *var,
-+			  enum search_flags flags,
- 			  char **hints, unsigned nhints);
--void grub_search_label (const char *key, const char *var, int no_floppy,
-+void grub_search_label (const char *key, const char *var,
-+			enum search_flags flags,
- 			char **hints, unsigned nhints);
- 
- #endif
diff --git a/SOURCES/0226-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch b/SOURCES/0226-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch
new file mode 100644
index 0000000..5491816
--- /dev/null
+++ b/SOURCES/0226-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch
@@ -0,0 +1,255 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 28 Jun 2021 14:16:14 +1000
+Subject: [PATCH] video/readers/jpeg: Abort sooner if a read operation fails
+
+Fuzzing revealed some inputs that were taking a long time, potentially
+forever, because they did not bail quickly upon encountering an I/O error.
+
+Try to catch I/O errors sooner and bail out.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit ab2e5d2e4bff488bbb557ed435a61ae102ef9f0c)
+---
+ grub-core/video/readers/jpeg.c | 86 ++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 70 insertions(+), 16 deletions(-)
+
+diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
+index e31602f766..10225abd53 100644
+--- a/grub-core/video/readers/jpeg.c
++++ b/grub-core/video/readers/jpeg.c
+@@ -109,9 +109,17 @@ static grub_uint8_t
+ grub_jpeg_get_byte (struct grub_jpeg_data *data)
+ {
+   grub_uint8_t r;
++  grub_ssize_t bytes_read;
+ 
+   r = 0;
+-  grub_file_read (data->file, &r, 1);
++  bytes_read = grub_file_read (data->file, &r, 1);
++
++  if (bytes_read != 1)
++    {
++      grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		  "jpeg: unexpected end of data");
++      return 0;
++    }
+ 
+   return r;
+ }
+@@ -120,9 +128,17 @@ static grub_uint16_t
+ grub_jpeg_get_word (struct grub_jpeg_data *data)
+ {
+   grub_uint16_t r;
++  grub_ssize_t bytes_read;
+ 
+   r = 0;
+-  grub_file_read (data->file, &r, sizeof (grub_uint16_t));
++  bytes_read = grub_file_read (data->file, &r, sizeof (grub_uint16_t));
++
++  if (bytes_read != sizeof (grub_uint16_t))
++    {
++      grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		  "jpeg: unexpected end of data");
++      return 0;
++    }
+ 
+   return grub_be_to_cpu16 (r);
+ }
+@@ -135,6 +151,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data)
+   if (data->bit_mask == 0)
+     {
+       data->bit_save = grub_jpeg_get_byte (data);
++      if (grub_errno != GRUB_ERR_NONE) {
++	grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		    "jpeg: file read error");
++	return 0;
++      }
+       if (data->bit_save == JPEG_ESC_CHAR)
+ 	{
+ 	  if (grub_jpeg_get_byte (data) != 0)
+@@ -143,6 +164,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data)
+ 			  "jpeg: invalid 0xFF in data stream");
+ 	      return 0;
+ 	    }
++	  if (grub_errno != GRUB_ERR_NONE)
++	    {
++	      grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: file read error");
++	      return 0;
++	    }
+ 	}
+       data->bit_mask = 0x80;
+     }
+@@ -161,7 +187,7 @@ grub_jpeg_get_number (struct grub_jpeg_data *data, int num)
+     return 0;
+ 
+   msb = value = grub_jpeg_get_bit (data);
+-  for (i = 1; i < num; i++)
++  for (i = 1; i < num && grub_errno == GRUB_ERR_NONE; i++)
+     value = (value << 1) + (grub_jpeg_get_bit (data) != 0);
+   if (!msb)
+     value += 1 - (1 << num);
+@@ -202,6 +228,8 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data)
+   while (data->file->offset + sizeof (count) + 1 <= next_marker)
+     {
+       id = grub_jpeg_get_byte (data);
++      if (grub_errno != GRUB_ERR_NONE)
++	return grub_errno;
+       ac = (id >> 4) & 1;
+       id &= 0xF;
+       if (id > 1)
+@@ -252,6 +280,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data)
+ 
+   next_marker = data->file->offset;
+   next_marker += grub_jpeg_get_word (data);
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
+ 
+   if (next_marker > data->file->size)
+     {
+@@ -263,6 +293,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data)
+ 	 <= next_marker)
+     {
+       id = grub_jpeg_get_byte (data);
++      if (grub_errno != GRUB_ERR_NONE)
++        return grub_errno;
+       if (id >= 0x10)		/* Upper 4-bit is precision.  */
+ 	return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ 			   "jpeg: only 8-bit precision is supported");
+@@ -294,6 +326,9 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data)
+   next_marker = data->file->offset;
+   next_marker += grub_jpeg_get_word (data);
+ 
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
++
+   if (grub_jpeg_get_byte (data) != 8)
+     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ 		       "jpeg: only 8-bit precision is supported");
+@@ -319,6 +354,8 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data)
+ 	return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index");
+ 
+       ss = grub_jpeg_get_byte (data);	/* Sampling factor.  */
++      if (grub_errno != GRUB_ERR_NONE)
++	return grub_errno;
+       if (!id)
+ 	{
+ 	  grub_uint8_t vs, hs;
+@@ -498,7 +535,7 @@ grub_jpeg_idct_transform (jpeg_data_unit_t du)
+     }
+ }
+ 
+-static void
++static grub_err_t
+ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
+ {
+   int h1, h2, qt;
+@@ -513,6 +550,9 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
+   data->dc_value[id] +=
+     grub_jpeg_get_number (data, grub_jpeg_get_huff_code (data, h1));
+ 
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
++
+   du[0] = data->dc_value[id] * (int) data->quan_table[qt][0];
+   pos = 1;
+   while (pos < ARRAY_SIZE (data->quan_table[qt]))
+@@ -527,11 +567,13 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
+       num >>= 4;
+       pos += num;
+ 
++      if (grub_errno != GRUB_ERR_NONE)
++        return grub_errno;
++
+       if (pos >= ARRAY_SIZE (jpeg_zigzag_order))
+ 	{
+-	  grub_error (GRUB_ERR_BAD_FILE_TYPE,
+-		      "jpeg: invalid position in zigzag order!?");
+-	  return;
++	  return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			     "jpeg: invalid position in zigzag order!?");
+ 	}
+ 
+       du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos];
+@@ -539,6 +581,7 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
+     }
+ 
+   grub_jpeg_idct_transform (du);
++  return GRUB_ERR_NONE;
+ }
+ 
+ static void
+@@ -597,7 +640,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
+   data_offset += grub_jpeg_get_word (data);
+ 
+   cc = grub_jpeg_get_byte (data);
+-
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
+   if (cc != 3 && cc != 1)
+     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ 		       "jpeg: component count must be 1 or 3");
+@@ -610,7 +654,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
+       id = grub_jpeg_get_byte (data) - 1;
+       if ((id < 0) || (id >= 3))
+ 	return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index");
+-
++      if (grub_errno != GRUB_ERR_NONE)
++	return grub_errno;
+       ht = grub_jpeg_get_byte (data);
+       data->comp_index[id][1] = (ht >> 4);
+       data->comp_index[id][2] = (ht & 0xF) + 2;
+@@ -618,11 +663,14 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
+       if ((data->comp_index[id][1] < 0) || (data->comp_index[id][1] > 3) ||
+ 	  (data->comp_index[id][2] < 0) || (data->comp_index[id][2] > 3))
+ 	return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid hufftable index");
++      if (grub_errno != GRUB_ERR_NONE)
++	return grub_errno;
+     }
+ 
+   grub_jpeg_get_byte (data);	/* Skip 3 unused bytes.  */
+   grub_jpeg_get_word (data);
+-
++  if (grub_errno != GRUB_ERR_NONE)
++    return grub_errno;
+   if (data->file->offset != data_offset)
+     return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos");
+ 
+@@ -640,6 +688,7 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
+ {
+   unsigned c1, vb, hb, nr1, nc1;
+   int rst = data->dri;
++  grub_err_t err = GRUB_ERR_NONE;
+ 
+   vb = 8 << data->log_vs;
+   hb = 8 << data->log_hs;
+@@ -660,17 +709,22 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
+ 
+ 	for (r2 = 0; r2 < (1U << data->log_vs); r2++)
+ 	  for (c2 = 0; c2 < (1U << data->log_hs); c2++)
+-	    grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]);
++            {
++              err = grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]);
++              if (err != GRUB_ERR_NONE)
++                return err;
++            }
+ 
+ 	if (data->color_components >= 3)
+ 	  {
+-	    grub_jpeg_decode_du (data, 1, data->cbdu);
+-	    grub_jpeg_decode_du (data, 2, data->crdu);
++	    err = grub_jpeg_decode_du (data, 1, data->cbdu);
++	    if (err != GRUB_ERR_NONE)
++	      return err;
++	    err = grub_jpeg_decode_du (data, 2, data->crdu);
++	    if (err != GRUB_ERR_NONE)
++	      return err;
+ 	  }
+ 
+-	if (grub_errno)
+-	  return grub_errno;
+-
+ 	nr2 = (data->r1 == nr1 - 1) ? (data->image_height - data->r1 * vb) : vb;
+ 	nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb;
+ 
diff --git a/SOURCES/0227-efi-new-connectefi-command.patch b/SOURCES/0227-efi-new-connectefi-command.patch
deleted file mode 100644
index abb6f6f..0000000
--- a/SOURCES/0227-efi-new-connectefi-command.patch
+++ /dev/null
@@ -1,396 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
-Date: Tue, 15 Feb 2022 14:05:22 +0100
-Subject: [PATCH] efi: new 'connectefi' command
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-When efi.quickboot is enabled on VMWare (which is the default for
-hardware release 16 and later), it may happen that not all EFI devices
-are connected. Due to this, browsing the devices in make_devices() just
-fails to find devices, in particular disks or partitions for a given
-disk.
-This typically happens when network booting, then trying to chainload to
-local disk (this is used in deployment tools such as Red Hat Satellite),
-which is done through using the following grub.cfg snippet:
--------- 8< ---------------- 8< ---------------- 8< --------
-unset prefix
-search --file --set=prefix /EFI/redhat/grubx64.efi
-if [ -n "$prefix" ]; then
-  chainloader ($prefix)/EFI/redhat/grubx64/efi
-...
--------- 8< ---------------- 8< ---------------- 8< --------
-
-With efi.quickboot, none of the devices are connected, causing "search"
-to fail. Sometimes devices are connected but not the partition of the
-disk matching $prefix, causing partition to not be found by
-"chainloader".
-
-This patch introduces a new "connectefi pciroot|scsi" command which
-recursively connects all EFI devices starting from a given controller
-type:
-- if 'pciroot' is specified, recursion is performed for all PCI root
-  handles
-- if 'scsi' is specified, recursion is performed for all SCSI I/O
-  handles (recommended usage to avoid connecting unwanted handles which
-  may impact Grub performances)
-
-Typical grub.cfg snippet would then be:
--------- 8< ---------------- 8< ---------------- 8< --------
-connectefi scsi
-unset prefix
-search --file --set=prefix /EFI/redhat/grubx64.efi
-if [ -n "$prefix" ]; then
-  chainloader ($prefix)/EFI/redhat/grubx64/efi
-...
--------- 8< ---------------- 8< ---------------- 8< --------
-
-The code is easily extensible to handle other arguments in the future if
-needed.
-
-Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
-(cherry picked from commit cc972c27314c841f80ab0fe8318fae06f078c680)
----
- grub-core/Makefile.core.def         |   6 ++
- grub-core/commands/efi/connectefi.c | 205 ++++++++++++++++++++++++++++++++++++
- grub-core/commands/efi/lsefi.c      |   1 +
- grub-core/disk/efi/efidisk.c        |  13 +++
- grub-core/kern/efi/efi.c            |  13 +++
- include/grub/efi/disk.h             |   2 +
- include/grub/efi/efi.h              |   5 +
- NEWS                                |   2 +-
- 8 files changed, 246 insertions(+), 1 deletion(-)
- create mode 100644 grub-core/commands/efi/connectefi.c
-
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 6b00eb55575..97abc01f064 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -833,6 +833,12 @@ module = {
-   enable = efi;
- };
- 
-+module = {
-+  name = connectefi;
-+  common = commands/efi/connectefi.c;
-+  enable = efi;
-+};
-+
- module = {
-   name = blocklist;
-   common = commands/blocklist.c;
-diff --git a/grub-core/commands/efi/connectefi.c b/grub-core/commands/efi/connectefi.c
-new file mode 100644
-index 00000000000..8ab75bd51be
---- /dev/null
-+++ b/grub-core/commands/efi/connectefi.c
-@@ -0,0 +1,205 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2022  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/pci.h>
-+#include <grub/efi/efi.h>
-+#include <grub/command.h>
-+#include <grub/err.h>
-+#include <grub/i18n.h>
-+
-+GRUB_MOD_LICENSE ("GPLv3+");
-+
-+typedef struct handle_list
-+{
-+  grub_efi_handle_t handle;
-+  struct handle_list *next;
-+} handle_list_t;
-+
-+static handle_list_t *already_handled = NULL;
-+
-+static grub_err_t
-+add_handle (grub_efi_handle_t handle)
-+{
-+  handle_list_t *e;
-+  e = grub_malloc (sizeof (*e));
-+  if (! e)
-+    return grub_errno;
-+  e->handle = handle;
-+  e->next = already_handled;
-+  already_handled = e;
-+  return GRUB_ERR_NONE;
-+}
-+
-+static int
-+is_in_list (grub_efi_handle_t handle)
-+{
-+  handle_list_t *e;
-+  for (e = already_handled; e != NULL; e = e->next)
-+    if (e->handle == handle)
-+      return 1;
-+  return 0;
-+}
-+
-+static void
-+free_handle_list (void)
-+{
-+  handle_list_t *e;
-+  while ((e = already_handled) != NULL)
-+    {
-+      already_handled = already_handled->next;
-+      grub_free (e);
-+    }
-+}
-+
-+typedef enum searched_item_flag
-+{
-+  SEARCHED_ITEM_FLAG_LOOP = 1,
-+  SEARCHED_ITEM_FLAG_RECURSIVE = 2
-+} searched_item_flags;
-+
-+typedef struct searched_item
-+{
-+  grub_efi_guid_t guid;
-+  const char *name;
-+  searched_item_flags flags;
-+} searched_items;
-+
-+static grub_err_t
-+grub_cmd_connectefi (grub_command_t cmd __attribute__ ((unused)),
-+		     int argc, char **args)
-+{
-+  unsigned s;
-+  searched_items pciroot_items[] =
-+    {
-+      { GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root", SEARCHED_ITEM_FLAG_RECURSIVE }
-+    };
-+  searched_items scsi_items[] =
-+    {
-+      { GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root", 0 },
-+      { GRUB_EFI_PCI_IO_GUID, "PCI", SEARCHED_ITEM_FLAG_LOOP },
-+      { GRUB_EFI_SCSI_IO_PROTOCOL_GUID, "SCSI I/O", SEARCHED_ITEM_FLAG_RECURSIVE }
-+    };
-+  searched_items *items = NULL;
-+  unsigned nitems = 0;
-+  grub_err_t grub_err = GRUB_ERR_NONE;
-+  unsigned total_connected = 0;
-+
-+  if (argc != 1)
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
-+
-+  if (grub_strcmp(args[0], N_("pciroot")) == 0)
-+    {
-+      items = pciroot_items;
-+      nitems = ARRAY_SIZE (pciroot_items);
-+    }
-+  else if (grub_strcmp(args[0], N_("scsi")) == 0)
-+    {
-+      items = scsi_items;
-+      nitems = ARRAY_SIZE (scsi_items);
-+    }
-+  else
-+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
-+		       N_("unexpected argument `%s'"), args[0]);
-+
-+  for (s = 0; s < nitems; s++)
-+    {
-+      grub_efi_handle_t *handles;
-+      grub_efi_uintn_t num_handles;
-+      unsigned i, connected = 0, loop = 0;
-+
-+loop:
-+      loop++;
-+      grub_dprintf ("efi", "step '%s' loop %d:\n", items[s].name, loop);
-+
-+      handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL,
-+					&items[s].guid, 0, &num_handles);
-+
-+      if (!handles)
-+	continue;
-+
-+      for (i = 0; i < num_handles; i++)
-+	{
-+	  grub_efi_handle_t handle = handles[i];
-+	  grub_efi_status_t status;
-+	  unsigned j;
-+
-+	  /* Skip already handled handles  */
-+	  if (is_in_list (handle))
-+	    {
-+	      grub_dprintf ("efi", "  handle %p: already processed\n",
-+				   handle);
-+	      continue;
-+	    }
-+
-+	  status = grub_efi_connect_controller(handle, NULL, NULL,
-+			items[s].flags & SEARCHED_ITEM_FLAG_RECURSIVE ? 1 : 0);
-+	  if (status == GRUB_EFI_SUCCESS)
-+	    {
-+	      connected++;
-+	      total_connected++;
-+	      grub_dprintf ("efi", "  handle %p: connected\n", handle);
-+	    }
-+	  else
-+	    grub_dprintf ("efi", "  handle %p: failed to connect (%d)\n",
-+				 handle, (grub_efi_int8_t) status);
-+
-+	  if ((grub_err = add_handle (handle)) != GRUB_ERR_NONE)
-+	    break; /* fatal  */
-+	}
-+
-+      grub_free (handles);
-+      if (grub_err != GRUB_ERR_NONE)
-+	break; /* fatal  */
-+
-+      if (items[s].flags & SEARCHED_ITEM_FLAG_LOOP && connected)
-+	{
-+	  connected = 0;
-+	  goto loop;
-+	}
-+
-+      free_handle_list ();
-+    }
-+
-+  free_handle_list ();
-+
-+  if (total_connected)
-+    grub_efidisk_reenumerate_disks ();
-+
-+  return grub_err;
-+}
-+
-+static grub_command_t cmd;
-+
-+GRUB_MOD_INIT(connectefi)
-+{
-+  cmd = grub_register_command ("connectefi", grub_cmd_connectefi,
-+			       N_("pciroot|scsi"),
-+			       N_("Connect EFI handles."
-+				  " If 'pciroot' is specified, connect PCI"
-+				  " root EFI handles recursively."
-+				  " If 'scsi' is specified, connect SCSI"
-+				  " I/O EFI handles recursively."));
-+}
-+
-+GRUB_MOD_FINI(connectefi)
-+{
-+  grub_unregister_command (cmd);
-+}
-diff --git a/grub-core/commands/efi/lsefi.c b/grub-core/commands/efi/lsefi.c
-index d1ce99af438..f2d2430e666 100644
---- a/grub-core/commands/efi/lsefi.c
-+++ b/grub-core/commands/efi/lsefi.c
-@@ -19,6 +19,7 @@
- #include <grub/mm.h>
- #include <grub/misc.h>
- #include <grub/efi/api.h>
-+#include <grub/efi/disk.h>
- #include <grub/efi/edid.h>
- #include <grub/efi/pci.h>
- #include <grub/efi/efi.h>
-diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c
-index fe8ba6e6c93..062143dfffd 100644
---- a/grub-core/disk/efi/efidisk.c
-+++ b/grub-core/disk/efi/efidisk.c
-@@ -396,6 +396,19 @@ enumerate_disks (void)
-   free_devices (devices);
- }
- 
-+void
-+grub_efidisk_reenumerate_disks (void)
-+{
-+  free_devices (fd_devices);
-+  free_devices (hd_devices);
-+  free_devices (cd_devices);
-+  fd_devices = 0;
-+  hd_devices = 0;
-+  cd_devices = 0;
-+
-+  enumerate_disks ();
-+}
-+
- static int
- grub_efidisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
- 		      grub_disk_pull_t pull)
-diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
-index 14bc10eb564..7fcca69c17b 100644
---- a/grub-core/kern/efi/efi.c
-+++ b/grub-core/kern/efi/efi.c
-@@ -95,6 +95,19 @@ grub_efi_locate_handle (grub_efi_locate_search_type_t search_type,
-   return buffer;
- }
- 
-+grub_efi_status_t
-+grub_efi_connect_controller (grub_efi_handle_t controller_handle,
-+			     grub_efi_handle_t *driver_image_handle,
-+			     grub_efi_device_path_protocol_t *remaining_device_path,
-+			     grub_efi_boolean_t recursive)
-+{
-+  grub_efi_boot_services_t *b;
-+
-+  b = grub_efi_system_table->boot_services;
-+  return efi_call_4 (b->connect_controller, controller_handle,
-+		     driver_image_handle, remaining_device_path, recursive);
-+}
-+
- void *
- grub_efi_open_protocol (grub_efi_handle_t handle,
- 			grub_efi_guid_t *protocol,
-diff --git a/include/grub/efi/disk.h b/include/grub/efi/disk.h
-index 254475c8428..6845c2f1fd8 100644
---- a/include/grub/efi/disk.h
-+++ b/include/grub/efi/disk.h
-@@ -27,6 +27,8 @@ grub_efi_handle_t
- EXPORT_FUNC(grub_efidisk_get_device_handle) (grub_disk_t disk);
- char *EXPORT_FUNC(grub_efidisk_get_device_name) (grub_efi_handle_t *handle);
- 
-+void EXPORT_FUNC(grub_efidisk_reenumerate_disks) (void);
-+
- void grub_efidisk_init (void);
- void grub_efidisk_fini (void);
- 
-diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
-index 8dfc89a33b9..ec52083c49f 100644
---- a/include/grub/efi/efi.h
-+++ b/include/grub/efi/efi.h
-@@ -41,6 +41,11 @@ EXPORT_FUNC(grub_efi_locate_handle) (grub_efi_locate_search_type_t search_type,
- 				     grub_efi_guid_t *protocol,
- 				     void *search_key,
- 				     grub_efi_uintn_t *num_handles);
-+grub_efi_status_t
-+EXPORT_FUNC(grub_efi_connect_controller) (grub_efi_handle_t controller_handle,
-+					  grub_efi_handle_t *driver_image_handle,
-+					  grub_efi_device_path_protocol_t *remaining_device_path,
-+					  grub_efi_boolean_t recursive);
- void *EXPORT_FUNC(grub_efi_open_protocol) (grub_efi_handle_t handle,
- 					   grub_efi_guid_t *protocol,
- 					   grub_efi_uint32_t attributes);
-diff --git a/NEWS b/NEWS
-index 73b8492bc42..d7c1d23aed7 100644
---- a/NEWS
-+++ b/NEWS
-@@ -98,7 +98,7 @@ New in 2.02:
-   * Prefer pmtimer for TSC calibration.
- 
- * New/improved platform support:
--  * New `efifwsetup' and `lsefi' commands on EFI platforms.
-+  * New `efifwsetup', `lsefi' and `connectefi` commands on EFI platforms.
-   * New `cmosdump' and `cmosset' commands on platforms with CMOS support.
-   * New command `pcidump' for PCI platforms.
-   * Improve opcode parsing in ACPI halt implementation.
diff --git a/SOURCES/0227-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch b/SOURCES/0227-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch
new file mode 100644
index 0000000..199ec32
--- /dev/null
+++ b/SOURCES/0227-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 28 Jun 2021 14:16:58 +1000
+Subject: [PATCH] video/readers/jpeg: Do not reallocate a given huff table
+
+Fix a memory leak where an invalid file could cause us to reallocate
+memory for a huffman table we had already allocated memory for.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit bc06e12b4de55cc6f926af9f064170c82b1403e9)
+---
+ grub-core/video/readers/jpeg.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
+index 10225abd53..caa211f06d 100644
+--- a/grub-core/video/readers/jpeg.c
++++ b/grub-core/video/readers/jpeg.c
+@@ -245,6 +245,9 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data)
+ 	n += count[i];
+ 
+       id += ac * 2;
++      if (data->huff_value[id] != NULL)
++	return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++			   "jpeg: attempt to reallocate huffman table");
+       data->huff_value[id] = grub_malloc (n);
+       if (grub_errno)
+ 	return grub_errno;
diff --git a/SOURCES/0228-powerpc-do-CAS-in-a-more-compatible-way.patch b/SOURCES/0228-powerpc-do-CAS-in-a-more-compatible-way.patch
deleted file mode 100644
index 32c06b0..0000000
--- a/SOURCES/0228-powerpc-do-CAS-in-a-more-compatible-way.patch
+++ /dev/null
@@ -1,111 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Fri, 8 Apr 2022 12:35:28 +1000
-Subject: [PATCH] powerpc: do CAS in a more compatible way
-
-I wrongly assumed that the most compatible way to perform CAS
-negotiation was to only set the minimum number of vectors required
-to ask for more memory. It turns out that this messes up booting
-if the minimum VP capacity would be less than the default 10% in
-vector 4.
-
-Linux configures the minimum capacity to be 1%, so copy it for that
-and for vector 3 which we now need to specify as well.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-(cherry picked from commit e6f02ad4e75cd995a8ee2954d28949c415b6cbfe)
----
- grub-core/kern/ieee1275/init.c | 54 ++++++++++++++++++++++++------------------
- 1 file changed, 31 insertions(+), 23 deletions(-)
-
-diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
-index 9704715c83..ef55107467 100644
---- a/grub-core/kern/ieee1275/init.c
-+++ b/grub-core/kern/ieee1275/init.c
-@@ -298,33 +298,37 @@ grub_ieee1275_total_mem (grub_uint64_t *total)
- 
- /* Based on linux - arch/powerpc/kernel/prom_init.c */
- struct option_vector2 {
--	grub_uint8_t byte1;
--	grub_uint16_t reserved;
--	grub_uint32_t real_base;
--	grub_uint32_t real_size;
--	grub_uint32_t virt_base;
--	grub_uint32_t virt_size;
--	grub_uint32_t load_base;
--	grub_uint32_t min_rma;
--	grub_uint32_t min_load;
--	grub_uint8_t min_rma_percent;
--	grub_uint8_t max_pft_size;
-+  grub_uint8_t byte1;
-+  grub_uint16_t reserved;
-+  grub_uint32_t real_base;
-+  grub_uint32_t real_size;
-+  grub_uint32_t virt_base;
-+  grub_uint32_t virt_size;
-+  grub_uint32_t load_base;
-+  grub_uint32_t min_rma;
-+  grub_uint32_t min_load;
-+  grub_uint8_t min_rma_percent;
-+  grub_uint8_t max_pft_size;
- } __attribute__((packed));
- 
- struct pvr_entry {
--	  grub_uint32_t mask;
--	  grub_uint32_t entry;
-+  grub_uint32_t mask;
-+  grub_uint32_t entry;
- };
- 
- struct cas_vector {
--    struct {
--      struct pvr_entry terminal;
--    } pvr_list;
--    grub_uint8_t num_vecs;
--    grub_uint8_t vec1_size;
--    grub_uint8_t vec1;
--    grub_uint8_t vec2_size;
--    struct option_vector2 vec2;
-+  struct {
-+    struct pvr_entry terminal;
-+  } pvr_list;
-+  grub_uint8_t num_vecs;
-+  grub_uint8_t vec1_size;
-+  grub_uint8_t vec1;
-+  grub_uint8_t vec2_size;
-+  struct option_vector2 vec2;
-+  grub_uint8_t vec3_size;
-+  grub_uint16_t vec3;
-+  grub_uint8_t vec4_size;
-+  grub_uint16_t vec4;
- } __attribute__((packed));
- 
- /* Call ibm,client-architecture-support to try to get more RMA.
-@@ -345,13 +349,17 @@ grub_ieee1275_ibm_cas (void)
-   } args;
-   struct cas_vector vector = {
-     .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */
--    .num_vecs = 2 - 1,
-+    .num_vecs = 4 - 1,
-     .vec1_size = 0,
-     .vec1 = 0x80, /* ignore */
-     .vec2_size = 1 + sizeof(struct option_vector2) - 2,
-     .vec2 = {
-       0, 0, -1, -1, -1, -1, -1, 512, -1, 0, 48
-     },
-+    .vec3_size = 2 - 1,
-+    .vec3 = 0x00e0, // ask for FP + VMX + DFP but don't halt if unsatisfied
-+    .vec4_size = 2 - 1,
-+    .vec4 = 0x0001, // set required minimum capacity % to the lowest value
-   };
- 
-   INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2);
-@@ -364,7 +372,7 @@ grub_ieee1275_ibm_cas (void)
-   args.ihandle = root;
-   args.cas_addr = (grub_ieee1275_cell_t)&vector;
- 
--  grub_printf("Calling ibm,client-architecture-support...");
-+  grub_printf("Calling ibm,client-architecture-support from grub...");
-   IEEE1275_CALL_ENTRY_FN (&args);
-   grub_printf("done\n");
- 
diff --git a/SOURCES/0228-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch b/SOURCES/0228-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch
new file mode 100644
index 0000000..179238b
--- /dev/null
+++ b/SOURCES/0228-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch
@@ -0,0 +1,44 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 28 Jun 2021 14:25:17 +1000
+Subject: [PATCH] video/readers/jpeg: Refuse to handle multiple start of
+ streams
+
+An invalid file could contain multiple start of stream blocks, which
+would cause us to reallocate and leak our bitmap. Refuse to handle
+multiple start of streams.
+
+Additionally, fix a grub_error() call formatting.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit f3a854def3e281b7ad4bbea730cd3046de1da52f)
+---
+ grub-core/video/readers/jpeg.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
+index caa211f06d..1df1171d78 100644
+--- a/grub-core/video/readers/jpeg.c
++++ b/grub-core/video/readers/jpeg.c
+@@ -677,6 +677,9 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
+   if (data->file->offset != data_offset)
+     return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos");
+ 
++  if (*data->bitmap)
++    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many start of scan blocks");
++
+   if (grub_video_bitmap_create (data->bitmap, data->image_width,
+ 				data->image_height,
+ 				GRUB_VIDEO_BLIT_FORMAT_RGB_888))
+@@ -699,8 +702,8 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
+   nc1 = (data->image_width + hb - 1)  >> (3 + data->log_hs);
+ 
+   if (data->bitmap_ptr == NULL)
+-    return grub_error(GRUB_ERR_BAD_FILE_TYPE,
+-		      "jpeg: attempted to decode data before start of stream");
++    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		       "jpeg: attempted to decode data before start of stream");
+ 
+   for (; data->r1 < nr1 && (!data->dri || rst);
+        data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3)
diff --git a/SOURCES/0229-powerpc-prefix-detection-support-device-names-with-c.patch b/SOURCES/0229-powerpc-prefix-detection-support-device-names-with-c.patch
deleted file mode 100644
index a0aeb10..0000000
--- a/SOURCES/0229-powerpc-prefix-detection-support-device-names-with-c.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 24 Mar 2022 14:34:32 +1100
-Subject: [PATCH] powerpc: prefix detection: support device names with commas
-
-Frustratingly, the device name itself can contain an embedded comma:
-e.g /pci@800000020000015/pci1014,034A@0/sas/disk@5000c50098a0ee8b
-
-So my previous approach was wrong: we cannot rely upon the presence
-of a comma to say that a partition has been specified!
-
-It turns out for prefixes like (,gpt2)/grub2 we really want to make
-up a full (device,partition)/patch prefix, because root discovery code
-in 10_linux will reset the root variable and use search to fill it again.
-If you have run grub-install, you probably don't have search built in,
-and if you don't have prefix containing (device,partition), grub will
-construct ($root)$prefix/powerpc-ieee1275/search.mod - but because $root
-has just been changed, this will no longer work, and the boot will fail!
-
-Retain the gist of the logic, but instead of looking for a comma, look for
-a leading '('. This matches the earlier code better anyway.
-
-There's certainly a better fix to be had. But any time you chose to build
-with a bare prefix like '/grub2', you're almost certainly going to build in
-search anyway, so this will do.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-(cherry picked from commit 80b6eb5e55e6d1a4c9896361e61de31c29e6939d)
----
- grub-core/kern/main.c | 27 +++++++++++++++++++++------
- 1 file changed, 21 insertions(+), 6 deletions(-)
-
-diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
-index 2d0d2bbd4c..4c4e6912f9 100644
---- a/grub-core/kern/main.c
-+++ b/grub-core/kern/main.c
-@@ -242,14 +242,29 @@ grub_set_prefix_and_root (void)
- 	    what sorts of paths represent disks with partition tables and those
- 	    without partition tables.
- 
--	 So we act unless there is a comma in the device, which would indicate
--	 a partition has already been specified.
-+          - Frustratingly, the device name itself can contain an embedded comma:
-+            /pci@800000020000015/pci1014,034A@0/sas/disk@5000c50098a0ee8b
-+            So we cannot even rely upon the presence of a comma to say that a
-+            partition has been specified!
- 
--	 (If we only have a path, the code in normal to discover config files
--	 will try both without partitions and then with any partitions so we
--	 will cover both CDs and HDs.)
-+         If we only have a path in $prefix, the code in normal to discover
-+	 config files will try all disks, both without partitions and then with
-+	 any partitions so we will cover both CDs and HDs.
-+
-+         However, it doesn't then set the prefix to be something like
-+         (discovered partition)/path, and so it is fragile against runtime
-+         changes to $root. For example some of the stuff done in 10_linux to
-+         reload $root sets root differently and then uses search to find it
-+         again. If the search module is not built in, when we change root, grub
-+         will look in (new root)/path/powerpc-ieee1275, that won't work, and we
-+         will not be able to load the search module and the boot will fail.
-+
-+         This is particularly likely to hit us in the grub-install
-+         (,msdos2)/grub2 case, so we act unless the supplied prefix starts with
-+         '(', which would likely indicate a partition has already been
-+         specified.
-        */
--      if (grub_strchr (device, ',') == NULL)
-+      if (prefix && prefix[0] != '(')
-         grub_env_set ("prefix", path);
-       else
- #endif
diff --git a/SOURCES/0229-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch b/SOURCES/0229-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch
new file mode 100644
index 0000000..99eeb62
--- /dev/null
+++ b/SOURCES/0229-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch
@@ -0,0 +1,53 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Wed, 7 Jul 2021 15:38:19 +1000
+Subject: [PATCH] video/readers/jpeg: Block int underflow -> wild pointer write
+
+Certain 1 px wide images caused a wild pointer write in
+grub_jpeg_ycrcb_to_rgb(). This was caused because in grub_jpeg_decode_data(),
+we have the following loop:
+
+for (; data->r1 < nr1 && (!data->dri || rst);
+     data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3)
+
+We did not check if vb * width >= hb * nc1.
+
+On a 64-bit platform, if that turns out to be negative, it will underflow,
+be interpreted as unsigned 64-bit, then be added to the 64-bit pointer, so
+we see data->bitmap_ptr jump, e.g.:
+
+0x6180_0000_0480 to
+0x6181_0000_0498
+     ^
+     ~--- carry has occurred and this pointer is now far away from
+          any object.
+
+On a 32-bit platform, it will decrement the pointer, creating a pointer
+that won't crash but will overwrite random data.
+
+Catch the underflow and error out.
+
+Fixes: CVE-2021-3697
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 41aeb2004db9924fecd9f2dd64bc2a5a5594a4b5)
+---
+ grub-core/video/readers/jpeg.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
+index 1df1171d78..2da04094b3 100644
+--- a/grub-core/video/readers/jpeg.c
++++ b/grub-core/video/readers/jpeg.c
+@@ -705,6 +705,10 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
+     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ 		       "jpeg: attempted to decode data before start of stream");
+ 
++  if (vb * data->image_width <= hb * nc1)
++    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
++		       "jpeg: cannot decode image with these dimensions");
++
+   for (; data->r1 < nr1 && (!data->dri || rst);
+        data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3)
+     for (c1 = 0;  c1 < nc1 && (!data->dri || rst);
diff --git a/SOURCES/0230-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch b/SOURCES/0230-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch
deleted file mode 100644
index 00cf0f7..0000000
--- a/SOURCES/0230-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch
+++ /dev/null
@@ -1,237 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Stefan Berger <stefanb@linux.ibm.com>
-Date: Sun, 15 Mar 2020 12:37:10 -0400
-Subject: [PATCH] ibmvtpm: Add support for trusted boot using a vTPM 2.0
-
-Add support for trusted boot using a vTPM 2.0 on the IBM IEEE1275
-PowerPC platform. With this patch grub now measures text and binary data
-into the TPM's PCRs 8 and 9 in the same way as the x86_64 platform
-does.
-
-This patch requires Daniel Axtens's patches for claiming more memory.
-
-For vTPM support to work on PowerVM, system driver levels 1010.30
-or 1020.00 are required.
-
-Note: Previous versions of firmware levels with the 2hash-ext-log
-API call have a bug that, once this API call is invoked, has the
-effect of disabling the vTPM driver under Linux causing an error
-message to be displayed in the Linux kernel log. Those users will
-have to update their machines to the firmware levels mentioned
-above.
-
-Cc: Eric Snowberg <eric.snowberg@oracle.com>
-Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
-(cherry picked from commit d3e5a8e6ecb8b87701135d97f45d27bbfbf731a2)
----
- grub-core/Makefile.core.def           |   7 ++
- grub-core/commands/ieee1275/ibmvtpm.c | 152 ++++++++++++++++++++++++++++++++++
- include/grub/ieee1275/ieee1275.h      |   3 +
- docs/grub.texi                        |   3 +-
- 4 files changed, 164 insertions(+), 1 deletion(-)
- create mode 100644 grub-core/commands/ieee1275/ibmvtpm.c
-
-diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index 97abc01f06..407d68f917 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -1172,6 +1172,13 @@ module = {
-   enable = powerpc_ieee1275;
- };
- 
-+module = {
-+  name = tpm;
-+  common = commands/tpm.c;
-+  ieee1275 = commands/ieee1275/ibmvtpm.c;
-+  enable = powerpc_ieee1275;
-+};
-+
- module = {
-   name = terminal;
-   common = commands/terminal.c;
-diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c
-new file mode 100644
-index 0000000000..e68b8448bc
---- /dev/null
-+++ b/grub-core/commands/ieee1275/ibmvtpm.c
-@@ -0,0 +1,152 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2021  Free Software Foundation, Inc.
-+ *  Copyright (C) 2021  IBM Corporation
-+ *
-+ *  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/>.
-+ *
-+ *  IBM vTPM support code.
-+ */
-+
-+#include <grub/err.h>
-+#include <grub/types.h>
-+#include <grub/tpm.h>
-+#include <grub/ieee1275/ieee1275.h>
-+#include <grub/mm.h>
-+#include <grub/misc.h>
-+
-+static grub_ieee1275_ihandle_t tpm_ihandle;
-+static grub_uint8_t tpm_version;
-+
-+#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t)0)
-+
-+static void
-+tpm_get_tpm_version (void)
-+{
-+  grub_ieee1275_phandle_t vtpm;
-+  char buffer[20];
-+
-+  if (!grub_ieee1275_finddevice ("/vdevice/vtpm", &vtpm) &&
-+      !grub_ieee1275_get_property (vtpm, "compatible", buffer,
-+				   sizeof (buffer), NULL) &&
-+      !grub_strcmp (buffer, "IBM,vtpm20"))
-+    tpm_version = 2;
-+}
-+
-+static grub_err_t
-+tpm_init (void)
-+{
-+  static int init_success = 0;
-+
-+  if (!init_success)
-+    {
-+      if (grub_ieee1275_open ("/vdevice/vtpm", &tpm_ihandle) < 0) {
-+        tpm_ihandle = IEEE1275_IHANDLE_INVALID;
-+        return GRUB_ERR_UNKNOWN_DEVICE;
-+      }
-+
-+      init_success = 1;
-+
-+      tpm_get_tpm_version ();
-+    }
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+static int
-+ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
-+		       grub_uint32_t eventtype,
-+		       const char *description,
-+		       grub_size_t description_size,
-+		       void *buf, grub_size_t size)
-+{
-+  struct tpm_2hash_ext_log
-+  {
-+    struct grub_ieee1275_common_hdr common;
-+    grub_ieee1275_cell_t method;
-+    grub_ieee1275_cell_t ihandle;
-+    grub_ieee1275_cell_t size;
-+    grub_ieee1275_cell_t buf;
-+    grub_ieee1275_cell_t description_size;
-+    grub_ieee1275_cell_t description;
-+    grub_ieee1275_cell_t eventtype;
-+    grub_ieee1275_cell_t pcrindex;
-+    grub_ieee1275_cell_t catch_result;
-+    grub_ieee1275_cell_t rc;
-+  }
-+  args;
-+
-+  INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2);
-+  args.method = (grub_ieee1275_cell_t) "2hash-ext-log";
-+  args.ihandle = tpm_ihandle;
-+  args.pcrindex = pcrindex;
-+  args.eventtype = eventtype;
-+  args.description = (grub_ieee1275_cell_t) description;
-+  args.description_size = description_size;
-+  args.buf = (grub_ieee1275_cell_t) buf;
-+  args.size = (grub_ieee1275_cell_t) size;
-+
-+  if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
-+    return -1;
-+
-+  /*
-+   * catch_result is set if firmware does not support 2hash-ext-log
-+   * rc is GRUB_IEEE1275_CELL_FALSE (0) on failure
-+   */
-+  if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE)
-+    return -1;
-+
-+  return 0;
-+}
-+
-+static grub_err_t
-+tpm2_log_event (unsigned char *buf,
-+		grub_size_t size, grub_uint8_t pcr,
-+		const char *description)
-+{
-+  static int error_displayed = 0;
-+  int err;
-+
-+  err = ibmvtpm_2hash_ext_log (pcr, EV_IPL,
-+			       description,
-+			       grub_strlen(description) + 1,
-+			       buf, size);
-+  if (err && !error_displayed)
-+    {
-+      error_displayed++;
-+      return grub_error (GRUB_ERR_BAD_DEVICE,
-+	      "2HASH-EXT-LOG failed: Firmware is likely too old.\n");
-+    }
-+
-+  return GRUB_ERR_NONE;
-+}
-+
-+grub_err_t
-+grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
-+		  const char *description)
-+{
-+  grub_err_t err = tpm_init();
-+
-+  /* Absence of a TPM isn't a failure. */
-+  if (err != GRUB_ERR_NONE)
-+    return GRUB_ERR_NONE;
-+
-+  grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n",
-+		pcr, size, description);
-+
-+  if (tpm_version == 2)
-+    return tpm2_log_event (buf, size, pcr, description);
-+
-+  return GRUB_ERR_NONE;
-+}
-diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
-index e0a6c2ce1e..f4c85265fe 100644
---- a/include/grub/ieee1275/ieee1275.h
-+++ b/include/grub/ieee1275/ieee1275.h
-@@ -24,6 +24,9 @@
- #include <grub/types.h>
- #include <grub/machine/ieee1275.h>
- 
-+#define GRUB_IEEE1275_CELL_FALSE       ((grub_ieee1275_cell_t) 0)
-+#define GRUB_IEEE1275_CELL_TRUE        ((grub_ieee1275_cell_t) -1)
-+
- struct grub_ieee1275_mem_region
- {
-   unsigned int start;
-diff --git a/docs/grub.texi b/docs/grub.texi
-index a4da9c2a1b..c433240f34 100644
---- a/docs/grub.texi
-+++ b/docs/grub.texi
-@@ -6221,7 +6221,8 @@ tpm module is loaded. As such it is recommended that the tpm module be built
- into @file{core.img} in order to avoid a potential gap in measurement between
- @file{core.img} being loaded and the tpm module being loaded.
- 
--Measured boot is currently only supported on EFI platforms.
-+Measured boot is currently only supported on EFI and IBM IEEE1275 PowerPC
-+platforms.
- 
- @node Lockdown
- @section Lockdown when booting on a secure setup
diff --git a/SOURCES/0230-normal-charset-Fix-array-out-of-bounds-formatting-un.patch b/SOURCES/0230-normal-charset-Fix-array-out-of-bounds-formatting-un.patch
new file mode 100644
index 0000000..6e64ed8
--- /dev/null
+++ b/SOURCES/0230-normal-charset-Fix-array-out-of-bounds-formatting-un.patch
@@ -0,0 +1,34 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 13 Jul 2021 13:24:38 +1000
+Subject: [PATCH] normal/charset: Fix array out-of-bounds formatting unicode
+ for display
+
+In some cases attempting to display arbitrary binary strings leads
+to ASAN splats reading the widthspec array out of bounds.
+
+Check the index. If it would be out of bounds, return a width of 1.
+I don't know if that's strictly correct, but we're not really expecting
+great display of arbitrary binary data, and it's certainly not worse than
+an OOB read.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit fdf32abc7a3928852422c0f291d8cd1dd6b34a8d)
+---
+ grub-core/normal/charset.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c
+index 4dfcc31078..7a5a7c153c 100644
+--- a/grub-core/normal/charset.c
++++ b/grub-core/normal/charset.c
+@@ -395,6 +395,8 @@ grub_unicode_estimate_width (const struct grub_unicode_glyph *c)
+ {
+   if (grub_unicode_get_comb_type (c->base))
+     return 0;
++  if (((unsigned long) (c->base >> 3)) >= ARRAY_SIZE (widthspec))
++    return 1;
+   if (widthspec[c->base >> 3] & (1 << (c->base & 7)))
+     return 2;
+   else
diff --git a/SOURCES/0231-make-ofdisk_retries-optional.patch b/SOURCES/0231-make-ofdisk_retries-optional.patch
deleted file mode 100644
index ac0bb44..0000000
--- a/SOURCES/0231-make-ofdisk_retries-optional.patch
+++ /dev/null
@@ -1,45 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Diego Domingos <diegdo@br.ibm.com>
-Date: Thu, 24 Mar 2022 13:14:42 -0400
-Subject: [PATCH] make ofdisk_retries optional
-
-The feature Retry on Fail added to GRUB can cause a LPM to take
-longer if the SAN is slow.
-
-When a LPM to external site occur, the path of the disk can change
-and thus the disk search function on grub can take some time since
-it is used as a hint. This can cause the Retry on Fail feature to
-try to access the disk 20x times (since this is hardcoded number)
-and, if the SAN is slow, the boot time can increase a lot.
-In some situations not acceptable.
-
-The following patch enables a configuration at user space of the
-maximum number of retries we want for this feature.
-
-The variable ofdisk_retries should be set using grub2-editenv
-and will be checked by retry function. If the variable is not set,
-so the default number of retries will be used instead.
-
-(cherry picked from commit 4c5c7563f45a6410667ca08bcbfac4ab79d7de31)
----
- include/grub/ieee1275/ofdisk.h | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/include/grub/ieee1275/ofdisk.h b/include/grub/ieee1275/ofdisk.h
-index 7d2d540930..0074d55eee 100644
---- a/include/grub/ieee1275/ofdisk.h
-+++ b/include/grub/ieee1275/ofdisk.h
-@@ -25,7 +25,12 @@ extern void grub_ofdisk_fini (void);
- #define MAX_RETRIES 20
- 
- 
--#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) unsigned retry_i=0;for(retry_i=0; retry_i < MAX_RETRIES; retry_i++){ \
-+#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) \
-+	                                        unsigned max_retries = MAX_RETRIES; \
-+                                                if(grub_env_get("ofdisk_retries") != NULL) \
-+                                                     max_retries = grub_strtoul(grub_env_get("ofdisk_retries"), 0, 10)+1; \
-+                                                grub_dprintf("ofdisk","MAX_RETRIES set to %u\n",max_retries); \
-+                                                unsigned retry_i=0;for(retry_i=0; retry_i < max_retries; retry_i++){ \
- 						if(!grub_ieee1275_open(device, last_ihandle)) \
- 						break; \
- 						grub_dprintf("ofdisk","Opening disk %s failed. Retrying...\n",device); }
diff --git a/SOURCES/0231-net-netbuff-Block-overly-large-netbuff-allocs.patch b/SOURCES/0231-net-netbuff-Block-overly-large-netbuff-allocs.patch
new file mode 100644
index 0000000..2e10d49
--- /dev/null
+++ b/SOURCES/0231-net-netbuff-Block-overly-large-netbuff-allocs.patch
@@ -0,0 +1,46 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 8 Mar 2022 23:47:46 +1100
+Subject: [PATCH] net/netbuff: Block overly large netbuff allocs
+
+A netbuff shouldn't be too huge. It's bounded by MTU and TCP segment
+reassembly.
+
+This helps avoid some bugs (and provides a spot to instrument to catch
+them at their source).
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit ee9591103004cd13b4efadda671536090ca7fd57)
+---
+ grub-core/net/netbuff.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/grub-core/net/netbuff.c b/grub-core/net/netbuff.c
+index dbeeefe478..d5e9e9a0d7 100644
+--- a/grub-core/net/netbuff.c
++++ b/grub-core/net/netbuff.c
+@@ -79,10 +79,23 @@ grub_netbuff_alloc (grub_size_t len)
+ 
+   COMPILE_TIME_ASSERT (NETBUFF_ALIGN % sizeof (grub_properly_aligned_t) == 0);
+ 
++  /*
++   * The largest size of a TCP packet is 64 KiB, and everything else
++   * should be a lot smaller - most MTUs are 1500 or less. Cap data
++   * size at 64 KiB + a buffer.
++   */
++  if (len > 0xffffUL + 0x1000UL)
++    {
++      grub_error (GRUB_ERR_BUG,
++                  "attempted to allocate a packet that is too big");
++      return NULL;
++    }
++
+   if (len < NETBUFFMINLEN)
+     len = NETBUFFMINLEN;
+ 
+   len = ALIGN_UP (len, NETBUFF_ALIGN);
++
+ #ifdef GRUB_MACHINE_EMU
+   data = grub_malloc (len + sizeof (*nb));
+ #else
diff --git a/SOURCES/0232-loader-efi-chainloader-grub_load_and_start_image-doe.patch b/SOURCES/0232-loader-efi-chainloader-grub_load_and_start_image-doe.patch
deleted file mode 100644
index 3fcd8e4..0000000
--- a/SOURCES/0232-loader-efi-chainloader-grub_load_and_start_image-doe.patch
+++ /dev/null
@@ -1,70 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Chris Coulson <chris.coulson@canonical.com>
-Date: Thu, 28 Apr 2022 21:53:36 +0100
-Subject: [PATCH] loader/efi/chainloader: grub_load_and_start_image doesn't
- load and start
-
-grub_load_and_start_image only loads an image - it still requires the
-caller to start it. This renames it to grub_load_image.
-
-It's called from 2 places:
-- grub_cmd_chainloader when not using the shim protocol.
-- grub_secureboot_chainloader_boot if handle_image returns an error.
-In this case, the image is loaded and then nothing else happens which
-seems strange. I assume the intention is that it falls back to LoadImage
-and StartImage if handle_image fails, so I've made it do that.
-
-Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
-(cherry picked from commit b4d70820a65c00561045856b7b8355461a9545f6)
-(cherry picked from commit 05b16a6be50b1910609740a66b561276fa490538)
----
- grub-core/loader/efi/chainloader.c | 16 +++++++++++++---
- 1 file changed, 13 insertions(+), 3 deletions(-)
-
-diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
-index 3af6b12292..39158e679e 100644
---- a/grub-core/loader/efi/chainloader.c
-+++ b/grub-core/loader/efi/chainloader.c
-@@ -841,7 +841,7 @@ grub_secureboot_chainloader_unload (void)
- }
- 
- static grub_err_t
--grub_load_and_start_image(void *boot_image)
-+grub_load_image(void *boot_image)
- {
-   grub_efi_boot_services_t *b;
-   grub_efi_status_t status;
-@@ -883,13 +883,23 @@ grub_load_and_start_image(void *boot_image)
- static grub_err_t
- grub_secureboot_chainloader_boot (void)
- {
-+  grub_efi_boot_services_t *b;
-   int rc;
-+
-   rc = handle_image ((void *)(unsigned long)address, fsize);
-   if (rc == 0)
-     {
--      grub_load_and_start_image((void *)(unsigned long)address);
-+      /* We weren't able to attempt to execute the image, so fall back
-+       * to LoadImage / StartImage.
-+       */
-+      rc = grub_load_image((void *)(unsigned long)address);
-+      if (rc == 0)
-+        grub_chainloader_boot ();
-     }
- 
-+  b = grub_efi_system_table->boot_services;
-+  efi_call_1 (b->unload_image, image_handle);
-+
-   grub_loader_unset ();
-   return grub_errno;
- }
-@@ -1094,7 +1104,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
-     }
-   else if (rc == 0)
-     {
--      grub_load_and_start_image(boot_image);
-+      grub_load_image(boot_image);
-       grub_file_close (file);
-       grub_device_close (dev);
-       grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
diff --git a/SOURCES/0232-net-ip-Do-IP-fragment-maths-safely.patch b/SOURCES/0232-net-ip-Do-IP-fragment-maths-safely.patch
new file mode 100644
index 0000000..118448d
--- /dev/null
+++ b/SOURCES/0232-net-ip-Do-IP-fragment-maths-safely.patch
@@ -0,0 +1,44 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 20 Dec 2021 19:41:21 +1100
+Subject: [PATCH] net/ip: Do IP fragment maths safely
+
+This avoids an underflow and subsequent unpleasantness.
+
+Fixes: CVE-2022-28733
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit eb74e5743ca7e18a5e75c392fe0b21d1549a1936)
+---
+ grub-core/net/ip.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
+index ce6bdc75c6..cf74f1f794 100644
+--- a/grub-core/net/ip.c
++++ b/grub-core/net/ip.c
+@@ -25,6 +25,7 @@
+ #include <grub/net/netbuff.h>
+ #include <grub/mm.h>
+ #include <grub/priority_queue.h>
++#include <grub/safemath.h>
+ #include <grub/time.h>
+ 
+ struct iphdr {
+@@ -551,7 +552,14 @@ grub_net_recv_ip4_packets (struct grub_net_buff *nb,
+     {
+       rsm->total_len = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK)
+ 			+ (nb->tail - nb->data));
+-      rsm->total_len -= ((iph->verhdrlen & 0xf) * sizeof (grub_uint32_t));
++
++      if (grub_sub (rsm->total_len, (iph->verhdrlen & 0xf) * sizeof (grub_uint32_t),
++		    &rsm->total_len))
++	{
++	  grub_dprintf ("net", "IP reassembly size underflow\n");
++	  return GRUB_ERR_NONE;
++	}
++
+       rsm->asm_netbuff = grub_netbuff_alloc (rsm->total_len);
+       if (!rsm->asm_netbuff)
+ 	{
diff --git a/SOURCES/0233-loader-efi-chainloader-simplify-the-loader-state.patch b/SOURCES/0233-loader-efi-chainloader-simplify-the-loader-state.patch
deleted file mode 100644
index 76c3d58..0000000
--- a/SOURCES/0233-loader-efi-chainloader-simplify-the-loader-state.patch
+++ /dev/null
@@ -1,332 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Chris Coulson <chris.coulson@canonical.com>
-Date: Fri, 29 Apr 2022 21:13:08 +0100
-Subject: [PATCH] loader/efi/chainloader: simplify the loader state
-
-When not using the shim lock protocol, the chainloader command retains
-the source buffer and device path passed to LoadImage, requiring the
-unload hook passed to grub_loader_set to free them. It isn't required
-to retain this state though - they aren't required by StartImage or
-anything else in the boot hook, so clean them up before
-grub_cmd_chainloader finishes.
-
-This also wraps the loader state when using the shim lock protocol
-inside a struct.
-
-Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
-(cherry picked from commit fa39862933b3be1553a580a3a5c28073257d8046)
-(cherry picked from commit 0333343ee99c4e88f062789263c94291c057251b)
-[rharwood: double-frees and uninitialized, verifying twice]
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
----
- grub-core/loader/efi/chainloader.c | 160 +++++++++++++++++++++++--------------
- 1 file changed, 102 insertions(+), 58 deletions(-)
-
-diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
-index 39158e679e..0717ce0478 100644
---- a/grub-core/loader/efi/chainloader.c
-+++ b/grub-core/loader/efi/chainloader.c
-@@ -48,38 +48,21 @@ GRUB_MOD_LICENSE ("GPLv3+");
- 
- static grub_dl_t my_mod;
- 
--static grub_efi_physical_address_t address;
--static grub_efi_uintn_t pages;
--static grub_ssize_t fsize;
--static grub_efi_device_path_t *file_path;
- static grub_efi_handle_t image_handle;
--static grub_efi_char16_t *cmdline;
--static grub_ssize_t cmdline_len;
--static grub_efi_handle_t dev_handle;
- 
--static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table);
-+struct grub_secureboot_chainloader_context {
-+  grub_efi_physical_address_t address;
-+  grub_efi_uintn_t pages;
-+  grub_ssize_t fsize;
-+  grub_efi_device_path_t *file_path;
-+  grub_efi_char16_t *cmdline;
-+  grub_ssize_t cmdline_len;
-+  grub_efi_handle_t dev_handle;
-+};
-+static struct grub_secureboot_chainloader_context *sb_context;
- 
- static grub_err_t
--grub_chainloader_unload (void)
--{
--  grub_efi_boot_services_t *b;
--
--  b = grub_efi_system_table->boot_services;
--  efi_call_1 (b->unload_image, image_handle);
--  grub_efi_free_pages (address, pages);
--
--  grub_free (file_path);
--  grub_free (cmdline);
--  cmdline = 0;
--  file_path = 0;
--  dev_handle = 0;
--
--  grub_dl_unref (my_mod);
--  return GRUB_ERR_NONE;
--}
--
--static grub_err_t
--grub_chainloader_boot (void)
-+grub_start_image (grub_efi_handle_t handle)
- {
-   grub_efi_boot_services_t *b;
-   grub_efi_status_t status;
-@@ -87,7 +70,7 @@ grub_chainloader_boot (void)
-   grub_efi_char16_t *exit_data = NULL;
- 
-   b = grub_efi_system_table->boot_services;
--  status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data);
-+  status = efi_call_3 (b->start_image, handle, &exit_data_size, &exit_data);
-   if (status != GRUB_EFI_SUCCESS)
-     {
-       if (exit_data)
-@@ -111,11 +94,37 @@ grub_chainloader_boot (void)
-   if (exit_data)
-     grub_efi_free_pool (exit_data);
- 
--  grub_loader_unset ();
--
-   return grub_errno;
- }
- 
-+static grub_err_t
-+grub_chainloader_unload (void)
-+{
-+  grub_efi_loaded_image_t *loaded_image;
-+  grub_efi_boot_services_t *b;
-+
-+  loaded_image = grub_efi_get_loaded_image (image_handle);
-+  if (loaded_image != NULL)
-+    grub_free (loaded_image->load_options);
-+
-+  b = grub_efi_system_table->boot_services;
-+  efi_call_1 (b->unload_image, image_handle);
-+
-+  grub_dl_unref (my_mod);
-+  return GRUB_ERR_NONE;
-+}
-+
-+static grub_err_t
-+grub_chainloader_boot (void)
-+{
-+  grub_err_t err;
-+
-+  err = grub_start_image (image_handle);
-+
-+  grub_loader_unset ();
-+  return err;
-+}
-+
- static grub_err_t
- copy_file_path (grub_efi_file_path_device_path_t *fp,
- 		const char *str, grub_efi_uint16_t len)
-@@ -150,7 +159,7 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
-   char *dir_start;
-   char *dir_end;
-   grub_size_t size;
--  grub_efi_device_path_t *d;
-+  grub_efi_device_path_t *d, *file_path;
- 
-   dir_start = grub_strchr (filename, ')');
-   if (! dir_start)
-@@ -526,10 +535,12 @@ grub_efi_get_media_file_path (grub_efi_device_path_t *dp)
- }
- 
- static grub_efi_boolean_t
--handle_image (void *data, grub_efi_uint32_t datasize)
-+handle_image (struct grub_secureboot_chainloader_context *load_context)
- {
-   grub_efi_loaded_image_t *li, li_bak;
-   grub_efi_status_t efi_status;
-+  void *data = (void *)(unsigned long)load_context->address;
-+  grub_efi_uint32_t datasize = load_context->fsize;
-   void *buffer = NULL;
-   char *buffer_aligned = NULL;
-   grub_efi_uint32_t i;
-@@ -540,6 +551,7 @@ handle_image (void *data, grub_efi_uint32_t datasize)
-   grub_uint32_t buffer_size;
-   int found_entry_point = 0;
-   int rc;
-+  grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table);
- 
-   rc = read_header (data, datasize, &context);
-   if (rc < 0)
-@@ -797,10 +809,10 @@ handle_image (void *data, grub_efi_uint32_t datasize)
-   grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t));
-   li->image_base = buffer_aligned;
-   li->image_size = context.image_size;
--  li->load_options = cmdline;
--  li->load_options_size = cmdline_len;
--  li->file_path = grub_efi_get_media_file_path (file_path);
--  li->device_handle = dev_handle;
-+  li->load_options = load_context->cmdline;
-+  li->load_options_size = load_context->cmdline_len;
-+  li->file_path = grub_efi_get_media_file_path (load_context->file_path);
-+  li->device_handle = load_context->dev_handle;
-   if (!li->file_path)
-     {
-       grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file path found");
-@@ -829,19 +841,22 @@ error_exit:
- static grub_err_t
- grub_secureboot_chainloader_unload (void)
- {
--  grub_efi_free_pages (address, pages);
--  grub_free (file_path);
--  grub_free (cmdline);
--  cmdline = 0;
--  file_path = 0;
--  dev_handle = 0;
-+  grub_efi_free_pages (sb_context->address, sb_context->pages);
-+  grub_free (sb_context->file_path);
-+  grub_free (sb_context->cmdline);
-+  grub_free (sb_context);
-+
-+  sb_context = 0;
- 
-   grub_dl_unref (my_mod);
-   return GRUB_ERR_NONE;
- }
- 
- static grub_err_t
--grub_load_image(void *boot_image)
-+grub_load_image(grub_efi_device_path_t *file_path, void *boot_image,
-+		grub_efi_uintn_t image_size, grub_efi_handle_t dev_handle,
-+		grub_efi_char16_t *cmdline, grub_ssize_t cmdline_len,
-+		grub_efi_handle_t *image_handle_out)
- {
-   grub_efi_boot_services_t *b;
-   grub_efi_status_t status;
-@@ -850,7 +865,7 @@ grub_load_image(void *boot_image)
-   b = grub_efi_system_table->boot_services;
- 
-   status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
--		       boot_image, fsize, &image_handle);
-+		       boot_image, image_size, image_handle_out);
-   if (status != GRUB_EFI_SUCCESS)
-     {
-       if (status == GRUB_EFI_OUT_OF_RESOURCES)
-@@ -863,7 +878,7 @@ grub_load_image(void *boot_image)
-   /* LoadImage does not set a device handler when the image is
-      loaded from memory, so it is necessary to set it explicitly here.
-      This is a mess.  */
--  loaded_image = grub_efi_get_loaded_image (image_handle);
-+  loaded_image = grub_efi_get_loaded_image (*image_handle_out);
-   if (! loaded_image)
-     {
-       grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
-@@ -885,20 +900,25 @@ grub_secureboot_chainloader_boot (void)
- {
-   grub_efi_boot_services_t *b;
-   int rc;
-+  grub_efi_handle_t handle = 0;
- 
--  rc = handle_image ((void *)(unsigned long)address, fsize);
-+  rc = handle_image (sb_context);
-   if (rc == 0)
-     {
-       /* We weren't able to attempt to execute the image, so fall back
-        * to LoadImage / StartImage.
-        */
--      rc = grub_load_image((void *)(unsigned long)address);
-+      rc = grub_load_image(sb_context->file_path,
-+			   (void *)(unsigned long)sb_context->address,
-+			   sb_context->fsize, sb_context->dev_handle,
-+			   sb_context->cmdline, sb_context->cmdline_len,
-+			   &handle);
-       if (rc == 0)
--        grub_chainloader_boot ();
-+	grub_start_image (handle);
-     }
- 
-   b = grub_efi_system_table->boot_services;
--  efi_call_1 (b->unload_image, image_handle);
-+  efi_call_1 (b->unload_image, handle);
- 
-   grub_loader_unset ();
-   return grub_errno;
-@@ -913,10 +933,16 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
-   grub_efi_boot_services_t *b;
-   grub_device_t dev = 0;
-   grub_device_t orig_dev = 0;
--  grub_efi_device_path_t *dp = 0;
-+  grub_efi_device_path_t *dp = 0, *file_path = 0;
-   char *filename;
-   void *boot_image = 0;
-   int rc;
-+  grub_efi_physical_address_t address = 0;
-+  grub_ssize_t fsize;
-+  grub_efi_uintn_t pages = 0;
-+  grub_efi_char16_t *cmdline = 0;
-+  grub_ssize_t cmdline_len = 0;
-+  grub_efi_handle_t dev_handle = 0;
- 
-   if (argc == 0)
-     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
-@@ -924,12 +950,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
- 
-   grub_dl_ref (my_mod);
- 
--  /* Initialize some global variables.  */
--  address = 0;
--  image_handle = 0;
--  file_path = 0;
--  dev_handle = 0;
--
-   b = grub_efi_system_table->boot_services;
- 
-   if (argc > 1)
-@@ -1096,17 +1116,35 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
-   grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc);
-   if (rc > 0)
-     {
-+      sb_context = grub_malloc (sizeof (*sb_context));
-+      if (sb_context == NULL)
-+        goto fail;
-+      sb_context->address = address;
-+      sb_context->fsize = fsize;
-+      sb_context->pages = pages;
-+      sb_context->file_path = file_path;
-+      sb_context->cmdline = cmdline;
-+      sb_context->cmdline_len = cmdline_len;
-+      sb_context->dev_handle = dev_handle;
-+
-       grub_file_close (file);
-       grub_device_close (dev);
-+
-       grub_loader_set (grub_secureboot_chainloader_boot,
- 		       grub_secureboot_chainloader_unload, 0);
-       return 0;
-     }
-   else if (rc == 0)
-     {
--      grub_load_image(boot_image);
-+      grub_load_image(file_path, boot_image, fsize, dev_handle, cmdline,
-+		      cmdline_len, &image_handle);
-       grub_file_close (file);
-       grub_device_close (dev);
-+
-+      /* We're finished with the source image buffer and file path now */
-+      efi_call_2 (b->free_pages, address, pages);
-+      grub_free (file_path);
-+
-       grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
- 
-       return 0;
-@@ -1134,6 +1172,12 @@ fail:
-   if (cmdline)
-     grub_free (cmdline);
- 
-+  if (image_handle != 0)
-+    {
-+      efi_call_1 (b->unload_image, image_handle);
-+      image_handle = 0;
-+    }
-+
-   grub_dl_unref (my_mod);
- 
-   return grub_errno;
diff --git a/SOURCES/0233-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch b/SOURCES/0233-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch
new file mode 100644
index 0000000..19701b6
--- /dev/null
+++ b/SOURCES/0233-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch
@@ -0,0 +1,56 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 16 Sep 2021 01:29:54 +1000
+Subject: [PATCH] net/dns: Fix double-free addresses on corrupt DNS response
+
+grub_net_dns_lookup() takes as inputs a pointer to an array of addresses
+("addresses") for the given name, and pointer to a number of addresses
+("naddresses"). grub_net_dns_lookup() is responsible for allocating
+"addresses", and the caller is responsible for freeing it if
+"naddresses" > 0.
+
+The DNS recv_hook will sometimes set and free the addresses array,
+for example if the packet is too short:
+
+      if (ptr + 10 >= nb->tail)
+	{
+	  if (!*data->naddresses)
+	    grub_free (*data->addresses);
+	  grub_netbuff_free (nb);
+	  return GRUB_ERR_NONE;
+	}
+
+Later on the nslookup command code unconditionally frees the "addresses"
+array. Normally this is fine: the array is either populated with valid
+data or is NULL. But in these sorts of error cases it is neither NULL
+nor valid and we get a double-free.
+
+Only free "addresses" if "naddresses" > 0.
+
+It looks like the other use of grub_net_dns_lookup() is not affected.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit eb2e69fcf51307757e43f55ee8c9354d1ee42dd1)
+---
+ grub-core/net/dns.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c
+index 906ec7d678..135faac035 100644
+--- a/grub-core/net/dns.c
++++ b/grub-core/net/dns.c
+@@ -667,9 +667,11 @@ grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)),
+       grub_net_addr_to_str (&addresses[i], buf);
+       grub_printf ("%s\n", buf);
+     }
+-  grub_free (addresses);
+   if (naddresses)
+-    return GRUB_ERR_NONE;
++    {
++      grub_free (addresses);
++      return GRUB_ERR_NONE;
++    }
+   return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found"));
+ }
+ 
diff --git a/SOURCES/0234-commands-boot-Add-API-to-pass-context-to-loader.patch b/SOURCES/0234-commands-boot-Add-API-to-pass-context-to-loader.patch
deleted file mode 100644
index 65aac76..0000000
--- a/SOURCES/0234-commands-boot-Add-API-to-pass-context-to-loader.patch
+++ /dev/null
@@ -1,159 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Chris Coulson <chris.coulson@canonical.com>
-Date: Fri, 29 Apr 2022 21:16:02 +0100
-Subject: [PATCH] commands/boot: Add API to pass context to loader
-
-Loaders rely on global variables for saving context which is consumed
-in the boot hook and freed in the unload hook. In the case where a loader
-command is executed twice, calling grub_loader_set a second time executes
-the unload hook, but in some cases this runs when the loader's global
-context has already been updated, resulting in the updated context being
-freed and potential use-after-free bugs when the boot hook is subsequently
-called.
-
-This adds a new API (grub_loader_set_ex) which allows a loader to specify
-context that is passed to its boot and unload hooks. This is an alternative
-to requiring that loaders call grub_loader_unset before mutating their
-global context.
-
-Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
-(cherry picked from commit 4322a64dde7e8fedb58e50b79408667129d45dd3)
-(cherry picked from commit 937ad0e2159b6b8cb0d2ce3515da3a8b797c7927)
----
- grub-core/commands/boot.c | 66 +++++++++++++++++++++++++++++++++++++++++------
- include/grub/loader.h     |  5 ++++
- 2 files changed, 63 insertions(+), 8 deletions(-)
-
-diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c
-index bbca81e947..53691a62d9 100644
---- a/grub-core/commands/boot.c
-+++ b/grub-core/commands/boot.c
-@@ -27,10 +27,20 @@
- 
- GRUB_MOD_LICENSE ("GPLv3+");
- 
--static grub_err_t (*grub_loader_boot_func) (void);
--static grub_err_t (*grub_loader_unload_func) (void);
-+static grub_err_t (*grub_loader_boot_func) (void *);
-+static grub_err_t (*grub_loader_unload_func) (void *);
-+static void *grub_loader_context;
- static int grub_loader_flags;
- 
-+struct grub_simple_loader_hooks
-+{
-+  grub_err_t (*boot) (void);
-+  grub_err_t (*unload) (void);
-+};
-+
-+/* Don't heap allocate this to avoid making grub_loader_set fallible. */
-+static struct grub_simple_loader_hooks simple_loader_hooks;
-+
- struct grub_preboot
- {
-   grub_err_t (*preboot_func) (int);
-@@ -44,6 +54,29 @@ static int grub_loader_loaded;
- static struct grub_preboot *preboots_head = 0,
-   *preboots_tail = 0;
- 
-+static grub_err_t
-+grub_simple_boot_hook (void *context)
-+{
-+  struct grub_simple_loader_hooks *hooks;
-+
-+  hooks = (struct grub_simple_loader_hooks *) context;
-+  return hooks->boot ();
-+}
-+
-+static grub_err_t
-+grub_simple_unload_hook (void *context)
-+{
-+  struct grub_simple_loader_hooks *hooks;
-+  grub_err_t ret;
-+
-+  hooks = (struct grub_simple_loader_hooks *) context;
-+
-+  ret = hooks->unload ();
-+  grub_memset (hooks, 0, sizeof (*hooks));
-+
-+  return ret;
-+}
-+
- int
- grub_loader_is_loaded (void)
- {
-@@ -110,28 +143,45 @@ grub_loader_unregister_preboot_hook (struct grub_preboot *hnd)
- }
- 
- void
--grub_loader_set (grub_err_t (*boot) (void),
--		 grub_err_t (*unload) (void),
--		 int flags)
-+grub_loader_set_ex (grub_err_t (*boot) (void *),
-+		    grub_err_t (*unload) (void *),
-+		    void *context,
-+		    int flags)
- {
-   if (grub_loader_loaded && grub_loader_unload_func)
--    grub_loader_unload_func ();
-+    grub_loader_unload_func (grub_loader_context);
- 
-   grub_loader_boot_func = boot;
-   grub_loader_unload_func = unload;
-+  grub_loader_context = context;
-   grub_loader_flags = flags;
- 
-   grub_loader_loaded = 1;
- }
- 
-+void
-+grub_loader_set (grub_err_t (*boot) (void),
-+		 grub_err_t (*unload) (void),
-+		 int flags)
-+{
-+  grub_loader_set_ex (grub_simple_boot_hook,
-+		      grub_simple_unload_hook,
-+		      &simple_loader_hooks,
-+		      flags);
-+
-+  simple_loader_hooks.boot = boot;
-+  simple_loader_hooks.unload = unload;
-+}
-+
- void
- grub_loader_unset(void)
- {
-   if (grub_loader_loaded && grub_loader_unload_func)
--    grub_loader_unload_func ();
-+    grub_loader_unload_func (grub_loader_context);
- 
-   grub_loader_boot_func = 0;
-   grub_loader_unload_func = 0;
-+  grub_loader_context = 0;
- 
-   grub_loader_loaded = 0;
- }
-@@ -158,7 +208,7 @@ grub_loader_boot (void)
- 	  return err;
- 	}
-     }
--  err = (grub_loader_boot_func) ();
-+  err = (grub_loader_boot_func) (grub_loader_context);
- 
-   for (cur = preboots_tail; cur; cur = cur->prev)
-     if (! err)
-diff --git a/include/grub/loader.h b/include/grub/loader.h
-index b208642821..1846fa6c5f 100644
---- a/include/grub/loader.h
-+++ b/include/grub/loader.h
-@@ -40,6 +40,11 @@ void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void),
- 				    grub_err_t (*unload) (void),
- 				    int flags);
- 
-+void EXPORT_FUNC (grub_loader_set_ex) (grub_err_t (*boot) (void *),
-+				       grub_err_t (*unload) (void *),
-+				       void *context,
-+				       int flags);
-+
- /* Unset current loader, if any.  */
- void EXPORT_FUNC (grub_loader_unset) (void);
- 
diff --git a/SOURCES/0234-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch b/SOURCES/0234-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch
new file mode 100644
index 0000000..ab0d471
--- /dev/null
+++ b/SOURCES/0234-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch
@@ -0,0 +1,71 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 20 Dec 2021 21:55:43 +1100
+Subject: [PATCH] net/dns: Don't read past the end of the string we're checking
+ against
+
+I don't really understand what's going on here but fuzzing found
+a bug where we read past the end of check_with. That's a C string,
+so use grub_strlen() to make sure we don't overread it.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 6a97b3f4b1d5173aa516edc6dedbc63de7306d21)
+---
+ grub-core/net/dns.c | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c
+index 135faac035..17961a9f18 100644
+--- a/grub-core/net/dns.c
++++ b/grub-core/net/dns.c
+@@ -146,11 +146,18 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
+ 		 int *length, char *set)
+ {
+   const char *readable_ptr = check_with;
++  int readable_len;
+   const grub_uint8_t *ptr;
+   char *optr = set;
+   int bytes_processed = 0;
+   if (length)
+     *length = 0;
++
++  if (readable_ptr != NULL)
++    readable_len = grub_strlen (readable_ptr);
++  else
++    readable_len = 0;
++
+   for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; )
+     {
+       /* End marker.  */
+@@ -172,13 +179,16 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
+ 	  ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]);
+ 	  continue;
+ 	}
+-      if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0)
++      if (readable_ptr != NULL && (*ptr > readable_len || grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0))
+ 	return 0;
+       if (grub_memchr (ptr + 1, 0, *ptr) 
+ 	  || grub_memchr (ptr + 1, '.', *ptr))
+ 	return 0;
+       if (readable_ptr)
+-	readable_ptr += *ptr;
++	{
++	  readable_ptr += *ptr;
++	  readable_len -= *ptr;
++	}
+       if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0)
+ 	return 0;
+       bytes_processed += *ptr + 1;
+@@ -192,7 +202,10 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
+       if (optr)
+ 	*optr++ = '.';
+       if (readable_ptr && *readable_ptr)
+-	readable_ptr++;
++	{
++	  readable_ptr++;
++	  readable_len--;
++	}
+       ptr += *ptr + 1;
+     }
+   return 0;
diff --git a/SOURCES/0235-loader-efi-chainloader-Use-grub_loader_set_ex.patch b/SOURCES/0235-loader-efi-chainloader-Use-grub_loader_set_ex.patch
deleted file mode 100644
index 6a41992..0000000
--- a/SOURCES/0235-loader-efi-chainloader-Use-grub_loader_set_ex.patch
+++ /dev/null
@@ -1,148 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Chris Coulson <chris.coulson@canonical.com>
-Date: Fri, 29 Apr 2022 21:30:56 +0100
-Subject: [PATCH] loader/efi/chainloader: Use grub_loader_set_ex
-
-This ports the EFI chainloader to use grub_loader_set_ex in order to fix
-a use-after-free bug that occurs when grub_cmd_chainloader is executed
-more than once before a boot attempt is performed.
-
-Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
-(cherry picked from commit 4b7f0402b7cb0f67a93be736f2b75b818d7f44c9)
-(cherry picked from commit fc1a79bf0e0bc019362ace46d908a92b48dcd55b)
-[rharwood: context sludge from previous commit]
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
----
- grub-core/loader/efi/chainloader.c | 38 ++++++++++++++++++++++----------------
- 1 file changed, 22 insertions(+), 16 deletions(-)
-
-diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
-index 0717ce0478..8ef508beca 100644
---- a/grub-core/loader/efi/chainloader.c
-+++ b/grub-core/loader/efi/chainloader.c
-@@ -48,8 +48,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
- 
- static grub_dl_t my_mod;
- 
--static grub_efi_handle_t image_handle;
--
- struct grub_secureboot_chainloader_context {
-   grub_efi_physical_address_t address;
-   grub_efi_uintn_t pages;
-@@ -59,7 +57,6 @@ struct grub_secureboot_chainloader_context {
-   grub_ssize_t cmdline_len;
-   grub_efi_handle_t dev_handle;
- };
--static struct grub_secureboot_chainloader_context *sb_context;
- 
- static grub_err_t
- grub_start_image (grub_efi_handle_t handle)
-@@ -98,11 +95,14 @@ grub_start_image (grub_efi_handle_t handle)
- }
- 
- static grub_err_t
--grub_chainloader_unload (void)
-+grub_chainloader_unload (void *context)
- {
-+  grub_efi_handle_t image_handle;
-   grub_efi_loaded_image_t *loaded_image;
-   grub_efi_boot_services_t *b;
- 
-+  image_handle = (grub_efi_handle_t) context;
-+
-   loaded_image = grub_efi_get_loaded_image (image_handle);
-   if (loaded_image != NULL)
-     grub_free (loaded_image->load_options);
-@@ -115,10 +115,12 @@ grub_chainloader_unload (void)
- }
- 
- static grub_err_t
--grub_chainloader_boot (void)
-+grub_chainloader_boot (void *context)
- {
-+  grub_efi_handle_t image_handle;
-   grub_err_t err;
- 
-+  image_handle = (grub_efi_handle_t) context;
-   err = grub_start_image (image_handle);
- 
-   grub_loader_unset ();
-@@ -839,15 +841,17 @@ error_exit:
- }
- 
- static grub_err_t
--grub_secureboot_chainloader_unload (void)
-+grub_secureboot_chainloader_unload (void *context)
- {
-+  struct grub_secureboot_chainloader_context *sb_context;
-+
-+  sb_context = (struct grub_secureboot_chainloader_context *) context;
-+
-   grub_efi_free_pages (sb_context->address, sb_context->pages);
-   grub_free (sb_context->file_path);
-   grub_free (sb_context->cmdline);
-   grub_free (sb_context);
- 
--  sb_context = 0;
--
-   grub_dl_unref (my_mod);
-   return GRUB_ERR_NONE;
- }
-@@ -896,12 +900,15 @@ grub_load_image(grub_efi_device_path_t *file_path, void *boot_image,
- }
- 
- static grub_err_t
--grub_secureboot_chainloader_boot (void)
-+grub_secureboot_chainloader_boot (void *context)
- {
-+  struct grub_secureboot_chainloader_context *sb_context;
-   grub_efi_boot_services_t *b;
-   int rc;
-   grub_efi_handle_t handle = 0;
- 
-+  sb_context = (struct grub_secureboot_chainloader_context *) context;
-+
-   rc = handle_image (sb_context);
-   if (rc == 0)
-     {
-@@ -943,6 +950,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
-   grub_efi_char16_t *cmdline = 0;
-   grub_ssize_t cmdline_len = 0;
-   grub_efi_handle_t dev_handle = 0;
-+  grub_efi_handle_t image_handle = 0;
-+  struct grub_secureboot_chainloader_context *sb_context = 0;
- 
-   if (argc == 0)
-     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
-@@ -1130,8 +1139,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
-       grub_file_close (file);
-       grub_device_close (dev);
- 
--      grub_loader_set (grub_secureboot_chainloader_boot,
--		       grub_secureboot_chainloader_unload, 0);
-+      grub_loader_set_ex (grub_secureboot_chainloader_boot,
-+			  grub_secureboot_chainloader_unload, sb_context, 0);
-       return 0;
-     }
-   else if (rc == 0)
-@@ -1145,7 +1154,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
-       efi_call_2 (b->free_pages, address, pages);
-       grub_free (file_path);
- 
--      grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
-+      grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0);
- 
-       return 0;
-     }
-@@ -1173,10 +1182,7 @@ fail:
-     grub_free (cmdline);
- 
-   if (image_handle != 0)
--    {
--      efi_call_1 (b->unload_image, image_handle);
--      image_handle = 0;
--    }
-+    efi_call_1 (b->unload_image, image_handle);
- 
-   grub_dl_unref (my_mod);
- 
diff --git a/SOURCES/0235-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch b/SOURCES/0235-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch
new file mode 100644
index 0000000..3ff7b6b
--- /dev/null
+++ b/SOURCES/0235-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch
@@ -0,0 +1,112 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 20 Sep 2021 01:12:24 +1000
+Subject: [PATCH] net/tftp: Prevent a UAF and double-free from a failed seek
+
+A malicious tftp server can cause UAFs and a double free.
+
+An attempt to read from a network file is handled by grub_net_fs_read(). If
+the read is at an offset other than the current offset, grub_net_seek_real()
+is invoked.
+
+In grub_net_seek_real(), if a backwards seek cannot be satisfied from the
+currently received packets, and the underlying transport does not provide
+a seek method, then grub_net_seek_real() will close and reopen the network
+protocol layer.
+
+For tftp, the ->close() call goes to tftp_close() and frees the tftp_data_t
+file->data. The file->data pointer is not nulled out after the free.
+
+If the ->open() call fails, the file->data will not be reallocated and will
+continue point to a freed memory block. This could happen from a server
+refusing to send the requisite ack to the new tftp request, for example.
+
+The seek and the read will then fail, but the grub_file continues to exist:
+the failed seek does not necessarily cause the entire file to be thrown
+away (e.g. where the file is checked to see if it is gzipped/lzio/xz/etc.,
+a read failure is interpreted as a decompressor passing on the file, not as
+an invalidation of the entire grub_file_t structure).
+
+This means subsequent attempts to read or seek the file will use the old
+file->data after free. Eventually, the file will be close()d again and
+file->data will be freed again.
+
+Mark a net_fs file that doesn't reopen as broken. Do not permit read() or
+close() on a broken file (seek is not exposed directly to the file API -
+it is only called as part of read, so this blocks seeks as well).
+
+As an additional defence, null out the ->data pointer if tftp_open() fails.
+That would have lead to a simple null pointer dereference rather than
+a mess of UAFs.
+
+This may affect other protocols, I haven't checked.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit dada1dda695439bb55b2848dddc2d89843552f81)
+---
+ grub-core/net/net.c  | 11 +++++++++--
+ grub-core/net/tftp.c |  1 +
+ include/grub/net.h   |  1 +
+ 3 files changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index 55aed92722..1001c611d1 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -1625,7 +1625,8 @@ grub_net_fs_close (grub_file_t file)
+       grub_netbuff_free (file->device->net->packs.first->nb);
+       grub_net_remove_packet (file->device->net->packs.first);
+     }
+-  file->device->net->protocol->close (file);
++  if (!file->device->net->broken)
++    file->device->net->protocol->close (file);
+   grub_free (file->device->net->name);
+   return GRUB_ERR_NONE;
+ }
+@@ -1847,7 +1848,10 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset)
+     file->device->net->stall = 0;
+     err = file->device->net->protocol->open (file, file->device->net->name);
+     if (err)
+-      return err;
++      {
++	file->device->net->broken = 1;
++	return err;
++      }
+     grub_net_fs_read_real (file, NULL, offset);
+     return grub_errno;
+   }
+@@ -1856,6 +1860,9 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset)
+ static grub_ssize_t
+ grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len)
+ {
++  if (file->device->net->broken)
++    return -1;
++
+   if (file->offset != file->device->net->offset)
+     {
+       grub_err_t err;
+diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
+index d54b13f09f..788ad1dc44 100644
+--- a/grub-core/net/tftp.c
++++ b/grub-core/net/tftp.c
+@@ -408,6 +408,7 @@ tftp_open (struct grub_file *file, const char *filename)
+     {
+       grub_net_udp_close (data->sock);
+       grub_free (data);
++      file->data = NULL;
+       return grub_errno;
+     }
+ 
+diff --git a/include/grub/net.h b/include/grub/net.h
+index 42af7de250..9e4898cc6b 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -280,6 +280,7 @@ typedef struct grub_net
+   grub_fs_t fs;
+   int eof;
+   int stall;
++  int broken;
+ } *grub_net_t;
+ 
+ extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name);
diff --git a/SOURCES/0236-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch b/SOURCES/0236-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch
deleted file mode 100644
index 4be2008..0000000
--- a/SOURCES/0236-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Chris Coulson <chris.coulson@canonical.com>
-Date: Mon, 2 May 2022 14:39:31 +0200
-Subject: [PATCH] loader/i386/efi/linux: Avoid a use-after-free in the linuxefi
- loader
-
-In some error paths in grub_cmd_linux, the pointer to lh may be
-dereferenced after the buffer it points to has been freed. There aren't
-any security implications from this because nothing else uses the
-allocator after the buffer is freed and before the pointer is
-dereferenced, but fix it anyway.
-
-Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
-(cherry picked from commit 8224f5a71af94bec8697de17e7e579792db9f9e2)
-(cherry picked from commit 4744b62e20d07674017213ac54d7442d679f9d1a)
----
- grub-core/loader/i386/efi/linux.c | 5 ++---
- 1 file changed, 2 insertions(+), 3 deletions(-)
-
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index 3cf0f9b330..08c9fe6b0e 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -478,9 +478,6 @@ fail:
-   if (file)
-     grub_file_close (file);
- 
--  if (kernel)
--    grub_free (kernel);
--
-   if (grub_errno != GRUB_ERR_NONE)
-     {
-       grub_dl_unref (my_mod);
-@@ -496,6 +493,8 @@ fail:
-       kernel_free (params, sizeof(*params));
-     }
- 
-+  grub_free (kernel);
-+
-   return grub_errno;
- }
- 
diff --git a/SOURCES/0236-net-tftp-Avoid-a-trivial-UAF.patch b/SOURCES/0236-net-tftp-Avoid-a-trivial-UAF.patch
new file mode 100644
index 0000000..4ec3b56
--- /dev/null
+++ b/SOURCES/0236-net-tftp-Avoid-a-trivial-UAF.patch
@@ -0,0 +1,35 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 18 Jan 2022 14:29:20 +1100
+Subject: [PATCH] net/tftp: Avoid a trivial UAF
+
+Under tftp errors, we print a tftp error message from the tftp header.
+However, the tftph pointer is a pointer inside nb, the netbuff. Previously,
+we were freeing the nb and then dereferencing it. Don't do that, use it
+and then free it later.
+
+This isn't really _bad_ per se, especially as we're single-threaded, but
+it trips up fuzzers.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 956f4329cec23e4375182030ca9b2be631a61ba5)
+---
+ grub-core/net/tftp.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
+index 788ad1dc44..a95766dcbd 100644
+--- a/grub-core/net/tftp.c
++++ b/grub-core/net/tftp.c
+@@ -251,9 +251,9 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
+       return GRUB_ERR_NONE;
+     case TFTP_ERROR:
+       data->have_oack = 1;
+-      grub_netbuff_free (nb);
+       grub_error (GRUB_ERR_IO, "%s", tftph->u.err.errmsg);
+       grub_error_save (&data->save_err);
++      grub_netbuff_free (nb);
+       return GRUB_ERR_NONE;
+     default:
+       grub_netbuff_free (nb);
diff --git a/SOURCES/0237-loader-i386-efi-linux-Use-grub_loader_set_ex.patch b/SOURCES/0237-loader-i386-efi-linux-Use-grub_loader_set_ex.patch
deleted file mode 100644
index 9f5c491..0000000
--- a/SOURCES/0237-loader-i386-efi-linux-Use-grub_loader_set_ex.patch
+++ /dev/null
@@ -1,298 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Chris Coulson <chris.coulson@canonical.com>
-Date: Mon, 2 May 2022 17:04:23 +0200
-Subject: [PATCH] loader/i386/efi/linux: Use grub_loader_set_ex
-
-This ports the linuxefi loader to use grub_loader_set_ex in order to fix
-a use-after-fre bug that occurs when grub_cmd_linux is executed more than
-once before a boot attempt is performed.
-
-This is more complicated than for the chainloader command, as the initrd
-command needs access to the loader state. To solve this, the linuxefi
-module registers a dummy initrd command at startup that returns an error.
-The linuxefi command then registers a proper initrd command with a higher
-priority that is passed the loader state.
-
-Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
-(cherry picked from commit 7cf736436b4c934df5ddfa6f44b46a7e07d99fdc)
-[rharwood/pjones: set kernel_size in context]
-(cherry picked from commit 9c056391f7a36ea480de9a759c12e55a90f2040a)
-[rharwood: verifying twice]
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
----
- grub-core/loader/i386/efi/linux.c | 146 +++++++++++++++++++++++---------------
- 1 file changed, 87 insertions(+), 59 deletions(-)
-
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index 08c9fe6b0e..9e25e51ccf 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -35,13 +35,19 @@
- GRUB_MOD_LICENSE ("GPLv3+");
- 
- static grub_dl_t my_mod;
--static int loaded;
--static void *kernel_mem;
--static grub_uint64_t kernel_size;
--static void *initrd_mem;
--static grub_uint32_t handover_offset;
--struct linux_kernel_params *params;
--static char *linux_cmdline;
-+
-+static grub_command_t cmd_linux, cmd_initrd;
-+static grub_command_t cmd_linuxefi, cmd_initrdefi;
-+
-+struct grub_linuxefi_context {
-+  void *kernel_mem;
-+  grub_uint64_t kernel_size;
-+  grub_uint32_t handover_offset;
-+  struct linux_kernel_params *params;
-+  char *cmdline;
-+
-+  void *initrd_mem;
-+};
- 
- #define MIN(a, b) \
-   ({ typeof (a) _a = (a); \
-@@ -124,25 +130,32 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
- }
- 
- static grub_err_t
--grub_linuxefi_boot (void)
-+grub_linuxefi_boot (void *data)
- {
-+  struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data;
-+
-   asm volatile ("cli");
- 
--  return grub_efi_linux_boot ((char *)kernel_mem,
--			      handover_offset,
--			      params);
-+  return grub_efi_linux_boot ((char *)context->kernel_mem,
-+			      context->handover_offset,
-+			      context->params);
- }
- 
- static grub_err_t
--grub_linuxefi_unload (void)
-+grub_linuxefi_unload (void *data)
- {
-+  struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data;
-+  struct linux_kernel_params *params = context->params;
-+
-   grub_dl_unref (my_mod);
--  loaded = 0;
- 
--  kernel_free(initrd_mem, params->ramdisk_size);
--  kernel_free(linux_cmdline, params->cmdline_size + 1);
--  kernel_free(kernel_mem, kernel_size);
--  kernel_free(params, sizeof(*params));
-+  kernel_free (context->initrd_mem, params->ramdisk_size);
-+  kernel_free (context->cmdline, params->cmdline_size + 1);
-+  kernel_free (context->kernel_mem, context->kernel_size);
-+  kernel_free (params, sizeof(*params));
-+  cmd_initrd->data = 0;
-+  cmd_initrdefi->data = 0;
-+  grub_free (context);
- 
-   return GRUB_ERR_NONE;
- }
-@@ -189,13 +202,14 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len)
- #define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull))
- 
- static grub_err_t
--grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
--                 int argc, char *argv[])
-+grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
- {
-   grub_file_t *files = 0;
-   int i, nfiles = 0;
-   grub_size_t size = 0;
-   grub_uint8_t *ptr;
-+  struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data;
-+  struct linux_kernel_params *params;
- 
-   if (argc == 0)
-     {
-@@ -203,12 +217,14 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
-       goto fail;
-     }
- 
--  if (!loaded)
-+  if (!context)
-     {
-       grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
-       goto fail;
-     }
- 
-+  params = context->params;
-+
-   files = grub_calloc (argc, sizeof (files[0]));
-   if (!files)
-     goto fail;
-@@ -226,19 +242,19 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
- 	}
-     }
- 
--  initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
--  if (initrd_mem == NULL)
-+  context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
-+  if (context->initrd_mem == NULL)
-     goto fail;
--  grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
-+  grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem);
- 
-   params->ramdisk_size = LOW_U32(size);
--  params->ramdisk_image = LOW_U32(initrd_mem);
-+  params->ramdisk_image = LOW_U32(context->initrd_mem);
- #if defined(__x86_64__)
-   params->ext_ramdisk_size = HIGH_U32(size);
--  params->ext_ramdisk_image = HIGH_U32(initrd_mem);
-+  params->ext_ramdisk_image = HIGH_U32(context->initrd_mem);
- #endif
- 
--  ptr = initrd_mem;
-+  ptr = context->initrd_mem;
- 
-   for (i = 0; i < nfiles; i++)
-     {
-@@ -262,8 +278,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
-     grub_file_close (files[i]);
-   grub_free (files);
- 
--  if (initrd_mem && grub_errno)
--    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem,
-+  if (context->initrd_mem && grub_errno)
-+    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem,
- 			 BYTES_TO_PAGES(size));
- 
-   return grub_errno;
-@@ -279,6 +295,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   void *kernel = NULL;
-   int setup_header_end_offset;
-   int rc;
-+  void *kernel_mem = 0;
-+  grub_uint64_t kernel_size = 0;
-+  grub_uint32_t handover_offset;
-+  struct linux_kernel_params *params = 0;
-+  char *cmdline = 0;
-+  struct grub_linuxefi_context *context = 0;
- 
-   grub_dl_ref (my_mod);
- 
-@@ -403,27 +425,27 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   grub_dprintf ("linux", "new lh is at %p\n", lh);
- 
-   grub_dprintf ("linux", "setting up cmdline\n");
--  linux_cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline"));
--  if (!linux_cmdline)
-+  cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline"));
-+  if (!cmdline)
-     goto fail;
--  grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline);
-+  grub_dprintf ("linux", "cmdline = %p\n", cmdline);
- 
--  grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
-+  grub_memcpy (cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
-   grub_create_loader_cmdline (argc, argv,
--                              linux_cmdline + sizeof (LINUX_IMAGE) - 1,
-+                              cmdline + sizeof (LINUX_IMAGE) - 1,
- 			      lh->cmdline_size - (sizeof (LINUX_IMAGE) - 1),
- 			      GRUB_VERIFY_KERNEL_CMDLINE);
- 
--  grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline);
-+  grub_dprintf ("linux", "cmdline:%s\n", cmdline);
-   grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n",
--		LOW_U32(linux_cmdline));
--  lh->cmd_line_ptr = LOW_U32(linux_cmdline);
-+		LOW_U32(cmdline));
-+  lh->cmd_line_ptr = LOW_U32(cmdline);
- #if defined(__x86_64__)
--  if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull)
-+  if ((grub_efi_uintn_t)cmdline > 0xffffffffull)
-     {
-       grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n",
--		    HIGH_U32(linux_cmdline));
--      params->ext_cmd_line_ptr = HIGH_U32(linux_cmdline);
-+		    HIGH_U32(cmdline));
-+      params->ext_cmd_line_ptr = HIGH_U32(cmdline);
-     }
- #endif
- 
-@@ -448,16 +470,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-     }
-   max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
-   max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
--  kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel"));
-+  kernel_size = lh->init_size;
-+  kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel"));
-   restore_addresses();
-   if (!kernel_mem)
-     goto fail;
-   grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem);
- 
--  grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
--
--  loaded = 1;
--
-   grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n",
- 		LOW_U32(kernel_mem));
-   lh->code32_start = LOW_U32(kernel_mem);
-@@ -474,33 +493,42 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
- 		"setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n",
- 		params->ext_loader_type, params->ext_loader_ver);
- 
-+  context = grub_zalloc (sizeof (*context));
-+  if (!context)
-+    goto fail;
-+  context->kernel_mem = kernel_mem;
-+  context->kernel_size = kernel_size;
-+  context->handover_offset = handover_offset;
-+  context->params = params;
-+  context->cmdline = cmdline;
-+
-+  grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0);
-+
-+  cmd_initrd->data = context;
-+  cmd_initrdefi->data = context;
-+
-+  grub_file_close (file);
-+  grub_free (kernel);
-+  return 0;
-+
- fail:
-   if (file)
-     grub_file_close (file);
- 
--  if (grub_errno != GRUB_ERR_NONE)
--    {
--      grub_dl_unref (my_mod);
--      loaded = 0;
--    }
-+  grub_dl_unref (my_mod);
- 
--  if (!loaded)
--    {
--      if (lh)
--	kernel_free (linux_cmdline, lh->cmdline_size + 1);
-+  if (lh)
-+    kernel_free (cmdline, lh->cmdline_size + 1);
- 
--      kernel_free (kernel_mem, kernel_size);
--      kernel_free (params, sizeof(*params));
--    }
-+  kernel_free (kernel_mem, kernel_size);
-+  kernel_free (params, sizeof(*params));
- 
-+  grub_free (context);
-   grub_free (kernel);
- 
-   return grub_errno;
- }
- 
--static grub_command_t cmd_linux, cmd_initrd;
--static grub_command_t cmd_linuxefi, cmd_initrdefi;
--
- GRUB_MOD_INIT(linux)
- {
-   cmd_linux =
diff --git a/SOURCES/0237-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch b/SOURCES/0237-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch
new file mode 100644
index 0000000..186f0c3
--- /dev/null
+++ b/SOURCES/0237-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch
@@ -0,0 +1,42 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 1 Mar 2022 23:14:15 +1100
+Subject: [PATCH] net/http: Do not tear down socket if it's already been torn
+ down
+
+It's possible for data->sock to get torn down in tcp error handling.
+If we unconditionally tear it down again we will end up doing writes
+to an offset of the NULL pointer when we go to tear it down again.
+
+Detect if it has been torn down and don't do it again.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit ec233d3ecf995293304de443579aab5c46c49e85)
+---
+ grub-core/net/http.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/net/http.c b/grub-core/net/http.c
+index 7f878b5615..19cb8768e3 100644
+--- a/grub-core/net/http.c
++++ b/grub-core/net/http.c
+@@ -427,7 +427,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
+       return err;
+     }
+ 
+-  for (i = 0; !data->headers_recv && i < 100; i++)
++  for (i = 0; data->sock && !data->headers_recv && i < 100; i++)
+     {
+       grub_net_tcp_retransmit ();
+       grub_net_poll_cards (300, &data->headers_recv);
+@@ -435,7 +435,8 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
+ 
+   if (!data->headers_recv)
+     {
+-      grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
++      if (data->sock)
++        grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
+       if (data->err)
+ 	{
+ 	  char *str = data->errmsg;
diff --git a/SOURCES/0238-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch b/SOURCES/0238-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch
deleted file mode 100644
index fe329e6..0000000
--- a/SOURCES/0238-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch
+++ /dev/null
@@ -1,76 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Chris Coulson <chris.coulson@canonical.com>
-Date: Tue, 3 May 2022 09:47:35 +0200
-Subject: [PATCH] loader/i386/efi/linux: Fix a memory leak in the initrd
- command
-
-Subsequent invocations of the initrd command result in the previous
-initrd being leaked, so fix that.
-
-Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
-(cherry picked from commit d98af31ce1e31bb22163960d53f5eb28c66582a0)
-(cherry picked from commit 62234d6a00e6d1dd8e017ff161d359feb5234082)
----
- grub-core/loader/i386/efi/linux.c | 21 ++++++++++++---------
- 1 file changed, 12 insertions(+), 9 deletions(-)
-
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index 9e25e51ccf..d24553a79d 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -210,6 +210,7 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
-   grub_uint8_t *ptr;
-   struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data;
-   struct linux_kernel_params *params;
-+  void *initrd_mem = 0;
- 
-   if (argc == 0)
-     {
-@@ -242,19 +243,19 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
- 	}
-     }
- 
--  context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
--  if (context->initrd_mem == NULL)
-+  initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
-+  if (initrd_mem == NULL)
-     goto fail;
--  grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem);
-+  grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
- 
-   params->ramdisk_size = LOW_U32(size);
--  params->ramdisk_image = LOW_U32(context->initrd_mem);
-+  params->ramdisk_image = LOW_U32(initrd_mem);
- #if defined(__x86_64__)
-   params->ext_ramdisk_size = HIGH_U32(size);
--  params->ext_ramdisk_image = HIGH_U32(context->initrd_mem);
-+  params->ext_ramdisk_image = HIGH_U32(initrd_mem);
- #endif
- 
--  ptr = context->initrd_mem;
-+  ptr = initrd_mem;
- 
-   for (i = 0; i < nfiles; i++)
-     {
-@@ -271,6 +272,9 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
-       ptr += ALIGN_UP_OVERHEAD (cursize, 4);
-     }
- 
-+  kernel_free(context->initrd_mem, params->ramdisk_size);
-+
-+  context->initrd_mem = initrd_mem;
-   params->ramdisk_size = size;
- 
-  fail:
-@@ -278,9 +282,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
-     grub_file_close (files[i]);
-   grub_free (files);
- 
--  if (context->initrd_mem && grub_errno)
--    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem,
--			 BYTES_TO_PAGES(size));
-+  if (initrd_mem && grub_errno)
-+    kernel_free (initrd_mem, size);
- 
-   return grub_errno;
- }
diff --git a/SOURCES/0238-net-http-Fix-OOB-write-for-split-http-headers.patch b/SOURCES/0238-net-http-Fix-OOB-write-for-split-http-headers.patch
new file mode 100644
index 0000000..f22960b
--- /dev/null
+++ b/SOURCES/0238-net-http-Fix-OOB-write-for-split-http-headers.patch
@@ -0,0 +1,46 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 8 Mar 2022 18:17:03 +1100
+Subject: [PATCH] net/http: Fix OOB write for split http headers
+
+GRUB has special code for handling an http header that is split
+across two packets.
+
+The code tracks the end of line by looking for a "\n" byte. The
+code for split headers has always advanced the pointer just past the
+end of the line, whereas the code that handles unsplit headers does
+not advance the pointer. This extra advance causes the length to be
+one greater, which breaks an assumption in parse_line(), leading to
+it writing a NUL byte one byte past the end of the buffer where we
+reconstruct the line from the two packets.
+
+It's conceivable that an attacker controlled set of packets could
+cause this to zero out the first byte of the "next" pointer of the
+grub_mm_region structure following the current_line buffer.
+
+Do not advance the pointer in the split header case.
+
+Fixes: CVE-2022-28734
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit e9fb459638811c12b0989dbf64e3e124974ef617)
+---
+ grub-core/net/http.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/grub-core/net/http.c b/grub-core/net/http.c
+index 19cb8768e3..58546739a2 100644
+--- a/grub-core/net/http.c
++++ b/grub-core/net/http.c
+@@ -193,9 +193,7 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)),
+ 	  int have_line = 1;
+ 	  char *t;
+ 	  ptr = grub_memchr (nb->data, '\n', nb->tail - nb->data);
+-	  if (ptr)
+-	    ptr++;
+-	  else
++	  if (ptr == NULL)
+ 	    {
+ 	      have_line = 0;
+ 	      ptr = (char *) nb->tail;
diff --git a/SOURCES/0239-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch b/SOURCES/0239-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch
deleted file mode 100644
index 716d1f1..0000000
--- a/SOURCES/0239-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch
+++ /dev/null
@@ -1,102 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Julian Andres Klode <julian.klode@canonical.com>
-Date: Thu, 2 Dec 2021 15:03:53 +0100
-Subject: [PATCH] kern/efi/sb: Reject non-kernel files in the shim_lock
- verifier
-
-We must not allow other verifiers to pass things like the GRUB modules.
-Instead of maintaining a blocklist, maintain an allowlist of things
-that we do not care about.
-
-This allowlist really should be made reusable, and shared by the
-lockdown verifier, but this is the minimal patch addressing
-security concerns where the TPM verifier was able to mark modules
-as verified (or the OpenPGP verifier for that matter), when it
-should not do so on shim-powered secure boot systems.
-
-Fixes: CVE-2022-28735
-
-Signed-off-by: Julian Andres Klode <julian.klode@canonical.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit fa61ad69861c1cb3f68bf853d78fae7fd93986a0)
-(cherry picked from commit f418191e01b38a635319a26925cf345523d4440c)
----
- grub-core/kern/efi/sb.c | 39 ++++++++++++++++++++++++++++++++++++---
- include/grub/verify.h   |  1 +
- 2 files changed, 37 insertions(+), 3 deletions(-)
-
-diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c
-index c52ec6226a..89c4bb3fd1 100644
---- a/grub-core/kern/efi/sb.c
-+++ b/grub-core/kern/efi/sb.c
-@@ -119,10 +119,11 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)),
- 			 void **context __attribute__ ((unused)),
- 			 enum grub_verify_flags *flags)
- {
--  *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
-+  *flags = GRUB_VERIFY_FLAGS_NONE;
- 
-   switch (type & GRUB_FILE_TYPE_MASK)
-     {
-+    /* Files we check. */
-     case GRUB_FILE_TYPE_LINUX_KERNEL:
-     case GRUB_FILE_TYPE_MULTIBOOT_KERNEL:
-     case GRUB_FILE_TYPE_BSD_KERNEL:
-@@ -130,11 +131,43 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)),
-     case GRUB_FILE_TYPE_PLAN9_KERNEL:
-     case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE:
-       *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
-+      return GRUB_ERR_NONE;
- 
--      /* Fall through. */
-+    /* Files that do not affect secureboot state. */
-+    case GRUB_FILE_TYPE_NONE:
-+    case GRUB_FILE_TYPE_LOOPBACK:
-+    case GRUB_FILE_TYPE_LINUX_INITRD:
-+    case GRUB_FILE_TYPE_OPENBSD_RAMDISK:
-+    case GRUB_FILE_TYPE_XNU_RAMDISK:
-+    case GRUB_FILE_TYPE_SIGNATURE:
-+    case GRUB_FILE_TYPE_PUBLIC_KEY:
-+    case GRUB_FILE_TYPE_PUBLIC_KEY_TRUST:
-+    case GRUB_FILE_TYPE_PRINT_BLOCKLIST:
-+    case GRUB_FILE_TYPE_TESTLOAD:
-+    case GRUB_FILE_TYPE_GET_SIZE:
-+    case GRUB_FILE_TYPE_FONT:
-+    case GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY:
-+    case GRUB_FILE_TYPE_CAT:
-+    case GRUB_FILE_TYPE_HEXCAT:
-+    case GRUB_FILE_TYPE_CMP:
-+    case GRUB_FILE_TYPE_HASHLIST:
-+    case GRUB_FILE_TYPE_TO_HASH:
-+    case GRUB_FILE_TYPE_KEYBOARD_LAYOUT:
-+    case GRUB_FILE_TYPE_PIXMAP:
-+    case GRUB_FILE_TYPE_GRUB_MODULE_LIST:
-+    case GRUB_FILE_TYPE_CONFIG:
-+    case GRUB_FILE_TYPE_THEME:
-+    case GRUB_FILE_TYPE_GETTEXT_CATALOG:
-+    case GRUB_FILE_TYPE_FS_SEARCH:
-+    case GRUB_FILE_TYPE_LOADENV:
-+    case GRUB_FILE_TYPE_SAVEENV:
-+    case GRUB_FILE_TYPE_VERIFY_SIGNATURE:
-+      *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
-+      return GRUB_ERR_NONE;
- 
-+    /* Other files. */
-     default:
--      return GRUB_ERR_NONE;
-+      return grub_error (GRUB_ERR_ACCESS_DENIED, N_("prohibited by secure boot policy"));
-     }
- }
- 
-diff --git a/include/grub/verify.h b/include/grub/verify.h
-index cd129c398f..672ae16924 100644
---- a/include/grub/verify.h
-+++ b/include/grub/verify.h
-@@ -24,6 +24,7 @@
- 
- enum grub_verify_flags
-   {
-+    GRUB_VERIFY_FLAGS_NONE		= 0,
-     GRUB_VERIFY_FLAGS_SKIP_VERIFICATION	= 1,
-     GRUB_VERIFY_FLAGS_SINGLE_CHUNK	= 2,
-     /* Defer verification to another authority. */
diff --git a/SOURCES/0239-net-http-Error-out-on-headers-with-LF-without-CR.patch b/SOURCES/0239-net-http-Error-out-on-headers-with-LF-without-CR.patch
new file mode 100644
index 0000000..b73c169
--- /dev/null
+++ b/SOURCES/0239-net-http-Error-out-on-headers-with-LF-without-CR.patch
@@ -0,0 +1,48 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 8 Mar 2022 19:04:40 +1100
+Subject: [PATCH] net/http: Error out on headers with LF without CR
+
+In a similar vein to the previous patch, parse_line() would write
+a NUL byte past the end of the buffer if there was an HTTP header
+with a LF rather than a CRLF.
+
+RFC-2616 says:
+
+  Many HTTP/1.1 header field values consist of words separated by LWS
+  or special characters. These special characters MUST be in a quoted
+  string to be used within a parameter value (as defined in section 3.6).
+
+We don't support quoted sections or continuation lines, etc.
+
+If we see an LF that's not part of a CRLF, bail out.
+
+Fixes: CVE-2022-28734
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit d232ad41ac4979a9de4d746e5fdff9caf0e303de)
+---
+ grub-core/net/http.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/grub-core/net/http.c b/grub-core/net/http.c
+index 58546739a2..57d2721719 100644
+--- a/grub-core/net/http.c
++++ b/grub-core/net/http.c
+@@ -69,7 +69,15 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len)
+   char *end = ptr + len;
+   while (end > ptr && *(end - 1) == '\r')
+     end--;
++
++  /* LF without CR. */
++  if (end == ptr + len)
++    {
++      data->errmsg = grub_strdup (_("invalid HTTP header - LF without CR"));
++      return GRUB_ERR_NONE;
++    }
+   *end = 0;
++
+   /* Trailing CRLF.  */
+   if (data->in_chunk_len == 1)
+     {
diff --git a/SOURCES/0240-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch b/SOURCES/0240-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch
new file mode 100644
index 0000000..79df1c2
--- /dev/null
+++ b/SOURCES/0240-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch
@@ -0,0 +1,72 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
+Date: Wed, 6 Apr 2022 18:03:37 +0530
+Subject: [PATCH] fs/f2fs: Do not read past the end of nat journal entries
+
+A corrupt f2fs file system could specify a nat journal entry count
+that is beyond the maximum NAT_JOURNAL_ENTRIES.
+
+Check if the specified nat journal entry count before accessing the
+array, and throw an error if it is too large.
+
+Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit a3988cb3f0a108dd67ac127a79a4c8479d23334e)
+---
+ grub-core/fs/f2fs.c | 21 ++++++++++++++-------
+ 1 file changed, 14 insertions(+), 7 deletions(-)
+
+diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
+index 8a9992ca9e..63702214b0 100644
+--- a/grub-core/fs/f2fs.c
++++ b/grub-core/fs/f2fs.c
+@@ -632,23 +632,27 @@ get_nat_journal (struct grub_f2fs_data *data)
+   return err;
+ }
+ 
+-static grub_uint32_t
+-get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid)
++static grub_err_t
++get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid,
++                              grub_uint32_t *blkaddr)
+ {
+   grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats);
+-  grub_uint32_t blkaddr = 0;
+   grub_uint16_t i;
+ 
++  if (n >= NAT_JOURNAL_ENTRIES)
++    return grub_error (GRUB_ERR_BAD_FS,
++                       "invalid number of nat journal entries");
++
+   for (i = 0; i < n; i++)
+     {
+       if (grub_le_to_cpu32 (data->nat_j.entries[i].nid) == nid)
+         {
+-          blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr);
++          *blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr);
+           break;
+         }
+     }
+ 
+-  return blkaddr;
++  return GRUB_ERR_NONE;
+ }
+ 
+ static grub_uint32_t
+@@ -656,10 +660,13 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
+ {
+   struct grub_f2fs_nat_block *nat_block;
+   grub_uint32_t seg_off, block_off, entry_off, block_addr;
+-  grub_uint32_t blkaddr;
++  grub_uint32_t blkaddr = 0;
+   grub_err_t err;
+ 
+-  blkaddr = get_blkaddr_from_nat_journal (data, nid);
++  err = get_blkaddr_from_nat_journal (data, nid, &blkaddr);
++  if (err != GRUB_ERR_NONE)
++    return 0;
++
+   if (blkaddr)
+     return blkaddr;
+ 
diff --git a/SOURCES/0240-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch b/SOURCES/0240-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch
deleted file mode 100644
index f75512c..0000000
--- a/SOURCES/0240-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Fri, 25 Jun 2021 02:19:05 +1000
-Subject: [PATCH] kern/file: Do not leak device_name on error in
- grub_file_open()
-
-If we have an error in grub_file_open() before we free device_name, we
-will leak it.
-
-Free device_name in the error path and null out the pointer in the good
-path once we free it there.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 1499a5068839fa37cb77ecef4b5bdacbd1ed12ea)
-(cherry picked from commit 2ec50b289d8b24922433439533113087f111f110)
----
- grub-core/kern/file.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
-index e19aea3e51..ed69fc0f0f 100644
---- a/grub-core/kern/file.c
-+++ b/grub-core/kern/file.c
-@@ -81,6 +81,7 @@ grub_file_open (const char *name, enum grub_file_type type)
- 
-   device = grub_device_open (device_name);
-   grub_free (device_name);
-+  device_name = NULL;
-   if (! device)
-     goto fail;
- 
-@@ -135,6 +136,7 @@ grub_file_open (const char *name, enum grub_file_type type)
-   return file;
- 
-  fail:
-+  grub_free (device_name);
-   if (device)
-     grub_device_close (device);
- 
diff --git a/SOURCES/0241-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch b/SOURCES/0241-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch
new file mode 100644
index 0000000..855e882
--- /dev/null
+++ b/SOURCES/0241-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch
@@ -0,0 +1,132 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
+Date: Wed, 6 Apr 2022 18:49:09 +0530
+Subject: [PATCH] fs/f2fs: Do not read past the end of nat bitmap
+
+A corrupt f2fs filesystem could have a block offset or a bitmap
+offset that would cause us to read beyond the bounds of the nat
+bitmap.
+
+Introduce the nat_bitmap_size member in grub_f2fs_data which holds
+the size of nat bitmap.
+
+Set the size when loading the nat bitmap in nat_bitmap_ptr(), and
+catch when an invalid offset would create a pointer past the end of
+the allocated space.
+
+Check against the bitmap size in grub_f2fs_test_bit() test bit to avoid
+reading past the end of the nat bitmap.
+
+Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 62d63d5e38c67a6e349148bf7cb87c560e935a7e)
+---
+ grub-core/fs/f2fs.c | 33 +++++++++++++++++++++++++++------
+ 1 file changed, 27 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
+index 63702214b0..8898b235e0 100644
+--- a/grub-core/fs/f2fs.c
++++ b/grub-core/fs/f2fs.c
+@@ -122,6 +122,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ #define F2FS_INLINE_DOTS          0x10  /* File having implicit dot dentries. */
+ 
+ #define MAX_VOLUME_NAME           512
++#define MAX_NAT_BITMAP_SIZE       3900
+ 
+ enum FILE_TYPE
+ {
+@@ -183,7 +184,7 @@ struct grub_f2fs_checkpoint
+   grub_uint32_t                   checksum_offset;
+   grub_uint64_t                   elapsed_time;
+   grub_uint8_t                    alloc_type[MAX_ACTIVE_LOGS];
+-  grub_uint8_t                    sit_nat_version_bitmap[3900];
++  grub_uint8_t                    sit_nat_version_bitmap[MAX_NAT_BITMAP_SIZE];
+   grub_uint32_t                   checksum;
+ } GRUB_PACKED;
+ 
+@@ -302,6 +303,7 @@ struct grub_f2fs_data
+ 
+   struct grub_f2fs_nat_journal    nat_j;
+   char                            *nat_bitmap;
++  grub_uint32_t                   nat_bitmap_size;
+ 
+   grub_disk_t                     disk;
+   struct grub_f2fs_node           *inode;
+@@ -377,15 +379,20 @@ sum_blk_addr (struct grub_f2fs_data *data, int base, int type)
+ }
+ 
+ static void *
+-nat_bitmap_ptr (struct grub_f2fs_data *data)
++nat_bitmap_ptr (struct grub_f2fs_data *data, grub_uint32_t *nat_bitmap_size)
+ {
+   struct grub_f2fs_checkpoint *ckpt = &data->ckpt;
+   grub_uint32_t offset;
++  *nat_bitmap_size = MAX_NAT_BITMAP_SIZE;
+ 
+   if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0)
+     return ckpt->sit_nat_version_bitmap;
+ 
+   offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize);
++  if (offset >= MAX_NAT_BITMAP_SIZE)
++     return NULL;
++
++  *nat_bitmap_size = *nat_bitmap_size - offset;
+ 
+   return ckpt->sit_nat_version_bitmap + offset;
+ }
+@@ -438,11 +445,15 @@ grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len)
+ }
+ 
+ static int
+-grub_f2fs_test_bit (grub_uint32_t nr, const char *p)
++grub_f2fs_test_bit (grub_uint32_t nr, const char *p, grub_uint32_t len)
+ {
+   int mask;
++  grub_uint32_t shifted_nr = (nr >> 3);
+ 
+-  p += (nr >> 3);
++  if (shifted_nr >= len)
++    return -1;
++
++  p += shifted_nr;
+   mask = 1 << (7 - (nr & 0x07));
+ 
+   return mask & *p;
+@@ -662,6 +673,7 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
+   grub_uint32_t seg_off, block_off, entry_off, block_addr;
+   grub_uint32_t blkaddr = 0;
+   grub_err_t err;
++  int result_bit;
+ 
+   err = get_blkaddr_from_nat_journal (data, nid, &blkaddr);
+   if (err != GRUB_ERR_NONE)
+@@ -682,8 +694,15 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
+         ((seg_off * data->blocks_per_seg) << 1) +
+         (block_off & (data->blocks_per_seg - 1));
+ 
+-  if (grub_f2fs_test_bit (block_off, data->nat_bitmap))
++  result_bit = grub_f2fs_test_bit (block_off, data->nat_bitmap,
++                                   data->nat_bitmap_size);
++  if (result_bit > 0)
+     block_addr += data->blocks_per_seg;
++  else if (result_bit == -1)
++    {
++      grub_free (nat_block);
++      return 0;
++    }
+ 
+   err = grub_f2fs_block_read (data, block_addr, nat_block);
+   if (err)
+@@ -833,7 +852,9 @@ grub_f2fs_mount (grub_disk_t disk)
+   if (err)
+     goto fail;
+ 
+-  data->nat_bitmap = nat_bitmap_ptr (data);
++  data->nat_bitmap = nat_bitmap_ptr (data, &data->nat_bitmap_size);
++  if (data->nat_bitmap == NULL)
++    goto fail;
+ 
+   err = get_nat_journal (data);
+   if (err)
diff --git a/SOURCES/0241-video-readers-png-Abort-sooner-if-a-read-operation-f.patch b/SOURCES/0241-video-readers-png-Abort-sooner-if-a-read-operation-f.patch
deleted file mode 100644
index 870f462..0000000
--- a/SOURCES/0241-video-readers-png-Abort-sooner-if-a-read-operation-f.patch
+++ /dev/null
@@ -1,199 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Tue, 6 Jul 2021 14:02:55 +1000
-Subject: [PATCH] video/readers/png: Abort sooner if a read operation fails
-
-Fuzzing revealed some inputs that were taking a long time, potentially
-forever, because they did not bail quickly upon encountering an I/O error.
-
-Try to catch I/O errors sooner and bail out.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 882be97d1df6449b9fd4d593f0cb70005fde3494)
-(cherry picked from commit 3f6fc3ebfd58fcdb3fe6c2f7a5a4fa05772ae786)
----
- grub-core/video/readers/png.c | 55 ++++++++++++++++++++++++++++++++++++-------
- 1 file changed, 47 insertions(+), 8 deletions(-)
-
-diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
-index 0157ff7420..e2a6b1cf3c 100644
---- a/grub-core/video/readers/png.c
-+++ b/grub-core/video/readers/png.c
-@@ -142,6 +142,7 @@ static grub_uint8_t
- grub_png_get_byte (struct grub_png_data *data)
- {
-   grub_uint8_t r;
-+  grub_ssize_t bytes_read = 0;
- 
-   if ((data->inside_idat) && (data->idat_remain == 0))
-     {
-@@ -175,7 +176,14 @@ grub_png_get_byte (struct grub_png_data *data)
-     }
- 
-   r = 0;
--  grub_file_read (data->file, &r, 1);
-+  bytes_read = grub_file_read (data->file, &r, 1);
-+
-+  if (bytes_read != 1)
-+    {
-+      grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		  "png: unexpected end of data");
-+      return 0;
-+    }
- 
-   if (data->inside_idat)
-     data->idat_remain--;
-@@ -231,15 +239,16 @@ grub_png_decode_image_palette (struct grub_png_data *data,
-   if (len == 0)
-     return GRUB_ERR_NONE;
- 
--  for (i = 0; 3 * i < len && i < 256; i++)
-+  grub_errno = GRUB_ERR_NONE;
-+  for (i = 0; 3 * i < len && i < 256 && grub_errno == GRUB_ERR_NONE; i++)
-     for (j = 0; j < 3; j++)
-       data->palette[i][j] = grub_png_get_byte (data);
--  for (i *= 3; i < len; i++)
-+  for (i *= 3; i < len && grub_errno == GRUB_ERR_NONE; i++)
-     grub_png_get_byte (data);
- 
-   grub_png_get_dword (data);
- 
--  return GRUB_ERR_NONE;
-+  return grub_errno;
- }
- 
- static grub_err_t
-@@ -256,9 +265,13 @@ grub_png_decode_image_header (struct grub_png_data *data)
-     return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size");
- 
-   color_bits = grub_png_get_byte (data);
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
-   data->is_16bit = (color_bits == 16);
- 
-   color_type = grub_png_get_byte (data);
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
- 
-   /* According to PNG spec, no other types are valid.  */
-   if ((color_type & ~(PNG_COLOR_MASK_ALPHA | PNG_COLOR_MASK_COLOR))
-@@ -340,14 +353,20 @@ grub_png_decode_image_header (struct grub_png_data *data)
-   if (grub_png_get_byte (data) != PNG_COMPRESSION_BASE)
-     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
- 		       "png: compression method not supported");
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
- 
-   if (grub_png_get_byte (data) != PNG_FILTER_TYPE_BASE)
-     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
- 		       "png: filter method not supported");
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
- 
-   if (grub_png_get_byte (data) != PNG_INTERLACE_NONE)
-     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
- 		       "png: interlace method not supported");
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
- 
-   /* Skip crc checksum.  */
-   grub_png_get_dword (data);
-@@ -449,7 +468,7 @@ grub_png_get_huff_code (struct grub_png_data *data, struct huff_table *ht)
-   int code, i;
- 
-   code = 0;
--  for (i = 0; i < ht->max_length; i++)
-+  for (i = 0; i < ht->max_length && grub_errno == GRUB_ERR_NONE; i++)
-     {
-       code = (code << 1) + grub_png_get_bits (data, 1);
-       if (code < ht->maxval[i])
-@@ -504,8 +523,14 @@ grub_png_init_dynamic_block (struct grub_png_data *data)
-   grub_uint8_t lens[DEFLATE_HCLEN_MAX];
- 
-   nl = DEFLATE_HLIT_BASE + grub_png_get_bits (data, 5);
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
-   nd = DEFLATE_HDIST_BASE + grub_png_get_bits (data, 5);
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
-   nb = DEFLATE_HCLEN_BASE + grub_png_get_bits (data, 4);
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
- 
-   if ((nl > DEFLATE_HLIT_MAX) || (nd > DEFLATE_HDIST_MAX) ||
-       (nb > DEFLATE_HCLEN_MAX))
-@@ -533,7 +558,7 @@ grub_png_init_dynamic_block (struct grub_png_data *data)
- 			    data->dist_offset);
- 
-   prev = 0;
--  for (i = 0; i < nl + nd; i++)
-+  for (i = 0; i < nl + nd && grub_errno == GRUB_ERR_NONE; i++)
-     {
-       int n, code;
-       struct huff_table *ht;
-@@ -721,17 +746,21 @@ grub_png_read_dynamic_block (struct grub_png_data *data)
- 	  len = cplens[n];
- 	  if (cplext[n])
- 	    len += grub_png_get_bits (data, cplext[n]);
-+	  if (grub_errno != GRUB_ERR_NONE)
-+	    return grub_errno;
- 
- 	  n = grub_png_get_huff_code (data, &data->dist_table);
- 	  dist = cpdist[n];
- 	  if (cpdext[n])
- 	    dist += grub_png_get_bits (data, cpdext[n]);
-+	  if (grub_errno != GRUB_ERR_NONE)
-+	    return grub_errno;
- 
- 	  pos = data->wp - dist;
- 	  if (pos < 0)
- 	    pos += WSIZE;
- 
--	  while (len > 0)
-+	  while (len > 0 && grub_errno == GRUB_ERR_NONE)
- 	    {
- 	      data->slide[data->wp] = data->slide[pos];
- 	      grub_png_output_byte (data, data->slide[data->wp]);
-@@ -759,7 +788,11 @@ grub_png_decode_image_data (struct grub_png_data *data)
-   int final;
- 
-   cmf = grub_png_get_byte (data);
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
-   flg = grub_png_get_byte (data);
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
- 
-   if ((cmf & 0xF) != Z_DEFLATED)
-     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-@@ -774,7 +807,11 @@ grub_png_decode_image_data (struct grub_png_data *data)
-       int block_type;
- 
-       final = grub_png_get_bits (data, 1);
-+      if (grub_errno != GRUB_ERR_NONE)
-+	return grub_errno;
-       block_type = grub_png_get_bits (data, 2);
-+      if (grub_errno != GRUB_ERR_NONE)
-+	return grub_errno;
- 
-       switch (block_type)
- 	{
-@@ -790,7 +827,7 @@ grub_png_decode_image_data (struct grub_png_data *data)
- 	    grub_png_get_byte (data);
- 	    grub_png_get_byte (data);
- 
--	    for (i = 0; i < len; i++)
-+	    for (i = 0; i < len && grub_errno == GRUB_ERR_NONE; i++)
- 	      grub_png_output_byte (data, grub_png_get_byte (data));
- 
- 	    break;
-@@ -1045,6 +1082,8 @@ grub_png_decode_png (struct grub_png_data *data)
- 
-       len = grub_png_get_dword (data);
-       type = grub_png_get_dword (data);
-+      if (grub_errno != GRUB_ERR_NONE)
-+	break;
-       data->next_offset = data->file->offset + len + 4;
- 
-       switch (type)
diff --git a/SOURCES/0242-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch b/SOURCES/0242-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch
new file mode 100644
index 0000000..0553d60
--- /dev/null
+++ b/SOURCES/0242-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch
@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
+Date: Wed, 6 Apr 2022 18:17:43 +0530
+Subject: [PATCH] fs/f2fs: Do not copy file names that are too long
+
+A corrupt f2fs file system might specify a name length which is greater
+than the maximum name length supported by the GRUB f2fs driver.
+
+We will allocate enough memory to store the overly long name, but there
+are only F2FS_NAME_LEN bytes in the source, so we would read past the end
+of the source.
+
+While checking directory entries, do not copy a file name with an invalid
+length.
+
+Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 9a891f638509e031d322c94e3cbcf38d36f3993a)
+---
+ grub-core/fs/f2fs.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
+index 8898b235e0..df6beb544c 100644
+--- a/grub-core/fs/f2fs.c
++++ b/grub-core/fs/f2fs.c
+@@ -1003,6 +1003,10 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx)
+ 
+       ftype = ctx->dentry[i].file_type;
+       name_len = grub_le_to_cpu16 (ctx->dentry[i].name_len);
++
++      if (name_len >= F2FS_NAME_LEN)
++        return 0;
++
+       filename = grub_malloc (name_len + 1);
+       if (!filename)
+         return 0;
diff --git a/SOURCES/0242-video-readers-png-Refuse-to-handle-multiple-image-he.patch b/SOURCES/0242-video-readers-png-Refuse-to-handle-multiple-image-he.patch
deleted file mode 100644
index 52832da..0000000
--- a/SOURCES/0242-video-readers-png-Refuse-to-handle-multiple-image-he.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Tue, 6 Jul 2021 14:13:40 +1000
-Subject: [PATCH] video/readers/png: Refuse to handle multiple image headers
-
-This causes the bitmap to be leaked. Do not permit multiple image headers.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 8ce433557adeadbc46429aabb9f850b02ad2bdfb)
-(cherry picked from commit 6e10bba6a4cbfd6c7bf116f41fd4e037465e19d8)
----
- grub-core/video/readers/png.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
-index e2a6b1cf3c..8955b8ecfd 100644
---- a/grub-core/video/readers/png.c
-+++ b/grub-core/video/readers/png.c
-@@ -258,6 +258,9 @@ grub_png_decode_image_header (struct grub_png_data *data)
-   int color_bits;
-   enum grub_video_blit_format blt;
- 
-+  if (data->image_width || data->image_height)
-+    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: two image headers found");
-+
-   data->image_width = grub_png_get_dword (data);
-   data->image_height = grub_png_get_dword (data);
- 
diff --git a/SOURCES/0243-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch b/SOURCES/0243-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch
new file mode 100644
index 0000000..7ff5821
--- /dev/null
+++ b/SOURCES/0243-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch
@@ -0,0 +1,79 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Darren Kenny <darren.kenny@oracle.com>
+Date: Tue, 29 Mar 2022 10:49:56 +0000
+Subject: [PATCH] fs/btrfs: Fix several fuzz issues with invalid dir item
+ sizing
+
+According to the btrfs code in Linux, the structure of a directory item
+leaf should be of the form:
+
+  |struct btrfs_dir_item|name|data|
+
+in GRUB the name len and data len are in the grub_btrfs_dir_item
+structure's n and m fields respectively.
+
+The combined size of the structure, name and data should be less than
+the allocated memory, a difference to the Linux kernel's struct
+btrfs_dir_item is that the grub_btrfs_dir_item has an extra field for
+where the name is stored, so we adjust for that too.
+
+Signed-off-by: Darren Kenny <darren.kenny@oracle.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 6d3f06c0b6a8992b9b1bb0e62af93ac5ff2781f0)
+[rharwood: we've an extra variable here]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/fs/btrfs.c | 26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index 07c0ff874b..2fcfb738fe 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -2254,6 +2254,7 @@ grub_btrfs_dir (grub_device_t device, const char *path,
+   grub_uint64_t tree;
+   grub_uint8_t type;
+   char *new_path = NULL;
++  grub_size_t est_size = 0;
+ 
+   if (!data)
+     return grub_errno;
+@@ -2320,6 +2321,18 @@ grub_btrfs_dir (grub_device_t device, const char *path,
+ 	  break;
+ 	}
+ 
++      if (direl == NULL ||
++	  grub_add (grub_le_to_cpu16 (direl->n),
++		    grub_le_to_cpu16 (direl->m), &est_size) ||
++	  grub_add (est_size, sizeof (*direl), &est_size) ||
++	  grub_sub (est_size, sizeof (direl->name), &est_size) ||
++	  est_size > allocated)
++       {
++         grub_errno = GRUB_ERR_OUT_OF_RANGE;
++         r = -grub_errno;
++         goto out;
++       }
++
+       for (cdirel = direl;
+ 	   (grub_uint8_t *) cdirel - (grub_uint8_t *) direl
+ 	   < (grub_ssize_t) elemsize;
+@@ -2330,6 +2343,19 @@ grub_btrfs_dir (grub_device_t device, const char *path,
+ 	  char c;
+ 	  struct grub_btrfs_inode inode;
+ 	  struct grub_dirhook_info info;
++
++	  if (cdirel == NULL ||
++	      grub_add (grub_le_to_cpu16 (cdirel->n),
++			grub_le_to_cpu16 (cdirel->m), &est_size) ||
++	      grub_add (est_size, sizeof (*cdirel), &est_size) ||
++	      grub_sub (est_size, sizeof (cdirel->name), &est_size) ||
++	      est_size > allocated)
++	   {
++	     grub_errno = GRUB_ERR_OUT_OF_RANGE;
++	     r = -grub_errno;
++	     goto out;
++	   }
++
+ 	  err = grub_btrfs_read_inode (data, &inode, cdirel->key.object_id,
+ 				       tree);
+ 	  grub_memset (&info, 0, sizeof (info));
diff --git a/SOURCES/0243-video-readers-png-Drop-greyscale-support-to-fix-heap.patch b/SOURCES/0243-video-readers-png-Drop-greyscale-support-to-fix-heap.patch
deleted file mode 100644
index c639780..0000000
--- a/SOURCES/0243-video-readers-png-Drop-greyscale-support-to-fix-heap.patch
+++ /dev/null
@@ -1,171 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Tue, 6 Jul 2021 18:51:35 +1000
-Subject: [PATCH] video/readers/png: Drop greyscale support to fix heap
- out-of-bounds write
-
-A 16-bit greyscale PNG without alpha is processed in the following loop:
-
-      for (i = 0; i < (data->image_width * data->image_height);
-	   i++, d1 += 4, d2 += 2)
-	{
-	  d1[R3] = d2[1];
-	  d1[G3] = d2[1];
-	  d1[B3] = d2[1];
-	}
-
-The increment of d1 is wrong. d1 is incremented by 4 bytes per iteration,
-but there are only 3 bytes allocated for storage. This means that image
-data will overwrite somewhat-attacker-controlled parts of memory - 3 bytes
-out of every 4 following the end of the image.
-
-This has existed since greyscale support was added in 2013 in commit
-3ccf16dff98f (grub-core/video/readers/png.c: Support grayscale).
-
-Saving starfield.png as a 16-bit greyscale image without alpha in the gimp
-and attempting to load it causes grub-emu to crash - I don't think this code
-has ever worked.
-
-Delete all PNG greyscale support.
-
-Fixes: CVE-2021-3695
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 0e1d163382669bd734439d8864ee969616d971d9)
-[rharwood: context conflict]
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
-(cherry picked from commit 4c631c8119206b3178912df2905434d967661c3d)
----
- grub-core/video/readers/png.c | 85 +++----------------------------------------
- 1 file changed, 6 insertions(+), 79 deletions(-)
-
-diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
-index 8955b8ecfd..a3161e25b6 100644
---- a/grub-core/video/readers/png.c
-+++ b/grub-core/video/readers/png.c
-@@ -100,7 +100,7 @@ struct grub_png_data
- 
-   unsigned image_width, image_height;
-   int bpp, is_16bit;
--  int raw_bytes, is_gray, is_alpha, is_palette;
-+  int raw_bytes, is_alpha, is_palette;
-   int row_bytes, color_bits;
-   grub_uint8_t *image_data;
- 
-@@ -296,13 +296,13 @@ grub_png_decode_image_header (struct grub_png_data *data)
-     data->bpp = 3;
-   else
-     {
--      data->is_gray = 1;
--      data->bpp = 1;
-+      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			 "png: color type not supported");
-     }
- 
-   if ((color_bits != 8) && (color_bits != 16)
-       && (color_bits != 4
--	  || !(data->is_gray || data->is_palette)))
-+	  || !data->is_palette))
-     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-                        "png: bit depth must be 8 or 16");
- 
-@@ -331,7 +331,7 @@ grub_png_decode_image_header (struct grub_png_data *data)
-     }
- 
- #ifndef GRUB_CPU_WORDS_BIGENDIAN
--  if (data->is_16bit || data->is_gray || data->is_palette)
-+  if (data->is_16bit || data->is_palette)
- #endif
-     {
-       data->image_data = grub_calloc (data->image_height, data->row_bytes);
-@@ -899,27 +899,8 @@ grub_png_convert_image (struct grub_png_data *data)
-       int shift;
-       int mask = (1 << data->color_bits) - 1;
-       unsigned j;
--      if (data->is_gray)
--	{
--	  /* Generic formula is
--	     (0xff * i) / ((1U << data->color_bits) - 1)
--	     but for allowed bit depth of 1, 2 and for it's
--	     equivalent to
--	     (0xff / ((1U << data->color_bits) - 1)) * i
--	     Precompute the multipliers to avoid division.
--	  */
- 
--	  const grub_uint8_t multipliers[5] = { 0xff, 0xff, 0x55, 0x24, 0x11 };
--	  for (i = 0; i < (1U << data->color_bits); i++)
--	    {
--	      grub_uint8_t col = multipliers[data->color_bits] * i;
--	      palette[i][0] = col;
--	      palette[i][1] = col;
--	      palette[i][2] = col;
--	    }
--	}
--      else
--	grub_memcpy (palette, data->palette, 3 << data->color_bits);
-+      grub_memcpy (palette, data->palette, 3 << data->color_bits);
-       d1c = d1;
-       d2c = d2;
-       for (j = 0; j < data->image_height; j++, d1c += data->image_width * 3,
-@@ -956,60 +937,6 @@ grub_png_convert_image (struct grub_png_data *data)
- 	}
-       return;
-     }
--  
--  if (data->is_gray)
--    {
--      switch (data->bpp)
--	{
--	case 4:
--	  /* 16-bit gray with alpha.  */
--	  for (i = 0; i < (data->image_width * data->image_height);
--	       i++, d1 += 4, d2 += 4)
--	    {
--	      d1[R4] = d2[3];
--	      d1[G4] = d2[3];
--	      d1[B4] = d2[3];
--	      d1[A4] = d2[1];
--	    }
--	  break;
--	case 2:
--	  if (data->is_16bit)
--	    /* 16-bit gray without alpha.  */
--	    {
--	      for (i = 0; i < (data->image_width * data->image_height);
--		   i++, d1 += 4, d2 += 2)
--		{
--		  d1[R3] = d2[1];
--		  d1[G3] = d2[1];
--		  d1[B3] = d2[1];
--		}
--	    }
--	  else
--	    /* 8-bit gray with alpha.  */
--	    {
--	      for (i = 0; i < (data->image_width * data->image_height);
--		   i++, d1 += 4, d2 += 2)
--		{
--		  d1[R4] = d2[1];
--		  d1[G4] = d2[1];
--		  d1[B4] = d2[1];
--		  d1[A4] = d2[0];
--		}
--	    }
--	  break;
--	  /* 8-bit gray without alpha.  */
--	case 1:
--	  for (i = 0; i < (data->image_width * data->image_height);
--	       i++, d1 += 3, d2++)
--	    {
--	      d1[R3] = d2[0];
--	      d1[G3] = d2[0];
--	      d1[B3] = d2[0];
--	    }
--	  break;
--	}
--      return;
--    }
- 
-     {
-   /* Only copy the upper 8 bit.  */
diff --git a/SOURCES/0244-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch b/SOURCES/0244-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch
new file mode 100644
index 0000000..d638c11
--- /dev/null
+++ b/SOURCES/0244-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch
@@ -0,0 +1,134 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Darren Kenny <darren.kenny@oracle.com>
+Date: Tue, 29 Mar 2022 15:52:46 +0000
+Subject: [PATCH] fs/btrfs: Fix more ASAN and SEGV issues found with fuzzing
+
+The fuzzer is generating btrfs file systems that have chunks with
+invalid combinations of stripes and substripes for the given RAID
+configurations.
+
+After examining the Linux kernel fs/btrfs/tree-checker.c code, it
+appears that sub-stripes should only be applied to RAID10, and in that
+case there should only ever be 2 of them.
+
+Similarly, RAID single should only have 1 stripe, and RAID1/1C3/1C4
+should have 2. 3 or 4 stripes respectively, which is what redundancy
+corresponds.
+
+Some of the chunks ended up with a size of 0, which grub_malloc() still
+returned memory for and in turn generated ASAN errors later when
+accessed.
+
+While it would be possible to specifically limit the number of stripes,
+a more correct test was on the combination of the chunk item, and the
+number of stripes by the size of the chunk stripe structure in
+comparison to the size of the chunk itself.
+
+Signed-off-by: Darren Kenny <darren.kenny@oracle.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 3849647b4b98a4419366708fc4b7f339c6f55ec7)
+---
+ grub-core/fs/btrfs.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 55 insertions(+)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index 2fcfb738fe..0e9b450413 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -941,6 +941,12 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
+ 	return grub_error (GRUB_ERR_BAD_FS,
+ 			   "couldn't find the chunk descriptor");
+ 
++      if (!chsize)
++	{
++	  grub_dprintf ("btrfs", "zero-size chunk\n");
++	  return grub_error (GRUB_ERR_BAD_FS,
++			     "got an invalid zero-size chunk");
++	}
+       chunk = grub_malloc (chsize);
+       if (!chunk)
+ 	return grub_errno;
+@@ -999,6 +1005,16 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
+ 	      stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size),
+ 					     nstripes,
+ 					     NULL);
++
++	      /* For single, there should be exactly 1 stripe. */
++	      if (grub_le_to_cpu16 (chunk->nstripes) != 1)
++		{
++		  grub_dprintf ("btrfs", "invalid RAID_SINGLE: nstripes != 1 (%u)\n",
++				grub_le_to_cpu16 (chunk->nstripes));
++		  return grub_error (GRUB_ERR_BAD_FS,
++				     "invalid RAID_SINGLE: nstripes != 1 (%u)",
++				      grub_le_to_cpu16 (chunk->nstripes));
++		}
+ 	      if (stripe_length == 0)
+ 		stripe_length = 512;
+ 	      stripen = grub_divmod64 (off, stripe_length, &stripe_offset);
+@@ -1018,6 +1034,19 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
+ 	      stripen = 0;
+ 	      stripe_offset = off;
+ 	      csize = grub_le_to_cpu64 (chunk->size) - off;
++
++             /*
++	      * Redundancy, and substripes only apply to RAID10, and there
++	      * should be exactly 2 sub-stripes.
++	      */
++	     if (grub_le_to_cpu16 (chunk->nstripes) != redundancy)
++               {
++                 grub_dprintf ("btrfs", "invalid RAID1: nstripes != %u (%u)\n",
++                               redundancy, grub_le_to_cpu16 (chunk->nstripes));
++                 return grub_error (GRUB_ERR_BAD_FS,
++                                    "invalid RAID1: nstripes != %u (%u)",
++                                    redundancy, grub_le_to_cpu16 (chunk->nstripes));
++               }
+ 	      break;
+ 	    }
+ 	  case GRUB_BTRFS_CHUNK_TYPE_RAID0:
+@@ -1054,6 +1083,20 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
+ 	      stripe_offset = low + chunk_stripe_length
+ 		* high;
+ 	      csize = chunk_stripe_length - low;
++
++	      /*
++	       * Substripes only apply to RAID10, and there
++	       * should be exactly 2 sub-stripes.
++	       */
++	      if (grub_le_to_cpu16 (chunk->nsubstripes) != 2)
++		{
++		  grub_dprintf ("btrfs", "invalid RAID10: nsubstripes != 2 (%u)",
++				grub_le_to_cpu16 (chunk->nsubstripes));
++		  return grub_error (GRUB_ERR_BAD_FS,
++				     "invalid RAID10: nsubstripes != 2 (%u)",
++				     grub_le_to_cpu16 (chunk->nsubstripes));
++		}
++
+ 	      break;
+ 	    }
+ 	  case GRUB_BTRFS_CHUNK_TYPE_RAID5:
+@@ -1153,6 +1196,8 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
+ 
+ 	for (j = 0; j < 2; j++)
+ 	  {
++	    grub_size_t est_chunk_alloc = 0;
++
+ 	    grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
+ 			  "+0x%" PRIxGRUB_UINT64_T
+ 			  " (%d stripes (%d substripes) of %"
+@@ -1165,6 +1210,16 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
+ 	    grub_dprintf ("btrfs", "reading laddr 0x%" PRIxGRUB_UINT64_T "\n",
+ 			  addr);
+ 
++	    if (grub_mul (sizeof (struct grub_btrfs_chunk_stripe),
++			  grub_le_to_cpu16 (chunk->nstripes), &est_chunk_alloc) ||
++		grub_add (est_chunk_alloc,
++			  sizeof (struct grub_btrfs_chunk_item), &est_chunk_alloc) ||
++		est_chunk_alloc > chunk->size)
++	      {
++		err = GRUB_ERR_BAD_FS;
++		break;
++	      }
++
+ 	    if (is_raid56)
+ 	      {
+ 		err = btrfs_read_from_chunk (data, chunk, stripen,
diff --git a/SOURCES/0244-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch b/SOURCES/0244-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch
deleted file mode 100644
index c1e232e..0000000
--- a/SOURCES/0244-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Tue, 6 Jul 2021 23:25:07 +1000
-Subject: [PATCH] video/readers/png: Avoid heap OOB R/W inserting huff table
- items
-
-In fuzzing we observed crashes where a code would attempt to be inserted
-into a huffman table before the start, leading to a set of heap OOB reads
-and writes as table entries with negative indices were shifted around and
-the new code written in.
-
-Catch the case where we would underflow the array and bail.
-
-Fixes: CVE-2021-3696
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 1ae9a91d42cb40da8a6f11fac65541858e340afa)
-(cherry picked from commit 132ccc681cf642ad748580f26b54c9259a7f43fd)
----
- grub-core/video/readers/png.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
-diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
-index a3161e25b6..d7ed5aa6cf 100644
---- a/grub-core/video/readers/png.c
-+++ b/grub-core/video/readers/png.c
-@@ -438,6 +438,13 @@ grub_png_insert_huff_item (struct huff_table *ht, int code, int len)
-   for (i = len; i < ht->max_length; i++)
-     n += ht->maxval[i];
- 
-+  if (n > ht->num_values)
-+    {
-+      grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		  "png: out of range inserting huffman table item");
-+      return;
-+    }
-+
-   for (i = 0; i < n; i++)
-     ht->values[ht->num_values - i] = ht->values[ht->num_values - i - 1];
- 
diff --git a/SOURCES/0245-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch b/SOURCES/0245-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch
new file mode 100644
index 0000000..2e5145f
--- /dev/null
+++ b/SOURCES/0245-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch
@@ -0,0 +1,75 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Darren Kenny <darren.kenny@oracle.com>
+Date: Thu, 7 Apr 2022 15:18:12 +0000
+Subject: [PATCH] fs/btrfs: Fix more fuzz issues related to chunks
+
+The corpus we generating issues in grub_btrfs_read_logical() when
+attempting to iterate over nstripes entries in the boot mapping.
+
+In most cases the reason for the failure was that the number of strips
+exceeded the possible space statically allocated in superblock bootmapping
+space. Each stripe entry in the bootmapping block consists of
+a grub_btrfs_key followed by a grub_btrfs_chunk_stripe.
+
+Another issue that came up was that while calculating the chunk size,
+in an earlier piece of code in that function, depending on the data
+provided in the btrfs file system, it would end up calculating a size
+that was too small to contain even 1 grub_btrfs_chunk_item, which is
+obviously invalid too.
+
+Signed-off-by: Darren Kenny <darren.kenny@oracle.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit e00cd76cbadcc897a9cc4087cb2fcb5dbe15e596)
+---
+ grub-core/fs/btrfs.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index 0e9b450413..47325f6ad7 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -947,6 +947,17 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
+ 	  return grub_error (GRUB_ERR_BAD_FS,
+ 			     "got an invalid zero-size chunk");
+ 	}
++
++      /*
++       * The space being allocated for a chunk should at least be able to
++       * contain one chunk item.
++       */
++      if (chsize < sizeof (struct grub_btrfs_chunk_item))
++       {
++         grub_dprintf ("btrfs", "chunk-size too small\n");
++         return grub_error (GRUB_ERR_BAD_FS,
++                            "got an invalid chunk size");
++       }
+       chunk = grub_malloc (chsize);
+       if (!chunk)
+ 	return grub_errno;
+@@ -1194,6 +1205,13 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
+ 	if (csize > (grub_uint64_t) size)
+ 	  csize = size;
+ 
++	/*
++	 * The space for a chunk stripe is limited to the space provide in the super-block's
++	 * bootstrap mapping with an initial btrfs key at the start of each chunk.
++	 */
++	grub_size_t avail_stripes = sizeof (data->sblock.bootstrap_mapping) /
++	  (sizeof (struct grub_btrfs_key) + sizeof (struct grub_btrfs_chunk_stripe));
++
+ 	for (j = 0; j < 2; j++)
+ 	  {
+ 	    grub_size_t est_chunk_alloc = 0;
+@@ -1220,6 +1238,12 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
+ 		break;
+ 	      }
+ 
++	   if (grub_le_to_cpu16 (chunk->nstripes) > avail_stripes)
++             {
++               err = GRUB_ERR_BAD_FS;
++               break;
++             }
++
+ 	    if (is_raid56)
+ 	      {
+ 		err = btrfs_read_from_chunk (data, chunk, stripen,
diff --git a/SOURCES/0245-video-readers-png-Sanity-check-some-huffman-codes.patch b/SOURCES/0245-video-readers-png-Sanity-check-some-huffman-codes.patch
deleted file mode 100644
index 01d6333..0000000
--- a/SOURCES/0245-video-readers-png-Sanity-check-some-huffman-codes.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Tue, 6 Jul 2021 19:19:11 +1000
-Subject: [PATCH] video/readers/png: Sanity check some huffman codes
-
-ASAN picked up two OOB global reads: we weren't checking if some code
-values fit within the cplens or cpdext arrays. Check and throw an error
-if not.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit c3a8ab0cbd24153ec7b1f84a96ddfdd72ef8d117)
-(cherry picked from commit 5d09addf58086aa11d5f9a91af5632ff87c2d2ee)
----
- grub-core/video/readers/png.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
-index d7ed5aa6cf..7f2ba7849b 100644
---- a/grub-core/video/readers/png.c
-+++ b/grub-core/video/readers/png.c
-@@ -753,6 +753,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data)
- 	  int len, dist, pos;
- 
- 	  n -= 257;
-+	  if (((unsigned int) n) >= ARRAY_SIZE (cplens))
-+	    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			       "png: invalid huff code");
- 	  len = cplens[n];
- 	  if (cplext[n])
- 	    len += grub_png_get_bits (data, cplext[n]);
-@@ -760,6 +763,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data)
- 	    return grub_errno;
- 
- 	  n = grub_png_get_huff_code (data, &data->dist_table);
-+	  if (((unsigned int) n) >= ARRAY_SIZE (cpdist))
-+	    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			       "png: invalid huff code");
- 	  dist = cpdist[n];
- 	  if (cpdext[n])
- 	    dist += grub_png_get_bits (data, cpdext[n]);
diff --git a/SOURCES/0246-misc-Make-grub_min-and-grub_max-more-resilient.patch b/SOURCES/0246-misc-Make-grub_min-and-grub_max-more-resilient.patch
new file mode 100644
index 0000000..eb2e8fd
--- /dev/null
+++ b/SOURCES/0246-misc-Make-grub_min-and-grub_max-more-resilient.patch
@@ -0,0 +1,83 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 21 Mar 2022 16:06:10 -0400
+Subject: [PATCH] misc: Make grub_min() and grub_max() more resilient.
+
+grub_min(a,b) and grub_max(a,b) use a relatively naive implementation
+which leads to several problems:
+- they evaluate their parameters more than once
+- the naive way to address this, to declare temporary variables in a
+  statement-expression, isn't resilient against nested uses, because
+  MIN(a,MIN(b,c)) results in the temporary variables being declared in
+  two nested scopes, which may result in a build warning depending on
+  your build options.
+
+This patch changes our implementation to use a statement-expression
+inside a helper macro, and creates the symbols for the temporary
+variables with __COUNTER__ (A GNU C cpp extension) and token pasting to
+create uniquely named internal variables.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/multiboot_elfxx.c |  4 +---
+ include/grub/misc.h                | 25 +++++++++++++++++++++++--
+ 2 files changed, 24 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c
+index f2318e0d16..87f6e31aa6 100644
+--- a/grub-core/loader/multiboot_elfxx.c
++++ b/grub-core/loader/multiboot_elfxx.c
+@@ -35,9 +35,7 @@
+ #endif
+ 
+ #include <grub/i386/relocator.h>
+-
+-#define CONCAT(a,b)	CONCAT_(a, b)
+-#define CONCAT_(a,b)	a ## b
++#include <grub/misc.h>
+ 
+ #pragma GCC diagnostic ignored "-Wcast-align"
+ 
+diff --git a/include/grub/misc.h b/include/grub/misc.h
+index 6c4aa85ac5..cf84aec1db 100644
+--- a/include/grub/misc.h
++++ b/include/grub/misc.h
+@@ -35,6 +35,14 @@
+ #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
+ #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; }
+ 
++#ifndef CONCAT_
++#define CONCAT_(a, b) a ## b
++#endif
++
++#ifndef CONCAT
++#define CONCAT(a, b) CONCAT_(a, b)
++#endif
++
+ #define grub_dprintf(condition, ...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, __VA_ARGS__)
+ 
+ void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t n);
+@@ -498,8 +506,21 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file,
+ #define grub_boot_time(...)
+ #endif
+ 
+-#define grub_max(a, b) (((a) > (b)) ? (a) : (b))
+-#define grub_min(a, b) (((a) < (b)) ? (a) : (b))
++#define _grub_min(a, b, _a, _b)						      \
++  ({ typeof (a) _a = (a);						      \
++     typeof (b) _b = (b);						      \
++     _a < _b ? _a : _b; })
++#define grub_min(a, b) _grub_min(a, b,					      \
++				 CONCAT(_a_,__COUNTER__),		      \
++				 CONCAT(_b_,__COUNTER__))
++
++#define _grub_max(a, b, _a, _b)						      \
++  ({ typeof (a) _a = (a);						      \
++     typeof (b) _b = (b);						      \
++     _a > _b ? _a : _b; })
++#define grub_max(a, b) _grub_max(a, b,					      \
++				 CONCAT(_a_,__COUNTER__),		      \
++				 CONCAT(_b_,__COUNTER__))
+ 
+ #define grub_log2ull(n) (GRUB_TYPE_BITS (grub_uint64_t) - __builtin_clzll (n) - 1)
+ 
diff --git a/SOURCES/0246-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch b/SOURCES/0246-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch
deleted file mode 100644
index e03b6d9..0000000
--- a/SOURCES/0246-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch
+++ /dev/null
@@ -1,256 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Mon, 28 Jun 2021 14:16:14 +1000
-Subject: [PATCH] video/readers/jpeg: Abort sooner if a read operation fails
-
-Fuzzing revealed some inputs that were taking a long time, potentially
-forever, because they did not bail quickly upon encountering an I/O error.
-
-Try to catch I/O errors sooner and bail out.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit ab2e5d2e4bff488bbb557ed435a61ae102ef9f0c)
-(cherry picked from commit 1ff8df0d2dea8ec7c8575241d5e7d6622c204ec3)
----
- grub-core/video/readers/jpeg.c | 86 ++++++++++++++++++++++++++++++++++--------
- 1 file changed, 70 insertions(+), 16 deletions(-)
-
-diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
-index e31602f766..10225abd53 100644
---- a/grub-core/video/readers/jpeg.c
-+++ b/grub-core/video/readers/jpeg.c
-@@ -109,9 +109,17 @@ static grub_uint8_t
- grub_jpeg_get_byte (struct grub_jpeg_data *data)
- {
-   grub_uint8_t r;
-+  grub_ssize_t bytes_read;
- 
-   r = 0;
--  grub_file_read (data->file, &r, 1);
-+  bytes_read = grub_file_read (data->file, &r, 1);
-+
-+  if (bytes_read != 1)
-+    {
-+      grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		  "jpeg: unexpected end of data");
-+      return 0;
-+    }
- 
-   return r;
- }
-@@ -120,9 +128,17 @@ static grub_uint16_t
- grub_jpeg_get_word (struct grub_jpeg_data *data)
- {
-   grub_uint16_t r;
-+  grub_ssize_t bytes_read;
- 
-   r = 0;
--  grub_file_read (data->file, &r, sizeof (grub_uint16_t));
-+  bytes_read = grub_file_read (data->file, &r, sizeof (grub_uint16_t));
-+
-+  if (bytes_read != sizeof (grub_uint16_t))
-+    {
-+      grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		  "jpeg: unexpected end of data");
-+      return 0;
-+    }
- 
-   return grub_be_to_cpu16 (r);
- }
-@@ -135,6 +151,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data)
-   if (data->bit_mask == 0)
-     {
-       data->bit_save = grub_jpeg_get_byte (data);
-+      if (grub_errno != GRUB_ERR_NONE) {
-+	grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		    "jpeg: file read error");
-+	return 0;
-+      }
-       if (data->bit_save == JPEG_ESC_CHAR)
- 	{
- 	  if (grub_jpeg_get_byte (data) != 0)
-@@ -143,6 +164,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data)
- 			  "jpeg: invalid 0xFF in data stream");
- 	      return 0;
- 	    }
-+	  if (grub_errno != GRUB_ERR_NONE)
-+	    {
-+	      grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: file read error");
-+	      return 0;
-+	    }
- 	}
-       data->bit_mask = 0x80;
-     }
-@@ -161,7 +187,7 @@ grub_jpeg_get_number (struct grub_jpeg_data *data, int num)
-     return 0;
- 
-   msb = value = grub_jpeg_get_bit (data);
--  for (i = 1; i < num; i++)
-+  for (i = 1; i < num && grub_errno == GRUB_ERR_NONE; i++)
-     value = (value << 1) + (grub_jpeg_get_bit (data) != 0);
-   if (!msb)
-     value += 1 - (1 << num);
-@@ -202,6 +228,8 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data)
-   while (data->file->offset + sizeof (count) + 1 <= next_marker)
-     {
-       id = grub_jpeg_get_byte (data);
-+      if (grub_errno != GRUB_ERR_NONE)
-+	return grub_errno;
-       ac = (id >> 4) & 1;
-       id &= 0xF;
-       if (id > 1)
-@@ -252,6 +280,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data)
- 
-   next_marker = data->file->offset;
-   next_marker += grub_jpeg_get_word (data);
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
- 
-   if (next_marker > data->file->size)
-     {
-@@ -263,6 +293,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data)
- 	 <= next_marker)
-     {
-       id = grub_jpeg_get_byte (data);
-+      if (grub_errno != GRUB_ERR_NONE)
-+        return grub_errno;
-       if (id >= 0x10)		/* Upper 4-bit is precision.  */
- 	return grub_error (GRUB_ERR_BAD_FILE_TYPE,
- 			   "jpeg: only 8-bit precision is supported");
-@@ -294,6 +326,9 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data)
-   next_marker = data->file->offset;
-   next_marker += grub_jpeg_get_word (data);
- 
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
-+
-   if (grub_jpeg_get_byte (data) != 8)
-     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
- 		       "jpeg: only 8-bit precision is supported");
-@@ -319,6 +354,8 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data)
- 	return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index");
- 
-       ss = grub_jpeg_get_byte (data);	/* Sampling factor.  */
-+      if (grub_errno != GRUB_ERR_NONE)
-+	return grub_errno;
-       if (!id)
- 	{
- 	  grub_uint8_t vs, hs;
-@@ -498,7 +535,7 @@ grub_jpeg_idct_transform (jpeg_data_unit_t du)
-     }
- }
- 
--static void
-+static grub_err_t
- grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
- {
-   int h1, h2, qt;
-@@ -513,6 +550,9 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
-   data->dc_value[id] +=
-     grub_jpeg_get_number (data, grub_jpeg_get_huff_code (data, h1));
- 
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
-+
-   du[0] = data->dc_value[id] * (int) data->quan_table[qt][0];
-   pos = 1;
-   while (pos < ARRAY_SIZE (data->quan_table[qt]))
-@@ -527,11 +567,13 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
-       num >>= 4;
-       pos += num;
- 
-+      if (grub_errno != GRUB_ERR_NONE)
-+        return grub_errno;
-+
-       if (pos >= ARRAY_SIZE (jpeg_zigzag_order))
- 	{
--	  grub_error (GRUB_ERR_BAD_FILE_TYPE,
--		      "jpeg: invalid position in zigzag order!?");
--	  return;
-+	  return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			     "jpeg: invalid position in zigzag order!?");
- 	}
- 
-       du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos];
-@@ -539,6 +581,7 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
-     }
- 
-   grub_jpeg_idct_transform (du);
-+  return GRUB_ERR_NONE;
- }
- 
- static void
-@@ -597,7 +640,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
-   data_offset += grub_jpeg_get_word (data);
- 
-   cc = grub_jpeg_get_byte (data);
--
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
-   if (cc != 3 && cc != 1)
-     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
- 		       "jpeg: component count must be 1 or 3");
-@@ -610,7 +654,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
-       id = grub_jpeg_get_byte (data) - 1;
-       if ((id < 0) || (id >= 3))
- 	return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index");
--
-+      if (grub_errno != GRUB_ERR_NONE)
-+	return grub_errno;
-       ht = grub_jpeg_get_byte (data);
-       data->comp_index[id][1] = (ht >> 4);
-       data->comp_index[id][2] = (ht & 0xF) + 2;
-@@ -618,11 +663,14 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
-       if ((data->comp_index[id][1] < 0) || (data->comp_index[id][1] > 3) ||
- 	  (data->comp_index[id][2] < 0) || (data->comp_index[id][2] > 3))
- 	return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid hufftable index");
-+      if (grub_errno != GRUB_ERR_NONE)
-+	return grub_errno;
-     }
- 
-   grub_jpeg_get_byte (data);	/* Skip 3 unused bytes.  */
-   grub_jpeg_get_word (data);
--
-+  if (grub_errno != GRUB_ERR_NONE)
-+    return grub_errno;
-   if (data->file->offset != data_offset)
-     return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos");
- 
-@@ -640,6 +688,7 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
- {
-   unsigned c1, vb, hb, nr1, nc1;
-   int rst = data->dri;
-+  grub_err_t err = GRUB_ERR_NONE;
- 
-   vb = 8 << data->log_vs;
-   hb = 8 << data->log_hs;
-@@ -660,17 +709,22 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
- 
- 	for (r2 = 0; r2 < (1U << data->log_vs); r2++)
- 	  for (c2 = 0; c2 < (1U << data->log_hs); c2++)
--	    grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]);
-+            {
-+              err = grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]);
-+              if (err != GRUB_ERR_NONE)
-+                return err;
-+            }
- 
- 	if (data->color_components >= 3)
- 	  {
--	    grub_jpeg_decode_du (data, 1, data->cbdu);
--	    grub_jpeg_decode_du (data, 2, data->crdu);
-+	    err = grub_jpeg_decode_du (data, 1, data->cbdu);
-+	    if (err != GRUB_ERR_NONE)
-+	      return err;
-+	    err = grub_jpeg_decode_du (data, 2, data->crdu);
-+	    if (err != GRUB_ERR_NONE)
-+	      return err;
- 	  }
- 
--	if (grub_errno)
--	  return grub_errno;
--
- 	nr2 = (data->r1 == nr1 - 1) ? (data->image_height - data->r1 * vb) : vb;
- 	nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb;
- 
diff --git a/SOURCES/0247-ReiserFS-switch-to-using-grub_min-grub_max.patch b/SOURCES/0247-ReiserFS-switch-to-using-grub_min-grub_max.patch
new file mode 100644
index 0000000..0707af3
--- /dev/null
+++ b/SOURCES/0247-ReiserFS-switch-to-using-grub_min-grub_max.patch
@@ -0,0 +1,92 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 21 Apr 2022 16:31:17 -0400
+Subject: [PATCH] ReiserFS: switch to using grub_min()/grub_max()
+
+This is a minor cleanup patch to remove the bespoke MIN() and MAX()
+definitions from the reiserfs driver, and uses grub_min() / grub_max()
+instead.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/fs/reiserfs.c | 28 +++++++++-------------------
+ 1 file changed, 9 insertions(+), 19 deletions(-)
+
+diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c
+index af6a226a7f..b8253da7fe 100644
+--- a/grub-core/fs/reiserfs.c
++++ b/grub-core/fs/reiserfs.c
+@@ -42,16 +42,6 @@
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+-#define MIN(a, b) \
+-  ({ typeof (a) _a = (a); \
+-     typeof (b) _b = (b); \
+-     _a < _b ? _a : _b; })
+-
+-#define MAX(a, b) \
+-  ({ typeof (a) _a = (a); \
+-     typeof (b) _b = (b); \
+-     _a > _b ? _a : _b; })
+-
+ #define REISERFS_SUPER_BLOCK_OFFSET 0x10000
+ #define REISERFS_MAGIC_LEN 12
+ #define REISERFS_MAGIC_STRING "ReIsEr"
+@@ -1076,7 +1066,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
+   grub_reiserfs_set_key_type (&key, GRUB_REISERFS_ANY, 2);
+   initial_position = off;
+   current_position = 0;
+-  final_position = MIN (len + initial_position, node->size);
++  final_position = grub_min (len + initial_position, node->size);
+   grub_dprintf ("reiserfs",
+ 		"Reading from %lld to %lld (%lld instead of requested %ld)\n",
+ 		(unsigned long long) initial_position,
+@@ -1115,8 +1105,8 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
+           grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block);
+           if (initial_position < current_position + item_size)
+             {
+-              offset = MAX ((signed) (initial_position - current_position), 0);
+-              length = (MIN (item_size, final_position - current_position)
++              offset = grub_max ((signed) (initial_position - current_position), 0);
++              length = (grub_min (item_size, final_position - current_position)
+                         - offset);
+               grub_dprintf ("reiserfs",
+                             "Reading direct block %u from %u to %u...\n",
+@@ -1161,9 +1151,9 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
+               grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block);
+               if (current_position + block_size >= initial_position)
+                 {
+-                  offset = MAX ((signed) (initial_position - current_position),
+-                                0);
+-                  length = (MIN (block_size, final_position - current_position)
++                  offset = grub_max ((signed) (initial_position - current_position),
++				     0);
++                  length = (grub_min (block_size, final_position - current_position)
+                             - offset);
+                   grub_dprintf ("reiserfs",
+                                 "Reading indirect block %u from %u to %u...\n",
+@@ -1205,7 +1195,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
+   switch (found.type)
+     {
+       case GRUB_REISERFS_DIRECT:
+-        read_length = MIN (len, item_size - file->offset);
++        read_length = grub_min (len, item_size - file->offset);
+         grub_disk_read (found.data->disk,
+                         (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE,
+                         grub_le_to_cpu16 (found.header.item_location) + file->offset,
+@@ -1224,12 +1214,12 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
+                         item_size, (char *) indirect_block_ptr);
+         if (grub_errno)
+           goto fail;
+-        len = MIN (len, file->size - file->offset);
++        len = grub_min (len, file->size - file->offset);
+         for (indirect_block = file->offset / block_size;
+              indirect_block < indirect_block_count && read_length < len;
+              indirect_block++)
+           {
+-            read = MIN (block_size, len - read_length);
++            read = grub_min (block_size, len - read_length);
+             grub_disk_read (found.data->disk,
+                             (grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) * block_size) / GRUB_DISK_SECTOR_SIZE,
+                             file->offset % block_size, read,
diff --git a/SOURCES/0247-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch b/SOURCES/0247-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch
deleted file mode 100644
index 0ee92d5..0000000
--- a/SOURCES/0247-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Mon, 28 Jun 2021 14:16:58 +1000
-Subject: [PATCH] video/readers/jpeg: Do not reallocate a given huff table
-
-Fix a memory leak where an invalid file could cause us to reallocate
-memory for a huffman table we had already allocated memory for.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit bc06e12b4de55cc6f926af9f064170c82b1403e9)
-(cherry picked from commit 5298bf758ea39a90537f9a1c76541ff2f21b970b)
----
- grub-core/video/readers/jpeg.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
-index 10225abd53..caa211f06d 100644
---- a/grub-core/video/readers/jpeg.c
-+++ b/grub-core/video/readers/jpeg.c
-@@ -245,6 +245,9 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data)
- 	n += count[i];
- 
-       id += ac * 2;
-+      if (data->huff_value[id] != NULL)
-+	return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+			   "jpeg: attempt to reallocate huffman table");
-       data->huff_value[id] = grub_malloc (n);
-       if (grub_errno)
- 	return grub_errno;
diff --git a/SOURCES/0248-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch b/SOURCES/0248-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch
new file mode 100644
index 0000000..a7ac6f2
--- /dev/null
+++ b/SOURCES/0248-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch
@@ -0,0 +1,46 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 24 Mar 2022 14:40:01 -0400
+Subject: [PATCH] misc: make grub_boot_time() also call
+ grub_dprintf("boot",...)
+
+Currently grub_boot_time() includes valuable debugging messages, but if
+you build without BOOT_TIME_STATS enabled, they are silently and
+confusingly compiled away.
+
+This patch changes grub_boot_time() to also log when "boot" is enabled
+in DEBUG, regardless of BOOT_TIME_STATS.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/misc.c | 3 ++-
+ include/grub/misc.h   | 2 +-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index a186ad3dd4..cb45461402 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -1334,7 +1334,8 @@ grub_real_boot_time (const char *file,
+   n->next = 0;
+ 
+   va_start (args, fmt);
+-  n->msg = grub_xvasprintf (fmt, args);    
++  n->msg = grub_xvasprintf (fmt, args);
++  grub_dprintf ("boot", "%s\n", n->msg);
+   va_end (args);
+ 
+   *boot_time_last = n;
+diff --git a/include/grub/misc.h b/include/grub/misc.h
+index cf84aec1db..faae0ae860 100644
+--- a/include/grub/misc.h
++++ b/include/grub/misc.h
+@@ -503,7 +503,7 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file,
+ 				       const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 3, 4)));
+ #define grub_boot_time(...) grub_real_boot_time(GRUB_FILE, __LINE__, __VA_ARGS__)
+ #else
+-#define grub_boot_time(...)
++#define grub_boot_time(fmt, ...) grub_dprintf("boot", fmt "\n", ##__VA_ARGS__)
+ #endif
+ 
+ #define _grub_min(a, b, _a, _b)						      \
diff --git a/SOURCES/0248-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch b/SOURCES/0248-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch
deleted file mode 100644
index ed20cda..0000000
--- a/SOURCES/0248-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch
+++ /dev/null
@@ -1,45 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Mon, 28 Jun 2021 14:25:17 +1000
-Subject: [PATCH] video/readers/jpeg: Refuse to handle multiple start of
- streams
-
-An invalid file could contain multiple start of stream blocks, which
-would cause us to reallocate and leak our bitmap. Refuse to handle
-multiple start of streams.
-
-Additionally, fix a grub_error() call formatting.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit f3a854def3e281b7ad4bbea730cd3046de1da52f)
-(cherry picked from commit db0154828989a0a52ee59a4dda8c3803752bc827)
----
- grub-core/video/readers/jpeg.c | 7 +++++--
- 1 file changed, 5 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
-index caa211f06d..1df1171d78 100644
---- a/grub-core/video/readers/jpeg.c
-+++ b/grub-core/video/readers/jpeg.c
-@@ -677,6 +677,9 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
-   if (data->file->offset != data_offset)
-     return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos");
- 
-+  if (*data->bitmap)
-+    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many start of scan blocks");
-+
-   if (grub_video_bitmap_create (data->bitmap, data->image_width,
- 				data->image_height,
- 				GRUB_VIDEO_BLIT_FORMAT_RGB_888))
-@@ -699,8 +702,8 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
-   nc1 = (data->image_width + hb - 1)  >> (3 + data->log_hs);
- 
-   if (data->bitmap_ptr == NULL)
--    return grub_error(GRUB_ERR_BAD_FILE_TYPE,
--		      "jpeg: attempted to decode data before start of stream");
-+    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		       "jpeg: attempted to decode data before start of stream");
- 
-   for (; data->r1 < nr1 && (!data->dri || rst);
-        data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3)
diff --git a/SOURCES/0249-modules-make-.module_license-read-only.patch b/SOURCES/0249-modules-make-.module_license-read-only.patch
new file mode 100644
index 0000000..ba3b313
--- /dev/null
+++ b/SOURCES/0249-modules-make-.module_license-read-only.patch
@@ -0,0 +1,30 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 24 Feb 2022 16:32:51 -0500
+Subject: [PATCH] modules: make .module_license read-only
+
+Currently .module_license is set writable (that is, the section has the
+SHF_WRITE flag set) in the module's ELF headers.  This probably never
+actually matters, but it can't possibly be correct.
+
+This patch sets that data as "const", which causes that flag not to be
+set.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ include/grub/dl.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/grub/dl.h b/include/grub/dl.h
+index 20d870f2a4..618ae6f474 100644
+--- a/include/grub/dl.h
++++ b/include/grub/dl.h
+@@ -121,7 +121,7 @@ grub_mod_fini (void)
+ #define ATTRIBUTE_USED __unused__
+ #endif
+ #define GRUB_MOD_LICENSE(license)	\
+-  static char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license;
++  static const char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license;
+ #define GRUB_MOD_DEP(name)	\
+ static const char grub_module_depend_##name[] \
+  __attribute__((section(GRUB_MOD_SECTION(moddeps)), ATTRIBUTE_USED)) = #name
diff --git a/SOURCES/0249-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch b/SOURCES/0249-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch
deleted file mode 100644
index ed39a71..0000000
--- a/SOURCES/0249-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch
+++ /dev/null
@@ -1,54 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Wed, 7 Jul 2021 15:38:19 +1000
-Subject: [PATCH] video/readers/jpeg: Block int underflow -> wild pointer write
-
-Certain 1 px wide images caused a wild pointer write in
-grub_jpeg_ycrcb_to_rgb(). This was caused because in grub_jpeg_decode_data(),
-we have the following loop:
-
-for (; data->r1 < nr1 && (!data->dri || rst);
-     data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3)
-
-We did not check if vb * width >= hb * nc1.
-
-On a 64-bit platform, if that turns out to be negative, it will underflow,
-be interpreted as unsigned 64-bit, then be added to the 64-bit pointer, so
-we see data->bitmap_ptr jump, e.g.:
-
-0x6180_0000_0480 to
-0x6181_0000_0498
-     ^
-     ~--- carry has occurred and this pointer is now far away from
-          any object.
-
-On a 32-bit platform, it will decrement the pointer, creating a pointer
-that won't crash but will overwrite random data.
-
-Catch the underflow and error out.
-
-Fixes: CVE-2021-3697
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 41aeb2004db9924fecd9f2dd64bc2a5a5594a4b5)
-(cherry picked from commit 5f9582490792108306d047379fed2371bee286f8)
----
- grub-core/video/readers/jpeg.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
-index 1df1171d78..2da04094b3 100644
---- a/grub-core/video/readers/jpeg.c
-+++ b/grub-core/video/readers/jpeg.c
-@@ -705,6 +705,10 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
-     return grub_error (GRUB_ERR_BAD_FILE_TYPE,
- 		       "jpeg: attempted to decode data before start of stream");
- 
-+  if (vb * data->image_width <= hb * nc1)
-+    return grub_error (GRUB_ERR_BAD_FILE_TYPE,
-+		       "jpeg: cannot decode image with these dimensions");
-+
-   for (; data->r1 < nr1 && (!data->dri || rst);
-        data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3)
-     for (c1 = 0;  c1 < nc1 && (!data->dri || rst);
diff --git a/SOURCES/0250-modules-strip-.llvm_addrsig-sections-and-similar.patch b/SOURCES/0250-modules-strip-.llvm_addrsig-sections-and-similar.patch
new file mode 100644
index 0000000..9f26115
--- /dev/null
+++ b/SOURCES/0250-modules-strip-.llvm_addrsig-sections-and-similar.patch
@@ -0,0 +1,39 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 24 Feb 2022 16:40:11 -0500
+Subject: [PATCH] modules: strip .llvm_addrsig sections and similar.
+
+Currently grub modules built with clang or gcc have several sections
+which we don't actually need or support.
+
+We already have a list of section to skip in genmod.sh, and this patch
+adds the following sections to that list (as well as a few newlines):
+
+.note.gnu.property
+.llvm*
+
+Note that the glob there won't work without a new enough linker, but the
+failure is just reversion to the status quo, so that's not a big problem.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/genmod.sh.in | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in
+index 1250589b3f..c2c5280d75 100644
+--- a/grub-core/genmod.sh.in
++++ b/grub-core/genmod.sh.in
+@@ -57,8 +57,11 @@ if test x@TARGET_APPLE_LINKER@ != x1; then
+ 	    @TARGET_STRIP@ --strip-unneeded \
+ 		-K grub_mod_init -K grub_mod_fini \
+ 		-K _grub_mod_init -K _grub_mod_fini \
+-		-R .note.gnu.gold-version -R .note.GNU-stack \
++		-R .note.GNU-stack \
++		-R .note.gnu.gold-version \
++		-R .note.gnu.property \
+ 		-R .gnu.build.attributes \
++		-R '.llvm*' \
+ 		-R .rel.gnu.build.attributes \
+ 		-R .rela.gnu.build.attributes \
+ 		-R .eh_frame -R .rela.eh_frame -R .rel.eh_frame \
diff --git a/SOURCES/0250-normal-charset-Fix-array-out-of-bounds-formatting-un.patch b/SOURCES/0250-normal-charset-Fix-array-out-of-bounds-formatting-un.patch
deleted file mode 100644
index e51d293..0000000
--- a/SOURCES/0250-normal-charset-Fix-array-out-of-bounds-formatting-un.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Tue, 13 Jul 2021 13:24:38 +1000
-Subject: [PATCH] normal/charset: Fix array out-of-bounds formatting unicode
- for display
-
-In some cases attempting to display arbitrary binary strings leads
-to ASAN splats reading the widthspec array out of bounds.
-
-Check the index. If it would be out of bounds, return a width of 1.
-I don't know if that's strictly correct, but we're not really expecting
-great display of arbitrary binary data, and it's certainly not worse than
-an OOB read.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit fdf32abc7a3928852422c0f291d8cd1dd6b34a8d)
-(cherry picked from commit f2c10aaf335b88a69885375c4d68ffab2429df77)
----
- grub-core/normal/charset.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c
-index 4dfcc31078..7a5a7c153c 100644
---- a/grub-core/normal/charset.c
-+++ b/grub-core/normal/charset.c
-@@ -395,6 +395,8 @@ grub_unicode_estimate_width (const struct grub_unicode_glyph *c)
- {
-   if (grub_unicode_get_comb_type (c->base))
-     return 0;
-+  if (((unsigned long) (c->base >> 3)) >= ARRAY_SIZE (widthspec))
-+    return 1;
-   if (widthspec[c->base >> 3] & (1 << (c->base & 7)))
-     return 2;
-   else
diff --git a/SOURCES/0251-modules-Don-t-allocate-space-for-non-allocable-secti.patch b/SOURCES/0251-modules-Don-t-allocate-space-for-non-allocable-secti.patch
new file mode 100644
index 0000000..d07d838
--- /dev/null
+++ b/SOURCES/0251-modules-Don-t-allocate-space-for-non-allocable-secti.patch
@@ -0,0 +1,35 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 21 Mar 2022 16:56:10 -0400
+Subject: [PATCH] modules: Don't allocate space for non-allocable sections.
+
+Currently when loading grub modules, we allocate space for all sections,
+including those without SHF_ALLOC set.  We then copy the sections that
+/do/ have SHF_ALLOC set into the allocated memory, leaving some of our
+allocation untouched forever.  Additionally, on platforms with GOT
+fixups and trampolines, we currently compute alignment round-ups for the
+sections and sections with sh_size = 0.
+
+This patch removes the extra space from the allocation computation, and
+makes the allocation computation loop skip empty sections as the loading
+loop does.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/dl.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index f304494574..aef8af8aa7 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -289,6 +289,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
+        i < e->e_shnum;
+        i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
+     {
++      if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC))
++	continue;
++
+       tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size;
+       if (talign < s->sh_addralign)
+ 	talign = s->sh_addralign;
diff --git a/SOURCES/0251-net-netbuff-Block-overly-large-netbuff-allocs.patch b/SOURCES/0251-net-netbuff-Block-overly-large-netbuff-allocs.patch
deleted file mode 100644
index e74df27..0000000
--- a/SOURCES/0251-net-netbuff-Block-overly-large-netbuff-allocs.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Tue, 8 Mar 2022 23:47:46 +1100
-Subject: [PATCH] net/netbuff: Block overly large netbuff allocs
-
-A netbuff shouldn't be too huge. It's bounded by MTU and TCP segment
-reassembly.
-
-This helps avoid some bugs (and provides a spot to instrument to catch
-them at their source).
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit ee9591103004cd13b4efadda671536090ca7fd57)
-(cherry picked from commit acde668bb9d9fa862a1a63e3bbd5fa47fdfa9183)
----
- grub-core/net/netbuff.c | 13 +++++++++++++
- 1 file changed, 13 insertions(+)
-
-diff --git a/grub-core/net/netbuff.c b/grub-core/net/netbuff.c
-index dbeeefe478..d5e9e9a0d7 100644
---- a/grub-core/net/netbuff.c
-+++ b/grub-core/net/netbuff.c
-@@ -79,10 +79,23 @@ grub_netbuff_alloc (grub_size_t len)
- 
-   COMPILE_TIME_ASSERT (NETBUFF_ALIGN % sizeof (grub_properly_aligned_t) == 0);
- 
-+  /*
-+   * The largest size of a TCP packet is 64 KiB, and everything else
-+   * should be a lot smaller - most MTUs are 1500 or less. Cap data
-+   * size at 64 KiB + a buffer.
-+   */
-+  if (len > 0xffffUL + 0x1000UL)
-+    {
-+      grub_error (GRUB_ERR_BUG,
-+                  "attempted to allocate a packet that is too big");
-+      return NULL;
-+    }
-+
-   if (len < NETBUFFMINLEN)
-     len = NETBUFFMINLEN;
- 
-   len = ALIGN_UP (len, NETBUFF_ALIGN);
-+
- #ifdef GRUB_MACHINE_EMU
-   data = grub_malloc (len + sizeof (*nb));
- #else
diff --git a/SOURCES/0252-net-ip-Do-IP-fragment-maths-safely.patch b/SOURCES/0252-net-ip-Do-IP-fragment-maths-safely.patch
deleted file mode 100644
index 4ba8455..0000000
--- a/SOURCES/0252-net-ip-Do-IP-fragment-maths-safely.patch
+++ /dev/null
@@ -1,45 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Mon, 20 Dec 2021 19:41:21 +1100
-Subject: [PATCH] net/ip: Do IP fragment maths safely
-
-This avoids an underflow and subsequent unpleasantness.
-
-Fixes: CVE-2022-28733
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit eb74e5743ca7e18a5e75c392fe0b21d1549a1936)
-(cherry picked from commit 552ad34583e788542e9ca08524a0d4bc8f98c297)
----
- grub-core/net/ip.c | 10 +++++++++-
- 1 file changed, 9 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
-index ce6bdc75c6..cf74f1f794 100644
---- a/grub-core/net/ip.c
-+++ b/grub-core/net/ip.c
-@@ -25,6 +25,7 @@
- #include <grub/net/netbuff.h>
- #include <grub/mm.h>
- #include <grub/priority_queue.h>
-+#include <grub/safemath.h>
- #include <grub/time.h>
- 
- struct iphdr {
-@@ -551,7 +552,14 @@ grub_net_recv_ip4_packets (struct grub_net_buff *nb,
-     {
-       rsm->total_len = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK)
- 			+ (nb->tail - nb->data));
--      rsm->total_len -= ((iph->verhdrlen & 0xf) * sizeof (grub_uint32_t));
-+
-+      if (grub_sub (rsm->total_len, (iph->verhdrlen & 0xf) * sizeof (grub_uint32_t),
-+		    &rsm->total_len))
-+	{
-+	  grub_dprintf ("net", "IP reassembly size underflow\n");
-+	  return GRUB_ERR_NONE;
-+	}
-+
-       rsm->asm_netbuff = grub_netbuff_alloc (rsm->total_len);
-       if (!rsm->asm_netbuff)
- 	{
diff --git a/SOURCES/0252-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch b/SOURCES/0252-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch
new file mode 100644
index 0000000..ef51214
--- /dev/null
+++ b/SOURCES/0252-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch
@@ -0,0 +1,81 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 25 Mar 2022 15:40:12 -0400
+Subject: [PATCH] pe: add the DOS header struct and fix some bad naming.
+
+In order to properly validate a loaded kernel's support for being loaded
+without a writable stack or executable, we need to be able to properly
+parse arbitrary PE headers.
+
+Currently, pe32.h is written in such a way that the MS-DOS header that
+tells us where to find the PE header in the binary can't be accessed.
+Further, for some reason it calls the DOS MZ magic "GRUB_PE32_MAGIC".
+
+This patch adds the structure for the DOS header, renames the DOS magic
+define, and adds defines for the actual PE magic.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/arm64/linux.c |  2 +-
+ include/grub/efi/pe32.h        | 28 ++++++++++++++++++++++++++--
+ 2 files changed, 27 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index d2af47c2c0..cc67f43906 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -58,7 +58,7 @@ grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh)
+   if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE)
+     return grub_error(GRUB_ERR_BAD_OS, "invalid magic number");
+ 
+-  if ((lh->code0 & 0xffff) != GRUB_PE32_MAGIC)
++  if ((lh->code0 & 0xffff) != GRUB_DOS_MAGIC)
+     return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ 		       N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled"));
+ 
+diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
+index a43adf2746..2a5e1ee003 100644
+--- a/include/grub/efi/pe32.h
++++ b/include/grub/efi/pe32.h
+@@ -46,7 +46,30 @@
+ 
+ #define GRUB_PE32_MSDOS_STUB_SIZE	0x80
+ 
+-#define GRUB_PE32_MAGIC			0x5a4d
++#define GRUB_DOS_MAGIC			0x5a4d
++
++struct grub_dos_header
++{
++  grub_uint16_t magic;
++  grub_uint16_t cblp;
++  grub_uint16_t cp;
++  grub_uint16_t crlc;
++  grub_uint16_t cparhdr;
++  grub_uint16_t minalloc;
++  grub_uint16_t maxalloc;
++  grub_uint16_t ss;
++  grub_uint16_t sp;
++  grub_uint16_t csum;
++  grub_uint16_t ip;
++  grub_uint16_t cs;
++  grub_uint16_t lfarlc;
++  grub_uint16_t ovno;
++  grub_uint16_t res0[4];
++  grub_uint16_t oemid;
++  grub_uint16_t oeminfo;
++  grub_uint16_t res1[10];
++  grub_uint32_t lfanew;
++};
+ 
+ /* According to the spec, the minimal alignment is 512 bytes...
+    But some examples (such as EFI drivers in the Intel
+@@ -280,7 +303,8 @@ struct grub_pe32_section_table
+ 
+ 
+ 
+-#define GRUB_PE32_SIGNATURE_SIZE 4
++#define GRUB_PE32_SIGNATURE_SIZE		4
++#define GRUB_PE32_SIGNATURE			"PE\0\0"
+ 
+ struct grub_pe32_header
+ {
diff --git a/SOURCES/0253-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch b/SOURCES/0253-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch
new file mode 100644
index 0000000..c6688cd
--- /dev/null
+++ b/SOURCES/0253-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch
@@ -0,0 +1,85 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 9 Feb 2022 16:08:20 -0500
+Subject: [PATCH] EFI: allocate kernel in EFI_RUNTIME_SERVICES_CODE instead of
+ EFI_LOADER_DATA.
+
+On some of the firmwares with more security mitigations, EFI_LOADER_DATA
+doesn't get you executable memory, and we take a fault and reboot when
+we enter kernel.
+
+This patch correctly allocates the kernel code as EFI_RUNTIME_SERVICES_CODE
+rather than EFI_LOADER_DATA.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+[rharwood: use kernel_size]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/loader/i386/efi/linux.c | 19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 9e5c11ac69..92b2fb5091 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -86,7 +86,9 @@ kernel_free(void *addr, grub_efi_uintn_t size)
+ }
+ 
+ static void *
+-kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
++kernel_alloc(grub_efi_uintn_t size,
++	     grub_efi_memory_type_t memtype,
++	     const char * const errmsg)
+ {
+   void *addr = 0;
+   unsigned int i;
+@@ -112,7 +114,7 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
+       prev_max = max;
+       addr = grub_efi_allocate_pages_real (max, pages,
+ 					   max_addresses[i].alloc_type,
+-					   GRUB_EFI_LOADER_DATA);
++					   memtype);
+       if (addr)
+ 	grub_dprintf ("linux", "Allocated at %p\n", addr);
+     }
+@@ -242,7 +244,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
+ 	}
+     }
+ 
+-  initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
++  initrd_mem = kernel_alloc(size, GRUB_EFI_RUNTIME_SERVICES_DATA,
++			    N_("can't allocate initrd"));
+   if (initrd_mem == NULL)
+     goto fail;
+   grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
+@@ -393,7 +396,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+     }
+ #endif
+ 
+-  params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters");
++  params = kernel_alloc (sizeof(*params), GRUB_EFI_RUNTIME_SERVICES_DATA,
++			 "cannot allocate kernel parameters");
+   if (!params)
+     goto fail;
+   grub_dprintf ("linux", "params = %p\n", params);
+@@ -415,7 +419,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_dprintf ("linux", "new lh is at %p\n", lh);
+ 
+   grub_dprintf ("linux", "setting up cmdline\n");
+-  cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline"));
++  cmdline = kernel_alloc (lh->cmdline_size + 1,
++			  GRUB_EFI_RUNTIME_SERVICES_DATA,
++			  N_("can't allocate cmdline"));
+   if (!cmdline)
+     goto fail;
+   grub_dprintf ("linux", "cmdline = %p\n", cmdline);
+@@ -461,7 +467,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
+   max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
+   kernel_size = lh->init_size;
+-  kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel"));
++  kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE,
++			     N_("can't allocate kernel"));
+   restore_addresses();
+   if (!kernel_mem)
+     goto fail;
diff --git a/SOURCES/0253-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch b/SOURCES/0253-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch
deleted file mode 100644
index 96c5361..0000000
--- a/SOURCES/0253-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Thu, 16 Sep 2021 01:29:54 +1000
-Subject: [PATCH] net/dns: Fix double-free addresses on corrupt DNS response
-
-grub_net_dns_lookup() takes as inputs a pointer to an array of addresses
-("addresses") for the given name, and pointer to a number of addresses
-("naddresses"). grub_net_dns_lookup() is responsible for allocating
-"addresses", and the caller is responsible for freeing it if
-"naddresses" > 0.
-
-The DNS recv_hook will sometimes set and free the addresses array,
-for example if the packet is too short:
-
-      if (ptr + 10 >= nb->tail)
-	{
-	  if (!*data->naddresses)
-	    grub_free (*data->addresses);
-	  grub_netbuff_free (nb);
-	  return GRUB_ERR_NONE;
-	}
-
-Later on the nslookup command code unconditionally frees the "addresses"
-array. Normally this is fine: the array is either populated with valid
-data or is NULL. But in these sorts of error cases it is neither NULL
-nor valid and we get a double-free.
-
-Only free "addresses" if "naddresses" > 0.
-
-It looks like the other use of grub_net_dns_lookup() is not affected.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit eb2e69fcf51307757e43f55ee8c9354d1ee42dd1)
-(cherry picked from commit d801a27e7acec6c1a83067fab0bb975877eaf704)
----
- grub-core/net/dns.c | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c
-index 906ec7d678..135faac035 100644
---- a/grub-core/net/dns.c
-+++ b/grub-core/net/dns.c
-@@ -667,9 +667,11 @@ grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)),
-       grub_net_addr_to_str (&addresses[i], buf);
-       grub_printf ("%s\n", buf);
-     }
--  grub_free (addresses);
-   if (naddresses)
--    return GRUB_ERR_NONE;
-+    {
-+      grub_free (addresses);
-+      return GRUB_ERR_NONE;
-+    }
-   return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found"));
- }
- 
diff --git a/SOURCES/0254-modules-load-module-sections-at-page-aligned-address.patch b/SOURCES/0254-modules-load-module-sections-at-page-aligned-address.patch
new file mode 100644
index 0000000..eb171f5
--- /dev/null
+++ b/SOURCES/0254-modules-load-module-sections-at-page-aligned-address.patch
@@ -0,0 +1,378 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 21 Mar 2022 17:45:40 -0400
+Subject: [PATCH] modules: load module sections at page-aligned addresses
+
+Currently we load module sections at whatever alignment gcc+ld happened
+to dump into the ELF section header, which is often pretty useless.  For
+example, by default time.mod has these sections on a current x86_64
+build:
+
+$ eu-readelf -a grub-core/time.mod |& grep ^Section -A13
+Section Headers:
+[Nr] Name            Type         Addr  Off      Size     ES Flags Lk Inf Al
+[ 0]                 NULL         0     00000000 00000000  0        0   0  0
+[ 1] .text           PROGBITS     0     00000040 0000015e  0 AX     0   0  1
+[ 2] .rela.text      RELA         0     00000458 000001e0 24 I      8   1  8
+[ 3] .rodata.str1.1  PROGBITS     0     0000019e 000000a1  1 AMS    0   0  1
+[ 4] .module_license PROGBITS     0     00000240 0000000f  0 A      0   0  8
+[ 5] .data           PROGBITS     0     0000024f 00000000  0 WA     0   0  1
+[ 6] .bss            NOBITS       0     00000250 00000008  0 WA     0   0  8
+[ 7] .modname        PROGBITS     0     00000250 00000005  0        0   0  1
+[ 8] .symtab         SYMTAB       0     00000258 00000150 24        9   6  8
+[ 9] .strtab         STRTAB       0     000003a8 000000ab  0        0   0  1
+[10] .shstrtab       STRTAB       0     00000638 00000059  0        0   0  1
+
+With NX protections being page based, loading sections with either a 1
+or 8 *byte* alignment does absolutely nothing to help us out.
+
+This patch switches most EFI platforms to load module sections at 4kB
+page-aligned addresses.  To do so, it adds an new per-arch function,
+grub_arch_dl_min_alignment(), which returns the alignment needed for
+dynamically loaded sections (in bytes).  Currently it sets it to 4096
+when GRUB_MACHINE_EFI is true on x86_64, i386, arm, arm64, and emu, and
+1-byte alignment on everything else.
+
+It then changes the allocation size computation and the loader code in
+grub_dl_load_segments() to align the locations and sizes up to these
+boundaries, and fills any added padding with zeros.
+
+All of this happens before relocations are applied, so the relocations
+factor that in with no change.
+
+As an aside, initially Daniel Kiper and I thought that it might be a
+better idea to split the modules up into top-level sections as
+.text.modules, .rodata.modules, .data.modules, etc., so that their page
+permissions would get set by the loader that's loading grub itself.
+This turns out to have two significant downsides: 1) either in mkimage
+or in grub_dl_relocate_symbols(), you wind up having to dynamically
+process the relocations to accommodate the moved module sections, and 2)
+you then need to change the permissions on the modules and change them
+back while relocating them in grub_dl_relocate_symbols(), which means
+that any loader that /does/ honor the section flags but does /not/
+generally support NX with the memory attributes API will cause grub to
+fail.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/arm/dl.c     | 13 +++++++++++++
+ grub-core/kern/arm64/dl.c   | 13 +++++++++++++
+ grub-core/kern/dl.c         | 29 +++++++++++++++++++++--------
+ grub-core/kern/emu/full.c   | 13 +++++++++++++
+ grub-core/kern/i386/dl.c    | 13 +++++++++++++
+ grub-core/kern/ia64/dl.c    |  9 +++++++++
+ grub-core/kern/mips/dl.c    |  8 ++++++++
+ grub-core/kern/powerpc/dl.c |  9 +++++++++
+ grub-core/kern/riscv/dl.c   | 13 +++++++++++++
+ grub-core/kern/sparc64/dl.c |  9 +++++++++
+ grub-core/kern/x86_64/dl.c  | 13 +++++++++++++
+ include/grub/dl.h           |  2 ++
+ docs/grub-dev.texi          |  6 +++---
+ 13 files changed, 139 insertions(+), 11 deletions(-)
+
+diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c
+index eab9d17ff2..9260737936 100644
+--- a/grub-core/kern/arm/dl.c
++++ b/grub-core/kern/arm/dl.c
+@@ -278,3 +278,16 @@ grub_arch_dl_check_header (void *ehdr)
+ 
+   return GRUB_ERR_NONE;
+ }
++
++/*
++ * Tell the loader what our minimum section alignment is.
++ */
++grub_size_t
++grub_arch_dl_min_alignment (void)
++{
++#ifdef GRUB_MACHINE_EFI
++  return 4096;
++#else
++  return 1;
++#endif
++}
+diff --git a/grub-core/kern/arm64/dl.c b/grub-core/kern/arm64/dl.c
+index 512e5a80b0..0d4a26857f 100644
+--- a/grub-core/kern/arm64/dl.c
++++ b/grub-core/kern/arm64/dl.c
+@@ -196,3 +196,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
+ 
+   return GRUB_ERR_NONE;
+ }
++
++/*
++ * Tell the loader what our minimum section alignment is.
++ */
++grub_size_t
++grub_arch_dl_min_alignment (void)
++{
++#ifdef GRUB_MACHINE_EFI
++  return 4096;
++#else
++  return 1;
++#endif
++}
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index aef8af8aa7..8c7aacef39 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -277,7 +277,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
+ {
+   unsigned i;
+   const Elf_Shdr *s;
+-  grub_size_t tsize = 0, talign = 1;
++  grub_size_t tsize = 0, talign = 1, arch_addralign = 1;
+ #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
+   grub_size_t tramp;
+   grub_size_t got;
+@@ -285,16 +285,24 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
+ #endif
+   char *ptr;
+ 
++  arch_addralign = grub_arch_dl_min_alignment ();
++
+   for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
+        i < e->e_shnum;
+        i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
+     {
++      grub_size_t sh_addralign;
++      grub_size_t sh_size;
++
+       if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC))
+ 	continue;
+ 
+-      tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size;
+-      if (talign < s->sh_addralign)
+-	talign = s->sh_addralign;
++      sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign);
++      sh_size = ALIGN_UP(s->sh_size, sh_addralign);
++
++      tsize = ALIGN_UP (tsize, sh_addralign) + sh_size;
++      if (talign < sh_addralign)
++	talign = sh_addralign;
+     }
+ 
+ #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
+@@ -323,6 +331,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
+        i < e->e_shnum;
+        i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
+     {
++      grub_size_t sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign);
++      grub_size_t sh_size = ALIGN_UP(s->sh_size, sh_addralign);
++
+       if (s->sh_flags & SHF_ALLOC)
+ 	{
+ 	  grub_dl_segment_t seg;
+@@ -335,17 +346,19 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
+ 	    {
+ 	      void *addr;
+ 
+-	      ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign);
++	      ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, sh_addralign);
+ 	      addr = ptr;
+-	      ptr += s->sh_size;
++	      ptr += sh_size;
+ 
+ 	      switch (s->sh_type)
+ 		{
+ 		case SHT_PROGBITS:
+ 		  grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size);
++		  grub_memset ((char *)addr + s->sh_size, 0,
++			       sh_size - s->sh_size);
+ 		  break;
+ 		case SHT_NOBITS:
+-		  grub_memset (addr, 0, s->sh_size);
++		  grub_memset (addr, 0, sh_size);
+ 		  break;
+ 		}
+ 
+@@ -354,7 +367,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
+ 	  else
+ 	    seg->addr = 0;
+ 
+-	  seg->size = s->sh_size;
++	  seg->size = sh_size;
+ 	  seg->section = i;
+ 	  seg->next = mod->segment;
+ 	  mod->segment = seg;
+diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c
+index e8d63b1f5f..1de1c28eb0 100644
+--- a/grub-core/kern/emu/full.c
++++ b/grub-core/kern/emu/full.c
+@@ -67,3 +67,16 @@ grub_arch_dl_init_linker (void)
+ }
+ #endif
+ 
++
++/*
++ * Tell the loader what our minimum section alignment is.
++ */
++grub_size_t
++grub_arch_dl_min_alignment (void)
++{
++#ifdef GRUB_MACHINE_EFI
++  return 4096;
++#else
++  return 1;
++#endif
++}
+diff --git a/grub-core/kern/i386/dl.c b/grub-core/kern/i386/dl.c
+index 1346da5cc9..d6b4681fc9 100644
+--- a/grub-core/kern/i386/dl.c
++++ b/grub-core/kern/i386/dl.c
+@@ -79,3 +79,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
+ 
+   return GRUB_ERR_NONE;
+ }
++
++/*
++ * Tell the loader what our minimum section alignment is.
++ */
++grub_size_t
++grub_arch_dl_min_alignment (void)
++{
++#ifdef GRUB_MACHINE_EFI
++  return 4096;
++#else
++  return 1;
++#endif
++}
+diff --git a/grub-core/kern/ia64/dl.c b/grub-core/kern/ia64/dl.c
+index db59300fea..92d82c5750 100644
+--- a/grub-core/kern/ia64/dl.c
++++ b/grub-core/kern/ia64/dl.c
+@@ -148,3 +148,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
+     }
+   return GRUB_ERR_NONE;
+ }
++
++/*
++ * Tell the loader what our minimum section alignment is.
++ */
++grub_size_t
++grub_arch_dl_min_alignment (void)
++{
++  return 1;
++}
+diff --git a/grub-core/kern/mips/dl.c b/grub-core/kern/mips/dl.c
+index 5d7d299c74..6d83bd71e9 100644
+--- a/grub-core/kern/mips/dl.c
++++ b/grub-core/kern/mips/dl.c
+@@ -272,3 +272,11 @@ grub_arch_dl_init_linker (void)
+   grub_dl_register_symbol ("_gp_disp", &_gp_disp_dummy, 0, 0);
+ }
+ 
++/*
++ * Tell the loader what our minimum section alignment is.
++ */
++grub_size_t
++grub_arch_dl_min_alignment (void)
++{
++  return 1;
++}
+diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c
+index cdd61b305f..5d9ba2e158 100644
+--- a/grub-core/kern/powerpc/dl.c
++++ b/grub-core/kern/powerpc/dl.c
+@@ -167,3 +167,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
+ 
+   return GRUB_ERR_NONE;
+ }
++
++/*
++ * Tell the loader what our minimum section alignment is.
++ */
++grub_size_t
++grub_arch_dl_min_alignment (void)
++{
++  return 1;
++}
+diff --git a/grub-core/kern/riscv/dl.c b/grub-core/kern/riscv/dl.c
+index f26b12aaa4..aa18f9e990 100644
+--- a/grub-core/kern/riscv/dl.c
++++ b/grub-core/kern/riscv/dl.c
+@@ -343,3 +343,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
+ 
+   return GRUB_ERR_NONE;
+ }
++
++/*
++ * Tell the loader what our minimum section alignment is.
++ */
++grub_size_t
++grub_arch_dl_min_alignment (void)
++{
++#ifdef GRUB_MACHINE_EFI
++  return 4096;
++#else
++  return 1;
++#endif
++}
+diff --git a/grub-core/kern/sparc64/dl.c b/grub-core/kern/sparc64/dl.c
+index f3d960186b..f054f08241 100644
+--- a/grub-core/kern/sparc64/dl.c
++++ b/grub-core/kern/sparc64/dl.c
+@@ -189,3 +189,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
+ 
+   return GRUB_ERR_NONE;
+ }
++
++/*
++ * Tell the loader what our minimum section alignment is.
++ */
++grub_size_t
++grub_arch_dl_min_alignment (void)
++{
++  return 1;
++}
+diff --git a/grub-core/kern/x86_64/dl.c b/grub-core/kern/x86_64/dl.c
+index e5a8bdcf4f..a105dc50ce 100644
+--- a/grub-core/kern/x86_64/dl.c
++++ b/grub-core/kern/x86_64/dl.c
+@@ -119,3 +119,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
+ 
+   return GRUB_ERR_NONE;
+ }
++
++/*
++ * Tell the loader what our minimum section alignment is.
++ */
++grub_size_t
++grub_arch_dl_min_alignment (void)
++{
++#ifdef GRUB_MACHINE_EFI
++  return 4096;
++#else
++  return 1;
++#endif
++}
+diff --git a/include/grub/dl.h b/include/grub/dl.h
+index 618ae6f474..f36ed5cb17 100644
+--- a/include/grub/dl.h
++++ b/include/grub/dl.h
+@@ -280,6 +280,8 @@ grub_err_t grub_arch_dl_check_header (void *ehdr);
+ grub_err_t
+ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
+ 			       Elf_Shdr *s, grub_dl_segment_t seg);
++grub_size_t
++grub_arch_dl_min_alignment (void);
+ #endif
+ 
+ #if defined (_mips)
+diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
+index 19f708ee66..7b2455a8fe 100644
+--- a/docs/grub-dev.texi
++++ b/docs/grub-dev.texi
+@@ -755,9 +755,9 @@ declare startup asm file ($cpu_$platform_startup) as well as any other files
+ (e.g. init.c and callwrap.S) (e.g. $cpu_$platform = kern/$cpu/$platform/init.c).
+ At this stage you will also need to add dummy dl.c and cache.S with functions
+ grub_err_t grub_arch_dl_check_header (void *ehdr), grub_err_t
+-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c) and
+-void grub_arch_sync_caches (void *address, grub_size_t len) (cache.S). They
+-won't be used for now.
++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c), grub_uint32_t
++grub_arch_dl_min_alignment (void), and void grub_arch_sync_caches (void
++*address, grub_size_t len) (cache.S). They won't be used for now.
+ 
+ You will need to create directory include/$cpu/$platform and a file
+ include/$cpu/types.h. The later folowing this template:
diff --git a/SOURCES/0254-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch b/SOURCES/0254-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch
deleted file mode 100644
index 8451c19..0000000
--- a/SOURCES/0254-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Mon, 20 Dec 2021 21:55:43 +1100
-Subject: [PATCH] net/dns: Don't read past the end of the string we're checking
- against
-
-I don't really understand what's going on here but fuzzing found
-a bug where we read past the end of check_with. That's a C string,
-so use grub_strlen() to make sure we don't overread it.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 6a97b3f4b1d5173aa516edc6dedbc63de7306d21)
-(cherry picked from commit e0589624e86bc96666cbdb62f6e55cafec2871b3)
----
- grub-core/net/dns.c | 19 ++++++++++++++++---
- 1 file changed, 16 insertions(+), 3 deletions(-)
-
-diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c
-index 135faac035..17961a9f18 100644
---- a/grub-core/net/dns.c
-+++ b/grub-core/net/dns.c
-@@ -146,11 +146,18 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
- 		 int *length, char *set)
- {
-   const char *readable_ptr = check_with;
-+  int readable_len;
-   const grub_uint8_t *ptr;
-   char *optr = set;
-   int bytes_processed = 0;
-   if (length)
-     *length = 0;
-+
-+  if (readable_ptr != NULL)
-+    readable_len = grub_strlen (readable_ptr);
-+  else
-+    readable_len = 0;
-+
-   for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; )
-     {
-       /* End marker.  */
-@@ -172,13 +179,16 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
- 	  ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]);
- 	  continue;
- 	}
--      if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0)
-+      if (readable_ptr != NULL && (*ptr > readable_len || grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0))
- 	return 0;
-       if (grub_memchr (ptr + 1, 0, *ptr) 
- 	  || grub_memchr (ptr + 1, '.', *ptr))
- 	return 0;
-       if (readable_ptr)
--	readable_ptr += *ptr;
-+	{
-+	  readable_ptr += *ptr;
-+	  readable_len -= *ptr;
-+	}
-       if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0)
- 	return 0;
-       bytes_processed += *ptr + 1;
-@@ -192,7 +202,10 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
-       if (optr)
- 	*optr++ = '.';
-       if (readable_ptr && *readable_ptr)
--	readable_ptr++;
-+	{
-+	  readable_ptr++;
-+	  readable_len--;
-+	}
-       ptr += *ptr + 1;
-     }
-   return 0;
diff --git a/SOURCES/0255-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch b/SOURCES/0255-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch
deleted file mode 100644
index dba4ca7..0000000
--- a/SOURCES/0255-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch
+++ /dev/null
@@ -1,113 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Mon, 20 Sep 2021 01:12:24 +1000
-Subject: [PATCH] net/tftp: Prevent a UAF and double-free from a failed seek
-
-A malicious tftp server can cause UAFs and a double free.
-
-An attempt to read from a network file is handled by grub_net_fs_read(). If
-the read is at an offset other than the current offset, grub_net_seek_real()
-is invoked.
-
-In grub_net_seek_real(), if a backwards seek cannot be satisfied from the
-currently received packets, and the underlying transport does not provide
-a seek method, then grub_net_seek_real() will close and reopen the network
-protocol layer.
-
-For tftp, the ->close() call goes to tftp_close() and frees the tftp_data_t
-file->data. The file->data pointer is not nulled out after the free.
-
-If the ->open() call fails, the file->data will not be reallocated and will
-continue point to a freed memory block. This could happen from a server
-refusing to send the requisite ack to the new tftp request, for example.
-
-The seek and the read will then fail, but the grub_file continues to exist:
-the failed seek does not necessarily cause the entire file to be thrown
-away (e.g. where the file is checked to see if it is gzipped/lzio/xz/etc.,
-a read failure is interpreted as a decompressor passing on the file, not as
-an invalidation of the entire grub_file_t structure).
-
-This means subsequent attempts to read or seek the file will use the old
-file->data after free. Eventually, the file will be close()d again and
-file->data will be freed again.
-
-Mark a net_fs file that doesn't reopen as broken. Do not permit read() or
-close() on a broken file (seek is not exposed directly to the file API -
-it is only called as part of read, so this blocks seeks as well).
-
-As an additional defence, null out the ->data pointer if tftp_open() fails.
-That would have lead to a simple null pointer dereference rather than
-a mess of UAFs.
-
-This may affect other protocols, I haven't checked.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit dada1dda695439bb55b2848dddc2d89843552f81)
-(cherry picked from commit 352c5ae8a9fc715712e6ecbd7ccb6218122c748f)
----
- grub-core/net/net.c  | 11 +++++++++--
- grub-core/net/tftp.c |  1 +
- include/grub/net.h   |  1 +
- 3 files changed, 11 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/net/net.c b/grub-core/net/net.c
-index 55aed92722..1001c611d1 100644
---- a/grub-core/net/net.c
-+++ b/grub-core/net/net.c
-@@ -1625,7 +1625,8 @@ grub_net_fs_close (grub_file_t file)
-       grub_netbuff_free (file->device->net->packs.first->nb);
-       grub_net_remove_packet (file->device->net->packs.first);
-     }
--  file->device->net->protocol->close (file);
-+  if (!file->device->net->broken)
-+    file->device->net->protocol->close (file);
-   grub_free (file->device->net->name);
-   return GRUB_ERR_NONE;
- }
-@@ -1847,7 +1848,10 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset)
-     file->device->net->stall = 0;
-     err = file->device->net->protocol->open (file, file->device->net->name);
-     if (err)
--      return err;
-+      {
-+	file->device->net->broken = 1;
-+	return err;
-+      }
-     grub_net_fs_read_real (file, NULL, offset);
-     return grub_errno;
-   }
-@@ -1856,6 +1860,9 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset)
- static grub_ssize_t
- grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len)
- {
-+  if (file->device->net->broken)
-+    return -1;
-+
-   if (file->offset != file->device->net->offset)
-     {
-       grub_err_t err;
-diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
-index d54b13f09f..788ad1dc44 100644
---- a/grub-core/net/tftp.c
-+++ b/grub-core/net/tftp.c
-@@ -408,6 +408,7 @@ tftp_open (struct grub_file *file, const char *filename)
-     {
-       grub_net_udp_close (data->sock);
-       grub_free (data);
-+      file->data = NULL;
-       return grub_errno;
-     }
- 
-diff --git a/include/grub/net.h b/include/grub/net.h
-index 42af7de250..9e4898cc6b 100644
---- a/include/grub/net.h
-+++ b/include/grub/net.h
-@@ -280,6 +280,7 @@ typedef struct grub_net
-   grub_fs_t fs;
-   int eof;
-   int stall;
-+  int broken;
- } *grub_net_t;
- 
- extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name);
diff --git a/SOURCES/0255-nx-add-memory-attribute-get-set-API.patch b/SOURCES/0255-nx-add-memory-attribute-get-set-API.patch
new file mode 100644
index 0000000..91c9d2f
--- /dev/null
+++ b/SOURCES/0255-nx-add-memory-attribute-get-set-API.patch
@@ -0,0 +1,317 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 22 Mar 2022 10:56:21 -0400
+Subject: [PATCH] nx: add memory attribute get/set API
+
+For NX, we need to set the page access permission attributes for write
+and execute permissions.
+
+This patch adds two new primitives, grub_set_mem_attrs() and
+grub_clear_mem_attrs(), and associated constant definitions, to be used
+for that purpose.
+
+For most platforms, it adds a dummy implementation that returns
+GRUB_ERR_NONE.  On EFI platforms, it adds a common helper function,
+grub_efi_status_to_err(), which translates EFI error codes to grub error
+codes, adds headers for the EFI Memory Attribute Protocol (still pending
+standardization), and an implementation of the grub nx primitives using
+it.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+[rharwood: add pjones's none/nyi fixup]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/kern/efi/efi.c |  36 +++++++++++++
+ grub-core/kern/efi/mm.c  | 131 +++++++++++++++++++++++++++++++++++++++++++++++
+ include/grub/efi/api.h   |  25 +++++++++
+ include/grub/efi/efi.h   |   2 +
+ include/grub/mm.h        |  32 ++++++++++++
+ 5 files changed, 226 insertions(+)
+
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index 7fcca69c17..4ac2b2754e 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -1096,3 +1096,39 @@ grub_efi_compare_device_paths (const grub_efi_device_path_t *dp1,
+ 
+   return 0;
+ }
++
++grub_err_t
++grub_efi_status_to_err (grub_efi_status_t status)
++{
++  grub_err_t err;
++  switch (status)
++    {
++    case GRUB_EFI_SUCCESS:
++      err = GRUB_ERR_NONE;
++      break;
++    case GRUB_EFI_INVALID_PARAMETER:
++    default:
++      err = GRUB_ERR_BAD_ARGUMENT;
++      break;
++    case GRUB_EFI_OUT_OF_RESOURCES:
++      err = GRUB_ERR_OUT_OF_MEMORY;
++      break;
++    case GRUB_EFI_DEVICE_ERROR:
++      err = GRUB_ERR_IO;
++      break;
++    case GRUB_EFI_WRITE_PROTECTED:
++      err = GRUB_ERR_WRITE_ERROR;
++      break;
++    case GRUB_EFI_SECURITY_VIOLATION:
++      err = GRUB_ERR_ACCESS_DENIED;
++      break;
++    case GRUB_EFI_NOT_FOUND:
++      err = GRUB_ERR_FILE_NOT_FOUND;
++      break;
++    case GRUB_EFI_ABORTED:
++      err = GRUB_ERR_WAIT;
++      break;
++    }
++
++  return err;
++}
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index e84961d078..2c33758ed7 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -738,3 +738,134 @@ grub_efi_get_ram_base(grub_addr_t *base_addr)
+   return GRUB_ERR_NONE;
+ }
+ #endif
++
++static inline grub_uint64_t
++grub_mem_attrs_to_uefi_mem_attrs (grub_uint64_t attrs)
++{
++  grub_uint64_t ret = GRUB_EFI_MEMORY_RP |
++		      GRUB_EFI_MEMORY_RO |
++		      GRUB_EFI_MEMORY_XP;
++
++  if (attrs & GRUB_MEM_ATTR_R)
++    ret &= ~GRUB_EFI_MEMORY_RP;
++
++  if (attrs & GRUB_MEM_ATTR_W)
++    ret &= ~GRUB_EFI_MEMORY_RO;
++
++  if (attrs & GRUB_MEM_ATTR_X)
++    ret &= ~GRUB_EFI_MEMORY_XP;
++
++  return ret;
++}
++
++static inline grub_uint64_t
++uefi_mem_attrs_to_grub_mem_attrs (grub_uint64_t attrs)
++{
++  grub_uint64_t ret = GRUB_MEM_ATTR_R |
++		      GRUB_MEM_ATTR_W |
++		      GRUB_MEM_ATTR_X;
++
++  if (attrs & GRUB_EFI_MEMORY_RP)
++    ret &= ~GRUB_MEM_ATTR_R;
++
++  if (attrs & GRUB_EFI_MEMORY_RO)
++    ret &= ~GRUB_MEM_ATTR_W;
++
++  if (attrs & GRUB_EFI_MEMORY_XP)
++    ret &= ~GRUB_MEM_ATTR_X;
++
++  return ret;
++}
++
++grub_err_t
++grub_get_mem_attrs (grub_addr_t addr, grub_size_t size, grub_uint64_t *attrs)
++{
++  grub_efi_memory_attribute_protocol_t *proto;
++  grub_efi_physical_address_t physaddr = addr;
++  grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
++  grub_efi_status_t efi_status;
++
++  proto = grub_efi_locate_protocol (&protocol_guid, 0);
++  if (!proto)
++    return GRUB_ERR_NOT_IMPLEMENTED_YET;
++
++  if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL)
++    {
++      grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" and attrs %p\n",
++		    __func__, physaddr, physaddr+size-1, attrs);
++      return 0;
++    }
++
++  efi_status = efi_call_4(proto->get_memory_attributes,
++			  proto, physaddr, size, attrs);
++  *attrs = uefi_mem_attrs_to_grub_mem_attrs (*attrs);
++
++  return grub_efi_status_to_err (efi_status);
++}
++
++grub_err_t
++grub_update_mem_attrs (grub_addr_t addr, grub_size_t size,
++		       grub_uint64_t set_attrs, grub_uint64_t clear_attrs)
++{
++  grub_efi_memory_attribute_protocol_t *proto;
++  grub_efi_physical_address_t physaddr = addr;
++  grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
++  grub_efi_status_t efi_status = GRUB_EFI_SUCCESS;
++  grub_uint64_t before = 0, after = 0, uefi_set_attrs, uefi_clear_attrs;
++  grub_err_t err;
++
++  proto = grub_efi_locate_protocol (&protocol_guid, 0);
++  if (!proto)
++    return GRUB_ERR_NONE;
++
++  err = grub_get_mem_attrs (addr, size, &before);
++  if (err)
++    grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n",
++		  addr, size, &before, err);
++
++  if (physaddr & 0xfff || size & 0xfff || size == 0)
++    {
++      grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" +%s%s%s -%s%s%s\n",
++		    __func__, physaddr, physaddr + size - 1,
++		    (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
++		    (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
++		    (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
++		    (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
++		    (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
++		    (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "");
++      return 0;
++    }
++
++  uefi_set_attrs = grub_mem_attrs_to_uefi_mem_attrs (set_attrs);
++  grub_dprintf ("nx", "translating set_attrs from 0x%lx to 0x%lx\n", set_attrs, uefi_set_attrs);
++  uefi_clear_attrs = grub_mem_attrs_to_uefi_mem_attrs (clear_attrs);
++  grub_dprintf ("nx", "translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs, uefi_clear_attrs);
++  if (uefi_set_attrs)
++    efi_status = efi_call_4(proto->set_memory_attributes,
++			    proto, physaddr, size, uefi_set_attrs);
++  if (efi_status == GRUB_EFI_SUCCESS && uefi_clear_attrs)
++    efi_status = efi_call_4(proto->clear_memory_attributes,
++			    proto, physaddr, size, uefi_clear_attrs);
++
++  err = grub_get_mem_attrs (addr, size, &after);
++  if (err)
++    grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n",
++		  addr, size, &after, err);
++
++  grub_dprintf ("nx", "set +%s%s%s -%s%s%s on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" before:%c%c%c after:%c%c%c\n",
++		(set_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
++		(set_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
++		(set_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
++		(clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
++		(clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
++		(clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
++		addr, addr + size - 1,
++		(before & GRUB_MEM_ATTR_R) ? 'r' : '-',
++		(before & GRUB_MEM_ATTR_W) ? 'w' : '-',
++		(before & GRUB_MEM_ATTR_X) ? 'x' : '-',
++		(after & GRUB_MEM_ATTR_R) ? 'r' : '-',
++		(after & GRUB_MEM_ATTR_W) ? 'w' : '-',
++		(after & GRUB_MEM_ATTR_X) ? 'x' : '-');
++
++  return grub_efi_status_to_err (efi_status);
++}
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index f431f49973..464842ba37 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -363,6 +363,11 @@
+       { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \
+   }
+ 
++#define GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID \
++  { 0xf4560cf6, 0x40ec, 0x4b4a, \
++    { 0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89 } \
++  }
++
+ struct grub_efi_sal_system_table
+ {
+   grub_uint32_t signature;
+@@ -2102,6 +2107,26 @@ struct grub_efi_ip6_config_manual_address {
+ };
+ typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t;
+ 
++struct grub_efi_memory_attribute_protocol
++{
++  grub_efi_status_t (*get_memory_attributes) (
++			    struct grub_efi_memory_attribute_protocol *this,
++			    grub_efi_physical_address_t base_address,
++			    grub_efi_uint64_t length,
++			    grub_efi_uint64_t *attributes);
++  grub_efi_status_t (*set_memory_attributes) (
++			    struct grub_efi_memory_attribute_protocol *this,
++			    grub_efi_physical_address_t base_address,
++			    grub_efi_uint64_t length,
++			    grub_efi_uint64_t attributes);
++  grub_efi_status_t (*clear_memory_attributes) (
++			    struct grub_efi_memory_attribute_protocol *this,
++			    grub_efi_physical_address_t base_address,
++			    grub_efi_uint64_t length,
++			    grub_efi_uint64_t attributes);
++};
++typedef struct grub_efi_memory_attribute_protocol grub_efi_memory_attribute_protocol_t;
++
+ #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
+   || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \
+   || defined(__riscv)
+diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
+index ec52083c49..34825c4adc 100644
+--- a/include/grub/efi/efi.h
++++ b/include/grub/efi/efi.h
+@@ -164,4 +164,6 @@ struct grub_net_card;
+ grub_efi_handle_t
+ grub_efinet_get_device_handle (struct grub_net_card *card);
+ 
++grub_err_t EXPORT_FUNC(grub_efi_status_to_err) (grub_efi_status_t status);
++
+ #endif /* ! GRUB_EFI_EFI_HEADER */
+diff --git a/include/grub/mm.h b/include/grub/mm.h
+index 9c38dd3ca5..d81623d226 100644
+--- a/include/grub/mm.h
++++ b/include/grub/mm.h
+@@ -22,6 +22,7 @@
+ 
+ #include <grub/types.h>
+ #include <grub/symbol.h>
++#include <grub/err.h>
+ #include <config.h>
+ 
+ #ifndef NULL
+@@ -38,6 +39,37 @@ void *EXPORT_FUNC(grub_realloc) (void *ptr, grub_size_t size);
+ void *EXPORT_FUNC(grub_memalign) (grub_size_t align, grub_size_t size);
+ #endif
+ 
++#define GRUB_MEM_ATTR_R	0x0000000000000004LLU
++#define GRUB_MEM_ATTR_W	0x0000000000000002LLU
++#define GRUB_MEM_ATTR_X	0x0000000000000001LLU
++
++#ifdef GRUB_MACHINE_EFI
++grub_err_t EXPORT_FUNC(grub_get_mem_attrs) (grub_addr_t addr,
++					    grub_size_t size,
++					    grub_uint64_t *attrs);
++grub_err_t EXPORT_FUNC(grub_update_mem_attrs) (grub_addr_t addr,
++					       grub_size_t size,
++					       grub_uint64_t set_attrs,
++					       grub_uint64_t clear_attrs);
++#else /* !GRUB_MACHINE_EFI */
++static inline grub_err_t
++grub_get_mem_attrs (grub_addr_t addr __attribute__((__unused__)),
++		    grub_size_t size __attribute__((__unused__)),
++		    grub_uint64_t *attrs __attribute__((__unused__)))
++{
++  return GRUB_ERR_NONE;
++}
++
++static inline grub_err_t
++grub_update_mem_attrs (grub_addr_t addr __attribute__((__unused__)),
++		       grub_size_t size __attribute__((__unused__)),
++		       grub_uint64_t set_attrs __attribute__((__unused__)),
++		       grub_uint64_t clear_attrs __attribute__((__unused__)))
++{
++  return GRUB_ERR_NONE;
++}
++#endif /* GRUB_MACHINE_EFI */
++
+ void grub_mm_check_real (const char *file, int line);
+ #define grub_mm_check() grub_mm_check_real (GRUB_FILE, __LINE__);
+ 
diff --git a/SOURCES/0256-net-tftp-Avoid-a-trivial-UAF.patch b/SOURCES/0256-net-tftp-Avoid-a-trivial-UAF.patch
deleted file mode 100644
index 09a583a..0000000
--- a/SOURCES/0256-net-tftp-Avoid-a-trivial-UAF.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Tue, 18 Jan 2022 14:29:20 +1100
-Subject: [PATCH] net/tftp: Avoid a trivial UAF
-
-Under tftp errors, we print a tftp error message from the tftp header.
-However, the tftph pointer is a pointer inside nb, the netbuff. Previously,
-we were freeing the nb and then dereferencing it. Don't do that, use it
-and then free it later.
-
-This isn't really _bad_ per se, especially as we're single-threaded, but
-it trips up fuzzers.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 956f4329cec23e4375182030ca9b2be631a61ba5)
-(cherry picked from commit dbe9abcdee6ce796811111b67e3f24eefe2135d1)
----
- grub-core/net/tftp.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
-index 788ad1dc44..a95766dcbd 100644
---- a/grub-core/net/tftp.c
-+++ b/grub-core/net/tftp.c
-@@ -251,9 +251,9 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
-       return GRUB_ERR_NONE;
-     case TFTP_ERROR:
-       data->have_oack = 1;
--      grub_netbuff_free (nb);
-       grub_error (GRUB_ERR_IO, "%s", tftph->u.err.errmsg);
-       grub_error_save (&data->save_err);
-+      grub_netbuff_free (nb);
-       return GRUB_ERR_NONE;
-     default:
-       grub_netbuff_free (nb);
diff --git a/SOURCES/0256-nx-set-page-permissions-for-loaded-modules.patch b/SOURCES/0256-nx-set-page-permissions-for-loaded-modules.patch
new file mode 100644
index 0000000..9e0aebb
--- /dev/null
+++ b/SOURCES/0256-nx-set-page-permissions-for-loaded-modules.patch
@@ -0,0 +1,263 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 21 Mar 2022 17:46:35 -0400
+Subject: [PATCH] nx: set page permissions for loaded modules.
+
+For NX, we need to set write and executable permissions on the sections
+of grub modules when we load them.
+
+On sections with SHF_ALLOC set, which is typically everything except
+.modname and the symbol and string tables, this patch clears the Read
+Only flag on sections that have the ELF flag SHF_WRITE set, and clears
+the No eXecute flag on sections with SHF_EXECINSTR set.  In all other
+cases it sets both flags.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+[rharwood: arm tgptr -> tgaddr]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/kern/dl.c | 120 +++++++++++++++++++++++++++++++++++++++-------------
+ include/grub/dl.h   |  44 +++++++++++++++++++
+ 2 files changed, 134 insertions(+), 30 deletions(-)
+
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index 8c7aacef39..d5de80186f 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -285,6 +285,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
+ #endif
+   char *ptr;
+ 
++  grub_dprintf ("modules", "loading segments for \"%s\"\n", mod->name);
++
+   arch_addralign = grub_arch_dl_min_alignment ();
+ 
+   for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
+@@ -384,6 +386,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
+   ptr += got;
+ #endif
+ 
++  grub_dprintf ("modules", "done loading segments for \"%s\"\n", mod->name);
+   return GRUB_ERR_NONE;
+ }
+ 
+@@ -517,23 +520,6 @@ grub_dl_find_section (Elf_Ehdr *e, const char *name)
+       return s;
+   return NULL;
+ }
+-static long
+-grub_dl_find_section_index (Elf_Ehdr *e, const char *name)
+-{
+-  Elf_Shdr *s;
+-  const char *str;
+-  unsigned i;
+-
+-  s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
+-  str = (char *) e + s->sh_offset;
+-
+-  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
+-       i < e->e_shnum;
+-       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
+-    if (grub_strcmp (str + s->sh_name, name) == 0)
+-      return (long)i;
+-  return -1;
+-}
+ 
+ /* Me, Vladimir Serbinenko, hereby I add this module check as per new
+    GNU module policy. Note that this license check is informative only.
+@@ -662,6 +648,7 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
+   Elf_Shdr *s;
+   unsigned i;
+ 
++  grub_dprintf ("modules", "relocating symbols for \"%s\"\n", mod->name);
+   for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
+        i < e->e_shnum;
+        i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
+@@ -670,24 +657,95 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
+ 	grub_dl_segment_t seg;
+ 	grub_err_t err;
+ 
+-	/* Find the target segment.  */
+-	for (seg = mod->segment; seg; seg = seg->next)
+-	  if (seg->section == s->sh_info)
+-	    break;
++	seg = grub_dl_find_segment(mod, s->sh_info);
++        if (!seg)
++	  continue;
+ 
+-	if (seg)
+-	  {
+-	    if (!mod->symtab)
+-	      return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table");
++	if (!mod->symtab)
++	  return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table");
+ 
+-	    err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg);
+-	    if (err)
+-	      return err;
+-	  }
++	err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg);
++	if (err)
++	  return err;
+       }
+ 
++  grub_dprintf ("modules", "done relocating symbols for \"%s\"\n", mod->name);
+   return GRUB_ERR_NONE;
+ }
++
++static grub_err_t
++grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr)
++{
++  unsigned i;
++  const Elf_Shdr *s;
++  const Elf_Ehdr *e = ehdr;
++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
++  grub_size_t arch_addralign = grub_arch_dl_min_alignment ();
++  grub_addr_t tgaddr;
++  grub_uint64_t tgsz;
++#endif
++
++  grub_dprintf ("modules", "updating memory attributes for \"%s\"\n",
++		mod->name);
++  for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
++       i < e->e_shnum;
++       i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
++    {
++      grub_dl_segment_t seg;
++      grub_uint64_t set_attrs = GRUB_MEM_ATTR_R;
++      grub_uint64_t clear_attrs = GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X;
++
++      seg = grub_dl_find_segment(mod, i);
++      if (!seg)
++	continue;
++
++      if (seg->size == 0 || !(s->sh_flags & SHF_ALLOC))
++	continue;
++
++      if (s->sh_flags & SHF_WRITE)
++	{
++	  set_attrs |= GRUB_MEM_ATTR_W;
++	  clear_attrs &= ~GRUB_MEM_ATTR_W;
++	}
++
++      if (s->sh_flags & SHF_EXECINSTR)
++	{
++	  set_attrs |= GRUB_MEM_ATTR_X;
++	  clear_attrs &= ~GRUB_MEM_ATTR_X;
++	}
++
++      grub_dprintf ("modules", "setting memory attrs for section \"%s\" to -%s%s%s+%s%s%s\n",
++		    grub_dl_get_section_name(e, s),
++		    (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
++		    (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
++		    (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
++		    (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
++		    (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
++		    (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "");
++      grub_update_mem_attrs ((grub_addr_t)(seg->addr), seg->size, set_attrs, clear_attrs);
++    }
++
++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
++  tgaddr = grub_min((grub_addr_t)mod->tramp, (grub_addr_t)mod->got);
++  tgsz = grub_max((grub_addr_t)mod->trampptr, (grub_addr_t)mod->gotptr) - tgaddr;
++
++  if (tgsz)
++    {
++      tgsz = ALIGN_UP(tgsz, arch_addralign);
++
++      grub_dprintf ("modules", "updating attributes for GOT and trampolines\n",
++		    mod->name);
++      grub_update_mem_attrs (tgaddr, tgsz, GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_X,
++			     GRUB_MEM_ATTR_W);
++    }
++#endif
++
++  grub_dprintf ("modules", "done updating module memory attributes for \"%s\"\n",
++		mod->name);
++
++  return GRUB_ERR_NONE;
++}
++
+ static void
+ grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e)
+ {
+@@ -753,6 +811,7 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
+   mod->ref_count = 1;
+ 
+   grub_dprintf ("modules", "relocating to %p\n", mod);
++
+   /* Me, Vladimir Serbinenko, hereby I add this module check as per new
+      GNU module policy. Note that this license check is informative only.
+      Modules have to be licensed under GPLv3 or GPLv3+ (optionally
+@@ -766,7 +825,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
+       || grub_dl_resolve_dependencies (mod, e)
+       || grub_dl_load_segments (mod, e)
+       || grub_dl_resolve_symbols (mod, e)
+-      || grub_dl_relocate_symbols (mod, e))
++      || grub_dl_relocate_symbols (mod, e)
++      || grub_dl_set_mem_attrs (mod, e))
+     {
+       mod->fini = 0;
+       grub_dl_unload (mod);
+diff --git a/include/grub/dl.h b/include/grub/dl.h
+index f36ed5cb17..45ac8e339f 100644
+--- a/include/grub/dl.h
++++ b/include/grub/dl.h
+@@ -27,6 +27,7 @@
+ #include <grub/elf.h>
+ #include <grub/list.h>
+ #include <grub/misc.h>
++#include <grub/mm.h>
+ #endif
+ 
+ /*
+@@ -268,6 +269,49 @@ grub_dl_is_persistent (grub_dl_t mod)
+   return mod->persistent;
+ }
+ 
++static inline const char *
++grub_dl_get_section_name (const Elf_Ehdr *e, const Elf_Shdr *s)
++{
++  Elf_Shdr *str_s;
++  const char *str;
++
++  str_s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
++  str = (char *) e + str_s->sh_offset;
++
++  return str + s->sh_name;
++}
++
++static inline long
++grub_dl_find_section_index (Elf_Ehdr *e, const char *name)
++{
++  Elf_Shdr *s;
++  const char *str;
++  unsigned i;
++
++  s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
++  str = (char *) e + s->sh_offset;
++
++  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
++       i < e->e_shnum;
++       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
++    if (grub_strcmp (str + s->sh_name, name) == 0)
++      return (long)i;
++  return -1;
++}
++
++/* Return the segment for a section of index N */
++static inline grub_dl_segment_t
++grub_dl_find_segment (grub_dl_t mod, unsigned n)
++{
++  grub_dl_segment_t seg;
++
++  for (seg = mod->segment; seg; seg = seg->next)
++    if (seg->section == n)
++      return seg;
++
++  return NULL;
++}
++
+ #endif
+ 
+ void * EXPORT_FUNC(grub_resolve_symbol) (const char *name);
diff --git a/SOURCES/0257-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch b/SOURCES/0257-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch
deleted file mode 100644
index cbc7162..0000000
--- a/SOURCES/0257-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Tue, 1 Mar 2022 23:14:15 +1100
-Subject: [PATCH] net/http: Do not tear down socket if it's already been torn
- down
-
-It's possible for data->sock to get torn down in tcp error handling.
-If we unconditionally tear it down again we will end up doing writes
-to an offset of the NULL pointer when we go to tear it down again.
-
-Detect if it has been torn down and don't do it again.
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit ec233d3ecf995293304de443579aab5c46c49e85)
-(cherry picked from commit d39cf87ed701b9f0900daed7f672e07994d37ce8)
----
- grub-core/net/http.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/net/http.c b/grub-core/net/http.c
-index 7f878b5615..19cb8768e3 100644
---- a/grub-core/net/http.c
-+++ b/grub-core/net/http.c
-@@ -427,7 +427,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
-       return err;
-     }
- 
--  for (i = 0; !data->headers_recv && i < 100; i++)
-+  for (i = 0; data->sock && !data->headers_recv && i < 100; i++)
-     {
-       grub_net_tcp_retransmit ();
-       grub_net_poll_cards (300, &data->headers_recv);
-@@ -435,7 +435,8 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
- 
-   if (!data->headers_recv)
-     {
--      grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
-+      if (data->sock)
-+        grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
-       if (data->err)
- 	{
- 	  char *str = data->errmsg;
diff --git a/SOURCES/0257-nx-set-attrs-in-our-kernel-loaders.patch b/SOURCES/0257-nx-set-attrs-in-our-kernel-loaders.patch
new file mode 100644
index 0000000..514df1f
--- /dev/null
+++ b/SOURCES/0257-nx-set-attrs-in-our-kernel-loaders.patch
@@ -0,0 +1,565 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 22 Mar 2022 10:57:07 -0400
+Subject: [PATCH] nx: set attrs in our kernel loaders
+
+For NX, our kernel loaders need to set write and execute page
+permissions on allocated pages and the stack.
+
+This patch adds those calls.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+[rharwood: fix stack_attrs undefined, fix aarch64 callsites]
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/kern/efi/mm.c            |  77 +++++++++++++++++
+ grub-core/loader/arm64/linux.c     |  16 +++-
+ grub-core/loader/arm64/xen_boot.c  |   4 +-
+ grub-core/loader/efi/chainloader.c |  11 +++
+ grub-core/loader/efi/linux.c       | 164 ++++++++++++++++++++++++++++++++++++-
+ grub-core/loader/i386/efi/linux.c  |  26 +++++-
+ grub-core/loader/i386/linux.c      |   5 ++
+ include/grub/efi/efi.h             |   6 +-
+ include/grub/efi/linux.h           |  16 +++-
+ include/grub/efi/pe32.h            |   2 +
+ 10 files changed, 312 insertions(+), 15 deletions(-)
+
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index 2c33758ed7..e460b072e6 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -610,6 +610,81 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map,
+ }
+ #endif
+ 
++grub_addr_t grub_stack_addr = (grub_addr_t)-1ll;
++grub_size_t grub_stack_size = 0;
++
++static void
++grub_nx_init (void)
++{
++  grub_uint64_t attrs, stack_attrs;
++  grub_err_t err;
++  grub_addr_t stack_current, stack_end;
++  const grub_uint64_t page_size = 4096;
++  const grub_uint64_t page_mask = ~(page_size - 1);
++
++  /*
++   * These are to confirm that the flags are working as expected when
++   * debugging.
++   */
++  attrs = 0;
++  stack_current = (grub_addr_t)grub_nx_init & page_mask;
++  err = grub_get_mem_attrs (stack_current, page_size, &attrs);
++  if (err)
++    {
++      grub_dprintf ("nx",
++		    "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
++		    stack_current, err);
++      grub_error_pop ();
++    }
++  else
++    grub_dprintf ("nx", "page attrs for grub_nx_init (%p) are %c%c%c\n",
++		  grub_dl_load_core,
++		  (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-',
++		  (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-',
++		  (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-');
++
++  stack_current = (grub_addr_t)&stack_current & page_mask;
++  err = grub_get_mem_attrs (stack_current, page_size, &stack_attrs);
++  if (err)
++    {
++      grub_dprintf ("nx",
++		    "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
++		    stack_current, err);
++      grub_error_pop ();
++    }
++  else
++    {
++      attrs = stack_attrs;
++      grub_dprintf ("nx", "page attrs for stack (%p) are %c%c%c\n",
++                    &attrs,
++                    (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-',
++                    (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-',
++                    (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-');
++    }
++  for (stack_end = stack_current + page_size ;
++       !(attrs & GRUB_MEM_ATTR_R);
++       stack_end += page_size)
++    {
++      err = grub_get_mem_attrs (stack_current, page_size, &attrs);
++      if (err)
++	{
++	  grub_dprintf ("nx",
++			"grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
++			stack_current, err);
++	  grub_error_pop ();
++	  break;
++	}
++    }
++  if (stack_end > stack_current)
++    {
++      grub_stack_addr = stack_current;
++      grub_stack_size = stack_end - stack_current;
++      grub_dprintf ("nx",
++		    "detected stack from 0x%"PRIxGRUB_ADDR" to 0x%"PRIxGRUB_ADDR"\n",
++		    grub_stack_addr, grub_stack_addr + grub_stack_size - 1);
++    }
++}
++
+ void
+ grub_efi_mm_init (void)
+ {
+@@ -623,6 +698,8 @@ grub_efi_mm_init (void)
+   grub_efi_uint64_t required_pages;
+   int mm_status;
+ 
++  grub_nx_init ();
++
+   /* Prepare a memory region to store two memory maps.  */
+   memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
+   if (! memory_map)
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index cc67f43906..de85583487 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -172,7 +172,8 @@ free_params (void)
+ }
+ 
+ grub_err_t
+-grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args)
++grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args,
++				int nx_supported)
+ {
+   grub_err_t retval;
+ 
+@@ -182,7 +183,8 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args)
+ 
+   grub_dprintf ("linux", "linux command line: '%s'\n", args);
+ 
+-  retval = grub_efi_linux_boot ((char *)addr, handover_offset, (void *)addr);
++  retval = grub_efi_linux_boot (addr, size, handover_offset,
++				(void *)addr, nx_supported);
+ 
+   /* Never reached... */
+   free_params();
+@@ -192,7 +194,10 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args)
+ static grub_err_t
+ grub_linux_boot (void)
+ {
+-  return (grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr, linux_args));
++  return grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr,
++					(grub_size_t)kernel_size,
++					linux_args,
++					0);
+ }
+ 
+ static grub_err_t
+@@ -340,6 +345,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_off_t filelen;
+   grub_uint32_t align;
+   void *kernel = NULL;
++  int nx_supported = 1;
+ 
+   grub_dl_ref (my_mod);
+ 
+@@ -376,6 +382,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset);
+   grub_dprintf ("linux", "kernel alignment    : 0x%x\n", align);
+ 
++  err = grub_efi_check_nx_image_support((grub_addr_t)kernel, filelen, &nx_supported);
++  if (err != GRUB_ERR_NONE)
++    goto fail;
++
+   grub_loader_unset();
+ 
+   kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1);
+diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c
+index d9b7a9ba40..6e7e920416 100644
+--- a/grub-core/loader/arm64/xen_boot.c
++++ b/grub-core/loader/arm64/xen_boot.c
+@@ -266,7 +266,9 @@ xen_boot (void)
+     return err;
+ 
+   return grub_arch_efi_linux_boot_image (xen_hypervisor->start,
+-					  xen_hypervisor->cmdline);
++                                         xen_hypervisor->size,
++                                         xen_hypervisor->cmdline,
++                                         0);
+ }
+ 
+ static void
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index fb874f1855..dd31ac9bb3 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -1070,6 +1070,17 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
++  /*
++   * The OS kernel is going to set its own permissions when it takes over
++   * paging a few million instructions from now, and load_image() will set up
++   * anything that's needed based on the section headers, so there's no point
++   * in doing anything but clearing the protection bits here.
++   */
++  grub_dprintf("nx", "setting attributes for %p (%lu bytes) to %llx\n",
++	       (void *)(grub_addr_t)address, fsize, 0llu);
++  grub_update_mem_attrs (address, fsize,
++			 GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X, 0);
++
+ #if defined (__i386__) || defined (__x86_64__)
+   if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header))
+     {
+diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
+index 9265cf4200..277f352e0c 100644
+--- a/grub-core/loader/efi/linux.c
++++ b/grub-core/loader/efi/linux.c
+@@ -26,16 +26,127 @@
+ 
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wcast-align"
++#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
++
++grub_err_t
++grub_efi_check_nx_image_support (grub_addr_t kernel_addr,
++				 grub_size_t kernel_size,
++				 int *nx_supported)
++{
++  struct grub_dos_header *doshdr;
++  grub_size_t sz = sizeof (*doshdr);
++
++  struct grub_pe32_header_32 *pe32;
++  struct grub_pe32_header_64 *pe64;
++
++  int image_is_compatible = 0;
++  int is_64_bit;
++
++  if (kernel_size < sz)
++    return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
++
++  doshdr = (void *)kernel_addr;
++
++  if ((doshdr->magic & 0xffff) != GRUB_DOS_MAGIC)
++    return grub_error (GRUB_ERR_BAD_OS, N_("kernel DOS magic is invalid"));
++
++  sz = doshdr->lfanew + sizeof (*pe32);
++  if (kernel_size < sz)
++    return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
++
++  pe32 = (struct grub_pe32_header_32 *)(kernel_addr + doshdr->lfanew);
++  pe64 = (struct grub_pe32_header_64 *)pe32;
++
++  if (grub_memcmp (pe32->signature, GRUB_PE32_SIGNATURE,
++		   GRUB_PE32_SIGNATURE_SIZE) != 0)
++    return grub_error (GRUB_ERR_BAD_OS, N_("kernel PE magic is invalid"));
++
++  switch (pe32->coff_header.machine)
++    {
++    case GRUB_PE32_MACHINE_ARMTHUMB_MIXED:
++    case GRUB_PE32_MACHINE_I386:
++    case GRUB_PE32_MACHINE_RISCV32:
++      is_64_bit = 0;
++      break;
++    case GRUB_PE32_MACHINE_ARM64:
++    case GRUB_PE32_MACHINE_IA64:
++    case GRUB_PE32_MACHINE_RISCV64:
++    case GRUB_PE32_MACHINE_X86_64:
++      is_64_bit = 1;
++      break;
++    default:
++      return grub_error (GRUB_ERR_BAD_OS, N_("PE machine type 0x%04hx unknown"),
++			 pe32->coff_header.machine);
++    }
++
++  if (is_64_bit)
++    {
++      sz = doshdr->lfanew + sizeof (*pe64);
++      if (kernel_size < sz)
++	return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
++
++      if (pe64->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT)
++	image_is_compatible = 1;
++    }
++  else
++    {
++      if (pe32->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT)
++	image_is_compatible = 1;
++    }
++
++  *nx_supported = image_is_compatible;
++  return GRUB_ERR_NONE;
++}
++
++grub_err_t
++grub_efi_check_nx_required (int *nx_required)
++{
++  grub_efi_status_t status;
++  grub_efi_guid_t guid = GRUB_EFI_SHIM_LOCK_GUID;
++  grub_size_t mok_policy_sz = 0;
++  char *mok_policy = NULL;
++  grub_uint32_t mok_policy_attrs = 0;
++
++  status = grub_efi_get_variable_with_attributes ("MokPolicy", &guid,
++						  &mok_policy_sz,
++						  (void **)&mok_policy,
++						  &mok_policy_attrs);
++  if (status == GRUB_EFI_NOT_FOUND ||
++      mok_policy_sz == 0 ||
++      mok_policy == NULL)
++    {
++      *nx_required = 0;
++      return GRUB_ERR_NONE;
++    }
++
++  *nx_required = 0;
++  if (mok_policy_sz < 1 ||
++      mok_policy_attrs != (GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS |
++			   GRUB_EFI_VARIABLE_RUNTIME_ACCESS) ||
++      (mok_policy[mok_policy_sz-1] & GRUB_MOK_POLICY_NX_REQUIRED))
++    *nx_required = 1;
++
++  return GRUB_ERR_NONE;
++}
+ 
+ typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *);
+ 
+ grub_err_t
+-grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
+-		     void *kernel_params)
++grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size,
++		     grub_off_t handover_offset, void *kernel_params,
++		     int nx_supported)
+ {
+   grub_efi_loaded_image_t *loaded_image = NULL;
+   handover_func hf;
+   int offset = 0;
++  grub_uint64_t stack_set_attrs = GRUB_MEM_ATTR_R |
++				  GRUB_MEM_ATTR_W |
++				  GRUB_MEM_ATTR_X;
++  grub_uint64_t stack_clear_attrs = 0;
++  grub_uint64_t kernel_set_attrs = stack_set_attrs;
++  grub_uint64_t kernel_clear_attrs = stack_clear_attrs;
++  grub_uint64_t attrs;
++  int nx_required = 0;
+ 
+ #ifdef __x86_64__
+   offset = 512;
+@@ -48,12 +159,57 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
+    */
+   loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
+   if (loaded_image)
+-    loaded_image->image_base = kernel_addr;
++    loaded_image->image_base = (void *)kernel_addr;
+   else
+     grub_dprintf ("linux", "Loaded Image base address could not be set\n");
+ 
+   grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n",
+-		kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params);
++		(void *)kernel_addr, (void *)handover_offset, kernel_params);
++
++
++  if (nx_required && !nx_supported)
++    return grub_error (GRUB_ERR_BAD_OS, N_("kernel does not support NX loading required by policy"));
++
++  if (nx_supported)
++    {
++      kernel_set_attrs &= ~GRUB_MEM_ATTR_W;
++      kernel_clear_attrs |= GRUB_MEM_ATTR_W;
++      stack_set_attrs &= ~GRUB_MEM_ATTR_X;
++      stack_clear_attrs |= GRUB_MEM_ATTR_X;
++    }
++
++  grub_dprintf ("nx", "Setting attributes for 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to r%cx\n",
++		    kernel_addr, kernel_addr + kernel_size - 1,
++		    (kernel_set_attrs & GRUB_MEM_ATTR_W) ? 'w' : '-');
++  grub_update_mem_attrs (kernel_addr, kernel_size,
++			 kernel_set_attrs, kernel_clear_attrs);
++
++  grub_get_mem_attrs (kernel_addr, 4096, &attrs);
++  grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
++		(grub_addr_t)kernel_addr,
++		(attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
++		(attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
++		(attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
++  if (grub_stack_addr != (grub_addr_t)-1ll)
++    {
++      grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n",
++		    grub_stack_addr, grub_stack_addr + grub_stack_size - 1,
++		    (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-');
++      grub_update_mem_attrs (grub_stack_addr, grub_stack_size,
++			     stack_set_attrs, stack_clear_attrs);
++
++      grub_get_mem_attrs (grub_stack_addr, 4096, &attrs);
++      grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
++		    grub_stack_addr,
++		    (attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
++		    (attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
++		    (attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
++    }
++
++#if defined(__i386__) || defined(__x86_64__)
++  asm volatile ("cli");
++#endif
++
+   hf = (handover_func)((char *)kernel_addr + handover_offset + offset);
+   hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
+ 
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 92b2fb5091..91ae274299 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -44,7 +44,7 @@ struct grub_linuxefi_context {
+   grub_uint32_t handover_offset;
+   struct linux_kernel_params *params;
+   char *cmdline;
+-
++  int nx_supported;
+   void *initrd_mem;
+ };
+ 
+@@ -110,13 +110,19 @@ kernel_alloc(grub_efi_uintn_t size,
+       pages = BYTES_TO_PAGES(size);
+       grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n",
+ 		    (unsigned long)pages, (void *)(unsigned long)max);
++      size = pages * GRUB_EFI_PAGE_SIZE;
+ 
+       prev_max = max;
+       addr = grub_efi_allocate_pages_real (max, pages,
+ 					   max_addresses[i].alloc_type,
+ 					   memtype);
+       if (addr)
+-	grub_dprintf ("linux", "Allocated at %p\n", addr);
++	{
++	  grub_dprintf ("linux", "Allocated at %p\n", addr);
++	  grub_update_mem_attrs ((grub_addr_t)addr, size,
++				 GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W,
++				 GRUB_MEM_ATTR_X);
++	}
+     }
+ 
+   while (grub_error_pop ())
+@@ -137,9 +143,11 @@ grub_linuxefi_boot (void *data)
+ 
+   asm volatile ("cli");
+ 
+-  return grub_efi_linux_boot ((char *)context->kernel_mem,
++  return grub_efi_linux_boot ((grub_addr_t)context->kernel_mem,
++			      context->kernel_size,
+ 			      context->handover_offset,
+-			      context->params);
++			      context->params,
++			      context->nx_supported);
+ }
+ 
+ static grub_err_t
+@@ -304,7 +312,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_uint32_t handover_offset;
+   struct linux_kernel_params *params = 0;
+   char *cmdline = 0;
++  int nx_supported = 1;
+   struct grub_linuxefi_context *context = 0;
++  grub_err_t err;
+ 
+   grub_dl_ref (my_mod);
+ 
+@@ -334,6 +344,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
++  err = grub_efi_check_nx_image_support ((grub_addr_t)kernel, filelen,
++					 &nx_supported);
++  if (err != GRUB_ERR_NONE)
++    return err;
++  grub_dprintf ("linux", "nx is%s supported by this kernel\n",
++		nx_supported ? "" : " not");
++
+   lh = (struct linux_i386_kernel_header *)kernel;
+   grub_dprintf ("linux", "original lh is at %p\n", kernel);
+ 
+@@ -498,6 +515,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   context->handover_offset = handover_offset;
+   context->params = params;
+   context->cmdline = cmdline;
++  context->nx_supported = nx_supported;
+ 
+   grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0);
+ 
+diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
+index 4aeb0e4b9a..3c1ff64763 100644
+--- a/grub-core/loader/i386/linux.c
++++ b/grub-core/loader/i386/linux.c
+@@ -805,6 +805,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       kernel_offset += len;
+     }
+ 
++  grub_dprintf("efi", "setting attributes for %p (%zu bytes) to +rw-x\n",
++	       &linux_params, sizeof (lh) + len);
++  grub_update_mem_attrs ((grub_addr_t)&linux_params, sizeof (lh) + len,
++			 GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, GRUB_MEM_ATTR_X);
++
+   linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR;
+   linux_params.kernel_alignment = (1 << align);
+   linux_params.ps_mouse = linux_params.padding11 = 0;
+diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
+index 34825c4adc..449e55269f 100644
+--- a/include/grub/efi/efi.h
++++ b/include/grub/efi/efi.h
+@@ -140,12 +140,16 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd,
+ 						char **device,
+ 						char **path);
+ 
++extern grub_addr_t EXPORT_VAR(grub_stack_addr);
++extern grub_size_t EXPORT_VAR(grub_stack_size);
++
+ #if defined(__arm__) || defined(__aarch64__) || defined(__riscv)
+ void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void);
+ grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *);
+ #include <grub/cpu/linux.h>
+ grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh);
+-grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, char *args);
++grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, grub_size_t size,
++					  char *args, int nx_enabled);
+ #endif
+ 
+ grub_addr_t grub_efi_section_addr (const char *section);
+diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
+index 887b02fd9f..b82f71006a 100644
+--- a/include/grub/efi/linux.h
++++ b/include/grub/efi/linux.h
+@@ -22,8 +22,20 @@
+ #include <grub/err.h>
+ #include <grub/symbol.h>
+ 
++#define GRUB_MOK_POLICY_NX_REQUIRED   0x1
++
+ grub_err_t
+-EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset,
+-				  void *kernel_param);
++EXPORT_FUNC(grub_efi_linux_boot) (grub_addr_t kernel_address,
++				  grub_size_t kernel_size,
++				  grub_off_t handover_offset,
++				  void *kernel_param, int nx_enabled);
++
++grub_err_t
++EXPORT_FUNC(grub_efi_check_nx_image_support) (grub_addr_t kernel_addr,
++					      grub_size_t kernel_size,
++					      int *nx_supported);
++
++grub_err_t
++EXPORT_FUNC(grub_efi_check_nx_required) (int *nx_required);
+ 
+ #endif /* ! GRUB_EFI_LINUX_HEADER */
+diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
+index 2a5e1ee003..a5e623eb04 100644
+--- a/include/grub/efi/pe32.h
++++ b/include/grub/efi/pe32.h
+@@ -181,6 +181,8 @@ struct grub_pe32_optional_header
+   struct grub_pe32_data_directory reserved_entry;
+ };
+ 
++#define GRUB_PE32_NX_COMPAT 0x0100
++
+ struct grub_pe64_optional_header
+ {
+   grub_uint16_t magic;
diff --git a/SOURCES/0258-net-http-Fix-OOB-write-for-split-http-headers.patch b/SOURCES/0258-net-http-Fix-OOB-write-for-split-http-headers.patch
deleted file mode 100644
index 367a827..0000000
--- a/SOURCES/0258-net-http-Fix-OOB-write-for-split-http-headers.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Tue, 8 Mar 2022 18:17:03 +1100
-Subject: [PATCH] net/http: Fix OOB write for split http headers
-
-GRUB has special code for handling an http header that is split
-across two packets.
-
-The code tracks the end of line by looking for a "\n" byte. The
-code for split headers has always advanced the pointer just past the
-end of the line, whereas the code that handles unsplit headers does
-not advance the pointer. This extra advance causes the length to be
-one greater, which breaks an assumption in parse_line(), leading to
-it writing a NUL byte one byte past the end of the buffer where we
-reconstruct the line from the two packets.
-
-It's conceivable that an attacker controlled set of packets could
-cause this to zero out the first byte of the "next" pointer of the
-grub_mm_region structure following the current_line buffer.
-
-Do not advance the pointer in the split header case.
-
-Fixes: CVE-2022-28734
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit e9fb459638811c12b0989dbf64e3e124974ef617)
-(cherry picked from commit b604916beb6c39e8ed27f72851eb16f3eaa293c5)
----
- grub-core/net/http.c | 4 +---
- 1 file changed, 1 insertion(+), 3 deletions(-)
-
-diff --git a/grub-core/net/http.c b/grub-core/net/http.c
-index 19cb8768e3..58546739a2 100644
---- a/grub-core/net/http.c
-+++ b/grub-core/net/http.c
-@@ -193,9 +193,7 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)),
- 	  int have_line = 1;
- 	  char *t;
- 	  ptr = grub_memchr (nb->data, '\n', nb->tail - nb->data);
--	  if (ptr)
--	    ptr++;
--	  else
-+	  if (ptr == NULL)
- 	    {
- 	      have_line = 0;
- 	      ptr = (char *) nb->tail;
diff --git a/SOURCES/0258-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch b/SOURCES/0258-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch
new file mode 100644
index 0000000..7da75a8
--- /dev/null
+++ b/SOURCES/0258-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch
@@ -0,0 +1,34 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 22 Mar 2022 10:57:20 -0400
+Subject: [PATCH] nx: set the nx compatible flag in EFI grub images
+
+For NX, we need the grub binary to announce that it is compatible with
+the NX feature.  This implies that when loading the executable grub
+image, several attributes are true:
+
+- the binary doesn't need an executable stack
+- the binary doesn't need sections to be both executable and writable
+- the binary knows how to use the EFI Memory Attributes protocol on code
+  it is loading.
+
+This patch adds a definition for the PE DLL Characteristics flag
+GRUB_PE32_NX_COMPAT, and changes grub-mkimage to set that flag.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/mkimage.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/util/mkimage.c b/util/mkimage.c
+index 8319e8dfbd..c3d33aaac8 100644
+--- a/util/mkimage.c
++++ b/util/mkimage.c
+@@ -1418,6 +1418,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
+ 	    section = (struct grub_pe32_section_table *)(o64 + 1);
+ 	  }
+ 
++	PE_OHDR (o32, o64, dll_characteristics) = grub_host_to_target16 (GRUB_PE32_NX_COMPAT);
+ 	PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size);
+ 	PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address);
+ 	PE_OHDR (o32, o64, image_base) = 0;
diff --git a/SOURCES/0259-grub-probe-document-the-behavior-of-multiple-v.patch b/SOURCES/0259-grub-probe-document-the-behavior-of-multiple-v.patch
new file mode 100644
index 0000000..4e9d7cc
--- /dev/null
+++ b/SOURCES/0259-grub-probe-document-the-behavior-of-multiple-v.patch
@@ -0,0 +1,25 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Fri, 15 Jul 2022 15:49:25 -0400
+Subject: [PATCH] grub-probe: document the behavior of multiple -v
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+(cherry picked from commit 51a55233eed08f7f12276afd6b3724b807a0b680)
+---
+ util/grub-probe.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/util/grub-probe.c b/util/grub-probe.c
+index c6fac732b4..ba867319a7 100644
+--- a/util/grub-probe.c
++++ b/util/grub-probe.c
+@@ -732,7 +732,8 @@ static struct argp_option options[] = {
+   {"device-map",  'm', N_("FILE"), 0,
+    N_("use FILE as the device map [default=%s]"), 0},
+   {"target",  't', N_("TARGET"), 0, 0, 0},
+-  {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
++  {"verbose",     'v', 0,      0,
++   N_("print verbose messages (pass twice to enable debug printing)."), 0},
+   {0, '0', 0, 0, N_("separate items in output using ASCII NUL characters"), 0},
+   { 0, 0, 0, 0, 0, 0 }
+ };
diff --git a/SOURCES/0259-net-http-Error-out-on-headers-with-LF-without-CR.patch b/SOURCES/0259-net-http-Error-out-on-headers-with-LF-without-CR.patch
deleted file mode 100644
index ea8ce37..0000000
--- a/SOURCES/0259-net-http-Error-out-on-headers-with-LF-without-CR.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Daniel Axtens <dja@axtens.net>
-Date: Tue, 8 Mar 2022 19:04:40 +1100
-Subject: [PATCH] net/http: Error out on headers with LF without CR
-
-In a similar vein to the previous patch, parse_line() would write
-a NUL byte past the end of the buffer if there was an HTTP header
-with a LF rather than a CRLF.
-
-RFC-2616 says:
-
-  Many HTTP/1.1 header field values consist of words separated by LWS
-  or special characters. These special characters MUST be in a quoted
-  string to be used within a parameter value (as defined in section 3.6).
-
-We don't support quoted sections or continuation lines, etc.
-
-If we see an LF that's not part of a CRLF, bail out.
-
-Fixes: CVE-2022-28734
-
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit d232ad41ac4979a9de4d746e5fdff9caf0e303de)
-(cherry picked from commit 8960e6d6137090a7e8c6592077da6e387a4ef972)
----
- grub-core/net/http.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/grub-core/net/http.c b/grub-core/net/http.c
-index 58546739a2..57d2721719 100644
---- a/grub-core/net/http.c
-+++ b/grub-core/net/http.c
-@@ -69,7 +69,15 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len)
-   char *end = ptr + len;
-   while (end > ptr && *(end - 1) == '\r')
-     end--;
-+
-+  /* LF without CR. */
-+  if (end == ptr + len)
-+    {
-+      data->errmsg = grub_strdup (_("invalid HTTP header - LF without CR"));
-+      return GRUB_ERR_NONE;
-+    }
-   *end = 0;
-+
-   /* Trailing CRLF.  */
-   if (data->in_chunk_len == 1)
-     {
diff --git a/SOURCES/0260-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch b/SOURCES/0260-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch
deleted file mode 100644
index f0292c5..0000000
--- a/SOURCES/0260-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch
+++ /dev/null
@@ -1,73 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
-Date: Wed, 6 Apr 2022 18:03:37 +0530
-Subject: [PATCH] fs/f2fs: Do not read past the end of nat journal entries
-
-A corrupt f2fs file system could specify a nat journal entry count
-that is beyond the maximum NAT_JOURNAL_ENTRIES.
-
-Check if the specified nat journal entry count before accessing the
-array, and throw an error if it is too large.
-
-Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit a3988cb3f0a108dd67ac127a79a4c8479d23334e)
-(cherry picked from commit 7125978aa7d6068812ef6da0ab38ce521ae7eba1)
----
- grub-core/fs/f2fs.c | 21 ++++++++++++++-------
- 1 file changed, 14 insertions(+), 7 deletions(-)
-
-diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
-index 8a9992ca9e..63702214b0 100644
---- a/grub-core/fs/f2fs.c
-+++ b/grub-core/fs/f2fs.c
-@@ -632,23 +632,27 @@ get_nat_journal (struct grub_f2fs_data *data)
-   return err;
- }
- 
--static grub_uint32_t
--get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid)
-+static grub_err_t
-+get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid,
-+                              grub_uint32_t *blkaddr)
- {
-   grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats);
--  grub_uint32_t blkaddr = 0;
-   grub_uint16_t i;
- 
-+  if (n >= NAT_JOURNAL_ENTRIES)
-+    return grub_error (GRUB_ERR_BAD_FS,
-+                       "invalid number of nat journal entries");
-+
-   for (i = 0; i < n; i++)
-     {
-       if (grub_le_to_cpu32 (data->nat_j.entries[i].nid) == nid)
-         {
--          blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr);
-+          *blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr);
-           break;
-         }
-     }
- 
--  return blkaddr;
-+  return GRUB_ERR_NONE;
- }
- 
- static grub_uint32_t
-@@ -656,10 +660,13 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
- {
-   struct grub_f2fs_nat_block *nat_block;
-   grub_uint32_t seg_off, block_off, entry_off, block_addr;
--  grub_uint32_t blkaddr;
-+  grub_uint32_t blkaddr = 0;
-   grub_err_t err;
- 
--  blkaddr = get_blkaddr_from_nat_journal (data, nid);
-+  err = get_blkaddr_from_nat_journal (data, nid, &blkaddr);
-+  if (err != GRUB_ERR_NONE)
-+    return 0;
-+
-   if (blkaddr)
-     return blkaddr;
- 
diff --git a/SOURCES/0260-grub_fs_probe-dprint-errors-from-filesystems.patch b/SOURCES/0260-grub_fs_probe-dprint-errors-from-filesystems.patch
new file mode 100644
index 0000000..1455ae4
--- /dev/null
+++ b/SOURCES/0260-grub_fs_probe-dprint-errors-from-filesystems.patch
@@ -0,0 +1,43 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Fri, 15 Jul 2022 15:39:41 -0400
+Subject: [PATCH] grub_fs_probe(): dprint errors from filesystems
+
+When filesystem detection fails, all that's currently debug-logged is a
+series of messages like:
+
+    grub-core/kern/fs.c:56:fs: Detecting ntfs...
+    grub-core/kern/fs.c:76:fs: ntfs detection failed.
+
+repeated for each filesystem.  Any messages provided to grub_error() by
+the filesystem are lost, and one has to break out gdb to figure out what
+went wrong.
+
+With this change, one instead sees:
+
+    grub-core/kern/fs.c:56:fs: Detecting fat...
+    grub-core/osdep/hostdisk.c:357:hostdisk: reusing open device
+    `/path/to/device'
+    grub-core/kern/fs.c:77:fs: error: invalid modification timestamp for /.
+    grub-core/kern/fs.c:79:fs: fat detection failed.
+
+in the debug prints.
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+(cherry picked from commit 838c79d658797d0662ee7f9e033e38ee88059e02)
+---
+ grub-core/kern/fs.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/grub-core/kern/fs.c b/grub-core/kern/fs.c
+index c698295bcb..b58e2ae1d2 100644
+--- a/grub-core/kern/fs.c
++++ b/grub-core/kern/fs.c
+@@ -74,6 +74,7 @@ grub_fs_probe (grub_device_t device)
+ 	  if (grub_errno == GRUB_ERR_NONE)
+ 	    return p;
+ 
++	  grub_dprintf ("fs", _("error: %s.\n"), grub_errmsg);
+ 	  grub_error_push ();
+ 	  grub_dprintf ("fs", "%s detection failed.\n", p->name);
+ 	  grub_error_pop ();
diff --git a/SOURCES/0261-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch b/SOURCES/0261-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch
deleted file mode 100644
index 1d59fb6..0000000
--- a/SOURCES/0261-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch
+++ /dev/null
@@ -1,133 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
-Date: Wed, 6 Apr 2022 18:49:09 +0530
-Subject: [PATCH] fs/f2fs: Do not read past the end of nat bitmap
-
-A corrupt f2fs filesystem could have a block offset or a bitmap
-offset that would cause us to read beyond the bounds of the nat
-bitmap.
-
-Introduce the nat_bitmap_size member in grub_f2fs_data which holds
-the size of nat bitmap.
-
-Set the size when loading the nat bitmap in nat_bitmap_ptr(), and
-catch when an invalid offset would create a pointer past the end of
-the allocated space.
-
-Check against the bitmap size in grub_f2fs_test_bit() test bit to avoid
-reading past the end of the nat bitmap.
-
-Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 62d63d5e38c67a6e349148bf7cb87c560e935a7e)
-(cherry picked from commit 92219e6d379b5b4d30b05361830b72ab1d95d281)
----
- grub-core/fs/f2fs.c | 33 +++++++++++++++++++++++++++------
- 1 file changed, 27 insertions(+), 6 deletions(-)
-
-diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
-index 63702214b0..8898b235e0 100644
---- a/grub-core/fs/f2fs.c
-+++ b/grub-core/fs/f2fs.c
-@@ -122,6 +122,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
- #define F2FS_INLINE_DOTS          0x10  /* File having implicit dot dentries. */
- 
- #define MAX_VOLUME_NAME           512
-+#define MAX_NAT_BITMAP_SIZE       3900
- 
- enum FILE_TYPE
- {
-@@ -183,7 +184,7 @@ struct grub_f2fs_checkpoint
-   grub_uint32_t                   checksum_offset;
-   grub_uint64_t                   elapsed_time;
-   grub_uint8_t                    alloc_type[MAX_ACTIVE_LOGS];
--  grub_uint8_t                    sit_nat_version_bitmap[3900];
-+  grub_uint8_t                    sit_nat_version_bitmap[MAX_NAT_BITMAP_SIZE];
-   grub_uint32_t                   checksum;
- } GRUB_PACKED;
- 
-@@ -302,6 +303,7 @@ struct grub_f2fs_data
- 
-   struct grub_f2fs_nat_journal    nat_j;
-   char                            *nat_bitmap;
-+  grub_uint32_t                   nat_bitmap_size;
- 
-   grub_disk_t                     disk;
-   struct grub_f2fs_node           *inode;
-@@ -377,15 +379,20 @@ sum_blk_addr (struct grub_f2fs_data *data, int base, int type)
- }
- 
- static void *
--nat_bitmap_ptr (struct grub_f2fs_data *data)
-+nat_bitmap_ptr (struct grub_f2fs_data *data, grub_uint32_t *nat_bitmap_size)
- {
-   struct grub_f2fs_checkpoint *ckpt = &data->ckpt;
-   grub_uint32_t offset;
-+  *nat_bitmap_size = MAX_NAT_BITMAP_SIZE;
- 
-   if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0)
-     return ckpt->sit_nat_version_bitmap;
- 
-   offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize);
-+  if (offset >= MAX_NAT_BITMAP_SIZE)
-+     return NULL;
-+
-+  *nat_bitmap_size = *nat_bitmap_size - offset;
- 
-   return ckpt->sit_nat_version_bitmap + offset;
- }
-@@ -438,11 +445,15 @@ grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len)
- }
- 
- static int
--grub_f2fs_test_bit (grub_uint32_t nr, const char *p)
-+grub_f2fs_test_bit (grub_uint32_t nr, const char *p, grub_uint32_t len)
- {
-   int mask;
-+  grub_uint32_t shifted_nr = (nr >> 3);
- 
--  p += (nr >> 3);
-+  if (shifted_nr >= len)
-+    return -1;
-+
-+  p += shifted_nr;
-   mask = 1 << (7 - (nr & 0x07));
- 
-   return mask & *p;
-@@ -662,6 +673,7 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
-   grub_uint32_t seg_off, block_off, entry_off, block_addr;
-   grub_uint32_t blkaddr = 0;
-   grub_err_t err;
-+  int result_bit;
- 
-   err = get_blkaddr_from_nat_journal (data, nid, &blkaddr);
-   if (err != GRUB_ERR_NONE)
-@@ -682,8 +694,15 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
-         ((seg_off * data->blocks_per_seg) << 1) +
-         (block_off & (data->blocks_per_seg - 1));
- 
--  if (grub_f2fs_test_bit (block_off, data->nat_bitmap))
-+  result_bit = grub_f2fs_test_bit (block_off, data->nat_bitmap,
-+                                   data->nat_bitmap_size);
-+  if (result_bit > 0)
-     block_addr += data->blocks_per_seg;
-+  else if (result_bit == -1)
-+    {
-+      grub_free (nat_block);
-+      return 0;
-+    }
- 
-   err = grub_f2fs_block_read (data, block_addr, nat_block);
-   if (err)
-@@ -833,7 +852,9 @@ grub_f2fs_mount (grub_disk_t disk)
-   if (err)
-     goto fail;
- 
--  data->nat_bitmap = nat_bitmap_ptr (data);
-+  data->nat_bitmap = nat_bitmap_ptr (data, &data->nat_bitmap_size);
-+  if (data->nat_bitmap == NULL)
-+    goto fail;
- 
-   err = get_nat_journal (data);
-   if (err)
diff --git a/SOURCES/0261-fs-fat-don-t-error-when-mtime-is-0.patch b/SOURCES/0261-fs-fat-don-t-error-when-mtime-is-0.patch
new file mode 100644
index 0000000..f014f6c
--- /dev/null
+++ b/SOURCES/0261-fs-fat-don-t-error-when-mtime-is-0.patch
@@ -0,0 +1,64 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Fri, 15 Jul 2022 15:42:41 -0400
+Subject: [PATCH] fs/fat: don't error when mtime is 0
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+In the wild, we occasionally see valid ESPs where some file modification times
+are 0.  For instance:
+
+    ├── [Dec 31  1979]  EFI
+    │   ├── [Dec 31  1979]  BOOT
+    │   │   ├── [Dec 31  1979]  BOOTX64.EFI
+    │   │   └── [Dec 31  1979]  fbx64.efi
+    │   └── [Jun 27 02:41]  fedora
+    │       ├── [Dec 31  1979]  BOOTX64.CSV
+    │       ├── [Dec 31  1979]  fonts
+    │       ├── [Mar 14 03:35]  fw
+    │       │   ├── [Mar 14 03:35]  fwupd-359c1169-abd6-4a0d-8bce-e4d4713335c1.cap
+    │       │   ├── [Mar 14 03:34]  fwupd-9d255c4b-2d88-4861-860d-7ee52ade9463.cap
+    │       │   └── [Mar 14 03:34]  fwupd-b36438d8-9128-49d2-b280-487be02d948b.cap
+    │       ├── [Dec 31  1979]  fwupdx64.efi
+    │       ├── [May 10 10:47]  grub.cfg
+    │       ├── [Jun  3 12:38]  grub.cfg.new.new
+    │       ├── [May 10 10:41]  grub.cfg.old
+    │       ├── [Jun 27 02:41]  grubenv
+    │       ├── [Dec 31  1979]  grubx64.efi
+    │       ├── [Dec 31  1979]  mmx64.efi
+    │       ├── [Dec 31  1979]  shim.efi
+    │       ├── [Dec 31  1979]  shimx64.efi
+    │       └── [Dec 31  1979]  shimx64-fedora.efi
+    └── [Dec 31  1979]  FSCK0000.REC
+
+    5 directories, 17 files
+
+This causes grub-probe failure, which in turn causes grub-mkconfig
+failure.  They are valid filesystems that appear intact, and the Linux
+FAT stack is able to mount and manipulate them without complaint.
+
+The check for mtime of 0 has been present since
+20def1a3c3952982395cd7c3ea7e78638527962b ("fat: support file
+modification times").
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+(cherry picked from commit 0615c4887352e32d7bb7198e9ad0d695f9dc2c31)
+---
+ grub-core/fs/fat.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/grub-core/fs/fat.c b/grub-core/fs/fat.c
+index dd82e4ee35..ff6200c5be 100644
+--- a/grub-core/fs/fat.c
++++ b/grub-core/fs/fat.c
+@@ -1027,9 +1027,6 @@ grub_fat_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
+ 					  grub_le_to_cpu16 (ctxt.dir.w_date),
+ 					  &info.mtime);
+ #endif
+-      if (info.mtimeset == 0)
+-	grub_error (GRUB_ERR_OUT_OF_RANGE,
+-		    "invalid modification timestamp for %s", path);
+ 
+       if (hook (ctxt.filename, &info, hook_data))
+ 	break;
diff --git a/SOURCES/0262-Make-debug-file-show-which-file-filters-get-run.patch b/SOURCES/0262-Make-debug-file-show-which-file-filters-get-run.patch
new file mode 100644
index 0000000..78bc095
--- /dev/null
+++ b/SOURCES/0262-Make-debug-file-show-which-file-filters-get-run.patch
@@ -0,0 +1,45 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 29 Jul 2022 15:56:00 -0400
+Subject: [PATCH] Make debug=file show which file filters get run.
+
+If one of the file filters breaks things, it's hard to figure out where
+it has happened.
+
+This makes grub log which filter is being run, which makes it easier to
+figure out where you are in the sequence of events.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/file.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
+index db938e099d..868ce3b63e 100644
+--- a/grub-core/kern/file.c
++++ b/grub-core/kern/file.c
+@@ -30,6 +30,14 @@ void (*EXPORT_VAR (grub_grubnet_fini)) (void);
+ 
+ grub_file_filter_t grub_file_filters[GRUB_FILE_FILTER_MAX];
+ 
++static const char *filter_names[] = {
++    [GRUB_FILE_FILTER_VERIFY] = "GRUB_FILE_FILTER_VERIFY",
++    [GRUB_FILE_FILTER_GZIO] = "GRUB_FILE_FILTER_GZIO",
++    [GRUB_FILE_FILTER_XZIO] = "GRUB_FILE_FILTER_XZIO",
++    [GRUB_FILE_FILTER_LZOPIO] = "GRUB_FILE_FILTER_LZOPIO",
++    [GRUB_FILE_FILTER_MAX] = "GRUB_FILE_FILTER_MAX"
++};
++
+ /* Get the device part of the filename NAME. It is enclosed by parentheses.  */
+ char *
+ grub_file_get_device_name (const char *name)
+@@ -124,6 +132,9 @@ grub_file_open (const char *name, enum grub_file_type type)
+     if (grub_file_filters[filter])
+       {
+ 	last_file = file;
++	if (filter < GRUB_FILE_FILTER_MAX)
++	  grub_dprintf ("file", "Running %s file filter\n",
++			filter_names[filter]);
+ 	file = grub_file_filters[filter] (file, type);
+ 	if (file && file != last_file)
+ 	  {
diff --git a/SOURCES/0262-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch b/SOURCES/0262-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch
deleted file mode 100644
index c454897..0000000
--- a/SOURCES/0262-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
-Date: Wed, 6 Apr 2022 18:17:43 +0530
-Subject: [PATCH] fs/f2fs: Do not copy file names that are too long
-
-A corrupt f2fs file system might specify a name length which is greater
-than the maximum name length supported by the GRUB f2fs driver.
-
-We will allocate enough memory to store the overly long name, but there
-are only F2FS_NAME_LEN bytes in the source, so we would read past the end
-of the source.
-
-While checking directory entries, do not copy a file name with an invalid
-length.
-
-Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
-Signed-off-by: Daniel Axtens <dja@axtens.net>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 9a891f638509e031d322c94e3cbcf38d36f3993a)
-(cherry picked from commit 13f9160ae0d2806baed459884999356817096cd7)
----
- grub-core/fs/f2fs.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
-index 8898b235e0..df6beb544c 100644
---- a/grub-core/fs/f2fs.c
-+++ b/grub-core/fs/f2fs.c
-@@ -1003,6 +1003,10 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx)
- 
-       ftype = ctx->dentry[i].file_type;
-       name_len = grub_le_to_cpu16 (ctx->dentry[i].name_len);
-+
-+      if (name_len >= F2FS_NAME_LEN)
-+        return 0;
-+
-       filename = grub_malloc (name_len + 1);
-       if (!filename)
-         return 0;
diff --git a/SOURCES/0263-efi-use-enumerated-array-positions-for-our-allocatio.patch b/SOURCES/0263-efi-use-enumerated-array-positions-for-our-allocatio.patch
new file mode 100644
index 0000000..206e3a6
--- /dev/null
+++ b/SOURCES/0263-efi-use-enumerated-array-positions-for-our-allocatio.patch
@@ -0,0 +1,81 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 1 Aug 2022 14:06:30 -0400
+Subject: [PATCH] efi: use enumerated array positions for our allocation
+ choices
+
+In our kernel allocator on EFI systems, we currently have a growing
+amount of code that references the various allocation policies by
+position in the array, and of course maintenance of this code scales
+very poorly.
+
+This patch changes them to be enumerated, so they're easier to refer to
+farther along in the code without confusion.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/i386/efi/linux.c | 31 ++++++++++++++++++++-----------
+ 1 file changed, 20 insertions(+), 11 deletions(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 91ae274299..8daa070132 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -60,17 +60,26 @@ struct allocation_choice {
+     grub_efi_allocate_type_t alloc_type;
+ };
+ 
+-static struct allocation_choice max_addresses[4] =
++enum {
++    KERNEL_PREF_ADDRESS,
++    KERNEL_4G_LIMIT,
++    KERNEL_NO_LIMIT,
++};
++
++static struct allocation_choice max_addresses[] =
+   {
+     /* the kernel overrides this one with pref_address and
+      * GRUB_EFI_ALLOCATE_ADDRESS */
+-    { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
++    [KERNEL_PREF_ADDRESS] =
++      { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
++    /* If the flag in params is set, this one gets changed to be above 4GB. */
++    [KERNEL_4G_LIMIT] =
++      { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
+     /* this one is always below 4GB, which we still *prefer* even if the flag
+      * is set. */
+-    { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
+-    /* If the flag in params is set, this one gets changed to be above 4GB. */
+-    { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
+-    { 0, 0 }
++    [KERNEL_NO_LIMIT] =
++      { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
++    { NO_MEM, 0, 0 }
+   };
+ static struct allocation_choice saved_addresses[4];
+ 
+@@ -405,7 +414,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G)
+     {
+       grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n");
+-      max_addresses[2].addr = GRUB_EFI_MAX_USABLE_ADDRESS;
++      max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_USABLE_ADDRESS;
+     }
+   else
+     {
+@@ -478,11 +487,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address);
+   if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS)
+     {
+-      max_addresses[0].addr = lh->pref_address;
+-      max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS;
++      max_addresses[KERNEL_PREF_ADDRESS].addr = lh->pref_address;
++      max_addresses[KERNEL_PREF_ADDRESS].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS;
+     }
+-  max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
+-  max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
++  max_addresses[KERNEL_4G_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
++  max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
+   kernel_size = lh->init_size;
+   kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE,
+ 			     N_("can't allocate kernel"));
diff --git a/SOURCES/0263-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch b/SOURCES/0263-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch
deleted file mode 100644
index 5e8cd4d..0000000
--- a/SOURCES/0263-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch
+++ /dev/null
@@ -1,80 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Darren Kenny <darren.kenny@oracle.com>
-Date: Tue, 29 Mar 2022 10:49:56 +0000
-Subject: [PATCH] fs/btrfs: Fix several fuzz issues with invalid dir item
- sizing
-
-According to the btrfs code in Linux, the structure of a directory item
-leaf should be of the form:
-
-  |struct btrfs_dir_item|name|data|
-
-in GRUB the name len and data len are in the grub_btrfs_dir_item
-structure's n and m fields respectively.
-
-The combined size of the structure, name and data should be less than
-the allocated memory, a difference to the Linux kernel's struct
-btrfs_dir_item is that the grub_btrfs_dir_item has an extra field for
-where the name is stored, so we adjust for that too.
-
-Signed-off-by: Darren Kenny <darren.kenny@oracle.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 6d3f06c0b6a8992b9b1bb0e62af93ac5ff2781f0)
-[rharwood: we've an extra variable here]
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
-(cherry picked from commit e3e21b9a81aea09dd43368cf097c1029a8380d82)
----
- grub-core/fs/btrfs.c | 26 ++++++++++++++++++++++++++
- 1 file changed, 26 insertions(+)
-
-diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
-index 4cc86e9b79..f3ab64e098 100644
---- a/grub-core/fs/btrfs.c
-+++ b/grub-core/fs/btrfs.c
-@@ -2254,6 +2254,7 @@ grub_btrfs_dir (grub_device_t device, const char *path,
-   grub_uint64_t tree;
-   grub_uint8_t type;
-   char *new_path = NULL;
-+  grub_size_t est_size = 0;
- 
-   if (!data)
-     return grub_errno;
-@@ -2320,6 +2321,18 @@ grub_btrfs_dir (grub_device_t device, const char *path,
- 	  break;
- 	}
- 
-+      if (direl == NULL ||
-+	  grub_add (grub_le_to_cpu16 (direl->n),
-+		    grub_le_to_cpu16 (direl->m), &est_size) ||
-+	  grub_add (est_size, sizeof (*direl), &est_size) ||
-+	  grub_sub (est_size, sizeof (direl->name), &est_size) ||
-+	  est_size > allocated)
-+       {
-+         grub_errno = GRUB_ERR_OUT_OF_RANGE;
-+         r = -grub_errno;
-+         goto out;
-+       }
-+
-       for (cdirel = direl;
- 	   (grub_uint8_t *) cdirel - (grub_uint8_t *) direl
- 	   < (grub_ssize_t) elemsize;
-@@ -2330,6 +2343,19 @@ grub_btrfs_dir (grub_device_t device, const char *path,
- 	  char c;
- 	  struct grub_btrfs_inode inode;
- 	  struct grub_dirhook_info info;
-+
-+	  if (cdirel == NULL ||
-+	      grub_add (grub_le_to_cpu16 (cdirel->n),
-+			grub_le_to_cpu16 (cdirel->m), &est_size) ||
-+	      grub_add (est_size, sizeof (*cdirel), &est_size) ||
-+	      grub_sub (est_size, sizeof (cdirel->name), &est_size) ||
-+	      est_size > allocated)
-+	   {
-+	     grub_errno = GRUB_ERR_OUT_OF_RANGE;
-+	     r = -grub_errno;
-+	     goto out;
-+	   }
-+
- 	  err = grub_btrfs_read_inode (data, &inode, cdirel->key.object_id,
- 				       tree);
- 	  grub_memset (&info, 0, sizeof (info));
diff --git a/SOURCES/0264-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch b/SOURCES/0264-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch
new file mode 100644
index 0000000..d25cf30
--- /dev/null
+++ b/SOURCES/0264-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch
@@ -0,0 +1,127 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 1 Aug 2022 14:24:39 -0400
+Subject: [PATCH] efi: split allocation policy for kernel vs initrd memories.
+
+Currently in our kernel allocator, we use the same set of choices for
+all of our various kernel and initramfs allocations, though they do not
+have exactly the same constraints.
+
+This patch adds the concept of an allocation purpose, which currently
+can be KERNEL_MEM or INITRD_MEM, and updates kernel_alloc() calls
+appropriately, but does not change any current policy decision.  It
+also adds a few debug prints.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/i386/efi/linux.c | 35 +++++++++++++++++++++++++++--------
+ 1 file changed, 27 insertions(+), 8 deletions(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 8daa070132..e6b8998e5e 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -55,7 +55,14 @@ struct grub_linuxefi_context {
+ 
+ #define BYTES_TO_PAGES(bytes)   (((bytes) + 0xfff) >> 12)
+ 
++typedef enum {
++    NO_MEM,
++    KERNEL_MEM,
++    INITRD_MEM,
++} kernel_alloc_purpose_t;
++
+ struct allocation_choice {
++    kernel_alloc_purpose_t purpose;
+     grub_efi_physical_address_t addr;
+     grub_efi_allocate_type_t alloc_type;
+ };
+@@ -64,6 +71,7 @@ enum {
+     KERNEL_PREF_ADDRESS,
+     KERNEL_4G_LIMIT,
+     KERNEL_NO_LIMIT,
++    INITRD_MAX_ADDRESS,
+ };
+ 
+ static struct allocation_choice max_addresses[] =
+@@ -71,14 +79,17 @@ static struct allocation_choice max_addresses[] =
+     /* the kernel overrides this one with pref_address and
+      * GRUB_EFI_ALLOCATE_ADDRESS */
+     [KERNEL_PREF_ADDRESS] =
+-      { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
++      { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
+     /* If the flag in params is set, this one gets changed to be above 4GB. */
+     [KERNEL_4G_LIMIT] =
+-      { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
++      { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
+     /* this one is always below 4GB, which we still *prefer* even if the flag
+      * is set. */
+     [KERNEL_NO_LIMIT] =
+-      { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
++      { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
++    /* this is for the initrd */
++    [INITRD_MAX_ADDRESS] =
++      { INITRD_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
+     { NO_MEM, 0, 0 }
+   };
+ static struct allocation_choice saved_addresses[4];
+@@ -95,7 +106,8 @@ kernel_free(void *addr, grub_efi_uintn_t size)
+ }
+ 
+ static void *
+-kernel_alloc(grub_efi_uintn_t size,
++kernel_alloc(kernel_alloc_purpose_t purpose,
++	     grub_efi_uintn_t size,
+ 	     grub_efi_memory_type_t memtype,
+ 	     const char * const errmsg)
+ {
+@@ -108,6 +120,9 @@ kernel_alloc(grub_efi_uintn_t size,
+       grub_uint64_t max = max_addresses[i].addr;
+       grub_efi_uintn_t pages;
+ 
++      if (purpose != max_addresses[i].purpose)
++	continue;
++
+       /*
+        * When we're *not* loading the kernel, or >4GB allocations aren't
+        * supported, these entries are basically all the same, so don't re-try
+@@ -261,7 +276,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
+ 	}
+     }
+ 
+-  initrd_mem = kernel_alloc(size, GRUB_EFI_RUNTIME_SERVICES_DATA,
++  grub_dprintf ("linux", "Trying to allocate initrd mem\n");
++  initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_RUNTIME_SERVICES_DATA,
+ 			    N_("can't allocate initrd"));
+   if (initrd_mem == NULL)
+     goto fail;
+@@ -422,7 +438,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+     }
+ #endif
+ 
+-  params = kernel_alloc (sizeof(*params), GRUB_EFI_RUNTIME_SERVICES_DATA,
++  params = kernel_alloc (KERNEL_MEM, sizeof(*params),
++			 GRUB_EFI_RUNTIME_SERVICES_DATA,
+ 			 "cannot allocate kernel parameters");
+   if (!params)
+     goto fail;
+@@ -445,7 +462,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_dprintf ("linux", "new lh is at %p\n", lh);
+ 
+   grub_dprintf ("linux", "setting up cmdline\n");
+-  cmdline = kernel_alloc (lh->cmdline_size + 1,
++  cmdline = kernel_alloc (KERNEL_MEM, lh->cmdline_size + 1,
+ 			  GRUB_EFI_RUNTIME_SERVICES_DATA,
+ 			  N_("can't allocate cmdline"));
+   if (!cmdline)
+@@ -493,7 +510,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   max_addresses[KERNEL_4G_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
+   max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
+   kernel_size = lh->init_size;
+-  kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE,
++  grub_dprintf ("linux", "Trying to allocate kernel mem\n");
++  kernel_mem = kernel_alloc (KERNEL_MEM, kernel_size,
++			     GRUB_EFI_RUNTIME_SERVICES_CODE,
+ 			     N_("can't allocate kernel"));
+   restore_addresses();
+   if (!kernel_mem)
diff --git a/SOURCES/0264-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch b/SOURCES/0264-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch
deleted file mode 100644
index f2a8815..0000000
--- a/SOURCES/0264-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch
+++ /dev/null
@@ -1,135 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Darren Kenny <darren.kenny@oracle.com>
-Date: Tue, 29 Mar 2022 15:52:46 +0000
-Subject: [PATCH] fs/btrfs: Fix more ASAN and SEGV issues found with fuzzing
-
-The fuzzer is generating btrfs file systems that have chunks with
-invalid combinations of stripes and substripes for the given RAID
-configurations.
-
-After examining the Linux kernel fs/btrfs/tree-checker.c code, it
-appears that sub-stripes should only be applied to RAID10, and in that
-case there should only ever be 2 of them.
-
-Similarly, RAID single should only have 1 stripe, and RAID1/1C3/1C4
-should have 2. 3 or 4 stripes respectively, which is what redundancy
-corresponds.
-
-Some of the chunks ended up with a size of 0, which grub_malloc() still
-returned memory for and in turn generated ASAN errors later when
-accessed.
-
-While it would be possible to specifically limit the number of stripes,
-a more correct test was on the combination of the chunk item, and the
-number of stripes by the size of the chunk stripe structure in
-comparison to the size of the chunk itself.
-
-Signed-off-by: Darren Kenny <darren.kenny@oracle.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 3849647b4b98a4419366708fc4b7f339c6f55ec7)
-(cherry picked from commit fa5a02a8930bbd8a3b5ae6ed9612307611f18500)
----
- grub-core/fs/btrfs.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 55 insertions(+)
-
-diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
-index f3ab64e098..b104da085c 100644
---- a/grub-core/fs/btrfs.c
-+++ b/grub-core/fs/btrfs.c
-@@ -941,6 +941,12 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
- 	return grub_error (GRUB_ERR_BAD_FS,
- 			   "couldn't find the chunk descriptor");
- 
-+      if (!chsize)
-+	{
-+	  grub_dprintf ("btrfs", "zero-size chunk\n");
-+	  return grub_error (GRUB_ERR_BAD_FS,
-+			     "got an invalid zero-size chunk");
-+	}
-       chunk = grub_malloc (chsize);
-       if (!chunk)
- 	return grub_errno;
-@@ -999,6 +1005,16 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
- 	      stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size),
- 					     nstripes,
- 					     NULL);
-+
-+	      /* For single, there should be exactly 1 stripe. */
-+	      if (grub_le_to_cpu16 (chunk->nstripes) != 1)
-+		{
-+		  grub_dprintf ("btrfs", "invalid RAID_SINGLE: nstripes != 1 (%u)\n",
-+				grub_le_to_cpu16 (chunk->nstripes));
-+		  return grub_error (GRUB_ERR_BAD_FS,
-+				     "invalid RAID_SINGLE: nstripes != 1 (%u)",
-+				      grub_le_to_cpu16 (chunk->nstripes));
-+		}
- 	      if (stripe_length == 0)
- 		stripe_length = 512;
- 	      stripen = grub_divmod64 (off, stripe_length, &stripe_offset);
-@@ -1018,6 +1034,19 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
- 	      stripen = 0;
- 	      stripe_offset = off;
- 	      csize = grub_le_to_cpu64 (chunk->size) - off;
-+
-+             /*
-+	      * Redundancy, and substripes only apply to RAID10, and there
-+	      * should be exactly 2 sub-stripes.
-+	      */
-+	     if (grub_le_to_cpu16 (chunk->nstripes) != redundancy)
-+               {
-+                 grub_dprintf ("btrfs", "invalid RAID1: nstripes != %u (%u)\n",
-+                               redundancy, grub_le_to_cpu16 (chunk->nstripes));
-+                 return grub_error (GRUB_ERR_BAD_FS,
-+                                    "invalid RAID1: nstripes != %u (%u)",
-+                                    redundancy, grub_le_to_cpu16 (chunk->nstripes));
-+               }
- 	      break;
- 	    }
- 	  case GRUB_BTRFS_CHUNK_TYPE_RAID0:
-@@ -1054,6 +1083,20 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
- 	      stripe_offset = low + chunk_stripe_length
- 		* high;
- 	      csize = chunk_stripe_length - low;
-+
-+	      /*
-+	       * Substripes only apply to RAID10, and there
-+	       * should be exactly 2 sub-stripes.
-+	       */
-+	      if (grub_le_to_cpu16 (chunk->nsubstripes) != 2)
-+		{
-+		  grub_dprintf ("btrfs", "invalid RAID10: nsubstripes != 2 (%u)",
-+				grub_le_to_cpu16 (chunk->nsubstripes));
-+		  return grub_error (GRUB_ERR_BAD_FS,
-+				     "invalid RAID10: nsubstripes != 2 (%u)",
-+				     grub_le_to_cpu16 (chunk->nsubstripes));
-+		}
-+
- 	      break;
- 	    }
- 	  case GRUB_BTRFS_CHUNK_TYPE_RAID5:
-@@ -1153,6 +1196,8 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
- 
- 	for (j = 0; j < 2; j++)
- 	  {
-+	    grub_size_t est_chunk_alloc = 0;
-+
- 	    grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
- 			  "+0x%" PRIxGRUB_UINT64_T
- 			  " (%d stripes (%d substripes) of %"
-@@ -1165,6 +1210,16 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
- 	    grub_dprintf ("btrfs", "reading laddr 0x%" PRIxGRUB_UINT64_T "\n",
- 			  addr);
- 
-+	    if (grub_mul (sizeof (struct grub_btrfs_chunk_stripe),
-+			  grub_le_to_cpu16 (chunk->nstripes), &est_chunk_alloc) ||
-+		grub_add (est_chunk_alloc,
-+			  sizeof (struct grub_btrfs_chunk_item), &est_chunk_alloc) ||
-+		est_chunk_alloc > chunk->size)
-+	      {
-+		err = GRUB_ERR_BAD_FS;
-+		break;
-+	      }
-+
- 	    if (is_raid56)
- 	      {
- 		err = btrfs_read_from_chunk (data, chunk, stripen,
diff --git a/SOURCES/0265-efi-allocate-the-initrd-within-the-bounds-expressed-.patch b/SOURCES/0265-efi-allocate-the-initrd-within-the-bounds-expressed-.patch
new file mode 100644
index 0000000..47e31e2
--- /dev/null
+++ b/SOURCES/0265-efi-allocate-the-initrd-within-the-bounds-expressed-.patch
@@ -0,0 +1,57 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 1 Aug 2022 14:07:50 -0400
+Subject: [PATCH] efi: allocate the initrd within the bounds expressed by the
+ kernel
+
+Currently on x86, only linux kernels built with CONFIG_RELOCATABLE for
+x86_64 can be loaded above 4G, but the maximum address for the initramfs
+is specified via a HdrS field.  This allows us to utilize that value,
+and unless loading the kernel above 4G, uses the value present there.
+If loading kernel above 4G is allowed, we assume loading the initramfs
+above 4G also works; in practice this has been true in the kernel code
+for quite some time.
+
+Resolves: rhbz#2112134
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/i386/efi/linux.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index e6b8998e5e..d003b474ee 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -190,6 +190,8 @@ grub_linuxefi_unload (void *data)
+   cmd_initrdefi->data = 0;
+   grub_free (context);
+ 
++  max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
++
+   return GRUB_ERR_NONE;
+ }
+ 
+@@ -426,11 +428,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+     }
+ #endif
+ 
++  max_addresses[INITRD_MAX_ADDRESS].addr = lh->initrd_addr_max;
+ #if defined(__x86_64__)
+   if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G)
+     {
+       grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n");
+       max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_USABLE_ADDRESS;
++      max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_USABLE_ADDRESS;
+     }
+   else
+     {
+@@ -560,6 +564,8 @@ fail:
+ 
+   grub_dl_unref (my_mod);
+ 
++  max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
++
+   if (lh)
+     kernel_free (cmdline, lh->cmdline_size + 1);
+ 
diff --git a/SOURCES/0265-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch b/SOURCES/0265-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch
deleted file mode 100644
index 01294d6..0000000
--- a/SOURCES/0265-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch
+++ /dev/null
@@ -1,76 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Darren Kenny <darren.kenny@oracle.com>
-Date: Thu, 7 Apr 2022 15:18:12 +0000
-Subject: [PATCH] fs/btrfs: Fix more fuzz issues related to chunks
-
-The corpus we generating issues in grub_btrfs_read_logical() when
-attempting to iterate over nstripes entries in the boot mapping.
-
-In most cases the reason for the failure was that the number of strips
-exceeded the possible space statically allocated in superblock bootmapping
-space. Each stripe entry in the bootmapping block consists of
-a grub_btrfs_key followed by a grub_btrfs_chunk_stripe.
-
-Another issue that came up was that while calculating the chunk size,
-in an earlier piece of code in that function, depending on the data
-provided in the btrfs file system, it would end up calculating a size
-that was too small to contain even 1 grub_btrfs_chunk_item, which is
-obviously invalid too.
-
-Signed-off-by: Darren Kenny <darren.kenny@oracle.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit e00cd76cbadcc897a9cc4087cb2fcb5dbe15e596)
-(cherry picked from commit b74a6fc95b0839937acf4f2b7445ae9d179f49ec)
----
- grub-core/fs/btrfs.c | 24 ++++++++++++++++++++++++
- 1 file changed, 24 insertions(+)
-
-diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
-index b104da085c..8ec885a93b 100644
---- a/grub-core/fs/btrfs.c
-+++ b/grub-core/fs/btrfs.c
-@@ -947,6 +947,17 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
- 	  return grub_error (GRUB_ERR_BAD_FS,
- 			     "got an invalid zero-size chunk");
- 	}
-+
-+      /*
-+       * The space being allocated for a chunk should at least be able to
-+       * contain one chunk item.
-+       */
-+      if (chsize < sizeof (struct grub_btrfs_chunk_item))
-+       {
-+         grub_dprintf ("btrfs", "chunk-size too small\n");
-+         return grub_error (GRUB_ERR_BAD_FS,
-+                            "got an invalid chunk size");
-+       }
-       chunk = grub_malloc (chsize);
-       if (!chunk)
- 	return grub_errno;
-@@ -1194,6 +1205,13 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
- 	if (csize > (grub_uint64_t) size)
- 	  csize = size;
- 
-+	/*
-+	 * The space for a chunk stripe is limited to the space provide in the super-block's
-+	 * bootstrap mapping with an initial btrfs key at the start of each chunk.
-+	 */
-+	grub_size_t avail_stripes = sizeof (data->sblock.bootstrap_mapping) /
-+	  (sizeof (struct grub_btrfs_key) + sizeof (struct grub_btrfs_chunk_stripe));
-+
- 	for (j = 0; j < 2; j++)
- 	  {
- 	    grub_size_t est_chunk_alloc = 0;
-@@ -1220,6 +1238,12 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
- 		break;
- 	      }
- 
-+	   if (grub_le_to_cpu16 (chunk->nstripes) > avail_stripes)
-+             {
-+               err = GRUB_ERR_BAD_FS;
-+               break;
-+             }
-+
- 	    if (is_raid56)
- 	      {
- 		err = btrfs_read_from_chunk (data, chunk, stripen,
diff --git a/SOURCES/0266-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch b/SOURCES/0266-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch
new file mode 100644
index 0000000..8451dbf
--- /dev/null
+++ b/SOURCES/0266-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch
@@ -0,0 +1,61 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 1 Aug 2022 13:04:43 -0400
+Subject: [PATCH] efi: use EFI_LOADER_(CODE|DATA) for kernel and initrd
+ allocations
+
+At some point due to an erroneous kernel warning, we switched kernel and
+initramfs to being loaded in EFI_RUNTIME_SERVICES_CODE and
+EFI_RUNTIME_SERVICES_DATA memory pools.  This doesn't appear to be
+correct according to the spec, and that kernel warning has gone away.
+
+This patch puts them back in EFI_LOADER_CODE and EFI_LOADER_DATA
+allocations, respectively.
+
+Resolves: rhbz#2108456
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/i386/efi/linux.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index d003b474ee..ac5ef50bdb 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -279,7 +279,7 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
+     }
+ 
+   grub_dprintf ("linux", "Trying to allocate initrd mem\n");
+-  initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_RUNTIME_SERVICES_DATA,
++  initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_LOADER_DATA,
+ 			    N_("can't allocate initrd"));
+   if (initrd_mem == NULL)
+     goto fail;
+@@ -443,7 +443,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ #endif
+ 
+   params = kernel_alloc (KERNEL_MEM, sizeof(*params),
+-			 GRUB_EFI_RUNTIME_SERVICES_DATA,
++			 GRUB_EFI_LOADER_DATA,
+ 			 "cannot allocate kernel parameters");
+   if (!params)
+     goto fail;
+@@ -467,7 +467,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   grub_dprintf ("linux", "setting up cmdline\n");
+   cmdline = kernel_alloc (KERNEL_MEM, lh->cmdline_size + 1,
+-			  GRUB_EFI_RUNTIME_SERVICES_DATA,
++			  GRUB_EFI_LOADER_DATA,
+ 			  N_("can't allocate cmdline"));
+   if (!cmdline)
+     goto fail;
+@@ -516,7 +516,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   kernel_size = lh->init_size;
+   grub_dprintf ("linux", "Trying to allocate kernel mem\n");
+   kernel_mem = kernel_alloc (KERNEL_MEM, kernel_size,
+-			     GRUB_EFI_RUNTIME_SERVICES_CODE,
++			     GRUB_EFI_LOADER_CODE,
+ 			     N_("can't allocate kernel"));
+   restore_addresses();
+   if (!kernel_mem)
diff --git a/SOURCES/0266-misc-Make-grub_min-and-grub_max-more-resilient.patch b/SOURCES/0266-misc-Make-grub_min-and-grub_max-more-resilient.patch
deleted file mode 100644
index d34a0e3..0000000
--- a/SOURCES/0266-misc-Make-grub_min-and-grub_max-more-resilient.patch
+++ /dev/null
@@ -1,84 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 21 Mar 2022 16:06:10 -0400
-Subject: [PATCH] misc: Make grub_min() and grub_max() more resilient.
-
-grub_min(a,b) and grub_max(a,b) use a relatively naive implementation
-which leads to several problems:
-- they evaluate their parameters more than once
-- the naive way to address this, to declare temporary variables in a
-  statement-expression, isn't resilient against nested uses, because
-  MIN(a,MIN(b,c)) results in the temporary variables being declared in
-  two nested scopes, which may result in a build warning depending on
-  your build options.
-
-This patch changes our implementation to use a statement-expression
-inside a helper macro, and creates the symbols for the temporary
-variables with __COUNTER__ (A GNU C cpp extension) and token pasting to
-create uniquely named internal variables.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit 2d6800450fa731d7b3ef9893986806e88e819eb6)
----
- grub-core/loader/multiboot_elfxx.c |  4 +---
- include/grub/misc.h                | 25 +++++++++++++++++++++++--
- 2 files changed, 24 insertions(+), 5 deletions(-)
-
-diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c
-index f2318e0d16..87f6e31aa6 100644
---- a/grub-core/loader/multiboot_elfxx.c
-+++ b/grub-core/loader/multiboot_elfxx.c
-@@ -35,9 +35,7 @@
- #endif
- 
- #include <grub/i386/relocator.h>
--
--#define CONCAT(a,b)	CONCAT_(a, b)
--#define CONCAT_(a,b)	a ## b
-+#include <grub/misc.h>
- 
- #pragma GCC diagnostic ignored "-Wcast-align"
- 
-diff --git a/include/grub/misc.h b/include/grub/misc.h
-index 6c4aa85ac5..cf84aec1db 100644
---- a/include/grub/misc.h
-+++ b/include/grub/misc.h
-@@ -35,6 +35,14 @@
- #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
- #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; }
- 
-+#ifndef CONCAT_
-+#define CONCAT_(a, b) a ## b
-+#endif
-+
-+#ifndef CONCAT
-+#define CONCAT(a, b) CONCAT_(a, b)
-+#endif
-+
- #define grub_dprintf(condition, ...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, __VA_ARGS__)
- 
- void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t n);
-@@ -498,8 +506,21 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file,
- #define grub_boot_time(...)
- #endif
- 
--#define grub_max(a, b) (((a) > (b)) ? (a) : (b))
--#define grub_min(a, b) (((a) < (b)) ? (a) : (b))
-+#define _grub_min(a, b, _a, _b)						      \
-+  ({ typeof (a) _a = (a);						      \
-+     typeof (b) _b = (b);						      \
-+     _a < _b ? _a : _b; })
-+#define grub_min(a, b) _grub_min(a, b,					      \
-+				 CONCAT(_a_,__COUNTER__),		      \
-+				 CONCAT(_b_,__COUNTER__))
-+
-+#define _grub_max(a, b, _a, _b)						      \
-+  ({ typeof (a) _a = (a);						      \
-+     typeof (b) _b = (b);						      \
-+     _a > _b ? _a : _b; })
-+#define grub_max(a, b) _grub_max(a, b,					      \
-+				 CONCAT(_a_,__COUNTER__),		      \
-+				 CONCAT(_b_,__COUNTER__))
- 
- #define grub_log2ull(n) (GRUB_TYPE_BITS (grub_uint64_t) - __builtin_clzll (n) - 1)
- 
diff --git a/SOURCES/0267-BLS-create-etc-kernel-cmdline-during-mkconfig.patch b/SOURCES/0267-BLS-create-etc-kernel-cmdline-during-mkconfig.patch
new file mode 100644
index 0000000..50ba0fb
--- /dev/null
+++ b/SOURCES/0267-BLS-create-etc-kernel-cmdline-during-mkconfig.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 2 Aug 2022 15:56:28 -0400
+Subject: [PATCH] BLS: create /etc/kernel/cmdline during mkconfig
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ util/grub.d/10_linux.in | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 865af3d6c4..9ebff661a9 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -161,6 +161,12 @@ update_bls_cmdline()
+     local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
+     local -a files=($(get_sorted_bls))
+ 
++    if [[ ! -f /etc/kernel/cmdline ]]; then
++	# anaconda has the correct information to do this during install;
++	# afterward, grubby will take care of syncing on updates.
++	echo "$cmdline rhgb quiet" > /etc/kernel/cmdline
++    fi
++
+     for bls in "${files[@]}"; do
+         local options="${cmdline}"
+         if [ -z "${bls##*debug*}" ]; then
diff --git a/SOURCES/0267-ReiserFS-switch-to-using-grub_min-grub_max.patch b/SOURCES/0267-ReiserFS-switch-to-using-grub_min-grub_max.patch
deleted file mode 100644
index e604215..0000000
--- a/SOURCES/0267-ReiserFS-switch-to-using-grub_min-grub_max.patch
+++ /dev/null
@@ -1,93 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 21 Apr 2022 16:31:17 -0400
-Subject: [PATCH] ReiserFS: switch to using grub_min()/grub_max()
-
-This is a minor cleanup patch to remove the bespoke MIN() and MAX()
-definitions from the reiserfs driver, and uses grub_min() / grub_max()
-instead.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit 5fc601574fce99b32fe4dfb55bd8f3ab0175fd6a)
----
- grub-core/fs/reiserfs.c | 28 +++++++++-------------------
- 1 file changed, 9 insertions(+), 19 deletions(-)
-
-diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c
-index af6a226a7f..b8253da7fe 100644
---- a/grub-core/fs/reiserfs.c
-+++ b/grub-core/fs/reiserfs.c
-@@ -42,16 +42,6 @@
- 
- GRUB_MOD_LICENSE ("GPLv3+");
- 
--#define MIN(a, b) \
--  ({ typeof (a) _a = (a); \
--     typeof (b) _b = (b); \
--     _a < _b ? _a : _b; })
--
--#define MAX(a, b) \
--  ({ typeof (a) _a = (a); \
--     typeof (b) _b = (b); \
--     _a > _b ? _a : _b; })
--
- #define REISERFS_SUPER_BLOCK_OFFSET 0x10000
- #define REISERFS_MAGIC_LEN 12
- #define REISERFS_MAGIC_STRING "ReIsEr"
-@@ -1076,7 +1066,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
-   grub_reiserfs_set_key_type (&key, GRUB_REISERFS_ANY, 2);
-   initial_position = off;
-   current_position = 0;
--  final_position = MIN (len + initial_position, node->size);
-+  final_position = grub_min (len + initial_position, node->size);
-   grub_dprintf ("reiserfs",
- 		"Reading from %lld to %lld (%lld instead of requested %ld)\n",
- 		(unsigned long long) initial_position,
-@@ -1115,8 +1105,8 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
-           grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block);
-           if (initial_position < current_position + item_size)
-             {
--              offset = MAX ((signed) (initial_position - current_position), 0);
--              length = (MIN (item_size, final_position - current_position)
-+              offset = grub_max ((signed) (initial_position - current_position), 0);
-+              length = (grub_min (item_size, final_position - current_position)
-                         - offset);
-               grub_dprintf ("reiserfs",
-                             "Reading direct block %u from %u to %u...\n",
-@@ -1161,9 +1151,9 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
-               grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block);
-               if (current_position + block_size >= initial_position)
-                 {
--                  offset = MAX ((signed) (initial_position - current_position),
--                                0);
--                  length = (MIN (block_size, final_position - current_position)
-+                  offset = grub_max ((signed) (initial_position - current_position),
-+				     0);
-+                  length = (grub_min (block_size, final_position - current_position)
-                             - offset);
-                   grub_dprintf ("reiserfs",
-                                 "Reading indirect block %u from %u to %u...\n",
-@@ -1205,7 +1195,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
-   switch (found.type)
-     {
-       case GRUB_REISERFS_DIRECT:
--        read_length = MIN (len, item_size - file->offset);
-+        read_length = grub_min (len, item_size - file->offset);
-         grub_disk_read (found.data->disk,
-                         (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE,
-                         grub_le_to_cpu16 (found.header.item_location) + file->offset,
-@@ -1224,12 +1214,12 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
-                         item_size, (char *) indirect_block_ptr);
-         if (grub_errno)
-           goto fail;
--        len = MIN (len, file->size - file->offset);
-+        len = grub_min (len, file->size - file->offset);
-         for (indirect_block = file->offset / block_size;
-              indirect_block < indirect_block_count && read_length < len;
-              indirect_block++)
-           {
--            read = MIN (block_size, len - read_length);
-+            read = grub_min (block_size, len - read_length);
-             grub_disk_read (found.data->disk,
-                             (grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) * block_size) / GRUB_DISK_SECTOR_SIZE,
-                             file->offset % block_size, read,
diff --git a/SOURCES/0268-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch b/SOURCES/0268-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch
deleted file mode 100644
index 64bbe31..0000000
--- a/SOURCES/0268-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 24 Mar 2022 14:40:01 -0400
-Subject: [PATCH] misc: make grub_boot_time() also call
- grub_dprintf("boot",...)
-
-Currently grub_boot_time() includes valuable debugging messages, but if
-you build without BOOT_TIME_STATS enabled, they are silently and
-confusingly compiled away.
-
-This patch changes grub_boot_time() to also log when "boot" is enabled
-in DEBUG, regardless of BOOT_TIME_STATS.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit 4fd282de00df05ce289467861deb7a0e186cfbd7)
----
- grub-core/kern/misc.c | 3 ++-
- include/grub/misc.h   | 2 +-
- 2 files changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
-index a186ad3dd4..cb45461402 100644
---- a/grub-core/kern/misc.c
-+++ b/grub-core/kern/misc.c
-@@ -1334,7 +1334,8 @@ grub_real_boot_time (const char *file,
-   n->next = 0;
- 
-   va_start (args, fmt);
--  n->msg = grub_xvasprintf (fmt, args);    
-+  n->msg = grub_xvasprintf (fmt, args);
-+  grub_dprintf ("boot", "%s\n", n->msg);
-   va_end (args);
- 
-   *boot_time_last = n;
-diff --git a/include/grub/misc.h b/include/grub/misc.h
-index cf84aec1db..faae0ae860 100644
---- a/include/grub/misc.h
-+++ b/include/grub/misc.h
-@@ -503,7 +503,7 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file,
- 				       const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 3, 4)));
- #define grub_boot_time(...) grub_real_boot_time(GRUB_FILE, __LINE__, __VA_ARGS__)
- #else
--#define grub_boot_time(...)
-+#define grub_boot_time(fmt, ...) grub_dprintf("boot", fmt "\n", ##__VA_ARGS__)
- #endif
- 
- #define _grub_min(a, b, _a, _b)						      \
diff --git a/SOURCES/0268-squish-don-t-dup-rhgb-quiet-check-mtimes.patch b/SOURCES/0268-squish-don-t-dup-rhgb-quiet-check-mtimes.patch
new file mode 100644
index 0000000..67073ec
--- /dev/null
+++ b/SOURCES/0268-squish-don-t-dup-rhgb-quiet-check-mtimes.patch
@@ -0,0 +1,35 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Wed, 17 Aug 2022 10:26:07 -0400
+Subject: [PATCH] squish: don't dup rhgb quiet, check mtimes
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ util/grub.d/10_linux.in | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 9ebff661a9..41c6cb1dc2 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -161,10 +161,16 @@ update_bls_cmdline()
+     local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
+     local -a files=($(get_sorted_bls))
+ 
+-    if [[ ! -f /etc/kernel/cmdline ]]; then
+-	# anaconda has the correct information to do this during install;
+-	# afterward, grubby will take care of syncing on updates.
+-	echo "$cmdline rhgb quiet" > /etc/kernel/cmdline
++    if [[ ! -f /etc/kernel/cmdline ]] ||
++	   [[ /etc/kernel/cmdline -ot /etc/default/grub ]]; then
++	# anaconda has the correct information to create this during install;
++	# afterward, grubby will take care of syncing on updates.  If the user
++	# has modified /etc/default/grub, try to cope.
++	if [[ ! "$cmdline" =~ "rhgb quiet" ]]; then
++	    # ensure these only show up once
++	    cmdline="$cmdline rhgb quiet"
++	fi
++	echo "$cmdline" > /etc/kernel/cmdline
+     fi
+ 
+     for bls in "${files[@]}"; do
diff --git a/SOURCES/0269-modules-make-.module_license-read-only.patch b/SOURCES/0269-modules-make-.module_license-read-only.patch
deleted file mode 100644
index 51281a3..0000000
--- a/SOURCES/0269-modules-make-.module_license-read-only.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 24 Feb 2022 16:32:51 -0500
-Subject: [PATCH] modules: make .module_license read-only
-
-Currently .module_license is set writable (that is, the section has the
-SHF_WRITE flag set) in the module's ELF headers.  This probably never
-actually matters, but it can't possibly be correct.
-
-This patch sets that data as "const", which causes that flag not to be
-set.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit 2eff3e2c9d9e6b75daa81b840c96f112ef7d5de6)
----
- include/grub/dl.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/include/grub/dl.h b/include/grub/dl.h
-index 20d870f2a4..618ae6f474 100644
---- a/include/grub/dl.h
-+++ b/include/grub/dl.h
-@@ -121,7 +121,7 @@ grub_mod_fini (void)
- #define ATTRIBUTE_USED __unused__
- #endif
- #define GRUB_MOD_LICENSE(license)	\
--  static char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license;
-+  static const char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license;
- #define GRUB_MOD_DEP(name)	\
- static const char grub_module_depend_##name[] \
-  __attribute__((section(GRUB_MOD_SECTION(moddeps)), ATTRIBUTE_USED)) = #name
diff --git a/SOURCES/0269-squish-give-up-on-rhgb-quiet.patch b/SOURCES/0269-squish-give-up-on-rhgb-quiet.patch
new file mode 100644
index 0000000..5858c91
--- /dev/null
+++ b/SOURCES/0269-squish-give-up-on-rhgb-quiet.patch
@@ -0,0 +1,25 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Wed, 17 Aug 2022 11:30:30 -0400
+Subject: [PATCH] squish: give up on rhgb quiet
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ util/grub.d/10_linux.in | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 41c6cb1dc2..5d1fa072f2 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -166,10 +166,6 @@ update_bls_cmdline()
+ 	# anaconda has the correct information to create this during install;
+ 	# afterward, grubby will take care of syncing on updates.  If the user
+ 	# has modified /etc/default/grub, try to cope.
+-	if [[ ! "$cmdline" =~ "rhgb quiet" ]]; then
+-	    # ensure these only show up once
+-	    cmdline="$cmdline rhgb quiet"
+-	fi
+ 	echo "$cmdline" > /etc/kernel/cmdline
+     fi
+ 
diff --git a/SOURCES/0270-modules-strip-.llvm_addrsig-sections-and-similar.patch b/SOURCES/0270-modules-strip-.llvm_addrsig-sections-and-similar.patch
deleted file mode 100644
index 16528e4..0000000
--- a/SOURCES/0270-modules-strip-.llvm_addrsig-sections-and-similar.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Thu, 24 Feb 2022 16:40:11 -0500
-Subject: [PATCH] modules: strip .llvm_addrsig sections and similar.
-
-Currently grub modules built with clang or gcc have several sections
-which we don't actually need or support.
-
-We already have a list of section to skip in genmod.sh, and this patch
-adds the following sections to that list (as well as a few newlines):
-
-.note.gnu.property
-.llvm*
-
-Note that the glob there won't work without a new enough linker, but the
-failure is just reversion to the status quo, so that's not a big problem.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit e85d1c4d795f8135ad0acfa36d64760d12d6fed1)
----
- grub-core/genmod.sh.in | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in
-index 1250589b3f..c2c5280d75 100644
---- a/grub-core/genmod.sh.in
-+++ b/grub-core/genmod.sh.in
-@@ -57,8 +57,11 @@ if test x@TARGET_APPLE_LINKER@ != x1; then
- 	    @TARGET_STRIP@ --strip-unneeded \
- 		-K grub_mod_init -K grub_mod_fini \
- 		-K _grub_mod_init -K _grub_mod_fini \
--		-R .note.gnu.gold-version -R .note.GNU-stack \
-+		-R .note.GNU-stack \
-+		-R .note.gnu.gold-version \
-+		-R .note.gnu.property \
- 		-R .gnu.build.attributes \
-+		-R '.llvm*' \
- 		-R .rel.gnu.build.attributes \
- 		-R .rela.gnu.build.attributes \
- 		-R .eh_frame -R .rela.eh_frame -R .rel.eh_frame \
diff --git a/SOURCES/0270-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch b/SOURCES/0270-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch
new file mode 100644
index 0000000..d5ac923
--- /dev/null
+++ b/SOURCES/0270-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch
@@ -0,0 +1,57 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jonathan Lebon <jonathan@jlebon.com>
+Date: Wed, 17 Aug 2022 10:26:03 -0400
+Subject: [PATCH] squish: BLS: only write /etc/kernel/cmdline if writable
+
+On OSTree systems, `grub2-mkconfig` is run with `/etc` mounted read-only
+because as part of the promise of transactional updates, we want to make
+sure that we're not modifying the current deployment's state (`/etc` or
+`/var`).
+
+This conflicts with 0837dcdf1 ("BLS: create /etc/kernel/cmdline during
+mkconfig") which wants to write to `/etc/kernel/cmdline`. I'm not
+exactly sure on the background there, but based on the comment I think
+the intent is to fulfill grubby's expectation that the file exists.
+
+However, in systems like Silverblue, kernel arguments are managed by the
+rpm-ostree stack and grubby is not shipped at all.
+
+Adjust the script slightly so that we only write `/etc/kernel/cmdline`
+if the parent directory is writable.
+
+In the future, we're hoping to simplify things further on rpm-ostree
+systems by not running `grub2-mkconfig` at all since libostree already
+directly writes BLS entries. Doing that would also have avoided this,
+but ratcheting it into existing systems needs more careful thought.
+
+Signed-off-by: Jonathan Lebon <jonathan@jlebon.com>
+
+Fixes: https://github.com/fedora-silverblue/issue-tracker/issues/322
+---
+ util/grub.d/10_linux.in | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 5d1fa072f2..4795a63b4c 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -161,12 +161,13 @@ update_bls_cmdline()
+     local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
+     local -a files=($(get_sorted_bls))
+ 
+-    if [[ ! -f /etc/kernel/cmdline ]] ||
+-	   [[ /etc/kernel/cmdline -ot /etc/default/grub ]]; then
+-	# anaconda has the correct information to create this during install;
+-	# afterward, grubby will take care of syncing on updates.  If the user
+-	# has modified /etc/default/grub, try to cope.
+-	echo "$cmdline" > /etc/kernel/cmdline
++    if [ -w /etc/kernel ] &&
++           [[ ! -f /etc/kernel/cmdline ||
++                  /etc/kernel/cmdline -ot /etc/default/grub ]]; then
++        # anaconda has the correct information to create this during install;
++        # afterward, grubby will take care of syncing on updates.  If the user
++        # has modified /etc/default/grub, try to cope.
++        echo "$cmdline" > /etc/kernel/cmdline
+     fi
+ 
+     for bls in "${files[@]}"; do
diff --git a/SOURCES/0271-blscfg-Don-t-root-device-in-emu-builds.patch b/SOURCES/0271-blscfg-Don-t-root-device-in-emu-builds.patch
new file mode 100644
index 0000000..3fe8baf
--- /dev/null
+++ b/SOURCES/0271-blscfg-Don-t-root-device-in-emu-builds.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Thu, 25 Aug 2022 17:57:55 -0400
+Subject: [PATCH] blscfg: Don't root device in emu builds
+
+Otherwise, we end up looking for kernel/initrd in /boot/boot which
+doesn't work at all.  Non-emu builds need to be looking in
+($root)/boot/, which is what this is for.
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/commands/blscfg.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index e907a6a5d2..dbd0899acf 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -41,7 +41,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+ #define GRUB_BLS_CONFIG_PATH "/loader/entries/"
+ #ifdef GRUB_MACHINE_EMU
+-#define GRUB_BOOT_DEVICE "/boot"
++#define GRUB_BOOT_DEVICE ""
+ #else
+ #define GRUB_BOOT_DEVICE "($root)"
+ #endif
diff --git a/SOURCES/0271-modules-Don-t-allocate-space-for-non-allocable-secti.patch b/SOURCES/0271-modules-Don-t-allocate-space-for-non-allocable-secti.patch
deleted file mode 100644
index 6599406..0000000
--- a/SOURCES/0271-modules-Don-t-allocate-space-for-non-allocable-secti.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 21 Mar 2022 16:56:10 -0400
-Subject: [PATCH] modules: Don't allocate space for non-allocable sections.
-
-Currently when loading grub modules, we allocate space for all sections,
-including those without SHF_ALLOC set.  We then copy the sections that
-/do/ have SHF_ALLOC set into the allocated memory, leaving some of our
-allocation untouched forever.  Additionally, on platforms with GOT
-fixups and trampolines, we currently compute alignment round-ups for the
-sections and sections with sh_size = 0.
-
-This patch removes the extra space from the allocation computation, and
-makes the allocation computation loop skip empty sections as the loading
-loop does.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit 03215e342f552396ab08125ea769b1e166417ec1)
----
- grub-core/kern/dl.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
-index f304494574..aef8af8aa7 100644
---- a/grub-core/kern/dl.c
-+++ b/grub-core/kern/dl.c
-@@ -289,6 +289,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
-        i < e->e_shnum;
-        i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
-     {
-+      if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC))
-+	continue;
-+
-       tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size;
-       if (talign < s->sh_addralign)
- 	talign = s->sh_addralign;
diff --git a/SOURCES/0272-loader-arm64-linux-Remove-magic-number-header-field-.patch b/SOURCES/0272-loader-arm64-linux-Remove-magic-number-header-field-.patch
new file mode 100644
index 0000000..faaa071
--- /dev/null
+++ b/SOURCES/0272-loader-arm64-linux-Remove-magic-number-header-field-.patch
@@ -0,0 +1,43 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Thu, 11 Aug 2022 16:51:57 +0200
+Subject: [PATCH] loader/arm64/linux: Remove magic number header field check
+
+The "ARM\x64" magic number in the file header identifies an image as one
+that implements the bare metal boot protocol, allowing the loader to
+simply move the file to a suitably aligned address in memory, with
+sufficient headroom for the trailing .bss segment (the required memory
+size is described in the header as well).
+
+Note of this matters for GRUB, as it only supports EFI boot. EFI does
+not care about this magic number, and nor should GRUB: this prevents us
+from booting other PE linux images, such as the generic EFI zboot
+decompressor, which is a pure PE/COFF image, and does not implement the
+bare metal boot protocol.
+
+So drop the magic number check.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+Resolves: rhbz#2125069
+Signed-off-by: Jeremy Linton <jlinton@redhat.com>
+(cherry-picked from commit 69edb31205602c29293a8c6e67363bba2a4a1e66)
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/loader/arm64/linux.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index de85583487..489d0c7173 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -55,9 +55,6 @@ static grub_addr_t initrd_end;
+ grub_err_t
+ grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh)
+ {
+-  if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE)
+-    return grub_error(GRUB_ERR_BAD_OS, "invalid magic number");
+-
+   if ((lh->code0 & 0xffff) != GRUB_DOS_MAGIC)
+     return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ 		       N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled"));
diff --git a/SOURCES/0272-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch b/SOURCES/0272-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch
deleted file mode 100644
index c3f2e0f..0000000
--- a/SOURCES/0272-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch
+++ /dev/null
@@ -1,82 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Fri, 25 Mar 2022 15:40:12 -0400
-Subject: [PATCH] pe: add the DOS header struct and fix some bad naming.
-
-In order to properly validate a loaded kernel's support for being loaded
-without a writable stack or executable, we need to be able to properly
-parse arbitrary PE headers.
-
-Currently, pe32.h is written in such a way that the MS-DOS header that
-tells us where to find the PE header in the binary can't be accessed.
-Further, for some reason it calls the DOS MZ magic "GRUB_PE32_MAGIC".
-
-This patch adds the structure for the DOS header, renames the DOS magic
-define, and adds defines for the actual PE magic.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit 955f47aa8300387eecf18b0866d21dde7720593d)
----
- grub-core/loader/arm64/linux.c |  2 +-
- include/grub/efi/pe32.h        | 28 ++++++++++++++++++++++++++--
- 2 files changed, 27 insertions(+), 3 deletions(-)
-
-diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
-index f18d90bd74..bcc6ef46e9 100644
---- a/grub-core/loader/arm64/linux.c
-+++ b/grub-core/loader/arm64/linux.c
-@@ -59,7 +59,7 @@ grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh)
-   if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE)
-     return grub_error(GRUB_ERR_BAD_OS, "invalid magic number");
- 
--  if ((lh->code0 & 0xffff) != GRUB_PE32_MAGIC)
-+  if ((lh->code0 & 0xffff) != GRUB_DOS_MAGIC)
-     return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- 		       N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled"));
- 
-diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
-index a43adf2746..2a5e1ee003 100644
---- a/include/grub/efi/pe32.h
-+++ b/include/grub/efi/pe32.h
-@@ -46,7 +46,30 @@
- 
- #define GRUB_PE32_MSDOS_STUB_SIZE	0x80
- 
--#define GRUB_PE32_MAGIC			0x5a4d
-+#define GRUB_DOS_MAGIC			0x5a4d
-+
-+struct grub_dos_header
-+{
-+  grub_uint16_t magic;
-+  grub_uint16_t cblp;
-+  grub_uint16_t cp;
-+  grub_uint16_t crlc;
-+  grub_uint16_t cparhdr;
-+  grub_uint16_t minalloc;
-+  grub_uint16_t maxalloc;
-+  grub_uint16_t ss;
-+  grub_uint16_t sp;
-+  grub_uint16_t csum;
-+  grub_uint16_t ip;
-+  grub_uint16_t cs;
-+  grub_uint16_t lfarlc;
-+  grub_uint16_t ovno;
-+  grub_uint16_t res0[4];
-+  grub_uint16_t oemid;
-+  grub_uint16_t oeminfo;
-+  grub_uint16_t res1[10];
-+  grub_uint32_t lfanew;
-+};
- 
- /* According to the spec, the minimal alignment is 512 bytes...
-    But some examples (such as EFI drivers in the Intel
-@@ -280,7 +303,8 @@ struct grub_pe32_section_table
- 
- 
- 
--#define GRUB_PE32_SIGNATURE_SIZE 4
-+#define GRUB_PE32_SIGNATURE_SIZE		4
-+#define GRUB_PE32_SIGNATURE			"PE\0\0"
- 
- struct grub_pe32_header
- {
diff --git a/SOURCES/0273-Correct-BSS-zeroing-on-aarch64.patch b/SOURCES/0273-Correct-BSS-zeroing-on-aarch64.patch
new file mode 100644
index 0000000..4f9a2b7
--- /dev/null
+++ b/SOURCES/0273-Correct-BSS-zeroing-on-aarch64.patch
@@ -0,0 +1,95 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jeremy Linton <jeremy.linton@arm.com>
+Date: Tue, 6 Sep 2022 15:33:03 -0500
+Subject: [PATCH] Correct BSS zeroing on aarch64
+
+The aarch64 loader doesn't use efi bootservices, and
+therefor it has a very minimal loader which makes a lot
+of assumptions about the kernel layout. With the ZBOOT
+changes, the layout has changed a bit and we not should
+really be parsing the PE sections to determine how much
+data to copy, otherwise the BSS won't be setup properly.
+
+This code still makes a lot of assumptions about the
+the kernel layout, so its far from ideal, but it works.
+
+Resolves: rhbz#2125069
+
+Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
+---
+ grub-core/loader/arm64/linux.c | 27 ++++++++++++++++++++++-----
+ 1 file changed, 22 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index 489d0c7173..419f2201df 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -316,10 +316,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+ static grub_err_t
+ parse_pe_header (void *kernel, grub_uint64_t *total_size,
+ 		 grub_uint32_t *entry_offset,
+-		 grub_uint32_t *alignment)
++		 grub_uint32_t *alignment,grub_uint32_t *code_size)
+ {
+   struct linux_arch_kernel_header *lh = kernel;
+   struct grub_armxx_linux_pe_header *pe;
++  grub_uint16_t i;
++  struct grub_pe32_section_table *sections;
+ 
+   pe = (void *)((unsigned long)kernel + lh->hdr_offset);
+ 
+@@ -329,6 +331,19 @@ parse_pe_header (void *kernel, grub_uint64_t *total_size,
+   *total_size   = pe->opt.image_size;
+   *entry_offset = pe->opt.entry_addr;
+   *alignment    = pe->opt.section_alignment;
++  *code_size    = pe->opt.section_alignment;
++
++  sections = (struct grub_pe32_section_table *) ((char *)&pe->opt +
++						 pe->coff.optional_header_size);
++  grub_dprintf ("linux", "num_sections     : %d\n",  pe->coff.num_sections );
++  for (i = 0 ; i < pe->coff.num_sections; i++)
++    {
++      grub_dprintf ("linux", "raw_size   : %lld\n",
++		    (long long) sections[i].raw_data_size);
++      grub_dprintf ("linux", "virt_size  : %lld\n",
++		    (long long) sections[i].virtual_size);
++      *code_size += sections[i].raw_data_size;
++    }
+ 
+   return GRUB_ERR_NONE;
+ }
+@@ -341,6 +356,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_err_t err;
+   grub_off_t filelen;
+   grub_uint32_t align;
++  grub_uint32_t code_size;
+   void *kernel = NULL;
+   int nx_supported = 1;
+ 
+@@ -373,11 +389,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   if (grub_arch_efi_linux_check_image (kernel) != GRUB_ERR_NONE)
+     goto fail;
+-  if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align) != GRUB_ERR_NONE)
++  if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align, &code_size) != GRUB_ERR_NONE)
+     goto fail;
+   grub_dprintf ("linux", "kernel mem size     : %lld\n", (long long) kernel_size);
+   grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset);
+   grub_dprintf ("linux", "kernel alignment    : 0x%x\n", align);
++  grub_dprintf ("linux", "kernel size         : 0x%x\n", code_size);
+ 
+   err = grub_efi_check_nx_image_support((grub_addr_t)kernel, filelen, &nx_supported);
+   if (err != GRUB_ERR_NONE)
+@@ -396,9 +413,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   kernel_addr = (void *)ALIGN_UP((grub_uint64_t)kernel_alloc_addr, align);
+ 
+   grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
+-  grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size));
+-  if (kernel_size > filelen)
+-    grub_memset ((char *)kernel_addr + filelen, 0, kernel_size - filelen);
++  grub_memcpy (kernel_addr, kernel, grub_min(code_size, kernel_size));
++  if (kernel_size > code_size)
++    grub_memset ((char *)kernel_addr + code_size, 0, kernel_size - code_size);
+   grub_free(kernel);
+   kernel = NULL;
+ 
diff --git a/SOURCES/0273-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch b/SOURCES/0273-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch
deleted file mode 100644
index b306f15..0000000
--- a/SOURCES/0273-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch
+++ /dev/null
@@ -1,86 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Wed, 9 Feb 2022 16:08:20 -0500
-Subject: [PATCH] EFI: allocate kernel in EFI_RUNTIME_SERVICES_CODE instead of
- EFI_LOADER_DATA.
-
-On some of the firmwares with more security mitigations, EFI_LOADER_DATA
-doesn't get you executable memory, and we take a fault and reboot when
-we enter kernel.
-
-This patch correctly allocates the kernel code as EFI_RUNTIME_SERVICES_CODE
-rather than EFI_LOADER_DATA.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-[rharwood: use kernel_size]
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
-(cherry picked from commit 8b31058a12d3e85f0f0180ac90b98d6465fccbb7)
----
- grub-core/loader/i386/efi/linux.c | 19 +++++++++++++------
- 1 file changed, 13 insertions(+), 6 deletions(-)
-
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index d24553a79d..b832c85728 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -87,7 +87,9 @@ kernel_free(void *addr, grub_efi_uintn_t size)
- }
- 
- static void *
--kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
-+kernel_alloc(grub_efi_uintn_t size,
-+	     grub_efi_memory_type_t memtype,
-+	     const char * const errmsg)
- {
-   void *addr = 0;
-   unsigned int i;
-@@ -113,7 +115,7 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
-       prev_max = max;
-       addr = grub_efi_allocate_pages_real (max, pages,
- 					   max_addresses[i].alloc_type,
--					   GRUB_EFI_LOADER_DATA);
-+					   memtype);
-       if (addr)
- 	grub_dprintf ("linux", "Allocated at %p\n", addr);
-     }
-@@ -243,7 +245,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
- 	}
-     }
- 
--  initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
-+  initrd_mem = kernel_alloc(size, GRUB_EFI_RUNTIME_SERVICES_DATA,
-+			    N_("can't allocate initrd"));
-   if (initrd_mem == NULL)
-     goto fail;
-   grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
-@@ -406,7 +409,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-     }
- #endif
- 
--  params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters");
-+  params = kernel_alloc (sizeof(*params), GRUB_EFI_RUNTIME_SERVICES_DATA,
-+			 "cannot allocate kernel parameters");
-   if (!params)
-     goto fail;
-   grub_dprintf ("linux", "params = %p\n", params);
-@@ -428,7 +432,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   grub_dprintf ("linux", "new lh is at %p\n", lh);
- 
-   grub_dprintf ("linux", "setting up cmdline\n");
--  cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline"));
-+  cmdline = kernel_alloc (lh->cmdline_size + 1,
-+			  GRUB_EFI_RUNTIME_SERVICES_DATA,
-+			  N_("can't allocate cmdline"));
-   if (!cmdline)
-     goto fail;
-   grub_dprintf ("linux", "cmdline = %p\n", cmdline);
-@@ -474,7 +480,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
-   max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
-   kernel_size = lh->init_size;
--  kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel"));
-+  kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE,
-+			     N_("can't allocate kernel"));
-   restore_addresses();
-   if (!kernel_mem)
-     goto fail;
diff --git a/SOURCES/0274-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch b/SOURCES/0274-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch
new file mode 100644
index 0000000..eff155d
--- /dev/null
+++ b/SOURCES/0274-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch
@@ -0,0 +1,39 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: dann frazier <dann.frazier@canonical.com>
+Date: Thu, 25 Aug 2022 17:08:09 -0600
+Subject: [PATCH] linuxefi: Invalidate i-cache before starting the kernel
+
+We need to flush the memory range of the code we are about to execute
+from the instruction cache before we can safely execute it. Not doing
+so appears to be the source of rare synchronous exceptions a user
+is seeing on a Cortex-A72-based platform while executing the Linux EFI
+stub. Notably they seem to correlate with an instruction on a cache
+line boundary.
+
+Signed-off-by: dann frazier <dann.frazier@canonical.com>
+---
+ grub-core/loader/efi/linux.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
+index 277f352e0c..e413bdcc23 100644
+--- a/grub-core/loader/efi/linux.c
++++ b/grub-core/loader/efi/linux.c
+@@ -16,6 +16,7 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
++#include <grub/cache.h>
+ #include <grub/err.h>
+ #include <grub/mm.h>
+ #include <grub/types.h>
+@@ -210,6 +211,9 @@ grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size,
+   asm volatile ("cli");
+ #endif
+ 
++  /* Invalidate the instruction cache */
++  grub_arch_sync_caches((void *)kernel_addr, kernel_size);
++
+   hf = (handover_func)((char *)kernel_addr + handover_offset + offset);
+   hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
+ 
diff --git a/SOURCES/0274-modules-load-module-sections-at-page-aligned-address.patch b/SOURCES/0274-modules-load-module-sections-at-page-aligned-address.patch
deleted file mode 100644
index 1c703d8..0000000
--- a/SOURCES/0274-modules-load-module-sections-at-page-aligned-address.patch
+++ /dev/null
@@ -1,379 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 21 Mar 2022 17:45:40 -0400
-Subject: [PATCH] modules: load module sections at page-aligned addresses
-
-Currently we load module sections at whatever alignment gcc+ld happened
-to dump into the ELF section header, which is often pretty useless.  For
-example, by default time.mod has these sections on a current x86_64
-build:
-
-$ eu-readelf -a grub-core/time.mod |& grep ^Section -A13
-Section Headers:
-[Nr] Name            Type         Addr  Off      Size     ES Flags Lk Inf Al
-[ 0]                 NULL         0     00000000 00000000  0        0   0  0
-[ 1] .text           PROGBITS     0     00000040 0000015e  0 AX     0   0  1
-[ 2] .rela.text      RELA         0     00000458 000001e0 24 I      8   1  8
-[ 3] .rodata.str1.1  PROGBITS     0     0000019e 000000a1  1 AMS    0   0  1
-[ 4] .module_license PROGBITS     0     00000240 0000000f  0 A      0   0  8
-[ 5] .data           PROGBITS     0     0000024f 00000000  0 WA     0   0  1
-[ 6] .bss            NOBITS       0     00000250 00000008  0 WA     0   0  8
-[ 7] .modname        PROGBITS     0     00000250 00000005  0        0   0  1
-[ 8] .symtab         SYMTAB       0     00000258 00000150 24        9   6  8
-[ 9] .strtab         STRTAB       0     000003a8 000000ab  0        0   0  1
-[10] .shstrtab       STRTAB       0     00000638 00000059  0        0   0  1
-
-With NX protections being page based, loading sections with either a 1
-or 8 *byte* alignment does absolutely nothing to help us out.
-
-This patch switches most EFI platforms to load module sections at 4kB
-page-aligned addresses.  To do so, it adds an new per-arch function,
-grub_arch_dl_min_alignment(), which returns the alignment needed for
-dynamically loaded sections (in bytes).  Currently it sets it to 4096
-when GRUB_MACHINE_EFI is true on x86_64, i386, arm, arm64, and emu, and
-1-byte alignment on everything else.
-
-It then changes the allocation size computation and the loader code in
-grub_dl_load_segments() to align the locations and sizes up to these
-boundaries, and fills any added padding with zeros.
-
-All of this happens before relocations are applied, so the relocations
-factor that in with no change.
-
-As an aside, initially Daniel Kiper and I thought that it might be a
-better idea to split the modules up into top-level sections as
-.text.modules, .rodata.modules, .data.modules, etc., so that their page
-permissions would get set by the loader that's loading grub itself.
-This turns out to have two significant downsides: 1) either in mkimage
-or in grub_dl_relocate_symbols(), you wind up having to dynamically
-process the relocations to accommodate the moved module sections, and 2)
-you then need to change the permissions on the modules and change them
-back while relocating them in grub_dl_relocate_symbols(), which means
-that any loader that /does/ honor the section flags but does /not/
-generally support NX with the memory attributes API will cause grub to
-fail.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit 31d52500b281619d92b03b2c2d30fe15aedaf326)
----
- grub-core/kern/arm/dl.c     | 13 +++++++++++++
- grub-core/kern/arm64/dl.c   | 13 +++++++++++++
- grub-core/kern/dl.c         | 29 +++++++++++++++++++++--------
- grub-core/kern/emu/full.c   | 13 +++++++++++++
- grub-core/kern/i386/dl.c    | 13 +++++++++++++
- grub-core/kern/ia64/dl.c    |  9 +++++++++
- grub-core/kern/mips/dl.c    |  8 ++++++++
- grub-core/kern/powerpc/dl.c |  9 +++++++++
- grub-core/kern/riscv/dl.c   | 13 +++++++++++++
- grub-core/kern/sparc64/dl.c |  9 +++++++++
- grub-core/kern/x86_64/dl.c  | 13 +++++++++++++
- include/grub/dl.h           |  2 ++
- docs/grub-dev.texi          |  6 +++---
- 13 files changed, 139 insertions(+), 11 deletions(-)
-
-diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c
-index eab9d17ff2..9260737936 100644
---- a/grub-core/kern/arm/dl.c
-+++ b/grub-core/kern/arm/dl.c
-@@ -278,3 +278,16 @@ grub_arch_dl_check_header (void *ehdr)
- 
-   return GRUB_ERR_NONE;
- }
-+
-+/*
-+ * Tell the loader what our minimum section alignment is.
-+ */
-+grub_size_t
-+grub_arch_dl_min_alignment (void)
-+{
-+#ifdef GRUB_MACHINE_EFI
-+  return 4096;
-+#else
-+  return 1;
-+#endif
-+}
-diff --git a/grub-core/kern/arm64/dl.c b/grub-core/kern/arm64/dl.c
-index 512e5a80b0..0d4a26857f 100644
---- a/grub-core/kern/arm64/dl.c
-+++ b/grub-core/kern/arm64/dl.c
-@@ -196,3 +196,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
- 
-   return GRUB_ERR_NONE;
- }
-+
-+/*
-+ * Tell the loader what our minimum section alignment is.
-+ */
-+grub_size_t
-+grub_arch_dl_min_alignment (void)
-+{
-+#ifdef GRUB_MACHINE_EFI
-+  return 4096;
-+#else
-+  return 1;
-+#endif
-+}
-diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
-index aef8af8aa7..8c7aacef39 100644
---- a/grub-core/kern/dl.c
-+++ b/grub-core/kern/dl.c
-@@ -277,7 +277,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
- {
-   unsigned i;
-   const Elf_Shdr *s;
--  grub_size_t tsize = 0, talign = 1;
-+  grub_size_t tsize = 0, talign = 1, arch_addralign = 1;
- #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
-   grub_size_t tramp;
-   grub_size_t got;
-@@ -285,16 +285,24 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
- #endif
-   char *ptr;
- 
-+  arch_addralign = grub_arch_dl_min_alignment ();
-+
-   for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
-        i < e->e_shnum;
-        i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
-     {
-+      grub_size_t sh_addralign;
-+      grub_size_t sh_size;
-+
-       if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC))
- 	continue;
- 
--      tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size;
--      if (talign < s->sh_addralign)
--	talign = s->sh_addralign;
-+      sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign);
-+      sh_size = ALIGN_UP(s->sh_size, sh_addralign);
-+
-+      tsize = ALIGN_UP (tsize, sh_addralign) + sh_size;
-+      if (talign < sh_addralign)
-+	talign = sh_addralign;
-     }
- 
- #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
-@@ -323,6 +331,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
-        i < e->e_shnum;
-        i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
-     {
-+      grub_size_t sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign);
-+      grub_size_t sh_size = ALIGN_UP(s->sh_size, sh_addralign);
-+
-       if (s->sh_flags & SHF_ALLOC)
- 	{
- 	  grub_dl_segment_t seg;
-@@ -335,17 +346,19 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
- 	    {
- 	      void *addr;
- 
--	      ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign);
-+	      ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, sh_addralign);
- 	      addr = ptr;
--	      ptr += s->sh_size;
-+	      ptr += sh_size;
- 
- 	      switch (s->sh_type)
- 		{
- 		case SHT_PROGBITS:
- 		  grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size);
-+		  grub_memset ((char *)addr + s->sh_size, 0,
-+			       sh_size - s->sh_size);
- 		  break;
- 		case SHT_NOBITS:
--		  grub_memset (addr, 0, s->sh_size);
-+		  grub_memset (addr, 0, sh_size);
- 		  break;
- 		}
- 
-@@ -354,7 +367,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
- 	  else
- 	    seg->addr = 0;
- 
--	  seg->size = s->sh_size;
-+	  seg->size = sh_size;
- 	  seg->section = i;
- 	  seg->next = mod->segment;
- 	  mod->segment = seg;
-diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c
-index e8d63b1f5f..1de1c28eb0 100644
---- a/grub-core/kern/emu/full.c
-+++ b/grub-core/kern/emu/full.c
-@@ -67,3 +67,16 @@ grub_arch_dl_init_linker (void)
- }
- #endif
- 
-+
-+/*
-+ * Tell the loader what our minimum section alignment is.
-+ */
-+grub_size_t
-+grub_arch_dl_min_alignment (void)
-+{
-+#ifdef GRUB_MACHINE_EFI
-+  return 4096;
-+#else
-+  return 1;
-+#endif
-+}
-diff --git a/grub-core/kern/i386/dl.c b/grub-core/kern/i386/dl.c
-index 1346da5cc9..d6b4681fc9 100644
---- a/grub-core/kern/i386/dl.c
-+++ b/grub-core/kern/i386/dl.c
-@@ -79,3 +79,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
- 
-   return GRUB_ERR_NONE;
- }
-+
-+/*
-+ * Tell the loader what our minimum section alignment is.
-+ */
-+grub_size_t
-+grub_arch_dl_min_alignment (void)
-+{
-+#ifdef GRUB_MACHINE_EFI
-+  return 4096;
-+#else
-+  return 1;
-+#endif
-+}
-diff --git a/grub-core/kern/ia64/dl.c b/grub-core/kern/ia64/dl.c
-index db59300fea..92d82c5750 100644
---- a/grub-core/kern/ia64/dl.c
-+++ b/grub-core/kern/ia64/dl.c
-@@ -148,3 +148,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
-     }
-   return GRUB_ERR_NONE;
- }
-+
-+/*
-+ * Tell the loader what our minimum section alignment is.
-+ */
-+grub_size_t
-+grub_arch_dl_min_alignment (void)
-+{
-+  return 1;
-+}
-diff --git a/grub-core/kern/mips/dl.c b/grub-core/kern/mips/dl.c
-index 5d7d299c74..6d83bd71e9 100644
---- a/grub-core/kern/mips/dl.c
-+++ b/grub-core/kern/mips/dl.c
-@@ -272,3 +272,11 @@ grub_arch_dl_init_linker (void)
-   grub_dl_register_symbol ("_gp_disp", &_gp_disp_dummy, 0, 0);
- }
- 
-+/*
-+ * Tell the loader what our minimum section alignment is.
-+ */
-+grub_size_t
-+grub_arch_dl_min_alignment (void)
-+{
-+  return 1;
-+}
-diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c
-index cdd61b305f..5d9ba2e158 100644
---- a/grub-core/kern/powerpc/dl.c
-+++ b/grub-core/kern/powerpc/dl.c
-@@ -167,3 +167,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
- 
-   return GRUB_ERR_NONE;
- }
-+
-+/*
-+ * Tell the loader what our minimum section alignment is.
-+ */
-+grub_size_t
-+grub_arch_dl_min_alignment (void)
-+{
-+  return 1;
-+}
-diff --git a/grub-core/kern/riscv/dl.c b/grub-core/kern/riscv/dl.c
-index f26b12aaa4..aa18f9e990 100644
---- a/grub-core/kern/riscv/dl.c
-+++ b/grub-core/kern/riscv/dl.c
-@@ -343,3 +343,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
- 
-   return GRUB_ERR_NONE;
- }
-+
-+/*
-+ * Tell the loader what our minimum section alignment is.
-+ */
-+grub_size_t
-+grub_arch_dl_min_alignment (void)
-+{
-+#ifdef GRUB_MACHINE_EFI
-+  return 4096;
-+#else
-+  return 1;
-+#endif
-+}
-diff --git a/grub-core/kern/sparc64/dl.c b/grub-core/kern/sparc64/dl.c
-index f3d960186b..f054f08241 100644
---- a/grub-core/kern/sparc64/dl.c
-+++ b/grub-core/kern/sparc64/dl.c
-@@ -189,3 +189,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
- 
-   return GRUB_ERR_NONE;
- }
-+
-+/*
-+ * Tell the loader what our minimum section alignment is.
-+ */
-+grub_size_t
-+grub_arch_dl_min_alignment (void)
-+{
-+  return 1;
-+}
-diff --git a/grub-core/kern/x86_64/dl.c b/grub-core/kern/x86_64/dl.c
-index e5a8bdcf4f..a105dc50ce 100644
---- a/grub-core/kern/x86_64/dl.c
-+++ b/grub-core/kern/x86_64/dl.c
-@@ -119,3 +119,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
- 
-   return GRUB_ERR_NONE;
- }
-+
-+/*
-+ * Tell the loader what our minimum section alignment is.
-+ */
-+grub_size_t
-+grub_arch_dl_min_alignment (void)
-+{
-+#ifdef GRUB_MACHINE_EFI
-+  return 4096;
-+#else
-+  return 1;
-+#endif
-+}
-diff --git a/include/grub/dl.h b/include/grub/dl.h
-index 618ae6f474..f36ed5cb17 100644
---- a/include/grub/dl.h
-+++ b/include/grub/dl.h
-@@ -280,6 +280,8 @@ grub_err_t grub_arch_dl_check_header (void *ehdr);
- grub_err_t
- grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
- 			       Elf_Shdr *s, grub_dl_segment_t seg);
-+grub_size_t
-+grub_arch_dl_min_alignment (void);
- #endif
- 
- #if defined (_mips)
-diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
-index 90083772c8..c23ba313dc 100644
---- a/docs/grub-dev.texi
-+++ b/docs/grub-dev.texi
-@@ -755,9 +755,9 @@ declare startup asm file ($cpu_$platform_startup) as well as any other files
- (e.g. init.c and callwrap.S) (e.g. $cpu_$platform = kern/$cpu/$platform/init.c).
- At this stage you will also need to add dummy dl.c and cache.S with functions
- grub_err_t grub_arch_dl_check_header (void *ehdr), grub_err_t
--grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c) and
--void grub_arch_sync_caches (void *address, grub_size_t len) (cache.S). They
--won't be used for now.
-+grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c), grub_uint32_t
-+grub_arch_dl_min_alignment (void), and void grub_arch_sync_caches (void
-+*address, grub_size_t len) (cache.S). They won't be used for now.
- 
- You will need to create directory include/$cpu/$platform and a file
- include/$cpu/types.h. The later folowing this template:
diff --git a/SOURCES/0275-nx-add-memory-attribute-get-set-API.patch b/SOURCES/0275-nx-add-memory-attribute-get-set-API.patch
deleted file mode 100644
index 9146ba1..0000000
--- a/SOURCES/0275-nx-add-memory-attribute-get-set-API.patch
+++ /dev/null
@@ -1,318 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 22 Mar 2022 10:56:21 -0400
-Subject: [PATCH] nx: add memory attribute get/set API
-
-For NX, we need to set the page access permission attributes for write
-and execute permissions.
-
-This patch adds two new primitives, grub_set_mem_attrs() and
-grub_clear_mem_attrs(), and associated constant definitions, to be used
-for that purpose.
-
-For most platforms, it adds a dummy implementation that returns
-GRUB_ERR_NONE.  On EFI platforms, it adds a common helper function,
-grub_efi_status_to_err(), which translates EFI error codes to grub error
-codes, adds headers for the EFI Memory Attribute Protocol (still pending
-standardization), and an implementation of the grub nx primitives using
-it.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-[rharwood: add pjones's none/nyi fixup]
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
-(cherry picked from commit 35de78a8d32b9fad5291ec96fd3cbb9cf2f4a80b)
----
- grub-core/kern/efi/efi.c |  36 +++++++++++++
- grub-core/kern/efi/mm.c  | 131 +++++++++++++++++++++++++++++++++++++++++++++++
- include/grub/efi/api.h   |  25 +++++++++
- include/grub/efi/efi.h   |   2 +
- include/grub/mm.h        |  32 ++++++++++++
- 5 files changed, 226 insertions(+)
-
-diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
-index 7fcca69c17..4ac2b2754e 100644
---- a/grub-core/kern/efi/efi.c
-+++ b/grub-core/kern/efi/efi.c
-@@ -1096,3 +1096,39 @@ grub_efi_compare_device_paths (const grub_efi_device_path_t *dp1,
- 
-   return 0;
- }
-+
-+grub_err_t
-+grub_efi_status_to_err (grub_efi_status_t status)
-+{
-+  grub_err_t err;
-+  switch (status)
-+    {
-+    case GRUB_EFI_SUCCESS:
-+      err = GRUB_ERR_NONE;
-+      break;
-+    case GRUB_EFI_INVALID_PARAMETER:
-+    default:
-+      err = GRUB_ERR_BAD_ARGUMENT;
-+      break;
-+    case GRUB_EFI_OUT_OF_RESOURCES:
-+      err = GRUB_ERR_OUT_OF_MEMORY;
-+      break;
-+    case GRUB_EFI_DEVICE_ERROR:
-+      err = GRUB_ERR_IO;
-+      break;
-+    case GRUB_EFI_WRITE_PROTECTED:
-+      err = GRUB_ERR_WRITE_ERROR;
-+      break;
-+    case GRUB_EFI_SECURITY_VIOLATION:
-+      err = GRUB_ERR_ACCESS_DENIED;
-+      break;
-+    case GRUB_EFI_NOT_FOUND:
-+      err = GRUB_ERR_FILE_NOT_FOUND;
-+      break;
-+    case GRUB_EFI_ABORTED:
-+      err = GRUB_ERR_WAIT;
-+      break;
-+    }
-+
-+  return err;
-+}
-diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
-index e84961d078..2c33758ed7 100644
---- a/grub-core/kern/efi/mm.c
-+++ b/grub-core/kern/efi/mm.c
-@@ -738,3 +738,134 @@ grub_efi_get_ram_base(grub_addr_t *base_addr)
-   return GRUB_ERR_NONE;
- }
- #endif
-+
-+static inline grub_uint64_t
-+grub_mem_attrs_to_uefi_mem_attrs (grub_uint64_t attrs)
-+{
-+  grub_uint64_t ret = GRUB_EFI_MEMORY_RP |
-+		      GRUB_EFI_MEMORY_RO |
-+		      GRUB_EFI_MEMORY_XP;
-+
-+  if (attrs & GRUB_MEM_ATTR_R)
-+    ret &= ~GRUB_EFI_MEMORY_RP;
-+
-+  if (attrs & GRUB_MEM_ATTR_W)
-+    ret &= ~GRUB_EFI_MEMORY_RO;
-+
-+  if (attrs & GRUB_MEM_ATTR_X)
-+    ret &= ~GRUB_EFI_MEMORY_XP;
-+
-+  return ret;
-+}
-+
-+static inline grub_uint64_t
-+uefi_mem_attrs_to_grub_mem_attrs (grub_uint64_t attrs)
-+{
-+  grub_uint64_t ret = GRUB_MEM_ATTR_R |
-+		      GRUB_MEM_ATTR_W |
-+		      GRUB_MEM_ATTR_X;
-+
-+  if (attrs & GRUB_EFI_MEMORY_RP)
-+    ret &= ~GRUB_MEM_ATTR_R;
-+
-+  if (attrs & GRUB_EFI_MEMORY_RO)
-+    ret &= ~GRUB_MEM_ATTR_W;
-+
-+  if (attrs & GRUB_EFI_MEMORY_XP)
-+    ret &= ~GRUB_MEM_ATTR_X;
-+
-+  return ret;
-+}
-+
-+grub_err_t
-+grub_get_mem_attrs (grub_addr_t addr, grub_size_t size, grub_uint64_t *attrs)
-+{
-+  grub_efi_memory_attribute_protocol_t *proto;
-+  grub_efi_physical_address_t physaddr = addr;
-+  grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
-+  grub_efi_status_t efi_status;
-+
-+  proto = grub_efi_locate_protocol (&protocol_guid, 0);
-+  if (!proto)
-+    return GRUB_ERR_NOT_IMPLEMENTED_YET;
-+
-+  if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL)
-+    {
-+      grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" and attrs %p\n",
-+		    __func__, physaddr, physaddr+size-1, attrs);
-+      return 0;
-+    }
-+
-+  efi_status = efi_call_4(proto->get_memory_attributes,
-+			  proto, physaddr, size, attrs);
-+  *attrs = uefi_mem_attrs_to_grub_mem_attrs (*attrs);
-+
-+  return grub_efi_status_to_err (efi_status);
-+}
-+
-+grub_err_t
-+grub_update_mem_attrs (grub_addr_t addr, grub_size_t size,
-+		       grub_uint64_t set_attrs, grub_uint64_t clear_attrs)
-+{
-+  grub_efi_memory_attribute_protocol_t *proto;
-+  grub_efi_physical_address_t physaddr = addr;
-+  grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
-+  grub_efi_status_t efi_status = GRUB_EFI_SUCCESS;
-+  grub_uint64_t before = 0, after = 0, uefi_set_attrs, uefi_clear_attrs;
-+  grub_err_t err;
-+
-+  proto = grub_efi_locate_protocol (&protocol_guid, 0);
-+  if (!proto)
-+    return GRUB_ERR_NONE;
-+
-+  err = grub_get_mem_attrs (addr, size, &before);
-+  if (err)
-+    grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n",
-+		  addr, size, &before, err);
-+
-+  if (physaddr & 0xfff || size & 0xfff || size == 0)
-+    {
-+      grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" +%s%s%s -%s%s%s\n",
-+		    __func__, physaddr, physaddr + size - 1,
-+		    (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
-+		    (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
-+		    (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
-+		    (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
-+		    (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
-+		    (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "");
-+      return 0;
-+    }
-+
-+  uefi_set_attrs = grub_mem_attrs_to_uefi_mem_attrs (set_attrs);
-+  grub_dprintf ("nx", "translating set_attrs from 0x%lx to 0x%lx\n", set_attrs, uefi_set_attrs);
-+  uefi_clear_attrs = grub_mem_attrs_to_uefi_mem_attrs (clear_attrs);
-+  grub_dprintf ("nx", "translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs, uefi_clear_attrs);
-+  if (uefi_set_attrs)
-+    efi_status = efi_call_4(proto->set_memory_attributes,
-+			    proto, physaddr, size, uefi_set_attrs);
-+  if (efi_status == GRUB_EFI_SUCCESS && uefi_clear_attrs)
-+    efi_status = efi_call_4(proto->clear_memory_attributes,
-+			    proto, physaddr, size, uefi_clear_attrs);
-+
-+  err = grub_get_mem_attrs (addr, size, &after);
-+  if (err)
-+    grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n",
-+		  addr, size, &after, err);
-+
-+  grub_dprintf ("nx", "set +%s%s%s -%s%s%s on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" before:%c%c%c after:%c%c%c\n",
-+		(set_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
-+		(set_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
-+		(set_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
-+		(clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
-+		(clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
-+		(clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
-+		addr, addr + size - 1,
-+		(before & GRUB_MEM_ATTR_R) ? 'r' : '-',
-+		(before & GRUB_MEM_ATTR_W) ? 'w' : '-',
-+		(before & GRUB_MEM_ATTR_X) ? 'x' : '-',
-+		(after & GRUB_MEM_ATTR_R) ? 'r' : '-',
-+		(after & GRUB_MEM_ATTR_W) ? 'w' : '-',
-+		(after & GRUB_MEM_ATTR_X) ? 'x' : '-');
-+
-+  return grub_efi_status_to_err (efi_status);
-+}
-diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
-index f431f49973..464842ba37 100644
---- a/include/grub/efi/api.h
-+++ b/include/grub/efi/api.h
-@@ -363,6 +363,11 @@
-       { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \
-   }
- 
-+#define GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID \
-+  { 0xf4560cf6, 0x40ec, 0x4b4a, \
-+    { 0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89 } \
-+  }
-+
- struct grub_efi_sal_system_table
- {
-   grub_uint32_t signature;
-@@ -2102,6 +2107,26 @@ struct grub_efi_ip6_config_manual_address {
- };
- typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t;
- 
-+struct grub_efi_memory_attribute_protocol
-+{
-+  grub_efi_status_t (*get_memory_attributes) (
-+			    struct grub_efi_memory_attribute_protocol *this,
-+			    grub_efi_physical_address_t base_address,
-+			    grub_efi_uint64_t length,
-+			    grub_efi_uint64_t *attributes);
-+  grub_efi_status_t (*set_memory_attributes) (
-+			    struct grub_efi_memory_attribute_protocol *this,
-+			    grub_efi_physical_address_t base_address,
-+			    grub_efi_uint64_t length,
-+			    grub_efi_uint64_t attributes);
-+  grub_efi_status_t (*clear_memory_attributes) (
-+			    struct grub_efi_memory_attribute_protocol *this,
-+			    grub_efi_physical_address_t base_address,
-+			    grub_efi_uint64_t length,
-+			    grub_efi_uint64_t attributes);
-+};
-+typedef struct grub_efi_memory_attribute_protocol grub_efi_memory_attribute_protocol_t;
-+
- #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
-   || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \
-   || defined(__riscv)
-diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
-index ec52083c49..34825c4adc 100644
---- a/include/grub/efi/efi.h
-+++ b/include/grub/efi/efi.h
-@@ -164,4 +164,6 @@ struct grub_net_card;
- grub_efi_handle_t
- grub_efinet_get_device_handle (struct grub_net_card *card);
- 
-+grub_err_t EXPORT_FUNC(grub_efi_status_to_err) (grub_efi_status_t status);
-+
- #endif /* ! GRUB_EFI_EFI_HEADER */
-diff --git a/include/grub/mm.h b/include/grub/mm.h
-index 9c38dd3ca5..d81623d226 100644
---- a/include/grub/mm.h
-+++ b/include/grub/mm.h
-@@ -22,6 +22,7 @@
- 
- #include <grub/types.h>
- #include <grub/symbol.h>
-+#include <grub/err.h>
- #include <config.h>
- 
- #ifndef NULL
-@@ -38,6 +39,37 @@ void *EXPORT_FUNC(grub_realloc) (void *ptr, grub_size_t size);
- void *EXPORT_FUNC(grub_memalign) (grub_size_t align, grub_size_t size);
- #endif
- 
-+#define GRUB_MEM_ATTR_R	0x0000000000000004LLU
-+#define GRUB_MEM_ATTR_W	0x0000000000000002LLU
-+#define GRUB_MEM_ATTR_X	0x0000000000000001LLU
-+
-+#ifdef GRUB_MACHINE_EFI
-+grub_err_t EXPORT_FUNC(grub_get_mem_attrs) (grub_addr_t addr,
-+					    grub_size_t size,
-+					    grub_uint64_t *attrs);
-+grub_err_t EXPORT_FUNC(grub_update_mem_attrs) (grub_addr_t addr,
-+					       grub_size_t size,
-+					       grub_uint64_t set_attrs,
-+					       grub_uint64_t clear_attrs);
-+#else /* !GRUB_MACHINE_EFI */
-+static inline grub_err_t
-+grub_get_mem_attrs (grub_addr_t addr __attribute__((__unused__)),
-+		    grub_size_t size __attribute__((__unused__)),
-+		    grub_uint64_t *attrs __attribute__((__unused__)))
-+{
-+  return GRUB_ERR_NONE;
-+}
-+
-+static inline grub_err_t
-+grub_update_mem_attrs (grub_addr_t addr __attribute__((__unused__)),
-+		       grub_size_t size __attribute__((__unused__)),
-+		       grub_uint64_t set_attrs __attribute__((__unused__)),
-+		       grub_uint64_t clear_attrs __attribute__((__unused__)))
-+{
-+  return GRUB_ERR_NONE;
-+}
-+#endif /* GRUB_MACHINE_EFI */
-+
- void grub_mm_check_real (const char *file, int line);
- #define grub_mm_check() grub_mm_check_real (GRUB_FILE, __LINE__);
- 
diff --git a/SOURCES/0275-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch b/SOURCES/0275-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch
new file mode 100644
index 0000000..0079750
--- /dev/null
+++ b/SOURCES/0275-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch
@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 11 Oct 2022 17:00:50 -0400
+Subject: [PATCH] x86-efi: Fix an incorrect array size in kernel allocation
+
+In 81a6ebf62bbe166ddc968463df2e8bd481bf697c ("efi: split allocation
+policy for kernel vs initrd memories."), I introduced a split in the
+kernel allocator to allow for different dynamic policies for the kernel
+and the initrd allocations.
+
+Unfortunately, that change increased the size of the policy data used to
+make decisions, but did not change the size of the temporary storage we
+use to back it up and restore.  This results in some of .data getting
+clobbered at runtime, and hilarity ensues.
+
+This patch makes the size of the backup storage be based on the size of
+the initial policy data.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/i386/efi/linux.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index ac5ef50bdb..9854b0defa 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -92,7 +92,7 @@ static struct allocation_choice max_addresses[] =
+       { INITRD_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
+     { NO_MEM, 0, 0 }
+   };
+-static struct allocation_choice saved_addresses[4];
++static struct allocation_choice saved_addresses[sizeof(max_addresses) / sizeof(max_addresses[0])];
+ 
+ #define save_addresses() grub_memcpy(saved_addresses, max_addresses, sizeof(max_addresses))
+ #define restore_addresses() grub_memcpy(max_addresses, saved_addresses, sizeof(max_addresses))
diff --git a/SOURCES/0276-commands-efi-tpm-Refine-the-status-of-log-event.patch b/SOURCES/0276-commands-efi-tpm-Refine-the-status-of-log-event.patch
new file mode 100644
index 0000000..896e49b
--- /dev/null
+++ b/SOURCES/0276-commands-efi-tpm-Refine-the-status-of-log-event.patch
@@ -0,0 +1,42 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Lu Ken <ken.lu@intel.com>
+Date: Wed, 13 Jul 2022 10:06:10 +0800
+Subject: [PATCH] commands/efi/tpm: Refine the status of log event
+
+1. Use macro GRUB_ERR_NONE instead of hard code 0.
+2. Keep lowercase of the first char for the status string of log event.
+
+Signed-off-by: Lu Ken <ken.lu@intel.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 922898573e37135f5dedc16f3e15a1d1d4c53f8a)
+---
+ grub-core/commands/efi/tpm.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c
+index a97d85368a..7acf510499 100644
+--- a/grub-core/commands/efi/tpm.c
++++ b/grub-core/commands/efi/tpm.c
+@@ -135,17 +135,17 @@ grub_efi_log_event_status (grub_efi_status_t status)
+   switch (status)
+     {
+     case GRUB_EFI_SUCCESS:
+-      return 0;
++      return GRUB_ERR_NONE;
+     case GRUB_EFI_DEVICE_ERROR:
+-      return grub_error (GRUB_ERR_IO, N_("Command failed"));
++      return grub_error (GRUB_ERR_IO, N_("command failed"));
+     case GRUB_EFI_INVALID_PARAMETER:
+-      return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter"));
++      return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid parameter"));
+     case GRUB_EFI_BUFFER_TOO_SMALL:
+-      return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small"));
++      return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("output buffer too small"));
+     case GRUB_EFI_NOT_FOUND:
+       return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable"));
+     default:
+-      return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error"));
++      return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("unknown TPM error"));
+     }
+ }
+ 
diff --git a/SOURCES/0276-nx-set-page-permissions-for-loaded-modules.patch b/SOURCES/0276-nx-set-page-permissions-for-loaded-modules.patch
deleted file mode 100644
index ad3c2aa..0000000
--- a/SOURCES/0276-nx-set-page-permissions-for-loaded-modules.patch
+++ /dev/null
@@ -1,264 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 21 Mar 2022 17:46:35 -0400
-Subject: [PATCH] nx: set page permissions for loaded modules.
-
-For NX, we need to set write and executable permissions on the sections
-of grub modules when we load them.
-
-On sections with SHF_ALLOC set, which is typically everything except
-.modname and the symbol and string tables, this patch clears the Read
-Only flag on sections that have the ELF flag SHF_WRITE set, and clears
-the No eXecute flag on sections with SHF_EXECINSTR set.  In all other
-cases it sets both flags.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-[rharwood: arm tgptr -> tgaddr]
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
-(cherry-picked from commit ca74904ede0406b594cbedc52ce8e38a6633d2ae)
----
- grub-core/kern/dl.c | 120 +++++++++++++++++++++++++++++++++++++++-------------
- include/grub/dl.h   |  44 +++++++++++++++++++
- 2 files changed, 134 insertions(+), 30 deletions(-)
-
-diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
-index 8c7aacef39..d5de80186f 100644
---- a/grub-core/kern/dl.c
-+++ b/grub-core/kern/dl.c
-@@ -285,6 +285,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
- #endif
-   char *ptr;
- 
-+  grub_dprintf ("modules", "loading segments for \"%s\"\n", mod->name);
-+
-   arch_addralign = grub_arch_dl_min_alignment ();
- 
-   for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
-@@ -384,6 +386,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
-   ptr += got;
- #endif
- 
-+  grub_dprintf ("modules", "done loading segments for \"%s\"\n", mod->name);
-   return GRUB_ERR_NONE;
- }
- 
-@@ -517,23 +520,6 @@ grub_dl_find_section (Elf_Ehdr *e, const char *name)
-       return s;
-   return NULL;
- }
--static long
--grub_dl_find_section_index (Elf_Ehdr *e, const char *name)
--{
--  Elf_Shdr *s;
--  const char *str;
--  unsigned i;
--
--  s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
--  str = (char *) e + s->sh_offset;
--
--  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
--       i < e->e_shnum;
--       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
--    if (grub_strcmp (str + s->sh_name, name) == 0)
--      return (long)i;
--  return -1;
--}
- 
- /* Me, Vladimir Serbinenko, hereby I add this module check as per new
-    GNU module policy. Note that this license check is informative only.
-@@ -662,6 +648,7 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
-   Elf_Shdr *s;
-   unsigned i;
- 
-+  grub_dprintf ("modules", "relocating symbols for \"%s\"\n", mod->name);
-   for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
-        i < e->e_shnum;
-        i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
-@@ -670,24 +657,95 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
- 	grub_dl_segment_t seg;
- 	grub_err_t err;
- 
--	/* Find the target segment.  */
--	for (seg = mod->segment; seg; seg = seg->next)
--	  if (seg->section == s->sh_info)
--	    break;
-+	seg = grub_dl_find_segment(mod, s->sh_info);
-+        if (!seg)
-+	  continue;
- 
--	if (seg)
--	  {
--	    if (!mod->symtab)
--	      return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table");
-+	if (!mod->symtab)
-+	  return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table");
- 
--	    err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg);
--	    if (err)
--	      return err;
--	  }
-+	err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg);
-+	if (err)
-+	  return err;
-       }
- 
-+  grub_dprintf ("modules", "done relocating symbols for \"%s\"\n", mod->name);
-   return GRUB_ERR_NONE;
- }
-+
-+static grub_err_t
-+grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr)
-+{
-+  unsigned i;
-+  const Elf_Shdr *s;
-+  const Elf_Ehdr *e = ehdr;
-+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
-+  grub_size_t arch_addralign = grub_arch_dl_min_alignment ();
-+  grub_addr_t tgaddr;
-+  grub_uint64_t tgsz;
-+#endif
-+
-+  grub_dprintf ("modules", "updating memory attributes for \"%s\"\n",
-+		mod->name);
-+  for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
-+       i < e->e_shnum;
-+       i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
-+    {
-+      grub_dl_segment_t seg;
-+      grub_uint64_t set_attrs = GRUB_MEM_ATTR_R;
-+      grub_uint64_t clear_attrs = GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X;
-+
-+      seg = grub_dl_find_segment(mod, i);
-+      if (!seg)
-+	continue;
-+
-+      if (seg->size == 0 || !(s->sh_flags & SHF_ALLOC))
-+	continue;
-+
-+      if (s->sh_flags & SHF_WRITE)
-+	{
-+	  set_attrs |= GRUB_MEM_ATTR_W;
-+	  clear_attrs &= ~GRUB_MEM_ATTR_W;
-+	}
-+
-+      if (s->sh_flags & SHF_EXECINSTR)
-+	{
-+	  set_attrs |= GRUB_MEM_ATTR_X;
-+	  clear_attrs &= ~GRUB_MEM_ATTR_X;
-+	}
-+
-+      grub_dprintf ("modules", "setting memory attrs for section \"%s\" to -%s%s%s+%s%s%s\n",
-+		    grub_dl_get_section_name(e, s),
-+		    (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
-+		    (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
-+		    (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
-+		    (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
-+		    (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
-+		    (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "");
-+      grub_update_mem_attrs ((grub_addr_t)(seg->addr), seg->size, set_attrs, clear_attrs);
-+    }
-+
-+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
-+  tgaddr = grub_min((grub_addr_t)mod->tramp, (grub_addr_t)mod->got);
-+  tgsz = grub_max((grub_addr_t)mod->trampptr, (grub_addr_t)mod->gotptr) - tgaddr;
-+
-+  if (tgsz)
-+    {
-+      tgsz = ALIGN_UP(tgsz, arch_addralign);
-+
-+      grub_dprintf ("modules", "updating attributes for GOT and trampolines\n",
-+		    mod->name);
-+      grub_update_mem_attrs (tgaddr, tgsz, GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_X,
-+			     GRUB_MEM_ATTR_W);
-+    }
-+#endif
-+
-+  grub_dprintf ("modules", "done updating module memory attributes for \"%s\"\n",
-+		mod->name);
-+
-+  return GRUB_ERR_NONE;
-+}
-+
- static void
- grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e)
- {
-@@ -753,6 +811,7 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
-   mod->ref_count = 1;
- 
-   grub_dprintf ("modules", "relocating to %p\n", mod);
-+
-   /* Me, Vladimir Serbinenko, hereby I add this module check as per new
-      GNU module policy. Note that this license check is informative only.
-      Modules have to be licensed under GPLv3 or GPLv3+ (optionally
-@@ -766,7 +825,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
-       || grub_dl_resolve_dependencies (mod, e)
-       || grub_dl_load_segments (mod, e)
-       || grub_dl_resolve_symbols (mod, e)
--      || grub_dl_relocate_symbols (mod, e))
-+      || grub_dl_relocate_symbols (mod, e)
-+      || grub_dl_set_mem_attrs (mod, e))
-     {
-       mod->fini = 0;
-       grub_dl_unload (mod);
-diff --git a/include/grub/dl.h b/include/grub/dl.h
-index f36ed5cb17..45ac8e339f 100644
---- a/include/grub/dl.h
-+++ b/include/grub/dl.h
-@@ -27,6 +27,7 @@
- #include <grub/elf.h>
- #include <grub/list.h>
- #include <grub/misc.h>
-+#include <grub/mm.h>
- #endif
- 
- /*
-@@ -268,6 +269,49 @@ grub_dl_is_persistent (grub_dl_t mod)
-   return mod->persistent;
- }
- 
-+static inline const char *
-+grub_dl_get_section_name (const Elf_Ehdr *e, const Elf_Shdr *s)
-+{
-+  Elf_Shdr *str_s;
-+  const char *str;
-+
-+  str_s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
-+  str = (char *) e + str_s->sh_offset;
-+
-+  return str + s->sh_name;
-+}
-+
-+static inline long
-+grub_dl_find_section_index (Elf_Ehdr *e, const char *name)
-+{
-+  Elf_Shdr *s;
-+  const char *str;
-+  unsigned i;
-+
-+  s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
-+  str = (char *) e + s->sh_offset;
-+
-+  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
-+       i < e->e_shnum;
-+       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
-+    if (grub_strcmp (str + s->sh_name, name) == 0)
-+      return (long)i;
-+  return -1;
-+}
-+
-+/* Return the segment for a section of index N */
-+static inline grub_dl_segment_t
-+grub_dl_find_segment (grub_dl_t mod, unsigned n)
-+{
-+  grub_dl_segment_t seg;
-+
-+  for (seg = mod->segment; seg; seg = seg->next)
-+    if (seg->section == n)
-+      return seg;
-+
-+  return NULL;
-+}
-+
- #endif
- 
- void * EXPORT_FUNC(grub_resolve_symbol) (const char *name);
diff --git a/SOURCES/0277-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch b/SOURCES/0277-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch
new file mode 100644
index 0000000..e04dcbc
--- /dev/null
+++ b/SOURCES/0277-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch
@@ -0,0 +1,37 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Lu Ken <ken.lu@intel.com>
+Date: Wed, 13 Jul 2022 10:06:11 +0800
+Subject: [PATCH] commands/efi/tpm: Use grub_strcpy() instead of grub_memcpy()
+
+The event description is a string, so using grub_strcpy() is cleaner than
+using grub_memcpy().
+
+Signed-off-by: Lu Ken <ken.lu@intel.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit ef8679b645a63eb9eb191bb9539d7d25a9d6ff3b)
+---
+ grub-core/commands/efi/tpm.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c
+index 7acf510499..bb59599721 100644
+--- a/grub-core/commands/efi/tpm.c
++++ b/grub-core/commands/efi/tpm.c
+@@ -175,7 +175,7 @@ grub_tpm1_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf,
+   event->PCRIndex = pcr;
+   event->EventType = EV_IPL;
+   event->EventSize = grub_strlen (description) + 1;
+-  grub_memcpy (event->Event, description, event->EventSize);
++  grub_strcpy ((char *) event->Event, description);
+ 
+   algorithm = TCG_ALG_SHA;
+   status = efi_call_7 (tpm->log_extend_event, tpm, (grub_addr_t) buf, (grub_uint64_t) size,
+@@ -212,7 +212,7 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf,
+   event->Header.EventType = EV_IPL;
+   event->Size =
+     sizeof (*event) - sizeof (event->Event) + grub_strlen (description) + 1;
+-  grub_memcpy (event->Event, description, grub_strlen (description) + 1);
++  grub_strcpy ((char *) event->Event, description);
+ 
+   status = efi_call_5 (tpm->hash_log_extend_event, tpm, 0, (grub_addr_t) buf,
+ 		       (grub_uint64_t) size, event);
diff --git a/SOURCES/0277-nx-set-attrs-in-our-kernel-loaders.patch b/SOURCES/0277-nx-set-attrs-in-our-kernel-loaders.patch
deleted file mode 100644
index 9beee6a..0000000
--- a/SOURCES/0277-nx-set-attrs-in-our-kernel-loaders.patch
+++ /dev/null
@@ -1,571 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 22 Mar 2022 10:57:07 -0400
-Subject: [PATCH] nx: set attrs in our kernel loaders
-
-For NX, our kernel loaders need to set write and execute page
-permissions on allocated pages and the stack.
-
-This patch adds those calls.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-[rharwood: fix aarch64 callsites]
-(cherry-picked from commit a9f79a997f01a83b36cdfa89ef2e72ac2a17c06c)
-[rharwood: uninitialized stack_attrs, double verification]
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
----
- grub-core/kern/efi/mm.c            |  78 ++++++++++++++++++
- grub-core/loader/arm64/linux.c     |  16 +++-
- grub-core/loader/arm64/xen_boot.c  |   4 +-
- grub-core/loader/efi/chainloader.c |  11 +++
- grub-core/loader/efi/linux.c       | 164 ++++++++++++++++++++++++++++++++++++-
- grub-core/loader/i386/efi/linux.c  |  26 +++++-
- grub-core/loader/i386/linux.c      |   5 ++
- include/grub/efi/efi.h             |   6 +-
- include/grub/efi/linux.h           |  17 +++-
- include/grub/efi/pe32.h            |   2 +
- 10 files changed, 314 insertions(+), 15 deletions(-)
-
-diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
-index 2c33758ed7..88364d764c 100644
---- a/grub-core/kern/efi/mm.c
-+++ b/grub-core/kern/efi/mm.c
-@@ -610,6 +610,82 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map,
- }
- #endif
- 
-+grub_addr_t grub_stack_addr = (grub_addr_t)-1ll;
-+grub_size_t grub_stack_size = 0;
-+
-+static void
-+grub_nx_init (void)
-+{
-+  grub_uint64_t attrs, stack_attrs;
-+  grub_err_t err;
-+  grub_addr_t stack_current, stack_end;
-+  const grub_uint64_t page_size = 4096;
-+  const grub_uint64_t page_mask = ~(page_size - 1);
-+
-+  /*
-+   * These are to confirm that the flags are working as expected when
-+   * debugging.
-+   */
-+  attrs = 0;
-+  stack_current = (grub_addr_t)grub_nx_init & page_mask;
-+  err = grub_get_mem_attrs (stack_current, page_size, &attrs);
-+  if (err)
-+    {
-+      grub_dprintf ("nx",
-+		    "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
-+		    stack_current, err);
-+      grub_error_pop ();
-+    }
-+  else
-+    grub_dprintf ("nx", "page attrs for grub_nx_init (%p) are %c%c%c\n",
-+		  grub_dl_load_core,
-+		  (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-',
-+		  (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-',
-+		  (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-');
-+
-+  stack_current = (grub_addr_t)&stack_current & page_mask;
-+  err = grub_get_mem_attrs (stack_current, page_size, &stack_attrs);
-+  if (err)
-+    {
-+      grub_dprintf ("nx",
-+		    "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
-+		    stack_current, err);
-+      grub_error_pop ();
-+    }
-+  else
-+    {
-+      attrs = stack_attrs;
-+      grub_dprintf ("nx", "page attrs for stack (%p) are %c%c%c\n",
-+                    &attrs,
-+                    (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-',
-+                    (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-',
-+                    (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-');
-+    }
-+
-+  for (stack_end = stack_current + page_size ;
-+       !(attrs & GRUB_MEM_ATTR_R);
-+       stack_end += page_size)
-+    {
-+      err = grub_get_mem_attrs (stack_current, page_size, &attrs);
-+      if (err)
-+	{
-+	  grub_dprintf ("nx",
-+			"grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
-+			stack_current, err);
-+	  grub_error_pop ();
-+	  break;
-+	}
-+    }
-+  if (stack_end > stack_current)
-+    {
-+      grub_stack_addr = stack_current;
-+      grub_stack_size = stack_end - stack_current;
-+      grub_dprintf ("nx",
-+		    "detected stack from 0x%"PRIxGRUB_ADDR" to 0x%"PRIxGRUB_ADDR"\n",
-+		    grub_stack_addr, grub_stack_addr + grub_stack_size - 1);
-+    }
-+}
-+
- void
- grub_efi_mm_init (void)
- {
-@@ -623,6 +699,8 @@ grub_efi_mm_init (void)
-   grub_efi_uint64_t required_pages;
-   int mm_status;
- 
-+  grub_nx_init ();
-+
-   /* Prepare a memory region to store two memory maps.  */
-   memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
-   if (! memory_map)
-diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
-index bcc6ef46e9..70db5a6e0b 100644
---- a/grub-core/loader/arm64/linux.c
-+++ b/grub-core/loader/arm64/linux.c
-@@ -173,7 +173,8 @@ free_params (void)
- }
- 
- grub_err_t
--grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args)
-+grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args,
-+				int nx_supported)
- {
-   grub_err_t retval;
- 
-@@ -183,7 +184,8 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args)
- 
-   grub_dprintf ("linux", "linux command line: '%s'\n", args);
- 
--  retval = grub_efi_linux_boot ((char *)addr, handover_offset, (void *)addr);
-+  retval = grub_efi_linux_boot (addr, size, handover_offset,
-+				(void *)addr, nx_supported);
- 
-   /* Never reached... */
-   free_params();
-@@ -193,7 +195,10 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args)
- static grub_err_t
- grub_linux_boot (void)
- {
--  return (grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr, linux_args));
-+  return grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr,
-+					(grub_size_t)kernel_size,
-+					linux_args,
-+					0);
- }
- 
- static grub_err_t
-@@ -342,6 +347,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   grub_uint32_t align;
-   void *kernel = NULL;
-   int rc;
-+  int nx_supported = 1;
- 
-   grub_dl_ref (my_mod);
- 
-@@ -389,6 +395,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset);
-   grub_dprintf ("linux", "kernel alignment    : 0x%x\n", align);
- 
-+  err = grub_efi_check_nx_image_support((grub_addr_t)kernel, filelen, &nx_supported);
-+  if (err != GRUB_ERR_NONE)
-+    goto fail;
-+
-   grub_loader_unset();
- 
-   kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1);
-diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c
-index d9b7a9ba40..6e7e920416 100644
---- a/grub-core/loader/arm64/xen_boot.c
-+++ b/grub-core/loader/arm64/xen_boot.c
-@@ -266,7 +266,9 @@ xen_boot (void)
-     return err;
- 
-   return grub_arch_efi_linux_boot_image (xen_hypervisor->start,
--					  xen_hypervisor->cmdline);
-+                                         xen_hypervisor->size,
-+                                         xen_hypervisor->cmdline,
-+                                         0);
- }
- 
- static void
-diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
-index 8ef508beca..6ac69f0f59 100644
---- a/grub-core/loader/efi/chainloader.c
-+++ b/grub-core/loader/efi/chainloader.c
-@@ -1071,6 +1071,17 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
-       goto fail;
-     }
- 
-+  /*
-+   * The OS kernel is going to set its own permissions when it takes over
-+   * paging a few million instructions from now, and load_image() will set up
-+   * anything that's needed based on the section headers, so there's no point
-+   * in doing anything but clearing the protection bits here.
-+   */
-+  grub_dprintf("nx", "setting attributes for %p (%lu bytes) to %llx\n",
-+	       (void *)(grub_addr_t)address, fsize, 0llu);
-+  grub_update_mem_attrs (address, fsize,
-+			 GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X, 0);
-+
- #if defined (__i386__) || defined (__x86_64__)
-   if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header))
-     {
-diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
-index 9260731c10..dcc9ea40ea 100644
---- a/grub-core/loader/efi/linux.c
-+++ b/grub-core/loader/efi/linux.c
-@@ -66,16 +66,127 @@ grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
- 
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wcast-align"
-+#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
-+
-+grub_err_t
-+grub_efi_check_nx_image_support (grub_addr_t kernel_addr,
-+				 grub_size_t kernel_size,
-+				 int *nx_supported)
-+{
-+  struct grub_dos_header *doshdr;
-+  grub_size_t sz = sizeof (*doshdr);
-+
-+  struct grub_pe32_header_32 *pe32;
-+  struct grub_pe32_header_64 *pe64;
-+
-+  int image_is_compatible = 0;
-+  int is_64_bit;
-+
-+  if (kernel_size < sz)
-+    return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
-+
-+  doshdr = (void *)kernel_addr;
-+
-+  if ((doshdr->magic & 0xffff) != GRUB_DOS_MAGIC)
-+    return grub_error (GRUB_ERR_BAD_OS, N_("kernel DOS magic is invalid"));
-+
-+  sz = doshdr->lfanew + sizeof (*pe32);
-+  if (kernel_size < sz)
-+    return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
-+
-+  pe32 = (struct grub_pe32_header_32 *)(kernel_addr + doshdr->lfanew);
-+  pe64 = (struct grub_pe32_header_64 *)pe32;
-+
-+  if (grub_memcmp (pe32->signature, GRUB_PE32_SIGNATURE,
-+		   GRUB_PE32_SIGNATURE_SIZE) != 0)
-+    return grub_error (GRUB_ERR_BAD_OS, N_("kernel PE magic is invalid"));
-+
-+  switch (pe32->coff_header.machine)
-+    {
-+    case GRUB_PE32_MACHINE_ARMTHUMB_MIXED:
-+    case GRUB_PE32_MACHINE_I386:
-+    case GRUB_PE32_MACHINE_RISCV32:
-+      is_64_bit = 0;
-+      break;
-+    case GRUB_PE32_MACHINE_ARM64:
-+    case GRUB_PE32_MACHINE_IA64:
-+    case GRUB_PE32_MACHINE_RISCV64:
-+    case GRUB_PE32_MACHINE_X86_64:
-+      is_64_bit = 1;
-+      break;
-+    default:
-+      return grub_error (GRUB_ERR_BAD_OS, N_("PE machine type 0x%04hx unknown"),
-+			 pe32->coff_header.machine);
-+    }
-+
-+  if (is_64_bit)
-+    {
-+      sz = doshdr->lfanew + sizeof (*pe64);
-+      if (kernel_size < sz)
-+	return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
-+
-+      if (pe64->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT)
-+	image_is_compatible = 1;
-+    }
-+  else
-+    {
-+      if (pe32->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT)
-+	image_is_compatible = 1;
-+    }
-+
-+  *nx_supported = image_is_compatible;
-+  return GRUB_ERR_NONE;
-+}
-+
-+grub_err_t
-+grub_efi_check_nx_required (int *nx_required)
-+{
-+  grub_efi_status_t status;
-+  grub_efi_guid_t guid = GRUB_EFI_SHIM_LOCK_GUID;
-+  grub_size_t mok_policy_sz = 0;
-+  char *mok_policy = NULL;
-+  grub_uint32_t mok_policy_attrs = 0;
-+
-+  status = grub_efi_get_variable_with_attributes ("MokPolicy", &guid,
-+						  &mok_policy_sz,
-+						  (void **)&mok_policy,
-+						  &mok_policy_attrs);
-+  if (status == GRUB_EFI_NOT_FOUND ||
-+      mok_policy_sz == 0 ||
-+      mok_policy == NULL)
-+    {
-+      *nx_required = 0;
-+      return GRUB_ERR_NONE;
-+    }
-+
-+  *nx_required = 0;
-+  if (mok_policy_sz < 1 ||
-+      mok_policy_attrs != (GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS |
-+			   GRUB_EFI_VARIABLE_RUNTIME_ACCESS) ||
-+      (mok_policy[mok_policy_sz-1] & GRUB_MOK_POLICY_NX_REQUIRED))
-+    *nx_required = 1;
-+
-+  return GRUB_ERR_NONE;
-+}
- 
- typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *);
- 
- grub_err_t
--grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
--		     void *kernel_params)
-+grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size,
-+		     grub_off_t handover_offset, void *kernel_params,
-+		     int nx_supported)
- {
-   grub_efi_loaded_image_t *loaded_image = NULL;
-   handover_func hf;
-   int offset = 0;
-+  grub_uint64_t stack_set_attrs = GRUB_MEM_ATTR_R |
-+				  GRUB_MEM_ATTR_W |
-+				  GRUB_MEM_ATTR_X;
-+  grub_uint64_t stack_clear_attrs = 0;
-+  grub_uint64_t kernel_set_attrs = stack_set_attrs;
-+  grub_uint64_t kernel_clear_attrs = stack_clear_attrs;
-+  grub_uint64_t attrs;
-+  int nx_required = 0;
- 
- #ifdef __x86_64__
-   offset = 512;
-@@ -88,12 +199,57 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
-    */
-   loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
-   if (loaded_image)
--    loaded_image->image_base = kernel_addr;
-+    loaded_image->image_base = (void *)kernel_addr;
-   else
-     grub_dprintf ("linux", "Loaded Image base address could not be set\n");
- 
-   grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n",
--		kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params);
-+		(void *)kernel_addr, (void *)handover_offset, kernel_params);
-+
-+
-+  if (nx_required && !nx_supported)
-+    return grub_error (GRUB_ERR_BAD_OS, N_("kernel does not support NX loading required by policy"));
-+
-+  if (nx_supported)
-+    {
-+      kernel_set_attrs &= ~GRUB_MEM_ATTR_W;
-+      kernel_clear_attrs |= GRUB_MEM_ATTR_W;
-+      stack_set_attrs &= ~GRUB_MEM_ATTR_X;
-+      stack_clear_attrs |= GRUB_MEM_ATTR_X;
-+    }
-+
-+  grub_dprintf ("nx", "Setting attributes for 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to r%cx\n",
-+		    kernel_addr, kernel_addr + kernel_size - 1,
-+		    (kernel_set_attrs & GRUB_MEM_ATTR_W) ? 'w' : '-');
-+  grub_update_mem_attrs (kernel_addr, kernel_size,
-+			 kernel_set_attrs, kernel_clear_attrs);
-+
-+  grub_get_mem_attrs (kernel_addr, 4096, &attrs);
-+  grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
-+		(grub_addr_t)kernel_addr,
-+		(attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
-+		(attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
-+		(attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
-+  if (grub_stack_addr != (grub_addr_t)-1ll)
-+    {
-+      grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n",
-+		    grub_stack_addr, grub_stack_addr + grub_stack_size - 1,
-+		    (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-');
-+      grub_update_mem_attrs (grub_stack_addr, grub_stack_size,
-+			     stack_set_attrs, stack_clear_attrs);
-+
-+      grub_get_mem_attrs (grub_stack_addr, 4096, &attrs);
-+      grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
-+		    grub_stack_addr,
-+		    (attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
-+		    (attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
-+		    (attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
-+    }
-+
-+#if defined(__i386__) || defined(__x86_64__)
-+  asm volatile ("cli");
-+#endif
-+
-   hf = (handover_func)((char *)kernel_addr + handover_offset + offset);
-   hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
- 
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index b832c85728..dc98077378 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -45,7 +45,7 @@ struct grub_linuxefi_context {
-   grub_uint32_t handover_offset;
-   struct linux_kernel_params *params;
-   char *cmdline;
--
-+  int nx_supported;
-   void *initrd_mem;
- };
- 
-@@ -111,13 +111,19 @@ kernel_alloc(grub_efi_uintn_t size,
-       pages = BYTES_TO_PAGES(size);
-       grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n",
- 		    (unsigned long)pages, (void *)(unsigned long)max);
-+      size = pages * GRUB_EFI_PAGE_SIZE;
- 
-       prev_max = max;
-       addr = grub_efi_allocate_pages_real (max, pages,
- 					   max_addresses[i].alloc_type,
- 					   memtype);
-       if (addr)
--	grub_dprintf ("linux", "Allocated at %p\n", addr);
-+	{
-+	  grub_dprintf ("linux", "Allocated at %p\n", addr);
-+	  grub_update_mem_attrs ((grub_addr_t)addr, size,
-+				 GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W,
-+				 GRUB_MEM_ATTR_X);
-+	}
-     }
- 
-   while (grub_error_pop ())
-@@ -138,9 +144,11 @@ grub_linuxefi_boot (void *data)
- 
-   asm volatile ("cli");
- 
--  return grub_efi_linux_boot ((char *)context->kernel_mem,
-+  return grub_efi_linux_boot ((grub_addr_t)context->kernel_mem,
-+			      context->kernel_size,
- 			      context->handover_offset,
--			      context->params);
-+			      context->params,
-+			      context->nx_supported);
- }
- 
- static grub_err_t
-@@ -306,7 +314,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   grub_uint32_t handover_offset;
-   struct linux_kernel_params *params = 0;
-   char *cmdline = 0;
-+  int nx_supported = 1;
-   struct grub_linuxefi_context *context = 0;
-+  grub_err_t err;
- 
-   grub_dl_ref (my_mod);
- 
-@@ -347,6 +357,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
- 	}
-     }
- 
-+  err = grub_efi_check_nx_image_support ((grub_addr_t)kernel, filelen,
-+					 &nx_supported);
-+  if (err != GRUB_ERR_NONE)
-+    return err;
-+  grub_dprintf ("linux", "nx is%s supported by this kernel\n",
-+		nx_supported ? "" : " not");
-+
-   lh = (struct linux_i386_kernel_header *)kernel;
-   grub_dprintf ("linux", "original lh is at %p\n", kernel);
- 
-@@ -511,6 +528,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   context->handover_offset = handover_offset;
-   context->params = params;
-   context->cmdline = cmdline;
-+  context->nx_supported = nx_supported;
- 
-   grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0);
- 
-diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
-index 4aeb0e4b9a..3c1ff64763 100644
---- a/grub-core/loader/i386/linux.c
-+++ b/grub-core/loader/i386/linux.c
-@@ -805,6 +805,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-       kernel_offset += len;
-     }
- 
-+  grub_dprintf("efi", "setting attributes for %p (%zu bytes) to +rw-x\n",
-+	       &linux_params, sizeof (lh) + len);
-+  grub_update_mem_attrs ((grub_addr_t)&linux_params, sizeof (lh) + len,
-+			 GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, GRUB_MEM_ATTR_X);
-+
-   linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR;
-   linux_params.kernel_alignment = (1 << align);
-   linux_params.ps_mouse = linux_params.padding11 = 0;
-diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
-index 34825c4adc..449e55269f 100644
---- a/include/grub/efi/efi.h
-+++ b/include/grub/efi/efi.h
-@@ -140,12 +140,16 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd,
- 						char **device,
- 						char **path);
- 
-+extern grub_addr_t EXPORT_VAR(grub_stack_addr);
-+extern grub_size_t EXPORT_VAR(grub_stack_size);
-+
- #if defined(__arm__) || defined(__aarch64__) || defined(__riscv)
- void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void);
- grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *);
- #include <grub/cpu/linux.h>
- grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh);
--grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, char *args);
-+grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, grub_size_t size,
-+					  char *args, int nx_enabled);
- #endif
- 
- grub_addr_t grub_efi_section_addr (const char *section);
-diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
-index 0033d9305a..8130b19590 100644
---- a/include/grub/efi/linux.h
-+++ b/include/grub/efi/linux.h
-@@ -22,10 +22,23 @@
- #include <grub/err.h>
- #include <grub/symbol.h>
- 
-+#define GRUB_MOK_POLICY_NX_REQUIRED   0x1
-+
- int
- EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size);
-+
- grub_err_t
--EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset,
--				  void *kernel_param);
-+EXPORT_FUNC(grub_efi_linux_boot) (grub_addr_t kernel_address,
-+				  grub_size_t kernel_size,
-+				  grub_off_t handover_offset,
-+				  void *kernel_param, int nx_enabled);
-+
-+grub_err_t
-+EXPORT_FUNC(grub_efi_check_nx_image_support) (grub_addr_t kernel_addr,
-+					      grub_size_t kernel_size,
-+					      int *nx_supported);
-+
-+grub_err_t
-+EXPORT_FUNC(grub_efi_check_nx_required) (int *nx_required);
- 
- #endif /* ! GRUB_EFI_LINUX_HEADER */
-diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
-index 2a5e1ee003..a5e623eb04 100644
---- a/include/grub/efi/pe32.h
-+++ b/include/grub/efi/pe32.h
-@@ -181,6 +181,8 @@ struct grub_pe32_optional_header
-   struct grub_pe32_data_directory reserved_entry;
- };
- 
-+#define GRUB_PE32_NX_COMPAT 0x0100
-+
- struct grub_pe64_optional_header
- {
-   grub_uint16_t magic;
diff --git a/SOURCES/0278-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch b/SOURCES/0278-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch
new file mode 100644
index 0000000..610c81a
--- /dev/null
+++ b/SOURCES/0278-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch
@@ -0,0 +1,258 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Lu Ken <ken.lu@intel.com>
+Date: Wed, 13 Jul 2022 10:06:12 +0800
+Subject: [PATCH] efi/tpm: Add EFI_CC_MEASUREMENT_PROTOCOL support
+
+The EFI_CC_MEASUREMENT_PROTOCOL abstracts the measurement for virtual firmware
+in confidential computing environment. It is similar to the EFI_TCG2_PROTOCOL.
+It was proposed by Intel and ARM and approved by UEFI organization.
+
+It is defined in Intel GHCI specification: https://cdrdv2.intel.com/v1/dl/getContent/726790 .
+The EDKII header file is available at https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/CcMeasurement.h .
+
+Signed-off-by: Lu Ken <ken.lu@intel.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 4c76565b6cb885b7e144dc27f3612066844e2d19)
+---
+ grub-core/commands/efi/tpm.c |  48 ++++++++++++++
+ include/grub/efi/cc.h        | 151 +++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 199 insertions(+)
+ create mode 100644 include/grub/efi/cc.h
+
+diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c
+index bb59599721..ae09c1bf8b 100644
+--- a/grub-core/commands/efi/tpm.c
++++ b/grub-core/commands/efi/tpm.c
+@@ -22,6 +22,7 @@
+ #include <grub/i18n.h>
+ #include <grub/efi/api.h>
+ #include <grub/efi/efi.h>
++#include <grub/efi/cc.h>
+ #include <grub/efi/tpm.h>
+ #include <grub/mm.h>
+ #include <grub/tpm.h>
+@@ -31,6 +32,7 @@ typedef TCG_PCR_EVENT grub_tpm_event_t;
+ 
+ static grub_efi_guid_t tpm_guid = EFI_TPM_GUID;
+ static grub_efi_guid_t tpm2_guid = EFI_TPM2_GUID;
++static grub_efi_guid_t cc_measurement_guid = GRUB_EFI_CC_MEASUREMENT_PROTOCOL_GUID;
+ 
+ static grub_efi_handle_t *grub_tpm_handle;
+ static grub_uint8_t grub_tpm_version;
+@@ -221,6 +223,50 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf,
+   return grub_efi_log_event_status (status);
+ }
+ 
++static void
++grub_cc_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
++		   const char *description)
++{
++  grub_efi_cc_event_t *event;
++  grub_efi_status_t status;
++  grub_efi_cc_protocol_t *cc;
++  grub_efi_cc_mr_index_t mr;
++
++  cc = grub_efi_locate_protocol (&cc_measurement_guid, NULL);
++  if (cc == NULL)
++    return;
++
++  status = efi_call_3 (cc->map_pcr_to_mr_index, cc, pcr, &mr);
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_efi_log_event_status (status);
++      return;
++    }
++
++  event = grub_zalloc (sizeof (grub_efi_cc_event_t) +
++		       grub_strlen (description) + 1);
++  if (event == NULL)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate CC event buffer"));
++      return;
++    }
++
++  event->Header.HeaderSize = sizeof (grub_efi_cc_event_header_t);
++  event->Header.HeaderVersion = GRUB_EFI_CC_EVENT_HEADER_VERSION;
++  event->Header.MrIndex = mr;
++  event->Header.EventType = EV_IPL;
++  event->Size = sizeof (*event) + grub_strlen (description) + 1;
++  grub_strcpy ((char *) event->Event, description);
++
++  status = efi_call_5 (cc->hash_log_extend_event, cc, 0,
++		       (grub_efi_physical_address_t)(grub_addr_t) buf,
++		       (grub_efi_uint64_t) size, event);
++  grub_free (event);
++
++  if (status != GRUB_EFI_SUCCESS)
++    grub_efi_log_event_status (status);
++}
++
+ grub_err_t
+ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
+ 		    const char *description)
+@@ -228,6 +274,8 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
+   grub_efi_handle_t tpm_handle;
+   grub_efi_uint8_t protocol_version;
+ 
++  grub_cc_log_event(buf, size, pcr, description);
++
+   if (!grub_tpm_handle_find (&tpm_handle, &protocol_version))
+     return 0;
+ 
+diff --git a/include/grub/efi/cc.h b/include/grub/efi/cc.h
+new file mode 100644
+index 0000000000..8960306890
+--- /dev/null
++++ b/include/grub/efi/cc.h
+@@ -0,0 +1,151 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2022  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/>.
++ */
++
++#ifndef GRUB_EFI_CC_H
++#define GRUB_EFI_CC_H 1
++
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/err.h>
++
++#define GRUB_EFI_CC_MEASUREMENT_PROTOCOL_GUID \
++  { 0x96751a3d, 0x72f4, 0x41a6, \
++    { 0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b } \
++  };
++
++struct grub_efi_cc_version
++{
++  grub_efi_uint8_t Major;
++  grub_efi_uint8_t Minor;
++};
++typedef struct grub_efi_cc_version grub_efi_cc_version_t;
++
++/* EFI_CC Type/SubType definition. */
++#define GRUB_EFI_CC_TYPE_NONE	0
++#define GRUB_EFI_CC_TYPE_SEV	1
++#define GRUB_EFI_CC_TYPE_TDX	2
++
++struct grub_efi_cc_type
++{
++  grub_efi_uint8_t Type;
++  grub_efi_uint8_t SubType;
++};
++typedef struct grub_efi_cc_type grub_efi_cc_type_t;
++
++typedef grub_efi_uint32_t grub_efi_cc_event_log_bitmap_t;
++typedef grub_efi_uint32_t grub_efi_cc_event_log_format_t;
++typedef grub_efi_uint32_t grub_efi_cc_event_algorithm_bitmap_t;
++typedef grub_efi_uint32_t grub_efi_cc_mr_index_t;
++
++/* Intel TDX measure register index. */
++#define GRUB_TDX_MR_INDEX_MRTD	0
++#define GRUB_TDX_MR_INDEX_RTMR0	1
++#define GRUB_TDX_MR_INDEX_RTMR1	2
++#define GRUB_TDX_MR_INDEX_RTMR2	3
++#define GRUB_TDX_MR_INDEX_RTMR3	4
++
++#define GRUB_EFI_CC_EVENT_LOG_FORMAT_TCG_2	0x00000002
++#define GRUB_EFI_CC_BOOT_HASH_ALG_SHA384	0x00000004
++#define GRUB_EFI_CC_EVENT_HEADER_VERSION	1
++
++struct grub_efi_cc_event_header
++{
++  /* Size of the event header itself (sizeof(EFI_TD_EVENT_HEADER)). */
++  grub_efi_uint32_t      HeaderSize;
++
++  /*
++   * Header version. For this version of this specification,
++   * the value shall be 1.
++   */
++  grub_efi_uint16_t      HeaderVersion;
++
++  /* Index of the MR that shall be extended. */
++  grub_efi_cc_mr_index_t MrIndex;
++
++  /* Type of the event that shall be extended (and optionally logged). */
++  grub_efi_uint32_t      EventType;
++} GRUB_PACKED;
++typedef struct grub_efi_cc_event_header grub_efi_cc_event_header_t;
++
++struct grub_efi_cc_event
++{
++  /* Total size of the event including the Size component, the header and the Event data. */
++  grub_efi_uint32_t          Size;
++  grub_efi_cc_event_header_t Header;
++  grub_efi_uint8_t           Event[0];
++} GRUB_PACKED;
++typedef struct grub_efi_cc_event grub_efi_cc_event_t;
++
++struct grub_efi_cc_boot_service_capability
++{
++  /* Allocated size of the structure. */
++  grub_efi_uint8_t                     Size;
++
++  /*
++   * Version of the grub_efi_cc_boot_service_capability_t structure itself.
++   * For this version of the protocol, the Major version shall be set to 1
++   * and the Minor version shall be set to 1.
++   */
++  grub_efi_cc_version_t                StructureVersion;
++
++  /*
++   * Version of the EFI TD protocol.
++   * For this version of the protocol, the Major version shall be set to 1
++   * and the Minor version shall be set to 1.
++   */
++  grub_efi_cc_version_t                ProtocolVersion;
++
++  /* Supported hash algorithms. */
++  grub_efi_cc_event_algorithm_bitmap_t HashAlgorithmBitmap;
++
++  /* Bitmap of supported event log formats. */
++  grub_efi_cc_event_log_bitmap_t       SupportedEventLogs;
++
++  /* Indicates the CC type. */
++  grub_efi_cc_type_t CcType;
++};
++typedef struct grub_efi_cc_boot_service_capability grub_efi_cc_boot_service_capability_t;
++
++struct grub_efi_cc_protocol
++{
++  grub_efi_status_t
++  (*get_capability) (struct grub_efi_cc_protocol *this,
++		     grub_efi_cc_boot_service_capability_t *ProtocolCapability);
++
++  grub_efi_status_t
++  (*get_event_log) (struct grub_efi_cc_protocol *this,
++		    grub_efi_cc_event_log_format_t EventLogFormat,
++		    grub_efi_physical_address_t *EventLogLocation,
++		    grub_efi_physical_address_t *EventLogLastEntry,
++		    grub_efi_boolean_t *EventLogTruncated);
++
++  grub_efi_status_t
++  (*hash_log_extend_event) (struct grub_efi_cc_protocol *this,
++			    grub_efi_uint64_t Flags,
++			    grub_efi_physical_address_t DataToHash,
++			    grub_efi_uint64_t DataToHashLen,
++			    grub_efi_cc_event_t *EfiCcEvent);
++
++  grub_efi_status_t
++  (*map_pcr_to_mr_index) (struct grub_efi_cc_protocol *this,
++			  grub_efi_uint32_t PcrIndex,
++			  grub_efi_cc_mr_index_t *MrIndex);
++};
++typedef struct grub_efi_cc_protocol grub_efi_cc_protocol_t;
++
++#endif
diff --git a/SOURCES/0278-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch b/SOURCES/0278-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch
deleted file mode 100644
index 8b5075b..0000000
--- a/SOURCES/0278-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 22 Mar 2022 10:57:20 -0400
-Subject: [PATCH] nx: set the nx compatible flag in EFI grub images
-
-For NX, we need the grub binary to announce that it is compatible with
-the NX feature.  This implies that when loading the executable grub
-image, several attributes are true:
-
-- the binary doesn't need an executable stack
-- the binary doesn't need sections to be both executable and writable
-- the binary knows how to use the EFI Memory Attributes protocol on code
-  it is loading.
-
-This patch adds a definition for the PE DLL Characteristics flag
-GRUB_PE32_NX_COMPAT, and changes grub-mkimage to set that flag.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit 0c7f1aed5a87f75051b421903a900ccb4bbd795a)
----
- util/mkimage.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/util/mkimage.c b/util/mkimage.c
-index 8319e8dfbd..c3d33aaac8 100644
---- a/util/mkimage.c
-+++ b/util/mkimage.c
-@@ -1418,6 +1418,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
- 	    section = (struct grub_pe32_section_table *)(o64 + 1);
- 	  }
- 
-+	PE_OHDR (o32, o64, dll_characteristics) = grub_host_to_target16 (GRUB_PE32_NX_COMPAT);
- 	PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size);
- 	PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address);
- 	PE_OHDR (o32, o64, image_base) = 0;
diff --git a/SOURCES/0279-Make-debug-file-show-which-file-filters-get-run.patch b/SOURCES/0279-Make-debug-file-show-which-file-filters-get-run.patch
deleted file mode 100644
index 475b3b4..0000000
--- a/SOURCES/0279-Make-debug-file-show-which-file-filters-get-run.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Fri, 29 Jul 2022 15:56:00 -0400
-Subject: [PATCH] Make debug=file show which file filters get run.
-
-If one of the file filters breaks things, it's hard to figure out where
-it has happened.
-
-This makes grub log which filter is being run, which makes it easier to
-figure out where you are in the sequence of events.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit d3d6518a13b5440a3be6c66b0ae47447182f2891)
----
- grub-core/kern/file.c | 11 +++++++++++
- 1 file changed, 11 insertions(+)
-
-diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
-index ed69fc0f0f..3f175630ea 100644
---- a/grub-core/kern/file.c
-+++ b/grub-core/kern/file.c
-@@ -30,6 +30,14 @@ void (*EXPORT_VAR (grub_grubnet_fini)) (void);
- 
- grub_file_filter_t grub_file_filters[GRUB_FILE_FILTER_MAX];
- 
-+static char *filter_names[] = {
-+    [GRUB_FILE_FILTER_VERIFY] = "GRUB_FILE_FILTER_VERIFY",
-+    [GRUB_FILE_FILTER_GZIO] = "GRUB_FILE_FILTER_GZIO",
-+    [GRUB_FILE_FILTER_XZIO] = "GRUB_FILE_FILTER_XZIO",
-+    [GRUB_FILE_FILTER_LZOPIO] = "GRUB_FILE_FILTER_LZOPIO",
-+    [GRUB_FILE_FILTER_MAX] = "GRUB_FILE_FILTER_MAX"
-+};
-+
- /* Get the device part of the filename NAME. It is enclosed by parentheses.  */
- char *
- grub_file_get_device_name (const char *name)
-@@ -121,6 +129,9 @@ grub_file_open (const char *name, enum grub_file_type type)
-     if (grub_file_filters[filter])
-       {
- 	last_file = file;
-+	if (filter < GRUB_FILE_FILTER_MAX)
-+	  grub_dprintf ("file", "Running %s file filter\n",
-+			filter_names[filter]);
- 	file = grub_file_filters[filter] (file, type);
- 	if (file && file != last_file)
- 	  {
diff --git a/SOURCES/0279-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch b/SOURCES/0279-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch
new file mode 100644
index 0000000..e0dd347
--- /dev/null
+++ b/SOURCES/0279-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch
@@ -0,0 +1,31 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Wed, 3 Aug 2022 19:45:33 +0800
+Subject: [PATCH] font: Reject glyphs exceeds font->max_glyph_width or
+ font->max_glyph_height
+
+Check glyph's width and height against limits specified in font's
+metadata. Reject the glyph (and font) if such limits are exceeded.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 5760fcfd466cc757540ea0d591bad6a08caeaa16)
+---
+ grub-core/font/font.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index d09bb38d89..2f09a4a55b 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -760,7 +760,9 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
+ 	  || read_be_uint16 (font->file, &height) != 0
+ 	  || read_be_int16 (font->file, &xoff) != 0
+ 	  || read_be_int16 (font->file, &yoff) != 0
+-	  || read_be_int16 (font->file, &dwidth) != 0)
++	  || read_be_int16 (font->file, &dwidth) != 0
++	  || width > font->max_char_width
++	  || height > font->max_char_height)
+ 	{
+ 	  remove_font (font);
+ 	  return 0;
diff --git a/SOURCES/0280-efi-make-the-default-arena-most-of-ram.patch b/SOURCES/0280-efi-make-the-default-arena-most-of-ram.patch
deleted file mode 100644
index 6821cde..0000000
--- a/SOURCES/0280-efi-make-the-default-arena-most-of-ram.patch
+++ /dev/null
@@ -1,74 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Fri, 29 Jul 2022 15:57:57 -0400
-Subject: [PATCH] efi: make the default arena most of ram
-
-Currently when populating the initial memory arena on EFI systems, we
-count the available regions below GRUB_EFI_MAX_ALLOCATION_ADDRESS from
-the EFI memory map and then allocates one quarter of that for our arena.
-
-Because many systems come up without IOMMUs, we currently set
-GRUB_EFI_MAX_ALLOCATION_ADDRESS to 0x7fffffff, i.e. all addresses
-allocated must be below 2G[0].  Due to firmware and other
-considerations, this makes the most memory we can possibly have in our
-arena 512M.
-
-Because our EFI loader doesn't get kernel and initrd memory from grub's
-allocator, but rather reserves it directly from UEFI and then simply
-marks those as allocated if they're within grub's arena, it was
-historically possible to have initrds that are larger than 512M, because
-we could use any memory region below 4G, without concern for grub's
-choice of arena size.
-
-Unfortunately, when we switched to using the "verifiers" API (and thus
-the file_filter_t API) to do measurement of kernel and initrd, this
-introduced a pattern that allocates the entire file when we call
-grub_file_open(), and buffers it to pass to the filter.  This results in
-needing to have enough space for the initramfs in the grub arena.
-
-This is bad.
-
-Since it's unlikely you're going to do anything *other* than loading a
-kernel and initramfs that takes much of the available free memory from
-UEFI, this patch introduces a workaround by changing the amount we give
-to the arena be three quarters of the available memory, rather than one
-quarter, thus changing our theoretical initrd limit to 1.5G.  In
-practice, it may still be smaller than that depending on allocation
-fragmentation, but generally it will be most of it.
-
-Note that this doesn't fix the underlying flaw, which is that there is
-no safe way to do the validation correctly using the "verifiers" system
-with the current file API without buffering the whole file before
-grub_file_read() is ever called, and thus you can't set an allocation
-policy for the initial buffer of the file at all, so unless we raise the
-allocation limit to >4G, it can't be allocated in the big region.
-
-[0] I'm not sure there was a good reason not to pick 4G, but even if we
-    had, at least one common firmware routes the first 2G of physical
-    RAM to 0x0, and any additional memory starting at 0x100000000.
-
-Related: rhbz#2112134
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit 005a0aaaad2a00a1fa1e60d94cc4fd5407c22e7d)
----
- grub-core/kern/efi/mm.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
-index 88364d764c..0288eab361 100644
---- a/grub-core/kern/efi/mm.c
-+++ b/grub-core/kern/efi/mm.c
-@@ -738,10 +738,10 @@ grub_efi_mm_init (void)
-   filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map,
- 					       desc_size, memory_map_end);
- 
--  /* By default, request a quarter of the available memory.  */
-+  /* By default, request three quarters of the available memory.  */
-   total_pages = get_total_pages (filtered_memory_map, desc_size,
- 				 filtered_memory_map_end);
--  required_pages = (total_pages >> 2);
-+  required_pages = (total_pages >> 1) + (total_pages >> 2);
-   if (required_pages < BYTES_TO_PAGES (MIN_HEAP_SIZE))
-     required_pages = BYTES_TO_PAGES (MIN_HEAP_SIZE);
-   else if (required_pages > BYTES_TO_PAGES (MAX_HEAP_SIZE))
diff --git a/SOURCES/0280-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch b/SOURCES/0280-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch
new file mode 100644
index 0000000..b5f10f6
--- /dev/null
+++ b/SOURCES/0280-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch
@@ -0,0 +1,110 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Fri, 5 Aug 2022 00:51:20 +0800
+Subject: [PATCH] font: Fix size overflow in grub_font_get_glyph_internal()
+
+The length of memory allocation and file read may overflow. This patch
+fixes the problem by using safemath macros.
+
+There is a lot of code repetition like "(x * y + 7) / 8". It is unsafe
+if overflow happens. This patch introduces grub_video_bitmap_calc_1bpp_bufsz().
+It is safe replacement for such code. It has safemath-like prototype.
+
+This patch also introduces grub_cast(value, pointer), it casts value to
+typeof(*pointer) then store the value to *pointer. It returns true when
+overflow occurs or false if there is no overflow. The semantics of arguments
+and return value are designed to be consistent with other safemath macros.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 941d10ad6f1dcbd12fb613002249e29ba035f985)
+---
+ grub-core/font/font.c   | 17 +++++++++++++----
+ include/grub/bitmap.h   | 18 ++++++++++++++++++
+ include/grub/safemath.h |  2 ++
+ 3 files changed, 33 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index 2f09a4a55b..6a3fbebbd8 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -739,7 +739,8 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
+       grub_int16_t xoff;
+       grub_int16_t yoff;
+       grub_int16_t dwidth;
+-      int len;
++      grub_ssize_t len;
++      grub_size_t sz;
+ 
+       if (index_entry->glyph)
+ 	/* Return cached glyph.  */
+@@ -768,9 +769,17 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
+ 	  return 0;
+ 	}
+ 
+-      len = (width * height + 7) / 8;
+-      glyph = grub_malloc (sizeof (struct grub_font_glyph) + len);
+-      if (!glyph)
++      /* Calculate real struct size of current glyph. */
++      if (grub_video_bitmap_calc_1bpp_bufsz (width, height, &len) ||
++	  grub_add (sizeof (struct grub_font_glyph), len, &sz))
++	{
++	  remove_font (font);
++	  return 0;
++	}
++
++      /* Allocate and initialize the glyph struct. */
++      glyph = grub_malloc (sz);
++      if (glyph == NULL)
+ 	{
+ 	  remove_font (font);
+ 	  return 0;
+diff --git a/include/grub/bitmap.h b/include/grub/bitmap.h
+index 5728f8ca3a..0d9603f619 100644
+--- a/include/grub/bitmap.h
++++ b/include/grub/bitmap.h
+@@ -23,6 +23,7 @@
+ #include <grub/symbol.h>
+ #include <grub/types.h>
+ #include <grub/video.h>
++#include <grub/safemath.h>
+ 
+ struct grub_video_bitmap
+ {
+@@ -79,6 +80,23 @@ grub_video_bitmap_get_height (struct grub_video_bitmap *bitmap)
+   return bitmap->mode_info.height;
+ }
+ 
++/*
++ * Calculate and store the size of data buffer of 1bit bitmap in result.
++ * Equivalent to "*result = (width * height + 7) / 8" if no overflow occurs.
++ * Return true when overflow occurs or false if there is no overflow.
++ * This function is intentionally implemented as a macro instead of
++ * an inline function. Although a bit awkward, it preserves data types for
++ * safemath macros and reduces macro side effects as much as possible.
++ *
++ * XXX: Will report false overflow if width * height > UINT64_MAX.
++ */
++#define grub_video_bitmap_calc_1bpp_bufsz(width, height, result) \
++({ \
++  grub_uint64_t _bitmap_pixels; \
++  grub_mul ((width), (height), &_bitmap_pixels) ? 1 : \
++    grub_cast (_bitmap_pixels / GRUB_CHAR_BIT + !!(_bitmap_pixels % GRUB_CHAR_BIT), (result)); \
++})
++
+ void EXPORT_FUNC (grub_video_bitmap_get_mode_info) (struct grub_video_bitmap *bitmap,
+ 						    struct grub_video_mode_info *mode_info);
+ 
+diff --git a/include/grub/safemath.h b/include/grub/safemath.h
+index c17b89bba1..bb0f826de1 100644
+--- a/include/grub/safemath.h
++++ b/include/grub/safemath.h
+@@ -30,6 +30,8 @@
+ #define grub_sub(a, b, res)	__builtin_sub_overflow(a, b, res)
+ #define grub_mul(a, b, res)	__builtin_mul_overflow(a, b, res)
+ 
++#define grub_cast(a, res)	grub_add ((a), 0, (res))
++
+ #else
+ #error gcc 5.1 or newer or clang 3.8 or newer is required
+ #endif
diff --git a/SOURCES/0281-efi-use-enumerated-array-positions-for-our-allocatio.patch b/SOURCES/0281-efi-use-enumerated-array-positions-for-our-allocatio.patch
deleted file mode 100644
index de5671c..0000000
--- a/SOURCES/0281-efi-use-enumerated-array-positions-for-our-allocatio.patch
+++ /dev/null
@@ -1,82 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 1 Aug 2022 14:06:30 -0400
-Subject: [PATCH] efi: use enumerated array positions for our allocation
- choices
-
-In our kernel allocator on EFI systems, we currently have a growing
-amount of code that references the various allocation policies by
-position in the array, and of course maintenance of this code scales
-very poorly.
-
-This patch changes them to be enumerated, so they're easier to refer to
-farther along in the code without confusion.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit 6768026270cca015d7fef0ecc8a4119e9b3d3923)
----
- grub-core/loader/i386/efi/linux.c | 31 ++++++++++++++++++++-----------
- 1 file changed, 20 insertions(+), 11 deletions(-)
-
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index dc98077378..781a333162 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -61,17 +61,26 @@ struct allocation_choice {
-     grub_efi_allocate_type_t alloc_type;
- };
- 
--static struct allocation_choice max_addresses[4] =
-+enum {
-+    KERNEL_PREF_ADDRESS,
-+    KERNEL_4G_LIMIT,
-+    KERNEL_NO_LIMIT,
-+};
-+
-+static struct allocation_choice max_addresses[] =
-   {
-     /* the kernel overrides this one with pref_address and
-      * GRUB_EFI_ALLOCATE_ADDRESS */
--    { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-+    [KERNEL_PREF_ADDRESS] =
-+      { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-+    /* If the flag in params is set, this one gets changed to be above 4GB. */
-+    [KERNEL_4G_LIMIT] =
-+      { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-     /* this one is always below 4GB, which we still *prefer* even if the flag
-      * is set. */
--    { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
--    /* If the flag in params is set, this one gets changed to be above 4GB. */
--    { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
--    { 0, 0 }
-+    [KERNEL_NO_LIMIT] =
-+      { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-+    { NO_MEM, 0, 0 }
-   };
- static struct allocation_choice saved_addresses[4];
- 
-@@ -418,7 +427,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G)
-     {
-       grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n");
--      max_addresses[2].addr = GRUB_EFI_MAX_USABLE_ADDRESS;
-+      max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_USABLE_ADDRESS;
-     }
-   else
-     {
-@@ -491,11 +500,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address);
-   if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS)
-     {
--      max_addresses[0].addr = lh->pref_address;
--      max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS;
-+      max_addresses[KERNEL_PREF_ADDRESS].addr = lh->pref_address;
-+      max_addresses[KERNEL_PREF_ADDRESS].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS;
-     }
--  max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
--  max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
-+  max_addresses[KERNEL_4G_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
-+  max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
-   kernel_size = lh->init_size;
-   kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE,
- 			     N_("can't allocate kernel"));
diff --git a/SOURCES/0281-font-Fix-several-integer-overflows-in-grub_font_cons.patch b/SOURCES/0281-font-Fix-several-integer-overflows-in-grub_font_cons.patch
new file mode 100644
index 0000000..3c76eb4
--- /dev/null
+++ b/SOURCES/0281-font-Fix-several-integer-overflows-in-grub_font_cons.patch
@@ -0,0 +1,79 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Fri, 5 Aug 2022 01:58:27 +0800
+Subject: [PATCH] font: Fix several integer overflows in
+ grub_font_construct_glyph()
+
+This patch fixes several integer overflows in grub_font_construct_glyph().
+Glyphs of invalid size, zero or leading to an overflow, are rejected.
+The inconsistency between "glyph" and "max_glyph_size" when grub_malloc()
+returns NULL is fixed too.
+
+Fixes: CVE-2022-2601
+
+Reported-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit b1805f251b31a9d3cfae5c3572ddfa630145dbbf)
+---
+ grub-core/font/font.c | 29 +++++++++++++++++------------
+ 1 file changed, 17 insertions(+), 12 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index 6a3fbebbd8..1fa181d4ca 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -1517,6 +1517,7 @@ grub_font_construct_glyph (grub_font_t hinted_font,
+   struct grub_video_signed_rect bounds;
+   static struct grub_font_glyph *glyph = 0;
+   static grub_size_t max_glyph_size = 0;
++  grub_size_t cur_glyph_size;
+ 
+   ensure_comb_space (glyph_id);
+ 
+@@ -1533,29 +1534,33 @@ grub_font_construct_glyph (grub_font_t hinted_font,
+   if (!glyph_id->ncomb && !glyph_id->attributes)
+     return main_glyph;
+ 
+-  if (max_glyph_size < sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT)
++  if (grub_video_bitmap_calc_1bpp_bufsz (bounds.width, bounds.height, &cur_glyph_size) ||
++      grub_add (sizeof (*glyph), cur_glyph_size, &cur_glyph_size))
++    return main_glyph;
++
++  if (max_glyph_size < cur_glyph_size)
+     {
+       grub_free (glyph);
+-      max_glyph_size = (sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT) * 2;
+-      if (max_glyph_size < 8)
+-	max_glyph_size = 8;
+-      glyph = grub_malloc (max_glyph_size);
++      if (grub_mul (cur_glyph_size, 2, &max_glyph_size))
++	max_glyph_size = 0;
++      glyph = max_glyph_size > 0 ? grub_malloc (max_glyph_size) : NULL;
+     }
+   if (!glyph)
+     {
++      max_glyph_size = 0;
+       grub_errno = GRUB_ERR_NONE;
+       return main_glyph;
+     }
+ 
+-  grub_memset (glyph, 0, sizeof (*glyph)
+-	       + (bounds.width * bounds.height
+-		  + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT);
++  grub_memset (glyph, 0, cur_glyph_size);
+ 
+   glyph->font = main_glyph->font;
+-  glyph->width = bounds.width;
+-  glyph->height = bounds.height;
+-  glyph->offset_x = bounds.x;
+-  glyph->offset_y = bounds.y;
++  if (bounds.width == 0 || bounds.height == 0 ||
++      grub_cast (bounds.width, &glyph->width) ||
++      grub_cast (bounds.height, &glyph->height) ||
++      grub_cast (bounds.x, &glyph->offset_x) ||
++      grub_cast (bounds.y, &glyph->offset_y))
++    return main_glyph;
+ 
+   if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR)
+     grub_font_blit_glyph_mirror (glyph, main_glyph,
diff --git a/SOURCES/0282-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch b/SOURCES/0282-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch
deleted file mode 100644
index 4eccd77..0000000
--- a/SOURCES/0282-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch
+++ /dev/null
@@ -1,128 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 1 Aug 2022 14:24:39 -0400
-Subject: [PATCH] efi: split allocation policy for kernel vs initrd memories.
-
-Currently in our kernel allocator, we use the same set of choices for
-all of our various kernel and initramfs allocations, though they do not
-have exactly the same constraints.
-
-This patch adds the concept of an allocation purpose, which currently
-can be KERNEL_MEM or INITRD_MEM, and updates kernel_alloc() calls
-appropriately, but does not change any current policy decision.  It
-also adds a few debug prints.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit 36307bed28cd838116fc4af26a30719660d62d4c)
----
- grub-core/loader/i386/efi/linux.c | 35 +++++++++++++++++++++++++++--------
- 1 file changed, 27 insertions(+), 8 deletions(-)
-
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index 781a333162..b9cd443a9a 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -56,7 +56,14 @@ struct grub_linuxefi_context {
- 
- #define BYTES_TO_PAGES(bytes)   (((bytes) + 0xfff) >> 12)
- 
-+typedef enum {
-+    NO_MEM,
-+    KERNEL_MEM,
-+    INITRD_MEM,
-+} kernel_alloc_purpose_t;
-+
- struct allocation_choice {
-+    kernel_alloc_purpose_t purpose;
-     grub_efi_physical_address_t addr;
-     grub_efi_allocate_type_t alloc_type;
- };
-@@ -65,6 +72,7 @@ enum {
-     KERNEL_PREF_ADDRESS,
-     KERNEL_4G_LIMIT,
-     KERNEL_NO_LIMIT,
-+    INITRD_MAX_ADDRESS,
- };
- 
- static struct allocation_choice max_addresses[] =
-@@ -72,14 +80,17 @@ static struct allocation_choice max_addresses[] =
-     /* the kernel overrides this one with pref_address and
-      * GRUB_EFI_ALLOCATE_ADDRESS */
-     [KERNEL_PREF_ADDRESS] =
--      { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-+      { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-     /* If the flag in params is set, this one gets changed to be above 4GB. */
-     [KERNEL_4G_LIMIT] =
--      { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-+      { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-     /* this one is always below 4GB, which we still *prefer* even if the flag
-      * is set. */
-     [KERNEL_NO_LIMIT] =
--      { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-+      { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-+    /* this is for the initrd */
-+    [INITRD_MAX_ADDRESS] =
-+      { INITRD_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-     { NO_MEM, 0, 0 }
-   };
- static struct allocation_choice saved_addresses[4];
-@@ -96,7 +107,8 @@ kernel_free(void *addr, grub_efi_uintn_t size)
- }
- 
- static void *
--kernel_alloc(grub_efi_uintn_t size,
-+kernel_alloc(kernel_alloc_purpose_t purpose,
-+	     grub_efi_uintn_t size,
- 	     grub_efi_memory_type_t memtype,
- 	     const char * const errmsg)
- {
-@@ -109,6 +121,9 @@ kernel_alloc(grub_efi_uintn_t size,
-       grub_uint64_t max = max_addresses[i].addr;
-       grub_efi_uintn_t pages;
- 
-+      if (purpose != max_addresses[i].purpose)
-+	continue;
-+
-       /*
-        * When we're *not* loading the kernel, or >4GB allocations aren't
-        * supported, these entries are basically all the same, so don't re-try
-@@ -262,7 +277,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
- 	}
-     }
- 
--  initrd_mem = kernel_alloc(size, GRUB_EFI_RUNTIME_SERVICES_DATA,
-+  grub_dprintf ("linux", "Trying to allocate initrd mem\n");
-+  initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_RUNTIME_SERVICES_DATA,
- 			    N_("can't allocate initrd"));
-   if (initrd_mem == NULL)
-     goto fail;
-@@ -435,7 +451,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-     }
- #endif
- 
--  params = kernel_alloc (sizeof(*params), GRUB_EFI_RUNTIME_SERVICES_DATA,
-+  params = kernel_alloc (KERNEL_MEM, sizeof(*params),
-+			 GRUB_EFI_RUNTIME_SERVICES_DATA,
- 			 "cannot allocate kernel parameters");
-   if (!params)
-     goto fail;
-@@ -458,7 +475,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   grub_dprintf ("linux", "new lh is at %p\n", lh);
- 
-   grub_dprintf ("linux", "setting up cmdline\n");
--  cmdline = kernel_alloc (lh->cmdline_size + 1,
-+  cmdline = kernel_alloc (KERNEL_MEM, lh->cmdline_size + 1,
- 			  GRUB_EFI_RUNTIME_SERVICES_DATA,
- 			  N_("can't allocate cmdline"));
-   if (!cmdline)
-@@ -506,7 +523,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   max_addresses[KERNEL_4G_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
-   max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
-   kernel_size = lh->init_size;
--  kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE,
-+  grub_dprintf ("linux", "Trying to allocate kernel mem\n");
-+  kernel_mem = kernel_alloc (KERNEL_MEM, kernel_size,
-+			     GRUB_EFI_RUNTIME_SERVICES_CODE,
- 			     N_("can't allocate kernel"));
-   restore_addresses();
-   if (!kernel_mem)
diff --git a/SOURCES/0282-font-Remove-grub_font_dup_glyph.patch b/SOURCES/0282-font-Remove-grub_font_dup_glyph.patch
new file mode 100644
index 0000000..4c3db92
--- /dev/null
+++ b/SOURCES/0282-font-Remove-grub_font_dup_glyph.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Fri, 5 Aug 2022 02:13:29 +0800
+Subject: [PATCH] font: Remove grub_font_dup_glyph()
+
+Remove grub_font_dup_glyph() since nobody is using it since 2013, and
+I'm too lazy to fix the integer overflow problem in it.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 25ad31c19c331aaa2dbd9bd2b2e2655de5766a9d)
+---
+ grub-core/font/font.c | 14 --------------
+ 1 file changed, 14 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index 1fa181d4ca..a115a63b0c 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -1055,20 +1055,6 @@ grub_font_get_glyph_with_fallback (grub_font_t font, grub_uint32_t code)
+   return best_glyph;
+ }
+ 
+-#if 0
+-static struct grub_font_glyph *
+-grub_font_dup_glyph (struct grub_font_glyph *glyph)
+-{
+-  static struct grub_font_glyph *ret;
+-  ret = grub_malloc (sizeof (*ret) + (glyph->width * glyph->height + 7) / 8);
+-  if (!ret)
+-    return NULL;
+-  grub_memcpy (ret, glyph, sizeof (*ret)
+-	       + (glyph->width * glyph->height + 7) / 8);
+-  return ret;
+-}
+-#endif
+-
+ /* FIXME: suboptimal.  */
+ static void
+ grub_font_blit_glyph (struct grub_font_glyph *target,
diff --git a/SOURCES/0283-efi-allocate-the-initrd-within-the-bounds-expressed-.patch b/SOURCES/0283-efi-allocate-the-initrd-within-the-bounds-expressed-.patch
deleted file mode 100644
index a58a8b6..0000000
--- a/SOURCES/0283-efi-allocate-the-initrd-within-the-bounds-expressed-.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 1 Aug 2022 14:07:50 -0400
-Subject: [PATCH] efi: allocate the initrd within the bounds expressed by the
- kernel
-
-Currently on x86, only linux kernels built with CONFIG_RELOCATABLE for
-x86_64 can be loaded above 4G, but the maximum address for the initramfs
-is specified via a HdrS field.  This allows us to utilize that value,
-and unless loading the kernel above 4G, uses the value present there.
-If loading kernel above 4G is allowed, we assume loading the initramfs
-above 4G also works; in practice this has been true in the kernel code
-for quite some time.
-
-Resolves: rhbz#2112134
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit 3e08c35f316990913718a4457665e8f653ecaa52)
----
- grub-core/loader/i386/efi/linux.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index b9cd443a9a..801e663fee 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -191,6 +191,8 @@ grub_linuxefi_unload (void *data)
-   cmd_initrdefi->data = 0;
-   grub_free (context);
- 
-+  max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
-+
-   return GRUB_ERR_NONE;
- }
- 
-@@ -439,11 +441,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-     }
- #endif
- 
-+  max_addresses[INITRD_MAX_ADDRESS].addr = lh->initrd_addr_max;
- #if defined(__x86_64__)
-   if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G)
-     {
-       grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n");
-       max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_USABLE_ADDRESS;
-+      max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_USABLE_ADDRESS;
-     }
-   else
-     {
-@@ -573,6 +577,8 @@ fail:
- 
-   grub_dl_unref (my_mod);
- 
-+  max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
-+
-   if (lh)
-     kernel_free (cmdline, lh->cmdline_size + 1);
- 
diff --git a/SOURCES/0283-font-Fix-integer-overflow-in-ensure_comb_space.patch b/SOURCES/0283-font-Fix-integer-overflow-in-ensure_comb_space.patch
new file mode 100644
index 0000000..6b73038
--- /dev/null
+++ b/SOURCES/0283-font-Fix-integer-overflow-in-ensure_comb_space.patch
@@ -0,0 +1,46 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Fri, 5 Aug 2022 02:27:05 +0800
+Subject: [PATCH] font: Fix integer overflow in ensure_comb_space()
+
+In fact it can't overflow at all because glyph_id->ncomb is only 8-bit
+wide. But let's keep safe if somebody changes the width of glyph_id->ncomb
+in the future. This patch also fixes the inconsistency between
+render_max_comb_glyphs and render_combining_glyphs when grub_malloc()
+returns NULL.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit b2740b7e4a03bb8331d48b54b119afea76bb9d5f)
+---
+ grub-core/font/font.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index a115a63b0c..d0e6340404 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -1468,14 +1468,18 @@ ensure_comb_space (const struct grub_unicode_glyph *glyph_id)
+   if (glyph_id->ncomb <= render_max_comb_glyphs)
+     return;
+ 
+-  render_max_comb_glyphs = 2 * glyph_id->ncomb;
+-  if (render_max_comb_glyphs < 8)
++  if (grub_mul (glyph_id->ncomb, 2, &render_max_comb_glyphs))
++    render_max_comb_glyphs = 0;
++  if (render_max_comb_glyphs > 0 && render_max_comb_glyphs < 8)
+     render_max_comb_glyphs = 8;
+   grub_free (render_combining_glyphs);
+-  render_combining_glyphs = grub_malloc (render_max_comb_glyphs
+-					 * sizeof (render_combining_glyphs[0]));
++  render_combining_glyphs = (render_max_comb_glyphs > 0) ?
++    grub_calloc (render_max_comb_glyphs, sizeof (render_combining_glyphs[0])) : NULL;
+   if (!render_combining_glyphs)
+-    grub_errno = 0;
++    {
++      render_max_comb_glyphs = 0;
++      grub_errno = GRUB_ERR_NONE;
++    }
+ }
+ 
+ int
diff --git a/SOURCES/0284-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch b/SOURCES/0284-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch
deleted file mode 100644
index 5ae7c7e..0000000
--- a/SOURCES/0284-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Mon, 1 Aug 2022 13:04:43 -0400
-Subject: [PATCH] efi: use EFI_LOADER_(CODE|DATA) for kernel and initrd
- allocations
-
-At some point due to an erroneous kernel warning, we switched kernel and
-initramfs to being loaded in EFI_RUNTIME_SERVICES_CODE and
-EFI_RUNTIME_SERVICES_DATA memory pools.  This doesn't appear to be
-correct according to the spec, and that kernel warning has gone away.
-
-This patch puts them back in EFI_LOADER_CODE and EFI_LOADER_DATA
-allocations, respectively.
-
-Resolves: rhbz#2108456
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit 35b5d5fa47bc394c76022e6595b173e68f53225e)
----
- grub-core/loader/i386/efi/linux.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index 801e663fee..f23b3f7b01 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -280,7 +280,7 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
-     }
- 
-   grub_dprintf ("linux", "Trying to allocate initrd mem\n");
--  initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_RUNTIME_SERVICES_DATA,
-+  initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_LOADER_DATA,
- 			    N_("can't allocate initrd"));
-   if (initrd_mem == NULL)
-     goto fail;
-@@ -456,7 +456,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
- #endif
- 
-   params = kernel_alloc (KERNEL_MEM, sizeof(*params),
--			 GRUB_EFI_RUNTIME_SERVICES_DATA,
-+			 GRUB_EFI_LOADER_DATA,
- 			 "cannot allocate kernel parameters");
-   if (!params)
-     goto fail;
-@@ -480,7 +480,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
- 
-   grub_dprintf ("linux", "setting up cmdline\n");
-   cmdline = kernel_alloc (KERNEL_MEM, lh->cmdline_size + 1,
--			  GRUB_EFI_RUNTIME_SERVICES_DATA,
-+			  GRUB_EFI_LOADER_DATA,
- 			  N_("can't allocate cmdline"));
-   if (!cmdline)
-     goto fail;
-@@ -529,7 +529,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
-   kernel_size = lh->init_size;
-   grub_dprintf ("linux", "Trying to allocate kernel mem\n");
-   kernel_mem = kernel_alloc (KERNEL_MEM, kernel_size,
--			     GRUB_EFI_RUNTIME_SERVICES_CODE,
-+			     GRUB_EFI_LOADER_CODE,
- 			     N_("can't allocate kernel"));
-   restore_addresses();
-   if (!kernel_mem)
diff --git a/SOURCES/0284-font-Fix-integer-overflow-in-BMP-index.patch b/SOURCES/0284-font-Fix-integer-overflow-in-BMP-index.patch
new file mode 100644
index 0000000..5e10699
--- /dev/null
+++ b/SOURCES/0284-font-Fix-integer-overflow-in-BMP-index.patch
@@ -0,0 +1,63 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Mon, 15 Aug 2022 02:04:58 +0800
+Subject: [PATCH] font: Fix integer overflow in BMP index
+
+The BMP index (font->bmp_idx) is designed as a reverse lookup table of
+char entries (font->char_index), in order to speed up lookups for BMP
+chars (i.e. code < 0x10000). The values in BMP index are the subscripts
+of the corresponding char entries, stored in grub_uint16_t, while 0xffff
+means not found.
+
+This patch fixes the problem of large subscript truncated to grub_uint16_t,
+leading BMP index to return wrong char entry or report false miss. The
+code now checks for bounds and uses BMP index as a hint, and fallbacks
+to binary-search if necessary.
+
+On the occasion add a comment about BMP index is initialized to 0xffff.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit afda8b60ba0712abe01ae1e64c5f7a067a0e6492)
+---
+ grub-core/font/font.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index d0e6340404..b208a28717 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -300,6 +300,8 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct
+   font->bmp_idx = grub_malloc (0x10000 * sizeof (grub_uint16_t));
+   if (!font->bmp_idx)
+     return 1;
++
++  /* Init the BMP index array to 0xffff. */
+   grub_memset (font->bmp_idx, 0xff, 0x10000 * sizeof (grub_uint16_t));
+ 
+ 
+@@ -328,7 +330,7 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct
+ 	  return 1;
+ 	}
+ 
+-      if (entry->code < 0x10000)
++      if (entry->code < 0x10000 && i < 0xffff)
+ 	font->bmp_idx[entry->code] = i;
+ 
+       last_code = entry->code;
+@@ -696,9 +698,12 @@ find_glyph (const grub_font_t font, grub_uint32_t code)
+   /* Use BMP index if possible.  */
+   if (code < 0x10000 && font->bmp_idx)
+     {
+-      if (font->bmp_idx[code] == 0xffff)
+-	return 0;
+-      return &table[font->bmp_idx[code]];
++      if (font->bmp_idx[code] < 0xffff)
++	return &table[font->bmp_idx[code]];
++      /*
++       * When we are here then lookup in BMP index result in miss,
++       * fallthough to binary-search.
++       */
+     }
+ 
+   /* Do a binary search in `char_index', which is ordered by code point.  */
diff --git a/SOURCES/0285-BLS-create-etc-kernel-cmdline-during-mkconfig.patch b/SOURCES/0285-BLS-create-etc-kernel-cmdline-during-mkconfig.patch
deleted file mode 100644
index 8d7405e..0000000
--- a/SOURCES/0285-BLS-create-etc-kernel-cmdline-during-mkconfig.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Robbie Harwood <rharwood@redhat.com>
-Date: Tue, 2 Aug 2022 15:56:28 -0400
-Subject: [PATCH] BLS: create /etc/kernel/cmdline during mkconfig
-
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
-(cherry picked from commit 0837dcdf17ac0429bafa4dbf063b2a94385c04ca)
----
- util/grub.d/10_linux.in | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
-index 6ee0a2cf3d..ec529eb814 100644
---- a/util/grub.d/10_linux.in
-+++ b/util/grub.d/10_linux.in
-@@ -166,6 +166,12 @@ update_bls_cmdline()
-     local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
-     local -a files=($(get_sorted_bls))
- 
-+    if [[ ! -f /etc/kernel/cmdline ]]; then
-+	# anaconda has the correct information to do this during install;
-+	# afterward, grubby will take care of syncing on updates.
-+	echo "$cmdline rhgb quiet" > /etc/kernel/cmdline
-+    fi
-+
-     for bls in "${files[@]}"; do
-         local options="${cmdline}"
-         if [ -z "${bls##*debug*}" ]; then
diff --git a/SOURCES/0285-font-Fix-integer-underflow-in-binary-search-of-char-.patch b/SOURCES/0285-font-Fix-integer-underflow-in-binary-search-of-char-.patch
new file mode 100644
index 0000000..e81824b
--- /dev/null
+++ b/SOURCES/0285-font-Fix-integer-underflow-in-binary-search-of-char-.patch
@@ -0,0 +1,83 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Sun, 14 Aug 2022 18:09:38 +0800
+Subject: [PATCH] font: Fix integer underflow in binary search of char index
+
+If search target is less than all entries in font->index then "hi"
+variable is set to -1, which translates to SIZE_MAX and leads to errors.
+
+This patch fixes the problem by replacing the entire binary search code
+with the libstdc++'s std::lower_bound() implementation.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit c140a086838e7c9af87842036f891b8393a8c4bc)
+---
+ grub-core/font/font.c | 40 ++++++++++++++++++++++------------------
+ 1 file changed, 22 insertions(+), 18 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index b208a28717..193dfec045 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -688,12 +688,12 @@ read_be_int16 (grub_file_t file, grub_int16_t * value)
+ static inline struct char_index_entry *
+ find_glyph (const grub_font_t font, grub_uint32_t code)
+ {
+-  struct char_index_entry *table;
+-  grub_size_t lo;
+-  grub_size_t hi;
+-  grub_size_t mid;
++  struct char_index_entry *table, *first, *end;
++  grub_size_t len;
+ 
+   table = font->char_index;
++  if (table == NULL)
++    return NULL;
+ 
+   /* Use BMP index if possible.  */
+   if (code < 0x10000 && font->bmp_idx)
+@@ -706,25 +706,29 @@ find_glyph (const grub_font_t font, grub_uint32_t code)
+        */
+     }
+ 
+-  /* Do a binary search in `char_index', which is ordered by code point.  */
+-  lo = 0;
+-  hi = font->num_chars - 1;
++  /*
++   * Do a binary search in char_index which is ordered by code point.
++   * The code below is the same as libstdc++'s std::lower_bound().
++   */
++  first = table;
++  len = font->num_chars;
++  end = first + len;
+ 
+-  if (!table)
+-    return 0;
+-
+-  while (lo <= hi)
++  while (len > 0)
+     {
+-      mid = lo + (hi - lo) / 2;
+-      if (code < table[mid].code)
+-	hi = mid - 1;
+-      else if (code > table[mid].code)
+-	lo = mid + 1;
++      grub_size_t half = len >> 1;
++      struct char_index_entry *middle = first + half;
++
++      if (middle->code < code)
++	{
++	  first = middle + 1;
++	  len = len - half - 1;
++	}
+       else
+-	return &table[mid];
++	len = half;
+     }
+ 
+-  return 0;
++  return (first < end && first->code == code) ? first : NULL;
+ }
+ 
+ /* Get a glyph for the Unicode character CODE in FONT.  The glyph is loaded
diff --git a/SOURCES/0286-ieee1275-implement-vec5-for-cas-negotiation.patch b/SOURCES/0286-ieee1275-implement-vec5-for-cas-negotiation.patch
deleted file mode 100644
index f9f2170..0000000
--- a/SOURCES/0286-ieee1275-implement-vec5-for-cas-negotiation.patch
+++ /dev/null
@@ -1,71 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Diego Domingos <diegodo@linux.vnet.ibm.com>
-Date: Thu, 25 Aug 2022 11:37:56 -0400
-Subject: [PATCH] ieee1275: implement vec5 for cas negotiation
-
-As a legacy support, if the vector 5 is not implemented, Power
-Hypervisor will consider the max CPUs as 64 instead 256 currently
-supported during client-architecture-support negotiation.
-
-This patch implements the vector 5 and set the MAX CPUs to 256 while
-setting the others values to 0 (default).
-
-Signed-off-by: Diego Domingos <diegodo@linux.vnet.ibm.com>
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
-(cherry picked from commit f735c65b6da8a9d4251242b37774e1a517511253)
----
- grub-core/kern/ieee1275/init.c | 20 +++++++++++++++++++-
- 1 file changed, 19 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
-index ef55107467..6a51c9efab 100644
---- a/grub-core/kern/ieee1275/init.c
-+++ b/grub-core/kern/ieee1275/init.c
-@@ -311,6 +311,18 @@ struct option_vector2 {
-   grub_uint8_t max_pft_size;
- } __attribute__((packed));
- 
-+struct option_vector5 {
-+        grub_uint8_t byte1;
-+        grub_uint8_t byte2;
-+        grub_uint8_t byte3;
-+        grub_uint8_t cmo;
-+        grub_uint8_t associativity;
-+        grub_uint8_t bin_opts;
-+        grub_uint8_t micro_checkpoint;
-+        grub_uint8_t reserved0;
-+        grub_uint32_t max_cpus;
-+} __attribute__((packed));
-+
- struct pvr_entry {
-   grub_uint32_t mask;
-   grub_uint32_t entry;
-@@ -329,6 +341,8 @@ struct cas_vector {
-   grub_uint16_t vec3;
-   grub_uint8_t vec4_size;
-   grub_uint16_t vec4;
-+  grub_uint8_t vec5_size;
-+  struct option_vector5 vec5;
- } __attribute__((packed));
- 
- /* Call ibm,client-architecture-support to try to get more RMA.
-@@ -349,7 +363,7 @@ grub_ieee1275_ibm_cas (void)
-   } args;
-   struct cas_vector vector = {
-     .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */
--    .num_vecs = 4 - 1,
-+    .num_vecs = 5 - 1,
-     .vec1_size = 0,
-     .vec1 = 0x80, /* ignore */
-     .vec2_size = 1 + sizeof(struct option_vector2) - 2,
-@@ -360,6 +374,10 @@ grub_ieee1275_ibm_cas (void)
-     .vec3 = 0x00e0, // ask for FP + VMX + DFP but don't halt if unsatisfied
-     .vec4_size = 2 - 1,
-     .vec4 = 0x0001, // set required minimum capacity % to the lowest value
-+    .vec5_size = 1 + sizeof(struct option_vector5) - 2,
-+    .vec5 = {
-+	0, 0, 0, 0, 0, 0, 0, 0, 256
-+    }
-   };
- 
-   INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2);
diff --git a/SOURCES/0286-kern-efi-sb-Enforce-verification-of-font-files.patch b/SOURCES/0286-kern-efi-sb-Enforce-verification-of-font-files.patch
new file mode 100644
index 0000000..1a381b0
--- /dev/null
+++ b/SOURCES/0286-kern-efi-sb-Enforce-verification-of-font-files.patch
@@ -0,0 +1,52 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Sun, 14 Aug 2022 15:51:54 +0800
+Subject: [PATCH] kern/efi/sb: Enforce verification of font files
+
+As a mitigation and hardening measure enforce verification of font
+files. Then only trusted font files can be load. This will reduce the
+attack surface at cost of losing the ability of end-users to customize
+fonts if e.g. UEFI Secure Boot is enabled. Vendors can always customize
+fonts because they have ability to pack fonts into their GRUB bundles.
+
+This goal is achieved by:
+
+  * Removing GRUB_FILE_TYPE_FONT from shim lock verifier's
+    skip-verification list.
+
+  * Adding GRUB_FILE_TYPE_FONT to lockdown verifier's defer-auth list,
+    so font files must be verified by a verifier before they can be loaded.
+
+Suggested-by: Daniel Kiper <daniel.kiper@oracle.com>
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 630deb8c0d8b02b670ced4b7030414bcf17aa080)
+---
+ grub-core/kern/efi/sb.c   | 1 -
+ grub-core/kern/lockdown.c | 1 +
+ 2 files changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c
+index 89c4bb3fd1..db42c2539f 100644
+--- a/grub-core/kern/efi/sb.c
++++ b/grub-core/kern/efi/sb.c
+@@ -145,7 +145,6 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)),
+     case GRUB_FILE_TYPE_PRINT_BLOCKLIST:
+     case GRUB_FILE_TYPE_TESTLOAD:
+     case GRUB_FILE_TYPE_GET_SIZE:
+-    case GRUB_FILE_TYPE_FONT:
+     case GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY:
+     case GRUB_FILE_TYPE_CAT:
+     case GRUB_FILE_TYPE_HEXCAT:
+diff --git a/grub-core/kern/lockdown.c b/grub-core/kern/lockdown.c
+index 0bc70fd42d..af6d493cd3 100644
+--- a/grub-core/kern/lockdown.c
++++ b/grub-core/kern/lockdown.c
+@@ -51,6 +51,7 @@ lockdown_verifier_init (grub_file_t io __attribute__ ((unused)),
+     case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE:
+     case GRUB_FILE_TYPE_ACPI_TABLE:
+     case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE:
++    case GRUB_FILE_TYPE_FONT:
+       *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH;
+ 
+       /* Fall through. */
diff --git a/SOURCES/0287-fbutil-Fix-integer-overflow.patch b/SOURCES/0287-fbutil-Fix-integer-overflow.patch
new file mode 100644
index 0000000..4d32dbd
--- /dev/null
+++ b/SOURCES/0287-fbutil-Fix-integer-overflow.patch
@@ -0,0 +1,83 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Tue, 6 Sep 2022 03:03:21 +0800
+Subject: [PATCH] fbutil: Fix integer overflow
+
+Expressions like u64 = u32 * u32 are unsafe because their products are
+truncated to u32 even if left hand side is u64. This patch fixes all
+problems like that one in fbutil.
+
+To get right result not only left hand side have to be u64 but it's also
+necessary to cast at least one of the operands of all leaf operators of
+right hand side to u64, e.g. u64 = u32 * u32 + u32 * u32 should be
+u64 = (u64)u32 * u32 + (u64)u32 * u32.
+
+For 1-bit bitmaps grub_uint64_t have to be used. It's safe because any
+combination of values in (grub_uint64_t)u32 * u32 + u32 expression will
+not overflow grub_uint64_t.
+
+Other expressions like ptr + u32 * u32 + u32 * u32 are also vulnerable.
+They should be ptr + (grub_addr_t)u32 * u32 + (grub_addr_t)u32 * u32.
+
+This patch also adds a comment to grub_video_fb_get_video_ptr() which
+says it's arguments must be valid and no sanity check is performed
+(like its siblings in grub-core/video/fb/fbutil.c).
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 50a11a81bc842c58962244a2dc86bbd31a426e12)
+---
+ grub-core/video/fb/fbutil.c |  4 ++--
+ include/grub/fbutil.h       | 13 +++++++++----
+ 2 files changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/video/fb/fbutil.c b/grub-core/video/fb/fbutil.c
+index b98bb51fe8..25ef39f47d 100644
+--- a/grub-core/video/fb/fbutil.c
++++ b/grub-core/video/fb/fbutil.c
+@@ -67,7 +67,7 @@ get_pixel (struct grub_video_fbblit_info *source,
+     case 1:
+       if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED)
+         {
+-          int bit_index = y * source->mode_info->width + x;
++          grub_uint64_t bit_index = (grub_uint64_t) y * source->mode_info->width + x;
+           grub_uint8_t *ptr = source->data + bit_index / 8;
+           int bit_pos = 7 - bit_index % 8;
+           color = (*ptr >> bit_pos) & 0x01;
+@@ -138,7 +138,7 @@ set_pixel (struct grub_video_fbblit_info *source,
+     case 1:
+       if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED)
+         {
+-          int bit_index = y * source->mode_info->width + x;
++          grub_uint64_t bit_index = (grub_uint64_t) y * source->mode_info->width + x;
+           grub_uint8_t *ptr = source->data + bit_index / 8;
+           int bit_pos = 7 - bit_index % 8;
+           *ptr = (*ptr & ~(1 << bit_pos)) | ((color & 0x01) << bit_pos);
+diff --git a/include/grub/fbutil.h b/include/grub/fbutil.h
+index 4205eb917f..78a1ab3b45 100644
+--- a/include/grub/fbutil.h
++++ b/include/grub/fbutil.h
+@@ -31,14 +31,19 @@ struct grub_video_fbblit_info
+   grub_uint8_t *data;
+ };
+ 
+-/* Don't use for 1-bit bitmaps, addressing needs to be done at the bit level
+-   and it doesn't make sense, in general, to ask for a pointer
+-   to a particular pixel's data.  */
++/*
++ * Don't use for 1-bit bitmaps, addressing needs to be done at the bit level
++ * and it doesn't make sense, in general, to ask for a pointer
++ * to a particular pixel's data.
++ *
++ * This function assumes that bounds checking has been done in previous phase
++ * and they are opted out in here.
++ */
+ static inline void *
+ grub_video_fb_get_video_ptr (struct grub_video_fbblit_info *source,
+               unsigned int x, unsigned int y)
+ {
+-  return source->data + y * source->mode_info->pitch + x * source->mode_info->bytes_per_pixel;
++  return source->data + (grub_addr_t) y * source->mode_info->pitch + (grub_addr_t) x * source->mode_info->bytes_per_pixel;
+ }
+ 
+ /* Advance pointer by VAL bytes. If there is no unaligned access available,
diff --git a/SOURCES/0287-squish-don-t-dup-rhgb-quiet-check-mtimes.patch b/SOURCES/0287-squish-don-t-dup-rhgb-quiet-check-mtimes.patch
deleted file mode 100644
index 9498f71..0000000
--- a/SOURCES/0287-squish-don-t-dup-rhgb-quiet-check-mtimes.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Robbie Harwood <rharwood@redhat.com>
-Date: Wed, 17 Aug 2022 10:26:07 -0400
-Subject: [PATCH] squish: don't dup rhgb quiet, check mtimes
-
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
-(cherry picked from commit 275a0487c74e309cfd0a8c670740f6c34e729c45)
----
- util/grub.d/10_linux.in | 14 ++++++++++----
- 1 file changed, 10 insertions(+), 4 deletions(-)
-
-diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
-index ec529eb814..becf5ba9c6 100644
---- a/util/grub.d/10_linux.in
-+++ b/util/grub.d/10_linux.in
-@@ -166,10 +166,16 @@ update_bls_cmdline()
-     local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
-     local -a files=($(get_sorted_bls))
- 
--    if [[ ! -f /etc/kernel/cmdline ]]; then
--	# anaconda has the correct information to do this during install;
--	# afterward, grubby will take care of syncing on updates.
--	echo "$cmdline rhgb quiet" > /etc/kernel/cmdline
-+    if [[ ! -f /etc/kernel/cmdline ]] ||
-+	   [[ /etc/kernel/cmdline -ot /etc/default/grub ]]; then
-+	# anaconda has the correct information to create this during install;
-+	# afterward, grubby will take care of syncing on updates.  If the user
-+	# has modified /etc/default/grub, try to cope.
-+	if [[ ! "$cmdline" =~ "rhgb quiet" ]]; then
-+	    # ensure these only show up once
-+	    cmdline="$cmdline rhgb quiet"
-+	fi
-+	echo "$cmdline" > /etc/kernel/cmdline
-     fi
- 
-     for bls in "${files[@]}"; do
diff --git a/SOURCES/0288-font-Fix-an-integer-underflow-in-blit_comb.patch b/SOURCES/0288-font-Fix-an-integer-underflow-in-blit_comb.patch
new file mode 100644
index 0000000..72f4308
--- /dev/null
+++ b/SOURCES/0288-font-Fix-an-integer-underflow-in-blit_comb.patch
@@ -0,0 +1,89 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Mon, 24 Oct 2022 08:05:35 +0800
+Subject: [PATCH] font: Fix an integer underflow in blit_comb()
+
+The expression (ctx.bounds.height - combining_glyphs[i]->height) / 2 may
+evaluate to a very big invalid value even if both ctx.bounds.height and
+combining_glyphs[i]->height are small integers. For example, if
+ctx.bounds.height is 10 and combining_glyphs[i]->height is 12, this
+expression evaluates to 2147483647 (expected -1). This is because
+coordinates are allowed to be negative but ctx.bounds.height is an
+unsigned int. So, the subtraction operates on unsigned ints and
+underflows to a very big value. The division makes things even worse.
+The quotient is still an invalid value even if converted back to int.
+
+This patch fixes the problem by casting ctx.bounds.height to int. As
+a result the subtraction will operate on int and grub_uint16_t which
+will be promoted to an int. So, the underflow will no longer happen. Other
+uses of ctx.bounds.height (and ctx.bounds.width) are also casted to int,
+to ensure coordinates are always calculated on signed integers.
+
+Fixes: CVE-2022-3775
+
+Reported-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 6d2668dea3774ed74c4cd1eadd146f1b846bc3d4)
+---
+ grub-core/font/font.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index 193dfec045..12a5f0d08c 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -1203,12 +1203,12 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
+   ctx.bounds.height = main_glyph->height;
+ 
+   above_rightx = main_glyph->offset_x + main_glyph->width;
+-  above_righty = ctx.bounds.y + ctx.bounds.height;
++  above_righty = ctx.bounds.y + (int) ctx.bounds.height;
+ 
+   above_leftx = main_glyph->offset_x;
+-  above_lefty = ctx.bounds.y + ctx.bounds.height;
++  above_lefty = ctx.bounds.y + (int) ctx.bounds.height;
+ 
+-  below_rightx = ctx.bounds.x + ctx.bounds.width;
++  below_rightx = ctx.bounds.x + (int) ctx.bounds.width;
+   below_righty = ctx.bounds.y;
+ 
+   comb = grub_unicode_get_comb (glyph_id);
+@@ -1221,7 +1221,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
+ 
+       if (!combining_glyphs[i])
+ 	continue;
+-      targetx = (ctx.bounds.width - combining_glyphs[i]->width) / 2 + ctx.bounds.x;
++      targetx = ((int) ctx.bounds.width - combining_glyphs[i]->width) / 2 + ctx.bounds.x;
+       /* CGJ is to avoid diacritics reordering. */
+       if (comb[i].code
+ 	  == GRUB_UNICODE_COMBINING_GRAPHEME_JOINER)
+@@ -1231,8 +1231,8 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
+ 	case GRUB_UNICODE_COMB_OVERLAY:
+ 	  do_blit (combining_glyphs[i],
+ 		   targetx,
+-		   (ctx.bounds.height - combining_glyphs[i]->height) / 2
+-		   - (ctx.bounds.height + ctx.bounds.y), &ctx);
++		   ((int) ctx.bounds.height - combining_glyphs[i]->height) / 2
++		   - ((int) ctx.bounds.height + ctx.bounds.y), &ctx);
+ 	  if (min_devwidth < combining_glyphs[i]->width)
+ 	    min_devwidth = combining_glyphs[i]->width;
+ 	  break;
+@@ -1305,7 +1305,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
+ 	  /* Fallthrough.  */
+ 	case GRUB_UNICODE_STACK_ATTACHED_ABOVE:
+ 	  do_blit (combining_glyphs[i], targetx,
+-		   -(ctx.bounds.height + ctx.bounds.y + space
++		   -((int) ctx.bounds.height + ctx.bounds.y + space
+ 		     + combining_glyphs[i]->height), &ctx);
+ 	  if (min_devwidth < combining_glyphs[i]->width)
+ 	    min_devwidth = combining_glyphs[i]->width;
+@@ -1313,7 +1313,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
+ 
+ 	case GRUB_UNICODE_COMB_HEBREW_DAGESH:
+ 	  do_blit (combining_glyphs[i], targetx,
+-		   -(ctx.bounds.height / 2 + ctx.bounds.y
++		   -((int) ctx.bounds.height / 2 + ctx.bounds.y
+ 		     + combining_glyphs[i]->height / 2), &ctx);
+ 	  if (min_devwidth < combining_glyphs[i]->width)
+ 	    min_devwidth = combining_glyphs[i]->width;
diff --git a/SOURCES/0288-squish-give-up-on-rhgb-quiet.patch b/SOURCES/0288-squish-give-up-on-rhgb-quiet.patch
deleted file mode 100644
index 6e994ed..0000000
--- a/SOURCES/0288-squish-give-up-on-rhgb-quiet.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Robbie Harwood <rharwood@redhat.com>
-Date: Wed, 17 Aug 2022 11:30:30 -0400
-Subject: [PATCH] squish: give up on rhgb quiet
-
-Signed-off-by: Robbie Harwood <rharwood@redhat.com>
-(cherry picked from commit 12354f586f0748efc5c016b7d2053330f784ab4e)
----
- util/grub.d/10_linux.in | 4 ----
- 1 file changed, 4 deletions(-)
-
-diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
-index becf5ba9c6..5a7e5326da 100644
---- a/util/grub.d/10_linux.in
-+++ b/util/grub.d/10_linux.in
-@@ -171,10 +171,6 @@ update_bls_cmdline()
- 	# anaconda has the correct information to create this during install;
- 	# afterward, grubby will take care of syncing on updates.  If the user
- 	# has modified /etc/default/grub, try to cope.
--	if [[ ! "$cmdline" =~ "rhgb quiet" ]]; then
--	    # ensure these only show up once
--	    cmdline="$cmdline rhgb quiet"
--	fi
- 	echo "$cmdline" > /etc/kernel/cmdline
-     fi
- 
diff --git a/SOURCES/0289-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch b/SOURCES/0289-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch
new file mode 100644
index 0000000..5207c12
--- /dev/null
+++ b/SOURCES/0289-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch
@@ -0,0 +1,73 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Mon, 24 Oct 2022 07:15:41 +0800
+Subject: [PATCH] font: Harden grub_font_blit_glyph() and
+ grub_font_blit_glyph_mirror()
+
+As a mitigation and hardening measure add sanity checks to
+grub_font_blit_glyph() and grub_font_blit_glyph_mirror(). This patch
+makes these two functions do nothing if target blitting area isn't fully
+contained in target bitmap. Therefore, if complex calculations in caller
+overflows and malicious coordinates are given, we are still safe because
+any coordinates which result in out-of-bound-write are rejected. However,
+this patch only checks for invalid coordinates, and doesn't provide any
+protection against invalid source glyph or destination glyph, e.g.
+mismatch between glyph size and buffer size.
+
+This hardening measure is designed to mitigate possible overflows in
+blit_comb(). If overflow occurs, it may return invalid bounding box
+during dry run and call grub_font_blit_glyph() with malicious
+coordinates during actual blitting. However, we are still safe because
+the scratch glyph itself is valid, although its size makes no sense, and
+any invalid coordinates are rejected.
+
+It would be better to call grub_fatal() if illegal parameter is detected.
+However, doing this may end up in a dangerous recursion because grub_fatal()
+would print messages to the screen and we are in the progress of drawing
+characters on the screen.
+
+Reported-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit fcd7aa0c278f7cf3fb9f93f1a3966e1792339eb6)
+---
+ grub-core/font/font.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index 12a5f0d08c..29fbb94294 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -1069,8 +1069,15 @@ static void
+ grub_font_blit_glyph (struct grub_font_glyph *target,
+ 		      struct grub_font_glyph *src, unsigned dx, unsigned dy)
+ {
++  grub_uint16_t max_x, max_y;
+   unsigned src_bit, tgt_bit, src_byte, tgt_byte;
+   unsigned i, j;
++
++  /* Harden against out-of-bound writes. */
++  if ((grub_add (dx, src->width, &max_x) || max_x > target->width) ||
++      (grub_add (dy, src->height, &max_y) || max_y > target->height))
++    return;
++
+   for (i = 0; i < src->height; i++)
+     {
+       src_bit = (src->width * i) % 8;
+@@ -1102,9 +1109,16 @@ grub_font_blit_glyph_mirror (struct grub_font_glyph *target,
+ 			     struct grub_font_glyph *src,
+ 			     unsigned dx, unsigned dy)
+ {
++  grub_uint16_t max_x, max_y;
+   unsigned tgt_bit, src_byte, tgt_byte;
+   signed src_bit;
+   unsigned i, j;
++
++  /* Harden against out-of-bound writes. */
++  if ((grub_add (dx, src->width, &max_x) || max_x > target->width) ||
++      (grub_add (dy, src->height, &max_y) || max_y > target->height))
++    return;
++
+   for (i = 0; i < src->height; i++)
+     {
+       src_bit = (src->width * i + src->width - 1) % 8;
diff --git a/SOURCES/0289-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch b/SOURCES/0289-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch
deleted file mode 100644
index e1e6a87..0000000
--- a/SOURCES/0289-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Jonathan Lebon <jonathan@jlebon.com>
-Date: Wed, 17 Aug 2022 10:26:03 -0400
-Subject: [PATCH] squish: BLS: only write /etc/kernel/cmdline if writable
-
-On OSTree systems, `grub2-mkconfig` is run with `/etc` mounted read-only
-because as part of the promise of transactional updates, we want to make
-sure that we're not modifying the current deployment's state (`/etc` or
-`/var`).
-
-This conflicts with 0837dcdf1 ("BLS: create /etc/kernel/cmdline during
-mkconfig") which wants to write to `/etc/kernel/cmdline`. I'm not
-exactly sure on the background there, but based on the comment I think
-the intent is to fulfill grubby's expectation that the file exists.
-
-However, in systems like Silverblue, kernel arguments are managed by the
-rpm-ostree stack and grubby is not shipped at all.
-
-Adjust the script slightly so that we only write `/etc/kernel/cmdline`
-if the parent directory is writable.
-
-In the future, we're hoping to simplify things further on rpm-ostree
-systems by not running `grub2-mkconfig` at all since libostree already
-directly writes BLS entries. Doing that would also have avoided this,
-but ratcheting it into existing systems needs more careful thought.
-
-Signed-off-by: Jonathan Lebon <jonathan@jlebon.com>
-
-Fixes: https://github.com/fedora-silverblue/issue-tracker/issues/322
-(cherry picked from commit 3c3d1a3c4a2dc4adfb38c2724618fefc913a63fc)
----
- util/grub.d/10_linux.in | 13 +++++++------
- 1 file changed, 7 insertions(+), 6 deletions(-)
-
-diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
-index 5a7e5326da..b1b9255c32 100644
---- a/util/grub.d/10_linux.in
-+++ b/util/grub.d/10_linux.in
-@@ -166,12 +166,13 @@ update_bls_cmdline()
-     local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
-     local -a files=($(get_sorted_bls))
- 
--    if [[ ! -f /etc/kernel/cmdline ]] ||
--	   [[ /etc/kernel/cmdline -ot /etc/default/grub ]]; then
--	# anaconda has the correct information to create this during install;
--	# afterward, grubby will take care of syncing on updates.  If the user
--	# has modified /etc/default/grub, try to cope.
--	echo "$cmdline" > /etc/kernel/cmdline
-+    if [ -w /etc/kernel ] &&
-+           [[ ! -f /etc/kernel/cmdline ||
-+                  /etc/kernel/cmdline -ot /etc/default/grub ]]; then
-+        # anaconda has the correct information to create this during install;
-+        # afterward, grubby will take care of syncing on updates.  If the user
-+        # has modified /etc/default/grub, try to cope.
-+        echo "$cmdline" > /etc/kernel/cmdline
-     fi
- 
-     for bls in "${files[@]}"; do
diff --git a/SOURCES/0290-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch b/SOURCES/0290-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch
new file mode 100644
index 0000000..c2bcc18
--- /dev/null
+++ b/SOURCES/0290-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch
@@ -0,0 +1,34 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Fri, 28 Oct 2022 17:29:16 +0800
+Subject: [PATCH] font: Assign null_font to glyphs in ascii_font_glyph[]
+
+The calculations in blit_comb() need information from glyph's font, e.g.
+grub_font_get_xheight(main_glyph->font). However, main_glyph->font is
+NULL if main_glyph comes from ascii_font_glyph[]. Therefore
+grub_font_get_*() crashes because of NULL pointer.
+
+There is already a solution, the null_font. So, assign it to those glyphs
+in ascii_font_glyph[].
+
+Reported-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit dd539d695482069d28b40f2d3821f710cdcf6ee6)
+---
+ grub-core/font/font.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index 29fbb94294..e6616e610c 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -137,7 +137,7 @@ ascii_glyph_lookup (grub_uint32_t code)
+ 	  ascii_font_glyph[current]->offset_x = 0;
+ 	  ascii_font_glyph[current]->offset_y = -2;
+ 	  ascii_font_glyph[current]->device_width = 8;
+-	  ascii_font_glyph[current]->font = NULL;
++	  ascii_font_glyph[current]->font = &null_font;
+ 
+ 	  grub_memcpy (ascii_font_glyph[current]->bitmap,
+ 		       &ascii_bitmaps[current * ASCII_BITMAP_SIZE],
diff --git a/SOURCES/0290-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch b/SOURCES/0290-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch
deleted file mode 100644
index 12c3525..0000000
--- a/SOURCES/0290-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Peter Jones <pjones@redhat.com>
-Date: Tue, 11 Oct 2022 17:00:50 -0400
-Subject: [PATCH] x86-efi: Fix an incorrect array size in kernel allocation
-
-In 81a6ebf62bbe166ddc968463df2e8bd481bf697c ("efi: split allocation
-policy for kernel vs initrd memories."), I introduced a split in the
-kernel allocator to allow for different dynamic policies for the kernel
-and the initrd allocations.
-
-Unfortunately, that change increased the size of the policy data used to
-make decisions, but did not change the size of the temporary storage we
-use to back it up and restore.  This results in some of .data getting
-clobbered at runtime, and hilarity ensues.
-
-This patch makes the size of the backup storage be based on the size of
-the initial policy data.
-
-Signed-off-by: Peter Jones <pjones@redhat.com>
-(cherry picked from commit 37747b22342499a798ca3a8895770cd93b6e1258)
----
- grub-core/loader/i386/efi/linux.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
-index f23b3f7b01..18aadc3e07 100644
---- a/grub-core/loader/i386/efi/linux.c
-+++ b/grub-core/loader/i386/efi/linux.c
-@@ -93,7 +93,7 @@ static struct allocation_choice max_addresses[] =
-       { INITRD_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS },
-     { NO_MEM, 0, 0 }
-   };
--static struct allocation_choice saved_addresses[4];
-+static struct allocation_choice saved_addresses[sizeof(max_addresses) / sizeof(max_addresses[0])];
- 
- #define save_addresses() grub_memcpy(saved_addresses, max_addresses, sizeof(max_addresses))
- #define restore_addresses() grub_memcpy(max_addresses, saved_addresses, sizeof(max_addresses))
diff --git a/SOURCES/0291-commands-efi-tpm-Refine-the-status-of-log-event.patch b/SOURCES/0291-commands-efi-tpm-Refine-the-status-of-log-event.patch
deleted file mode 100644
index 12315fd..0000000
--- a/SOURCES/0291-commands-efi-tpm-Refine-the-status-of-log-event.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Lu Ken <ken.lu@intel.com>
-Date: Wed, 13 Jul 2022 10:06:10 +0800
-Subject: [PATCH] commands/efi/tpm: Refine the status of log event
-
-1. Use macro GRUB_ERR_NONE instead of hard code 0.
-2. Keep lowercase of the first char for the status string of log event.
-
-Signed-off-by: Lu Ken <ken.lu@intel.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 922898573e37135f5dedc16f3e15a1d1d4c53f8a)
-(cherry picked from commit a326f1247c4d3a1d1079eacbe7e58b35b9a287e2)
----
- grub-core/commands/efi/tpm.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c
-index a97d85368a..7acf510499 100644
---- a/grub-core/commands/efi/tpm.c
-+++ b/grub-core/commands/efi/tpm.c
-@@ -135,17 +135,17 @@ grub_efi_log_event_status (grub_efi_status_t status)
-   switch (status)
-     {
-     case GRUB_EFI_SUCCESS:
--      return 0;
-+      return GRUB_ERR_NONE;
-     case GRUB_EFI_DEVICE_ERROR:
--      return grub_error (GRUB_ERR_IO, N_("Command failed"));
-+      return grub_error (GRUB_ERR_IO, N_("command failed"));
-     case GRUB_EFI_INVALID_PARAMETER:
--      return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter"));
-+      return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid parameter"));
-     case GRUB_EFI_BUFFER_TOO_SMALL:
--      return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small"));
-+      return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("output buffer too small"));
-     case GRUB_EFI_NOT_FOUND:
-       return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable"));
-     default:
--      return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error"));
-+      return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("unknown TPM error"));
-     }
- }
- 
diff --git a/SOURCES/0291-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch b/SOURCES/0291-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch
new file mode 100644
index 0000000..ec2184f
--- /dev/null
+++ b/SOURCES/0291-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch
@@ -0,0 +1,53 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Fri, 28 Oct 2022 21:31:39 +0800
+Subject: [PATCH] normal/charset: Fix an integer overflow in
+ grub_unicode_aglomerate_comb()
+
+The out->ncomb is a bit-field of 8 bits. So, the max possible value is 255.
+However, code in grub_unicode_aglomerate_comb() doesn't check for an
+overflow when incrementing out->ncomb. If out->ncomb is already 255,
+after incrementing it will get 0 instead of 256, and cause illegal
+memory access in subsequent processing.
+
+This patch introduces GRUB_UNICODE_NCOMB_MAX to represent the max
+acceptable value of ncomb. The code now checks for this limit and
+ignores additional combining characters when limit is reached.
+
+Reported-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit da90d62316a3b105d2fbd7334d6521936bd6dcf6)
+---
+ grub-core/normal/charset.c | 3 +++
+ include/grub/unicode.h     | 2 ++
+ 2 files changed, 5 insertions(+)
+
+diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c
+index 7a5a7c153c..c243ca6dae 100644
+--- a/grub-core/normal/charset.c
++++ b/grub-core/normal/charset.c
+@@ -472,6 +472,9 @@ grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen,
+ 	  if (!haveout)
+ 	    continue;
+ 
++	  if (out->ncomb == GRUB_UNICODE_NCOMB_MAX)
++	    continue;
++
+ 	  if (comb_type == GRUB_UNICODE_COMB_MC
+ 	      || comb_type == GRUB_UNICODE_COMB_ME
+ 	      || comb_type == GRUB_UNICODE_COMB_MN)
+diff --git a/include/grub/unicode.h b/include/grub/unicode.h
+index 4de986a857..c4f6fca043 100644
+--- a/include/grub/unicode.h
++++ b/include/grub/unicode.h
+@@ -147,7 +147,9 @@ struct grub_unicode_glyph
+   grub_uint8_t bidi_level:6; /* minimum: 6 */
+   enum grub_bidi_type bidi_type:5; /* minimum: :5 */
+ 
++#define GRUB_UNICODE_NCOMB_MAX ((1 << 8) - 1)
+   unsigned ncomb:8;
++
+   /* Hint by unicode subsystem how wide this character usually is.
+      Real width is determined by font. Set only in UTF-8 stream.  */
+   int estimated_width:8;
diff --git a/SOURCES/0292-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch b/SOURCES/0292-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch
deleted file mode 100644
index 3e8d899..0000000
--- a/SOURCES/0292-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Lu Ken <ken.lu@intel.com>
-Date: Wed, 13 Jul 2022 10:06:11 +0800
-Subject: [PATCH] commands/efi/tpm: Use grub_strcpy() instead of grub_memcpy()
-
-The event description is a string, so using grub_strcpy() is cleaner than
-using grub_memcpy().
-
-Signed-off-by: Lu Ken <ken.lu@intel.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit ef8679b645a63eb9eb191bb9539d7d25a9d6ff3b)
-(cherry picked from commit 6d0d478585c435cce50d4025d2301dc0413bc5c0)
----
- grub-core/commands/efi/tpm.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c
-index 7acf510499..bb59599721 100644
---- a/grub-core/commands/efi/tpm.c
-+++ b/grub-core/commands/efi/tpm.c
-@@ -175,7 +175,7 @@ grub_tpm1_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf,
-   event->PCRIndex = pcr;
-   event->EventType = EV_IPL;
-   event->EventSize = grub_strlen (description) + 1;
--  grub_memcpy (event->Event, description, event->EventSize);
-+  grub_strcpy ((char *) event->Event, description);
- 
-   algorithm = TCG_ALG_SHA;
-   status = efi_call_7 (tpm->log_extend_event, tpm, (grub_addr_t) buf, (grub_uint64_t) size,
-@@ -212,7 +212,7 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf,
-   event->Header.EventType = EV_IPL;
-   event->Size =
-     sizeof (*event) - sizeof (event->Event) + grub_strlen (description) + 1;
--  grub_memcpy (event->Event, description, grub_strlen (description) + 1);
-+  grub_strcpy ((char *) event->Event, description);
- 
-   status = efi_call_5 (tpm->hash_log_extend_event, tpm, 0, (grub_addr_t) buf,
- 		       (grub_uint64_t) size, event);
diff --git a/SOURCES/0292-font-Try-opening-fonts-from-the-bundled-memdisk.patch b/SOURCES/0292-font-Try-opening-fonts-from-the-bundled-memdisk.patch
new file mode 100644
index 0000000..bad9d90
--- /dev/null
+++ b/SOURCES/0292-font-Try-opening-fonts-from-the-bundled-memdisk.patch
@@ -0,0 +1,78 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Chris Coulson <chris.coulson@canonical.com>
+Date: Wed, 16 Nov 2022 14:40:04 +0000
+Subject: [PATCH] font: Try opening fonts from the bundled memdisk
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+---
+ grub-core/font/font.c | 48 +++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 31 insertions(+), 17 deletions(-)
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index e6616e610c..e421d1ae6f 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -409,6 +409,27 @@ read_section_as_short (struct font_file_section *section,
+   return 0;
+ }
+ 
++static grub_file_t
++try_open_from_prefix (const char *prefix, const char *filename)
++{
++  grub_file_t file;
++  char *fullname, *ptr;
++
++  fullname = grub_malloc (grub_strlen (prefix) + grub_strlen (filename) + 1
++			  + sizeof ("/fonts/") + sizeof (".pf2"));
++  if (!fullname)
++    return 0;
++  ptr = grub_stpcpy (fullname, prefix);
++  ptr = grub_stpcpy (ptr, "/fonts/");
++  ptr = grub_stpcpy (ptr, filename);
++  ptr = grub_stpcpy (ptr, ".pf2");
++  *ptr = 0;
++
++  file = grub_buffile_open (fullname, GRUB_FILE_TYPE_FONT, 1024);
++  grub_free (fullname);
++  return file;
++}
++
+ /* Load a font and add it to the beginning of the global font list.
+    Returns 0 upon success, nonzero upon failure.  */
+ grub_font_t
+@@ -427,25 +448,18 @@ grub_font_load (const char *filename)
+     file = grub_buffile_open (filename, GRUB_FILE_TYPE_FONT, 1024);
+   else
+     {
+-      const char *prefix = grub_env_get ("prefix");
+-      char *fullname, *ptr;
+-      if (!prefix)
++      file = try_open_from_prefix ("(memdisk)", filename);
++      if (!file)
+ 	{
+-	  grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"),
+-		      "prefix");
+-	  goto fail;
++	  const char *prefix = grub_env_get ("prefix");
++	  if (!prefix)
++	    {
++	      grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"),
++			  "prefix");
++	      goto fail;
++	    }
++	  file = try_open_from_prefix (prefix, filename);
+ 	}
+-      fullname = grub_malloc (grub_strlen (prefix) + grub_strlen (filename) + 1
+-			      + sizeof ("/fonts/") + sizeof (".pf2"));
+-      if (!fullname)
+-	goto fail;
+-      ptr = grub_stpcpy (fullname, prefix);
+-      ptr = grub_stpcpy (ptr, "/fonts/");
+-      ptr = grub_stpcpy (ptr, filename);
+-      ptr = grub_stpcpy (ptr, ".pf2");
+-      *ptr = 0;
+-      file = grub_buffile_open (fullname, GRUB_FILE_TYPE_FONT, 1024);
+-      grub_free (fullname);
+     }
+   if (!file)
+     goto fail;
diff --git a/SOURCES/0293-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch b/SOURCES/0293-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch
deleted file mode 100644
index c8b703b..0000000
--- a/SOURCES/0293-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch
+++ /dev/null
@@ -1,259 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Lu Ken <ken.lu@intel.com>
-Date: Wed, 13 Jul 2022 10:06:12 +0800
-Subject: [PATCH] efi/tpm: Add EFI_CC_MEASUREMENT_PROTOCOL support
-
-The EFI_CC_MEASUREMENT_PROTOCOL abstracts the measurement for virtual firmware
-in confidential computing environment. It is similar to the EFI_TCG2_PROTOCOL.
-It was proposed by Intel and ARM and approved by UEFI organization.
-
-It is defined in Intel GHCI specification: https://cdrdv2.intel.com/v1/dl/getContent/726790 .
-The EDKII header file is available at https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/CcMeasurement.h .
-
-Signed-off-by: Lu Ken <ken.lu@intel.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 4c76565b6cb885b7e144dc27f3612066844e2d19)
-(cherry picked from commit cad2fc1ff659390a228efb474a72f7ed7ab21697)
----
- grub-core/commands/efi/tpm.c |  48 ++++++++++++++
- include/grub/efi/cc.h        | 151 +++++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 199 insertions(+)
- create mode 100644 include/grub/efi/cc.h
-
-diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c
-index bb59599721..ae09c1bf8b 100644
---- a/grub-core/commands/efi/tpm.c
-+++ b/grub-core/commands/efi/tpm.c
-@@ -22,6 +22,7 @@
- #include <grub/i18n.h>
- #include <grub/efi/api.h>
- #include <grub/efi/efi.h>
-+#include <grub/efi/cc.h>
- #include <grub/efi/tpm.h>
- #include <grub/mm.h>
- #include <grub/tpm.h>
-@@ -31,6 +32,7 @@ typedef TCG_PCR_EVENT grub_tpm_event_t;
- 
- static grub_efi_guid_t tpm_guid = EFI_TPM_GUID;
- static grub_efi_guid_t tpm2_guid = EFI_TPM2_GUID;
-+static grub_efi_guid_t cc_measurement_guid = GRUB_EFI_CC_MEASUREMENT_PROTOCOL_GUID;
- 
- static grub_efi_handle_t *grub_tpm_handle;
- static grub_uint8_t grub_tpm_version;
-@@ -221,6 +223,50 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf,
-   return grub_efi_log_event_status (status);
- }
- 
-+static void
-+grub_cc_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
-+		   const char *description)
-+{
-+  grub_efi_cc_event_t *event;
-+  grub_efi_status_t status;
-+  grub_efi_cc_protocol_t *cc;
-+  grub_efi_cc_mr_index_t mr;
-+
-+  cc = grub_efi_locate_protocol (&cc_measurement_guid, NULL);
-+  if (cc == NULL)
-+    return;
-+
-+  status = efi_call_3 (cc->map_pcr_to_mr_index, cc, pcr, &mr);
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      grub_efi_log_event_status (status);
-+      return;
-+    }
-+
-+  event = grub_zalloc (sizeof (grub_efi_cc_event_t) +
-+		       grub_strlen (description) + 1);
-+  if (event == NULL)
-+    {
-+      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate CC event buffer"));
-+      return;
-+    }
-+
-+  event->Header.HeaderSize = sizeof (grub_efi_cc_event_header_t);
-+  event->Header.HeaderVersion = GRUB_EFI_CC_EVENT_HEADER_VERSION;
-+  event->Header.MrIndex = mr;
-+  event->Header.EventType = EV_IPL;
-+  event->Size = sizeof (*event) + grub_strlen (description) + 1;
-+  grub_strcpy ((char *) event->Event, description);
-+
-+  status = efi_call_5 (cc->hash_log_extend_event, cc, 0,
-+		       (grub_efi_physical_address_t)(grub_addr_t) buf,
-+		       (grub_efi_uint64_t) size, event);
-+  grub_free (event);
-+
-+  if (status != GRUB_EFI_SUCCESS)
-+    grub_efi_log_event_status (status);
-+}
-+
- grub_err_t
- grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
- 		    const char *description)
-@@ -228,6 +274,8 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
-   grub_efi_handle_t tpm_handle;
-   grub_efi_uint8_t protocol_version;
- 
-+  grub_cc_log_event(buf, size, pcr, description);
-+
-   if (!grub_tpm_handle_find (&tpm_handle, &protocol_version))
-     return 0;
- 
-diff --git a/include/grub/efi/cc.h b/include/grub/efi/cc.h
-new file mode 100644
-index 0000000000..8960306890
---- /dev/null
-+++ b/include/grub/efi/cc.h
-@@ -0,0 +1,151 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2022  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/>.
-+ */
-+
-+#ifndef GRUB_EFI_CC_H
-+#define GRUB_EFI_CC_H 1
-+
-+#include <grub/efi/api.h>
-+#include <grub/efi/efi.h>
-+#include <grub/err.h>
-+
-+#define GRUB_EFI_CC_MEASUREMENT_PROTOCOL_GUID \
-+  { 0x96751a3d, 0x72f4, 0x41a6, \
-+    { 0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b } \
-+  };
-+
-+struct grub_efi_cc_version
-+{
-+  grub_efi_uint8_t Major;
-+  grub_efi_uint8_t Minor;
-+};
-+typedef struct grub_efi_cc_version grub_efi_cc_version_t;
-+
-+/* EFI_CC Type/SubType definition. */
-+#define GRUB_EFI_CC_TYPE_NONE	0
-+#define GRUB_EFI_CC_TYPE_SEV	1
-+#define GRUB_EFI_CC_TYPE_TDX	2
-+
-+struct grub_efi_cc_type
-+{
-+  grub_efi_uint8_t Type;
-+  grub_efi_uint8_t SubType;
-+};
-+typedef struct grub_efi_cc_type grub_efi_cc_type_t;
-+
-+typedef grub_efi_uint32_t grub_efi_cc_event_log_bitmap_t;
-+typedef grub_efi_uint32_t grub_efi_cc_event_log_format_t;
-+typedef grub_efi_uint32_t grub_efi_cc_event_algorithm_bitmap_t;
-+typedef grub_efi_uint32_t grub_efi_cc_mr_index_t;
-+
-+/* Intel TDX measure register index. */
-+#define GRUB_TDX_MR_INDEX_MRTD	0
-+#define GRUB_TDX_MR_INDEX_RTMR0	1
-+#define GRUB_TDX_MR_INDEX_RTMR1	2
-+#define GRUB_TDX_MR_INDEX_RTMR2	3
-+#define GRUB_TDX_MR_INDEX_RTMR3	4
-+
-+#define GRUB_EFI_CC_EVENT_LOG_FORMAT_TCG_2	0x00000002
-+#define GRUB_EFI_CC_BOOT_HASH_ALG_SHA384	0x00000004
-+#define GRUB_EFI_CC_EVENT_HEADER_VERSION	1
-+
-+struct grub_efi_cc_event_header
-+{
-+  /* Size of the event header itself (sizeof(EFI_TD_EVENT_HEADER)). */
-+  grub_efi_uint32_t      HeaderSize;
-+
-+  /*
-+   * Header version. For this version of this specification,
-+   * the value shall be 1.
-+   */
-+  grub_efi_uint16_t      HeaderVersion;
-+
-+  /* Index of the MR that shall be extended. */
-+  grub_efi_cc_mr_index_t MrIndex;
-+
-+  /* Type of the event that shall be extended (and optionally logged). */
-+  grub_efi_uint32_t      EventType;
-+} GRUB_PACKED;
-+typedef struct grub_efi_cc_event_header grub_efi_cc_event_header_t;
-+
-+struct grub_efi_cc_event
-+{
-+  /* Total size of the event including the Size component, the header and the Event data. */
-+  grub_efi_uint32_t          Size;
-+  grub_efi_cc_event_header_t Header;
-+  grub_efi_uint8_t           Event[0];
-+} GRUB_PACKED;
-+typedef struct grub_efi_cc_event grub_efi_cc_event_t;
-+
-+struct grub_efi_cc_boot_service_capability
-+{
-+  /* Allocated size of the structure. */
-+  grub_efi_uint8_t                     Size;
-+
-+  /*
-+   * Version of the grub_efi_cc_boot_service_capability_t structure itself.
-+   * For this version of the protocol, the Major version shall be set to 1
-+   * and the Minor version shall be set to 1.
-+   */
-+  grub_efi_cc_version_t                StructureVersion;
-+
-+  /*
-+   * Version of the EFI TD protocol.
-+   * For this version of the protocol, the Major version shall be set to 1
-+   * and the Minor version shall be set to 1.
-+   */
-+  grub_efi_cc_version_t                ProtocolVersion;
-+
-+  /* Supported hash algorithms. */
-+  grub_efi_cc_event_algorithm_bitmap_t HashAlgorithmBitmap;
-+
-+  /* Bitmap of supported event log formats. */
-+  grub_efi_cc_event_log_bitmap_t       SupportedEventLogs;
-+
-+  /* Indicates the CC type. */
-+  grub_efi_cc_type_t CcType;
-+};
-+typedef struct grub_efi_cc_boot_service_capability grub_efi_cc_boot_service_capability_t;
-+
-+struct grub_efi_cc_protocol
-+{
-+  grub_efi_status_t
-+  (*get_capability) (struct grub_efi_cc_protocol *this,
-+		     grub_efi_cc_boot_service_capability_t *ProtocolCapability);
-+
-+  grub_efi_status_t
-+  (*get_event_log) (struct grub_efi_cc_protocol *this,
-+		    grub_efi_cc_event_log_format_t EventLogFormat,
-+		    grub_efi_physical_address_t *EventLogLocation,
-+		    grub_efi_physical_address_t *EventLogLastEntry,
-+		    grub_efi_boolean_t *EventLogTruncated);
-+
-+  grub_efi_status_t
-+  (*hash_log_extend_event) (struct grub_efi_cc_protocol *this,
-+			    grub_efi_uint64_t Flags,
-+			    grub_efi_physical_address_t DataToHash,
-+			    grub_efi_uint64_t DataToHashLen,
-+			    grub_efi_cc_event_t *EfiCcEvent);
-+
-+  grub_efi_status_t
-+  (*map_pcr_to_mr_index) (struct grub_efi_cc_protocol *this,
-+			  grub_efi_uint32_t PcrIndex,
-+			  grub_efi_cc_mr_index_t *MrIndex);
-+};
-+typedef struct grub_efi_cc_protocol grub_efi_cc_protocol_t;
-+
-+#endif
diff --git a/SOURCES/0293-mm-Clarify-grub_real_malloc.patch b/SOURCES/0293-mm-Clarify-grub_real_malloc.patch
new file mode 100644
index 0000000..0a99c08
--- /dev/null
+++ b/SOURCES/0293-mm-Clarify-grub_real_malloc.patch
@@ -0,0 +1,183 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 25 Nov 2021 02:22:46 +1100
+Subject: [PATCH] mm: Clarify grub_real_malloc()
+
+When iterating through the singly linked list of free blocks,
+grub_real_malloc() uses p and q for the current and previous blocks
+respectively. This isn't super clear, so swap to using prev and cur.
+
+This makes another quirk more obvious. The comment at the top of
+grub_real_malloc() might lead you to believe that the function will
+allocate from *first if there is space in that block.
+
+It actually doesn't do that, and it can't do that with the current
+data structures. If we used up all of *first, we would need to change
+the ->next of the previous block to point to *first->next, but we
+can't do that because it's a singly linked list and we don't have
+access to *first's previous block.
+
+What grub_real_malloc() actually does is set *first to the initial
+previous block, and *first->next is the block we try to allocate
+from. That allows us to keep all the data structures consistent.
+
+Document that.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 246ad6a44c281bb13486ddea0a26bb661db73106)
+---
+ grub-core/kern/mm.c | 76 +++++++++++++++++++++++++++++------------------------
+ 1 file changed, 41 insertions(+), 35 deletions(-)
+
+diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
+index d8c8377578..fb20e93acf 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -178,13 +178,20 @@ grub_mm_init_region (void *addr, grub_size_t size)
+ }
+ 
+ /* Allocate the number of units N with the alignment ALIGN from the ring
+-   buffer starting from *FIRST.  ALIGN must be a power of two. Both N and
+-   ALIGN are in units of GRUB_MM_ALIGN.  Return a non-NULL if successful,
+-   otherwise return NULL.  */
++ * buffer given in *FIRST.  ALIGN must be a power of two. Both N and
++ * ALIGN are in units of GRUB_MM_ALIGN.  Return a non-NULL if successful,
++ * otherwise return NULL.
++ *
++ * Note: because in certain circumstances we need to adjust the ->next
++ * pointer of the previous block, we iterate over the singly linked
++ * list with the pair (prev, cur). *FIRST is our initial previous, and
++ * *FIRST->next is our initial current pointer. So we will actually
++ * allocate from *FIRST->next first and *FIRST itself last.
++ */
+ static void *
+ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
+ {
+-  grub_mm_header_t p, q;
++  grub_mm_header_t cur, prev;
+ 
+   /* When everything is allocated side effect is that *first will have alloc
+      magic marked, meaning that there is no room in this region.  */
+@@ -192,24 +199,24 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
+     return 0;
+ 
+   /* Try to search free slot for allocation in this memory region.  */
+-  for (q = *first, p = q->next; ; q = p, p = p->next)
++  for (prev = *first, cur = prev->next; ; prev = cur, cur = cur->next)
+     {
+       grub_off_t extra;
+ 
+-      extra = ((grub_addr_t) (p + 1) >> GRUB_MM_ALIGN_LOG2) & (align - 1);
++      extra = ((grub_addr_t) (cur + 1) >> GRUB_MM_ALIGN_LOG2) & (align - 1);
+       if (extra)
+ 	extra = align - extra;
+ 
+-      if (! p)
++      if (! cur)
+ 	grub_fatal ("null in the ring");
+ 
+-      if (p->magic != GRUB_MM_FREE_MAGIC)
+-	grub_fatal ("free magic is broken at %p: 0x%x", p, p->magic);
++      if (cur->magic != GRUB_MM_FREE_MAGIC)
++	grub_fatal ("free magic is broken at %p: 0x%x", cur, cur->magic);
+ 
+-      if (p->size >= n + extra)
++      if (cur->size >= n + extra)
+ 	{
+-	  extra += (p->size - extra - n) & (~(align - 1));
+-	  if (extra == 0 && p->size == n)
++	  extra += (cur->size - extra - n) & (~(align - 1));
++	  if (extra == 0 && cur->size == n)
+ 	    {
+ 	      /* There is no special alignment requirement and memory block
+ 	         is complete match.
+@@ -222,9 +229,9 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
+ 	         | alloc, size=n |          |
+ 	         +---------------+          v
+ 	       */
+-	      q->next = p->next;
++	      prev->next = cur->next;
+ 	    }
+-	  else if (align == 1 || p->size == n + extra)
++	  else if (align == 1 || cur->size == n + extra)
+ 	    {
+ 	      /* There might be alignment requirement, when taking it into
+ 	         account memory block fits in.
+@@ -241,23 +248,22 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
+ 	         | alloc, size=n |        |
+ 	         +---------------+        v
+ 	       */
+-
+-	      p->size -= n;
+-	      p += p->size;
++	      cur->size -= n;
++	      cur += cur->size;
+ 	    }
+ 	  else if (extra == 0)
+ 	    {
+ 	      grub_mm_header_t r;
+ 	      
+-	      r = p + extra + n;
++	      r = cur + extra + n;
+ 	      r->magic = GRUB_MM_FREE_MAGIC;
+-	      r->size = p->size - extra - n;
+-	      r->next = p->next;
+-	      q->next = r;
++	      r->size = cur->size - extra - n;
++	      r->next = cur->next;
++	      prev->next = r;
+ 
+-	      if (q == p)
++	      if (prev == cur)
+ 		{
+-		  q = r;
++		  prev = r;
+ 		  r->next = r;
+ 		}
+ 	    }
+@@ -284,32 +290,32 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
+ 	       */
+ 	      grub_mm_header_t r;
+ 
+-	      r = p + extra + n;
++	      r = cur + extra + n;
+ 	      r->magic = GRUB_MM_FREE_MAGIC;
+-	      r->size = p->size - extra - n;
+-	      r->next = p;
++	      r->size = cur->size - extra - n;
++	      r->next = cur;
+ 
+-	      p->size = extra;
+-	      q->next = r;
+-	      p += extra;
++	      cur->size = extra;
++	      prev->next = r;
++	      cur += extra;
+ 	    }
+ 
+-	  p->magic = GRUB_MM_ALLOC_MAGIC;
+-	  p->size = n;
++	  cur->magic = GRUB_MM_ALLOC_MAGIC;
++	  cur->size = n;
+ 
+ 	  /* Mark find as a start marker for next allocation to fasten it.
+ 	     This will have side effect of fragmenting memory as small
+ 	     pieces before this will be un-used.  */
+ 	  /* So do it only for chunks under 64K.  */
+ 	  if (n < (0x8000 >> GRUB_MM_ALIGN_LOG2)
+-	      || *first == p)
+-	    *first = q;
++	      || *first == cur)
++	    *first = prev;
+ 
+-	  return p + 1;
++	  return cur + 1;
+ 	}
+ 
+       /* Search was completed without result.  */
+-      if (p == *first)
++      if (cur == *first)
+ 	break;
+     }
+ 
diff --git a/SOURCES/0294-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch b/SOURCES/0294-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch
deleted file mode 100644
index e264b09..0000000
--- a/SOURCES/0294-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Zhang Boyang <zhangboyang.id@gmail.com>
-Date: Wed, 3 Aug 2022 19:45:33 +0800
-Subject: [PATCH] font: Reject glyphs exceeds font->max_glyph_width or
- font->max_glyph_height
-
-Check glyph's width and height against limits specified in font's
-metadata. Reject the glyph (and font) if such limits are exceeded.
-
-Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 5760fcfd466cc757540ea0d591bad6a08caeaa16)
-(cherry picked from commit 3b410ef4bb95e607cadeba2193fa90ae9bddb98d)
----
- grub-core/font/font.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/grub-core/font/font.c b/grub-core/font/font.c
-index d09bb38d89..2f09a4a55b 100644
---- a/grub-core/font/font.c
-+++ b/grub-core/font/font.c
-@@ -760,7 +760,9 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
- 	  || read_be_uint16 (font->file, &height) != 0
- 	  || read_be_int16 (font->file, &xoff) != 0
- 	  || read_be_int16 (font->file, &yoff) != 0
--	  || read_be_int16 (font->file, &dwidth) != 0)
-+	  || read_be_int16 (font->file, &dwidth) != 0
-+	  || width > font->max_char_width
-+	  || height > font->max_char_height)
- 	{
- 	  remove_font (font);
- 	  return 0;
diff --git a/SOURCES/0294-mm-grub_real_malloc-Make-small-allocs-comment-match-.patch b/SOURCES/0294-mm-grub_real_malloc-Make-small-allocs-comment-match-.patch
new file mode 100644
index 0000000..a5601c9
--- /dev/null
+++ b/SOURCES/0294-mm-grub_real_malloc-Make-small-allocs-comment-match-.patch
@@ -0,0 +1,32 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 25 Nov 2021 02:22:47 +1100
+Subject: [PATCH] mm: grub_real_malloc(): Make small allocs comment match code
+
+Small allocations move the region's *first pointer. The comment
+says that this happens for allocations under 64K. The code says
+it's for allocations under 32K. Commit 45bf8b3a7549 changed the
+code intentionally: make the comment match.
+
+Fixes: 45bf8b3a7549 (* grub-core/kern/mm.c (grub_real_malloc): Decrease cut-off of moving the)
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit a847895a8d000bdf27ad4d4326f883a0eed769ca)
+---
+ grub-core/kern/mm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
+index fb20e93acf..db7e0b2a5b 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -306,7 +306,7 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
+ 	  /* Mark find as a start marker for next allocation to fasten it.
+ 	     This will have side effect of fragmenting memory as small
+ 	     pieces before this will be un-used.  */
+-	  /* So do it only for chunks under 64K.  */
++	  /* So do it only for chunks under 32K.  */
+ 	  if (n < (0x8000 >> GRUB_MM_ALIGN_LOG2)
+ 	      || *first == cur)
+ 	    *first = prev;
diff --git a/SOURCES/0295-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch b/SOURCES/0295-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch
deleted file mode 100644
index 7ec23ab..0000000
--- a/SOURCES/0295-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch
+++ /dev/null
@@ -1,111 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Zhang Boyang <zhangboyang.id@gmail.com>
-Date: Fri, 5 Aug 2022 00:51:20 +0800
-Subject: [PATCH] font: Fix size overflow in grub_font_get_glyph_internal()
-
-The length of memory allocation and file read may overflow. This patch
-fixes the problem by using safemath macros.
-
-There is a lot of code repetition like "(x * y + 7) / 8". It is unsafe
-if overflow happens. This patch introduces grub_video_bitmap_calc_1bpp_bufsz().
-It is safe replacement for such code. It has safemath-like prototype.
-
-This patch also introduces grub_cast(value, pointer), it casts value to
-typeof(*pointer) then store the value to *pointer. It returns true when
-overflow occurs or false if there is no overflow. The semantics of arguments
-and return value are designed to be consistent with other safemath macros.
-
-Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 941d10ad6f1dcbd12fb613002249e29ba035f985)
-(cherry picked from commit 6bca9693878bdf61dd62b8c784862a48e75f569a)
----
- grub-core/font/font.c   | 17 +++++++++++++----
- include/grub/bitmap.h   | 18 ++++++++++++++++++
- include/grub/safemath.h |  2 ++
- 3 files changed, 33 insertions(+), 4 deletions(-)
-
-diff --git a/grub-core/font/font.c b/grub-core/font/font.c
-index 2f09a4a55b..6a3fbebbd8 100644
---- a/grub-core/font/font.c
-+++ b/grub-core/font/font.c
-@@ -739,7 +739,8 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
-       grub_int16_t xoff;
-       grub_int16_t yoff;
-       grub_int16_t dwidth;
--      int len;
-+      grub_ssize_t len;
-+      grub_size_t sz;
- 
-       if (index_entry->glyph)
- 	/* Return cached glyph.  */
-@@ -768,9 +769,17 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
- 	  return 0;
- 	}
- 
--      len = (width * height + 7) / 8;
--      glyph = grub_malloc (sizeof (struct grub_font_glyph) + len);
--      if (!glyph)
-+      /* Calculate real struct size of current glyph. */
-+      if (grub_video_bitmap_calc_1bpp_bufsz (width, height, &len) ||
-+	  grub_add (sizeof (struct grub_font_glyph), len, &sz))
-+	{
-+	  remove_font (font);
-+	  return 0;
-+	}
-+
-+      /* Allocate and initialize the glyph struct. */
-+      glyph = grub_malloc (sz);
-+      if (glyph == NULL)
- 	{
- 	  remove_font (font);
- 	  return 0;
-diff --git a/include/grub/bitmap.h b/include/grub/bitmap.h
-index 5728f8ca3a..0d9603f619 100644
---- a/include/grub/bitmap.h
-+++ b/include/grub/bitmap.h
-@@ -23,6 +23,7 @@
- #include <grub/symbol.h>
- #include <grub/types.h>
- #include <grub/video.h>
-+#include <grub/safemath.h>
- 
- struct grub_video_bitmap
- {
-@@ -79,6 +80,23 @@ grub_video_bitmap_get_height (struct grub_video_bitmap *bitmap)
-   return bitmap->mode_info.height;
- }
- 
-+/*
-+ * Calculate and store the size of data buffer of 1bit bitmap in result.
-+ * Equivalent to "*result = (width * height + 7) / 8" if no overflow occurs.
-+ * Return true when overflow occurs or false if there is no overflow.
-+ * This function is intentionally implemented as a macro instead of
-+ * an inline function. Although a bit awkward, it preserves data types for
-+ * safemath macros and reduces macro side effects as much as possible.
-+ *
-+ * XXX: Will report false overflow if width * height > UINT64_MAX.
-+ */
-+#define grub_video_bitmap_calc_1bpp_bufsz(width, height, result) \
-+({ \
-+  grub_uint64_t _bitmap_pixels; \
-+  grub_mul ((width), (height), &_bitmap_pixels) ? 1 : \
-+    grub_cast (_bitmap_pixels / GRUB_CHAR_BIT + !!(_bitmap_pixels % GRUB_CHAR_BIT), (result)); \
-+})
-+
- void EXPORT_FUNC (grub_video_bitmap_get_mode_info) (struct grub_video_bitmap *bitmap,
- 						    struct grub_video_mode_info *mode_info);
- 
-diff --git a/include/grub/safemath.h b/include/grub/safemath.h
-index c17b89bba1..bb0f826de1 100644
---- a/include/grub/safemath.h
-+++ b/include/grub/safemath.h
-@@ -30,6 +30,8 @@
- #define grub_sub(a, b, res)	__builtin_sub_overflow(a, b, res)
- #define grub_mul(a, b, res)	__builtin_mul_overflow(a, b, res)
- 
-+#define grub_cast(a, res)	grub_add ((a), 0, (res))
-+
- #else
- #error gcc 5.1 or newer or clang 3.8 or newer is required
- #endif
diff --git a/SOURCES/0295-mm-Document-grub_free.patch b/SOURCES/0295-mm-Document-grub_free.patch
new file mode 100644
index 0000000..6c9b7cc
--- /dev/null
+++ b/SOURCES/0295-mm-Document-grub_free.patch
@@ -0,0 +1,120 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 25 Nov 2021 02:22:48 +1100
+Subject: [PATCH] mm: Document grub_free()
+
+The grub_free() possesses a surprising number of quirks, and also
+uses single-letter variable names confusingly to iterate through
+the free list.
+
+Document what's going on.
+
+Use prev and cur to iterate over the free list.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 1f8d0b01738e49767d662d6426af3570a64565f0)
+---
+ grub-core/kern/mm.c | 63 ++++++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 41 insertions(+), 22 deletions(-)
+
+diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
+index db7e0b2a5b..0351171cf9 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -446,54 +446,73 @@ grub_free (void *ptr)
+     }
+   else
+     {
+-      grub_mm_header_t q, s;
++      grub_mm_header_t cur, prev;
+ 
+ #if 0
+-      q = r->first;
++      cur = r->first;
+       do
+ 	{
+ 	  grub_printf ("%s:%d: q=%p, q->size=0x%x, q->magic=0x%x\n",
+-		       GRUB_FILE, __LINE__, q, q->size, q->magic);
+-	  q = q->next;
++		       GRUB_FILE, __LINE__, cur, cur->size, cur->magic);
++	  cur = cur->next;
+ 	}
+-      while (q != r->first);
++      while (cur != r->first);
+ #endif
+-
+-      for (s = r->first, q = s->next; q <= p || q->next >= p; s = q, q = s->next)
++      /* Iterate over all blocks in the free ring.
++       *
++       * The free ring is arranged from high addresses to low
++       * addresses, modulo wraparound.
++       *
++       * We are looking for a block with a higher address than p or
++       * whose next address is lower than p.
++       */
++      for (prev = r->first, cur = prev->next; cur <= p || cur->next >= p;
++	   prev = cur, cur = prev->next)
+ 	{
+-	  if (q->magic != GRUB_MM_FREE_MAGIC)
+-	    grub_fatal ("free magic is broken at %p: 0x%x", q, q->magic);
++	  if (cur->magic != GRUB_MM_FREE_MAGIC)
++	    grub_fatal ("free magic is broken at %p: 0x%x", cur, cur->magic);
+ 
+-	  if (q <= q->next && (q > p || q->next < p))
++	  /* Deal with wrap-around */
++	  if (cur <= cur->next && (cur > p || cur->next < p))
+ 	    break;
+ 	}
+ 
++      /* mark p as free and insert it between cur and cur->next */
+       p->magic = GRUB_MM_FREE_MAGIC;
+-      p->next = q->next;
+-      q->next = p;
++      p->next = cur->next;
++      cur->next = p;
+ 
++      /*
++       * If the block we are freeing can be merged with the next
++       * free block, do that.
++       */
+       if (p->next + p->next->size == p)
+ 	{
+ 	  p->magic = 0;
+ 
+ 	  p->next->size += p->size;
+-	  q->next = p->next;
++	  cur->next = p->next;
+ 	  p = p->next;
+ 	}
+ 
+-      r->first = q;
++      r->first = cur;
+ 
+-      if (q == p + p->size)
++      /* Likewise if can be merged with the preceeding free block */
++      if (cur == p + p->size)
+ 	{
+-	  q->magic = 0;
+-	  p->size += q->size;
+-	  if (q == s)
+-	    s = p;
+-	  s->next = p;
+-	  q = s;
++	  cur->magic = 0;
++	  p->size += cur->size;
++	  if (cur == prev)
++	    prev = p;
++	  prev->next = p;
++	  cur = prev;
+ 	}
+ 
+-      r->first = q;
++      /*
++       * Set r->first such that the just free()d block is tried first.
++       * (An allocation is tried from *first->next, and cur->next == p.)
++       */
++      r->first = cur;
+     }
+ }
+ 
diff --git a/SOURCES/0296-font-Fix-several-integer-overflows-in-grub_font_cons.patch b/SOURCES/0296-font-Fix-several-integer-overflows-in-grub_font_cons.patch
deleted file mode 100644
index fcc1d3c..0000000
--- a/SOURCES/0296-font-Fix-several-integer-overflows-in-grub_font_cons.patch
+++ /dev/null
@@ -1,80 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Zhang Boyang <zhangboyang.id@gmail.com>
-Date: Fri, 5 Aug 2022 01:58:27 +0800
-Subject: [PATCH] font: Fix several integer overflows in
- grub_font_construct_glyph()
-
-This patch fixes several integer overflows in grub_font_construct_glyph().
-Glyphs of invalid size, zero or leading to an overflow, are rejected.
-The inconsistency between "glyph" and "max_glyph_size" when grub_malloc()
-returns NULL is fixed too.
-
-Fixes: CVE-2022-2601
-
-Reported-by: Zhang Boyang <zhangboyang.id@gmail.com>
-Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit b1805f251b31a9d3cfae5c3572ddfa630145dbbf)
-(cherry picked from commit b91eb9bd6c724339b7d7bb4765b9d36f1ee88b84)
----
- grub-core/font/font.c | 29 +++++++++++++++++------------
- 1 file changed, 17 insertions(+), 12 deletions(-)
-
-diff --git a/grub-core/font/font.c b/grub-core/font/font.c
-index 6a3fbebbd8..1fa181d4ca 100644
---- a/grub-core/font/font.c
-+++ b/grub-core/font/font.c
-@@ -1517,6 +1517,7 @@ grub_font_construct_glyph (grub_font_t hinted_font,
-   struct grub_video_signed_rect bounds;
-   static struct grub_font_glyph *glyph = 0;
-   static grub_size_t max_glyph_size = 0;
-+  grub_size_t cur_glyph_size;
- 
-   ensure_comb_space (glyph_id);
- 
-@@ -1533,29 +1534,33 @@ grub_font_construct_glyph (grub_font_t hinted_font,
-   if (!glyph_id->ncomb && !glyph_id->attributes)
-     return main_glyph;
- 
--  if (max_glyph_size < sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT)
-+  if (grub_video_bitmap_calc_1bpp_bufsz (bounds.width, bounds.height, &cur_glyph_size) ||
-+      grub_add (sizeof (*glyph), cur_glyph_size, &cur_glyph_size))
-+    return main_glyph;
-+
-+  if (max_glyph_size < cur_glyph_size)
-     {
-       grub_free (glyph);
--      max_glyph_size = (sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT) * 2;
--      if (max_glyph_size < 8)
--	max_glyph_size = 8;
--      glyph = grub_malloc (max_glyph_size);
-+      if (grub_mul (cur_glyph_size, 2, &max_glyph_size))
-+	max_glyph_size = 0;
-+      glyph = max_glyph_size > 0 ? grub_malloc (max_glyph_size) : NULL;
-     }
-   if (!glyph)
-     {
-+      max_glyph_size = 0;
-       grub_errno = GRUB_ERR_NONE;
-       return main_glyph;
-     }
- 
--  grub_memset (glyph, 0, sizeof (*glyph)
--	       + (bounds.width * bounds.height
--		  + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT);
-+  grub_memset (glyph, 0, cur_glyph_size);
- 
-   glyph->font = main_glyph->font;
--  glyph->width = bounds.width;
--  glyph->height = bounds.height;
--  glyph->offset_x = bounds.x;
--  glyph->offset_y = bounds.y;
-+  if (bounds.width == 0 || bounds.height == 0 ||
-+      grub_cast (bounds.width, &glyph->width) ||
-+      grub_cast (bounds.height, &glyph->height) ||
-+      grub_cast (bounds.x, &glyph->offset_x) ||
-+      grub_cast (bounds.y, &glyph->offset_y))
-+    return main_glyph;
- 
-   if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR)
-     grub_font_blit_glyph_mirror (glyph, main_glyph,
diff --git a/SOURCES/0296-mm-Document-grub_mm_init_region.patch b/SOURCES/0296-mm-Document-grub_mm_init_region.patch
new file mode 100644
index 0000000..0173f04
--- /dev/null
+++ b/SOURCES/0296-mm-Document-grub_mm_init_region.patch
@@ -0,0 +1,73 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 25 Nov 2021 02:22:49 +1100
+Subject: [PATCH] mm: Document grub_mm_init_region()
+
+The grub_mm_init_region() does some things that seem magical, especially
+around region merging. Make it a bit clearer.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 246d69b7ea619fc1e77dcc5960e37aea45a9808c)
+---
+ grub-core/kern/mm.c | 31 ++++++++++++++++++++++++++++++-
+ 1 file changed, 30 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
+index 0351171cf9..1cbf98c7ab 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -128,23 +128,52 @@ grub_mm_init_region (void *addr, grub_size_t size)
+   if (((grub_addr_t) addr + 0x1000) > ~(grub_addr_t) size)
+     size = ((grub_addr_t) -0x1000) - (grub_addr_t) addr;
+ 
++  /* Attempt to merge this region with every existing region */
+   for (p = &grub_mm_base, q = *p; q; p = &(q->next), q = *p)
++    /*
++     * Is the new region immediately below an existing region? That
++     * is, is the address of the memory we're adding now (addr) + size
++     * of the memory we're adding (size) + the bytes we couldn't use
++     * at the start of the region we're considering (q->pre_size)
++     * equal to the address of q? In other words, does the memory
++     * looks like this?
++     *
++     * addr                          q
++     *   |----size-----|-q->pre_size-|<q region>|
++     */
+     if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q)
+       {
++	/*
++	 * Yes, we can merge the memory starting at addr into the
++	 * existing region from below. Align up addr to GRUB_MM_ALIGN
++	 * so that our new region has proper alignment.
++	 */
+ 	r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN);
++	/* Copy the region data across */
+ 	*r = *q;
++	/* Consider all the new size as pre-size */
+ 	r->pre_size += size;
+-	
++
++	/*
++	 * If we have enough pre-size to create a block, create a
++	 * block with it. Mark it as allocated and pass it to
++	 * grub_free (), which will sort out getting it into the free
++	 * list.
++	 */
+ 	if (r->pre_size >> GRUB_MM_ALIGN_LOG2)
+ 	  {
+ 	    h = (grub_mm_header_t) (r + 1);
++	    /* block size is pre-size converted to cells */
+ 	    h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2);
+ 	    h->magic = GRUB_MM_ALLOC_MAGIC;
++	    /* region size grows by block size converted back to bytes */
+ 	    r->size += h->size << GRUB_MM_ALIGN_LOG2;
++	    /* adjust pre_size to be accurate */
+ 	    r->pre_size &= (GRUB_MM_ALIGN - 1);
+ 	    *p = r;
+ 	    grub_free (h + 1);
+ 	  }
++	/* Replace the old region with the new region */
+ 	*p = r;
+ 	return;
+       }
diff --git a/SOURCES/0297-font-Remove-grub_font_dup_glyph.patch b/SOURCES/0297-font-Remove-grub_font_dup_glyph.patch
deleted file mode 100644
index a3493f6..0000000
--- a/SOURCES/0297-font-Remove-grub_font_dup_glyph.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Zhang Boyang <zhangboyang.id@gmail.com>
-Date: Fri, 5 Aug 2022 02:13:29 +0800
-Subject: [PATCH] font: Remove grub_font_dup_glyph()
-
-Remove grub_font_dup_glyph() since nobody is using it since 2013, and
-I'm too lazy to fix the integer overflow problem in it.
-
-Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 25ad31c19c331aaa2dbd9bd2b2e2655de5766a9d)
-(cherry picked from commit ad950e1e033318bb50222ed268a6dcfb97389035)
----
- grub-core/font/font.c | 14 --------------
- 1 file changed, 14 deletions(-)
-
-diff --git a/grub-core/font/font.c b/grub-core/font/font.c
-index 1fa181d4ca..a115a63b0c 100644
---- a/grub-core/font/font.c
-+++ b/grub-core/font/font.c
-@@ -1055,20 +1055,6 @@ grub_font_get_glyph_with_fallback (grub_font_t font, grub_uint32_t code)
-   return best_glyph;
- }
- 
--#if 0
--static struct grub_font_glyph *
--grub_font_dup_glyph (struct grub_font_glyph *glyph)
--{
--  static struct grub_font_glyph *ret;
--  ret = grub_malloc (sizeof (*ret) + (glyph->width * glyph->height + 7) / 8);
--  if (!ret)
--    return NULL;
--  grub_memcpy (ret, glyph, sizeof (*ret)
--	       + (glyph->width * glyph->height + 7) / 8);
--  return ret;
--}
--#endif
--
- /* FIXME: suboptimal.  */
- static void
- grub_font_blit_glyph (struct grub_font_glyph *target,
diff --git a/SOURCES/0297-mm-Document-GRUB-internal-memory-management-structur.patch b/SOURCES/0297-mm-Document-GRUB-internal-memory-management-structur.patch
new file mode 100644
index 0000000..c793926
--- /dev/null
+++ b/SOURCES/0297-mm-Document-GRUB-internal-memory-management-structur.patch
@@ -0,0 +1,78 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 25 Nov 2021 02:22:45 +1100
+Subject: [PATCH] mm: Document GRUB internal memory management structures
+
+I spent more than a trivial quantity of time figuring out pre_size and
+whether a memory region's size contains the header cell or not.
+
+Document the meanings of all the properties. Hopefully now no-one else
+has to figure it out!
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit a6c5c52ccffd2674d43db25fb4baa9c528526aa0)
+---
+ include/grub/mm_private.h | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h
+index c2c4cb1511..203533cc3d 100644
+--- a/include/grub/mm_private.h
++++ b/include/grub/mm_private.h
+@@ -21,15 +21,27 @@
+ 
+ #include <grub/mm.h>
+ 
++/* For context, see kern/mm.c */
++
+ /* Magic words.  */
+ #define GRUB_MM_FREE_MAGIC	0x2d3c2808
+ #define GRUB_MM_ALLOC_MAGIC	0x6db08fa4
+ 
++/* A header describing a block of memory - either allocated or free */
+ typedef struct grub_mm_header
+ {
++  /*
++   * The 'next' free block in this region's circular free list.
++   * Only meaningful if the block is free.
++   */
+   struct grub_mm_header *next;
++  /* The block size, not in bytes but the number of cells of
++   * GRUB_MM_ALIGN bytes. Includes the header cell.
++   */
+   grub_size_t size;
++  /* either free or alloc magic, depending on the block type. */
+   grub_size_t magic;
++  /* pad to cell size: see the top of kern/mm.c. */
+ #if GRUB_CPU_SIZEOF_VOID_P == 4
+   char padding[4];
+ #elif GRUB_CPU_SIZEOF_VOID_P == 8
+@@ -48,11 +60,27 @@ typedef struct grub_mm_header
+ 
+ #define GRUB_MM_ALIGN	(1 << GRUB_MM_ALIGN_LOG2)
+ 
++/* A region from which we can make allocations. */
+ typedef struct grub_mm_region
+ {
++  /* The first free block in this region. */
+   struct grub_mm_header *first;
++
++  /*
++   * The next region in the linked list of regions. Regions are initially
++   * sorted in order of increasing size, but can grow, in which case the
++   * ordering may not be preserved.
++   */
+   struct grub_mm_region *next;
++
++  /*
++   * A grub_mm_region will always be aligned to cell size. The pre-size is
++   * the number of bytes we were given but had to skip in order to get that
++   * alignment.
++   */
+   grub_size_t pre_size;
++
++  /* How many bytes are in this region? (free and allocated) */
+   grub_size_t size;
+ }
+ *grub_mm_region_t;
diff --git a/SOURCES/0298-font-Fix-integer-overflow-in-ensure_comb_space.patch b/SOURCES/0298-font-Fix-integer-overflow-in-ensure_comb_space.patch
deleted file mode 100644
index af5eedb..0000000
--- a/SOURCES/0298-font-Fix-integer-overflow-in-ensure_comb_space.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Zhang Boyang <zhangboyang.id@gmail.com>
-Date: Fri, 5 Aug 2022 02:27:05 +0800
-Subject: [PATCH] font: Fix integer overflow in ensure_comb_space()
-
-In fact it can't overflow at all because glyph_id->ncomb is only 8-bit
-wide. But let's keep safe if somebody changes the width of glyph_id->ncomb
-in the future. This patch also fixes the inconsistency between
-render_max_comb_glyphs and render_combining_glyphs when grub_malloc()
-returns NULL.
-
-Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit b2740b7e4a03bb8331d48b54b119afea76bb9d5f)
-(cherry picked from commit f66ea1e60c347408e92b6695d5105c7e0f24d568)
----
- grub-core/font/font.c | 14 +++++++++-----
- 1 file changed, 9 insertions(+), 5 deletions(-)
-
-diff --git a/grub-core/font/font.c b/grub-core/font/font.c
-index a115a63b0c..d0e6340404 100644
---- a/grub-core/font/font.c
-+++ b/grub-core/font/font.c
-@@ -1468,14 +1468,18 @@ ensure_comb_space (const struct grub_unicode_glyph *glyph_id)
-   if (glyph_id->ncomb <= render_max_comb_glyphs)
-     return;
- 
--  render_max_comb_glyphs = 2 * glyph_id->ncomb;
--  if (render_max_comb_glyphs < 8)
-+  if (grub_mul (glyph_id->ncomb, 2, &render_max_comb_glyphs))
-+    render_max_comb_glyphs = 0;
-+  if (render_max_comb_glyphs > 0 && render_max_comb_glyphs < 8)
-     render_max_comb_glyphs = 8;
-   grub_free (render_combining_glyphs);
--  render_combining_glyphs = grub_malloc (render_max_comb_glyphs
--					 * sizeof (render_combining_glyphs[0]));
-+  render_combining_glyphs = (render_max_comb_glyphs > 0) ?
-+    grub_calloc (render_max_comb_glyphs, sizeof (render_combining_glyphs[0])) : NULL;
-   if (!render_combining_glyphs)
--    grub_errno = 0;
-+    {
-+      render_max_comb_glyphs = 0;
-+      grub_errno = GRUB_ERR_NONE;
-+    }
- }
- 
- int
diff --git a/SOURCES/0298-mm-Assert-that-we-preserve-header-vs-region-alignmen.patch b/SOURCES/0298-mm-Assert-that-we-preserve-header-vs-region-alignmen.patch
new file mode 100644
index 0000000..2893784
--- /dev/null
+++ b/SOURCES/0298-mm-Assert-that-we-preserve-header-vs-region-alignmen.patch
@@ -0,0 +1,56 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 21 Apr 2022 15:24:14 +1000
+Subject: [PATCH] mm: Assert that we preserve header vs region alignment
+
+grub_mm_region_init() does:
+
+  h = (grub_mm_header_t) (r + 1);
+
+where h is a grub_mm_header_t and r is a grub_mm_region_t.
+
+Cells are supposed to be GRUB_MM_ALIGN aligned, but while grub_mm_dump
+ensures this vs the region header, grub_mm_region_init() does not.
+
+It's better to be explicit than implicit here: rather than changing
+grub_mm_region_init() to ALIGN_UP(), require that the struct is
+explicitly a multiple of the header size.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+Tested-by: Patrick Steinhardt <ps@pks.im>
+(cherry picked from commit 1df8fe66c57087eb33bd6dc69f786ed124615aa7)
+---
+ include/grub/mm_private.h | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h
+index 203533cc3d..a688b92a83 100644
+--- a/include/grub/mm_private.h
++++ b/include/grub/mm_private.h
+@@ -20,6 +20,7 @@
+ #define GRUB_MM_PRIVATE_H	1
+ 
+ #include <grub/mm.h>
++#include <grub/misc.h>
+ 
+ /* For context, see kern/mm.c */
+ 
+@@ -89,4 +90,17 @@ typedef struct grub_mm_region
+ extern grub_mm_region_t EXPORT_VAR (grub_mm_base);
+ #endif
+ 
++static inline void
++grub_mm_size_sanity_check (void) {
++  /* Ensure we preserve alignment when doing h = (grub_mm_header_t) (r + 1). */
++  COMPILE_TIME_ASSERT ((sizeof (struct grub_mm_region) %
++		        sizeof (struct grub_mm_header)) == 0);
++
++  /*
++   * GRUB_MM_ALIGN is supposed to represent cell size, and a mm_header is
++   * supposed to be 1 cell.
++   */
++  COMPILE_TIME_ASSERT (sizeof (struct grub_mm_header) == GRUB_MM_ALIGN);
++}
++
+ #endif
diff --git a/SOURCES/0299-font-Fix-integer-overflow-in-BMP-index.patch b/SOURCES/0299-font-Fix-integer-overflow-in-BMP-index.patch
deleted file mode 100644
index bb22749..0000000
--- a/SOURCES/0299-font-Fix-integer-overflow-in-BMP-index.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Zhang Boyang <zhangboyang.id@gmail.com>
-Date: Mon, 15 Aug 2022 02:04:58 +0800
-Subject: [PATCH] font: Fix integer overflow in BMP index
-
-The BMP index (font->bmp_idx) is designed as a reverse lookup table of
-char entries (font->char_index), in order to speed up lookups for BMP
-chars (i.e. code < 0x10000). The values in BMP index are the subscripts
-of the corresponding char entries, stored in grub_uint16_t, while 0xffff
-means not found.
-
-This patch fixes the problem of large subscript truncated to grub_uint16_t,
-leading BMP index to return wrong char entry or report false miss. The
-code now checks for bounds and uses BMP index as a hint, and fallbacks
-to binary-search if necessary.
-
-On the occasion add a comment about BMP index is initialized to 0xffff.
-
-Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit afda8b60ba0712abe01ae1e64c5f7a067a0e6492)
-(cherry picked from commit 6d90568929e11739b56f09ebbce9185ca9c23519)
----
- grub-core/font/font.c | 13 +++++++++----
- 1 file changed, 9 insertions(+), 4 deletions(-)
-
-diff --git a/grub-core/font/font.c b/grub-core/font/font.c
-index d0e6340404..b208a28717 100644
---- a/grub-core/font/font.c
-+++ b/grub-core/font/font.c
-@@ -300,6 +300,8 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct
-   font->bmp_idx = grub_malloc (0x10000 * sizeof (grub_uint16_t));
-   if (!font->bmp_idx)
-     return 1;
-+
-+  /* Init the BMP index array to 0xffff. */
-   grub_memset (font->bmp_idx, 0xff, 0x10000 * sizeof (grub_uint16_t));
- 
- 
-@@ -328,7 +330,7 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct
- 	  return 1;
- 	}
- 
--      if (entry->code < 0x10000)
-+      if (entry->code < 0x10000 && i < 0xffff)
- 	font->bmp_idx[entry->code] = i;
- 
-       last_code = entry->code;
-@@ -696,9 +698,12 @@ find_glyph (const grub_font_t font, grub_uint32_t code)
-   /* Use BMP index if possible.  */
-   if (code < 0x10000 && font->bmp_idx)
-     {
--      if (font->bmp_idx[code] == 0xffff)
--	return 0;
--      return &table[font->bmp_idx[code]];
-+      if (font->bmp_idx[code] < 0xffff)
-+	return &table[font->bmp_idx[code]];
-+      /*
-+       * When we are here then lookup in BMP index result in miss,
-+       * fallthough to binary-search.
-+       */
-     }
- 
-   /* Do a binary search in `char_index', which is ordered by code point.  */
diff --git a/SOURCES/0299-mm-When-adding-a-region-merge-with-region-after-as-w.patch b/SOURCES/0299-mm-When-adding-a-region-merge-with-region-after-as-w.patch
new file mode 100644
index 0000000..52cfeee
--- /dev/null
+++ b/SOURCES/0299-mm-When-adding-a-region-merge-with-region-after-as-w.patch
@@ -0,0 +1,203 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 21 Apr 2022 15:24:15 +1000
+Subject: [PATCH] mm: When adding a region, merge with region after as well as
+ before
+
+On x86_64-efi (at least) regions seem to be added from top down. The mm
+code will merge a new region with an existing region that comes
+immediately before the new region. This allows larger allocations to be
+satisfied that would otherwise be the case.
+
+On powerpc-ieee1275, however, regions are added from bottom up. So if
+we add 3x 32MB regions, we can still only satisfy a 32MB allocation,
+rather than the 96MB allocation we might otherwise be able to satisfy.
+
+  * Define 'post_size' as being bytes lost to the end of an allocation
+    due to being given weird sizes from firmware that are not multiples
+    of GRUB_MM_ALIGN.
+
+  * Allow merging of regions immediately _after_ existing regions, not
+    just before. As with the other approach, we create an allocated
+    block to represent the new space and the pass it to grub_free() to
+    get the metadata right.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Tested-by: Stefan Berger <stefanb@linux.ibm.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+Tested-by: Patrick Steinhardt <ps@pks.im>
+(cherry picked from commit 052e6068be622ff53f1238b449c300dbd0a8abcd)
+---
+ grub-core/kern/mm.c       | 128 +++++++++++++++++++++++++++++-----------------
+ include/grub/mm_private.h |   9 ++++
+ 2 files changed, 91 insertions(+), 46 deletions(-)
+
+diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
+index 1cbf98c7ab..7be33e23bf 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -130,53 +130,88 @@ grub_mm_init_region (void *addr, grub_size_t size)
+ 
+   /* Attempt to merge this region with every existing region */
+   for (p = &grub_mm_base, q = *p; q; p = &(q->next), q = *p)
+-    /*
+-     * Is the new region immediately below an existing region? That
+-     * is, is the address of the memory we're adding now (addr) + size
+-     * of the memory we're adding (size) + the bytes we couldn't use
+-     * at the start of the region we're considering (q->pre_size)
+-     * equal to the address of q? In other words, does the memory
+-     * looks like this?
+-     *
+-     * addr                          q
+-     *   |----size-----|-q->pre_size-|<q region>|
+-     */
+-    if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q)
+-      {
+-	/*
+-	 * Yes, we can merge the memory starting at addr into the
+-	 * existing region from below. Align up addr to GRUB_MM_ALIGN
+-	 * so that our new region has proper alignment.
+-	 */
+-	r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN);
+-	/* Copy the region data across */
+-	*r = *q;
+-	/* Consider all the new size as pre-size */
+-	r->pre_size += size;
++    {
++      /*
++       * Is the new region immediately below an existing region? That
++       * is, is the address of the memory we're adding now (addr) + size
++       * of the memory we're adding (size) + the bytes we couldn't use
++       * at the start of the region we're considering (q->pre_size)
++       * equal to the address of q? In other words, does the memory
++       * looks like this?
++       *
++       * addr                          q
++       *   |----size-----|-q->pre_size-|<q region>|
++       */
++      if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q)
++        {
++          /*
++           * Yes, we can merge the memory starting at addr into the
++           * existing region from below. Align up addr to GRUB_MM_ALIGN
++           * so that our new region has proper alignment.
++           */
++          r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN);
++          /* Copy the region data across */
++          *r = *q;
++          /* Consider all the new size as pre-size */
++          r->pre_size += size;
+ 
+-	/*
+-	 * If we have enough pre-size to create a block, create a
+-	 * block with it. Mark it as allocated and pass it to
+-	 * grub_free (), which will sort out getting it into the free
+-	 * list.
+-	 */
+-	if (r->pre_size >> GRUB_MM_ALIGN_LOG2)
+-	  {
+-	    h = (grub_mm_header_t) (r + 1);
+-	    /* block size is pre-size converted to cells */
+-	    h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2);
+-	    h->magic = GRUB_MM_ALLOC_MAGIC;
+-	    /* region size grows by block size converted back to bytes */
+-	    r->size += h->size << GRUB_MM_ALIGN_LOG2;
+-	    /* adjust pre_size to be accurate */
+-	    r->pre_size &= (GRUB_MM_ALIGN - 1);
+-	    *p = r;
+-	    grub_free (h + 1);
+-	  }
+-	/* Replace the old region with the new region */
+-	*p = r;
+-	return;
+-      }
++          /*
++           * If we have enough pre-size to create a block, create a
++           * block with it. Mark it as allocated and pass it to
++           * grub_free (), which will sort out getting it into the free
++           * list.
++           */
++          if (r->pre_size >> GRUB_MM_ALIGN_LOG2)
++            {
++              h = (grub_mm_header_t) (r + 1);
++              /* block size is pre-size converted to cells */
++              h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2);
++              h->magic = GRUB_MM_ALLOC_MAGIC;
++              /* region size grows by block size converted back to bytes */
++              r->size += h->size << GRUB_MM_ALIGN_LOG2;
++              /* adjust pre_size to be accurate */
++              r->pre_size &= (GRUB_MM_ALIGN - 1);
++              *p = r;
++              grub_free (h + 1);
++            }
++          /* Replace the old region with the new region */
++          *p = r;
++          return;
++        }
++
++      /*
++       * Is the new region immediately above an existing region? That
++       * is:
++       *   q                       addr
++       *   |<q region>|-q->post_size-|----size-----|
++       */
++      if ((grub_uint8_t *) q + sizeof (*q) + q->size + q->post_size ==
++	  (grub_uint8_t *) addr)
++	{
++	  /*
++	   * Yes! Follow a similar pattern to above, but simpler.
++	   * Our header starts at address - post_size, which should align us
++	   * to a cell boundary.
++	   *
++	   * Cast to (void *) first to avoid the following build error:
++	   *   kern/mm.c: In function ‘grub_mm_init_region’:
++	   *   kern/mm.c:211:15: error: cast increases required alignment of target type [-Werror=cast-align]
++	   *     211 |           h = (grub_mm_header_t) ((grub_uint8_t *) addr - q->post_size);
++	   *         |               ^
++	   * It is safe to do that because proper alignment is enforced in grub_mm_size_sanity_check().
++	   */
++	  h = (grub_mm_header_t)(void *) ((grub_uint8_t *) addr - q->post_size);
++	  /* our size is the allocated size plus post_size, in cells */
++	  h->size = (size + q->post_size) >> GRUB_MM_ALIGN_LOG2;
++	  h->magic = GRUB_MM_ALLOC_MAGIC;
++	  /* region size grows by block size converted back to bytes */
++	  q->size += h->size << GRUB_MM_ALIGN_LOG2;
++	  /* adjust new post_size to be accurate */
++	  q->post_size = (q->post_size + size) & (GRUB_MM_ALIGN - 1);
++	  grub_free (h + 1);
++	  return;
++	}
++    }
+ 
+   /* Allocate a region from the head.  */
+   r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN);
+@@ -195,6 +230,7 @@ grub_mm_init_region (void *addr, grub_size_t size)
+   r->first = h;
+   r->pre_size = (grub_addr_t) r - (grub_addr_t) addr;
+   r->size = (h->size << GRUB_MM_ALIGN_LOG2);
++  r->post_size = size - r->size;
+ 
+   /* Find where to insert this region. Put a smaller one before bigger ones,
+      to prevent fragmentation.  */
+diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h
+index a688b92a83..96c2d816be 100644
+--- a/include/grub/mm_private.h
++++ b/include/grub/mm_private.h
+@@ -81,8 +81,17 @@ typedef struct grub_mm_region
+    */
+   grub_size_t pre_size;
+ 
++  /*
++   * Likewise, the post-size is the number of bytes we wasted at the end
++   * of the allocation because it wasn't a multiple of GRUB_MM_ALIGN
++   */
++  grub_size_t post_size;
++
+   /* How many bytes are in this region? (free and allocated) */
+   grub_size_t size;
++
++  /* pad to a multiple of cell size */
++  char padding[3 * GRUB_CPU_SIZEOF_VOID_P];
+ }
+ *grub_mm_region_t;
+ 
diff --git a/SOURCES/0300-font-Fix-integer-underflow-in-binary-search-of-char-.patch b/SOURCES/0300-font-Fix-integer-underflow-in-binary-search-of-char-.patch
deleted file mode 100644
index 5c25e09..0000000
--- a/SOURCES/0300-font-Fix-integer-underflow-in-binary-search-of-char-.patch
+++ /dev/null
@@ -1,84 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Zhang Boyang <zhangboyang.id@gmail.com>
-Date: Sun, 14 Aug 2022 18:09:38 +0800
-Subject: [PATCH] font: Fix integer underflow in binary search of char index
-
-If search target is less than all entries in font->index then "hi"
-variable is set to -1, which translates to SIZE_MAX and leads to errors.
-
-This patch fixes the problem by replacing the entire binary search code
-with the libstdc++'s std::lower_bound() implementation.
-
-Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit c140a086838e7c9af87842036f891b8393a8c4bc)
-(cherry picked from commit e110997335b1744464ea232d57a7d86e16ca8dee)
----
- grub-core/font/font.c | 40 ++++++++++++++++++++++------------------
- 1 file changed, 22 insertions(+), 18 deletions(-)
-
-diff --git a/grub-core/font/font.c b/grub-core/font/font.c
-index b208a28717..193dfec045 100644
---- a/grub-core/font/font.c
-+++ b/grub-core/font/font.c
-@@ -688,12 +688,12 @@ read_be_int16 (grub_file_t file, grub_int16_t * value)
- static inline struct char_index_entry *
- find_glyph (const grub_font_t font, grub_uint32_t code)
- {
--  struct char_index_entry *table;
--  grub_size_t lo;
--  grub_size_t hi;
--  grub_size_t mid;
-+  struct char_index_entry *table, *first, *end;
-+  grub_size_t len;
- 
-   table = font->char_index;
-+  if (table == NULL)
-+    return NULL;
- 
-   /* Use BMP index if possible.  */
-   if (code < 0x10000 && font->bmp_idx)
-@@ -706,25 +706,29 @@ find_glyph (const grub_font_t font, grub_uint32_t code)
-        */
-     }
- 
--  /* Do a binary search in `char_index', which is ordered by code point.  */
--  lo = 0;
--  hi = font->num_chars - 1;
-+  /*
-+   * Do a binary search in char_index which is ordered by code point.
-+   * The code below is the same as libstdc++'s std::lower_bound().
-+   */
-+  first = table;
-+  len = font->num_chars;
-+  end = first + len;
- 
--  if (!table)
--    return 0;
--
--  while (lo <= hi)
-+  while (len > 0)
-     {
--      mid = lo + (hi - lo) / 2;
--      if (code < table[mid].code)
--	hi = mid - 1;
--      else if (code > table[mid].code)
--	lo = mid + 1;
-+      grub_size_t half = len >> 1;
-+      struct char_index_entry *middle = first + half;
-+
-+      if (middle->code < code)
-+	{
-+	  first = middle + 1;
-+	  len = len - half - 1;
-+	}
-       else
--	return &table[mid];
-+	len = half;
-     }
- 
--  return 0;
-+  return (first < end && first->code == code) ? first : NULL;
- }
- 
- /* Get a glyph for the Unicode character CODE in FONT.  The glyph is loaded
diff --git a/SOURCES/0300-mm-Debug-support-for-region-operations.patch b/SOURCES/0300-mm-Debug-support-for-region-operations.patch
new file mode 100644
index 0000000..f434260
--- /dev/null
+++ b/SOURCES/0300-mm-Debug-support-for-region-operations.patch
@@ -0,0 +1,71 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Thu, 21 Apr 2022 15:24:16 +1000
+Subject: [PATCH] mm: Debug support for region operations
+
+This is handy for debugging. Enable with "set debug=regions".
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+Tested-by: Patrick Steinhardt <ps@pks.im>
+(cherry picked from commit 8afa5ef45b797ba5d8147ceee85ac2c59dcc7f09)
+---
+ grub-core/kern/mm.c | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
+index 7be33e23bf..38bfb01df9 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -115,9 +115,8 @@ grub_mm_init_region (void *addr, grub_size_t size)
+   grub_mm_header_t h;
+   grub_mm_region_t r, *p, q;
+ 
+-#if 0
+-  grub_printf ("Using memory for heap: start=%p, end=%p\n", addr, addr + (unsigned int) size);
+-#endif
++  grub_dprintf ("regions", "Using memory for heap: start=%p, end=%p\n",
++                addr, (char *) addr + (unsigned int) size);
+ 
+   /* Exclude last 4K to avoid overflows. */
+   /* If addr + 0x1000 overflows then whole region is in excluded zone.  */
+@@ -142,8 +141,14 @@ grub_mm_init_region (void *addr, grub_size_t size)
+        * addr                          q
+        *   |----size-----|-q->pre_size-|<q region>|
+        */
++      grub_dprintf ("regions", "Can we extend into region above?"
++		    " %p + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " ?=? %p\n",
++		    (grub_uint8_t *) addr, size, q->pre_size, (grub_uint8_t *) q);
+       if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q)
+         {
++	  grub_dprintf ("regions", "Yes: extending a region: (%p -> %p) -> (%p -> %p)\n",
++			q, (grub_uint8_t *) q + sizeof (*q) + q->size,
++			addr, (grub_uint8_t *) q + sizeof (*q) + q->size);
+           /*
+            * Yes, we can merge the memory starting at addr into the
+            * existing region from below. Align up addr to GRUB_MM_ALIGN
+@@ -185,9 +190,15 @@ grub_mm_init_region (void *addr, grub_size_t size)
+        *   q                       addr
+        *   |<q region>|-q->post_size-|----size-----|
+        */
++      grub_dprintf ("regions", "Can we extend into region below?"
++                    " %p + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " ?=? %p\n",
++                    (grub_uint8_t *) q, sizeof(*q), q->size, q->post_size, (grub_uint8_t *) addr);
+       if ((grub_uint8_t *) q + sizeof (*q) + q->size + q->post_size ==
+ 	  (grub_uint8_t *) addr)
+ 	{
++	  grub_dprintf ("regions", "Yes: extending a region: (%p -> %p) -> (%p -> %p)\n",
++			q, (grub_uint8_t *) q + sizeof (*q) + q->size,
++			q, (grub_uint8_t *) addr + size);
+ 	  /*
+ 	   * Yes! Follow a similar pattern to above, but simpler.
+ 	   * Our header starts at address - post_size, which should align us
+@@ -213,6 +224,8 @@ grub_mm_init_region (void *addr, grub_size_t size)
+ 	}
+     }
+ 
++  grub_dprintf ("regions", "No: considering a new region at %p of size %" PRIxGRUB_SIZE "\n",
++		addr, size);
+   /* Allocate a region from the head.  */
+   r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN);
+ 
diff --git a/SOURCES/0301-kern-efi-sb-Enforce-verification-of-font-files.patch b/SOURCES/0301-kern-efi-sb-Enforce-verification-of-font-files.patch
deleted file mode 100644
index 42fea35..0000000
--- a/SOURCES/0301-kern-efi-sb-Enforce-verification-of-font-files.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Zhang Boyang <zhangboyang.id@gmail.com>
-Date: Sun, 14 Aug 2022 15:51:54 +0800
-Subject: [PATCH] kern/efi/sb: Enforce verification of font files
-
-As a mitigation and hardening measure enforce verification of font
-files. Then only trusted font files can be load. This will reduce the
-attack surface at cost of losing the ability of end-users to customize
-fonts if e.g. UEFI Secure Boot is enabled. Vendors can always customize
-fonts because they have ability to pack fonts into their GRUB bundles.
-
-This goal is achieved by:
-
-  * Removing GRUB_FILE_TYPE_FONT from shim lock verifier's
-    skip-verification list.
-
-  * Adding GRUB_FILE_TYPE_FONT to lockdown verifier's defer-auth list,
-    so font files must be verified by a verifier before they can be loaded.
-
-Suggested-by: Daniel Kiper <daniel.kiper@oracle.com>
-Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 630deb8c0d8b02b670ced4b7030414bcf17aa080)
-(cherry picked from commit 37257e0ee45b9029b62f4046c983481d063b821d)
----
- grub-core/kern/efi/sb.c   | 1 -
- grub-core/kern/lockdown.c | 1 +
- 2 files changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c
-index 89c4bb3fd1..db42c2539f 100644
---- a/grub-core/kern/efi/sb.c
-+++ b/grub-core/kern/efi/sb.c
-@@ -145,7 +145,6 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)),
-     case GRUB_FILE_TYPE_PRINT_BLOCKLIST:
-     case GRUB_FILE_TYPE_TESTLOAD:
-     case GRUB_FILE_TYPE_GET_SIZE:
--    case GRUB_FILE_TYPE_FONT:
-     case GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY:
-     case GRUB_FILE_TYPE_CAT:
-     case GRUB_FILE_TYPE_HEXCAT:
-diff --git a/grub-core/kern/lockdown.c b/grub-core/kern/lockdown.c
-index 0bc70fd42d..af6d493cd3 100644
---- a/grub-core/kern/lockdown.c
-+++ b/grub-core/kern/lockdown.c
-@@ -51,6 +51,7 @@ lockdown_verifier_init (grub_file_t io __attribute__ ((unused)),
-     case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE:
-     case GRUB_FILE_TYPE_ACPI_TABLE:
-     case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE:
-+    case GRUB_FILE_TYPE_FONT:
-       *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH;
- 
-       /* Fall through. */
diff --git a/SOURCES/0301-mm-Drop-unused-unloading-of-modules-on-OOM.patch b/SOURCES/0301-mm-Drop-unused-unloading-of-modules-on-OOM.patch
new file mode 100644
index 0000000..a18d912
--- /dev/null
+++ b/SOURCES/0301-mm-Drop-unused-unloading-of-modules-on-OOM.patch
@@ -0,0 +1,80 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Patrick Steinhardt <ps@pks.im>
+Date: Thu, 21 Apr 2022 15:24:17 +1000
+Subject: [PATCH] mm: Drop unused unloading of modules on OOM
+
+In grub_memalign(), there's a commented section which would allow for
+unloading of unneeded modules in case where there is not enough free
+memory available to satisfy a request. Given that this code is never
+compiled in, let's remove it together with grub_dl_unload_unneeded().
+
+Signed-off-by: Patrick Steinhardt <ps@pks.im>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+Tested-by: Patrick Steinhardt <ps@pks.im>
+(cherry picked from commit 139fd9b134a01e0b5fe0ebefafa7f48d1ffb6d60)
+---
+ grub-core/kern/dl.c | 20 --------------------
+ grub-core/kern/mm.c |  8 --------
+ include/grub/dl.h   |  1 -
+ 3 files changed, 29 deletions(-)
+
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index d5de80186f..ab9101a5ad 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -998,23 +998,3 @@ grub_dl_unload (grub_dl_t mod)
+   grub_free (mod);
+   return 1;
+ }
+-
+-/* Unload unneeded modules.  */
+-void
+-grub_dl_unload_unneeded (void)
+-{
+-  /* Because grub_dl_remove modifies the list of modules, this
+-     implementation is tricky.  */
+-  grub_dl_t p = grub_dl_head;
+-
+-  while (p)
+-    {
+-      if (grub_dl_unload (p))
+-	{
+-	  p = grub_dl_head;
+-	  continue;
+-	}
+-
+-      p = p->next;
+-    }
+-}
+diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
+index 38bfb01df9..1825dc8289 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -444,14 +444,6 @@ grub_memalign (grub_size_t align, grub_size_t size)
+       count++;
+       goto again;
+ 
+-#if 0
+-    case 1:
+-      /* Unload unneeded modules.  */
+-      grub_dl_unload_unneeded ();
+-      count++;
+-      goto again;
+-#endif
+-
+     default:
+       break;
+     }
+diff --git a/include/grub/dl.h b/include/grub/dl.h
+index 45ac8e339f..6bc2560bf0 100644
+--- a/include/grub/dl.h
++++ b/include/grub/dl.h
+@@ -206,7 +206,6 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name);
+ grub_dl_t grub_dl_load_core (void *addr, grub_size_t size);
+ grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size);
+ int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod);
+-extern void grub_dl_unload_unneeded (void);
+ extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod);
+ extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod);
+ extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod);
diff --git a/SOURCES/0302-fbutil-Fix-integer-overflow.patch b/SOURCES/0302-fbutil-Fix-integer-overflow.patch
deleted file mode 100644
index f8e82e5..0000000
--- a/SOURCES/0302-fbutil-Fix-integer-overflow.patch
+++ /dev/null
@@ -1,84 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Zhang Boyang <zhangboyang.id@gmail.com>
-Date: Tue, 6 Sep 2022 03:03:21 +0800
-Subject: [PATCH] fbutil: Fix integer overflow
-
-Expressions like u64 = u32 * u32 are unsafe because their products are
-truncated to u32 even if left hand side is u64. This patch fixes all
-problems like that one in fbutil.
-
-To get right result not only left hand side have to be u64 but it's also
-necessary to cast at least one of the operands of all leaf operators of
-right hand side to u64, e.g. u64 = u32 * u32 + u32 * u32 should be
-u64 = (u64)u32 * u32 + (u64)u32 * u32.
-
-For 1-bit bitmaps grub_uint64_t have to be used. It's safe because any
-combination of values in (grub_uint64_t)u32 * u32 + u32 expression will
-not overflow grub_uint64_t.
-
-Other expressions like ptr + u32 * u32 + u32 * u32 are also vulnerable.
-They should be ptr + (grub_addr_t)u32 * u32 + (grub_addr_t)u32 * u32.
-
-This patch also adds a comment to grub_video_fb_get_video_ptr() which
-says it's arguments must be valid and no sanity check is performed
-(like its siblings in grub-core/video/fb/fbutil.c).
-
-Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 50a11a81bc842c58962244a2dc86bbd31a426e12)
-(cherry picked from commit 8fa75d647362c938c4cc302cf5945b31fb92c078)
----
- grub-core/video/fb/fbutil.c |  4 ++--
- include/grub/fbutil.h       | 13 +++++++++----
- 2 files changed, 11 insertions(+), 6 deletions(-)
-
-diff --git a/grub-core/video/fb/fbutil.c b/grub-core/video/fb/fbutil.c
-index b98bb51fe8..25ef39f47d 100644
---- a/grub-core/video/fb/fbutil.c
-+++ b/grub-core/video/fb/fbutil.c
-@@ -67,7 +67,7 @@ get_pixel (struct grub_video_fbblit_info *source,
-     case 1:
-       if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED)
-         {
--          int bit_index = y * source->mode_info->width + x;
-+          grub_uint64_t bit_index = (grub_uint64_t) y * source->mode_info->width + x;
-           grub_uint8_t *ptr = source->data + bit_index / 8;
-           int bit_pos = 7 - bit_index % 8;
-           color = (*ptr >> bit_pos) & 0x01;
-@@ -138,7 +138,7 @@ set_pixel (struct grub_video_fbblit_info *source,
-     case 1:
-       if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED)
-         {
--          int bit_index = y * source->mode_info->width + x;
-+          grub_uint64_t bit_index = (grub_uint64_t) y * source->mode_info->width + x;
-           grub_uint8_t *ptr = source->data + bit_index / 8;
-           int bit_pos = 7 - bit_index % 8;
-           *ptr = (*ptr & ~(1 << bit_pos)) | ((color & 0x01) << bit_pos);
-diff --git a/include/grub/fbutil.h b/include/grub/fbutil.h
-index 4205eb917f..78a1ab3b45 100644
---- a/include/grub/fbutil.h
-+++ b/include/grub/fbutil.h
-@@ -31,14 +31,19 @@ struct grub_video_fbblit_info
-   grub_uint8_t *data;
- };
- 
--/* Don't use for 1-bit bitmaps, addressing needs to be done at the bit level
--   and it doesn't make sense, in general, to ask for a pointer
--   to a particular pixel's data.  */
-+/*
-+ * Don't use for 1-bit bitmaps, addressing needs to be done at the bit level
-+ * and it doesn't make sense, in general, to ask for a pointer
-+ * to a particular pixel's data.
-+ *
-+ * This function assumes that bounds checking has been done in previous phase
-+ * and they are opted out in here.
-+ */
- static inline void *
- grub_video_fb_get_video_ptr (struct grub_video_fbblit_info *source,
-               unsigned int x, unsigned int y)
- {
--  return source->data + y * source->mode_info->pitch + x * source->mode_info->bytes_per_pixel;
-+  return source->data + (grub_addr_t) y * source->mode_info->pitch + (grub_addr_t) x * source->mode_info->bytes_per_pixel;
- }
- 
- /* Advance pointer by VAL bytes. If there is no unaligned access available,
diff --git a/SOURCES/0302-mm-Allow-dynamically-requesting-additional-memory-re.patch b/SOURCES/0302-mm-Allow-dynamically-requesting-additional-memory-re.patch
new file mode 100644
index 0000000..d225c10
--- /dev/null
+++ b/SOURCES/0302-mm-Allow-dynamically-requesting-additional-memory-re.patch
@@ -0,0 +1,130 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Patrick Steinhardt <ps@pks.im>
+Date: Thu, 21 Apr 2022 15:24:18 +1000
+Subject: [PATCH] mm: Allow dynamically requesting additional memory regions
+
+Currently, all platforms will set up their heap on initialization of the
+platform code. While this works mostly fine, it poses some limitations
+on memory management on us. Most notably, allocating big chunks of
+memory in the gigabyte range would require us to pre-request this many
+bytes from the firmware and add it to the heap from the beginning on
+some platforms like EFI. As this isn't needed for most configurations,
+it is inefficient and may even negatively impact some usecases when,
+e.g., chainloading. Nonetheless, allocating big chunks of memory is
+required sometimes, where one example is the upcoming support for the
+Argon2 key derival function in LUKS2.
+
+In order to avoid pre-allocating big chunks of memory, this commit
+implements a runtime mechanism to add more pages to the system. When
+a given allocation cannot be currently satisfied, we'll call a given
+callback set up by the platform's own memory management subsystem,
+asking it to add a memory area with at least "n" bytes. If this
+succeeds, we retry searching for a valid memory region, which should
+now succeed.
+
+If this fails, we try asking for "n" bytes, possibly spread across
+multiple regions, in hopes that region merging means that we end up
+with enough memory for things to work out.
+
+Signed-off-by: Patrick Steinhardt <ps@pks.im>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Tested-by: Stefan Berger <stefanb@linux.ibm.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+Tested-by: Patrick Steinhardt <ps@pks.im>
+(cherry picked from commit 887f98f0db43e33fba4ec1f85e42fae1185700bc)
+---
+ grub-core/kern/mm.c | 30 ++++++++++++++++++++++++++++++
+ include/grub/mm.h   | 18 ++++++++++++++++++
+ 2 files changed, 48 insertions(+)
+
+diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
+index 1825dc8289..f2e27f263b 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -28,6 +28,9 @@
+   - multiple regions may be used as free space. They may not be
+   contiguous.
+ 
++  - if existing regions are insufficient to satisfy an allocation, a new
++  region can be requested from firmware.
++
+   Regions are managed by a singly linked list, and the meta information is
+   stored in the beginning of each region. Space after the meta information
+   is used to allocate memory.
+@@ -81,6 +84,7 @@
+ 
+ 
+ grub_mm_region_t grub_mm_base;
++grub_mm_add_region_func_t grub_mm_add_region_fn;
+ 
+ /* Get a header from the pointer PTR, and set *P and *R to a pointer
+    to the header and a pointer to its region, respectively. PTR must
+@@ -444,6 +448,32 @@ grub_memalign (grub_size_t align, grub_size_t size)
+       count++;
+       goto again;
+ 
++    case 1:
++      /* Request additional pages, contiguous */
++      count++;
++
++      if (grub_mm_add_region_fn != NULL &&
++          grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE)
++	goto again;
++
++      /* fallthrough  */
++
++    case 2:
++      /* Request additional pages, anything at all */
++      count++;
++
++      if (grub_mm_add_region_fn != NULL)
++        {
++          /*
++           * Try again even if this fails, in case it was able to partially
++           * satisfy the request
++           */
++          grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_NONE);
++          goto again;
++        }
++
++      /* fallthrough */
++
+     default:
+       break;
+     }
+diff --git a/include/grub/mm.h b/include/grub/mm.h
+index d81623d226..7c6f925ffd 100644
+--- a/include/grub/mm.h
++++ b/include/grub/mm.h
+@@ -20,6 +20,7 @@
+ #ifndef GRUB_MM_H
+ #define GRUB_MM_H	1
+ 
++#include <grub/err.h>
+ #include <grub/types.h>
+ #include <grub/symbol.h>
+ #include <grub/err.h>
+@@ -29,6 +30,23 @@
+ # define NULL	((void *) 0)
+ #endif
+ 
++#define GRUB_MM_ADD_REGION_NONE        0
++#define GRUB_MM_ADD_REGION_CONSECUTIVE (1 << 0)
++
++/*
++ * Function used to request memory regions of `grub_size_t` bytes. The second
++ * parameter is a bitfield of `GRUB_MM_ADD_REGION` flags.
++ */
++typedef grub_err_t (*grub_mm_add_region_func_t) (grub_size_t, unsigned int);
++
++/*
++ * Set this function pointer to enable adding memory-regions at runtime in case
++ * a memory allocation cannot be satisfied with existing regions.
++ */
++#ifndef GRUB_MACHINE_EMU
++extern grub_mm_add_region_func_t EXPORT_VAR(grub_mm_add_region_fn);
++#endif
++
+ void grub_mm_init_region (void *addr, grub_size_t size);
+ void *EXPORT_FUNC(grub_calloc) (grub_size_t nmemb, grub_size_t size);
+ void *EXPORT_FUNC(grub_malloc) (grub_size_t size);
diff --git a/SOURCES/0303-font-Fix-an-integer-underflow-in-blit_comb.patch b/SOURCES/0303-font-Fix-an-integer-underflow-in-blit_comb.patch
deleted file mode 100644
index b8a0e9e..0000000
--- a/SOURCES/0303-font-Fix-an-integer-underflow-in-blit_comb.patch
+++ /dev/null
@@ -1,90 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Zhang Boyang <zhangboyang.id@gmail.com>
-Date: Mon, 24 Oct 2022 08:05:35 +0800
-Subject: [PATCH] font: Fix an integer underflow in blit_comb()
-
-The expression (ctx.bounds.height - combining_glyphs[i]->height) / 2 may
-evaluate to a very big invalid value even if both ctx.bounds.height and
-combining_glyphs[i]->height are small integers. For example, if
-ctx.bounds.height is 10 and combining_glyphs[i]->height is 12, this
-expression evaluates to 2147483647 (expected -1). This is because
-coordinates are allowed to be negative but ctx.bounds.height is an
-unsigned int. So, the subtraction operates on unsigned ints and
-underflows to a very big value. The division makes things even worse.
-The quotient is still an invalid value even if converted back to int.
-
-This patch fixes the problem by casting ctx.bounds.height to int. As
-a result the subtraction will operate on int and grub_uint16_t which
-will be promoted to an int. So, the underflow will no longer happen. Other
-uses of ctx.bounds.height (and ctx.bounds.width) are also casted to int,
-to ensure coordinates are always calculated on signed integers.
-
-Fixes: CVE-2022-3775
-
-Reported-by: Daniel Axtens <dja@axtens.net>
-Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit 6d2668dea3774ed74c4cd1eadd146f1b846bc3d4)
-(cherry picked from commit 05e532fb707bbf79aa4e1efbde4d208d7da89d6b)
----
- grub-core/font/font.c | 16 ++++++++--------
- 1 file changed, 8 insertions(+), 8 deletions(-)
-
-diff --git a/grub-core/font/font.c b/grub-core/font/font.c
-index 193dfec045..12a5f0d08c 100644
---- a/grub-core/font/font.c
-+++ b/grub-core/font/font.c
-@@ -1203,12 +1203,12 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
-   ctx.bounds.height = main_glyph->height;
- 
-   above_rightx = main_glyph->offset_x + main_glyph->width;
--  above_righty = ctx.bounds.y + ctx.bounds.height;
-+  above_righty = ctx.bounds.y + (int) ctx.bounds.height;
- 
-   above_leftx = main_glyph->offset_x;
--  above_lefty = ctx.bounds.y + ctx.bounds.height;
-+  above_lefty = ctx.bounds.y + (int) ctx.bounds.height;
- 
--  below_rightx = ctx.bounds.x + ctx.bounds.width;
-+  below_rightx = ctx.bounds.x + (int) ctx.bounds.width;
-   below_righty = ctx.bounds.y;
- 
-   comb = grub_unicode_get_comb (glyph_id);
-@@ -1221,7 +1221,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
- 
-       if (!combining_glyphs[i])
- 	continue;
--      targetx = (ctx.bounds.width - combining_glyphs[i]->width) / 2 + ctx.bounds.x;
-+      targetx = ((int) ctx.bounds.width - combining_glyphs[i]->width) / 2 + ctx.bounds.x;
-       /* CGJ is to avoid diacritics reordering. */
-       if (comb[i].code
- 	  == GRUB_UNICODE_COMBINING_GRAPHEME_JOINER)
-@@ -1231,8 +1231,8 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
- 	case GRUB_UNICODE_COMB_OVERLAY:
- 	  do_blit (combining_glyphs[i],
- 		   targetx,
--		   (ctx.bounds.height - combining_glyphs[i]->height) / 2
--		   - (ctx.bounds.height + ctx.bounds.y), &ctx);
-+		   ((int) ctx.bounds.height - combining_glyphs[i]->height) / 2
-+		   - ((int) ctx.bounds.height + ctx.bounds.y), &ctx);
- 	  if (min_devwidth < combining_glyphs[i]->width)
- 	    min_devwidth = combining_glyphs[i]->width;
- 	  break;
-@@ -1305,7 +1305,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
- 	  /* Fallthrough.  */
- 	case GRUB_UNICODE_STACK_ATTACHED_ABOVE:
- 	  do_blit (combining_glyphs[i], targetx,
--		   -(ctx.bounds.height + ctx.bounds.y + space
-+		   -((int) ctx.bounds.height + ctx.bounds.y + space
- 		     + combining_glyphs[i]->height), &ctx);
- 	  if (min_devwidth < combining_glyphs[i]->width)
- 	    min_devwidth = combining_glyphs[i]->width;
-@@ -1313,7 +1313,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
- 
- 	case GRUB_UNICODE_COMB_HEBREW_DAGESH:
- 	  do_blit (combining_glyphs[i], targetx,
--		   -(ctx.bounds.height / 2 + ctx.bounds.y
-+		   -((int) ctx.bounds.height / 2 + ctx.bounds.y
- 		     + combining_glyphs[i]->height / 2), &ctx);
- 	  if (min_devwidth < combining_glyphs[i]->width)
- 	    min_devwidth = combining_glyphs[i]->width;
diff --git a/SOURCES/0303-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch b/SOURCES/0303-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch
new file mode 100644
index 0000000..6fa378c
--- /dev/null
+++ b/SOURCES/0303-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch
@@ -0,0 +1,103 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Patrick Steinhardt <ps@pks.im>
+Date: Thu, 21 Apr 2022 15:24:19 +1000
+Subject: [PATCH] kern/efi/mm: Always request a fixed number of pages on init
+
+When initializing the EFI memory subsystem, we will by default request
+a quarter of the available memory, bounded by a minimum/maximum value.
+Given that we're about to extend the EFI memory system to dynamically
+request additional pages from the firmware as required, this scaling of
+requested memory based on available memory will not make a lot of sense
+anymore.
+
+Remove this logic as a preparatory patch such that we'll instead defer
+to the runtime memory allocator. Note that ideally, we'd want to change
+this after dynamic requesting of pages has been implemented for the EFI
+platform. But because we'll need to split up initialization of the
+memory subsystem and the request of pages from the firmware, we'd have
+to duplicate quite some logic at first only to remove it afterwards
+again. This seems quite pointless, so we instead have patches slightly
+out of order.
+
+Signed-off-by: Patrick Steinhardt <ps@pks.im>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+Tested-by: Patrick Steinhardt <ps@pks.im>
+(cherry picked from commit 938c3760b8c0fca759140be48307179b50107ff6)
+---
+ grub-core/kern/efi/mm.c | 35 +++--------------------------------
+ 1 file changed, 3 insertions(+), 32 deletions(-)
+
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index e460b072e6..782a1365a1 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -38,9 +38,8 @@
+    a multiplier of 4KB.  */
+ #define MEMORY_MAP_SIZE	0x3000
+ 
+-/* The minimum and maximum heap size for GRUB itself.  */
+-#define MIN_HEAP_SIZE	0x100000
+-#define MAX_HEAP_SIZE	(1600 * 0x100000)
++/* The default heap size for GRUB itself in bytes.  */
++#define DEFAULT_HEAP_SIZE	0x100000
+ 
+ static void *finish_mmap_buf = 0;
+ static grub_efi_uintn_t finish_mmap_size = 0;
+@@ -514,23 +513,6 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
+   return filtered_desc;
+ }
+ 
+-/* Return the total number of pages.  */
+-static grub_efi_uint64_t
+-get_total_pages (grub_efi_memory_descriptor_t *memory_map,
+-		 grub_efi_uintn_t desc_size,
+-		 grub_efi_memory_descriptor_t *memory_map_end)
+-{
+-  grub_efi_memory_descriptor_t *desc;
+-  grub_efi_uint64_t total = 0;
+-
+-  for (desc = memory_map;
+-       desc < memory_map_end;
+-       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
+-    total += desc->num_pages;
+-
+-  return total;
+-}
+-
+ /* Add memory regions.  */
+ static void
+ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
+@@ -694,8 +676,6 @@ grub_efi_mm_init (void)
+   grub_efi_memory_descriptor_t *filtered_memory_map_end;
+   grub_efi_uintn_t map_size;
+   grub_efi_uintn_t desc_size;
+-  grub_efi_uint64_t total_pages;
+-  grub_efi_uint64_t required_pages;
+   int mm_status;
+ 
+   grub_nx_init ();
+@@ -737,22 +717,13 @@ grub_efi_mm_init (void)
+   filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map,
+ 					       desc_size, memory_map_end);
+ 
+-  /* By default, request a quarter of the available memory.  */
+-  total_pages = get_total_pages (filtered_memory_map, desc_size,
+-				 filtered_memory_map_end);
+-  required_pages = (total_pages >> 2);
+-  if (required_pages < BYTES_TO_PAGES (MIN_HEAP_SIZE))
+-    required_pages = BYTES_TO_PAGES (MIN_HEAP_SIZE);
+-  else if (required_pages > BYTES_TO_PAGES (MAX_HEAP_SIZE))
+-    required_pages = BYTES_TO_PAGES (MAX_HEAP_SIZE);
+-
+   /* Sort the filtered descriptors, so that GRUB can allocate pages
+      from smaller regions.  */
+   sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end);
+ 
+   /* Allocate memory regions for GRUB's memory management.  */
+   add_memory_regions (filtered_memory_map, desc_size,
+-		      filtered_memory_map_end, required_pages);
++		      filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE));
+ 
+ #if 0
+   /* For debug.  */
diff --git a/SOURCES/0304-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch b/SOURCES/0304-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch
deleted file mode 100644
index 307572c..0000000
--- a/SOURCES/0304-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch
+++ /dev/null
@@ -1,74 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Zhang Boyang <zhangboyang.id@gmail.com>
-Date: Mon, 24 Oct 2022 07:15:41 +0800
-Subject: [PATCH] font: Harden grub_font_blit_glyph() and
- grub_font_blit_glyph_mirror()
-
-As a mitigation and hardening measure add sanity checks to
-grub_font_blit_glyph() and grub_font_blit_glyph_mirror(). This patch
-makes these two functions do nothing if target blitting area isn't fully
-contained in target bitmap. Therefore, if complex calculations in caller
-overflows and malicious coordinates are given, we are still safe because
-any coordinates which result in out-of-bound-write are rejected. However,
-this patch only checks for invalid coordinates, and doesn't provide any
-protection against invalid source glyph or destination glyph, e.g.
-mismatch between glyph size and buffer size.
-
-This hardening measure is designed to mitigate possible overflows in
-blit_comb(). If overflow occurs, it may return invalid bounding box
-during dry run and call grub_font_blit_glyph() with malicious
-coordinates during actual blitting. However, we are still safe because
-the scratch glyph itself is valid, although its size makes no sense, and
-any invalid coordinates are rejected.
-
-It would be better to call grub_fatal() if illegal parameter is detected.
-However, doing this may end up in a dangerous recursion because grub_fatal()
-would print messages to the screen and we are in the progress of drawing
-characters on the screen.
-
-Reported-by: Daniel Axtens <dja@axtens.net>
-Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit fcd7aa0c278f7cf3fb9f93f1a3966e1792339eb6)
-(cherry picked from commit 1d37ec63a1c76a14fdf70f548eada92667b42ddb)
----
- grub-core/font/font.c | 14 ++++++++++++++
- 1 file changed, 14 insertions(+)
-
-diff --git a/grub-core/font/font.c b/grub-core/font/font.c
-index 12a5f0d08c..29fbb94294 100644
---- a/grub-core/font/font.c
-+++ b/grub-core/font/font.c
-@@ -1069,8 +1069,15 @@ static void
- grub_font_blit_glyph (struct grub_font_glyph *target,
- 		      struct grub_font_glyph *src, unsigned dx, unsigned dy)
- {
-+  grub_uint16_t max_x, max_y;
-   unsigned src_bit, tgt_bit, src_byte, tgt_byte;
-   unsigned i, j;
-+
-+  /* Harden against out-of-bound writes. */
-+  if ((grub_add (dx, src->width, &max_x) || max_x > target->width) ||
-+      (grub_add (dy, src->height, &max_y) || max_y > target->height))
-+    return;
-+
-   for (i = 0; i < src->height; i++)
-     {
-       src_bit = (src->width * i) % 8;
-@@ -1102,9 +1109,16 @@ grub_font_blit_glyph_mirror (struct grub_font_glyph *target,
- 			     struct grub_font_glyph *src,
- 			     unsigned dx, unsigned dy)
- {
-+  grub_uint16_t max_x, max_y;
-   unsigned tgt_bit, src_byte, tgt_byte;
-   signed src_bit;
-   unsigned i, j;
-+
-+  /* Harden against out-of-bound writes. */
-+  if ((grub_add (dx, src->width, &max_x) || max_x > target->width) ||
-+      (grub_add (dy, src->height, &max_y) || max_y > target->height))
-+    return;
-+
-   for (i = 0; i < src->height; i++)
-     {
-       src_bit = (src->width * i + src->width - 1) % 8;
diff --git a/SOURCES/0304-kern-efi-mm-Extract-function-to-add-memory-regions.patch b/SOURCES/0304-kern-efi-mm-Extract-function-to-add-memory-regions.patch
new file mode 100644
index 0000000..28cf2e7
--- /dev/null
+++ b/SOURCES/0304-kern-efi-mm-Extract-function-to-add-memory-regions.patch
@@ -0,0 +1,85 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Patrick Steinhardt <ps@pks.im>
+Date: Thu, 21 Apr 2022 15:24:20 +1000
+Subject: [PATCH] kern/efi/mm: Extract function to add memory regions
+
+In preparation of support for runtime-allocating additional memory
+region, this patch extracts the function to retrieve the EFI memory
+map and add a subset of it to GRUB's own memory regions.
+
+Signed-off-by: Patrick Steinhardt <ps@pks.im>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+Tested-by: Patrick Steinhardt <ps@pks.im>
+(cherry picked from commit 96a7ea29e3cb61b6c2302e260e8e6a6117e17fa3)
+[rharwood: backport around our nx]
+---
+ grub-core/kern/efi/mm.c | 21 +++++++++++++++------
+ 1 file changed, 15 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index 782a1365a1..a1d3b51fe6 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -667,8 +667,8 @@ grub_nx_init (void)
+     }
+ }
+ 
+-void
+-grub_efi_mm_init (void)
++static grub_err_t
++grub_efi_mm_add_regions (grub_size_t required_bytes)
+ {
+   grub_efi_memory_descriptor_t *memory_map;
+   grub_efi_memory_descriptor_t *memory_map_end;
+@@ -683,7 +683,7 @@ grub_efi_mm_init (void)
+   /* Prepare a memory region to store two memory maps.  */
+   memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
+   if (! memory_map)
+-    grub_fatal ("cannot allocate memory");
++    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for memory map");
+ 
+   /* Obtain descriptors for available memory.  */
+   map_size = MEMORY_MAP_SIZE;
+@@ -701,14 +701,14 @@ grub_efi_mm_init (void)
+ 
+       memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size));
+       if (! memory_map)
+-	grub_fatal ("cannot allocate memory");
++	return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for new memory map");
+ 
+       mm_status = grub_efi_get_memory_map (&map_size, memory_map, 0,
+ 					   &desc_size, 0);
+     }
+ 
+   if (mm_status < 0)
+-    grub_fatal ("cannot get memory map");
++    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "error fetching memory map from EFI");
+ 
+   memory_map_end = NEXT_MEMORY_DESCRIPTOR (memory_map, map_size);
+ 
+@@ -723,7 +723,7 @@ grub_efi_mm_init (void)
+ 
+   /* Allocate memory regions for GRUB's memory management.  */
+   add_memory_regions (filtered_memory_map, desc_size,
+-		      filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE));
++		      filtered_memory_map_end, BYTES_TO_PAGES (required_bytes));
+ 
+ #if 0
+   /* For debug.  */
+@@ -741,6 +741,15 @@ grub_efi_mm_init (void)
+   /* Release the memory maps.  */
+   grub_efi_free_pages ((grub_addr_t) memory_map,
+ 		       2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
++
++  return GRUB_ERR_NONE;
++}
++
++void
++grub_efi_mm_init (void)
++{
++  if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE)
++    grub_fatal ("%s", grub_errmsg);
+ }
+ 
+ #if defined (__aarch64__) || defined (__arm__) || defined (__riscv)
diff --git a/SOURCES/0305-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch b/SOURCES/0305-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch
deleted file mode 100644
index 368b9d0..0000000
--- a/SOURCES/0305-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Zhang Boyang <zhangboyang.id@gmail.com>
-Date: Fri, 28 Oct 2022 17:29:16 +0800
-Subject: [PATCH] font: Assign null_font to glyphs in ascii_font_glyph[]
-
-The calculations in blit_comb() need information from glyph's font, e.g.
-grub_font_get_xheight(main_glyph->font). However, main_glyph->font is
-NULL if main_glyph comes from ascii_font_glyph[]. Therefore
-grub_font_get_*() crashes because of NULL pointer.
-
-There is already a solution, the null_font. So, assign it to those glyphs
-in ascii_font_glyph[].
-
-Reported-by: Daniel Axtens <dja@axtens.net>
-Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit dd539d695482069d28b40f2d3821f710cdcf6ee6)
-(cherry picked from commit 87526376857eaceae474c9797e3cee5b50597332)
----
- grub-core/font/font.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/grub-core/font/font.c b/grub-core/font/font.c
-index 29fbb94294..e6616e610c 100644
---- a/grub-core/font/font.c
-+++ b/grub-core/font/font.c
-@@ -137,7 +137,7 @@ ascii_glyph_lookup (grub_uint32_t code)
- 	  ascii_font_glyph[current]->offset_x = 0;
- 	  ascii_font_glyph[current]->offset_y = -2;
- 	  ascii_font_glyph[current]->device_width = 8;
--	  ascii_font_glyph[current]->font = NULL;
-+	  ascii_font_glyph[current]->font = &null_font;
- 
- 	  grub_memcpy (ascii_font_glyph[current]->bitmap,
- 		       &ascii_bitmaps[current * ASCII_BITMAP_SIZE],
diff --git a/SOURCES/0305-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch b/SOURCES/0305-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch
new file mode 100644
index 0000000..b4b7891
--- /dev/null
+++ b/SOURCES/0305-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch
@@ -0,0 +1,87 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Patrick Steinhardt <ps@pks.im>
+Date: Thu, 21 Apr 2022 15:24:21 +1000
+Subject: [PATCH] kern/efi/mm: Pass up errors from add_memory_regions()
+
+The function add_memory_regions() is currently only called on system
+initialization to allocate a fixed amount of pages. As such, it didn't
+need to return any errors: in case it failed, we cannot proceed anyway.
+This will change with the upcoming support for requesting more memory
+from the firmware at runtime, where it doesn't make sense anymore to
+fail hard.
+
+Refactor the function to return an error to prepare for this. Note that
+this does not change the behaviour when initializing the memory system
+because grub_efi_mm_init() knows to call grub_fatal() in case
+grub_efi_mm_add_regions() returns an error.
+
+Signed-off-by: Patrick Steinhardt <ps@pks.im>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+Tested-by: Patrick Steinhardt <ps@pks.im>
+(cherry picked from commit 15a015698921240adc1ac266a3b5bc5fcbd81521)
+---
+ grub-core/kern/efi/mm.c | 22 +++++++++++++++-------
+ 1 file changed, 15 insertions(+), 7 deletions(-)
+
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index a1d3b51fe6..e0ebc65dba 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -514,7 +514,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
+ }
+ 
+ /* Add memory regions.  */
+-static void
++static grub_err_t
+ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
+ 		    grub_efi_uintn_t desc_size,
+ 		    grub_efi_memory_descriptor_t *memory_map_end,
+@@ -542,9 +542,9 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
+ 					   GRUB_EFI_ALLOCATE_ADDRESS,
+ 					   GRUB_EFI_LOADER_CODE);      
+       if (! addr)
+-	grub_fatal ("cannot allocate conventional memory %p with %u pages",
+-		    (void *) ((grub_addr_t) start),
+-		    (unsigned) pages);
++	return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			    "Memory starting at %p (%u pages) marked as free, but EFI would not allocate",
++			    (void *) ((grub_addr_t) start), (unsigned) pages);
+ 
+       grub_mm_init_region (addr, PAGES_TO_BYTES (pages));
+ 
+@@ -554,7 +554,11 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
+     }
+ 
+   if (required_pages > 0)
+-    grub_fatal ("too little memory");
++    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++                       "could not allocate all requested memory: %" PRIuGRUB_UINT64_T " pages still required after iterating EFI memory map",
++                       required_pages);
++
++  return GRUB_ERR_NONE;
+ }
+ 
+ void
+@@ -676,6 +680,7 @@ grub_efi_mm_add_regions (grub_size_t required_bytes)
+   grub_efi_memory_descriptor_t *filtered_memory_map_end;
+   grub_efi_uintn_t map_size;
+   grub_efi_uintn_t desc_size;
++  grub_err_t err;
+   int mm_status;
+ 
+   grub_nx_init ();
+@@ -722,8 +727,11 @@ grub_efi_mm_add_regions (grub_size_t required_bytes)
+   sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end);
+ 
+   /* Allocate memory regions for GRUB's memory management.  */
+-  add_memory_regions (filtered_memory_map, desc_size,
+-		      filtered_memory_map_end, BYTES_TO_PAGES (required_bytes));
++  err = add_memory_regions (filtered_memory_map, desc_size,
++			    filtered_memory_map_end,
++			    BYTES_TO_PAGES (required_bytes));
++  if (err != GRUB_ERR_NONE)
++    return err;
+ 
+ #if 0
+   /* For debug.  */
diff --git a/SOURCES/0306-kern-efi-mm-Implement-runtime-addition-of-pages.patch b/SOURCES/0306-kern-efi-mm-Implement-runtime-addition-of-pages.patch
new file mode 100644
index 0000000..1f52581
--- /dev/null
+++ b/SOURCES/0306-kern-efi-mm-Implement-runtime-addition-of-pages.patch
@@ -0,0 +1,75 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Patrick Steinhardt <ps@pks.im>
+Date: Thu, 21 Apr 2022 15:24:22 +1000
+Subject: [PATCH] kern/efi/mm: Implement runtime addition of pages
+
+Adjust the interface of grub_efi_mm_add_regions() to take a set of
+GRUB_MM_ADD_REGION_* flags, which most notably is currently only the
+GRUB_MM_ADD_REGION_CONSECUTIVE flag. This allows us to set the function
+up as callback for the memory subsystem and have it call out to us in
+case there's not enough pages available in the current heap.
+
+Signed-off-by: Patrick Steinhardt <ps@pks.im>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+Tested-by: Patrick Steinhardt <ps@pks.im>
+(cherry picked from commit 1df2934822df4c1170dde069d97cfbf7a9572bba)
+---
+ grub-core/kern/efi/mm.c | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index e0ebc65dba..016ba6cf2f 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -518,7 +518,8 @@ static grub_err_t
+ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
+ 		    grub_efi_uintn_t desc_size,
+ 		    grub_efi_memory_descriptor_t *memory_map_end,
+-		    grub_efi_uint64_t required_pages)
++		    grub_efi_uint64_t required_pages,
++		    unsigned int flags)
+ {
+   grub_efi_memory_descriptor_t *desc;
+ 
+@@ -532,6 +533,10 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
+ 
+       start = desc->physical_start;
+       pages = desc->num_pages;
++
++      if (pages < required_pages && (flags & GRUB_MM_ADD_REGION_CONSECUTIVE))
++	continue;
++
+       if (pages > required_pages)
+ 	{
+ 	  start += PAGES_TO_BYTES (pages - required_pages);
+@@ -672,7 +677,7 @@ grub_nx_init (void)
+ }
+ 
+ static grub_err_t
+-grub_efi_mm_add_regions (grub_size_t required_bytes)
++grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags)
+ {
+   grub_efi_memory_descriptor_t *memory_map;
+   grub_efi_memory_descriptor_t *memory_map_end;
+@@ -729,7 +734,8 @@ grub_efi_mm_add_regions (grub_size_t required_bytes)
+   /* Allocate memory regions for GRUB's memory management.  */
+   err = add_memory_regions (filtered_memory_map, desc_size,
+ 			    filtered_memory_map_end,
+-			    BYTES_TO_PAGES (required_bytes));
++			    BYTES_TO_PAGES (required_bytes),
++			    flags);
+   if (err != GRUB_ERR_NONE)
+     return err;
+ 
+@@ -756,8 +762,9 @@ grub_efi_mm_add_regions (grub_size_t required_bytes)
+ void
+ grub_efi_mm_init (void)
+ {
+-  if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE)
++  if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE, GRUB_MM_ADD_REGION_NONE) != GRUB_ERR_NONE)
+     grub_fatal ("%s", grub_errmsg);
++  grub_mm_add_region_fn = grub_efi_mm_add_regions;
+ }
+ 
+ #if defined (__aarch64__) || defined (__arm__) || defined (__riscv)
diff --git a/SOURCES/0306-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch b/SOURCES/0306-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch
deleted file mode 100644
index 96f2f94..0000000
--- a/SOURCES/0306-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch
+++ /dev/null
@@ -1,54 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Zhang Boyang <zhangboyang.id@gmail.com>
-Date: Fri, 28 Oct 2022 21:31:39 +0800
-Subject: [PATCH] normal/charset: Fix an integer overflow in
- grub_unicode_aglomerate_comb()
-
-The out->ncomb is a bit-field of 8 bits. So, the max possible value is 255.
-However, code in grub_unicode_aglomerate_comb() doesn't check for an
-overflow when incrementing out->ncomb. If out->ncomb is already 255,
-after incrementing it will get 0 instead of 256, and cause illegal
-memory access in subsequent processing.
-
-This patch introduces GRUB_UNICODE_NCOMB_MAX to represent the max
-acceptable value of ncomb. The code now checks for this limit and
-ignores additional combining characters when limit is reached.
-
-Reported-by: Daniel Axtens <dja@axtens.net>
-Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
-Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
-(cherry picked from commit da90d62316a3b105d2fbd7334d6521936bd6dcf6)
-(cherry picked from commit 26fafec86000b5322837722a115279ef03922ca6)
----
- grub-core/normal/charset.c | 3 +++
- include/grub/unicode.h     | 2 ++
- 2 files changed, 5 insertions(+)
-
-diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c
-index 7a5a7c153c..c243ca6dae 100644
---- a/grub-core/normal/charset.c
-+++ b/grub-core/normal/charset.c
-@@ -472,6 +472,9 @@ grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen,
- 	  if (!haveout)
- 	    continue;
- 
-+	  if (out->ncomb == GRUB_UNICODE_NCOMB_MAX)
-+	    continue;
-+
- 	  if (comb_type == GRUB_UNICODE_COMB_MC
- 	      || comb_type == GRUB_UNICODE_COMB_ME
- 	      || comb_type == GRUB_UNICODE_COMB_MN)
-diff --git a/include/grub/unicode.h b/include/grub/unicode.h
-index 4de986a857..c4f6fca043 100644
---- a/include/grub/unicode.h
-+++ b/include/grub/unicode.h
-@@ -147,7 +147,9 @@ struct grub_unicode_glyph
-   grub_uint8_t bidi_level:6; /* minimum: 6 */
-   enum grub_bidi_type bidi_type:5; /* minimum: :5 */
- 
-+#define GRUB_UNICODE_NCOMB_MAX ((1 << 8) - 1)
-   unsigned ncomb:8;
-+
-   /* Hint by unicode subsystem how wide this character usually is.
-      Real width is determined by font. Set only in UTF-8 stream.  */
-   int estimated_width:8;
diff --git a/SOURCES/0307-efi-Increase-default-memory-allocation-to-32-MiB.patch b/SOURCES/0307-efi-Increase-default-memory-allocation-to-32-MiB.patch
new file mode 100644
index 0000000..b70c3cc
--- /dev/null
+++ b/SOURCES/0307-efi-Increase-default-memory-allocation-to-32-MiB.patch
@@ -0,0 +1,31 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Tue, 20 Sep 2022 00:30:30 +1000
+Subject: [PATCH] efi: Increase default memory allocation to 32 MiB
+
+We have multiple reports of things being slower with a 1 MiB initial static
+allocation, and a report (more difficult to nail down) of a boot failure
+as a result of the smaller initial allocation.
+
+Make the initial memory allocation 32 MiB.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 75e38e86e7d9202f050b093f20500d9ad4c6dad9)
+---
+ grub-core/kern/efi/mm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index 016ba6cf2f..b27e966e1f 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -39,7 +39,7 @@
+ #define MEMORY_MAP_SIZE	0x3000
+ 
+ /* The default heap size for GRUB itself in bytes.  */
+-#define DEFAULT_HEAP_SIZE	0x100000
++#define DEFAULT_HEAP_SIZE	0x2000000
+ 
+ static void *finish_mmap_buf = 0;
+ static grub_efi_uintn_t finish_mmap_size = 0;
diff --git a/SOURCES/0308-mm-Try-invalidate-disk-caches-last-when-out-of-memor.patch b/SOURCES/0308-mm-Try-invalidate-disk-caches-last-when-out-of-memor.patch
new file mode 100644
index 0000000..c919891
--- /dev/null
+++ b/SOURCES/0308-mm-Try-invalidate-disk-caches-last-when-out-of-memor.patch
@@ -0,0 +1,57 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Sat, 15 Oct 2022 22:15:11 +0800
+Subject: [PATCH] mm: Try invalidate disk caches last when out of memory
+
+Every heap grow will cause all disk caches invalidated which decreases
+performance severely. This patch moves disk cache invalidation code to
+the last of memory squeezing measures. So, disk caches are released only
+when there are no other ways to get free memory.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+Reviewed-by: Patrick Steinhardt <ps@pks.im>
+(cherry picked from commit 17975d10a80e2457e5237f87fa58a7943031983e)
+---
+ grub-core/kern/mm.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
+index f2e27f263b..da1ac9427c 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -443,12 +443,6 @@ grub_memalign (grub_size_t align, grub_size_t size)
+   switch (count)
+     {
+     case 0:
+-      /* Invalidate disk caches.  */
+-      grub_disk_cache_invalidate_all ();
+-      count++;
+-      goto again;
+-
+-    case 1:
+       /* Request additional pages, contiguous */
+       count++;
+ 
+@@ -458,7 +452,7 @@ grub_memalign (grub_size_t align, grub_size_t size)
+ 
+       /* fallthrough  */
+ 
+-    case 2:
++    case 1:
+       /* Request additional pages, anything at all */
+       count++;
+ 
+@@ -474,6 +468,12 @@ grub_memalign (grub_size_t align, grub_size_t size)
+ 
+       /* fallthrough */
+ 
++    case 2:
++      /* Invalidate disk caches.  */
++      grub_disk_cache_invalidate_all ();
++      count++;
++      goto again;
++
+     default:
+       break;
+     }
diff --git a/SOURCES/0309-ppc64le-signed-boot-media-changes.patch b/SOURCES/0309-ppc64le-signed-boot-media-changes.patch
new file mode 100644
index 0000000..bd71437
--- /dev/null
+++ b/SOURCES/0309-ppc64le-signed-boot-media-changes.patch
@@ -0,0 +1,125 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Wed, 25 Jan 2023 16:10:58 -0500
+Subject: [PATCH] ppc64le: signed boot media changes
+
+Skip mdraid < 1.1 on isos since mdraid* can't even
+
+Prior to this change, on ppc64le with part_msdos and the mdraid* modules
+enabled, we see:
+
+    disk/diskfilter.c:191: scanning ieee1275/cdrom
+    kern/disk.c:196: Opening `ieee1275/cdrom'...
+    disk/ieee1275/ofdisk.c:477: Opening `cdrom'.
+    disk/ieee1275/ofdisk.c:502: MAX_RETRIES set to 20
+    kern/disk.c:288: Opening `ieee1275/cdrom' succeeded.
+    disk/diskfilter.c:136: Scanning for DISKFILTER devices on disk ieee1275/cdrom
+    partmap/msdos.c:184: partition 0: flag 0x80, type 0x96, start 0x0, len
+    0x6a5d70
+    disk/diskfilter.c:136: Scanning for DISKFILTER devices on disk ieee1275/cdrom
+    SCSI-DISK: Access beyond end of device !
+    SCSI-DISK: Access beyond end of device !
+    SCSI-DISK: Access beyond end of device !
+    SCSI-DISK: Access beyond end of device !
+    SCSI-DISK: Access beyond end of device !
+    disk/ieee1275/ofdisk.c:578: MAX_RETRIES set to 20
+
+These latter two lines repeat many times, eventually ending in:
+
+    kern/disk.c:388: ieee1275/cdrom read failed
+    error: ../../grub-core/disk/ieee1275/ofdisk.c:608:failure reading sector
+    0x1a9720 from `ieee1275/cdrom'.
+
+and the system drops to a "grub>" prompt.
+
+Prior to 1.1, mdraid stored the superblock offset from the end of the
+disk, and the firmware really doesn't like reads there.  Best guess was
+that the firmware and the iso image appear to diagree on the blocksize
+(512 vs. 2048), and the diskfilter RAID probing is too much for it.
+It's tempting to just skip probing for cdroms, but unfortunately isos
+can be virtualized elsewhere - such as regular disks.
+
+Also fix detection of root, and try the chrp path as a fallback if the
+built prefix doesn't work.
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+
+wip
+---
+ grub-core/disk/mdraid1x_linux.c  | 8 +++++++-
+ grub-core/disk/mdraid_linux.c    | 5 +++++
+ grub-core/kern/ieee1275/openfw.c | 2 +-
+ grub-core/normal/main.c          | 5 +++++
+ 4 files changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/disk/mdraid1x_linux.c b/grub-core/disk/mdraid1x_linux.c
+index 38444b02c7..08c57ae16e 100644
+--- a/grub-core/disk/mdraid1x_linux.c
++++ b/grub-core/disk/mdraid1x_linux.c
+@@ -129,7 +129,13 @@ grub_mdraid_detect (grub_disk_t disk,
+       grub_uint32_t level;
+       struct grub_diskfilter_vg *array;
+       char *uuid;
+-	
++
++#ifdef __powerpc__
++      /* Firmware will yell at us for reading too far. */
++      if (minor_version == 0)
++        continue;
++#endif
++
+       if (size == GRUB_DISK_SIZE_UNKNOWN && minor_version == 0)
+ 	continue;
+ 	
+diff --git a/grub-core/disk/mdraid_linux.c b/grub-core/disk/mdraid_linux.c
+index e40216f511..98fcfb1be6 100644
+--- a/grub-core/disk/mdraid_linux.c
++++ b/grub-core/disk/mdraid_linux.c
+@@ -189,6 +189,11 @@ grub_mdraid_detect (grub_disk_t disk,
+   grub_uint32_t level;
+   struct grub_diskfilter_vg *ret;
+ 
++#ifdef __powerpc__
++  /* Firmware will yell at us for reading too far. */
++  return NULL;
++#endif
++
+   /* The sector where the mdraid 0.90 superblock is stored, if available.  */
+   size = grub_disk_native_sectors (disk);
+   if (size == GRUB_DISK_SIZE_UNKNOWN)
+diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c
+index 3a6689abb1..0278054c61 100644
+--- a/grub-core/kern/ieee1275/openfw.c
++++ b/grub-core/kern/ieee1275/openfw.c
+@@ -499,7 +499,7 @@ grub_ieee1275_encode_devname (const char *path)
+ 	*optr++ ='\\';
+       *optr++ = *iptr++;
+     }
+-  if (partition && partition[0])
++  if (partition && partition[0] >= '0' && partition[0] <= '9')
+     {
+       unsigned int partno = grub_strtoul (partition, 0, 0);
+ 
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index 8f5fd81003..d59145f861 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -372,6 +372,7 @@ grub_try_normal_prefix (const char *prefix)
+            file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG);
+            if (file)
+              {
++               grub_env_set ("prefix", prefix);
+                grub_file_close (file);
+                err = GRUB_ERR_NONE;
+              }
+@@ -447,6 +448,10 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
+       err = grub_try_normal ("fw_path");
+       if (err == GRUB_ERR_FILE_NOT_FOUND)
+         err = grub_try_normal ("prefix");
++#ifdef __powerpc__
++      if (err == GRUB_ERR_FILE_NOT_FOUND)
++        err = grub_try_normal_prefix ("/boot/grub");
++#endif
+       if (err == GRUB_ERR_FILE_NOT_FOUND)
+         err = grub_try_normal_discover ();
+       if (err == GRUB_ERR_FILE_NOT_FOUND)
diff --git a/SOURCES/0310-core-Fix-several-implicit-function-declarations.patch b/SOURCES/0310-core-Fix-several-implicit-function-declarations.patch
new file mode 100644
index 0000000..48c5bb0
--- /dev/null
+++ b/SOURCES/0310-core-Fix-several-implicit-function-declarations.patch
@@ -0,0 +1,54 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Arjun Shankar <arjun@redhat.com>
+Date: Sun, 5 Feb 2023 11:13:55 +0100
+Subject: [PATCH] core: Fix several implicit function declarations
+
+These #include lines ensure that grub2 continues to build with C99
+where implicit function declarations are removed.
+
+Related to:
+
+  <https://fedoraproject.org/wiki/Changes/PortingToModernC>
+  <https://fedoraproject.org/wiki/Toolchain/PortingToModernC>
+---
+ grub-core/commands/efi/connectefi.c | 1 +
+ grub-core/net/http.c                | 1 +
+ grub-core/term/at_keyboard.c        | 1 +
+ 3 files changed, 3 insertions(+)
+
+diff --git a/grub-core/commands/efi/connectefi.c b/grub-core/commands/efi/connectefi.c
+index 8ab75bd51b..3752ae17ed 100644
+--- a/grub-core/commands/efi/connectefi.c
++++ b/grub-core/commands/efi/connectefi.c
+@@ -21,6 +21,7 @@
+ #include <grub/efi/api.h>
+ #include <grub/efi/pci.h>
+ #include <grub/efi/efi.h>
++#include <grub/efi/disk.h>
+ #include <grub/command.h>
+ #include <grub/err.h>
+ #include <grub/i18n.h>
+diff --git a/grub-core/net/http.c b/grub-core/net/http.c
+index 57d2721719..5f956b743e 100644
+--- a/grub-core/net/http.c
++++ b/grub-core/net/http.c
+@@ -26,6 +26,7 @@
+ #include <grub/dl.h>
+ #include <grub/file.h>
+ #include <grub/i18n.h>
++#include <grub/env.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c
+index dac0f946fe..de3e4abe44 100644
+--- a/grub-core/term/at_keyboard.c
++++ b/grub-core/term/at_keyboard.c
+@@ -25,6 +25,7 @@
+ #include <grub/time.h>
+ #include <grub/loader.h>
+ #include <grub/ps2.h>
++#include <grub/env.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
diff --git a/SOURCES/0311-loader-Add-support-for-grub-emu-to-kexec-Linux-menu-.patch b/SOURCES/0311-loader-Add-support-for-grub-emu-to-kexec-Linux-menu-.patch
new file mode 100644
index 0000000..65834d8
--- /dev/null
+++ b/SOURCES/0311-loader-Add-support-for-grub-emu-to-kexec-Linux-menu-.patch
@@ -0,0 +1,431 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Raymund Will <rw@suse.com>
+Date: Mon, 24 Oct 2022 14:33:50 -0400
+Subject: [PATCH] loader: Add support for grub-emu to kexec Linux menu entries
+
+The GRUB emulator is used as a debugging utility but it could also be
+used as a user-space bootloader if there is support to boot an operating
+system.
+
+The Linux kernel is already able to (re)boot another kernel via the
+kexec boot mechanism. So the grub-emu tool could rely on this feature
+and have linux and initrd commands that are used to pass a kernel,
+initramfs image and command line parameters to kexec for booting
+a selected menu entry.
+
+By default the systemctl kexec option is used so systemd can shutdown
+all of the running services before doing a reboot using kexec. But if
+this is not present, it can fall back to executing the kexec user-space
+tool directly. The ability to force a kexec-reboot when systemctl kexec
+fails must only be used in controlled environments to avoid possible
+filesystem corruption and data loss.
+
+Signed-off-by: Raymund Will <rw@suse.com>
+Signed-off-by: John Jolly <jjolly@suse.com>
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit e364307f6acc2f631b4c1fefda0791b9ce1f205f)
+[rharwood: conflicts around makefile and grub_exit return code]
+---
+ grub-core/Makefile.core.def  |   3 -
+ grub-core/kern/emu/main.c    |   4 +
+ grub-core/kern/emu/misc.c    |  18 ++++-
+ grub-core/loader/emu/linux.c | 178 +++++++++++++++++++++++++++++++++++++++++++
+ include/grub/emu/exec.h      |   4 +-
+ include/grub/emu/hostfile.h  |   3 +-
+ include/grub/emu/misc.h      |   3 +
+ docs/grub.texi               |  30 ++++++--
+ grub-core/Makefile.am        |   1 +
+ 9 files changed, 230 insertions(+), 14 deletions(-)
+ create mode 100644 grub-core/loader/emu/linux.c
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 741a033978..f21da23213 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -1864,11 +1864,8 @@ module = {
+   riscv32 = loader/riscv/linux.c;
+   riscv64 = loader/riscv/linux.c;
+   emu = loader/emu/linux.c;
+-
+   common = loader/linux.c;
+   common = lib/cmdline.c;
+-  enable = noemu;
+-
+   efi = loader/efi/linux.c;
+ };
+ 
+diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c
+index 12277c34d2..68e2b283bb 100644
+--- a/grub-core/kern/emu/main.c
++++ b/grub-core/kern/emu/main.c
+@@ -107,6 +107,7 @@ static struct argp_option options[] = {
+    N_("use GRUB files in the directory DIR [default=%s]"), 0},
+   {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
+   {"hold",     'H', N_("SECS"),      OPTION_ARG_OPTIONAL, N_("wait until a debugger will attach"), 0},
++  {"kexec",       'X', 0,      0, N_("use kexec to boot Linux kernels via systemctl (pass twice to enable dangerous fallback to non-systemctl)."), 0},
+   { 0, 0, 0, 0, 0, 0 }
+ };
+ 
+@@ -164,6 +165,9 @@ argp_parser (int key, char *arg, struct argp_state *state)
+     case 'v':
+       verbosity++;
+       break;
++    case 'X':
++      grub_util_set_kexecute ();
++      break;
+ 
+     case ARGP_KEY_ARG:
+       {
+diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c
+index d278c2921f..02d27c3440 100644
+--- a/grub-core/kern/emu/misc.c
++++ b/grub-core/kern/emu/misc.c
+@@ -39,6 +39,7 @@
+ #include <grub/emu/misc.h>
+ 
+ int verbosity;
++int kexecute;
+ 
+ void
+ grub_util_warn (const char *fmt, ...)
+@@ -82,7 +83,7 @@ grub_util_error (const char *fmt, ...)
+   vfprintf (stderr, fmt, ap);
+   va_end (ap);
+   fprintf (stderr, ".\n");
+-  exit (1);
++  grub_exit (1);
+ }
+ 
+ void *
+@@ -154,6 +155,9 @@ void
+ __attribute__ ((noreturn))
+ grub_exit (int rc)
+ {
++#if defined (GRUB_KERNEL)
++  grub_reboot ();
++#endif
+   exit (rc < 0 ? 1 : rc);
+ }
+ #endif
+@@ -215,3 +219,15 @@ grub_util_load_image (const char *path, char *buf)
+ 
+   fclose (fp);
+ }
++
++void
++grub_util_set_kexecute (void)
++{
++  kexecute++;
++}
++
++int
++grub_util_get_kexecute (void)
++{
++  return kexecute;
++}
+diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c
+new file mode 100644
+index 0000000000..0cf378a376
+--- /dev/null
++++ b/grub-core/loader/emu/linux.c
+@@ -0,0 +1,178 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2022  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/loader.h>
++#include <grub/dl.h>
++#include <grub/command.h>
++#include <grub/time.h>
++
++#include <grub/emu/exec.h>
++#include <grub/emu/hostfile.h>
++#include <grub/emu/misc.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++static grub_dl_t my_mod;
++
++static char *kernel_path;
++static char *initrd_path;
++static char *boot_cmdline;
++
++static grub_err_t
++grub_linux_boot (void)
++{
++  grub_err_t rc = GRUB_ERR_NONE;
++  char *initrd_param;
++  const char *kexec[] = {"kexec", "-la", kernel_path, boot_cmdline, NULL, NULL};
++  const char *systemctl[] = {"systemctl", "kexec", NULL};
++  int kexecute = grub_util_get_kexecute ();
++
++  if (initrd_path)
++    {
++      initrd_param = grub_xasprintf ("--initrd=%s", initrd_path);
++      kexec[3] = initrd_param;
++      kexec[4] = boot_cmdline;
++    }
++  else
++    initrd_param = grub_xasprintf ("%s", "");
++
++  grub_dprintf ("linux", "%serforming 'kexec -la %s %s %s'\n",
++                (kexecute) ? "P" : "Not p",
++                kernel_path, initrd_param, boot_cmdline);
++
++  if (kexecute)
++    rc = grub_util_exec (kexec);
++
++  grub_free (initrd_param);
++
++  if (rc != GRUB_ERR_NONE)
++    {
++      grub_error (rc, N_("error trying to perform kexec load operation"));
++      grub_sleep (3);
++      return rc;
++    }
++
++  if (kexecute < 1)
++    grub_fatal (N_("use '"PACKAGE"-emu --kexec' to force a system restart"));
++
++  grub_dprintf ("linux", "Performing 'systemctl kexec' (%s) ",
++		(kexecute==1) ? "do-or-die" : "just-in-case");
++  rc = grub_util_exec (systemctl);
++
++  if (kexecute == 1)
++    grub_fatal (N_("error trying to perform 'systemctl kexec': %d"), rc);
++
++  /*
++   * WARNING: forcible reset should only be used in read-only environments.
++   * grub-emu cannot check for these - users beware.
++   */
++  grub_dprintf ("linux", "Performing 'kexec -ex'");
++  kexec[1] = "-ex";
++  kexec[2] = NULL;
++  rc = grub_util_exec (kexec);
++  if (rc != GRUB_ERR_NONE)
++    grub_fatal (N_("error trying to directly perform 'kexec -ex': %d"), rc);
++
++  return rc;
++}
++
++static grub_err_t
++grub_linux_unload (void)
++{
++  /* Unloading: we're no longer in use. */
++  grub_dl_unref (my_mod);
++  grub_free (boot_cmdline);
++  boot_cmdline = NULL;
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc,
++		char *argv[])
++{
++  int i;
++  char *tempstr;
++
++  /* Mark ourselves as in-use. */
++  grub_dl_ref (my_mod);
++
++  if (argc == 0)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
++
++  if (!grub_util_is_regular (argv[0]))
++    return grub_error (GRUB_ERR_FILE_NOT_FOUND,
++		       N_("cannot find kernel file %s"), argv[0]);
++
++  grub_free (kernel_path);
++  kernel_path = grub_xasprintf ("%s", argv[0]);
++
++  grub_free (boot_cmdline);
++  boot_cmdline = NULL;
++
++  if (argc > 1)
++    {
++      boot_cmdline = grub_xasprintf ("--command-line=%s", argv[1]);
++      for (i = 2; i < argc; i++)
++        {
++          tempstr = grub_xasprintf ("%s %s", boot_cmdline, argv[i]);
++          grub_free (boot_cmdline);
++          boot_cmdline = tempstr;
++        }
++    }
++
++  grub_loader_set (grub_linux_boot, grub_linux_unload, 0);
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc,
++		 char *argv[])
++{
++  if (argc == 0)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
++
++  if (!grub_util_is_regular (argv[0]))
++    return grub_error (GRUB_ERR_FILE_NOT_FOUND,
++		       N_("Cannot find initrd file %s"), argv[0]);
++
++  grub_free (initrd_path);
++  initrd_path = grub_xasprintf ("%s", argv[0]);
++
++  /* We are done - mark ourselves as on longer in use. */
++  grub_dl_unref (my_mod);
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_command_t cmd_linux, cmd_initrd;
++
++GRUB_MOD_INIT (linux)
++{
++  cmd_linux = grub_register_command ("linux", grub_cmd_linux, 0,
++				     N_("Load Linux."));
++  cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, 0,
++				      N_("Load initrd."));
++  my_mod = mod;
++}
++
++GRUB_MOD_FINI (linux)
++{
++  grub_unregister_command (cmd_linux);
++  grub_unregister_command (cmd_initrd);
++}
+diff --git a/include/grub/emu/exec.h b/include/grub/emu/exec.h
+index d1073ef86a..1b61b4a2e5 100644
+--- a/include/grub/emu/exec.h
++++ b/include/grub/emu/exec.h
+@@ -23,6 +23,8 @@
+ #include <stdarg.h>
+ 
+ #include <sys/types.h>
++#include <grub/symbol.h>
++
+ pid_t
+ grub_util_exec_pipe (const char *const *argv, int *fd);
+ pid_t
+@@ -32,7 +34,7 @@ int
+ grub_util_exec_redirect_all (const char *const *argv, const char *stdin_file,
+ 			     const char *stdout_file, const char *stderr_file);
+ int
+-grub_util_exec (const char *const *argv);
++EXPORT_FUNC(grub_util_exec) (const char *const *argv);
+ int
+ grub_util_exec_redirect (const char *const *argv, const char *stdin_file,
+ 			 const char *stdout_file);
+diff --git a/include/grub/emu/hostfile.h b/include/grub/emu/hostfile.h
+index cfb1e2b566..a61568e36e 100644
+--- a/include/grub/emu/hostfile.h
++++ b/include/grub/emu/hostfile.h
+@@ -22,6 +22,7 @@
+ #include <grub/disk.h>
+ #include <grub/partition.h>
+ #include <sys/types.h>
++#include <grub/symbol.h>
+ #include <grub/osdep/hostfile.h>
+ 
+ int
+@@ -29,7 +30,7 @@ grub_util_is_directory (const char *path);
+ int
+ grub_util_is_special_file (const char *path);
+ int
+-grub_util_is_regular (const char *path);
++EXPORT_FUNC(grub_util_is_regular) (const char *path);
+ 
+ char *
+ grub_util_path_concat (size_t n, ...);
+diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h
+index ff9c48a649..01056954b9 100644
+--- a/include/grub/emu/misc.h
++++ b/include/grub/emu/misc.h
+@@ -57,6 +57,9 @@ void EXPORT_FUNC(grub_util_warn) (const char *fmt, ...) __attribute__ ((format (
+ void EXPORT_FUNC(grub_util_info) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2)));
+ void EXPORT_FUNC(grub_util_error) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2), noreturn));
+ 
++void EXPORT_FUNC(grub_util_set_kexecute) (void);
++int EXPORT_FUNC(grub_util_get_kexecute) (void) WARN_UNUSED_RESULT;
++
+ grub_uint64_t EXPORT_FUNC (grub_util_get_cpu_time_ms) (void);
+ 
+ #ifdef HAVE_DEVICE_MAPPER
+diff --git a/docs/grub.texi b/docs/grub.texi
+index a4da9c2a1b..1750b72ee9 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -923,17 +923,17 @@ magic.
+ @node General boot methods
+ @section How to boot operating systems
+ 
+-GRUB has two distinct boot methods. One of the two is to load an
+-operating system directly, and the other is to chain-load another boot
+-loader which then will load an operating system actually. Generally
+-speaking, the former is more desirable, because you don't need to
+-install or maintain other boot loaders and GRUB is flexible enough to
+-load an operating system from an arbitrary disk/partition. However,
+-the latter is sometimes required, since GRUB doesn't support all the
+-existing operating systems natively.
++GRUB has three distinct boot methods: loading an operating system
++directly, using kexec from userspace, and chainloading another
++bootloader. Generally speaking, the first two are more desirable
++because you don't need to install or maintain other boot loaders and
++GRUB is flexible enough to load an operating system from an arbitrary
++disk/partition. However, chainloading is sometimes required, as GRUB
++doesn't support all existing operating systems natively.
+ 
+ @menu
+ * Loading an operating system directly::
++* Kexec::
+ * Chain-loading::
+ @end menu
+ 
+@@ -959,6 +959,20 @@ use more complicated instructions. @xref{DOS/Windows}, for more
+ information.
+ 
+ 
++@node Kexec
++@subsection Kexec with grub2-emu
++
++GRUB can be run in userspace by invoking the grub2-emu tool. It will
++read all configuration scripts as if booting directly (see @xref{Loading
++an operating system directly}). With the @code{--kexec} flag, and
++kexec(8) support from the operating system, the @command{linux} command
++will directly boot the target image. For systems that lack working
++systemctl(1) support for kexec, passing the @code{--kexec} flag twice
++will fallback to invoking kexec(8) directly; note however that this
++fallback may be unsafe outside read-only environments, as it does not
++invoke shutdown machinery.
++
++
+ @node Chain-loading
+ @subsection Chain-loading an OS
+ 
+diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
+index c2e8a82bce..dd49939aaa 100644
+--- a/grub-core/Makefile.am
++++ b/grub-core/Makefile.am
+@@ -309,6 +309,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/net.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostdisk.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostfile.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/exec.h
+ if COND_GRUB_EMU_SDL
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sdl.h
+ endif
diff --git a/SOURCES/0312-powerpc-Drop-Open-Hack-Ware-remove-GRUB_IEEE1275_FLA.patch b/SOURCES/0312-powerpc-Drop-Open-Hack-Ware-remove-GRUB_IEEE1275_FLA.patch
new file mode 100644
index 0000000..735075a
--- /dev/null
+++ b/SOURCES/0312-powerpc-Drop-Open-Hack-Ware-remove-GRUB_IEEE1275_FLA.patch
@@ -0,0 +1,111 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 6 Sep 2021 15:46:12 +1000
+Subject: [PATCH] powerpc: Drop Open Hack'Ware - remove
+ GRUB_IEEE1275_FLAG_FORCE_CLAIM
+
+Open Hack'Ware was the only user. It added a lot of complexity.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 333e63b356f1ce833cda1937ed8351618cbdf9d3)
+---
+ grub-core/kern/ieee1275/init.c            |  6 +-----
+ grub-core/lib/ieee1275/relocator.c        |  4 ----
+ grub-core/loader/powerpc/ieee1275/linux.c | 14 --------------
+ include/grub/ieee1275/ieee1275.h          | 11 -----------
+ 4 files changed, 1 insertion(+), 34 deletions(-)
+
+diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
+index 0dcd114ce5..6581c2c996 100644
+--- a/grub-core/kern/ieee1275/init.c
++++ b/grub-core/kern/ieee1275/init.c
+@@ -207,11 +207,7 @@ grub_claim_heap (void)
+ {
+   unsigned long total = 0;
+ 
+-  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM))
+-    heap_init (GRUB_IEEE1275_STATIC_HEAP_START, GRUB_IEEE1275_STATIC_HEAP_LEN,
+-	       1, &total);
+-  else
+-    grub_machine_mmap_iterate (heap_init, &total);
++  grub_machine_mmap_iterate (heap_init, &total);
+ }
+ #endif
+ 
+diff --git a/grub-core/lib/ieee1275/relocator.c b/grub-core/lib/ieee1275/relocator.c
+index c6dd8facb0..d1bb45c75e 100644
+--- a/grub-core/lib/ieee1275/relocator.c
++++ b/grub-core/lib/ieee1275/relocator.c
+@@ -38,8 +38,6 @@ grub_relocator_firmware_get_max_events (void)
+ {
+   int counter = 0;
+ 
+-  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM))
+-    return 0;
+   grub_machine_mmap_iterate (count, &counter);
+   return 2 * counter;
+ }
+@@ -92,8 +90,6 @@ grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events)
+     .counter = 0
+   };
+ 
+-  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM))
+-    return 0;
+   grub_machine_mmap_iterate (grub_relocator_firmware_fill_events_iter, &ctx);
+   return ctx.counter;
+ }
+diff --git a/grub-core/loader/powerpc/ieee1275/linux.c b/grub-core/loader/powerpc/ieee1275/linux.c
+index 818b2a86d1..6fdd863130 100644
+--- a/grub-core/loader/powerpc/ieee1275/linux.c
++++ b/grub-core/loader/powerpc/ieee1275/linux.c
+@@ -111,20 +111,6 @@ grub_linux_claimmap_iterate (grub_addr_t target, grub_size_t size,
+     .found_addr = (grub_addr_t) -1
+   };
+ 
+-  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM))
+-    {
+-      grub_uint64_t addr = target;
+-      if (addr < GRUB_IEEE1275_STATIC_HEAP_START
+-	  + GRUB_IEEE1275_STATIC_HEAP_LEN)
+-	addr = GRUB_IEEE1275_STATIC_HEAP_START
+-	  + GRUB_IEEE1275_STATIC_HEAP_LEN;
+-      addr = ALIGN_UP (addr, align);
+-      if (grub_claimmap (addr, size) == GRUB_ERR_NONE)
+-	return addr;
+-      return (grub_addr_t) -1;
+-    }
+-	
+-
+   grub_machine_mmap_iterate (alloc_mem, &ctx);
+ 
+   return ctx.found_addr;
+diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
+index b5a1d49bbc..6a1d3e5d70 100644
+--- a/include/grub/ieee1275/ieee1275.h
++++ b/include/grub/ieee1275/ieee1275.h
+@@ -85,14 +85,6 @@ extern grub_ieee1275_ihandle_t EXPORT_VAR(grub_ieee1275_mmu);
+ 
+ extern int (* EXPORT_VAR(grub_ieee1275_entry_fn)) (void *) GRUB_IEEE1275_ENTRY_FN_ATTRIBUTE;
+ 
+-/* Static heap, used only if FORCE_CLAIM is set,
+-   happens on Open Hack'Ware. Should be in platform-specific
+-   header but is used only on PPC anyway.
+-*/
+-#define GRUB_IEEE1275_STATIC_HEAP_START 0x1000000
+-#define GRUB_IEEE1275_STATIC_HEAP_LEN   0x1000000
+-
+-
+ enum grub_ieee1275_flag
+ {
+   /* Old World Macintosh firmware fails seek when "dev:0" is opened.  */
+@@ -119,9 +111,6 @@ enum grub_ieee1275_flag
+   /* Open Hack'Ware stops when grub_ieee1275_interpret is used.  */
+   GRUB_IEEE1275_FLAG_CANNOT_INTERPRET,
+ 
+-  /* Open Hack'Ware has no memory map, just claim what we need.  */
+-  GRUB_IEEE1275_FLAG_FORCE_CLAIM,
+-
+   /* Open Hack'Ware don't support the ANSI sequence.  */
+   GRUB_IEEE1275_FLAG_NO_ANSI,
+ 
diff --git a/SOURCES/0313-ieee1275-request-memory-with-ibm-client-architecture.patch b/SOURCES/0313-ieee1275-request-memory-with-ibm-client-architecture.patch
new file mode 100644
index 0000000..4e95630
--- /dev/null
+++ b/SOURCES/0313-ieee1275-request-memory-with-ibm-client-architecture.patch
@@ -0,0 +1,308 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 6 Feb 2023 10:03:20 -0500
+Subject: [PATCH] ieee1275: request memory with ibm,
+ client-architecture-support
+
+On PowerVM, the first time we boot a Linux partition, we may only get
+256MB of real memory area, even if the partition has more memory.
+
+This isn't enough to reliably verify a kernel. Fortunately, the Power
+Architecture Platform Reference (PAPR) defines a method we can call to ask
+for more memory: the broad and powerful ibm,client-architecture-support
+(CAS) method.
+
+CAS can do an enormous amount of things on a PAPR platform: as well as
+asking for memory, you can set the supported processor level, the interrupt
+controller, hash vs radix mmu, and so on.
+
+If:
+
+ - we are running under what we think is PowerVM (compatible property of /
+   begins with "IBM"), and
+
+ - the full amount of RMA is less than 512MB (as determined by the reg
+   property of /memory)
+
+then call CAS as follows: (refer to the Linux on Power Architecture
+Reference, LoPAR, which is public, at B.5.2.3):
+
+ - Use the "any" PVR value and supply 2 option vectors.
+
+ - Set option vector 1 (PowerPC Server Processor Architecture Level)
+   to "ignore".
+
+ - Set option vector 2 with default or Linux-like options, including a
+   min-rma-size of 512MB.
+
+ - Set option vector 3 to request Floating Point, VMX and Decimal Floating
+   point, but don't abort the boot if we can't get them.
+
+ - Set option vector 4 to request a minimum VP percentage to 1%, which is
+   what Linux requests, and is below the default of 10%. Without this,
+   some systems with very large or very small configurations fail to boot.
+
+This will cause a CAS reboot and the partition will restart with 512MB
+of RMA. Importantly, grub will notice the 512MB and not call CAS again.
+
+Notes about the choices of parameters:
+
+ - A partition can be configured with only 256MB of memory, which would
+   mean this request couldn't be satisfied, but PFW refuses to load with
+   only 256MB of memory, so it's a bit moot. SLOF will run fine with 256MB,
+   but we will never call CAS under qemu/SLOF because /compatible won't
+   begin with "IBM".)
+
+ - unspecified CAS vectors take on default values. Some of these values
+   might restrict the ability of certain hardware configurations to boot.
+   This is why we need to specify the VP percentage in vector 4, which is
+   in turn why we need to specify vector 3.
+
+Finally, we should have enough memory to verify a kernel, and we will
+reach Linux. One of the first things Linux does while still running under
+OpenFirmware is to call CAS with a much fuller set of options (including
+asking for 512MB of memory). Linux includes a much more restrictive set of
+PVR values and processor support levels, and this CAS invocation will likely
+induce another reboot. On this reboot grub will again notice the higher RMA,
+and not call CAS. We will get to Linux again, Linux will call CAS again, but
+because the values are now set for Linux this will not induce another CAS
+reboot and we will finally boot all the way to userspace.
+
+On all subsequent boots, everything will be configured with 512MB of RMA,
+so there will be no further CAS reboots from grub. (phyp is super sticky
+with the RMA size - it persists even on cold boots. So if you've ever booted
+Linux in a partition, you'll probably never have grub call CAS. It'll only
+ever fire the first time a partition loads grub, or if you deliberately lower
+the amount of memory your partition has below 512MB.)
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit d5571590b7de61887efac1c298901455697ba307)
+---
+ grub-core/kern/ieee1275/cmain.c  |   5 ++
+ grub-core/kern/ieee1275/init.c   | 167 ++++++++++++++++++++++++++++++++++++++-
+ include/grub/ieee1275/ieee1275.h |  12 ++-
+ 3 files changed, 182 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c
+index 04df9d2c66..dce7b84922 100644
+--- a/grub-core/kern/ieee1275/cmain.c
++++ b/grub-core/kern/ieee1275/cmain.c
+@@ -127,6 +127,11 @@ grub_ieee1275_find_options (void)
+ 	      break;
+ 	    }
+ 	}
++
++#if defined(__powerpc__)
++      if (grub_strncmp (tmp, "IBM,", 4) == 0)
++	grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY);
++#endif
+     }
+ 
+   if (is_smartfirmware)
+diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
+index 6581c2c996..8ae405bc79 100644
+--- a/grub-core/kern/ieee1275/init.c
++++ b/grub-core/kern/ieee1275/init.c
+@@ -202,11 +202,176 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
+   return 0;
+ }
+ 
+-static void 
++/*
++ * How much memory does OF believe it has? (regardless of whether
++ * it's accessible or not)
++ */
++static grub_err_t
++grub_ieee1275_total_mem (grub_uint64_t *total)
++{
++  grub_ieee1275_phandle_t root;
++  grub_ieee1275_phandle_t memory;
++  grub_uint32_t reg[4];
++  grub_ssize_t reg_size;
++  grub_uint32_t address_cells = 1;
++  grub_uint32_t size_cells = 1;
++  grub_uint64_t size;
++
++  /* If we fail to get to the end, report 0. */
++  *total = 0;
++
++  /* Determine the format of each entry in `reg'.  */
++  if (grub_ieee1275_finddevice ("/", &root))
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't find / node");
++  if (grub_ieee1275_get_integer_property (root, "#address-cells", &address_cells,
++					  sizeof (address_cells), 0))
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine #address-cells");
++  if (grub_ieee1275_get_integer_property (root, "#size-cells", &size_cells,
++					  sizeof (size_cells), 0))
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine #size-cells");
++
++  if (size_cells > address_cells)
++    address_cells = size_cells;
++
++  /* Load `/memory/reg'.  */
++  if (grub_ieee1275_finddevice ("/memory", &memory))
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't find /memory node");
++  if (grub_ieee1275_get_integer_property (memory, "reg", reg,
++					  sizeof (reg), &reg_size))
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine /memory/reg property");
++  if (reg_size < 0 || (grub_size_t) reg_size > sizeof (reg))
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "/memory response buffer exceeded");
++
++  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS))
++    {
++      address_cells = 1;
++      size_cells = 1;
++    }
++
++  /* Decode only the size */
++  size = reg[address_cells];
++  if (size_cells == 2)
++    size = (size << 32) | reg[address_cells + 1];
++
++  *total = size;
++
++  return grub_errno;
++}
++
++#if defined(__powerpc__)
++
++/* See PAPR or arch/powerpc/kernel/prom_init.c */
++struct option_vector2
++{
++  grub_uint8_t byte1;
++  grub_uint16_t reserved;
++  grub_uint32_t real_base;
++  grub_uint32_t real_size;
++  grub_uint32_t virt_base;
++  grub_uint32_t virt_size;
++  grub_uint32_t load_base;
++  grub_uint32_t min_rma;
++  grub_uint32_t min_load;
++  grub_uint8_t min_rma_percent;
++  grub_uint8_t max_pft_size;
++} GRUB_PACKED;
++
++struct pvr_entry
++{
++  grub_uint32_t mask;
++  grub_uint32_t entry;
++};
++
++struct cas_vector
++{
++  struct
++  {
++    struct pvr_entry terminal;
++  } pvr_list;
++  grub_uint8_t num_vecs;
++  grub_uint8_t vec1_size;
++  grub_uint8_t vec1;
++  grub_uint8_t vec2_size;
++  struct option_vector2 vec2;
++  grub_uint8_t vec3_size;
++  grub_uint16_t vec3;
++  grub_uint8_t vec4_size;
++  grub_uint16_t vec4;
++} GRUB_PACKED;
++
++/*
++ * Call ibm,client-architecture-support to try to get more RMA.
++ * We ask for 512MB which should be enough to verify a distro kernel.
++ * We ignore most errors: if we don't succeed we'll proceed with whatever
++ * memory we have.
++ */
++static void
++grub_ieee1275_ibm_cas (void)
++{
++  int rc;
++  grub_ieee1275_ihandle_t root;
++  struct cas_args
++  {
++    struct grub_ieee1275_common_hdr common;
++    grub_ieee1275_cell_t method;
++    grub_ieee1275_ihandle_t ihandle;
++    grub_ieee1275_cell_t cas_addr;
++    grub_ieee1275_cell_t result;
++  } args;
++  struct cas_vector vector =
++  {
++    .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */
++    .num_vecs = 4 - 1,
++    .vec1_size = 0,
++    .vec1 = 0x80, /* ignore */
++    .vec2_size = 1 + sizeof (struct option_vector2) - 2,
++    .vec2 = {
++      0, 0, -1, -1, -1, -1, -1, 512, -1, 0, 48
++    },
++    .vec3_size = 2 - 1,
++    .vec3 = 0x00e0, /* ask for FP + VMX + DFP but don't halt if unsatisfied */
++    .vec4_size = 2 - 1,
++    .vec4 = 0x0001, /* set required minimum capacity % to the lowest value */
++  };
++
++  INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2);
++  args.method = (grub_ieee1275_cell_t) "ibm,client-architecture-support";
++  rc = grub_ieee1275_open ("/", &root);
++  if (rc)
++    {
++      grub_error (GRUB_ERR_IO, "could not open root when trying to call CAS");
++      return;
++    }
++  args.ihandle = root;
++  args.cas_addr = (grub_ieee1275_cell_t) &vector;
++
++  grub_printf ("Calling ibm,client-architecture-support from grub...");
++  IEEE1275_CALL_ENTRY_FN (&args);
++  grub_printf ("done\n");
++
++  grub_ieee1275_close (root);
++}
++
++#endif /* __powerpc__ */
++
++static void
+ grub_claim_heap (void)
+ {
+   unsigned long total = 0;
+ 
++#if defined(__powerpc__)
++  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY))
++    {
++      grub_uint64_t rma_size;
++      grub_err_t err;
++
++      err = grub_ieee1275_total_mem (&rma_size);
++      /* if we have an error, don't call CAS, just hope for the best */
++      if (err == GRUB_ERR_NONE && rma_size < (512 * 1024 * 1024))
++	grub_ieee1275_ibm_cas ();
++    }
++#endif
++
+   grub_machine_mmap_iterate (heap_init, &total);
+ }
+ #endif
+diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
+index 6a1d3e5d70..560c968460 100644
+--- a/include/grub/ieee1275/ieee1275.h
++++ b/include/grub/ieee1275/ieee1275.h
+@@ -138,7 +138,17 @@ enum grub_ieee1275_flag
+ 
+   GRUB_IEEE1275_FLAG_RAW_DEVNAMES,
+   
+-  GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT
++  GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT,
++
++#if defined(__powerpc__)
++  /*
++   * On PFW, the first time we boot a Linux partition, we may only get 256MB of
++   * real memory area, even if the partition has more memory. Set this flag if
++   * we think we're running under PFW. Then, if this flag is set, and the RMA is
++   * only 256MB in size, try asking for more with CAS.
++   */
++  GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY,
++#endif
+ };
+ 
+ extern int EXPORT_FUNC(grub_ieee1275_test_flag) (enum grub_ieee1275_flag flag);
diff --git a/SOURCES/0314-ieee1275-drop-len-1-quirk-in-heap_init.patch b/SOURCES/0314-ieee1275-drop-len-1-quirk-in-heap_init.patch
new file mode 100644
index 0000000..4ce064b
--- /dev/null
+++ b/SOURCES/0314-ieee1275-drop-len-1-quirk-in-heap_init.patch
@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 6 Feb 2023 10:03:21 -0500
+Subject: [PATCH] ieee1275: drop len -= 1 quirk in heap_init
+
+This was apparently 'required by some firmware': commit dc9468500919
+("2007-02-12  Hollis Blanchard  <hollis@penguinppc.org>").
+
+It's not clear what firmware that was, and what platform from 14 years ago
+which exhibited the bug then is still both in use and buggy now.
+
+It doesn't cause issues on qemu (mac99 or pseries) or under PFW for Power8.
+
+I don't have access to old Mac hardware, but if anyone feels especially
+strongly we can put it under some feature flag. I really want to disable
+it under pseries because it will mess with region merging.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit fc639d430297321ee4f77c5d2d698f698cec0dc7)
+---
+ grub-core/kern/ieee1275/init.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
+index 8ae405bc79..c8d551759d 100644
+--- a/grub-core/kern/ieee1275/init.c
++++ b/grub-core/kern/ieee1275/init.c
+@@ -168,7 +168,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
+ 	  addr = 0x180000;
+ 	}
+     }
+-  len -= 1; /* Required for some firmware.  */
+ 
+   /* Never exceed HEAP_MAX_SIZE  */
+   if (*total + len > HEAP_MAX_SIZE)
diff --git a/SOURCES/0315-ieee1275-support-runtime-memory-claiming.patch b/SOURCES/0315-ieee1275-support-runtime-memory-claiming.patch
new file mode 100644
index 0000000..17ad61d
--- /dev/null
+++ b/SOURCES/0315-ieee1275-support-runtime-memory-claiming.patch
@@ -0,0 +1,435 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 6 Feb 2023 10:03:22 -0500
+Subject: [PATCH] ieee1275: support runtime memory claiming
+
+On powerpc-ieee1275, we are running out of memory trying to verify
+anything. This is because:
+
+ - we have to load an entire file into memory to verify it. This is
+   difficult to change with appended signatures.
+ - We only have 32MB of heap.
+ - Distro kernels are now often around 30MB.
+
+So we want to be able to claim more memory from OpenFirmware for our heap
+at runtime.
+
+There are some complications:
+
+ - The grub mm code isn't the only thing that will make claims on
+   memory from OpenFirmware:
+
+    * PFW/SLOF will have claimed some for their own use.
+
+    * The ieee1275 loader will try to find other bits of memory that we
+      haven't claimed to place the kernel and initrd when we go to boot.
+
+    * Once we load Linux, it will also try to claim memory. It claims
+      memory without any reference to /memory/available, it just starts
+      at min(top of RMO, 768MB) and works down. So we need to avoid this
+      area. See arch/powerpc/kernel/prom_init.c as of v5.11.
+
+ - The smallest amount of memory a ppc64 KVM guest can have is 256MB.
+   It doesn't work with distro kernels but can work with custom kernels.
+   We should maintain support for that. (ppc32 can boot with even less,
+   and we shouldn't break that either.)
+
+ - Even if a VM has more memory, the memory OpenFirmware makes available
+   as Real Memory Area can be restricted. Even with our CAS work, an LPAR
+   on a PowerVM box is likely to have only 512MB available to OpenFirmware
+   even if it has many gigabytes of memory allocated.
+
+What should we do?
+
+We don't know in advance how big the kernel and initrd are going to be,
+which makes figuring out how much memory we can take a bit tricky.
+
+To figure out how much memory we should leave unused, I looked at:
+
+ - an Ubuntu 20.04.1 ppc64le pseries KVM guest:
+    vmlinux: ~30MB
+    initrd:  ~50MB
+
+ - a RHEL8.2 ppc64le pseries KVM guest:
+    vmlinux: ~30MB
+    initrd:  ~30MB
+
+So to give us a little wriggle room, I think we want to leave at least
+128MB for the loader to put vmlinux and initrd in memory and leave Linux
+with space to satisfy its early allocations.
+
+Allow other space to be allocated at runtime.
+
+Tested-by: Stefan Berger <stefanb@linux.ibm.com>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+(cherry picked from commit a5c710789ccdd27a84ae4a34c7d453bd585e2b66)
+[rharwood: _start?]
+---
+ grub-core/kern/ieee1275/init.c | 270 ++++++++++++++++++++++++++++++++++++++---
+ docs/grub-dev.texi             |   7 +-
+ 2 files changed, 257 insertions(+), 20 deletions(-)
+
+diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
+index c8d551759d..85af8fa97b 100644
+--- a/grub-core/kern/ieee1275/init.c
++++ b/grub-core/kern/ieee1275/init.c
+@@ -46,13 +46,26 @@
+ #endif
+ #include <grub/lockdown.h>
+ 
+-/* The maximum heap size we're going to claim */
++/* The maximum heap size we're going to claim at boot. Not used by sparc. */
+ #ifdef __i386__
+ #define HEAP_MAX_SIZE		(unsigned long) (64 * 1024 * 1024)
+-#else
++#else /* __powerpc__ */
+ #define HEAP_MAX_SIZE		(unsigned long) (32 * 1024 * 1024)
+ #endif
+ 
++/* RMO max. address at 768 MB */
++#define RMO_ADDR_MAX		(grub_uint64_t) (768 * 1024 * 1024)
++
++/*
++ * The amount of OF space we will not claim here so as to leave space for
++ * the loader and linux to service early allocations.
++ *
++ * In 2021, Daniel Axtens claims that we should leave at least 128MB to
++ * ensure we can load a stock kernel and initrd on a pseries guest with
++ * a 512MB real memory area under PowerVM.
++ */
++#define RUNTIME_MIN_SPACE (128UL * 1024 * 1024)
++
+ extern char _end[];
+ 
+ #ifdef __sparc__
+@@ -147,16 +160,52 @@ grub_claim_heap (void)
+ 				 + GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000);
+ }
+ #else
+-/* Helper for grub_claim_heap.  */
++/* Helpers for mm on powerpc. */
++
++/*
++ * How much memory does OF believe exists in total?
++ *
++ * This isn't necessarily the true total. It can be the total memory
++ * accessible in real mode for a pseries guest, for example.
++ */
++static grub_uint64_t rmo_top;
++
+ static int
+-heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
+-	   void *data)
++count_free (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
++	    void *data)
+ {
+-  unsigned long *total = data;
++  if (type != GRUB_MEMORY_AVAILABLE)
++    return 0;
++
++  /* Do not consider memory beyond 4GB */
++  if (addr > 0xffffffffULL)
++    return 0;
++
++  if (addr + len > 0xffffffffULL)
++    len = 0xffffffffULL - addr;
++
++  *(grub_uint32_t *) data += len;
++
++  return 0;
++}
++
++static int
++regions_claim (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
++	      unsigned int flags, void *data)
++{
++  grub_uint32_t total = *(grub_uint32_t *) data;
++  grub_uint64_t linux_rmo_save;
+ 
+   if (type != GRUB_MEMORY_AVAILABLE)
+     return 0;
+ 
++  /* Do not consider memory beyond 4GB */
++  if (addr > 0xffffffffULL)
++    return 0;
++
++  if (addr + len > 0xffffffffULL)
++    len = 0xffffffffULL - addr;
++
+   if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM))
+     {
+       if (addr + len <= 0x180000)
+@@ -169,10 +218,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
+ 	}
+     }
+ 
+-  /* Never exceed HEAP_MAX_SIZE  */
+-  if (*total + len > HEAP_MAX_SIZE)
+-    len = HEAP_MAX_SIZE - *total;
+-
+   /* In theory, firmware should already prevent this from happening by not
+      listing our own image in /memory/available.  The check below is intended
+      as a safeguard in case that doesn't happen.  However, it doesn't protect
+@@ -184,6 +229,108 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
+       len = 0;
+     }
+ 
++  /*
++   * Linux likes to claim memory at min(RMO top, 768MB) and works down
++   * without reference to /memory/available. (See prom_init.c::alloc_down)
++   *
++   * If this block contains min(RMO top, 768MB), do not claim below that for
++   * at least a few MB (this is where RTAS, SML and potentially TCEs live).
++   *
++   * We also need to leave enough space for the DT in the RMA. (See
++   * prom_init.c::alloc_up)
++   *
++   * Finally, we also want to make sure that when grub loads the kernel,
++   * it isn't going to use up all the memory we're trying to reserve! So
++   * enforce our entire RUNTIME_MIN_SPACE here:
++   *
++   * |---------- Top of memory ----------|
++   * |                                   |
++   * |             available             |
++   * |                                   |
++   * |----------     768 MB    ----------|
++   * |                                   |
++   * |              reserved             |
++   * |                                   |
++   * |--- 768 MB - runtime min space  ---|
++   * |                                   |
++   * |             available             |
++   * |                                   |
++   * |----------      0 MB     ----------|
++   *
++   * Edge cases:
++   *
++   * - Total memory less than RUNTIME_MIN_SPACE: only claim up to HEAP_MAX_SIZE.
++   *   (enforced elsewhere)
++   *
++   * - Total memory between RUNTIME_MIN_SPACE and 768MB:
++   *
++   * |---------- Top of memory ----------|
++   * |                                   |
++   * |              reserved             |
++   * |                                   |
++   * |----  top - runtime min space  ----|
++   * |                                   |
++   * |             available             |
++   * |                                   |
++   * |----------      0 MB     ----------|
++   *
++   * This by itself would not leave us with RUNTIME_MIN_SPACE of free bytes: if
++   * rmo_top < 768MB, we will almost certainly have FW claims in the reserved
++   * region. We try to address that elsewhere: grub_ieee1275_mm_add_region will
++   * not call us if the resulting free space would be less than RUNTIME_MIN_SPACE.
++   */
++  linux_rmo_save = grub_min (RMO_ADDR_MAX, rmo_top) - RUNTIME_MIN_SPACE;
++  if (rmo_top > RUNTIME_MIN_SPACE)
++    {
++      if (rmo_top <= RMO_ADDR_MAX)
++        {
++          if (addr > linux_rmo_save)
++            {
++              grub_dprintf ("ieee1275", "rejecting region in RUNTIME_MIN_SPACE reservation (%llx)\n",
++                            addr);
++              return 0;
++            }
++          else if (addr + len > linux_rmo_save)
++            {
++              grub_dprintf ("ieee1275", "capping region: (%llx -> %llx) -> (%llx -> %llx)\n",
++                            addr, addr + len, addr, rmo_top - RUNTIME_MIN_SPACE);
++              len = linux_rmo_save - addr;
++            }
++        }
++      else
++        {
++          /*
++           * we order these cases to prefer higher addresses and avoid some
++           * splitting issues
++           */
++          if (addr < RMO_ADDR_MAX && (addr + len) > RMO_ADDR_MAX)
++            {
++              grub_dprintf ("ieee1275",
++                            "adjusting region for RUNTIME_MIN_SPACE: (%llx -> %llx) -> (%llx -> %llx)\n",
++                            addr, addr + len, RMO_ADDR_MAX, addr + len);
++              len = (addr + len) - RMO_ADDR_MAX;
++              addr = RMO_ADDR_MAX;
++            }
++          else if ((addr < linux_rmo_save) && ((addr + len) > linux_rmo_save))
++            {
++              grub_dprintf ("ieee1275", "capping region: (%llx -> %llx) -> (%llx -> %llx)\n",
++                            addr, addr + len, addr, linux_rmo_save);
++              len = linux_rmo_save - addr;
++            }
++          else if (addr >= linux_rmo_save && (addr + len) <= RMO_ADDR_MAX)
++            {
++              grub_dprintf ("ieee1275", "rejecting region in RUNTIME_MIN_SPACE reservation (%llx)\n",
++                            addr);
++              return 0;
++            }
++        }
++    }
++  if (flags & GRUB_MM_ADD_REGION_CONSECUTIVE && len < total)
++    return 0;
++
++  if (len > total)
++    len = total;
++
+   if (len)
+     {
+       grub_err_t err;
+@@ -192,15 +339,95 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
+       if (err)
+ 	return err;
+       grub_mm_init_region ((void *) (grub_addr_t) addr, len);
++      total -= len;
+     }
+ 
+-  *total += len;
+-  if (*total >= HEAP_MAX_SIZE)
++  *(grub_uint32_t *) data = total;
++
++  if (total == 0)
+     return 1;
+ 
+   return 0;
+ }
+ 
++static int
++heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
++	   void *data)
++{
++  return regions_claim (addr, len, type, GRUB_MM_ADD_REGION_NONE, data);
++}
++
++static int
++region_claim (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type,
++	   void *data)
++{
++  return regions_claim (addr, len, type, GRUB_MM_ADD_REGION_CONSECUTIVE, data);
++}
++
++static grub_err_t
++grub_ieee1275_mm_add_region (grub_size_t size, unsigned int flags)
++{
++  grub_uint32_t free_memory = 0;
++  grub_uint32_t avail = 0;
++  grub_uint32_t total;
++
++  grub_dprintf ("ieee1275", "mm requested region of size %x, flags %x\n",
++               size, flags);
++
++  /*
++   * Update free memory each time, which is a bit inefficient but guards us
++   * against a situation where some OF driver goes out to firmware for
++   * memory and we don't realise.
++   */
++  grub_machine_mmap_iterate (count_free, &free_memory);
++
++  /* Ensure we leave enough space to boot. */
++  if (free_memory <= RUNTIME_MIN_SPACE + size)
++    {
++      grub_dprintf ("ieee1275", "Cannot satisfy allocation and retain minimum runtime space\n");
++      return GRUB_ERR_OUT_OF_MEMORY;
++    }
++
++  if (free_memory > RUNTIME_MIN_SPACE)
++      avail = free_memory - RUNTIME_MIN_SPACE;
++
++  grub_dprintf ("ieee1275", "free = 0x%x available = 0x%x\n", free_memory, avail);
++
++  if (flags & GRUB_MM_ADD_REGION_CONSECUTIVE)
++    {
++      /* first try rounding up hard for the sake of speed */
++      total = grub_max (ALIGN_UP (size, 1024 * 1024) + 1024 * 1024, 32 * 1024 * 1024);
++      total = grub_min (avail, total);
++
++      grub_dprintf ("ieee1275", "looking for %x bytes of memory (%x requested)\n", total, size);
++
++      grub_machine_mmap_iterate (region_claim, &total);
++      grub_dprintf ("ieee1275", "get memory from fw %s\n", total == 0 ? "succeeded" : "failed");
++
++      if (total != 0)
++        {
++          total = grub_min (avail, size);
++
++          grub_dprintf ("ieee1275", "fallback for %x bytes of memory (%x requested)\n", total, size);
++
++          grub_machine_mmap_iterate (region_claim, &total);
++          grub_dprintf ("ieee1275", "fallback from fw %s\n", total == 0 ? "succeeded" : "failed");
++        }
++    }
++  else
++    {
++      /* provide padding for a grub_mm_header_t and region */
++      total = grub_min (avail, size);
++      grub_machine_mmap_iterate (heap_init, &total);
++      grub_dprintf ("ieee1275", "get noncontig memory from fw %s\n", total == 0 ? "succeeded" : "failed");
++    }
++
++  if (total == 0)
++    return GRUB_ERR_NONE;
++  else
++    return GRUB_ERR_OUT_OF_MEMORY;
++}
++
+ /*
+  * How much memory does OF believe it has? (regardless of whether
+  * it's accessible or not)
+@@ -356,17 +583,24 @@ grub_ieee1275_ibm_cas (void)
+ static void
+ grub_claim_heap (void)
+ {
+-  unsigned long total = 0;
++  grub_err_t err;
++  grub_uint32_t total = HEAP_MAX_SIZE;
++
++  err = grub_ieee1275_total_mem (&rmo_top);
++
++  /*
++   * If we cannot size the available memory, we can't be sure we're leaving
++   * space for the kernel, initrd and things Linux loads early in boot. So only
++   * allow further allocations from firmware on success
++   */
++  if (err == GRUB_ERR_NONE)
++    grub_mm_add_region_fn = grub_ieee1275_mm_add_region;
+ 
+ #if defined(__powerpc__)
+   if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY))
+     {
+-      grub_uint64_t rma_size;
+-      grub_err_t err;
+-
+-      err = grub_ieee1275_total_mem (&rma_size);
+       /* if we have an error, don't call CAS, just hope for the best */
+-      if (err == GRUB_ERR_NONE && rma_size < (512 * 1024 * 1024))
++      if (err == GRUB_ERR_NONE && rmo_top < (512 * 1024 * 1024))
+ 	grub_ieee1275_ibm_cas ();
+     }
+ #endif
+diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
+index 7b2455a8fe..7edc5b7e2b 100644
+--- a/docs/grub-dev.texi
++++ b/docs/grub-dev.texi
+@@ -1047,7 +1047,10 @@ space is limited to 4GiB. GRUB allocates pages from EFI for its heap, at most
+ 1.6 GiB.
+ 
+ On i386-ieee1275 and powerpc-ieee1275 GRUB uses same stack as IEEE1275.
+-It allocates at most 32MiB for its heap.
++
++On i386-ieee1275 and powerpc-ieee1275, GRUB will allocate 32MiB for its heap on
++startup. It may allocate more at runtime, as long as at least 128MiB remain free
++in OpenFirmware.
+ 
+ On sparc64-ieee1275 stack is 256KiB and heap is 2MiB.
+ 
+@@ -1075,7 +1078,7 @@ In short:
+ @item i386-qemu               @tab 60 KiB  @tab < 4 GiB
+ @item *-efi                   @tab ?       @tab < 1.6 GiB
+ @item i386-ieee1275           @tab ?       @tab < 32 MiB
+-@item powerpc-ieee1275        @tab ?       @tab < 32 MiB
++@item powerpc-ieee1275        @tab ?       @tab available memory - 128MiB
+ @item sparc64-ieee1275        @tab 256KiB  @tab 2 MiB
+ @item arm-uboot               @tab 256KiB  @tab 2 MiB
+ @item mips(el)-qemu_mips      @tab 2MiB    @tab 253 MiB
diff --git a/SOURCES/0316-ieee1275-implement-vec5-for-cas-negotiation.patch b/SOURCES/0316-ieee1275-implement-vec5-for-cas-negotiation.patch
new file mode 100644
index 0000000..fad39db
--- /dev/null
+++ b/SOURCES/0316-ieee1275-implement-vec5-for-cas-negotiation.patch
@@ -0,0 +1,74 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Diego Domingos <diegodo@linux.vnet.ibm.com>
+Date: Mon, 6 Feb 2023 10:03:23 -0500
+Subject: [PATCH] ieee1275: implement vec5 for cas negotiation
+
+As a legacy support, if the vector 5 is not implemented, Power Hypervisor will
+consider the max CPUs as 64 instead 256 currently supported during
+client-architecture-support negotiation.
+
+This patch implements the vector 5 and set the MAX CPUs to 256 while setting the
+others values to 0 (default).
+
+Signed-off-by: Diego Domingos <diegodo@linux.vnet.ibm.com>
+Acked-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
+Signed-off-by: Avnish Chouhan <avnish@linux.vnet.ibm.com>
+(cherry picked from commit 942f19959fe7465fb52a1da39ff271a7ab704892)
+---
+ grub-core/kern/ieee1275/init.c | 21 ++++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
+index 85af8fa97b..72d4fed312 100644
+--- a/grub-core/kern/ieee1275/init.c
++++ b/grub-core/kern/ieee1275/init.c
+@@ -502,6 +502,19 @@ struct option_vector2
+   grub_uint8_t max_pft_size;
+ } GRUB_PACKED;
+ 
++struct option_vector5
++{
++  grub_uint8_t byte1;
++  grub_uint8_t byte2;
++  grub_uint8_t byte3;
++  grub_uint8_t cmo;
++  grub_uint8_t associativity;
++  grub_uint8_t bin_opts;
++  grub_uint8_t micro_checkpoint;
++  grub_uint8_t reserved0;
++  grub_uint32_t max_cpus;
++} GRUB_PACKED;
++
+ struct pvr_entry
+ {
+   grub_uint32_t mask;
+@@ -523,6 +536,8 @@ struct cas_vector
+   grub_uint16_t vec3;
+   grub_uint8_t vec4_size;
+   grub_uint16_t vec4;
++  grub_uint8_t vec5_size;
++  struct option_vector5 vec5;
+ } GRUB_PACKED;
+ 
+ /*
+@@ -547,7 +562,7 @@ grub_ieee1275_ibm_cas (void)
+   struct cas_vector vector =
+   {
+     .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */
+-    .num_vecs = 4 - 1,
++    .num_vecs = 5 - 1,
+     .vec1_size = 0,
+     .vec1 = 0x80, /* ignore */
+     .vec2_size = 1 + sizeof (struct option_vector2) - 2,
+@@ -558,6 +573,10 @@ grub_ieee1275_ibm_cas (void)
+     .vec3 = 0x00e0, /* ask for FP + VMX + DFP but don't halt if unsatisfied */
+     .vec4_size = 2 - 1,
+     .vec4 = 0x0001, /* set required minimum capacity % to the lowest value */
++    .vec5_size = 1 + sizeof (struct option_vector5) - 2,
++    .vec5 = {
++      0, 192, 0, 128, 0, 0, 0, 0, 256
++    }
+   };
+ 
+   INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2);
diff --git a/SOURCES/0317-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch b/SOURCES/0317-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch
new file mode 100644
index 0000000..02c0282
--- /dev/null
+++ b/SOURCES/0317-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch
@@ -0,0 +1,246 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Stefan Berger <stefanb@linux.ibm.com>
+Date: Mon, 6 Feb 2023 10:03:25 -0500
+Subject: [PATCH] ibmvtpm: Add support for trusted boot using a vTPM 2.0
+
+Add support for trusted boot using a vTPM 2.0 on the IBM IEEE1275
+PowerPC platform. With this patch grub now measures text and binary data
+into the TPM's PCRs 8 and 9 in the same way as the x86_64 platform
+does.
+
+This patch requires Daniel Axtens's patches for claiming more memory.
+
+Note: The tpm_init() function cannot be called from GRUB_MOD_INIT() since
+it does not find the device nodes upon module initialization and
+therefore the call to tpm_init() must be deferred to grub_tpm_measure().
+
+For vTPM support to work on PowerVM, system driver levels 1010.30
+or 1020.00 are required.
+
+Note: Previous versions of firmware levels with the 2hash-ext-log
+API call have a bug that, once this API call is invoked, has the
+effect of disabling the vTPM driver under Linux causing an error
+message to be displayed in the Linux kernel log. Those users will
+have to update their machines to the firmware levels mentioned
+above.
+
+Cc: Eric Snowberg <eric.snowberg@oracle.com>
+Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 2aa5ef83743dfea79377309ff4f5e9c9a55de355)
+---
+ grub-core/Makefile.core.def           |   7 ++
+ grub-core/commands/ieee1275/ibmvtpm.c | 155 ++++++++++++++++++++++++++++++++++
+ include/grub/ieee1275/ieee1275.h      |   3 +
+ docs/grub.texi                        |   3 +-
+ 4 files changed, 167 insertions(+), 1 deletion(-)
+ create mode 100644 grub-core/commands/ieee1275/ibmvtpm.c
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index f21da23213..02ea718652 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -1175,6 +1175,13 @@ module = {
+   enable = powerpc_ieee1275;
+ };
+ 
++module = {
++  name = tpm;
++  common = commands/tpm.c;
++  ieee1275 = commands/ieee1275/ibmvtpm.c;
++  enable = powerpc_ieee1275;
++};
++
+ module = {
+   name = terminal;
+   common = commands/terminal.c;
+diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c
+new file mode 100644
+index 0000000000..239942d27e
+--- /dev/null
++++ b/grub-core/commands/ieee1275/ibmvtpm.c
+@@ -0,0 +1,155 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2022  Free Software Foundation, Inc.
++ *  Copyright (C) 2022  IBM Corporation
++ *
++ *  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/>.
++ *
++ *  IBM vTPM support code.
++ */
++
++#include <grub/err.h>
++#include <grub/types.h>
++#include <grub/tpm.h>
++#include <grub/ieee1275/ieee1275.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++
++static grub_ieee1275_ihandle_t tpm_ihandle;
++static grub_uint8_t tpm_version;
++
++#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t) 0)
++
++static void
++tpm_get_tpm_version (void)
++{
++  grub_ieee1275_phandle_t vtpm;
++  char buffer[20];
++
++  if (!grub_ieee1275_finddevice ("/vdevice/vtpm", &vtpm) &&
++      !grub_ieee1275_get_property (vtpm, "compatible", buffer,
++				   sizeof (buffer), NULL) &&
++      !grub_strcmp (buffer, "IBM,vtpm20"))
++    tpm_version = 2;
++}
++
++static grub_err_t
++tpm_init (void)
++{
++  static int init_success = 0;
++
++  if (!init_success)
++    {
++      if (grub_ieee1275_open ("/vdevice/vtpm", &tpm_ihandle) < 0)
++	{
++	  tpm_ihandle = IEEE1275_IHANDLE_INVALID;
++	  return GRUB_ERR_UNKNOWN_DEVICE;
++	}
++
++      init_success = 1;
++
++      tpm_get_tpm_version ();
++    }
++
++  return GRUB_ERR_NONE;
++}
++
++static int
++ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
++		       grub_uint32_t eventtype,
++		       const char *description,
++		       grub_size_t description_size,
++		       void *buf, grub_size_t size)
++{
++  struct tpm_2hash_ext_log
++  {
++    struct grub_ieee1275_common_hdr common;
++    grub_ieee1275_cell_t method;
++    grub_ieee1275_cell_t ihandle;
++    grub_ieee1275_cell_t size;
++    grub_ieee1275_cell_t buf;
++    grub_ieee1275_cell_t description_size;
++    grub_ieee1275_cell_t description;
++    grub_ieee1275_cell_t eventtype;
++    grub_ieee1275_cell_t pcrindex;
++    grub_ieee1275_cell_t catch_result;
++    grub_ieee1275_cell_t rc;
++  };
++  struct tpm_2hash_ext_log args;
++
++  INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2);
++  args.method = (grub_ieee1275_cell_t) "2hash-ext-log";
++  args.ihandle = tpm_ihandle;
++  args.pcrindex = pcrindex;
++  args.eventtype = eventtype;
++  args.description = (grub_ieee1275_cell_t) description;
++  args.description_size = description_size;
++  args.buf = (grub_ieee1275_cell_t) buf;
++  args.size = (grub_ieee1275_cell_t) size;
++
++  if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
++    return -1;
++
++  /*
++   * catch_result is set if firmware does not support 2hash-ext-log
++   * rc is GRUB_IEEE1275_CELL_FALSE (0) on failure
++   */
++  if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE)
++    return -1;
++
++  return 0;
++}
++
++static grub_err_t
++tpm2_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
++		const char *description)
++{
++  static int error_displayed = 0;
++  int rc;
++
++  rc = ibmvtpm_2hash_ext_log (pcr, EV_IPL,
++			      description, grub_strlen(description) + 1,
++			      buf, size);
++  if (rc && !error_displayed)
++    {
++      error_displayed++;
++      return grub_error (GRUB_ERR_BAD_DEVICE,
++			 "2HASH-EXT-LOG failed: Firmware is likely too old.\n");
++    }
++
++  return GRUB_ERR_NONE;
++}
++
++grub_err_t
++grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
++		  const char *description)
++{
++  /*
++   * Call tpm_init() 'late' rather than from GRUB_MOD_INIT() so that device nodes
++   * can be found.
++   */
++  grub_err_t err = tpm_init ();
++
++  /* Absence of a TPM isn't a failure. */
++  if (err != GRUB_ERR_NONE)
++    return GRUB_ERR_NONE;
++
++  grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n",
++		pcr, size, description);
++
++  if (tpm_version == 2)
++    return tpm2_log_event (buf, size, pcr, description);
++
++  return GRUB_ERR_NONE;
++}
+diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
+index 560c968460..27b9cf259b 100644
+--- a/include/grub/ieee1275/ieee1275.h
++++ b/include/grub/ieee1275/ieee1275.h
+@@ -24,6 +24,9 @@
+ #include <grub/types.h>
+ #include <grub/machine/ieee1275.h>
+ 
++#define GRUB_IEEE1275_CELL_FALSE       ((grub_ieee1275_cell_t) 0)
++#define GRUB_IEEE1275_CELL_TRUE        ((grub_ieee1275_cell_t) -1)
++
+ struct grub_ieee1275_mem_region
+ {
+   unsigned int start;
+diff --git a/docs/grub.texi b/docs/grub.texi
+index 1750b72ee9..825278a7f3 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -6235,7 +6235,8 @@ tpm module is loaded. As such it is recommended that the tpm module be built
+ into @file{core.img} in order to avoid a potential gap in measurement between
+ @file{core.img} being loaded and the tpm module being loaded.
+ 
+-Measured boot is currently only supported on EFI platforms.
++Measured boot is currently only supported on EFI and IBM IEEE1275 PowerPC
++platforms.
+ 
+ @node Lockdown
+ @section Lockdown when booting on a secure setup
diff --git a/SOURCES/0318-powerpc-Drop-Open-Hack-Ware.patch b/SOURCES/0318-powerpc-Drop-Open-Hack-Ware.patch
new file mode 100644
index 0000000..1d201d3
--- /dev/null
+++ b/SOURCES/0318-powerpc-Drop-Open-Hack-Ware.patch
@@ -0,0 +1,69 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Mon, 6 Sep 2021 15:46:11 +1000
+Subject: [PATCH] powerpc: Drop Open Hack'Ware
+
+Open Hack'Ware was an alternative firmware of powerpc under QEMU.
+
+The last commit to any Open Hack'Ware repo I can find is from 2014 [1].
+
+Open Hack'Ware was used for the QEMU "prep" machine type, which was
+deprecated in QEMU in commit 54c86f5a4844 (hw/ppc: deprecate the
+machine type 'prep', replaced by '40p') in QEMU v3.1, and had reportedly
+been broken for years before without anyone noticing. Support was removed
+in February 2020 by commit b2ce76a0730e (hw/ppc/prep: Remove the
+deprecated "prep" machine and the OpenHackware BIOS).
+
+Open Hack'Ware's limitations require some messy code in GRUB. This
+complexity is not worth carrying any more.
+
+Remove detection of Open Hack'Ware. We will clean up the feature flags
+in following commits.
+
+[1]: https://github.com/qemu/openhackware and
+     https://repo.or.cz/w/openhackware.git are QEMU submodules. They have
+     only small changes on top of OHW v0.4.1, which was imported into
+     QEMU SCM in 2010. I can't find anything resembling an official repo
+     any more.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit f9ce538eec88c5cffbfde021c4e8a95a5e9d0e8f)
+---
+ grub-core/kern/ieee1275/cmain.c | 16 ----------------
+ 1 file changed, 16 deletions(-)
+
+diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c
+index dce7b84922..cb42f60ebe 100644
+--- a/grub-core/kern/ieee1275/cmain.c
++++ b/grub-core/kern/ieee1275/cmain.c
+@@ -49,7 +49,6 @@ grub_ieee1275_find_options (void)
+   grub_ieee1275_phandle_t root;
+   grub_ieee1275_phandle_t options;
+   grub_ieee1275_phandle_t openprom;
+-  grub_ieee1275_phandle_t bootrom;
+   int rc;
+   grub_uint32_t realmode = 0;
+   char tmp[256];
+@@ -198,21 +197,6 @@ grub_ieee1275_find_options (void)
+ 
+       grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_HAS_CURSORONOFF);
+     }
+-
+-  if (! grub_ieee1275_finddevice ("/rom/boot-rom", &bootrom)
+-      || ! grub_ieee1275_finddevice ("/boot-rom", &bootrom))
+-    {
+-      rc = grub_ieee1275_get_property (bootrom, "model", tmp, sizeof (tmp), 0);
+-      if (rc >= 0 && !grub_strncmp (tmp, "PPC Open Hack'Ware",
+-				    sizeof ("PPC Open Hack'Ware") - 1))
+-	{
+-	  grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_BROKEN_OUTPUT);
+-	  grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CANNOT_SET_COLORS);
+-	  grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET);
+-	  grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM);
+-	  grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_ANSI);
+-	}
+-    }
+ }
+ 
+ void
diff --git a/SOURCES/0319-osdep-linux-hostdisk-Modify-sector-by-sysfs-as-disk-.patch b/SOURCES/0319-osdep-linux-hostdisk-Modify-sector-by-sysfs-as-disk-.patch
new file mode 100644
index 0000000..6e7b17f
--- /dev/null
+++ b/SOURCES/0319-osdep-linux-hostdisk-Modify-sector-by-sysfs-as-disk-.patch
@@ -0,0 +1,70 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Mukesh Kumar Chaurasiya <mchauras@linux.vnet.ibm.com>
+Date: Thu, 9 Feb 2023 13:09:16 +0530
+Subject: [PATCH] osdep/linux/hostdisk: Modify sector by sysfs as disk sector
+
+The disk sector size provided by sysfs file system considers the sector
+size of 512 irrespective of disk sector size, thus causing the read by
+the GRUB to an incorrect offset from what was originally intended.
+
+Considering the 512 sector size of sysfs data the actual sector needs to
+be modified corresponding to disk sector size.
+
+Signed-off-by: Mukesh Kumar Chaurasiya <mchauras@linux.vnet.ibm.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit f7564844f82b57078d601befadc438b5bc1fa01b)
+---
+ grub-core/osdep/linux/hostdisk.c | 7 ++++---
+ include/grub/disk.h              | 7 +++++++
+ 2 files changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/osdep/linux/hostdisk.c b/grub-core/osdep/linux/hostdisk.c
+index 7bc99ac1c1..a9ea0bb465 100644
+--- a/grub-core/osdep/linux/hostdisk.c
++++ b/grub-core/osdep/linux/hostdisk.c
+@@ -240,7 +240,8 @@ have_devfs (void)
+ #pragma GCC diagnostic ignored "-Wformat-nonliteral"
+ 
+ static int
+-grub_hostdisk_linux_find_partition (char *dev, grub_disk_addr_t sector)
++grub_hostdisk_linux_find_partition (const grub_disk_t disk, char *dev,
++                                    grub_disk_addr_t sector)
+ {
+   size_t len = strlen (dev);
+   const char *format;
+@@ -305,7 +306,7 @@ grub_hostdisk_linux_find_partition (char *dev, grub_disk_addr_t sector)
+       if (fstat (fd, &st) < 0
+ 	  || !grub_util_device_is_mapped_stat (&st)
+ 	  || !grub_util_get_dm_node_linear_info (st.st_rdev, 0, 0, &start))
+-	start = grub_util_find_partition_start_os (real_dev);
++	start = grub_disk_to_native_sector (disk, grub_util_find_partition_start_os (real_dev));
+       /* We don't care about errors here.  */
+       grub_errno = GRUB_ERR_NONE;
+ 
+@@ -386,7 +387,7 @@ grub_util_fd_open_device (const grub_disk_t disk, grub_disk_addr_t sector, int f
+ 	&& strncmp (dev, "/dev/", 5) == 0)
+       {
+ 	if (sector >= part_start)
+-	  is_partition = grub_hostdisk_linux_find_partition (dev, part_start);
++	  is_partition = grub_hostdisk_linux_find_partition (disk, dev, part_start);
+ 	else
+ 	  *max = part_start - sector;
+       }
+diff --git a/include/grub/disk.h b/include/grub/disk.h
+index 06210a7049..881addcc77 100644
+--- a/include/grub/disk.h
++++ b/include/grub/disk.h
+@@ -208,6 +208,13 @@ grub_disk_from_native_sector (grub_disk_t disk, grub_disk_addr_t sector)
+   return sector << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
+ }
+ 
++/* Convert from GRUB native disk sized sector to disk sized sector. */
++static inline grub_disk_addr_t
++grub_disk_to_native_sector (grub_disk_t disk, grub_disk_addr_t sector)
++{
++  return sector >> (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
++}
++
+ /* This is called from the memory manager.  */
+ void grub_disk_cache_invalidate_all (void);
+ 
diff --git a/SOURCES/0320-mm-Adjust-new-region-size-to-take-management-overhea.patch b/SOURCES/0320-mm-Adjust-new-region-size-to-take-management-overhea.patch
new file mode 100644
index 0000000..456f8f7
--- /dev/null
+++ b/SOURCES/0320-mm-Adjust-new-region-size-to-take-management-overhea.patch
@@ -0,0 +1,145 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Sun, 29 Jan 2023 19:49:31 +0800
+Subject: [PATCH] mm: Adjust new region size to take management overhead into
+ account
+
+When grub_memalign() encounters out-of-memory, it will try
+grub_mm_add_region_fn() to request more memory from system firmware.
+However, the size passed to it doesn't take region management overhead
+into account. Adding a memory area of "size" bytes may result in a heap
+region of less than "size" bytes really available. Thus, the new region
+may not be adequate for current allocation request, confusing
+out-of-memory handling code.
+
+This patch introduces GRUB_MM_MGMT_OVERHEAD to address the region
+management overhead (e.g. metadata, padding). The value of this new
+constant must be large enough to make sure grub_memalign(align, size)
+always succeeds after a successful call to
+  grub_mm_init_region(addr, size + align + GRUB_MM_MGMT_OVERHEAD),
+for any given addr and size (assuming no integer overflow).
+
+The size passed to grub_mm_add_region_fn() is now correctly adjusted,
+thus if grub_mm_add_region_fn() succeeded, current allocation request
+can always succeed.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 2282cbfe5aa1ff6c1bbcbdcd2003089ad7c03ba3)
+---
+ grub-core/kern/mm.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 61 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
+index da1ac9427c..f29a3e5cbd 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -83,6 +83,46 @@
+ 
+ 
+ 
++/*
++ * GRUB_MM_MGMT_OVERHEAD is an upper bound of management overhead of
++ * each region, with any possible padding taken into account.
++ *
++ * The value must be large enough to make sure grub_memalign(align, size)
++ * always succeeds after a successful call to
++ * grub_mm_init_region(addr, size + align + GRUB_MM_MGMT_OVERHEAD),
++ * for any given addr, align and size (assuming no interger overflow).
++ *
++ * The worst case which has maximum overhead is shown in the figure below:
++ *
++ * +-- addr
++ * v                                           |<- size + align ->|
++ * +---------+----------------+----------------+------------------+---------+
++ * | padding | grub_mm_region | grub_mm_header |   usable bytes   | padding |
++ * +---------+----------------+----------------+------------------+---------+
++ * |<-  a  ->|<-     b      ->|<-     c      ->|<-      d       ->|<-  e  ->|
++ *                                             ^
++ *    b == sizeof (struct grub_mm_region)      | / Assuming no other suitable
++ *    c == sizeof (struct grub_mm_header)      | | block is available, then:
++ *    d == size + align                        +-| If align == 0, this will be
++ *                                               | the pointer returned by next
++ * Assuming addr % GRUB_MM_ALIGN == 1, then:     | grub_memalign(align, size).
++ *    a == GRUB_MM_ALIGN - 1                     | If align > 0, this chunk may
++ *                                               | need to be split to fulfill
++ * Assuming d % GRUB_MM_ALIGN == 1, then:        | alignment requirements, and
++ *    e == GRUB_MM_ALIGN - 1                     | the returned pointer may be
++ *                                               \ inside these usable bytes.
++ * Therefore, the maximum overhead is:
++ *    a + b + c + e == (GRUB_MM_ALIGN - 1) + sizeof (struct grub_mm_region)
++ *                     + sizeof (struct grub_mm_header) + (GRUB_MM_ALIGN - 1)
++ */
++#define GRUB_MM_MGMT_OVERHEAD	((GRUB_MM_ALIGN - 1) \
++				 + sizeof (struct grub_mm_region) \
++				 + sizeof (struct grub_mm_header) \
++				 + (GRUB_MM_ALIGN - 1))
++
++/* The size passed to grub_mm_add_region_fn() is aligned up by this value. */
++#define GRUB_MM_HEAP_GROW_ALIGN	4096
++
+ grub_mm_region_t grub_mm_base;
+ grub_mm_add_region_func_t grub_mm_add_region_fn;
+ 
+@@ -230,6 +270,11 @@ grub_mm_init_region (void *addr, grub_size_t size)
+ 
+   grub_dprintf ("regions", "No: considering a new region at %p of size %" PRIxGRUB_SIZE "\n",
+ 		addr, size);
++  /*
++   * If you want to modify the code below, please also take a look at
++   * GRUB_MM_MGMT_OVERHEAD and make sure it is synchronized with the code.
++   */
++
+   /* Allocate a region from the head.  */
+   r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN);
+ 
+@@ -410,6 +455,7 @@ grub_memalign (grub_size_t align, grub_size_t size)
+ {
+   grub_mm_region_t r;
+   grub_size_t n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + 1;
++  grub_size_t grow;
+   int count = 0;
+ 
+   if (!grub_mm_base)
+@@ -418,10 +464,22 @@ grub_memalign (grub_size_t align, grub_size_t size)
+   if (size > ~(grub_size_t) align)
+     goto fail;
+ 
++  /*
++   * Pre-calculate the necessary size of heap growth (if applicable),
++   * with region management overhead taken into account.
++   */
++  if (grub_add (size + align, GRUB_MM_MGMT_OVERHEAD, &grow))
++    goto fail;
++
++  /* Align up heap growth to make it friendly to CPU/MMU. */
++  if (grow > ~(grub_size_t) (GRUB_MM_HEAP_GROW_ALIGN - 1))
++    goto fail;
++  grow = ALIGN_UP (grow, GRUB_MM_HEAP_GROW_ALIGN);
++
+   /* We currently assume at least a 32-bit grub_size_t,
+      so limiting allocations to <adress space size> - 1MiB
+      in name of sanity is beneficial. */
+-  if ((size + align) > ~(grub_size_t) 0x100000)
++  if (grow > ~(grub_size_t) 0x100000)
+     goto fail;
+ 
+   align = (align >> GRUB_MM_ALIGN_LOG2);
+@@ -447,7 +505,7 @@ grub_memalign (grub_size_t align, grub_size_t size)
+       count++;
+ 
+       if (grub_mm_add_region_fn != NULL &&
+-          grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE)
++          grub_mm_add_region_fn (grow, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE)
+ 	goto again;
+ 
+       /* fallthrough  */
+@@ -462,7 +520,7 @@ grub_memalign (grub_size_t align, grub_size_t size)
+            * Try again even if this fails, in case it was able to partially
+            * satisfy the request
+            */
+-          grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_NONE);
++          grub_mm_add_region_fn (grow, GRUB_MM_ADD_REGION_NONE);
+           goto again;
+         }
+ 
diff --git a/SOURCES/0321-mm-Preallocate-some-space-when-adding-new-regions.patch b/SOURCES/0321-mm-Preallocate-some-space-when-adding-new-regions.patch
new file mode 100644
index 0000000..291092d
--- /dev/null
+++ b/SOURCES/0321-mm-Preallocate-some-space-when-adding-new-regions.patch
@@ -0,0 +1,53 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Sun, 29 Jan 2023 19:49:32 +0800
+Subject: [PATCH] mm: Preallocate some space when adding new regions
+
+When grub_memalign() encounters out-of-memory, it will try
+grub_mm_add_region_fn() to request more memory from system firmware.
+However, it doesn't preallocate memory space for future allocation
+requests. In extreme cases, it requires one call to
+grub_mm_add_region_fn() for each memory allocation request. This can
+be very slow.
+
+This patch introduces GRUB_MM_HEAP_GROW_EXTRA, the minimal heap growth
+granularity. The new region size is now set to the bigger one of its
+original value and GRUB_MM_HEAP_GROW_EXTRA. Thus, it will result in some
+memory space preallocated if current allocations request is small.
+
+The value of GRUB_MM_HEAP_GROW_EXTRA is set to 1MB. If this value is
+smaller, the cost of small memory allocations will be higher. If this
+value is larger, more memory will be wasted and it might cause
+out-of-memory on machines with small amount of RAM.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 21869baec15239b6d99122b32b14a778af4c754f)
+---
+ grub-core/kern/mm.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
+index f29a3e5cbd..cc8a4703bc 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -123,6 +123,9 @@
+ /* The size passed to grub_mm_add_region_fn() is aligned up by this value. */
+ #define GRUB_MM_HEAP_GROW_ALIGN	4096
+ 
++/* Minimal heap growth granularity when existing heap space is exhausted. */
++#define GRUB_MM_HEAP_GROW_EXTRA	0x100000
++
+ grub_mm_region_t grub_mm_base;
+ grub_mm_add_region_func_t grub_mm_add_region_fn;
+ 
+@@ -471,6 +474,9 @@ grub_memalign (grub_size_t align, grub_size_t size)
+   if (grub_add (size + align, GRUB_MM_MGMT_OVERHEAD, &grow))
+     goto fail;
+ 
++  /* Preallocate some extra space if heap growth is small. */
++  grow = grub_max (grow, GRUB_MM_HEAP_GROW_EXTRA);
++
+   /* Align up heap growth to make it friendly to CPU/MMU. */
+   if (grow > ~(grub_size_t) (GRUB_MM_HEAP_GROW_ALIGN - 1))
+     goto fail;
diff --git a/SOURCES/0322-mm-Avoid-complex-heap-growth-math-in-hot-path.patch b/SOURCES/0322-mm-Avoid-complex-heap-growth-math-in-hot-path.patch
new file mode 100644
index 0000000..fe6b3e1
--- /dev/null
+++ b/SOURCES/0322-mm-Avoid-complex-heap-growth-math-in-hot-path.patch
@@ -0,0 +1,72 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zhang Boyang <zhangboyang.id@gmail.com>
+Date: Sun, 29 Jan 2023 19:49:33 +0800
+Subject: [PATCH] mm: Avoid complex heap growth math in hot path
+
+We do a lot of math about heap growth in hot path of grub_memalign().
+However, the result is only used if out of memory is encountered, which
+is seldom.
+
+This patch moves these calculations away from hot path. These
+calculations are now only done if out of memory is encountered. This
+change can also help compiler to optimize integer overflow checks away.
+
+Signed-off-by: Zhang Boyang <zhangboyang.id@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+(cherry picked from commit 65bc45963014773e2062ccc63ff34a089d2e352e)
+---
+ grub-core/kern/mm.c | 34 ++++++++++++++++++++--------------
+ 1 file changed, 20 insertions(+), 14 deletions(-)
+
+diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
+index cc8a4703bc..630d7be0e2 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -467,20 +467,7 @@ grub_memalign (grub_size_t align, grub_size_t size)
+   if (size > ~(grub_size_t) align)
+     goto fail;
+ 
+-  /*
+-   * Pre-calculate the necessary size of heap growth (if applicable),
+-   * with region management overhead taken into account.
+-   */
+-  if (grub_add (size + align, GRUB_MM_MGMT_OVERHEAD, &grow))
+-    goto fail;
+-
+-  /* Preallocate some extra space if heap growth is small. */
+-  grow = grub_max (grow, GRUB_MM_HEAP_GROW_EXTRA);
+-
+-  /* Align up heap growth to make it friendly to CPU/MMU. */
+-  if (grow > ~(grub_size_t) (GRUB_MM_HEAP_GROW_ALIGN - 1))
+-    goto fail;
+-  grow = ALIGN_UP (grow, GRUB_MM_HEAP_GROW_ALIGN);
++  grow = size + align;
+ 
+   /* We currently assume at least a 32-bit grub_size_t,
+      so limiting allocations to <adress space size> - 1MiB
+@@ -510,6 +497,25 @@ grub_memalign (grub_size_t align, grub_size_t size)
+       /* Request additional pages, contiguous */
+       count++;
+ 
++      /*
++       * Calculate the necessary size of heap growth (if applicable),
++       * with region management overhead taken into account.
++       */
++      if (grub_add (grow, GRUB_MM_MGMT_OVERHEAD, &grow))
++	goto fail;
++
++      /* Preallocate some extra space if heap growth is small. */
++      grow = grub_max (grow, GRUB_MM_HEAP_GROW_EXTRA);
++
++      /* Align up heap growth to make it friendly to CPU/MMU. */
++      if (grow > ~(grub_size_t) (GRUB_MM_HEAP_GROW_ALIGN - 1))
++	goto fail;
++      grow = ALIGN_UP (grow, GRUB_MM_HEAP_GROW_ALIGN);
++
++      /* Do the same sanity check again. */
++      if (grow > ~(grub_size_t) 0x100000)
++	goto fail;
++
+       if (grub_mm_add_region_fn != NULL &&
+           grub_mm_add_region_fn (grow, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE)
+ 	goto again;
diff --git a/SOURCES/701-ca.cer b/SOURCES/701-ca.cer
deleted file mode 100644
index 0e6e79b..0000000
Binary files a/SOURCES/701-ca.cer and /dev/null differ
diff --git a/SOURCES/701-cer.cer b/SOURCES/701-cer.cer
deleted file mode 100644
index 25e3743..0000000
Binary files a/SOURCES/701-cer.cer and /dev/null differ
diff --git a/SOURCES/grub.macros b/SOURCES/grub.macros
index 62ed7b6..4a2883d 100755
--- a/SOURCES/grub.macros
+++ b/SOURCES/grub.macros
@@ -9,11 +9,14 @@
 %global _configure ../configure
 
 %if %{?_with_ccache: 1}%{?!_with_ccache: 0}
-%global cc_equals CC=/usr/%{_lib}/ccache/gcc
+%global ccpath /usr/%{_lib}/ccache/gcc
 %else
-%global cc_equals %{nil}
+%global ccpath %{__cc}
 %endif
 
+# gnulib actively ignores CFLAGS because it's terrible
+%global cc_equals "CC=%{ccpath} -fPIE -Wl,-z,noexecstack"
+
 %global cflags_sed						\\\
 	sed							\\\
 		-e 's/-O. //g'					\\\
@@ -122,7 +125,7 @@
 %endif
 
 %ifarch ppc64le
-%global platform_modules " appendedsig tpm "
+%global platform_modules " appendedsig ofnet tpm "
 %endif
 
 %ifarch aarch64 %{arm} riscv64
@@ -322,6 +325,7 @@ git commit -a -q -m "%{tarversion} baseline."			\
 #git apply --index --whitespace=nowarn %{SOURCE3}		\
 #git commit -a -q -m "%{tarversion} master."			\
 git am --whitespace=nowarn %%{patches} </dev/null		\
+rm -r build-aux m4						\
 ./bootstrap							\
 %{nil}
 
diff --git a/SOURCES/grub.patches b/SOURCES/grub.patches
index e38c069..510ab16 100644
--- a/SOURCES/grub.patches
+++ b/SOURCES/grub.patches
@@ -20,287 +20,303 @@ Patch0019: 0019-Add-fw_path-variable-revised.patch
 Patch0020: 0020-Pass-x-hex-hex-straight-through-unmolested.patch
 Patch0021: 0021-blscfg-add-blscfg-module-to-parse-Boot-Loader-Specif.patch
 Patch0022: 0022-Add-devicetree-loading.patch
-Patch0023: 0023-Don-t-write-messages-to-the-screen.patch
-Patch0024: 0024-Don-t-print-GNU-GRUB-header.patch
-Patch0025: 0025-Don-t-add-to-highlighted-row.patch
-Patch0026: 0026-Message-string-cleanups.patch
-Patch0027: 0027-Fix-border-spacing-now-that-we-aren-t-displaying-it.patch
-Patch0028: 0028-Use-the-correct-indentation-for-the-term-help-text.patch
-Patch0029: 0029-Indent-menu-entries.patch
-Patch0030: 0030-Fix-margins.patch
-Patch0031: 0031-Use-2-instead-of-1-for-our-right-hand-margin-so-line.patch
-Patch0032: 0032-Enable-pager-by-default.-985860.patch
-Patch0033: 0033-F10-doesn-t-work-on-serial-so-don-t-tell-the-user-to.patch
-Patch0034: 0034-Don-t-say-GNU-Linux-in-generated-menus.patch
-Patch0035: 0035-Don-t-draw-a-border-around-the-menu.patch
-Patch0036: 0036-Use-the-standard-margin-for-the-timeout-string.patch
-Patch0037: 0037-Add-.eh_frame-to-list-of-relocations-stripped.patch
-Patch0038: 0038-Don-t-require-a-password-to-boot-entries-generated-b.patch
-Patch0039: 0039-Don-t-emit-Booting-.-message.patch
-Patch0040: 0040-Replace-a-lot-of-man-pages-with-slightly-nicer-ones.patch
-Patch0041: 0041-use-fw_path-prefix-when-fallback-searching-for-grub-.patch
-Patch0042: 0042-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch
-Patch0043: 0043-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch
-Patch0044: 0044-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch
-Patch0045: 0045-Try-prefix-if-fw_path-doesn-t-work.patch
-Patch0046: 0046-Use-Distribution-Package-Sort-for-grub2-mkconfig-112.patch
-Patch0047: 0047-Make-grub2-mkconfig-construct-titles-that-look-like-.patch
-Patch0048: 0048-Add-friendly-grub2-password-config-tool-985962.patch
-Patch0049: 0049-tcp-add-window-scaling-support.patch
-Patch0050: 0050-efinet-and-bootp-add-support-for-dhcpv6.patch
-Patch0051: 0051-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch
-Patch0052: 0052-bz1374141-fix-incorrect-mask-for-ppc64.patch
-Patch0053: 0053-Make-grub_fatal-also-backtrace.patch
-Patch0054: 0054-Fix-up-some-man-pages-rpmdiff-noticed.patch
-Patch0055: 0055-Make-our-info-pages-say-grub2-where-appropriate.patch
-Patch0056: 0056-macos-just-build-chainloader-entries-don-t-try-any-x.patch
-Patch0057: 0057-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch
-Patch0058: 0058-export-btrfs_subvol-and-btrfs_subvolid.patch
-Patch0059: 0059-grub2-btrfs-03-follow_default.patch
-Patch0060: 0060-grub2-btrfs-04-grub2-install.patch
-Patch0061: 0061-grub2-btrfs-05-grub2-mkconfig.patch
-Patch0062: 0062-grub2-btrfs-06-subvol-mount.patch
-Patch0063: 0063-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch
-Patch0064: 0064-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch
-Patch0065: 0065-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch
-Patch0066: 0066-Use-grub_efi_.-memory-helpers-where-reasonable.patch
-Patch0067: 0067-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch
-Patch0068: 0068-don-t-use-int-for-efi-status.patch
-Patch0069: 0069-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch
-Patch0070: 0070-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch
-Patch0071: 0071-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch
-Patch0072: 0072-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch
-Patch0073: 0073-align-struct-efi_variable-better.patch
-Patch0074: 0074-Add-BLS-support-to-grub-mkconfig.patch
-Patch0075: 0075-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch
-Patch0076: 0076-Add-linux-and-initrd-commands-for-grub-emu.patch
-Patch0077: 0077-Add-grub2-switch-to-blscfg.patch
-Patch0078: 0078-make-better-backtraces.patch
-Patch0079: 0079-normal-don-t-draw-our-startup-message-if-debug-is-se.patch
-Patch0080: 0080-Work-around-some-minor-include-path-weirdnesses.patch
-Patch0081: 0081-Make-it-possible-to-enabled-build-id-sha1.patch
-Patch0082: 0082-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch
-Patch0083: 0083-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch
-Patch0084: 0084-Fixup-for-newer-compiler.patch
-Patch0085: 0085-Don-t-attempt-to-export-the-start-and-_start-symbols.patch
-Patch0086: 0086-Fixup-for-newer-compiler.patch
-Patch0087: 0087-Add-support-for-non-Ethernet-network-cards.patch
-Patch0088: 0088-net-read-bracketed-ipv6-addrs-and-port-numbers.patch
-Patch0089: 0089-bootp-New-net_bootp6-command.patch
-Patch0090: 0090-efinet-UEFI-IPv6-PXE-support.patch
-Patch0091: 0091-grub.texi-Add-net_bootp6-doument.patch
-Patch0092: 0092-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch
-Patch0093: 0093-efinet-Setting-network-from-UEFI-device-path.patch
-Patch0094: 0094-efinet-Setting-DNS-server-from-UEFI-protocol.patch
-Patch0095: 0095-Support-UEFI-networking-protocols.patch
-Patch0096: 0096-AUDIT-0-http-boot-tracker-bug.patch
-Patch0097: 0097-grub-editenv-Add-incr-command-to-increment-integer-v.patch
-Patch0098: 0098-Add-auto-hide-menu-support.patch
-Patch0099: 0099-Add-grub-set-bootflag-utility.patch
-Patch0100: 0100-docs-Add-grub-boot-indeterminate.service-example.patch
-Patch0101: 0101-gentpl-add-disable-support.patch
-Patch0102: 0102-gentpl-add-pc-firmware-type.patch
-Patch0103: 0103-efinet-also-use-the-firmware-acceleration-for-http.patch
-Patch0104: 0104-efi-http-Make-root_url-reflect-the-protocol-hostname.patch
-Patch0105: 0105-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch
-Patch0106: 0106-module-verifier-make-it-possible-to-run-checkers-on-.patch
-Patch0107: 0107-Rework-how-the-fdt-command-builds.patch
-Patch0108: 0108-Disable-non-wordsize-allocations-on-arm.patch
-Patch0109: 0109-Prepend-prefix-when-HTTP-path-is-relative.patch
-Patch0110: 0110-Make-grub_error-more-verbose.patch
-Patch0111: 0111-Make-reset-an-alias-for-the-reboot-command.patch
-Patch0112: 0112-Add-a-version-command.patch
-Patch0113: 0113-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch
-Patch0114: 0114-arm-arm64-loader-Better-memory-allocation-and-error-.patch
-Patch0115: 0115-Try-to-pick-better-locations-for-kernel-and-initrd.patch
-Patch0116: 0116-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch
-Patch0117: 0117-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch
-Patch0118: 0118-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch
-Patch0119: 0119-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch
-Patch0120: 0120-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch
-Patch0121: 0121-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch
-Patch0122: 0122-Fix-getroot.c-s-trampolines.patch
-Patch0123: 0123-Do-not-allow-stack-trampolines-anywhere.patch
-Patch0124: 0124-Reimplement-boot_counter.patch
-Patch0125: 0125-Fix-menu-entry-selection-based-on-ID-and-title.patch
-Patch0126: 0126-Make-the-menu-entry-users-option-argument-to-be-opti.patch
-Patch0127: 0127-Add-efi-export-env-and-efi-load-env-commands.patch
-Patch0128: 0128-Make-it-possible-to-subtract-conditions-from-debug.patch
-Patch0129: 0129-Export-all-variables-from-the-initial-context-when-c.patch
-Patch0130: 0130-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch
-Patch0131: 0131-Fix-systemctl-kexec-exit-status-check.patch
-Patch0132: 0132-Print-grub-emu-linux-loader-messages-as-debug.patch
-Patch0133: 0133-Don-t-assume-that-boot-commands-will-only-return-on-.patch
-Patch0134: 0134-Fix-undefined-references-for-fdt-when-building-with-.patch
-Patch0135: 0135-Do-better-in-bootstrap.conf.patch
-Patch0136: 0136-Use-git-to-apply-gnulib-patches.patch
-Patch0137: 0137-Fix-build-error-with-the-fdt-module-on-risc-v.patch
-Patch0138: 0138-grub-set-bootflag-Update-comment-about-running-as-ro.patch
-Patch0139: 0139-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch
-Patch0140: 0140-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch
-Patch0141: 0141-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch
-Patch0142: 0142-chainloader-Define-machine-types-for-RISC-V.patch
-Patch0143: 0143-Add-start-symbol-for-RISC-V.patch
-Patch0144: 0144-bootstrap.conf-Force-autogen.sh-to-use-python3.patch
-Patch0145: 0145-efi-http-Export-fw-http-_path-variables-to-make-them.patch
-Patch0146: 0146-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch
-Patch0147: 0147-efi-net-Allow-to-specify-a-port-number-in-addresses.patch
-Patch0148: 0148-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch
-Patch0149: 0149-efi-net-Print-a-debug-message-if-parsing-the-address.patch
-Patch0150: 0150-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch
-Patch0151: 0151-efi-Set-image-base-address-before-jumping-to-the-PE-.patch
-Patch0152: 0152-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch
-Patch0153: 0153-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch
-Patch0154: 0154-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch
-Patch0155: 0155-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch
-Patch0156: 0156-efi-dhcp-fix-some-allocation-error-checking.patch
-Patch0157: 0157-efi-http-fix-some-allocation-error-checking.patch
-Patch0158: 0158-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch
-Patch0159: 0159-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch
-Patch0160: 0160-linuxefi-fail-kernel-validation-without-shim-protoco.patch
-Patch0161: 0161-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch
-Patch0162: 0162-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch
-Patch0163: 0163-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch
-Patch0164: 0164-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch
-Patch0165: 0165-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch
-Patch0166: 0166-Add-systemd-integration-scripts-to-make-systemctl-re.patch
-Patch0167: 0167-systemd-integration.sh-Also-set-old-menu_show_once-g.patch
-Patch0168: 0168-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch
-Patch0169: 0169-grub-install-disable-support-for-EFI-platforms.patch
-Patch0170: 0170-New-with-debug-timestamps-configure-flag-to-prepend-.patch
-Patch0171: 0171-Added-debug-statements-to-grub_disk_open-and-grub_di.patch
-Patch0172: 0172-Introduce-function-grub_debug_is_enabled-void-return.patch
-Patch0173: 0173-Don-t-clear-screen-when-debugging-is-enabled.patch
-Patch0174: 0174-grub_file_-instrumentation-new-file-debug-tag.patch
-Patch0175: 0175-ieee1275-Avoiding-many-unecessary-open-close.patch
-Patch0176: 0176-ieee1275-powerpc-implements-fibre-channel-discovery-.patch
-Patch0177: 0177-ieee1275-powerpc-enables-device-mapper-discovery.patch
-Patch0178: 0178-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch
-Patch0179: 0179-Add-suport-for-signing-grub-with-an-appended-signatu.patch
-Patch0180: 0180-docs-grub-Document-signing-grub-under-UEFI.patch
-Patch0181: 0181-docs-grub-Document-signing-grub-with-an-appended-sig.patch
-Patch0182: 0182-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch
-Patch0183: 0183-pgp-factor-out-rsa_pad.patch
-Patch0184: 0184-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch
-Patch0185: 0185-posix_wrap-tweaks-in-preparation-for-libtasn1.patch
-Patch0186: 0186-libtasn1-import-libtasn1-4.16.0.patch
-Patch0187: 0187-libtasn1-disable-code-not-needed-in-grub.patch
-Patch0188: 0188-libtasn1-changes-for-grub-compatibility.patch
-Patch0189: 0189-libtasn1-compile-into-asn1-module.patch
-Patch0190: 0190-test_asn1-test-module-for-libtasn1.patch
-Patch0191: 0191-grub-install-support-embedding-x509-certificates.patch
-Patch0192: 0192-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch
-Patch0193: 0193-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch
-Patch0194: 0194-appended-signatures-support-verifying-appended-signa.patch
-Patch0195: 0195-appended-signatures-verification-tests.patch
-Patch0196: 0196-appended-signatures-documentation.patch
-Patch0197: 0197-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch
-Patch0198: 0198-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch
-Patch0199: 0199-ieee1275-claim-more-memory.patch
-Patch0200: 0200-ieee1275-request-memory-with-ibm-client-architecture.patch
-Patch0201: 0201-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch
-Patch0202: 0202-ieee1275-ofdisk-retry-on-open-failure.patch
-Patch0203: 0203-01_menu_auto_hide.in-fix-a-then-than-typo.patch
-Patch0204: 0204-Fix-disabling-grub-rpm-sort.patch
-Patch0205: 0205-Don-t-check-for-rpmvercmp-in-librpm.patch
-Patch0206: 0206-Allow-chainloading-EFI-apps-from-loop-mounts.patch
-Patch0207: 0207-efinet-Add-DHCP-proxy-support.patch
-Patch0208: 0208-fs-ext2-Ignore-checksum-seed-incompat-feature.patch
-Patch0209: 0209-Don-t-update-the-cmdline-when-generating-legacy-menu.patch
-Patch0210: 0210-Suppress-gettext-error-message.patch
-Patch0211: 0211-grub-boot-success.timer-Only-run-if-not-in-a-contain.patch
-Patch0212: 0212-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch
-Patch0213: 0213-Remove-outdated-URL-for-BLS-document.patch
-Patch0214: 0214-templates-Check-for-EFI-at-runtime-instead-of-config.patch
-Patch0215: 0215-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch
-Patch0216: 0216-arm64-Fix-EFI-loader-kernel-image-allocation.patch
-Patch0217: 0217-normal-main-Discover-the-device-to-read-the-config-f.patch
-Patch0218: 0218-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch
-Patch0219: 0219-powerpc-fix-prefix-signed-grub-special-case-for-Powe.patch
-Patch0220: 0220-Arm-check-for-the-PE-magic-for-the-compiled-arch.patch
-Patch0221: 0221-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch
-Patch0222: 0222-Print-module-name-on-license-check-failure.patch
-Patch0223: 0223-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch
-Patch0224: 0224-grub-mkconfig-restore-umask-for-grub.cfg.patch
-Patch0225: 0225-commands-search-Fix-bug-stopping-iteration-when-no-f.patch
-Patch0226: 0226-search-new-efidisk-only-option-on-EFI-systems.patch
-Patch0227: 0227-efi-new-connectefi-command.patch
-Patch0228: 0228-powerpc-do-CAS-in-a-more-compatible-way.patch
-Patch0229: 0229-powerpc-prefix-detection-support-device-names-with-c.patch
-Patch0230: 0230-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch
-Patch0231: 0231-make-ofdisk_retries-optional.patch
-Patch0232: 0232-loader-efi-chainloader-grub_load_and_start_image-doe.patch
-Patch0233: 0233-loader-efi-chainloader-simplify-the-loader-state.patch
-Patch0234: 0234-commands-boot-Add-API-to-pass-context-to-loader.patch
-Patch0235: 0235-loader-efi-chainloader-Use-grub_loader_set_ex.patch
-Patch0236: 0236-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch
-Patch0237: 0237-loader-i386-efi-linux-Use-grub_loader_set_ex.patch
-Patch0238: 0238-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch
-Patch0239: 0239-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch
-Patch0240: 0240-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch
-Patch0241: 0241-video-readers-png-Abort-sooner-if-a-read-operation-f.patch
-Patch0242: 0242-video-readers-png-Refuse-to-handle-multiple-image-he.patch
-Patch0243: 0243-video-readers-png-Drop-greyscale-support-to-fix-heap.patch
-Patch0244: 0244-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch
-Patch0245: 0245-video-readers-png-Sanity-check-some-huffman-codes.patch
-Patch0246: 0246-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch
-Patch0247: 0247-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch
-Patch0248: 0248-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch
-Patch0249: 0249-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch
-Patch0250: 0250-normal-charset-Fix-array-out-of-bounds-formatting-un.patch
-Patch0251: 0251-net-netbuff-Block-overly-large-netbuff-allocs.patch
-Patch0252: 0252-net-ip-Do-IP-fragment-maths-safely.patch
-Patch0253: 0253-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch
-Patch0254: 0254-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch
-Patch0255: 0255-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch
-Patch0256: 0256-net-tftp-Avoid-a-trivial-UAF.patch
-Patch0257: 0257-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch
-Patch0258: 0258-net-http-Fix-OOB-write-for-split-http-headers.patch
-Patch0259: 0259-net-http-Error-out-on-headers-with-LF-without-CR.patch
-Patch0260: 0260-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch
-Patch0261: 0261-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch
-Patch0262: 0262-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch
-Patch0263: 0263-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch
-Patch0264: 0264-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch
-Patch0265: 0265-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch
-Patch0266: 0266-misc-Make-grub_min-and-grub_max-more-resilient.patch
-Patch0267: 0267-ReiserFS-switch-to-using-grub_min-grub_max.patch
-Patch0268: 0268-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch
-Patch0269: 0269-modules-make-.module_license-read-only.patch
-Patch0270: 0270-modules-strip-.llvm_addrsig-sections-and-similar.patch
-Patch0271: 0271-modules-Don-t-allocate-space-for-non-allocable-secti.patch
-Patch0272: 0272-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch
-Patch0273: 0273-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch
-Patch0274: 0274-modules-load-module-sections-at-page-aligned-address.patch
-Patch0275: 0275-nx-add-memory-attribute-get-set-API.patch
-Patch0276: 0276-nx-set-page-permissions-for-loaded-modules.patch
-Patch0277: 0277-nx-set-attrs-in-our-kernel-loaders.patch
-Patch0278: 0278-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch
-Patch0279: 0279-Make-debug-file-show-which-file-filters-get-run.patch
-Patch0280: 0280-efi-make-the-default-arena-most-of-ram.patch
-Patch0281: 0281-efi-use-enumerated-array-positions-for-our-allocatio.patch
-Patch0282: 0282-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch
-Patch0283: 0283-efi-allocate-the-initrd-within-the-bounds-expressed-.patch
-Patch0284: 0284-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch
-Patch0285: 0285-BLS-create-etc-kernel-cmdline-during-mkconfig.patch
-Patch0286: 0286-ieee1275-implement-vec5-for-cas-negotiation.patch
-Patch0287: 0287-squish-don-t-dup-rhgb-quiet-check-mtimes.patch
-Patch0288: 0288-squish-give-up-on-rhgb-quiet.patch
-Patch0289: 0289-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch
-Patch0290: 0290-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch
-Patch0291: 0291-commands-efi-tpm-Refine-the-status-of-log-event.patch
-Patch0292: 0292-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch
-Patch0293: 0293-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch
-Patch0294: 0294-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch
-Patch0295: 0295-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch
-Patch0296: 0296-font-Fix-several-integer-overflows-in-grub_font_cons.patch
-Patch0297: 0297-font-Remove-grub_font_dup_glyph.patch
-Patch0298: 0298-font-Fix-integer-overflow-in-ensure_comb_space.patch
-Patch0299: 0299-font-Fix-integer-overflow-in-BMP-index.patch
-Patch0300: 0300-font-Fix-integer-underflow-in-binary-search-of-char-.patch
-Patch0301: 0301-kern-efi-sb-Enforce-verification-of-font-files.patch
-Patch0302: 0302-fbutil-Fix-integer-overflow.patch
-Patch0303: 0303-font-Fix-an-integer-underflow-in-blit_comb.patch
-Patch0304: 0304-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch
-Patch0305: 0305-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch
-Patch0306: 0306-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch
+Patch0023: 0023-Enable-pager-by-default.-985860.patch
+Patch0024: 0024-Don-t-say-GNU-Linux-in-generated-menus.patch
+Patch0025: 0025-Add-.eh_frame-to-list-of-relocations-stripped.patch
+Patch0026: 0026-Don-t-require-a-password-to-boot-entries-generated-b.patch
+Patch0027: 0027-use-fw_path-prefix-when-fallback-searching-for-grub-.patch
+Patch0028: 0028-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch
+Patch0029: 0029-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch
+Patch0030: 0030-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch
+Patch0031: 0031-Try-prefix-if-fw_path-doesn-t-work.patch
+Patch0032: 0032-Make-grub2-mkconfig-construct-titles-that-look-like-.patch
+Patch0033: 0033-Add-friendly-grub2-password-config-tool-985962.patch
+Patch0034: 0034-tcp-add-window-scaling-support.patch
+Patch0035: 0035-efinet-and-bootp-add-support-for-dhcpv6.patch
+Patch0036: 0036-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch
+Patch0037: 0037-bz1374141-fix-incorrect-mask-for-ppc64.patch
+Patch0038: 0038-Make-grub_fatal-also-backtrace.patch
+Patch0039: 0039-Make-our-info-pages-say-grub2-where-appropriate.patch
+Patch0040: 0040-macos-just-build-chainloader-entries-don-t-try-any-x.patch
+Patch0041: 0041-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch
+Patch0042: 0042-export-btrfs_subvol-and-btrfs_subvolid.patch
+Patch0043: 0043-grub2-btrfs-03-follow_default.patch
+Patch0044: 0044-grub2-btrfs-04-grub2-install.patch
+Patch0045: 0045-grub2-btrfs-05-grub2-mkconfig.patch
+Patch0046: 0046-grub2-btrfs-06-subvol-mount.patch
+Patch0047: 0047-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch
+Patch0048: 0048-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch
+Patch0049: 0049-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch
+Patch0050: 0050-Use-grub_efi_.-memory-helpers-where-reasonable.patch
+Patch0051: 0051-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch
+Patch0052: 0052-don-t-use-int-for-efi-status.patch
+Patch0053: 0053-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch
+Patch0054: 0054-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch
+Patch0055: 0055-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch
+Patch0056: 0056-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch
+Patch0057: 0057-align-struct-efi_variable-better.patch
+Patch0058: 0058-Add-BLS-support-to-grub-mkconfig.patch
+Patch0059: 0059-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch
+Patch0060: 0060-Add-grub2-switch-to-blscfg.patch
+Patch0061: 0061-make-better-backtraces.patch
+Patch0062: 0062-normal-don-t-draw-our-startup-message-if-debug-is-se.patch
+Patch0063: 0063-Work-around-some-minor-include-path-weirdnesses.patch
+Patch0064: 0064-Make-it-possible-to-enabled-build-id-sha1.patch
+Patch0065: 0065-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch
+Patch0066: 0066-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch
+Patch0067: 0067-Fixup-for-newer-compiler.patch
+Patch0068: 0068-Don-t-attempt-to-export-the-start-and-_start-symbols.patch
+Patch0069: 0069-Fixup-for-newer-compiler.patch
+Patch0070: 0070-Add-support-for-non-Ethernet-network-cards.patch
+Patch0071: 0071-net-read-bracketed-ipv6-addrs-and-port-numbers.patch
+Patch0072: 0072-bootp-New-net_bootp6-command.patch
+Patch0073: 0073-efinet-UEFI-IPv6-PXE-support.patch
+Patch0074: 0074-grub.texi-Add-net_bootp6-doument.patch
+Patch0075: 0075-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch
+Patch0076: 0076-efinet-Setting-network-from-UEFI-device-path.patch
+Patch0077: 0077-efinet-Setting-DNS-server-from-UEFI-protocol.patch
+Patch0078: 0078-Support-UEFI-networking-protocols.patch
+Patch0079: 0079-AUDIT-0-http-boot-tracker-bug.patch
+Patch0080: 0080-grub-editenv-Add-incr-command-to-increment-integer-v.patch
+Patch0081: 0081-Add-auto-hide-menu-support.patch
+Patch0082: 0082-Add-grub-set-bootflag-utility.patch
+Patch0083: 0083-docs-Add-grub-boot-indeterminate.service-example.patch
+Patch0084: 0084-gentpl-add-disable-support.patch
+Patch0085: 0085-gentpl-add-pc-firmware-type.patch
+Patch0086: 0086-efinet-also-use-the-firmware-acceleration-for-http.patch
+Patch0087: 0087-efi-http-Make-root_url-reflect-the-protocol-hostname.patch
+Patch0088: 0088-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch
+Patch0089: 0089-module-verifier-make-it-possible-to-run-checkers-on-.patch
+Patch0090: 0090-Rework-how-the-fdt-command-builds.patch
+Patch0091: 0091-Disable-non-wordsize-allocations-on-arm.patch
+Patch0092: 0092-Prepend-prefix-when-HTTP-path-is-relative.patch
+Patch0093: 0093-Make-grub_error-more-verbose.patch
+Patch0094: 0094-Make-reset-an-alias-for-the-reboot-command.patch
+Patch0095: 0095-Add-a-version-command.patch
+Patch0096: 0096-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch
+Patch0097: 0097-arm-arm64-loader-Better-memory-allocation-and-error-.patch
+Patch0098: 0098-Try-to-pick-better-locations-for-kernel-and-initrd.patch
+Patch0099: 0099-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch
+Patch0100: 0100-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch
+Patch0101: 0101-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch
+Patch0102: 0102-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch
+Patch0103: 0103-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch
+Patch0104: 0104-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch
+Patch0105: 0105-Fix-getroot.c-s-trampolines.patch
+Patch0106: 0106-Do-not-allow-stack-trampolines-anywhere.patch
+Patch0107: 0107-Reimplement-boot_counter.patch
+Patch0108: 0108-Fix-menu-entry-selection-based-on-ID-and-title.patch
+Patch0109: 0109-Make-the-menu-entry-users-option-argument-to-be-opti.patch
+Patch0110: 0110-Add-efi-export-env-and-efi-load-env-commands.patch
+Patch0111: 0111-Make-it-possible-to-subtract-conditions-from-debug.patch
+Patch0112: 0112-Export-all-variables-from-the-initial-context-when-c.patch
+Patch0113: 0113-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch
+Patch0114: 0114-Don-t-assume-that-boot-commands-will-only-return-on-.patch
+Patch0115: 0115-grub-set-bootflag-Update-comment-about-running-as-ro.patch
+Patch0116: 0116-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch
+Patch0117: 0117-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch
+Patch0118: 0118-Add-start-symbol-for-RISC-V.patch
+Patch0119: 0119-bootstrap.conf-Force-autogen.sh-to-use-python3.patch
+Patch0120: 0120-efi-http-Export-fw-http-_path-variables-to-make-them.patch
+Patch0121: 0121-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch
+Patch0122: 0122-efi-net-Allow-to-specify-a-port-number-in-addresses.patch
+Patch0123: 0123-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch
+Patch0124: 0124-efi-net-Print-a-debug-message-if-parsing-the-address.patch
+Patch0125: 0125-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch
+Patch0126: 0126-efi-Set-image-base-address-before-jumping-to-the-PE-.patch
+Patch0127: 0127-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch
+Patch0128: 0128-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch
+Patch0129: 0129-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch
+Patch0130: 0130-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch
+Patch0131: 0131-efi-dhcp-fix-some-allocation-error-checking.patch
+Patch0132: 0132-efi-http-fix-some-allocation-error-checking.patch
+Patch0133: 0133-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch
+Patch0134: 0134-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch
+Patch0135: 0135-linuxefi-fail-kernel-validation-without-shim-protoco.patch
+Patch0136: 0136-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch
+Patch0137: 0137-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch
+Patch0138: 0138-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch
+Patch0139: 0139-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch
+Patch0140: 0140-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch
+Patch0141: 0141-Add-systemd-integration-scripts-to-make-systemctl-re.patch
+Patch0142: 0142-systemd-integration.sh-Also-set-old-menu_show_once-g.patch
+Patch0143: 0143-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch
+Patch0144: 0144-grub-install-disable-support-for-EFI-platforms.patch
+Patch0145: 0145-New-with-debug-timestamps-configure-flag-to-prepend-.patch
+Patch0146: 0146-Added-debug-statements-to-grub_disk_open-and-grub_di.patch
+Patch0147: 0147-Introduce-function-grub_debug_is_enabled-void-return.patch
+Patch0148: 0148-Don-t-clear-screen-when-debugging-is-enabled.patch
+Patch0149: 0149-kern-file-Fix-error-handling-in-grub_file_open.patch
+Patch0150: 0150-grub_file_-instrumentation-new-file-debug-tag.patch
+Patch0151: 0151-ieee1275-Avoiding-many-unecessary-open-close.patch
+Patch0152: 0152-ieee1275-powerpc-implements-fibre-channel-discovery-.patch
+Patch0153: 0153-ieee1275-powerpc-enables-device-mapper-discovery.patch
+Patch0154: 0154-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch
+Patch0155: 0155-Add-suport-for-signing-grub-with-an-appended-signatu.patch
+Patch0156: 0156-docs-grub-Document-signing-grub-under-UEFI.patch
+Patch0157: 0157-docs-grub-Document-signing-grub-with-an-appended-sig.patch
+Patch0158: 0158-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch
+Patch0159: 0159-pgp-factor-out-rsa_pad.patch
+Patch0160: 0160-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch
+Patch0161: 0161-posix_wrap-tweaks-in-preparation-for-libtasn1.patch
+Patch0162: 0162-libtasn1-import-libtasn1-4.16.0.patch
+Patch0163: 0163-libtasn1-disable-code-not-needed-in-grub.patch
+Patch0164: 0164-libtasn1-changes-for-grub-compatibility.patch
+Patch0165: 0165-libtasn1-compile-into-asn1-module.patch
+Patch0166: 0166-test_asn1-test-module-for-libtasn1.patch
+Patch0167: 0167-grub-install-support-embedding-x509-certificates.patch
+Patch0168: 0168-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch
+Patch0169: 0169-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch
+Patch0170: 0170-appended-signatures-support-verifying-appended-signa.patch
+Patch0171: 0171-appended-signatures-verification-tests.patch
+Patch0172: 0172-appended-signatures-documentation.patch
+Patch0173: 0173-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch
+Patch0174: 0174-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch
+Patch0175: 0175-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch
+Patch0176: 0176-ieee1275-ofdisk-retry-on-open-failure.patch
+Patch0177: 0177-Allow-chainloading-EFI-apps-from-loop-mounts.patch
+Patch0178: 0178-efinet-Add-DHCP-proxy-support.patch
+Patch0179: 0179-fs-ext2-Ignore-checksum-seed-incompat-feature.patch
+Patch0180: 0180-Don-t-update-the-cmdline-when-generating-legacy-menu.patch
+Patch0181: 0181-Suppress-gettext-error-message.patch
+Patch0182: 0182-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch
+Patch0183: 0183-templates-Check-for-EFI-at-runtime-instead-of-config.patch
+Patch0184: 0184-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch
+Patch0185: 0185-arm64-Fix-EFI-loader-kernel-image-allocation.patch
+Patch0186: 0186-normal-main-Discover-the-device-to-read-the-config-f.patch
+Patch0187: 0187-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch
+Patch0188: 0188-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch
+Patch0189: 0189-Print-module-name-on-license-check-failure.patch
+Patch0190: 0190-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch
+Patch0191: 0191-grub-mkconfig-restore-umask-for-grub.cfg.patch
+Patch0192: 0192-fs-btrfs-Use-full-btrfs-bootloader-area.patch
+Patch0193: 0193-Add-Fedora-location-of-DejaVu-SANS-font.patch
+Patch0194: 0194-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch
+Patch0195: 0195-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch
+Patch0196: 0196-EFI-console-Do-not-set-colorstate-until-the-first-te.patch
+Patch0197: 0197-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch
+Patch0198: 0198-Use-visual-indentation-in-config.h.in.patch
+Patch0199: 0199-Where-present-ensure-config-util.h-precedes-config.h.patch
+Patch0200: 0200-Drop-gnulib-fix-base64.patch.patch
+Patch0201: 0201-Drop-gnulib-no-abort.patch.patch
+Patch0202: 0202-Update-gnulib-version-and-drop-most-gnulib-patches.patch
+Patch0203: 0203-commands-search-Fix-bug-stopping-iteration-when-no-f.patch
+Patch0204: 0204-search-new-efidisk-only-option-on-EFI-systems.patch
+Patch0205: 0205-efi-new-connectefi-command.patch
+Patch0206: 0206-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch
+Patch0207: 0207-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch
+Patch0208: 0208-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch
+Patch0209: 0209-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch
+Patch0210: 0210-powerpc-prefix-detection-support-device-names-with-c.patch
+Patch0211: 0211-make-ofdisk_retries-optional.patch
+Patch0212: 0212-loader-efi-chainloader-grub_load_and_start_image-doe.patch
+Patch0213: 0213-loader-efi-chainloader-simplify-the-loader-state.patch
+Patch0214: 0214-commands-boot-Add-API-to-pass-context-to-loader.patch
+Patch0215: 0215-loader-efi-chainloader-Use-grub_loader_set_ex.patch
+Patch0216: 0216-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch
+Patch0217: 0217-loader-i386-efi-linux-Use-grub_loader_set_ex.patch
+Patch0218: 0218-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch
+Patch0219: 0219-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch
+Patch0220: 0220-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch
+Patch0221: 0221-video-readers-png-Abort-sooner-if-a-read-operation-f.patch
+Patch0222: 0222-video-readers-png-Refuse-to-handle-multiple-image-he.patch
+Patch0223: 0223-video-readers-png-Drop-greyscale-support-to-fix-heap.patch
+Patch0224: 0224-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch
+Patch0225: 0225-video-readers-png-Sanity-check-some-huffman-codes.patch
+Patch0226: 0226-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch
+Patch0227: 0227-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch
+Patch0228: 0228-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch
+Patch0229: 0229-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch
+Patch0230: 0230-normal-charset-Fix-array-out-of-bounds-formatting-un.patch
+Patch0231: 0231-net-netbuff-Block-overly-large-netbuff-allocs.patch
+Patch0232: 0232-net-ip-Do-IP-fragment-maths-safely.patch
+Patch0233: 0233-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch
+Patch0234: 0234-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch
+Patch0235: 0235-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch
+Patch0236: 0236-net-tftp-Avoid-a-trivial-UAF.patch
+Patch0237: 0237-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch
+Patch0238: 0238-net-http-Fix-OOB-write-for-split-http-headers.patch
+Patch0239: 0239-net-http-Error-out-on-headers-with-LF-without-CR.patch
+Patch0240: 0240-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch
+Patch0241: 0241-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch
+Patch0242: 0242-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch
+Patch0243: 0243-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch
+Patch0244: 0244-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch
+Patch0245: 0245-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch
+Patch0246: 0246-misc-Make-grub_min-and-grub_max-more-resilient.patch
+Patch0247: 0247-ReiserFS-switch-to-using-grub_min-grub_max.patch
+Patch0248: 0248-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch
+Patch0249: 0249-modules-make-.module_license-read-only.patch
+Patch0250: 0250-modules-strip-.llvm_addrsig-sections-and-similar.patch
+Patch0251: 0251-modules-Don-t-allocate-space-for-non-allocable-secti.patch
+Patch0252: 0252-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch
+Patch0253: 0253-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch
+Patch0254: 0254-modules-load-module-sections-at-page-aligned-address.patch
+Patch0255: 0255-nx-add-memory-attribute-get-set-API.patch
+Patch0256: 0256-nx-set-page-permissions-for-loaded-modules.patch
+Patch0257: 0257-nx-set-attrs-in-our-kernel-loaders.patch
+Patch0258: 0258-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch
+Patch0259: 0259-grub-probe-document-the-behavior-of-multiple-v.patch
+Patch0260: 0260-grub_fs_probe-dprint-errors-from-filesystems.patch
+Patch0261: 0261-fs-fat-don-t-error-when-mtime-is-0.patch
+Patch0262: 0262-Make-debug-file-show-which-file-filters-get-run.patch
+Patch0263: 0263-efi-use-enumerated-array-positions-for-our-allocatio.patch
+Patch0264: 0264-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch
+Patch0265: 0265-efi-allocate-the-initrd-within-the-bounds-expressed-.patch
+Patch0266: 0266-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch
+Patch0267: 0267-BLS-create-etc-kernel-cmdline-during-mkconfig.patch
+Patch0268: 0268-squish-don-t-dup-rhgb-quiet-check-mtimes.patch
+Patch0269: 0269-squish-give-up-on-rhgb-quiet.patch
+Patch0270: 0270-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch
+Patch0271: 0271-blscfg-Don-t-root-device-in-emu-builds.patch
+Patch0272: 0272-loader-arm64-linux-Remove-magic-number-header-field-.patch
+Patch0273: 0273-Correct-BSS-zeroing-on-aarch64.patch
+Patch0274: 0274-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch
+Patch0275: 0275-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch
+Patch0276: 0276-commands-efi-tpm-Refine-the-status-of-log-event.patch
+Patch0277: 0277-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch
+Patch0278: 0278-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch
+Patch0279: 0279-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch
+Patch0280: 0280-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch
+Patch0281: 0281-font-Fix-several-integer-overflows-in-grub_font_cons.patch
+Patch0282: 0282-font-Remove-grub_font_dup_glyph.patch
+Patch0283: 0283-font-Fix-integer-overflow-in-ensure_comb_space.patch
+Patch0284: 0284-font-Fix-integer-overflow-in-BMP-index.patch
+Patch0285: 0285-font-Fix-integer-underflow-in-binary-search-of-char-.patch
+Patch0286: 0286-kern-efi-sb-Enforce-verification-of-font-files.patch
+Patch0287: 0287-fbutil-Fix-integer-overflow.patch
+Patch0288: 0288-font-Fix-an-integer-underflow-in-blit_comb.patch
+Patch0289: 0289-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch
+Patch0290: 0290-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch
+Patch0291: 0291-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch
+Patch0292: 0292-font-Try-opening-fonts-from-the-bundled-memdisk.patch
+Patch0293: 0293-mm-Clarify-grub_real_malloc.patch
+Patch0294: 0294-mm-grub_real_malloc-Make-small-allocs-comment-match-.patch
+Patch0295: 0295-mm-Document-grub_free.patch
+Patch0296: 0296-mm-Document-grub_mm_init_region.patch
+Patch0297: 0297-mm-Document-GRUB-internal-memory-management-structur.patch
+Patch0298: 0298-mm-Assert-that-we-preserve-header-vs-region-alignmen.patch
+Patch0299: 0299-mm-When-adding-a-region-merge-with-region-after-as-w.patch
+Patch0300: 0300-mm-Debug-support-for-region-operations.patch
+Patch0301: 0301-mm-Drop-unused-unloading-of-modules-on-OOM.patch
+Patch0302: 0302-mm-Allow-dynamically-requesting-additional-memory-re.patch
+Patch0303: 0303-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch
+Patch0304: 0304-kern-efi-mm-Extract-function-to-add-memory-regions.patch
+Patch0305: 0305-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch
+Patch0306: 0306-kern-efi-mm-Implement-runtime-addition-of-pages.patch
+Patch0307: 0307-efi-Increase-default-memory-allocation-to-32-MiB.patch
+Patch0308: 0308-mm-Try-invalidate-disk-caches-last-when-out-of-memor.patch
+Patch0309: 0309-ppc64le-signed-boot-media-changes.patch
+Patch0310: 0310-core-Fix-several-implicit-function-declarations.patch
+Patch0311: 0311-loader-Add-support-for-grub-emu-to-kexec-Linux-menu-.patch
+Patch0312: 0312-powerpc-Drop-Open-Hack-Ware-remove-GRUB_IEEE1275_FLA.patch
+Patch0313: 0313-ieee1275-request-memory-with-ibm-client-architecture.patch
+Patch0314: 0314-ieee1275-drop-len-1-quirk-in-heap_init.patch
+Patch0315: 0315-ieee1275-support-runtime-memory-claiming.patch
+Patch0316: 0316-ieee1275-implement-vec5-for-cas-negotiation.patch
+Patch0317: 0317-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch
+Patch0318: 0318-powerpc-Drop-Open-Hack-Ware.patch
+Patch0319: 0319-osdep-linux-hostdisk-Modify-sector-by-sysfs-as-disk-.patch
+Patch0320: 0320-mm-Adjust-new-region-size-to-take-management-overhea.patch
+Patch0321: 0321-mm-Preallocate-some-space-when-adding-new-regions.patch
+Patch0322: 0322-mm-Avoid-complex-heap-growth-math-in-hot-path.patch
diff --git a/SPECS/grub2.spec b/SPECS/grub2.spec
index a0b8503..8b8b808 100644
--- a/SPECS/grub2.spec
+++ b/SPECS/grub2.spec
@@ -9,12 +9,14 @@
 %undefine _missing_build_ids_terminate_build
 %global _configure_gnuconfig_hack 0
 
-%global gnulibversion fixes
+# It's a commit from their gnulib's development tree.  They don't do releases,
+# and it is *awful* to update this.
+%global gnulibversion 9f48fb992a3d7e96610c4ce8be969cff2d61a01b
 
 Name:		grub2
 Epoch:		1
 Version:	2.06
-Release:	46%{?dist}.3
+Release:	46%{?dist}.5
 Summary:	Bootloader with support for Linux, Multiboot and more
 License:	GPLv3+
 URL:		http://www.gnu.org/software/grub/
@@ -32,21 +34,14 @@ Source9:	strtoull_test.c
 Source10:	20-grub.install
 Source11:	grub.patches
 Source12:	sbat.csv.in
-Source13:       701-ca.cer
-Source14:       701-cer.cer
 
 %include %{SOURCE1}
 
-%ifarch x86_64 aarch64
+%ifarch x86_64 aarch64 ppc64le
 %define sb_ca		%{_datadir}/pki/sb-certs/secureboot-ca-%{_arch}.cer
 %define sb_cer		%{_datadir}/pki/sb-certs/secureboot-grub2-%{_arch}.cer
 %endif
 
-%ifarch ppc64le
-%define sb_ca %{SOURCE13}
-%define sb_cer %{SOURCE14}
-%endif
-
 %if 0%{?centos}
 
 %ifarch x86_64 aarch64 ppc64le
@@ -438,7 +433,6 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg
 %{_datarootdir}/bash-completion/completions/grub
 %{_sbindir}/%{name}-mkconfig
 %{_sbindir}/%{name}-switch-to-blscfg
-%{_sbindir}/%{name}-rpm-sort
 %{_sbindir}/%{name}-reboot
 %{_bindir}/%{name}-file
 %{_bindir}/%{name}-menulst2cfg
@@ -539,8 +533,13 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg
 %endif
 
 %changelog
-* Tue Feb 14 2023 CentOS Sources <bugs@centos.org> - 2.06-46.el9.centos.3
-- Apply debranding changes
+* Mon Mar 27 2023 Robbie Harwood <rharwood@redhat.com> - 2.06-46.el9_1.5
+- Sync (actually 2.06-61)
+- Resolves: #2181506
+
+* Tue Feb 07 2023 Robbie Harwood <rharwood@redhat.com> - 2.06-46.el9_1.4
+- Sync with 9.2 (actually 2.06-58)
+- Resolves: #2156419
 
 * Fri Nov 11 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-46.el9_1.3
 - Give up on redhat-sb-certs