summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorAxelen1232022-01-02 14:53:06 +0100
committerAxelen1232022-01-02 15:06:09 +0100
commitabac075026037834721776323539bd55a64c45e3 (patch)
tree7c39ca4b162237320fc491b325c1ef4c097ecb05
downloadaur-abac075026037834721776323539bd55a64c45e3.tar.gz
Initial commit
-rw-r--r--.SRCINFO69
-rw-r--r--PKGBUILD190
-rw-r--r--add-GRUB_COLOR_variables.patch41
-rw-r--r--argon_1.patch56
-rw-r--r--argon_2.patch52
-rw-r--r--argon_3.patch2624
-rw-r--r--argon_4.patch71
-rw-r--r--argon_5.patch96
-rw-r--r--detect-archlinux-initramfs.patch49
-rw-r--r--grub-improved-luks2-git.install17
-rw-r--r--grub-install_luks2.patch263
-rw-r--r--grub.default57
-rw-r--r--mm_1.patch87
-rw-r--r--mm_2.patch89
-rw-r--r--mm_3.patch99
-rw-r--r--mm_4.patch101
-rw-r--r--mm_5.patch85
-rw-r--r--mm_6.patch81
18 files changed, 4127 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..cc822f16793a
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,69 @@
+pkgbase = grub-improved-luks2-git
+ pkgdesc = GNU GRand Unified Bootloader (2) with Argon2 and better LUKS2 support
+ pkgver = 2.06.r92.g246d69b7e
+ pkgrel = 1
+ url = https://www.gnu.org/software/grub/
+ install = grub-improved-luks2-git.install
+ arch = x86_64
+ license = GPL3
+ makedepends = autogen
+ makedepends = bdf-unifont
+ makedepends = git
+ makedepends = help2man
+ makedepends = python
+ makedepends = rsync
+ makedepends = texinfo
+ makedepends = ttf-dejavu
+ depends = device-mapper
+ depends = freetype2
+ depends = fuse2
+ depends = gettext
+ optdepends = dosfstools: For grub-mkrescue FAT FS and EFI support
+ optdepends = efibootmgr: For grub-install EFI support
+ optdepends = libisoburn: Provides xorriso for generating grub rescue iso using grub-mkrescue
+ optdepends = mtools: For grub-mkrescue FAT FS support
+ optdepends = os-prober: To detect other OSes when generating grub.cfg in BIOS systems
+ provides = grub
+ conflicts = grub
+ backup = etc/default/grub
+ backup = etc/grub.d/40_custom
+ source = grub::git+https://git.savannah.gnu.org/git/grub.git
+ source = grub-extras::git+https://git.savannah.gnu.org/git/grub-extras.git
+ source = gnulib::git+https://git.savannah.gnu.org/git/gnulib.git
+ source = argon_1.patch
+ source = argon_2.patch
+ source = argon_2.patch
+ source = argon_3.patch
+ source = argon_4.patch
+ source = argon_5.patch
+ source = mm_1.patch
+ source = mm_2.patch
+ source = mm_3.patch
+ source = mm_4.patch
+ source = mm_5.patch
+ source = mm_6.patch
+ source = grub-install_luks2.patch
+ source = add-GRUB_COLOR_variables.patch
+ source = detect-archlinux-initramfs.patch
+ source = grub.default
+ sha256sums = SKIP
+ sha256sums = SKIP
+ sha256sums = SKIP
+ sha256sums = SKIP
+ sha256sums = SKIP
+ sha256sums = SKIP
+ sha256sums = SKIP
+ sha256sums = SKIP
+ sha256sums = SKIP
+ sha256sums = SKIP
+ sha256sums = SKIP
+ sha256sums = SKIP
+ sha256sums = SKIP
+ sha256sums = SKIP
+ sha256sums = SKIP
+ sha256sums = SKIP
+ sha256sums = 5dee6628c48eef79812bb9e86ee772068d85e7fcebbd2b2b8d1e19d24eda9dab
+ sha256sums = 580a81b00088773d554832b0d74c85bf16fec37728802973c45993bcb97cd7d5
+ sha256sums = 791fadf182edf8d5bee4b45c008b08adce9689a9624971136527891a8f67d206
+
+pkgname = grub-improved-luks2-git
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..dbadffbae0d8
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,190 @@
+# Maintainer: Ax333l
+# Contributor: Llewelyn Trahaearn <WoefulDerelict [at] GMail [dot] com>
+# Contributor: Tobias Powalowski <tpowa [at] archlinux [dot] org>
+# Contributor: Ronald van Haren <ronald [at] archlinux [dot] org>
+# Contributor: Keshav Amburay <(the ddoott ridikulus ddoott rat) (aatt) (gemmaeiil) (ddoott) (ccoomm)>
+
+## "1" to enable IA32-EFI build in Arch x86_64, "0" to disable
+_ia32_efi_in_arch_x64="1"
+
+## "1" to enable EMU build, "0" to disable
+_grub_emu_build="0"
+
+[[ "${CARCH}" == "x86_64" ]] && _target_arch="x86_64"
+[[ "${CARCH}" == "i686" ]] && _target_arch="i386"
+
+_build_platforms="i386-pc ${_target_arch}-efi"
+[[ "${CARCH}" == "x86_64" ]] && [[ "${_ia32_efi_in_arch_x64}" == "1" ]] && _build_platforms+=" i386-efi"
+[[ "${_grub_emu_build}" == "1" ]] && _build_platforms+=" ${_target_arch}-emu"
+
+pkgname="grub-improved-luks2-git"
+pkgver=2.06.r92.g246d69b7e
+pkgrel=1
+pkgdesc="GNU GRand Unified Bootloader (2) with Argon2 and better LUKS2 support"
+arch=('x86_64')
+url="https://www.gnu.org/software/grub/"
+license=('GPL3')
+depends=('device-mapper' 'freetype2' 'fuse2' 'gettext')
+makedepends=('autogen' 'bdf-unifont' 'git' 'help2man'
+ 'python' 'rsync' 'texinfo' 'ttf-dejavu')
+optdepends=('dosfstools: For grub-mkrescue FAT FS and EFI support'
+ 'efibootmgr: For grub-install EFI support'
+ 'libisoburn: Provides xorriso for generating grub rescue iso using grub-mkrescue'
+ 'mtools: For grub-mkrescue FAT FS support'
+ 'os-prober: To detect other OSes when generating grub.cfg in BIOS systems')
+
+if [[ "${_grub_emu_build}" == "1" ]]; then
+ depends+=('sdl')
+ makedepends+=('libusb')
+ optdepends+=('libusb: For grub-emu USB support')
+fi
+
+provides=("grub")
+conflicts=("grub")
+backup=('etc/default/grub'
+ 'etc/grub.d/40_custom')
+install="${pkgname}.install"
+source=("grub::git+https://git.savannah.gnu.org/git/grub.git"
+ "grub-extras::git+https://git.savannah.gnu.org/git/grub-extras.git"
+ "gnulib::git+https://git.savannah.gnu.org/git/gnulib.git"
+ 'argon_1.patch'
+ 'argon_2.patch'
+ 'argon_2.patch'
+ 'argon_3.patch'
+ 'argon_4.patch'
+ 'argon_5.patch'
+ 'mm_1.patch'
+ 'mm_2.patch'
+ 'mm_3.patch'
+ 'mm_4.patch'
+ 'mm_5.patch'
+ 'mm_6.patch'
+ 'grub-install_luks2.patch'
+ 'add-GRUB_COLOR_variables.patch'
+ 'detect-archlinux-initramfs.patch'
+ 'grub.default')
+sha256sums=('SKIP'
+ 'SKIP'
+ 'SKIP'
+ 'SKIP'
+ 'SKIP'
+ 'SKIP'
+ 'SKIP'
+ 'SKIP'
+ 'SKIP'
+ 'SKIP'
+ 'SKIP'
+ 'SKIP'
+ 'SKIP'
+ 'SKIP'
+ 'SKIP'
+ 'SKIP'
+ '5dee6628c48eef79812bb9e86ee772068d85e7fcebbd2b2b8d1e19d24eda9dab'
+ '580a81b00088773d554832b0d74c85bf16fec37728802973c45993bcb97cd7d5'
+ '791fadf182edf8d5bee4b45c008b08adce9689a9624971136527891a8f67d206')
+
+prepare() {
+ cd grub
+
+ # Patch to enable GRUB_COLOR_* variables in grub-mkconfig.
+ # Based on http://lists.gnu.org/archive/html/grub-devel/2012-02/msg00021.html
+ patch -Np1 -i "$srcdir"/add-GRUB_COLOR_variables.patch
+
+ # Patch grub-mkconfig to detect Arch Linux initramfs images.
+ patch -Np1 -i "$srcdir"/detect-archlinux-initramfs.patch
+
+ # mm
+ patch -Np1 -i "$srcdir"/mm_1.patch
+ patch -Np1 -i "$srcdir"/mm_2.patch
+ patch -Np1 -i "$srcdir"/mm_3.patch
+ patch -Np1 -i "$srcdir"/mm_4.patch
+ patch -Np1 -i "$srcdir"/mm_5.patch
+ patch -Np1 -i "$srcdir"/mm_6.patch
+
+ # argon2
+ patch -Np1 -i "$srcdir"/argon_1.patch
+ patch -Np1 -i "$srcdir"/argon_2.patch
+ patch -Np1 -i "$srcdir"/argon_3.patch
+ patch -Np1 -i "$srcdir"/argon_4.patch
+ patch -Np1 -i "$srcdir"/argon_5.patch
+
+ # make grub-install work with luks2
+ patch -Np1 -i "$srcdir"/grub-install_luks2.patch
+
+ # Fix DejaVuSans.ttf location so that grub-mkfont can create *.pf2 files for starfield theme.
+ sed 's|/usr/share/fonts/dejavu|/usr/share/fonts/dejavu /usr/share/fonts/TTF|g' -i "configure.ac"
+
+ # Modify grub-mkconfig behaviour to silence warnings FS#36275
+ sed 's| ro | rw |g' -i "util/grub.d/10_linux.in"
+
+ # Modify grub-mkconfig behaviour so automatically generated entries read 'Arch Linux' FS#33393
+ sed 's|GNU/Linux|Linux|' -i "util/grub.d/10_linux.in"
+
+ # Pull in latest language files
+ ./linguas.sh
+
+ # Remove lua module from grub-extras as it is incompatible with changes to grub_file_open
+ # http://git.savannah.gnu.org/cgit/grub.git/commit/?id=ca0a4f689a02c2c5a5e385f874aaaa38e151564e
+ rm -rf "$srcdir"/grub-extras/lua
+}
+
+pkgver() {
+ cd grub
+ git describe --long --tags | sed 's/^grub.//;s/\([^-]*-g\)/r\1/;s/-/./g'
+}
+
+build() {
+ cd grub
+ export GRUB_CONTRIB="$srcdir"/grub-extras
+ export GNULIB_SRCDIR="$srcdir"/gnulib
+
+ # Undefined references to _GLOBAL_OFFSET_TABLE_
+ CFLAGS=${CFLAGS/-fno-plt}
+
+ ./bootstrap
+
+ for _arch in $_build_platforms; do
+ mkdir "$srcdir"/grub/build_"$_arch"
+ cd "$srcdir"/grub/build_"$_arch"
+
+ # * _FORTIFY_SOURCE requires compiling with optimization warnings
+ # become errors due to a -Werror added during ./configure tests.
+ # This results in an incorrect configuration and only by adding -O2
+ # to CPPFLAGS does this problem seem to be worked around.
+ ../configure --with-platform="${_arch##*-}" \
+ --target="${_arch%%-*}" \
+ --prefix="/usr" \
+ --sbindir="/usr/bin" \
+ --sysconfdir="/etc" \
+ --enable-boot-time \
+ --enable-cache-stats \
+ --enable-device-mapper \
+ --enable-grub-mkfont \
+ --enable-grub-mount \
+ --enable-mm-debug \
+ --enable-nls \
+ --disable-silent-rules \
+ --disable-werror \
+ CPPFLAGS="$CPPFLAGS -O2"
+ make
+ done
+}
+
+package() {
+ cd grub
+
+ for _arch in $_build_platforms; do
+ cd "$srcdir"/grub/build_"$_arch"
+ make DESTDIR="$pkgdir" bashcompletiondir=/usr/share/bash-completion/completions install
+ done
+
+ # Install /etc/default/grub (used by grub-mkconfig)
+ install -D -m0644 "$srcdir"/grub.default "$pkgdir"/etc/default/grub
+
+ # Tidy up
+ find "$pkgdir"/usr/lib/grub \( -name '*.module' -o \
+ -name '*.image' -o \
+ -name 'kernel.exec' -o \
+ -name 'gdb_grub' -o \
+ -name 'gmodule.pl' \) -delete
+}
diff --git a/add-GRUB_COLOR_variables.patch b/add-GRUB_COLOR_variables.patch
new file mode 100644
index 000000000000..867e8feeb7b9
--- /dev/null
+++ b/add-GRUB_COLOR_variables.patch
@@ -0,0 +1,41 @@
+From 21e5bcf22ab1a9f08c63e2a0212219d7482f77c1 Mon Sep 17 00:00:00 2001
+From: Christian Hesse <mail@eworm.de>
+Date: Wed, 10 Mar 2021 18:42:25 +0100
+Subject: [PATCH] 00_header: add GRUB_COLOR_* variables
+---
+ util/grub-mkconfig.in | 2 ++
+ util/grub.d/00_header.in | 8 ++++++++
+ 2 files changed, 10 insertions(+)
+
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index f8cbb8d7a..1189d95f9 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -246,6 +246,8 @@ export GRUB_DEFAULT \
+ GRUB_BACKGROUND \
+ GRUB_THEME \
+ GRUB_GFXPAYLOAD_LINUX \
++ GRUB_COLOR_NORMAL \
++ GRUB_COLOR_HIGHLIGHT \
+ GRUB_INIT_TUNE \
+ GRUB_SAVEDEFAULT \
+ GRUB_ENABLE_CRYPTODISK \
+diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
+index 93a90233e..c5955df00 100644
+--- a/util/grub.d/00_header.in
++++ b/util/grub.d/00_header.in
+@@ -125,6 +125,14 @@ cat <<EOF
+
+ EOF
+
++if [ x$GRUB_COLOR_NORMAL != x ] && [ x$GRUB_COLOR_HIGHLIGHT != x ] ; then
++ cat << EOF
++set menu_color_normal=$GRUB_COLOR_NORMAL
++set menu_color_highlight=$GRUB_COLOR_HIGHLIGHT
++
++EOF
++fi
++
+ serial=0;
+ gfxterm=0;
+ for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do
diff --git a/argon_1.patch b/argon_1.patch
new file mode 100644
index 000000000000..fe19861f800e
--- /dev/null
+++ b/argon_1.patch
@@ -0,0 +1,56 @@
+---
+ grub-core/kern/dl.c | 3 ++-
+ util/grub-module-verifierXX.c | 3 ++-
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index 48f8a7907..7d395096f 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -467,7 +467,8 @@ grub_dl_check_license (grub_dl_t mod, El
+
+ if (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)
++ || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv2+") == 0
++ || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=CC0") == 0)
+ return GRUB_ERR_NONE;
+
+ return grub_error (GRUB_ERR_BAD_MODULE,
+diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c
+index ceb24309a..284f9026e 100644
+--- a/util/grub-module-verifierXX.c
++++ b/util/grub-module-verifierXX.c
+@@ -157,7 +157,8 @@ check_license (const char * const filena
+ Elf_Shdr *s = find_section (arch, e, ".module_license");
+ if (s && (strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv3") == 0
+ || strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv3+") == 0
+- || strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv2+") == 0))
++ || strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv2+") == 0
++ || strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=CC0") == 0))
+ return;
+ grub_util_error ("%s: incompatible license", filename);
+ }
+--
+2.32.0
+
+
+The original PGP Signature. I had to modify the patch to apply it to the latest grub source code.
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEEF9hrgiFbCdvenl/rVbJhu7ckPpQFAmEP4xMACgkQVbJhu7ck
+PpRSTxAAo3leEk7U47GFerE4CBrrC3CZpkpXjoNdcYuEbvy8rhhZrFzt4+g+8s5w
+z9BvXArf1G85XY4bvk61oeaLO7A52WOg5qpK3dKfcv6wZheq/MbjrE/JjcDNiLLc
+yOW/dipv23hXDNRU4xWHchWw792lBcTfO5QqTDhQczTfaze4LLYFt0W7ySuV39ir
+Q6FIZSLQPJFpH/lAjRJf5CjmDGzkuc6xg+km5NBQIKh695jKUv+H3oBGzmUfcd36
+Smv9cM7R7HuyU0y+Uc3nV6IU77H2+gGelvdodHpMPABiKrcsqiU3e347itmjTFRT
+7Yy9iThh3biPO6dxzdVGw9BwKeM9fH0Dvja6rQxx1+NkeuM7YGBAlYIe6JV8kYRo
+TtdjOUtixlfNuqwdYjFMwkAdQWaq0wCebQ9MvF9r0BuiH009u1dmGHHwen3yhzyO
+xxvk1bsC0B4yjy+Wq5I2r3DZSfr10RensKYxuKyWMDKRSbI2mUk/5/JJDiZlfW+r
+EIV73GAjURBM/kSS7Bo1MZmjuNcH5oXSJk4PfEOypK7xFbgPX0GM1hilJB1MZQC7
+T6EJwe1+WyHkAB5nVFqiPbUM7/xWw4LwQctjLBtJ9JW/+5n/rCAtkUIGOrQIedZg
+r/lckIxn6ujrKwIu5Rh03eqTIrG5PZ7Uy8LdMut0IOALp25zO7o=
+=w8r3
+-----END PGP SIGNATURE-----
+
+
diff --git a/argon_2.patch b/argon_2.patch
new file mode 100644
index 000000000000..40a4981f0c61
--- /dev/null
+++ b/argon_2.patch
@@ -0,0 +1,52 @@
+---
+ include/grub/types.h | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/include/grub/types.h b/include/grub/types.h
+index 0a3ff1591..13b0c46b3 100644
+--- a/include/grub/types.h
++++ b/include/grub/types.h
+@@ -153,6 +153,7 @@ typedef grub_int32_t grub_ssize_t;
+ #define GRUB_SHRT_MAX 0x7fff
+ #define GRUB_SHRT_MIN (-GRUB_SHRT_MAX - 1)
+ #define GRUB_UINT_MAX 4294967295U
++#define GRUB_UINT32_MAX 4294967295U
+ #define GRUB_INT_MAX 0x7fffffff
+ #define GRUB_INT_MIN (-GRUB_INT_MAX - 1)
+ #define GRUB_INT32_MAX 2147483647
+@@ -174,6 +175,13 @@ typedef grub_int32_t grub_ssize_t;
+ #define GRUB_TYPE_U_MAX(type) ((unsigned long long)((typeof (type))(~0)))
+ #define GRUB_TYPE_U_MIN(type) 0ULL
+
++# define GRUB_UINT32_C(x) x ## U
++# if GRUB_ULONG_MAX >> 31 >> 31 >> 1 == 1
++# define GRUB_UINT64_C(x) x##UL
++# elif 1
++# define GRUB_UINT64_C(x) x##ULL
++# endif
++
+ typedef grub_uint64_t grub_properly_aligned_t;
+
+ #define GRUB_PROPERLY_ALIGNED_ARRAY(name, size) grub_properly_aligned_t name[((size) + sizeof (grub_properly_aligned_t) - 1) / sizeof (grub_properly_aligned_t)]
+--
+2.32.0
+
+
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEEF9hrgiFbCdvenl/rVbJhu7ckPpQFAmEP4xcACgkQVbJhu7ck
+PpTcrA/+PqtqzLX54L1VYNehv8ilsLbLPLLJp6ov/sjDbKzFt/50Y1LGguTG81hF
+DMjqk2NtF6FGZS494GzZyZDpNMzfEFTxEZdOsSzoq9EbuDILUZ/2UMCwmTbYX9Bd
+2pZaI+ZeI+H7hI78CKAIAYRRz4dUuH0f7xnlpNzjk4XqE/2kkNwzbiwK+zhAb4Xw
+zD9BfPnPqSF1YoOMGJ5nNYwEKaqRg9XRq+zim1ADQDIydt/qS3GFudlLddC2x5UR
+umbP6EltWqn7jthHyK8aD924PvkiuVWlHa9kbn6ePkrkWpiXMYQyrfzlBjcoVRfw
+wHE2X7LzBKTf0vgB8uCNY9rxpy44dBFXxEqknwLn1heLx7NbaRaylzdRmeDCSsDR
+VlR8mF45BvLZwv4LrIT9Ok4cR3vGbYQjWs3eqCklH5R/GwDnlZnc6SwN1tdxZLk2
+om2cdTS/cfz/5qodKKQGjk9rZqOV4dHAi9SwxzpafmXFRUPEJOHuDoIGIeuAofLz
+4RsiSDBVAYCq+qWdkye38Ei37WlzFBJvz3DHMDUAqsjw+IWorFJBeWAerL1viCNj
+SDFBAT+QuLYJS0F2h3IIzCgVJAnXMKrCLEuruhoSw4duYjOQw0fMlXgrYX30VCx6
+xkdfrzE5Bh9jqr+igqqglaTD8OpF+dFMSWHTU9Ew+CtpbiLzN5c=
+=YqYY
+-----END PGP SIGNATURE-----
+
+
diff --git a/argon_3.patch b/argon_3.patch
new file mode 100644
index 000000000000..bc39630ffe82
--- /dev/null
+++ b/argon_3.patch
@@ -0,0 +1,2624 @@
+---
+ docs/grub-dev.texi | 64 +++
+ grub-core/Makefile.core.def | 8 +
+ grub-core/lib/argon2/LICENSE | 314 +++++++++++
+ grub-core/lib/argon2/argon2.c | 232 ++++++++
+ grub-core/lib/argon2/argon2.h | 264 +++++++++
+ grub-core/lib/argon2/blake2/blake2-impl.h | 151 ++++++
+ grub-core/lib/argon2/blake2/blake2.h | 89 +++
+ grub-core/lib/argon2/blake2/blake2b.c | 388 ++++++++++++++
+ .../lib/argon2/blake2/blamka-round-ref.h | 56 ++
+ grub-core/lib/argon2/core.c | 506 ++++++++++++++++++
+ grub-core/lib/argon2/core.h | 228 ++++++++
+ grub-core/lib/argon2/ref.c | 190 +++++++
+ 12 files changed, 2490 insertions(+)
+ create mode 100644 grub-core/lib/argon2/LICENSE
+ create mode 100644 grub-core/lib/argon2/argon2.c
+ create mode 100644 grub-core/lib/argon2/argon2.h
+ create mode 100644 grub-core/lib/argon2/blake2/blake2-impl.h
+ create mode 100644 grub-core/lib/argon2/blake2/blake2.h
+ create mode 100644 grub-core/lib/argon2/blake2/blake2b.c
+ create mode 100644 grub-core/lib/argon2/blake2/blamka-round-ref.h
+ create mode 100644 grub-core/lib/argon2/core.c
+ create mode 100644 grub-core/lib/argon2/core.h
+ create mode 100644 grub-core/lib/argon2/ref.c
+
+diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
+index 6c629a23e..ead2a8259 100644
+--- a/docs/grub-dev.texi
++++ b/docs/grub-dev.texi
+@@ -490,11 +490,75 @@ GRUB includes some code from other projects, and it is sometimes necessary
+ to update it.
+
+ @menu
++* Argon2::
+ * Gnulib::
+ * jsmn::
+ * minilzo::
+ @end menu
+
++@node Argon2
++@section Argon2
++
++Argon2 is a key derivation function used by LUKS2 in order to derive encryption
++keys from a user-provided password. GRUB imports the official reference
++implementation of Argon2 from @url{https://github.com/P-H-C/phc-winner-argon2}.
++In order to make the library usable for GRUB, we need to perform various
++conversions. This is mainly due to the fact that the imported code makes use of
++types and functions defined in the C standard library, which isn't available.
++Furthermore, using the POSIX wrapper library is not possible as the code needs
++to be part of the kernel.
++
++Updating the code can thus be performed like following:
++
++@example
++$ git clone https://github.com/P-H-C/phc-winner-argon2 argon2
++$ cp argon2/include/argon2.h argon2/src/@{argon2.c,core.c,core.h,ref.c@} \
++ grub-core/lib/argon2/
++$ cp argon2/src/blake2/@{blake2-impl.h,blake2.h,blake2b.c,blamka-round-ref.h@} \
++ grub-core/lib/argon2/blake2/
++$ sed -e 's/UINT32_C/GRUB_UINT32_C/g' \
++ -e 's/UINT64_C/GRUB_UINT64_C/g' \
++ -e 's/UINT32_MAX/GRUB_UINT32_MAX/g' \
++ -e 's/CHAR_BIT/GRUB_CHAR_BIT/g' \
++ -e 's/UINT_MAX/GRUB_UINT_MAX/g' \
++ -e 's/uintptr_t/grub_addr_t/g' \
++ -e 's/size_t/grub_size_t/g' \
++ -e 's/uint32_t/grub_uint32_t/g' \
++ -e 's/uint64_t/grub_uint64_t/g' \
++ -e 's/uint8_t/grub_uint8_t/g' \
++ -e 's/memset/grub_memset/g' \
++ -e 's/memcpy/grub_memcpy/g' \
++ -e 's/malloc/grub_malloc/g' \
++ -e 's/free/grub_free/g' \
++ -e 's/#elif _MSC_VER/#elif defined(_MSC_VER)/' \
++ grub-core/lib/argon2/@{*,blake2/*@}.@{c,h@} -i
++@end example
++
++Afterwards, you need to perform the following manual steps:
++
++@enumerate
++@item Remove all includes of standard library headers, "encoding.h" and
++ "thread.h".
++@item Add includes <grub/mm.h> and <grub/misc.h> to "argon2.h".
++@item Add include <grub/dl.h> and module license declaration to "argon2.c".
++@item Remove the following declarations and functions from "argon2.h" and
++ "argon2.c": argon2_type2string, argon2i_hash_encoded, argon2i_hash_raw,
++ argon2d_hash_encoded, argon2d_hash_raw, argon2id_hash_encoded,
++ argon2id_hash_raw, argon2_compare, argon2_verify, argon2i_verify,
++ argon2d_verify, argon2id_verify, argon2d_ctx, argon2i_ctx, argon2id_ctx,
++ argon2_verify_ctx, argon2d_verify_ctx, argon2i_verify_ctx,
++ argon2id_verify_ctx, argon2_encodedlen.
++@item Move the declaration of `clear_internal_memory()` in "blake2-impl.h" to
++ "blake2b.c".
++@item Remove code guarded by the ARGON2_NO_THREADS macro.
++@item Remove parameters `encoded` and `encodedlen` from `argon2_hash` and remove
++ the encoding block in that function.
++@item Remove parameter verifications in `validate_inputs()` for
++ ARGON2_MIN_PWD_LENGTH, ARGON2_MIN_SECRET, ARGON2_MIN_AD_LENGTH and
++ ARGON2_MAX_MEMORY to fix compiler warnings.
++@item Mark the function argon2_ctx as static.
++@end enumerate
++
+ @node Gnulib
+ @section Gnulib
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 8022e1c0a..3a004e88c 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -1174,6 +1174,14 @@ module = {
+ common = lib/json/json.c;
+ };
+
++module = {
++ name = argon2;
++ common = lib/argon2/argon2.c;
++ common = lib/argon2/core.c;
++ common = lib/argon2/ref.c;
++ common = lib/argon2/blake2/blake2b.c;
++};
++
+ module = {
+ name = afsplitter;
+ common = disk/AFSplitter.c;
+diff --git a/grub-core/lib/argon2/LICENSE b/grub-core/lib/argon2/LICENSE
+new file mode 100644
+index 000000000..fa611f7ac
+--- /dev/null
++++ b/grub-core/lib/argon2/LICENSE
+@@ -0,0 +1,314 @@
++Argon2 reference source code package - reference C implementations
++
++Copyright 2015
++Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
++
++You may use this work under the terms of a Creative Commons CC0 1.0
++License/Waiver or the Apache Public License 2.0, at your option. The terms of
++these licenses can be found at:
++
++- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
++- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
++
++The terms of the licenses are reproduced below.
++
++--------------------------------------------------------------------------------
++
++Creative Commons Legal Code
++
++CC0 1.0 Universal
++
++ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
++ LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
++ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
++ INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
++ REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
++ PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
++ THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
++ HEREUNDER.
++
++Statement of Purpose
++
++The laws of most jurisdictions throughout the world automatically confer
++exclusive Copyright and Related Rights (defined below) upon the creator
++and subsequent owner(s) (each and all, an "owner") of an original work of
++authorship and/or a database (each, a "Work").
++
++Certain owners wish to permanently relinquish those rights to a Work for
++the purpose of contributing to a commons of creative, cultural and
++scientific works ("Commons") that the public can reliably and without fear
++of later claims of infringement build upon, modify, incorporate in other
++works, reuse and redistribute as freely as possible in any form whatsoever
++and for any purposes, including without limitation commercial purposes.
++These owners may contribute to the Commons to promote the ideal of a free
++culture and the further production of creative, cultural and scientific
++works, or to gain reputation or greater distribution for their Work in
++part through the use and efforts of others.
++
++For these and/or other purposes and motivations, and without any
++expectation of additional consideration or compensation, the person
++associating CC0 with a Work (the "Affirmer"), to the extent that he or she
++is an owner of Copyright and Related Rights in the Work, voluntarily
++elects to apply CC0 to the Work and publicly distribute the Work under its
++terms, with knowledge of his or her Copyright and Related Rights in the
++Work and the meaning and intended legal effect of CC0 on those rights.
++
++1. Copyright and Related Rights. A Work made available under CC0 may be
++protected by copyright and related or neighboring rights ("Copyright and
++Related Rights"). Copyright and Related Rights include, but are not
++limited to, the following:
++
++ i. the right to reproduce, adapt, distribute, perform, display,
++ communicate, and translate a Work;
++ ii. moral rights retained by the original author(s) and/or performer(s);
++iii. publicity and privacy rights pertaining to a person's image or
++ likeness depicted in a Work;
++ iv. rights protecting against unfair competition in regards to a Work,
++ subject to the limitations in paragraph 4(a), below;
++ v. rights protecting the extraction, dissemination, use and reuse of data
++ in a Work;
++ vi. database rights (such as those arising under Directive 96/9/EC of the
++ European Parliament and of the Council of 11 March 1996 on the legal
++ protection of databases, and under any national implementation
++ thereof, including any amended or successor version of such
++ directive); and
++vii. other similar, equivalent or corresponding rights throughout the
++ world based on applicable law or treaty, and any national
++ implementations thereof.
++
++2. Waiver. To the greatest extent permitted by, but not in contravention
++of, applicable law, Affirmer hereby overtly, fully, permanently,
++irrevocably and unconditionally waives, abandons, and surrenders all of
++Affirmer's Copyright and Related Rights and associated claims and causes
++of action, whether now known or unknown (including existing as well as
++future claims and causes of action), in the Work (i) in all territories
++worldwide, (ii) for the maximum duration provided by applicable law or
++treaty (including future time extensions), (iii) in any current or future
++medium and for any number of copies, and (iv) for any purpose whatsoever,
++including without limitation commercial, advertising or promotional
++purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
++member of the public at large and to the detriment of Affirmer's heirs and
++successors, fully intending that such Waiver shall not be subject to
++revocation, rescission, cancellation, termination, or any other legal or
++equitable action to disrupt the quiet enjoyment of the Work by the public
++as contemplated by Affirmer's express Statement of Purpose.
++
++3. Public License Fallback. Should any part of the Waiver for any reason
++be judged legally invalid or ineffective under applicable law, then the
++Waiver shall be preserved to the maximum extent permitted taking into
++account Affirmer's express Statement of Purpose. In addition, to the
++extent the Waiver is so judged Affirmer hereby grants to each affected
++person a royalty-free, non transferable, non sublicensable, non exclusive,
++irrevocable and unconditional license to exercise Affirmer's Copyright and
++Related Rights in the Work (i) in all territories worldwide, (ii) for the
++maximum duration provided by applicable law or treaty (including future
++time extensions), (iii) in any current or future medium and for any number
++of copies, and (iv) for any purpose whatsoever, including without
++limitation commercial, advertising or promotional purposes (the
++"License"). The License shall be deemed effective as of the date CC0 was
++applied by Affirmer to the Work. Should any part of the License for any
++reason be judged legally invalid or ineffective under applicable law, such
++partial invalidity or ineffectiveness shall not invalidate the remainder
++of the License, and in such case Affirmer hereby affirms that he or she
++will not (i) exercise any of his or her remaining Copyright and Related
++Rights in the Work or (ii) assert any associated claims and causes of
++action with respect to the Work, in either case contrary to Affirmer's
++express Statement of Purpose.
++
++4. Limitations and Disclaimers.
++
++ a. No trademark or patent rights held by Affirmer are waived, abandoned,
++ surrendered, licensed or otherwise affected by this document.
++ b. Affirmer offers the Work as-is and makes no representations or
++ warranties of any kind concerning the Work, express, implied,
++ statutory or otherwise, including without limitation warranties of
++ title, merchantability, fitness for a particular purpose, non
++ infringement, or the absence of latent or other defects, accuracy, or
++ the present or absence of errors, whether or not discoverable, all to
++ the greatest extent permissible under applicable law.
++ c. Affirmer disclaims responsibility for clearing rights of other persons
++ that may apply to the Work or any use thereof, including without
++ limitation any person's Copyright and Related Rights in the Work.
++ Further, Affirmer disclaims responsibility for obtaining any necessary
++ consents, permissions or other rights required for any use of the
++ Work.
++ d. Affirmer understands and acknowledges that Creative Commons is not a
++ party to this document and has no duty or obligation with respect to
++ this CC0 or use of the Work.
++
++--------------------------------------------------------------------------------
++
++ Apache License
++ Version 2.0, January 2004
++ http://www.apache.org/licenses/
++
++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
++
++ 1. Definitions.
++
++ "License" shall mean the terms and conditions for use, reproduction,
++ and distribution as defined by Sections 1 through 9 of this document.
++
++ "Licensor" shall mean the copyright owner or entity authorized by
++ the copyright owner that is granting the License.
++
++ "Legal Entity" shall mean the union of the acting entity and all
++ other entities that control, are controlled by, or are under common
++ control with that entity. For the purposes of this definition,
++ "control" means (i) the power, direct or indirect, to cause the
++ direction or management of such entity, whether by contract or
++ otherwise, or (ii) ownership of fifty percent (50%) or more of the
++ outstanding shares, or (iii) beneficial ownership of such entity.
++
++ "You" (or "Your") shall mean an individual or Legal Entity
++ exercising permissions granted by this License.
++
++ "Source" form shall mean the preferred form for making modifications,
++ including but not limited to software source code, documentation
++ source, and configuration files.
++
++ "Object" form shall mean any form resulting from mechanical
++ transformation or translation of a Source form, including but
++ not limited to compiled object code, generated documentation,
++ and conversions to other media types.
++
++ "Work" shall mean the work of authorship, whether in Source or
++ Object form, made available under the License, as indicated by a
++ copyright notice that is included in or attached to the work
++ (an example is provided in the Appendix below).
++
++ "Derivative Works" shall mean any work, whether in Source or Object
++ form, that is based on (or derived from) the Work and for which the
++ editorial revisions, annotations, elaborations, or other modifications
++ represent, as a whole, an original work of authorship. For the purposes
++ of this License, Derivative Works shall not include works that remain
++ separable from, or merely link (or bind by name) to the interfaces of,
++ the Work and Derivative Works thereof.
++
++ "Contribution" shall mean any work of authorship, including
++ the original version of the Work and any modifications or additions
++ to that Work or Derivative Works thereof, that is intentionally
++ submitted to Licensor for inclusion in the Work by the copyright owner
++ or by an individual or Legal Entity authorized to submit on behalf of
++ the copyright owner. For the purposes of this definition, "submitted"
++ means any form of electronic, verbal, or written communication sent
++ to the Licensor or its representatives, including but not limited to
++ communication on electronic mailing lists, source code control systems,
++ and issue tracking systems that are managed by, or on behalf of, the
++ Licensor for the purpose of discussing and improving the Work, but
++ excluding communication that is conspicuously marked or otherwise
++ designated in writing by the copyright owner as "Not a Contribution."
++
++ "Contributor" shall mean Licensor and any individual or Legal Entity
++ on behalf of whom a Contribution has been received by Licensor and
++ subsequently incorporated within the Work.
++
++ 2. Grant of Copyright License. Subject to the terms and conditions of
++ this License, each Contributor hereby grants to You a perpetual,
++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
++ copyright license to reproduce, prepare Derivative Works of,
++ publicly display, publicly perform, sublicense, and distribute the
++ Work and such Derivative Works in Source or Object form.
++
++ 3. Grant of Patent License. Subject to the terms and conditions of
++ this License, each Contributor hereby grants to You a perpetual,
++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
++ (except as stated in this section) patent license to make, have made,
++ use, offer to sell, sell, import, and otherwise transfer the Work,
++ where such license applies only to those patent claims licensable
++ by such Contributor that are necessarily infringed by their
++ Contribution(s) alone or by combination of their Contribution(s)
++ with the Work to which such Contribution(s) was submitted. If You
++ institute patent litigation against any entity (including a
++ cross-claim or counterclaim in a lawsuit) alleging that the Work
++ or a Contribution incorporated within the Work constitutes direct
++ or contributory patent infringement, then any patent licenses
++ granted to You under this License for that Work shall terminate
++ as of the date such litigation is filed.
++
++ 4. Redistribution. You may reproduce and distribute copies of the
++ Work or Derivative Works thereof in any medium, with or without
++ modifications, and in Source or Object form, provided that You
++ meet the following conditions:
++
++ (a) You must give any other recipients of the Work or
++ Derivative Works a copy of this License; and
++
++ (b) You must cause any modified files to carry prominent notices
++ stating that You changed the files; and
++
++ (c) You must retain, in the Source form of any Derivative Works
++ that You distribute, all copyright, patent, trademark, and
++ attribution notices from the Source form of the Work,
++ excluding those notices that do not pertain to any part of
++ the Derivative Works; and
++
++ (d) If the Work includes a "NOTICE" text file as part of its
++ distribution, then any Derivative Works that You distribute must
++ include a readable copy of the attribution notices contained
++ within such NOTICE file, excluding those notices that do not
++ pertain to any part of the Derivative Works, in at least one
++ of the following places: within a NOTICE text file distributed
++ as part of the Derivative Works; within the Source form or
++ documentation, if provided along with the Derivative Works; or,
++ within a display generated by the Derivative Works, if and
++ wherever such third-party notices normally appear. The contents
++ of the NOTICE file are for informational purposes only and
++ do not modify the License. You may add Your own attribution
++ notices within Derivative Works that You distribute, alongside
++ or as an addendum to the NOTICE text from the Work, provided
++ that such additional attribution notices cannot be construed
++ as modifying the License.
++
++ You may add Your own copyright statement to Your modifications and
++ may provide additional or different license terms and conditions
++ for use, reproduction, or distribution of Your modifications, or
++ for any such Derivative Works as a whole, provided Your use,
++ reproduction, and distribution of the Work otherwise complies with
++ the conditions stated in this License.
++
++ 5. Submission of Contributions. Unless You explicitly state otherwise,
++ any Contribution intentionally submitted for inclusion in the Work
++ by You to the Licensor shall be under the terms and conditions of
++ this License, without any additional terms or conditions.
++ Notwithstanding the above, nothing herein shall supersede or modify
++ the terms of any separate license agreement you may have executed
++ with Licensor regarding such Contributions.
++
++ 6. Trademarks. This License does not grant permission to use the trade
++ names, trademarks, service marks, or product names of the Licensor,
++ except as required for reasonable and customary use in describing the
++ origin of the Work and reproducing the content of the NOTICE file.
++
++ 7. Disclaimer of Warranty. Unless required by applicable law or
++ agreed to in writing, Licensor provides the Work (and each
++ Contributor provides its Contributions) on an "AS IS" BASIS,
++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
++ implied, including, without limitation, any warranties or conditions
++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
++ PARTICULAR PURPOSE. You are solely responsible for determining the
++ appropriateness of using or redistributing the Work and assume any
++ risks associated with Your exercise of permissions under this License.
++
++ 8. Limitation of Liability. In no event and under no legal theory,
++ whether in tort (including negligence), contract, or otherwise,
++ unless required by applicable law (such as deliberate and grossly
++ negligent acts) or agreed to in writing, shall any Contributor be
++ liable to You for damages, including any direct, indirect, special,
++ incidental, or consequential damages of any character arising as a
++ result of this License or out of the use or inability to use the
++ Work (including but not limited to damages for loss of goodwill,
++ work stoppage, computer failure or malfunction, or any and all
++ other commercial damages or losses), even if such Contributor
++ has been advised of the possibility of such damages.
++
++ 9. Accepting Warranty or Additional Liability. While redistributing
++ the Work or Derivative Works thereof, You may choose to offer,
++ and charge a fee for, acceptance of support, warranty, indemnity,
++ or other liability obligations and/or rights consistent with this
++ License. However, in accepting such obligations, You may act only
++ on Your own behalf and on Your sole responsibility, not on behalf
++ of any other Contributor, and only if You agree to indemnify,
++ defend, and hold each Contributor harmless for any liability
++ incurred by, or claims asserted against, such Contributor by reason
++ of your accepting any such warranty or additional liability.
+diff --git a/grub-core/lib/argon2/argon2.c b/grub-core/lib/argon2/argon2.c
+new file mode 100644
+index 000000000..49532fe80
+--- /dev/null
++++ b/grub-core/lib/argon2/argon2.c
+@@ -0,0 +1,232 @@
++/*
++ * Argon2 reference source code package - reference C implementations
++ *
++ * Copyright 2015
++ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
++ *
++ * You may use this work under the terms of a Creative Commons CC0 1.0
++ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
++ * these licenses can be found at:
++ *
++ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
++ * - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * You should have received a copy of both of these licenses along with this
++ * software. If not, they may be obtained at the above URLs.
++ */
++
++#include <grub/dl.h>
++
++#include "argon2.h"
++#include "core.h"
++
++GRUB_MOD_LICENSE ("CC0");
++
++static int argon2_ctx(argon2_context *context, argon2_type type) {
++ /* 1. Validate all inputs */
++ int result = validate_inputs(context);
++ grub_uint32_t memory_blocks, segment_length;
++ argon2_instance_t instance;
++
++ if (ARGON2_OK != result) {
++ return result;
++ }
++
++ if (Argon2_d != type && Argon2_i != type && Argon2_id != type) {
++ return ARGON2_INCORRECT_TYPE;
++ }
++
++ /* 2. Align memory size */
++ /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */
++ memory_blocks = context->m_cost;
++
++ if (memory_blocks < 2 * ARGON2_SYNC_POINTS * context->lanes) {
++ memory_blocks = 2 * ARGON2_SYNC_POINTS * context->lanes;
++ }
++
++ segment_length = memory_blocks / (context->lanes * ARGON2_SYNC_POINTS);
++ /* Ensure that all segments have equal length */
++ memory_blocks = segment_length * (context->lanes * ARGON2_SYNC_POINTS);
++
++ instance.version = context->version;
++ instance.memory = NULL;
++ instance.passes = context->t_cost;
++ instance.memory_blocks = memory_blocks;
++ instance.segment_length = segment_length;
++ instance.lane_length = segment_length * ARGON2_SYNC_POINTS;
++ instance.lanes = context->lanes;
++ instance.threads = context->threads;
++ instance.type = type;
++
++ if (instance.threads > instance.lanes) {
++ instance.threads = instance.lanes;
++ }
++
++ /* 3. Initialization: Hashing inputs, allocating memory, filling first
++ * blocks
++ */
++ result = initialize(&instance, context);
++
++ if (ARGON2_OK != result) {
++ return result;
++ }
++
++ /* 4. Filling memory */
++ result = fill_memory_blocks(&instance);
++
++ if (ARGON2_OK != result) {
++ return result;
++ }
++ /* 5. Finalization */
++ finalize(context, &instance);
++
++ return ARGON2_OK;
++}
++
++int argon2_hash(const grub_uint32_t t_cost, const grub_uint32_t m_cost,
++ const grub_uint32_t parallelism, const void *pwd,
++ const grub_size_t pwdlen, const void *salt, const grub_size_t saltlen,
++ void *hash, const grub_size_t hashlen, argon2_type type,
++ const grub_uint32_t version){
++
++ argon2_context context;
++ int result;
++ grub_uint8_t *out;
++
++ if (pwdlen > ARGON2_MAX_PWD_LENGTH) {
++ return ARGON2_PWD_TOO_LONG;
++ }
++
++ if (saltlen > ARGON2_MAX_SALT_LENGTH) {
++ return ARGON2_SALT_TOO_LONG;
++ }
++
++ if (hashlen > ARGON2_MAX_OUTLEN) {
++ return ARGON2_OUTPUT_TOO_LONG;
++ }
++
++ if (hashlen < ARGON2_MIN_OUTLEN) {
++ return ARGON2_OUTPUT_TOO_SHORT;
++ }
++
++ out = grub_malloc(hashlen);
++ if (!out) {
++ return ARGON2_MEMORY_ALLOCATION_ERROR;
++ }
++
++ context.out = (grub_uint8_t *)out;
++ context.outlen = (grub_uint32_t)hashlen;
++ context.pwd = CONST_CAST(grub_uint8_t *)pwd;
++ context.pwdlen = (grub_uint32_t)pwdlen;
++ context.salt = CONST_CAST(grub_uint8_t *)salt;
++ context.saltlen = (grub_uint32_t)saltlen;
++ context.secret = NULL;
++ context.secretlen = 0;
++ context.ad = NULL;
++ context.adlen = 0;
++ context.t_cost = t_cost;
++ context.m_cost = m_cost;
++ context.lanes = parallelism;
++ context.threads = parallelism;
++ context.allocate_cbk = NULL;
++ context.grub_free_cbk = NULL;
++ context.flags = ARGON2_DEFAULT_FLAGS;
++ context.version = version;
++
++ result = argon2_ctx(&context, type);
++
++ if (result != ARGON2_OK) {
++ clear_internal_memory(out, hashlen);
++ grub_free(out);
++ return result;
++ }
++
++ /* if raw hash requested, write it */
++ if (hash) {
++ grub_memcpy(hash, out, hashlen);
++ }
++
++ clear_internal_memory(out, hashlen);
++ grub_free(out);
++
++ return ARGON2_OK;
++}
++
++const char *argon2_error_message(int error_code) {
++ switch (error_code) {
++ case ARGON2_OK:
++ return "OK";
++ case ARGON2_OUTPUT_PTR_NULL:
++ return "Output pointer is NULL";
++ case ARGON2_OUTPUT_TOO_SHORT:
++ return "Output is too short";
++ case ARGON2_OUTPUT_TOO_LONG:
++ return "Output is too long";
++ case ARGON2_PWD_TOO_SHORT:
++ return "Password is too short";
++ case ARGON2_PWD_TOO_LONG:
++ return "Password is too long";
++ case ARGON2_SALT_TOO_SHORT:
++ return "Salt is too short";
++ case ARGON2_SALT_TOO_LONG:
++ return "Salt is too long";
++ case ARGON2_AD_TOO_SHORT:
++ return "Associated data is too short";
++ case ARGON2_AD_TOO_LONG:
++ return "Associated data is too long";
++ case ARGON2_SECRET_TOO_SHORT:
++ return "Secret is too short";
++ case ARGON2_SECRET_TOO_LONG:
++ return "Secret is too long";
++ case ARGON2_TIME_TOO_SMALL:
++ return "Time cost is too small";
++ case ARGON2_TIME_TOO_LARGE:
++ return "Time cost is too large";
++ case ARGON2_MEMORY_TOO_LITTLE:
++ return "Memory cost is too small";
++ case ARGON2_MEMORY_TOO_MUCH:
++ return "Memory cost is too large";
++ case ARGON2_LANES_TOO_FEW:
++ return "Too few lanes";
++ case ARGON2_LANES_TOO_MANY:
++ return "Too many lanes";
++ case ARGON2_PWD_PTR_MISMATCH:
++ return "Password pointer is NULL, but password length is not 0";
++ case ARGON2_SALT_PTR_MISMATCH:
++ return "Salt pointer is NULL, but salt length is not 0";
++ case ARGON2_SECRET_PTR_MISMATCH:
++ return "Secret pointer is NULL, but secret length is not 0";
++ case ARGON2_AD_PTR_MISMATCH:
++ return "Associated data pointer is NULL, but ad length is not 0";
++ case ARGON2_MEMORY_ALLOCATION_ERROR:
++ return "Memory allocation error";
++ case ARGON2_FREE_MEMORY_CBK_NULL:
++ return "The grub_free memory callback is NULL";
++ case ARGON2_ALLOCATE_MEMORY_CBK_NULL:
++ return "The allocate memory callback is NULL";
++ case ARGON2_INCORRECT_PARAMETER:
++ return "Argon2_Context context is NULL";
++ case ARGON2_INCORRECT_TYPE:
++ return "There is no such version of Argon2";
++ case ARGON2_OUT_PTR_MISMATCH:
++ return "Output pointer mismatch";
++ case ARGON2_THREADS_TOO_FEW:
++ return "Not enough threads";
++ case ARGON2_THREADS_TOO_MANY:
++ return "Too many threads";
++ case ARGON2_MISSING_ARGS:
++ return "Missing arguments";
++ case ARGON2_ENCODING_FAIL:
++ return "Encoding failed";
++ case ARGON2_DECODING_FAIL:
++ return "Decoding failed";
++ case ARGON2_THREAD_FAIL:
++ return "Threading failure";
++ case ARGON2_DECODING_LENGTH_FAIL:
++ return "Some of encoded parameters are too long or too short";
++ case ARGON2_VERIFY_MISMATCH:
++ return "The password does not match the supplied hash";
++ default:
++ return "Unknown error code";
++ }
++}
+diff --git a/grub-core/lib/argon2/argon2.h b/grub-core/lib/argon2/argon2.h
+new file mode 100644
+index 000000000..129f7efbd
+--- /dev/null
++++ b/grub-core/lib/argon2/argon2.h
+@@ -0,0 +1,264 @@
++/*
++ * Argon2 reference source code package - reference C implementations
++ *
++ * Copyright 2015
++ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
++ *
++ * You may use this work under the terms of a Creative Commons CC0 1.0
++ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
++ * these licenses can be found at:
++ *
++ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
++ * - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * You should have received a copy of both of these licenses along with this
++ * software. If not, they may be obtained at the above URLs.
++ */
++
++#ifndef ARGON2_H
++#define ARGON2_H
++
++#include <grub/misc.h>
++#include <grub/mm.h>
++
++#if defined(__cplusplus)
++extern "C" {
++#endif
++
++/* Symbols visibility control */
++#ifdef A2_VISCTL
++#define ARGON2_PUBLIC __attribute__((visibility("default")))
++#define ARGON2_LOCAL __attribute__ ((visibility ("hidden")))
++#elif defined(_MSC_VER)
++#define ARGON2_PUBLIC __declspec(dllexport)
++#define ARGON2_LOCAL
++#else
++#define ARGON2_PUBLIC
++#define ARGON2_LOCAL
++#endif
++
++/*
++ * Argon2 input parameter restrictions
++ */
++
++/* Minimum and maximum number of lanes (degree of parallelism) */
++#define ARGON2_MIN_LANES GRUB_UINT32_C(1)
++#define ARGON2_MAX_LANES GRUB_UINT32_C(0xFFFFFF)
++
++/* Minimum and maximum number of threads */
++#define ARGON2_MIN_THREADS GRUB_UINT32_C(1)
++#define ARGON2_MAX_THREADS GRUB_UINT32_C(0xFFFFFF)
++
++/* Number of synchronization points between lanes per pass */
++#define ARGON2_SYNC_POINTS GRUB_UINT32_C(4)
++
++/* Minimum and maximum digest size in bytes */
++#define ARGON2_MIN_OUTLEN GRUB_UINT32_C(4)
++#define ARGON2_MAX_OUTLEN GRUB_UINT32_C(0xFFFFFFFF)
++
++/* Minimum and maximum number of memory blocks (each of BLOCK_SIZE bytes) */
++#define ARGON2_MIN_MEMORY (2 * ARGON2_SYNC_POINTS) /* 2 blocks per slice */
++
++#define ARGON2_MIN(a, b) ((a) < (b) ? (a) : (b))
++/* Max memory size is addressing-space/2, topping at 2^32 blocks (4 TB) */
++#define ARGON2_MAX_MEMORY_BITS \
++ ARGON2_MIN(GRUB_UINT32_C(32), (sizeof(void *) * GRUB_CHAR_BIT - 10 - 1))
++#define ARGON2_MAX_MEMORY \
++ ARGON2_MIN(GRUB_UINT32_C(0xFFFFFFFF), GRUB_UINT64_C(1) << ARGON2_MAX_MEMORY_BITS)
++
++/* Minimum and maximum number of passes */
++#define ARGON2_MIN_TIME GRUB_UINT32_C(1)
++#define ARGON2_MAX_TIME GRUB_UINT32_C(0xFFFFFFFF)
++
++/* Minimum and maximum password length in bytes */
++#define ARGON2_MIN_PWD_LENGTH GRUB_UINT32_C(0)
++#define ARGON2_MAX_PWD_LENGTH GRUB_UINT32_C(0xFFFFFFFF)
++
++/* Minimum and maximum associated data length in bytes */
++#define ARGON2_MIN_AD_LENGTH GRUB_UINT32_C(0)
++#define ARGON2_MAX_AD_LENGTH GRUB_UINT32_C(0xFFFFFFFF)
++
++/* Minimum and maximum salt length in bytes */
++#define ARGON2_MIN_SALT_LENGTH GRUB_UINT32_C(8)
++#define ARGON2_MAX_SALT_LENGTH GRUB_UINT32_C(0xFFFFFFFF)
++
++/* Minimum and maximum key length in bytes */
++#define ARGON2_MIN_SECRET GRUB_UINT32_C(0)
++#define ARGON2_MAX_SECRET GRUB_UINT32_C(0xFFFFFFFF)
++
++/* Flags to determine which fields are securely wiped (default = no wipe). */
++#define ARGON2_DEFAULT_FLAGS GRUB_UINT32_C(0)
++#define ARGON2_FLAG_CLEAR_PASSWORD (GRUB_UINT32_C(1) << 0)
++#define ARGON2_FLAG_CLEAR_SECRET (GRUB_UINT32_C(1) << 1)
++
++/* Global flag to determine if we are wiping internal memory buffers. This flag
++ * is defined in core.c and defaults to 1 (wipe internal memory). */
++extern int FLAG_clear_internal_memory;
++
++/* Error codes */
++typedef enum Argon2_ErrorCodes {
++ ARGON2_OK = 0,
++
++ ARGON2_OUTPUT_PTR_NULL = -1,
++
++ ARGON2_OUTPUT_TOO_SHORT = -2,
++ ARGON2_OUTPUT_TOO_LONG = -3,
++
++ ARGON2_PWD_TOO_SHORT = -4,
++ ARGON2_PWD_TOO_LONG = -5,
++
++ ARGON2_SALT_TOO_SHORT = -6,
++ ARGON2_SALT_TOO_LONG = -7,
++
++ ARGON2_AD_TOO_SHORT = -8,
++ ARGON2_AD_TOO_LONG = -9,
++
++ ARGON2_SECRET_TOO_SHORT = -10,
++ ARGON2_SECRET_TOO_LONG = -11,
++
++ ARGON2_TIME_TOO_SMALL = -12,
++ ARGON2_TIME_TOO_LARGE = -13,
++
++ ARGON2_MEMORY_TOO_LITTLE = -14,
++ ARGON2_MEMORY_TOO_MUCH = -15,
++
++ ARGON2_LANES_TOO_FEW = -16,
++ ARGON2_LANES_TOO_MANY = -17,
++
++ ARGON2_PWD_PTR_MISMATCH = -18, /* NULL ptr with non-zero length */
++ ARGON2_SALT_PTR_MISMATCH = -19, /* NULL ptr with non-zero length */
++ ARGON2_SECRET_PTR_MISMATCH = -20, /* NULL ptr with non-zero length */
++ ARGON2_AD_PTR_MISMATCH = -21, /* NULL ptr with non-zero length */
++
++ ARGON2_MEMORY_ALLOCATION_ERROR = -22,
++
++ ARGON2_FREE_MEMORY_CBK_NULL = -23,
++ ARGON2_ALLOCATE_MEMORY_CBK_NULL = -24,
++
++ ARGON2_INCORRECT_PARAMETER = -25,
++ ARGON2_INCORRECT_TYPE = -26,
++
++ ARGON2_OUT_PTR_MISMATCH = -27,
++
++ ARGON2_THREADS_TOO_FEW = -28,
++ ARGON2_THREADS_TOO_MANY = -29,
++
++ ARGON2_MISSING_ARGS = -30,
++
++ ARGON2_ENCODING_FAIL = -31,
++
++ ARGON2_DECODING_FAIL = -32,
++
++ ARGON2_THREAD_FAIL = -33,
++
++ ARGON2_DECODING_LENGTH_FAIL = -34,
++
++ ARGON2_VERIFY_MISMATCH = -35
++} argon2_error_codes;
++
++/* Memory allocator types --- for external allocation */
++typedef int (*allocate_fptr)(grub_uint8_t **memory, grub_size_t bytes_to_allocate);
++typedef void (*deallocate_fptr)(grub_uint8_t *memory, grub_size_t bytes_to_allocate);
++
++/* Argon2 external data structures */
++
++/*
++ *****
++ * Context: structure to hold Argon2 inputs:
++ * output array and its length,
++ * password and its length,
++ * salt and its length,
++ * secret and its length,
++ * associated data and its length,
++ * number of passes, amount of used memory (in KBytes, can be rounded up a bit)
++ * number of parallel threads that will be run.
++ * All the parameters above affect the output hash value.
++ * Additionally, two function pointers can be provided to allocate and
++ * deallocate the memory (if NULL, memory will be allocated internally).
++ * Also, three flags indicate whether to erase password, secret as soon as they
++ * are pre-hashed (and thus not needed anymore), and the entire memory
++ *****
++ * Simplest situation: you have output array out[8], password is stored in
++ * pwd[32], salt is stored in salt[16], you do not have keys nor associated
++ * data. You need to spend 1 GB of RAM and you run 5 passes of Argon2d with
++ * 4 parallel lanes.
++ * You want to erase the password, but you're OK with last pass not being
++ * erased. You want to use the default memory allocator.
++ * Then you initialize:
++ Argon2_Context(out,8,pwd,32,salt,16,NULL,0,NULL,0,5,1<<20,4,4,NULL,NULL,true,false,false,false)
++ */
++typedef struct Argon2_Context {
++ grub_uint8_t *out; /* output array */
++ grub_uint32_t outlen; /* digest length */
++
++ grub_uint8_t *pwd; /* password array */
++ grub_uint32_t pwdlen; /* password length */
++
++ grub_uint8_t *salt; /* salt array */
++ grub_uint32_t saltlen; /* salt length */
++
++ grub_uint8_t *secret; /* key array */
++ grub_uint32_t secretlen; /* key length */
++
++ grub_uint8_t *ad; /* associated data array */
++ grub_uint32_t adlen; /* associated data length */
++
++ grub_uint32_t t_cost; /* number of passes */
++ grub_uint32_t m_cost; /* amount of memory requested (KB) */
++ grub_uint32_t lanes; /* number of lanes */
++ grub_uint32_t threads; /* maximum number of threads */
++
++ grub_uint32_t version; /* version number */
++
++ allocate_fptr allocate_cbk; /* pointer to memory allocator */
++ deallocate_fptr grub_free_cbk; /* pointer to memory deallocator */
++
++ grub_uint32_t flags; /* array of bool options */
++} argon2_context;
++
++/* Argon2 primitive type */
++typedef enum Argon2_type {
++ Argon2_d = 0,
++ Argon2_i = 1,
++ Argon2_id = 2
++} argon2_type;
++
++/* Version of the algorithm */
++typedef enum Argon2_version {
++ ARGON2_VERSION_10 = 0x10,
++ ARGON2_VERSION_13 = 0x13,
++ ARGON2_VERSION_NUMBER = ARGON2_VERSION_13
++} argon2_version;
++
++/**
++ * Hashes a password with Argon2, producing a raw hash at @hash
++ * @param t_cost Number of iterations
++ * @param m_cost Sets memory usage to m_cost kibibytes
++ * @param parallelism Number of threads and compute lanes
++ * @param pwd Pointer to password
++ * @param pwdlen Password size in bytes
++ * @param salt Pointer to salt
++ * @param saltlen Salt size in bytes
++ * @param hash Buffer where to write the raw hash - updated by the function
++ * @param hashlen Desired length of the hash in bytes
++ * @pre Different parallelism levels will give different results
++ * @pre Returns ARGON2_OK if successful
++ */
++ARGON2_PUBLIC int argon2_hash(const grub_uint32_t t_cost, const grub_uint32_t m_cost,
++ const grub_uint32_t parallelism, const void *pwd,
++ const grub_size_t pwdlen, const void *salt,
++ const grub_size_t saltlen, void *hash,
++ const grub_size_t hashlen, argon2_type type,
++ const grub_uint32_t version);
++
++/**
++ * Get the associated error message for given error code
++ * @return The error message associated with the given error code
++ */
++ARGON2_PUBLIC const char *argon2_error_message(int error_code);
++
++#if defined(__cplusplus)
++}
++#endif
++
++#endif
+diff --git a/grub-core/lib/argon2/blake2/blake2-impl.h b/grub-core/lib/argon2/blake2/blake2-impl.h
+new file mode 100644
+index 000000000..3a795680b
+--- /dev/null
++++ b/grub-core/lib/argon2/blake2/blake2-impl.h
+@@ -0,0 +1,151 @@
++/*
++ * Argon2 reference source code package - reference C implementations
++ *
++ * Copyright 2015
++ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
++ *
++ * You may use this work under the terms of a Creative Commons CC0 1.0
++ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
++ * these licenses can be found at:
++ *
++ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
++ * - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * You should have received a copy of both of these licenses along with this
++ * software. If not, they may be obtained at the above URLs.
++ */
++
++#ifndef PORTABLE_BLAKE2_IMPL_H
++#define PORTABLE_BLAKE2_IMPL_H
++
++#if defined(_MSC_VER)
++#define BLAKE2_INLINE __inline
++#elif defined(__GNUC__) || defined(__clang__)
++#define BLAKE2_INLINE __inline__
++#else
++#define BLAKE2_INLINE
++#endif
++
++/* Argon2 Team - Begin Code */
++/*
++ Not an exhaustive list, but should cover the majority of modern platforms
++ Additionally, the code will always be correct---this is only a performance
++ tweak.
++*/
++#if (defined(__BYTE_ORDER__) && \
++ (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \
++ defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \
++ defined(__AARCH64EL__) || defined(__amd64__) || defined(__i386__) || \
++ defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || \
++ defined(_M_ARM)
++#define NATIVE_LITTLE_ENDIAN
++#endif
++/* Argon2 Team - End Code */
++
++static BLAKE2_INLINE grub_uint32_t load32(const void *src) {
++#if defined(NATIVE_LITTLE_ENDIAN)
++ grub_uint32_t w;
++ grub_memcpy(&w, src, sizeof w);
++ return w;
++#else
++ const grub_uint8_t *p = (const grub_uint8_t *)src;
++ grub_uint32_t w = *p++;
++ w |= (grub_uint32_t)(*p++) << 8;
++ w |= (grub_uint32_t)(*p++) << 16;
++ w |= (grub_uint32_t)(*p++) << 24;
++ return w;
++#endif
++}
++
++static BLAKE2_INLINE grub_uint64_t load64(const void *src) {
++#if defined(NATIVE_LITTLE_ENDIAN)
++ grub_uint64_t w;
++ grub_memcpy(&w, src, sizeof w);
++ return w;
++#else
++ const grub_uint8_t *p = (const grub_uint8_t *)src;
++ grub_uint64_t w = *p++;
++ w |= (grub_uint64_t)(*p++) << 8;
++ w |= (grub_uint64_t)(*p++) << 16;
++ w |= (grub_uint64_t)(*p++) << 24;
++ w |= (grub_uint64_t)(*p++) << 32;
++ w |= (grub_uint64_t)(*p++) << 40;
++ w |= (grub_uint64_t)(*p++) << 48;
++ w |= (grub_uint64_t)(*p++) << 56;
++ return w;
++#endif
++}
++
++static BLAKE2_INLINE void store32(void *dst, grub_uint32_t w) {
++#if defined(NATIVE_LITTLE_ENDIAN)
++ grub_memcpy(dst, &w, sizeof w);
++#else
++ grub_uint8_t *p = (grub_uint8_t *)dst;
++ *p++ = (grub_uint8_t)w;
++ w >>= 8;
++ *p++ = (grub_uint8_t)w;
++ w >>= 8;
++ *p++ = (grub_uint8_t)w;
++ w >>= 8;
++ *p++ = (grub_uint8_t)w;
++#endif
++}
++
++static BLAKE2_INLINE void store64(void *dst, grub_uint64_t w) {
++#if defined(NATIVE_LITTLE_ENDIAN)
++ grub_memcpy(dst, &w, sizeof w);
++#else
++ grub_uint8_t *p = (grub_uint8_t *)dst;
++ *p++ = (grub_uint8_t)w;
++ w >>= 8;
++ *p++ = (grub_uint8_t)w;
++ w >>= 8;
++ *p++ = (grub_uint8_t)w;
++ w >>= 8;
++ *p++ = (grub_uint8_t)w;
++ w >>= 8;
++ *p++ = (grub_uint8_t)w;
++ w >>= 8;
++ *p++ = (grub_uint8_t)w;
++ w >>= 8;
++ *p++ = (grub_uint8_t)w;
++ w >>= 8;
++ *p++ = (grub_uint8_t)w;
++#endif
++}
++
++static BLAKE2_INLINE grub_uint64_t load48(const void *src) {
++ const grub_uint8_t *p = (const grub_uint8_t *)src;
++ grub_uint64_t w = *p++;
++ w |= (grub_uint64_t)(*p++) << 8;
++ w |= (grub_uint64_t)(*p++) << 16;
++ w |= (grub_uint64_t)(*p++) << 24;
++ w |= (grub_uint64_t)(*p++) << 32;
++ w |= (grub_uint64_t)(*p++) << 40;
++ return w;
++}
++
++static BLAKE2_INLINE void store48(void *dst, grub_uint64_t w) {
++ grub_uint8_t *p = (grub_uint8_t *)dst;
++ *p++ = (grub_uint8_t)w;
++ w >>= 8;
++ *p++ = (grub_uint8_t)w;
++ w >>= 8;
++ *p++ = (grub_uint8_t)w;
++ w >>= 8;
++ *p++ = (grub_uint8_t)w;
++ w >>= 8;
++ *p++ = (grub_uint8_t)w;
++ w >>= 8;
++ *p++ = (grub_uint8_t)w;
++}
++
++static BLAKE2_INLINE grub_uint32_t rotr32(const grub_uint32_t w, const unsigned c) {
++ return (w >> c) | (w << (32 - c));
++}
++
++static BLAKE2_INLINE grub_uint64_t rotr64(const grub_uint64_t w, const unsigned c) {
++ return (w >> c) | (w << (64 - c));
++}
++
++#endif
+diff --git a/grub-core/lib/argon2/blake2/blake2.h b/grub-core/lib/argon2/blake2/blake2.h
+new file mode 100644
+index 000000000..4e8efeb22
+--- /dev/null
++++ b/grub-core/lib/argon2/blake2/blake2.h
+@@ -0,0 +1,89 @@
++/*
++ * Argon2 reference source code package - reference C implementations
++ *
++ * Copyright 2015
++ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
++ *
++ * You may use this work under the terms of a Creative Commons CC0 1.0
++ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
++ * these licenses can be found at:
++ *
++ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
++ * - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * You should have received a copy of both of these licenses along with this
++ * software. If not, they may be obtained at the above URLs.
++ */
++
++#ifndef PORTABLE_BLAKE2_H
++#define PORTABLE_BLAKE2_H
++
++#include "../argon2.h"
++
++#if defined(__cplusplus)
++extern "C" {
++#endif
++
++enum blake2b_constant {
++ BLAKE2B_BLOCKBYTES = 128,
++ BLAKE2B_OUTBYTES = 64,
++ BLAKE2B_KEYBYTES = 64,
++ BLAKE2B_SALTBYTES = 16,
++ BLAKE2B_PERSONALBYTES = 16
++};
++
++#pragma pack(push, 1)
++typedef struct __blake2b_param {
++ grub_uint8_t digest_length; /* 1 */
++ grub_uint8_t key_length; /* 2 */
++ grub_uint8_t fanout; /* 3 */
++ grub_uint8_t depth; /* 4 */
++ grub_uint32_t leaf_length; /* 8 */
++ grub_uint64_t node_offset; /* 16 */
++ grub_uint8_t node_depth; /* 17 */
++ grub_uint8_t inner_length; /* 18 */
++ grub_uint8_t reserved[14]; /* 32 */
++ grub_uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */
++ grub_uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */
++} blake2b_param;
++#pragma pack(pop)
++
++typedef struct __blake2b_state {
++ grub_uint64_t h[8];
++ grub_uint64_t t[2];
++ grub_uint64_t f[2];
++ grub_uint8_t buf[BLAKE2B_BLOCKBYTES];
++ unsigned buflen;
++ unsigned outlen;
++ grub_uint8_t last_node;
++} blake2b_state;
++
++/* Ensure param structs have not been wrongly padded */
++/* Poor man's static_assert */
++enum {
++ blake2_size_check_0 = 1 / !!(GRUB_CHAR_BIT == 8),
++ blake2_size_check_2 =
++ 1 / !!(sizeof(blake2b_param) == sizeof(grub_uint64_t) * GRUB_CHAR_BIT)
++};
++
++/* Streaming API */
++ARGON2_LOCAL int blake2b_init(blake2b_state *S, grub_size_t outlen);
++ARGON2_LOCAL int blake2b_init_key(blake2b_state *S, grub_size_t outlen, const void *key,
++ grub_size_t keylen);
++ARGON2_LOCAL int blake2b_init_param(blake2b_state *S, const blake2b_param *P);
++ARGON2_LOCAL int blake2b_update(blake2b_state *S, const void *in, grub_size_t inlen);
++ARGON2_LOCAL int blake2b_final(blake2b_state *S, void *out, grub_size_t outlen);
++
++/* Simple API */
++ARGON2_LOCAL int blake2b(void *out, grub_size_t outlen, const void *in, grub_size_t inlen,
++ const void *key, grub_size_t keylen);
++
++/* Argon2 Team - Begin Code */
++ARGON2_LOCAL int blake2b_long(void *out, grub_size_t outlen, const void *in, grub_size_t inlen);
++/* Argon2 Team - End Code */
++
++#if defined(__cplusplus)
++}
++#endif
++
++#endif
+diff --git a/grub-core/lib/argon2/blake2/blake2b.c b/grub-core/lib/argon2/blake2/blake2b.c
+new file mode 100644
+index 000000000..53abd7bef
+--- /dev/null
++++ b/grub-core/lib/argon2/blake2/blake2b.c
+@@ -0,0 +1,388 @@
++/*
++ * Argon2 reference source code package - reference C implementations
++ *
++ * Copyright 2015
++ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
++ *
++ * You may use this work under the terms of a Creative Commons CC0 1.0
++ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
++ * these licenses can be found at:
++ *
++ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
++ * - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * You should have received a copy of both of these licenses along with this
++ * software. If not, they may be obtained at the above URLs.
++ */
++
++#include "blake2.h"
++#include "blake2-impl.h"
++
++static const grub_uint64_t blake2b_IV[8] = {
++ GRUB_UINT64_C(0x6a09e667f3bcc908), GRUB_UINT64_C(0xbb67ae8584caa73b),
++ GRUB_UINT64_C(0x3c6ef372fe94f82b), GRUB_UINT64_C(0xa54ff53a5f1d36f1),
++ GRUB_UINT64_C(0x510e527fade682d1), GRUB_UINT64_C(0x9b05688c2b3e6c1f),
++ GRUB_UINT64_C(0x1f83d9abfb41bd6b), GRUB_UINT64_C(0x5be0cd19137e2179)};
++
++static const unsigned int blake2b_sigma[12][16] = {
++ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
++ {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
++ {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
++ {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
++ {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
++ {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
++ {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
++ {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
++ {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
++ {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
++ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
++ {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
++};
++
++void clear_internal_memory(void *v, grub_size_t n);
++
++static BLAKE2_INLINE void blake2b_set_lastnode(blake2b_state *S) {
++ S->f[1] = (grub_uint64_t)-1;
++}
++
++static BLAKE2_INLINE void blake2b_set_lastblock(blake2b_state *S) {
++ if (S->last_node) {
++ blake2b_set_lastnode(S);
++ }
++ S->f[0] = (grub_uint64_t)-1;
++}
++
++static BLAKE2_INLINE void blake2b_increment_counter(blake2b_state *S,
++ grub_uint64_t inc) {
++ S->t[0] += inc;
++ S->t[1] += (S->t[0] < inc);
++}
++
++static BLAKE2_INLINE void blake2b_invalidate_state(blake2b_state *S) {
++ clear_internal_memory(S, sizeof(*S)); /* wipe */
++ blake2b_set_lastblock(S); /* invalidate for further use */
++}
++
++static BLAKE2_INLINE void blake2b_init0(blake2b_state *S) {
++ grub_memset(S, 0, sizeof(*S));
++ grub_memcpy(S->h, blake2b_IV, sizeof(S->h));
++}
++
++int blake2b_init_param(blake2b_state *S, const blake2b_param *P) {
++ const unsigned char *p = (const unsigned char *)P;
++ unsigned int i;
++
++ if (NULL == P || NULL == S) {
++ return -1;
++ }
++
++ blake2b_init0(S);
++ /* IV XOR Parameter Block */
++ for (i = 0; i < 8; ++i) {
++ S->h[i] ^= load64(&p[i * sizeof(S->h[i])]);
++ }
++ S->outlen = P->digest_length;
++ return 0;
++}
++
++/* Sequential blake2b initialization */
++int blake2b_init(blake2b_state *S, grub_size_t outlen) {
++ blake2b_param P;
++
++ if (S == NULL) {
++ return -1;
++ }
++
++ if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) {
++ blake2b_invalidate_state(S);
++ return -1;
++ }
++
++ /* Setup Parameter Block for unkeyed BLAKE2 */
++ P.digest_length = (grub_uint8_t)outlen;
++ P.key_length = 0;
++ P.fanout = 1;
++ P.depth = 1;
++ P.leaf_length = 0;
++ P.node_offset = 0;
++ P.node_depth = 0;
++ P.inner_length = 0;
++ grub_memset(P.reserved, 0, sizeof(P.reserved));
++ grub_memset(P.salt, 0, sizeof(P.salt));
++ grub_memset(P.personal, 0, sizeof(P.personal));
++
++ return blake2b_init_param(S, &P);
++}
++
++int blake2b_init_key(blake2b_state *S, grub_size_t outlen, const void *key,
++ grub_size_t keylen) {
++ blake2b_param P;
++
++ if (S == NULL) {
++ return -1;
++ }
++
++ if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) {
++ blake2b_invalidate_state(S);
++ return -1;
++ }
++
++ if ((key == 0) || (keylen == 0) || (keylen > BLAKE2B_KEYBYTES)) {
++ blake2b_invalidate_state(S);
++ return -1;
++ }
++
++ /* Setup Parameter Block for keyed BLAKE2 */
++ P.digest_length = (grub_uint8_t)outlen;
++ P.key_length = (grub_uint8_t)keylen;
++ P.fanout = 1;
++ P.depth = 1;
++ P.leaf_length = 0;
++ P.node_offset = 0;
++ P.node_depth = 0;
++ P.inner_length = 0;
++ grub_memset(P.reserved, 0, sizeof(P.reserved));
++ grub_memset(P.salt, 0, sizeof(P.salt));
++ grub_memset(P.personal, 0, sizeof(P.personal));
++
++ if (blake2b_init_param(S, &P) < 0) {
++ blake2b_invalidate_state(S);
++ return -1;
++ }
++
++ {
++ grub_uint8_t block[BLAKE2B_BLOCKBYTES];
++ grub_memset(block, 0, BLAKE2B_BLOCKBYTES);
++ grub_memcpy(block, key, keylen);
++ blake2b_update(S, block, BLAKE2B_BLOCKBYTES);
++ /* Burn the key from stack */
++ clear_internal_memory(block, BLAKE2B_BLOCKBYTES);
++ }
++ return 0;
++}
++
++static void blake2b_compress(blake2b_state *S, const grub_uint8_t *block) {
++ grub_uint64_t m[16];
++ grub_uint64_t v[16];
++ unsigned int i, r;
++
++ for (i = 0; i < 16; ++i) {
++ m[i] = load64(block + i * sizeof(m[i]));
++ }
++
++ for (i = 0; i < 8; ++i) {
++ v[i] = S->h[i];
++ }
++
++ v[8] = blake2b_IV[0];
++ v[9] = blake2b_IV[1];
++ v[10] = blake2b_IV[2];
++ v[11] = blake2b_IV[3];
++ v[12] = blake2b_IV[4] ^ S->t[0];
++ v[13] = blake2b_IV[5] ^ S->t[1];
++ v[14] = blake2b_IV[6] ^ S->f[0];
++ v[15] = blake2b_IV[7] ^ S->f[1];
++
++#define G(r, i, a, b, c, d) \
++ do { \
++ a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \
++ d = rotr64(d ^ a, 32); \
++ c = c + d; \
++ b = rotr64(b ^ c, 24); \
++ a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \
++ d = rotr64(d ^ a, 16); \
++ c = c + d; \
++ b = rotr64(b ^ c, 63); \
++ } while ((void)0, 0)
++
++#define ROUND(r) \
++ do { \
++ G(r, 0, v[0], v[4], v[8], v[12]); \
++ G(r, 1, v[1], v[5], v[9], v[13]); \
++ G(r, 2, v[2], v[6], v[10], v[14]); \
++ G(r, 3, v[3], v[7], v[11], v[15]); \
++ G(r, 4, v[0], v[5], v[10], v[15]); \
++ G(r, 5, v[1], v[6], v[11], v[12]); \
++ G(r, 6, v[2], v[7], v[8], v[13]); \
++ G(r, 7, v[3], v[4], v[9], v[14]); \
++ } while ((void)0, 0)
++
++ for (r = 0; r < 12; ++r) {
++ ROUND(r);
++ }
++
++ for (i = 0; i < 8; ++i) {
++ S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
++ }
++
++#undef G
++#undef ROUND
++}
++
++int blake2b_update(blake2b_state *S, const void *in, grub_size_t inlen) {
++ const grub_uint8_t *pin = (const grub_uint8_t *)in;
++
++ if (inlen == 0) {
++ return 0;
++ }
++
++ /* Sanity check */
++ if (S == NULL || in == NULL) {
++ return -1;
++ }
++
++ /* Is this a reused state? */
++ if (S->f[0] != 0) {
++ return -1;
++ }
++
++ if (S->buflen + inlen > BLAKE2B_BLOCKBYTES) {
++ /* Complete current block */
++ grub_size_t left = S->buflen;
++ grub_size_t fill = BLAKE2B_BLOCKBYTES - left;
++ grub_memcpy(&S->buf[left], pin, fill);
++ blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
++ blake2b_compress(S, S->buf);
++ S->buflen = 0;
++ inlen -= fill;
++ pin += fill;
++ /* Avoid buffer copies when possible */
++ while (inlen > BLAKE2B_BLOCKBYTES) {
++ blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
++ blake2b_compress(S, pin);
++ inlen -= BLAKE2B_BLOCKBYTES;
++ pin += BLAKE2B_BLOCKBYTES;
++ }
++ }
++ grub_memcpy(&S->buf[S->buflen], pin, inlen);
++ S->buflen += (unsigned int)inlen;
++ return 0;
++}
++
++int blake2b_final(blake2b_state *S, void *out, grub_size_t outlen) {
++ grub_uint8_t buffer[BLAKE2B_OUTBYTES] = {0};
++ unsigned int i;
++
++ /* Sanity checks */
++ if (S == NULL || out == NULL || outlen < S->outlen) {
++ return -1;
++ }
++
++ /* Is this a reused state? */
++ if (S->f[0] != 0) {
++ return -1;
++ }
++
++ blake2b_increment_counter(S, S->buflen);
++ blake2b_set_lastblock(S);
++ grub_memset(&S->buf[S->buflen], 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */
++ blake2b_compress(S, S->buf);
++
++ for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */
++ store64(buffer + sizeof(S->h[i]) * i, S->h[i]);
++ }
++
++ grub_memcpy(out, buffer, S->outlen);
++ clear_internal_memory(buffer, sizeof(buffer));
++ clear_internal_memory(S->buf, sizeof(S->buf));
++ clear_internal_memory(S->h, sizeof(S->h));
++ return 0;
++}
++
++int blake2b(void *out, grub_size_t outlen, const void *in, grub_size_t inlen,
++ const void *key, grub_size_t keylen) {
++ blake2b_state S;
++ int ret = -1;
++
++ /* Verify parameters */
++ if (NULL == in && inlen > 0) {
++ goto fail;
++ }
++
++ if (NULL == out || outlen == 0 || outlen > BLAKE2B_OUTBYTES) {
++ goto fail;
++ }
++
++ if ((NULL == key && keylen > 0) || keylen > BLAKE2B_KEYBYTES) {
++ goto fail;
++ }
++
++ if (keylen > 0) {
++ if (blake2b_init_key(&S, outlen, key, keylen) < 0) {
++ goto fail;
++ }
++ } else {
++ if (blake2b_init(&S, outlen) < 0) {
++ goto fail;
++ }
++ }
++
++ if (blake2b_update(&S, in, inlen) < 0) {
++ goto fail;
++ }
++ ret = blake2b_final(&S, out, outlen);
++
++fail:
++ clear_internal_memory(&S, sizeof(S));
++ return ret;
++}
++
++/* Argon2 Team - Begin Code */
++int blake2b_long(void *pout, grub_size_t outlen, const void *in, grub_size_t inlen) {
++ grub_uint8_t *out = (grub_uint8_t *)pout;
++ blake2b_state blake_state;
++ grub_uint8_t outlen_bytes[sizeof(grub_uint32_t)] = {0};
++ int ret = -1;
++
++ if (outlen > GRUB_UINT32_MAX) {
++ goto fail;
++ }
++
++ /* Ensure little-endian byte order! */
++ store32(outlen_bytes, (grub_uint32_t)outlen);
++
++#define TRY(statement) \
++ do { \
++ ret = statement; \
++ if (ret < 0) { \
++ goto fail; \
++ } \
++ } while ((void)0, 0)
++
++ if (outlen <= BLAKE2B_OUTBYTES) {
++ TRY(blake2b_init(&blake_state, outlen));
++ TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));
++ TRY(blake2b_update(&blake_state, in, inlen));
++ TRY(blake2b_final(&blake_state, out, outlen));
++ } else {
++ grub_uint32_t toproduce;
++ grub_uint8_t out_buffer[BLAKE2B_OUTBYTES];
++ grub_uint8_t in_buffer[BLAKE2B_OUTBYTES];
++ TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES));
++ TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));
++ TRY(blake2b_update(&blake_state, in, inlen));
++ TRY(blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES));
++ grub_memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);
++ out += BLAKE2B_OUTBYTES / 2;
++ toproduce = (grub_uint32_t)outlen - BLAKE2B_OUTBYTES / 2;
++
++ while (toproduce > BLAKE2B_OUTBYTES) {
++ grub_memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);
++ TRY(blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer,
++ BLAKE2B_OUTBYTES, NULL, 0));
++ grub_memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);
++ out += BLAKE2B_OUTBYTES / 2;
++ toproduce -= BLAKE2B_OUTBYTES / 2;
++ }
++
++ grub_memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);
++ TRY(blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES, NULL,
++ 0));
++ grub_memcpy(out, out_buffer, toproduce);
++ }
++fail:
++ clear_internal_memory(&blake_state, sizeof(blake_state));
++ return ret;
++#undef TRY
++}
++/* Argon2 Team - End Code */
+diff --git a/grub-core/lib/argon2/blake2/blamka-round-ref.h b/grub-core/lib/argon2/blake2/blamka-round-ref.h
+new file mode 100644
+index 000000000..7f0071ada
+--- /dev/null
++++ b/grub-core/lib/argon2/blake2/blamka-round-ref.h
+@@ -0,0 +1,56 @@
++/*
++ * Argon2 reference source code package - reference C implementations
++ *
++ * Copyright 2015
++ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
++ *
++ * You may use this work under the terms of a Creative Commons CC0 1.0
++ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
++ * these licenses can be found at:
++ *
++ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
++ * - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * You should have received a copy of both of these licenses along with this
++ * software. If not, they may be obtained at the above URLs.
++ */
++
++#ifndef BLAKE_ROUND_MKA_H
++#define BLAKE_ROUND_MKA_H
++
++#include "blake2.h"
++#include "blake2-impl.h"
++
++/* designed by the Lyra PHC team */
++static BLAKE2_INLINE grub_uint64_t fBlaMka(grub_uint64_t x, grub_uint64_t y) {
++ const grub_uint64_t m = GRUB_UINT64_C(0xFFFFFFFF);
++ const grub_uint64_t xy = (x & m) * (y & m);
++ return x + y + 2 * xy;
++}
++
++#define G(a, b, c, d) \
++ do { \
++ a = fBlaMka(a, b); \
++ d = rotr64(d ^ a, 32); \
++ c = fBlaMka(c, d); \
++ b = rotr64(b ^ c, 24); \
++ a = fBlaMka(a, b); \
++ d = rotr64(d ^ a, 16); \
++ c = fBlaMka(c, d); \
++ b = rotr64(b ^ c, 63); \
++ } while ((void)0, 0)
++
++#define BLAKE2_ROUND_NOMSG(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, \
++ v12, v13, v14, v15) \
++ do { \
++ G(v0, v4, v8, v12); \
++ G(v1, v5, v9, v13); \
++ G(v2, v6, v10, v14); \
++ G(v3, v7, v11, v15); \
++ G(v0, v5, v10, v15); \
++ G(v1, v6, v11, v12); \
++ G(v2, v7, v8, v13); \
++ G(v3, v4, v9, v14); \
++ } while ((void)0, 0)
++
++#endif
+diff --git a/grub-core/lib/argon2/core.c b/grub-core/lib/argon2/core.c
+new file mode 100644
+index 000000000..0fe5b74cb
+--- /dev/null
++++ b/grub-core/lib/argon2/core.c
+@@ -0,0 +1,506 @@
++/*
++ * Argon2 reference source code package - reference C implementations
++ *
++ * Copyright 2015
++ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
++ *
++ * You may use this work under the terms of a Creative Commons CC0 1.0
++ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
++ * these licenses can be found at:
++ *
++ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
++ * - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * You should have received a copy of both of these licenses along with this
++ * software. If not, they may be obtained at the above URLs.
++ */
++
++/*For memory wiping*/
++#ifdef _MSC_VER
++#include <windows.h>
++#include <winbase.h> /* For SecureZeroMemory */
++#endif
++#if defined __STDC_LIB_EXT1__
++#define __STDC_WANT_LIB_EXT1__ 1
++#endif
++#define VC_GE_2005(version) (version >= 1400)
++
++#include "core.h"
++#include "blake2/blake2.h"
++#include "blake2/blake2-impl.h"
++
++#ifdef GENKAT
++#include "genkat.h"
++#endif
++
++#if defined(__clang__)
++#if __has_attribute(optnone)
++#define NOT_OPTIMIZED __attribute__((optnone))
++#endif
++#elif defined(__GNUC__)
++#define GCC_VERSION \
++ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
++#if GCC_VERSION >= 40400
++#define NOT_OPTIMIZED __attribute__((optimize("O0")))
++#endif
++#endif
++#ifndef NOT_OPTIMIZED
++#define NOT_OPTIMIZED
++#endif
++
++/***************Instance and Position constructors**********/
++void init_block_value(block *b, grub_uint8_t in) { grub_memset(b->v, in, sizeof(b->v)); }
++
++void copy_block(block *dst, const block *src) {
++ grub_memcpy(dst->v, src->v, sizeof(grub_uint64_t) * ARGON2_QWORDS_IN_BLOCK);
++}
++
++void xor_block(block *dst, const block *src) {
++ int i;
++ for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
++ dst->v[i] ^= src->v[i];
++ }
++}
++
++static void load_block(block *dst, const void *input) {
++ unsigned i;
++ for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
++ dst->v[i] = load64((const grub_uint8_t *)input + i * sizeof(dst->v[i]));
++ }
++}
++
++static void store_block(void *output, const block *src) {
++ unsigned i;
++ for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
++ store64((grub_uint8_t *)output + i * sizeof(src->v[i]), src->v[i]);
++ }
++}
++
++/***************Memory functions*****************/
++
++int allocate_memory(const argon2_context *context, grub_uint8_t **memory,
++ grub_size_t num, grub_size_t size) {
++ grub_size_t memory_size = num*size;
++ if (memory == NULL) {
++ return ARGON2_MEMORY_ALLOCATION_ERROR;
++ }
++
++ /* 1. Check for multiplication overflow */
++ if (size != 0 && memory_size / size != num) {
++ return ARGON2_MEMORY_ALLOCATION_ERROR;
++ }
++
++ /* 2. Try to allocate with appropriate allocator */
++ if (context->allocate_cbk) {
++ (context->allocate_cbk)(memory, memory_size);
++ } else {
++ *memory = grub_malloc(memory_size);
++ }
++
++ if (*memory == NULL) {
++ return ARGON2_MEMORY_ALLOCATION_ERROR;
++ }
++
++ return ARGON2_OK;
++}
++
++void grub_free_memory(const argon2_context *context, grub_uint8_t *memory,
++ grub_size_t num, grub_size_t size) {
++ grub_size_t memory_size = num*size;
++ clear_internal_memory(memory, memory_size);
++ if (context->grub_free_cbk) {
++ (context->grub_free_cbk)(memory, memory_size);
++ } else {
++ grub_free(memory);
++ }
++}
++
++void NOT_OPTIMIZED secure_wipe_memory(void *v, grub_size_t n) {
++ static void *(*const volatile grub_memset_sec)(void *, int, grub_size_t) = &grub_memset;
++ grub_memset_sec(v, 0, n);
++}
++
++/* Memory clear flag defaults to true. */
++int FLAG_clear_internal_memory = 1;
++void clear_internal_memory(void *v, grub_size_t n) {
++ if (FLAG_clear_internal_memory && v) {
++ secure_wipe_memory(v, n);
++ }
++}
++
++void finalize(const argon2_context *context, argon2_instance_t *instance) {
++ if (context != NULL && instance != NULL) {
++ block blockhash;
++ grub_uint32_t l;
++
++ copy_block(&blockhash, instance->memory + instance->lane_length - 1);
++
++ /* XOR the last blocks */
++ for (l = 1; l < instance->lanes; ++l) {
++ grub_uint32_t last_block_in_lane =
++ l * instance->lane_length + (instance->lane_length - 1);
++ xor_block(&blockhash, instance->memory + last_block_in_lane);
++ }
++
++ /* Hash the result */
++ {
++ grub_uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];
++ store_block(blockhash_bytes, &blockhash);
++ blake2b_long(context->out, context->outlen, blockhash_bytes,
++ ARGON2_BLOCK_SIZE);
++ /* clear blockhash and blockhash_bytes */
++ clear_internal_memory(blockhash.v, ARGON2_BLOCK_SIZE);
++ clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE);
++ }
++
++#ifdef GENKAT
++ print_tag(context->out, context->outlen);
++#endif
++
++ grub_free_memory(context, (grub_uint8_t *)instance->memory,
++ instance->memory_blocks, sizeof(block));
++ }
++}
++
++grub_uint32_t index_alpha(const argon2_instance_t *instance,
++ const argon2_position_t *position, grub_uint32_t pseudo_rand,
++ int same_lane) {
++ /*
++ * Pass 0:
++ * This lane : all already finished segments plus already constructed
++ * blocks in this segment
++ * Other lanes : all already finished segments
++ * Pass 1+:
++ * This lane : (SYNC_POINTS - 1) last segments plus already constructed
++ * blocks in this segment
++ * Other lanes : (SYNC_POINTS - 1) last segments
++ */
++ grub_uint32_t reference_area_size;
++ grub_uint64_t relative_position;
++ grub_uint64_t start_position, absolute_position;
++
++ if (0 == position->pass) {
++ /* First pass */
++ if (0 == position->slice) {
++ /* First slice */
++ reference_area_size =
++ position->index - 1; /* all but the previous */
++ } else {
++ if (same_lane) {
++ /* The same lane => add current segment */
++ reference_area_size =
++ position->slice * instance->segment_length +
++ position->index - 1;
++ } else {
++ reference_area_size =
++ position->slice * instance->segment_length +
++ ((position->index == 0) ? (-1) : 0);
++ }
++ }
++ } else {
++ /* Second pass */
++ if (same_lane) {
++ reference_area_size = instance->lane_length -
++ instance->segment_length + position->index -
++ 1;
++ } else {
++ reference_area_size = instance->lane_length -
++ instance->segment_length +
++ ((position->index == 0) ? (-1) : 0);
++ }
++ }
++
++ /* 1.2.4. Mapping pseudo_rand to 0..<reference_area_size-1> and produce
++ * relative position */
++ relative_position = pseudo_rand;
++ relative_position = relative_position * relative_position >> 32;
++ relative_position = reference_area_size - 1 -
++ (reference_area_size * relative_position >> 32);
++
++ /* 1.2.5 Computing starting position */
++ start_position = 0;
++
++ if (0 != position->pass) {
++ start_position = (position->slice == ARGON2_SYNC_POINTS - 1)
++ ? 0
++ : (position->slice + 1) * instance->segment_length;
++ }
++
++ /* 1.2.6. Computing absolute position */
++ grub_divmod64 (start_position + relative_position, instance->lane_length,
++ &absolute_position); /* absolute position */
++ return absolute_position;
++}
++
++/* Single-threaded version for p=1 case */
++static int fill_memory_blocks_st(argon2_instance_t *instance) {
++ grub_uint32_t r, s, l;
++
++ for (r = 0; r < instance->passes; ++r) {
++ for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {
++ for (l = 0; l < instance->lanes; ++l) {
++ argon2_position_t position = {r, l, (grub_uint8_t)s, 0};
++ fill_segment(instance, position);
++ }
++ }
++#ifdef GENKAT
++ internal_kat(instance, r); /* Print all memory blocks */
++#endif
++ }
++ return ARGON2_OK;
++}
++
++int fill_memory_blocks(argon2_instance_t *instance) {
++ if (instance == NULL || instance->lanes == 0) {
++ return ARGON2_INCORRECT_PARAMETER;
++ }
++ return fill_memory_blocks_st(instance);
++}
++
++int validate_inputs(const argon2_context *context) {
++ if (NULL == context) {
++ return ARGON2_INCORRECT_PARAMETER;
++ }
++
++ if (NULL == context->out) {
++ return ARGON2_OUTPUT_PTR_NULL;
++ }
++
++ /* Validate output length */
++ if (ARGON2_MIN_OUTLEN > context->outlen) {
++ return ARGON2_OUTPUT_TOO_SHORT;
++ }
++
++ if (ARGON2_MAX_OUTLEN < context->outlen) {
++ return ARGON2_OUTPUT_TOO_LONG;
++ }
++
++ /* Validate password (required param) */
++ if (NULL == context->pwd) {
++ if (0 != context->pwdlen) {
++ return ARGON2_PWD_PTR_MISMATCH;
++ }
++ }
++
++ if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) {
++ return ARGON2_PWD_TOO_LONG;
++ }
++
++ /* Validate salt (required param) */
++ if (NULL == context->salt) {
++ if (0 != context->saltlen) {
++ return ARGON2_SALT_PTR_MISMATCH;
++ }
++ }
++
++ if (ARGON2_MIN_SALT_LENGTH > context->saltlen) {
++ return ARGON2_SALT_TOO_SHORT;
++ }
++
++ if (ARGON2_MAX_SALT_LENGTH < context->saltlen) {
++ return ARGON2_SALT_TOO_LONG;
++ }
++
++ /* Validate secret (optional param) */
++ if (NULL == context->secret) {
++ if (0 != context->secretlen) {
++ return ARGON2_SECRET_PTR_MISMATCH;
++ }
++ } else {
++ if (ARGON2_MAX_SECRET < context->secretlen) {
++ return ARGON2_SECRET_TOO_LONG;
++ }
++ }
++
++ /* Validate associated data (optional param) */
++ if (NULL == context->ad) {
++ if (0 != context->adlen) {
++ return ARGON2_AD_PTR_MISMATCH;
++ }
++ } else {
++ if (ARGON2_MAX_AD_LENGTH < context->adlen) {
++ return ARGON2_AD_TOO_LONG;
++ }
++ }
++
++ /* Validate memory cost */
++ if (ARGON2_MIN_MEMORY > context->m_cost) {
++ return ARGON2_MEMORY_TOO_LITTLE;
++ }
++
++ if (context->m_cost < 8 * context->lanes) {
++ return ARGON2_MEMORY_TOO_LITTLE;
++ }
++
++ /* Validate time cost */
++ if (ARGON2_MIN_TIME > context->t_cost) {
++ return ARGON2_TIME_TOO_SMALL;
++ }
++
++ if (ARGON2_MAX_TIME < context->t_cost) {
++ return ARGON2_TIME_TOO_LARGE;
++ }
++
++ /* Validate lanes */
++ if (ARGON2_MIN_LANES > context->lanes) {
++ return ARGON2_LANES_TOO_FEW;
++ }
++
++ if (ARGON2_MAX_LANES < context->lanes) {
++ return ARGON2_LANES_TOO_MANY;
++ }
++
++ /* Validate threads */
++ if (ARGON2_MIN_THREADS > context->threads) {
++ return ARGON2_THREADS_TOO_FEW;
++ }
++
++ if (ARGON2_MAX_THREADS < context->threads) {
++ return ARGON2_THREADS_TOO_MANY;
++ }
++
++ if (NULL != context->allocate_cbk && NULL == context->grub_free_cbk) {
++ return ARGON2_FREE_MEMORY_CBK_NULL;
++ }
++
++ if (NULL == context->allocate_cbk && NULL != context->grub_free_cbk) {
++ return ARGON2_ALLOCATE_MEMORY_CBK_NULL;
++ }
++
++ return ARGON2_OK;
++}
++
++void fill_first_blocks(grub_uint8_t *blockhash, const argon2_instance_t *instance) {
++ grub_uint32_t l;
++ /* Make the first and second block in each lane as G(H0||0||i) or
++ G(H0||1||i) */
++ grub_uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];
++ for (l = 0; l < instance->lanes; ++l) {
++
++ store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0);
++ store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l);
++ blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash,
++ ARGON2_PREHASH_SEED_LENGTH);
++ load_block(&instance->memory[l * instance->lane_length + 0],
++ blockhash_bytes);
++
++ store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1);
++ blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash,
++ ARGON2_PREHASH_SEED_LENGTH);
++ load_block(&instance->memory[l * instance->lane_length + 1],
++ blockhash_bytes);
++ }
++ clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE);
++}
++
++void initial_hash(grub_uint8_t *blockhash, argon2_context *context,
++ argon2_type type) {
++ blake2b_state BlakeHash;
++ grub_uint8_t value[sizeof(grub_uint32_t)];
++
++ if (NULL == context || NULL == blockhash) {
++ return;
++ }
++
++ blake2b_init(&BlakeHash, ARGON2_PREHASH_DIGEST_LENGTH);
++
++ store32(&value, context->lanes);
++ blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
++
++ store32(&value, context->outlen);
++ blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
++
++ store32(&value, context->m_cost);
++ blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
++
++ store32(&value, context->t_cost);
++ blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
++
++ store32(&value, context->version);
++ blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
++
++ store32(&value, (grub_uint32_t)type);
++ blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
++
++ store32(&value, context->pwdlen);
++ blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
++
++ if (context->pwd != NULL) {
++ blake2b_update(&BlakeHash, (const grub_uint8_t *)context->pwd,
++ context->pwdlen);
++
++ if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) {
++ secure_wipe_memory(context->pwd, context->pwdlen);
++ context->pwdlen = 0;
++ }
++ }
++
++ store32(&value, context->saltlen);
++ blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
++
++ if (context->salt != NULL) {
++ blake2b_update(&BlakeHash, (const grub_uint8_t *)context->salt,
++ context->saltlen);
++ }
++
++ store32(&value, context->secretlen);
++ blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
++
++ if (context->secret != NULL) {
++ blake2b_update(&BlakeHash, (const grub_uint8_t *)context->secret,
++ context->secretlen);
++
++ if (context->flags & ARGON2_FLAG_CLEAR_SECRET) {
++ secure_wipe_memory(context->secret, context->secretlen);
++ context->secretlen = 0;
++ }
++ }
++
++ store32(&value, context->adlen);
++ blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
++
++ if (context->ad != NULL) {
++ blake2b_update(&BlakeHash, (const grub_uint8_t *)context->ad,
++ context->adlen);
++ }
++
++ blake2b_final(&BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH);
++}
++
++int initialize(argon2_instance_t *instance, argon2_context *context) {
++ grub_uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH];
++ int result = ARGON2_OK;
++
++ if (instance == NULL || context == NULL)
++ return ARGON2_INCORRECT_PARAMETER;
++ instance->context_ptr = context;
++
++ /* 1. Memory allocation */
++ result = allocate_memory(context, (grub_uint8_t **)&(instance->memory),
++ instance->memory_blocks, sizeof(block));
++ if (result != ARGON2_OK) {
++ return result;
++ }
++
++ /* 2. Initial hashing */
++ /* H_0 + 8 extra bytes to produce the first blocks */
++ /* grub_uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */
++ /* Hashing all inputs */
++ initial_hash(blockhash, context, instance->type);
++ /* Zeroing 8 extra bytes */
++ clear_internal_memory(blockhash + ARGON2_PREHASH_DIGEST_LENGTH,
++ ARGON2_PREHASH_SEED_LENGTH -
++ ARGON2_PREHASH_DIGEST_LENGTH);
++
++#ifdef GENKAT
++ initial_kat(blockhash, context, instance->type);
++#endif
++
++ /* 3. Creating first blocks, we always have at least two blocks in a slice
++ */
++ fill_first_blocks(blockhash, instance);
++ /* Clearing the hash */
++ clear_internal_memory(blockhash, ARGON2_PREHASH_SEED_LENGTH);
++
++ return ARGON2_OK;
++}
+diff --git a/grub-core/lib/argon2/core.h b/grub-core/lib/argon2/core.h
+new file mode 100644
+index 000000000..bbcd56998
+--- /dev/null
++++ b/grub-core/lib/argon2/core.h
+@@ -0,0 +1,228 @@
++/*
++ * Argon2 reference source code package - reference C implementations
++ *
++ * Copyright 2015
++ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
++ *
++ * You may use this work under the terms of a Creative Commons CC0 1.0
++ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
++ * these licenses can be found at:
++ *
++ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
++ * - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * You should have received a copy of both of these licenses along with this
++ * software. If not, they may be obtained at the above URLs.
++ */
++
++#ifndef ARGON2_CORE_H
++#define ARGON2_CORE_H
++
++#include "argon2.h"
++
++#define CONST_CAST(x) (x)(grub_addr_t)
++
++/**********************Argon2 internal constants*******************************/
++
++enum argon2_core_constants {
++ /* Memory block size in bytes */
++ ARGON2_BLOCK_SIZE = 1024,
++ ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8,
++ ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16,
++ ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32,
++ ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64,
++
++ /* Number of pseudo-random values generated by one call to Blake in Argon2i
++ to
++ generate reference block positions */
++ ARGON2_ADDRESSES_IN_BLOCK = 128,
++
++ /* Pre-hashing digest length and its extension*/
++ ARGON2_PREHASH_DIGEST_LENGTH = 64,
++ ARGON2_PREHASH_SEED_LENGTH = 72
++};
++
++/*************************Argon2 internal data types***********************/
++
++/*
++ * Structure for the (1KB) memory block implemented as 128 64-bit words.
++ * Memory blocks can be copied, XORed. Internal words can be accessed by [] (no
++ * bounds checking).
++ */
++typedef struct block_ { grub_uint64_t v[ARGON2_QWORDS_IN_BLOCK]; } block;
++
++/*****************Functions that work with the block******************/
++
++/* Initialize each byte of the block with @in */
++void init_block_value(block *b, grub_uint8_t in);
++
++/* Copy block @src to block @dst */
++void copy_block(block *dst, const block *src);
++
++/* XOR @src onto @dst bytewise */
++void xor_block(block *dst, const block *src);
++
++/*
++ * Argon2 instance: memory pointer, number of passes, amount of memory, type,
++ * and derived values.
++ * Used to evaluate the number and location of blocks to construct in each
++ * thread
++ */
++typedef struct Argon2_instance_t {
++ block *memory; /* Memory pointer */
++ grub_uint32_t version;
++ grub_uint32_t passes; /* Number of passes */
++ grub_uint32_t memory_blocks; /* Number of blocks in memory */
++ grub_uint32_t segment_length;
++ grub_uint32_t lane_length;
++ grub_uint32_t lanes;
++ grub_uint32_t threads;
++ argon2_type type;
++ int print_internals; /* whether to print the memory blocks */
++ argon2_context *context_ptr; /* points back to original context */
++} argon2_instance_t;
++
++/*
++ * Argon2 position: where we construct the block right now. Used to distribute
++ * work between threads.
++ */
++typedef struct Argon2_position_t {
++ grub_uint32_t pass;
++ grub_uint32_t lane;
++ grub_uint8_t slice;
++ grub_uint32_t index;
++} argon2_position_t;
++
++/*Struct that holds the inputs for thread handling FillSegment*/
++typedef struct Argon2_thread_data {
++ argon2_instance_t *instance_ptr;
++ argon2_position_t pos;
++} argon2_thread_data;
++
++/*************************Argon2 core functions********************************/
++
++/* Allocates memory to the given pointer, uses the appropriate allocator as
++ * specified in the context. Total allocated memory is num*size.
++ * @param context argon2_context which specifies the allocator
++ * @param memory pointer to the pointer to the memory
++ * @param size the size in bytes for each element to be allocated
++ * @param num the number of elements to be allocated
++ * @return ARGON2_OK if @memory is a valid pointer and memory is allocated
++ */
++int allocate_memory(const argon2_context *context, grub_uint8_t **memory,
++ grub_size_t num, grub_size_t size);
++
++/*
++ * Frees memory at the given pointer, uses the appropriate deallocator as
++ * specified in the context. Also cleans the memory using clear_internal_memory.
++ * @param context argon2_context which specifies the deallocator
++ * @param memory pointer to buffer to be grub_freed
++ * @param size the size in bytes for each element to be deallocated
++ * @param num the number of elements to be deallocated
++ */
++void grub_free_memory(const argon2_context *context, grub_uint8_t *memory,
++ grub_size_t num, grub_size_t size);
++
++/* Function that securely cleans the memory. This ignores any flags set
++ * regarding clearing memory. Usually one just calls clear_internal_memory.
++ * @param mem Pointer to the memory
++ * @param s Memory size in bytes
++ */
++void secure_wipe_memory(void *v, grub_size_t n);
++
++/* Function that securely clears the memory if FLAG_clear_internal_memory is
++ * set. If the flag isn't set, this function does nothing.
++ * @param mem Pointer to the memory
++ * @param s Memory size in bytes
++ */
++void clear_internal_memory(void *v, grub_size_t n);
++
++/*
++ * Computes absolute position of reference block in the lane following a skewed
++ * distribution and using a pseudo-random value as input
++ * @param instance Pointer to the current instance
++ * @param position Pointer to the current position
++ * @param pseudo_rand 32-bit pseudo-random value used to determine the position
++ * @param same_lane Indicates if the block will be taken from the current lane.
++ * If so we can reference the current segment
++ * @pre All pointers must be valid
++ */
++grub_uint32_t index_alpha(const argon2_instance_t *instance,
++ const argon2_position_t *position, grub_uint32_t pseudo_rand,
++ int same_lane);
++
++/*
++ * Function that validates all inputs against predefined restrictions and return
++ * an error code
++ * @param context Pointer to current Argon2 context
++ * @return ARGON2_OK if everything is all right, otherwise one of error codes
++ * (all defined in <argon2.h>
++ */
++int validate_inputs(const argon2_context *context);
++
++/*
++ * Hashes all the inputs into @a blockhash[PREHASH_DIGEST_LENGTH], clears
++ * password and secret if needed
++ * @param context Pointer to the Argon2 internal structure containing memory
++ * pointer, and parameters for time and space requirements.
++ * @param blockhash Buffer for pre-hashing digest
++ * @param type Argon2 type
++ * @pre @a blockhash must have at least @a PREHASH_DIGEST_LENGTH bytes
++ * allocated
++ */
++void initial_hash(grub_uint8_t *blockhash, argon2_context *context,
++ argon2_type type);
++
++/*
++ * Function creates first 2 blocks per lane
++ * @param instance Pointer to the current instance
++ * @param blockhash Pointer to the pre-hashing digest
++ * @pre blockhash must point to @a PREHASH_SEED_LENGTH allocated values
++ */
++void fill_first_blocks(grub_uint8_t *blockhash, const argon2_instance_t *instance);
++
++/*
++ * Function allocates memory, hashes the inputs with Blake, and creates first
++ * two blocks. Returns the pointer to the main memory with 2 blocks per lane
++ * initialized
++ * @param context Pointer to the Argon2 internal structure containing memory
++ * pointer, and parameters for time and space requirements.
++ * @param instance Current Argon2 instance
++ * @return Zero if successful, -1 if memory failed to allocate. @context->state
++ * will be modified if successful.
++ */
++int initialize(argon2_instance_t *instance, argon2_context *context);
++
++/*
++ * XORing the last block of each lane, hashing it, making the tag. Deallocates
++ * the memory.
++ * @param context Pointer to current Argon2 context (use only the out parameters
++ * from it)
++ * @param instance Pointer to current instance of Argon2
++ * @pre instance->state must point to necessary amount of memory
++ * @pre context->out must point to outlen bytes of memory
++ * @pre if context->grub_free_cbk is not NULL, it should point to a function that
++ * deallocates memory
++ */
++void finalize(const argon2_context *context, argon2_instance_t *instance);
++
++/*
++ * Function that fills the segment using previous segments also from other
++ * threads
++ * @param context current context
++ * @param instance Pointer to the current instance
++ * @param position Current position
++ * @pre all block pointers must be valid
++ */
++void fill_segment(const argon2_instance_t *instance,
++ argon2_position_t position);
++
++/*
++ * Function that fills the entire memory t_cost times based on the first two
++ * blocks in each lane
++ * @param instance Pointer to the current instance
++ * @return ARGON2_OK if successful, @context->state
++ */
++int fill_memory_blocks(argon2_instance_t *instance);
++
++#endif
+diff --git a/grub-core/lib/argon2/ref.c b/grub-core/lib/argon2/ref.c
+new file mode 100644
+index 000000000..c933df80d
+--- /dev/null
++++ b/grub-core/lib/argon2/ref.c
+@@ -0,0 +1,190 @@
++/*
++ * Argon2 reference source code package - reference C implementations
++ *
++ * Copyright 2015
++ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
++ *
++ * You may use this work under the terms of a Creative Commons CC0 1.0
++ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
++ * these licenses can be found at:
++ *
++ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
++ * - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * You should have received a copy of both of these licenses along with this
++ * software. If not, they may be obtained at the above URLs.
++ */
++
++#include "argon2.h"
++#include "core.h"
++
++#include "blake2/blamka-round-ref.h"
++#include "blake2/blake2-impl.h"
++#include "blake2/blake2.h"
++
++
++/*
++ * Function fills a new memory block and optionally XORs the old block over the new one.
++ * @next_block must be initialized.
++ * @param prev_block Pointer to the previous block
++ * @param ref_block Pointer to the reference block
++ * @param next_block Pointer to the block to be constructed
++ * @param with_xor Whether to XOR into the new block (1) or just overwrite (0)
++ * @pre all block pointers must be valid
++ */
++static void fill_block(const block *prev_block, const block *ref_block,
++ block *next_block, int with_xor) {
++ block blockR, block_tmp;
++ unsigned i;
++
++ copy_block(&blockR, ref_block);
++ xor_block(&blockR, prev_block);
++ copy_block(&block_tmp, &blockR);
++ /* Now blockR = ref_block + prev_block and block_tmp = ref_block + prev_block */
++ if (with_xor) {
++ /* Saving the next block contents for XOR over: */
++ xor_block(&block_tmp, next_block);
++ /* Now blockR = ref_block + prev_block and
++ block_tmp = ref_block + prev_block + next_block */
++ }
++
++ /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then
++ (16,17,..31)... finally (112,113,...127) */
++ for (i = 0; i < 8; ++i) {
++ BLAKE2_ROUND_NOMSG(
++ blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2],
++ blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5],
++ blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8],
++ blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11],
++ blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14],
++ blockR.v[16 * i + 15]);
++ }
++
++ /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then
++ (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */
++ for (i = 0; i < 8; i++) {
++ BLAKE2_ROUND_NOMSG(
++ blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16],
++ blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33],
++ blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64],
++ blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81],
++ blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112],
++ blockR.v[2 * i + 113]);
++ }
++
++ copy_block(next_block, &block_tmp);
++ xor_block(next_block, &blockR);
++}
++
++static void next_addresses(block *address_block, block *input_block,
++ const block *zero_block) {
++ input_block->v[6]++;
++ fill_block(zero_block, input_block, address_block, 0);
++ fill_block(zero_block, address_block, address_block, 0);
++}
++
++void fill_segment(const argon2_instance_t *instance,
++ argon2_position_t position) {
++ block *ref_block = NULL, *curr_block = NULL;
++ block address_block, input_block, zero_block;
++ grub_uint64_t pseudo_rand, ref_index, ref_lane;
++ grub_uint32_t prev_offset, curr_offset;
++ grub_uint32_t starting_index;
++ grub_uint32_t i;
++ int data_independent_addressing;
++
++ if (instance == NULL) {
++ return;
++ }
++
++ data_independent_addressing =
++ (instance->type == Argon2_i) ||
++ (instance->type == Argon2_id && (position.pass == 0) &&
++ (position.slice < ARGON2_SYNC_POINTS / 2));
++
++ if (data_independent_addressing) {
++ init_block_value(&zero_block, 0);
++ init_block_value(&input_block, 0);
++
++ input_block.v[0] = position.pass;
++ input_block.v[1] = position.lane;
++ input_block.v[2] = position.slice;
++ input_block.v[3] = instance->memory_blocks;
++ input_block.v[4] = instance->passes;
++ input_block.v[5] = instance->type;
++ }
++
++ starting_index = 0;
++
++ if ((0 == position.pass) && (0 == position.slice)) {
++ starting_index = 2; /* we have already generated the first two blocks */
++
++ /* Don't forget to generate the first block of addresses: */
++ if (data_independent_addressing) {
++ next_addresses(&address_block, &input_block, &zero_block);
++ }
++ }
++
++ /* Offset of the current block */
++ curr_offset = position.lane * instance->lane_length +
++ position.slice * instance->segment_length + starting_index;
++
++ if (0 == curr_offset % instance->lane_length) {
++ /* Last block in this lane */
++ prev_offset = curr_offset + instance->lane_length - 1;
++ } else {
++ /* Previous block */
++ prev_offset = curr_offset - 1;
++ }
++
++ for (i = starting_index; i < instance->segment_length;
++ ++i, ++curr_offset, ++prev_offset) {
++ /*1.1 Rotating prev_offset if needed */
++ if (curr_offset % instance->lane_length == 1) {
++ prev_offset = curr_offset - 1;
++ }
++
++ /* 1.2 Computing the index of the reference block */
++ /* 1.2.1 Taking pseudo-random value from the previous block */
++ if (data_independent_addressing) {
++ if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
++ next_addresses(&address_block, &input_block, &zero_block);
++ }
++ pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];
++ } else {
++ pseudo_rand = instance->memory[prev_offset].v[0];
++ }
++
++ /* 1.2.2 Computing the lane of the reference block */
++ grub_divmod64 (pseudo_rand >> 32, instance->lanes, &ref_lane);
++
++ if ((position.pass == 0) && (position.slice == 0)) {
++ /* Can not reference other lanes yet */
++ ref_lane = position.lane;
++ }
++
++ /* 1.2.3 Computing the number of possible reference block within the
++ * lane.
++ */
++ position.index = i;
++ ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF,
++ ref_lane == position.lane);
++
++ /* 2 Creating a new block */
++ ref_block =
++ instance->memory + instance->lane_length * ref_lane + ref_index;
++ curr_block = instance->memory + curr_offset;
++ if (ARGON2_VERSION_10 == instance->version) {
++ /* version 1.2.1 and earlier: overwrite, not XOR */
++ fill_block(instance->memory + prev_offset, ref_block, curr_block, 0);
++ } else {
++ if(0 == position.pass) {
++ fill_block(instance->memory + prev_offset, ref_block,
++ curr_block, 0);
++ } else {
++ fill_block(instance->memory + prev_offset, ref_block,
++ curr_block, 1);
++ }
++ }
++ }
++}
+--
+2.32.0
+
+
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEEF9hrgiFbCdvenl/rVbJhu7ckPpQFAmEP4xsACgkQVbJhu7ck
+PpRmAA/8C5AlxA0SBA3Avgcm0QDyb1ifNtc8mNCiaVsDV0xfBafVK2IX/dm+q0H7
+fB5Qazpqb+502nZCzyeuyx4PFJj2EPxbw5SSfZKQw97cqO2DArIMduKselHSuopL
+N9myVreoX7bumzeOt4TNFVRKvxqZ1cYCBoLz6AOm9sPhmjf8dzLi0sZ3ZAF7YLza
+bi/lts1TahIOBPk7cpJBOWYK5N/EiLiLmsfSwsZyhrPbzo2f+LVSkf+Ev7/MZfJN
+zhY4OdGb6MCq5JJ6fcAFrqKNfinGbHwfz5S/WyClhfzbbtgGX8NofYx0JNHdVVRw
+pT6/Na/L1gIkVTMfgQn8w0VGcKKXMbqE+pas42W0ZH8pgThh87utZZtlbYQG3kRL
+7oviRYqS1fVKLiDTi1dYE2CKnk2lyy6J8T+Ia2/PR/UGsWbxR5pwFlEWJyqnOIDg
+vq46AQBndRYf8RuJAJr2uPZkl9ZniSL/7IS96yJFzRTAgbYNwgoT8EEI4NJiUmA3
+ySqbEzAx/p7F1E8FFBUtY2onpaiIJAcl39RDK+hd6juHplUfAboUYlznu03YnX7o
+GAWSpA90LuZZ8hTwkBOwOK8SExmOOFh4FvqfJPwSPgHIdM71nsZN2ktHWTymapAg
+ds11gWlKJ50mz4K9KpmA+EdHENmtPhsRb6OcWycYq9X5+o/1TCk=
+=05dK
+-----END PGP SIGNATURE-----
+
+
diff --git a/argon_4.patch b/argon_4.patch
new file mode 100644
index 000000000000..051cf7bd477b
--- /dev/null
+++ b/argon_4.patch
@@ -0,0 +1,71 @@
+---
+ grub-core/disk/luks2.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
+index 371a53b83..02822c777 100644
+--- a/grub-core/disk/luks2.c
++++ b/grub-core/disk/luks2.c
+@@ -40,6 +40,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ enum grub_luks2_kdf_type
+ {
+ LUKS2_KDF_TYPE_ARGON2I,
++ LUKS2_KDF_TYPE_ARGON2ID,
+ LUKS2_KDF_TYPE_PBKDF2
+ };
+ typedef enum grub_luks2_kdf_type grub_luks2_kdf_type_t;
+@@ -92,7 +93,7 @@ struct grub_luks2_keyslot
+ grub_int64_t time;
+ grub_int64_t memory;
+ grub_int64_t cpus;
+- } argon2i;
++ } argon2;
+ struct
+ {
+ const char *hash;
+@@ -162,10 +163,11 @@ luks2_parse_keyslot (grub_luks2_keyslot_t *out, const grub_json_t *keyslot)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Missing or invalid KDF");
+ else if (!grub_strcmp (type, "argon2i") || !grub_strcmp (type, "argon2id"))
+ {
+- out->kdf.type = LUKS2_KDF_TYPE_ARGON2I;
+- if (grub_json_getint64 (&out->kdf.u.argon2i.time, &kdf, "time") ||
+- grub_json_getint64 (&out->kdf.u.argon2i.memory, &kdf, "memory") ||
+- grub_json_getint64 (&out->kdf.u.argon2i.cpus, &kdf, "cpus"))
++ out->kdf.type = !grub_strcmp (type, "argon2i")
++ ? LUKS2_KDF_TYPE_ARGON2I : LUKS2_KDF_TYPE_ARGON2ID;
++ if (grub_json_getint64 (&out->kdf.u.argon2.time, &kdf, "time") ||
++ grub_json_getint64 (&out->kdf.u.argon2.memory, &kdf, "memory") ||
++ grub_json_getint64 (&out->kdf.u.argon2.cpus, &kdf, "cpus"))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Missing Argon2i parameters");
+ }
+ else if (!grub_strcmp (type, "pbkdf2"))
+@@ -445,6 +447,7 @@ luks2_decrypt_key (grub_uint8_t *out_key,
+ switch (k->kdf.type)
+ {
+ case LUKS2_KDF_TYPE_ARGON2I:
++ case LUKS2_KDF_TYPE_ARGON2ID:
+ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Argon2 not supported");
+ goto err;
+ case LUKS2_KDF_TYPE_PBKDF2:
+--
+2.32.0
+
+
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEEF9hrgiFbCdvenl/rVbJhu7ckPpQFAmEP4x8ACgkQVbJhu7ck
+PpQ/1g/9EM6PVsjbyTdgy3rNWWEuk2VJrjagm4+qwr2Nt1d69NvsyQIzGw4wTnI3
+ZgDQW3ddn4KhWioBusD8XOgZEySc3Q0wOh2tbjGVV235bmxUTu22Z6vhnj34BN/2
+0sOFjSjRtRNh5LmfR+7HP39id2ZppljDaDNzDeRZzCEXUymt3xKtGNlASAe1IW6G
+PKIYkols3GsYp406P/Fjqvu8YRJuAGv6VyrS4QineAR1Iv70pBWkQTtE7JgWBmv4
++cCs+MD88kSwxf40DEo5o0AVjrsAv6VqMp89yi3z8TRbDTtMERPr0zP5hWCkkuXd
+st8FqPCunHv+afEk3q8Xn9LlJ65wXJ7XflIwbBEsdSf4cL03rx3WgPGu1sK+s8o+
+JxjkYKH+GJUbDZ+uw7ngcNKUnsWNxe0Lpu+zEakkJmoWQ/GIhFf93G2yJag7mKMP
+q0A/oh6+z6L2+pg91jPwAatisICYks1S5MpWKiNP+EnEGHrr2dnjfOEWq9W0Qghx
+ixJtltwfVh3EIcLwitGrRhQykL1E1DG8yJyjWzsaf+6moF9uvZSHN/7JxEw3oOtB
+9NQi7m4okMe3ACqLAp2z2VcvVZ1hVCp7HlTp5tK6j2FCQJYsku8tuaxuYrJ/qThz
+iOraDrwHv/wo84K5J20na/xEroQYZvVudRJZj/cjBdgzjzqFAUA=
+=wl50
+-----END PGP SIGNATURE-----
+
+
diff --git a/argon_5.patch b/argon_5.patch
new file mode 100644
index 000000000000..bca5449f1455
--- /dev/null
+++ b/argon_5.patch
@@ -0,0 +1,96 @@
+---
+ Makefile.util.def | 6 +++++-
+ grub-core/Makefile.core.def | 2 +-
+ grub-core/disk/luks2.c | 13 +++++++++++--
+ 3 files changed, 17 insertions(+), 4 deletions(-)
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index f8b356cc1..39fe9cb7c 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -3,7 +3,7 @@ AutoGen definitions Makefile.tpl;
+ library = {
+ name = libgrubkern.a;
+ cflags = '$(CFLAGS_GNULIB)';
+- cppflags = '$(CPPFLAGS_GNULIB) -I$(srcdir)/grub-core/lib/json';
++ cppflags = '$(CPPFLAGS_GNULIB) -I$(srcdir)/grub-core/lib/json -I$(srcdir)/grub-core/lib/argon2';
+
+ common = util/misc.c;
+ common = grub-core/kern/command.c;
+@@ -36,6 +36,10 @@ library = {
+ common = grub-core/kern/misc.c;
+ common = grub-core/kern/partition.c;
+ common = grub-core/lib/crypto.c;
++ common = grub-core/lib/argon2/argon2.c;
++ common = grub-core/lib/argon2/core.c;
++ common = grub-core/lib/argon2/ref.c;
++ common = grub-core/lib/argon2/blake2/blake2b.c;
+ common = grub-core/lib/json/json.c;
+ common = grub-core/disk/luks.c;
+ common = grub-core/disk/luks2.c;
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 3a004e88c..e5e5b216b 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -1197,7 +1197,7 @@ module = {
+ common = disk/luks2.c;
+ common = lib/gnulib/base64.c;
+ cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
+- cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/json';
++ cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/json -I$(srcdir)/lib/argon2';
+ };
+
+ module = {
+diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
+index 02822c777..2ec0d4116 100644
+--- a/grub-core/disk/luks2.c
++++ b/grub-core/disk/luks2.c
+@@ -27,6 +27,7 @@
+ #include <grub/partition.h>
+ #include <grub/i18n.h>
+
++#include <argon2.h>
+ #include <base64.h>
+ #include <json.h>
+
+@@ -448,8 +449,16 @@ luks2_decrypt_key (grub_uint8_t *out_key,
+ {
+ case LUKS2_KDF_TYPE_ARGON2I:
+ case LUKS2_KDF_TYPE_ARGON2ID:
+- ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Argon2 not supported");
+- goto err;
++ ret = argon2_hash (k->kdf.u.argon2.time, k->kdf.u.argon2.memory, k->kdf.u.argon2.cpus,
++ passphrase, passphraselen, salt, saltlen, area_key, k->area.key_size,
++ k->kdf.type == LUKS2_KDF_TYPE_ARGON2I ? Argon2_i : Argon2_id,
++ ARGON2_VERSION_NUMBER);
++ if (ret)
++ {
++ grub_dprintf ("luks2", "Argon2 failed: %s\n", argon2_error_message (ret));
++ goto err;
++ }
++ break;
+ case LUKS2_KDF_TYPE_PBKDF2:
+ hash = grub_crypto_lookup_md_by_name (k->kdf.u.pbkdf2.hash);
+ if (!hash)
+--
+2.32.0
+
+
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEEF9hrgiFbCdvenl/rVbJhu7ckPpQFAmEP4yQACgkQVbJhu7ck
+PpSm3g//WJHea428olgraKZcMWFBq4CpJJUYtaDq/Sxdy/VubY42Or3s90mKTFPw
+xiu3/r/WQXnzR5QnwhsVsk7eQNz2oxR5Bpw8XvNBFhMvMrCc8T+RhUeytsCFSjCg
+koW7Bub3TLhUnzPH/qHaXtK8inKk3G49fUi+iUFhj6YcMZFIKbiKX5B/SseswUwm
+9hJeA2aqgflOQT2ucEKxNJ7VQoqdn7QE0dxWd/7wUPoirBvePa3NcYcp/+QJ+gfr
+77N8Sb4hPhU63apnTbzkq72jLyng4h1LTnQMFvcfs1ktUPHWOKHnDxYgLAVEAMKR
+nKpfDyEGaAXtO1s2outPHykBnNzQYFiz06vFMoLfXr986m2/5I6XSBIKhEC3XUbO
+ZO2Kbys5u/T+O5j9KNlTKX2/9+XhCQwGZP+UXtz2KxTUQm1ZKKjJvNa7LLe6qm0c
+ps3YV20jXp5bI7Nsw0MN6+Vu67UXHcr0reCwhI4A/oUrNAVG3DYqaxQAbpKDcIlk
+FtVrmwAC3gOw2vjT6Z5T5CGD3jwLX1zN50G8GiSIMzYN7o0S8fU1AEdNpkfZAG8h
++CgCuSBwBY0wfDX1SKWczhVcodJ+E6hoPaXNhk4f31cvNFYuq0IUPKJ4WxNU3NJI
+56TdrKzrS322Pb16CC3GX7MgSlTvv3LcbX3Akv2SOpeOxsyc3OI=
+=Vrqy
+-----END PGP SIGNATURE-----
+
+
diff --git a/detect-archlinux-initramfs.patch b/detect-archlinux-initramfs.patch
new file mode 100644
index 000000000000..0f5568bf219e
--- /dev/null
+++ b/detect-archlinux-initramfs.patch
@@ -0,0 +1,49 @@
+From 058d08a025f9a6ec77d5ddd1fc62c7bd6abe1a52 Mon Sep 17 00:00:00 2001
+From: Christian Hesse <mail@eworm.de>
+Date: Wed, 10 Mar 2021 18:40:00 +0100
+Subject: [PATCH] 10_linux: detect archlinux initramfs
+---
+ util/grub.d/10_linux.in | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index e8b01c0d0..e703dcdb0 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -93,6 +93,8 @@ linux_entry ()
+ case $type in
+ recovery)
+ title="$(gettext_printf "%s, with Linux %s (recovery mode)" "${os}" "${version}")" ;;
++ fallback)
++ title="$(gettext_printf "%s, with Linux %s (fallback initramfs)" "${os}" "${version}")" ;;
+ *)
+ title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;;
+ esac
+@@ -198,7 +200,7 @@ while [ "x$list" != "x" ] ; do
+ basename=`basename $linux`
+ dirname=`dirname $linux`
+ rel_dirname=`make_system_path_relative_to_its_root $dirname`
+- version=`echo $basename | sed -e "s,^[^0-9]*-,,g"`
++ version=`echo $basename | sed -e "s,vmlinuz-,,g"`
+ alt_version=`echo $version | sed -e "s,\.old$,,g"`
+ linux_root_device_thisversion="${LINUX_ROOT_DEVICE}"
+
+@@ -285,6 +287,18 @@ while [ "x$list" != "x" ] ; do
+
+ linux_entry "${OS}" "${version}" advanced \
+ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
++
++ if test -e "${dirname}/initramfs-${version}-fallback.img" ; then
++ initrd="initramfs-${version}-fallback.img"
++
++ if test -n "${initrd}" ; then
++ gettext_printf "Found fallback initrd image(s) in %s:%s\n" "${dirname}" "${initrd_extra} ${initrd}" >&2
++ fi
++
++ linux_entry "${OS}" "${version}" fallback \
++ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
++ fi
++
+ if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
+ linux_entry "${OS}" "${version}" recovery \
+ "single ${GRUB_CMDLINE_LINUX}"
diff --git a/grub-improved-luks2-git.install b/grub-improved-luks2-git.install
new file mode 100644
index 000000000000..c13ef99c77c5
--- /dev/null
+++ b/grub-improved-luks2-git.install
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+post_upgrade() {
+ # We used to package /boot/grub/grub.cfg, but there is no reason to.
+ # Remove the file from package, but move real file back in place.
+ if [ ! -f /boot/grub/grub.cfg -a -f /boot/grub/grub.cfg.pacsave ]; then
+ mv /boot/grub/grub.cfg.pacsave /boot/grub/grub.cfg
+ fi
+}
+
+post_install() {
+ cat << 'EOM'
+Generate your bootloader configuration with:
+ grub-mkconfig -o /boot/grub/grub.cfg
+EOM
+}
+
diff --git a/grub-install_luks2.patch b/grub-install_luks2.patch
new file mode 100644
index 000000000000..3748d4b399eb
--- /dev/null
+++ b/grub-install_luks2.patch
@@ -0,0 +1,263 @@
+diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
+index ccfacb63a..1aaac1da6 100644
+--- a/grub-core/disk/luks2.c
++++ b/grub-core/disk/luks2.c
+@@ -350,8 +350,15 @@ luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs)
+ {
+ grub_cryptodisk_t cryptodisk;
+ grub_luks2_header_t header;
++ grub_luks2_keyslot_t keyslot;
++ grub_luks2_digest_t digest;
++ grub_luks2_segment_t segment;
++ char *json_header = NULL, *ptr;
++ grub_size_t candidate_key_len = 0, json_idx, size;
+ char uuid[sizeof (header.uuid) + 1];
+ grub_size_t i, j;
++ grub_err_t ret;
++ grub_json_t *json = NULL, keyslots;
+
+ if (cargs->check_boot)
+ return NULL;
+@@ -361,6 +368,157 @@ luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs)
+ grub_errno = GRUB_ERR_NONE;
+ return NULL;
+ }
++ json_header = grub_zalloc (grub_be_to_cpu64 (header.hdr_size) - sizeof (header));
++ if (!json_header)
++ return GRUB_ERR_OUT_OF_MEMORY;
++
++ /* Read the JSON area. */
++ ret = grub_disk_read (disk, 0, grub_be_to_cpu64 (header.hdr_offset) + sizeof (header),
++ grub_be_to_cpu64 (header.hdr_size) - sizeof (header), json_header);
++ if (ret)
++ goto err;
++
++ ptr = grub_memchr (json_header, 0, grub_be_to_cpu64 (header.hdr_size) - sizeof (header));
++ if (!ptr)
++ goto err;
++
++ ret = grub_json_parse (&json, json_header, grub_be_to_cpu64 (header.hdr_size));
++ if (ret)
++ {
++ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid LUKS2 JSON header");
++ goto err;
++ }
++
++ if (grub_json_getvalue (&keyslots, json, "keyslots") ||
++ grub_json_getsize (&size, &keyslots))
++ {
++ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Could not get keyslots");
++ goto err;
++ }
++
++ if (grub_disk_native_sectors (disk) == GRUB_DISK_SIZE_UNKNOWN)
++ {
++ /* FIXME: Allow use of source disk, and maybe cause errors in read. */
++ grub_dprintf ("luks2", "Source disk %s has an unknown size, "
++ "conservatively returning error\n", disk->name);
++ ret = grub_error (GRUB_ERR_BUG, "Unknown size of luks2 source device");
++ goto err;
++ }
++
++ cryptodisk = grub_zalloc (sizeof (*cryptodisk));
++ if (!cryptodisk)
++ return NULL;
++
++
++ /* Try all keyslot */
++ for (json_idx = 0; json_idx < size; json_idx++)
++ {
++ char indexstr[21]; /* log10(2^64) ~ 20, plus NUL character. */
++ typeof (disk->total_sectors) max_crypt_sectors = 0;
++
++ grub_errno = GRUB_ERR_NONE;
++ ret = luks2_get_keyslot (&keyslot, &digest, &segment, json, json_idx);
++ if (ret)
++ goto err;
++ if (grub_errno != GRUB_ERR_NONE)
++ grub_dprintf ("luks2", "Ignoring unhandled error %d from luks2_get_keyslot\n", grub_errno);
++
++ if (keyslot.priority == 0)
++ {
++ grub_dprintf ("luks2", "Ignoring keyslot \"%" PRIuGRUB_UINT64_T "\" due to priority\n", keyslot.idx);
++ continue;
++ }
++
++ grub_dprintf ("luks2", "Trying keyslot \"%" PRIuGRUB_UINT64_T "\"\n", keyslot.idx);
++
++ /* Sector size should be one of 512, 1024, 2048, or 4096. */
++ if (!(segment.sector_size == 512 || segment.sector_size == 1024 ||
++ segment.sector_size == 2048 || segment.sector_size == 4096))
++ {
++ grub_dprintf ("luks2", "Segment \"%" PRIuGRUB_UINT64_T "\" sector"
++ " size %" PRIuGRUB_UINT64_T " is not one of"
++ " 512, 1024, 2048, or 4096\n",
++ segment.idx, segment.sector_size);
++ continue;
++ }
++
++ /* Set up disk according to keyslot's segment. */
++ cryptodisk->offset_sectors = grub_divmod64 (segment.offset, segment.sector_size, NULL);
++ cryptodisk->log_sector_size = grub_log2ull (segment.sector_size);
++ /* Set to the source disk/partition size, which is the maximum we allow. */
++ max_crypt_sectors = grub_disk_native_sectors (disk);
++ max_crypt_sectors = grub_convert_sector (max_crypt_sectors, GRUB_DISK_SECTOR_BITS,
++ cryptodisk->log_sector_size);
++
++ if (max_crypt_sectors < cryptodisk->offset_sectors)
++ {
++ grub_dprintf ("luks2", "Segment \"%" PRIuGRUB_UINT64_T "\" has offset"
++ " %" PRIuGRUB_UINT64_T " which is greater than"
++ " source disk size %" PRIuGRUB_UINT64_T ","
++ " skipping\n", segment.idx, cryptodisk->offset_sectors,
++ max_crypt_sectors);
++ continue;
++ }
++
++ if (grub_strcmp (segment.size, "dynamic") == 0)
++ cryptodisk->total_sectors = max_crypt_sectors - cryptodisk->offset_sectors;
++ else
++ {
++ grub_errno = GRUB_ERR_NONE;
++
++ /* Convert segment.size to sectors, rounding up to nearest sector */
++ cryptodisk->total_sectors = grub_strtoull (segment.size, NULL, 10);
++
++ if (grub_errno == GRUB_ERR_NONE)
++ {
++ cryptodisk->total_sectors = ALIGN_UP (cryptodisk->total_sectors,
++ 1 << cryptodisk->log_sector_size);
++ cryptodisk->total_sectors >>= cryptodisk->log_sector_size;
++ }
++ else if (grub_errno == GRUB_ERR_BAD_NUMBER)
++ {
++ grub_dprintf ("luks2", "Segment \"%" PRIuGRUB_UINT64_T "\" size"
++ " \"%s\" is not a parsable number,"
++ " skipping keyslot\n",
++ segment.idx, segment.size);
++ continue;
++ }
++ else if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
++ {
++ /*
++ * There was an overflow in parsing segment.size, so disk must
++ * be very large or the string is incorrect.
++ *
++ * TODO: Allow reading of at least up max_crypt_sectors. Really,
++ * its very unlikely one would be booting from such a large drive
++ * anyway. Use another smaller LUKS2 boot device.
++ */
++ grub_dprintf ("luks2", "Segment \"%" PRIuGRUB_UINT64_T "\" size"
++ " %s overflowed 64-bit unsigned integer,"
++ " skipping keyslot\n", segment.idx, segment.size);
++ continue;
++ }
++ }
++
++ if (cryptodisk->total_sectors == 0)
++ {
++ grub_dprintf ("luks2", "Segment \"%" PRIuGRUB_UINT64_T "\" has zero"
++ " sectors, skipping\n", segment.idx);
++ continue;
++ }
++ else if (max_crypt_sectors < (cryptodisk->offset_sectors + cryptodisk->total_sectors))
++ {
++ grub_dprintf ("luks2", "Segment \"%" PRIuGRUB_UINT64_T "\" has last"
++ " data position greater than source disk size,"
++ " the end of the crypto device will be"
++ " inaccessible\n", segment.idx);
++
++ /* Allow decryption up to the end of the source disk. */
++ cryptodisk->total_sectors = max_crypt_sectors - cryptodisk->offset_sectors;
++ }
++
++ break;
++ }
+
+ for (i = 0, j = 0; i < sizeof (header.uuid); i++)
+ if (header.uuid[i] != '-')
+@@ -373,15 +531,16 @@ luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs)
+ return NULL;
+ }
+
+- cryptodisk = grub_zalloc (sizeof (*cryptodisk));
+- if (!cryptodisk)
+- return NULL;
+-
+ COMPILE_TIME_ASSERT (sizeof (cryptodisk->uuid) >= sizeof (uuid));
+ grub_memcpy (cryptodisk->uuid, uuid, sizeof (uuid));
+
+ cryptodisk->modname = "luks2";
+ return cryptodisk;
++err:
++ grub_free (json_header);
++ grub_json_free (json);
++ grub_errno = ret;
++ return NULL;
+ }
+
+ static grub_err_t
+diff --git a/grub-core/osdep/devmapper/getroot.c b/grub-core/osdep/devmapper/getroot.c
+index 9ba5c9865..9ae1780c9 100644
+--- a/grub-core/osdep/devmapper/getroot.c
++++ b/grub-core/osdep/devmapper/getroot.c
+@@ -141,7 +141,12 @@ grub_util_get_dm_abstraction (const char *os_dev)
+ if (strncmp (uuid, "CRYPT-LUKS1-", 12) == 0)
+ {
+ grub_free (uuid);
+- return GRUB_DEV_ABSTRACTION_LUKS;
++ return GRUB_DEV_ABSTRACTION_LUKS1;
++ }
++ if (strncmp (uuid, "CRYPT-LUKS2-", 12) == 0)
++ {
++ grub_free (uuid);
++ return GRUB_DEV_ABSTRACTION_LUKS2;
+ }
+
+ grub_free (uuid);
+@@ -179,7 +184,7 @@ grub_util_pull_devmapper (const char *os_dev)
+ grub_util_pull_device (subdev);
+ }
+ }
+- if (uuid && strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0
++ if (uuid && (strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0 || strncmp (uuid, "CRYPT-LUKS2-", sizeof ("CRYPT-LUKS2-") - 1) == 0)
+ && lastsubdev)
+ {
+ char *grdev = grub_util_get_grub_dev (lastsubdev);
+@@ -249,7 +254,8 @@ grub_util_get_devmapper_grub_dev (const char *os_dev)
+ return grub_dev;
+ }
+
+- case GRUB_DEV_ABSTRACTION_LUKS:
++ case GRUB_DEV_ABSTRACTION_LUKS1:
++ case GRUB_DEV_ABSTRACTION_LUKS2:
+ {
+ char *dash;
+
+diff --git a/include/grub/emu/getroot.h b/include/grub/emu/getroot.h
+index 73fa2d34a..1a27faf28 100644
+--- a/include/grub/emu/getroot.h
++++ b/include/grub/emu/getroot.h
+@@ -29,7 +29,8 @@ enum grub_dev_abstraction_types {
+ GRUB_DEV_ABSTRACTION_NONE,
+ GRUB_DEV_ABSTRACTION_LVM,
+ GRUB_DEV_ABSTRACTION_RAID,
+- GRUB_DEV_ABSTRACTION_LUKS,
++ GRUB_DEV_ABSTRACTION_LUKS1,
++ GRUB_DEV_ABSTRACTION_LUKS2,
+ GRUB_DEV_ABSTRACTION_GELI,
+ };
+
+diff --git a/util/getroot.c b/util/getroot.c
+index a5eaa64fd..76d86c174 100644
+--- a/util/getroot.c
++++ b/util/getroot.c
+@@ -100,7 +100,8 @@ grub_util_pull_device (const char *os_dev)
+ case GRUB_DEV_ABSTRACTION_LVM:
+ grub_util_pull_lvm_by_command (os_dev);
+ /* Fallthrough - in case that lvm-tools are unavailable. */
+- case GRUB_DEV_ABSTRACTION_LUKS:
++ case GRUB_DEV_ABSTRACTION_LUKS1:
++ case GRUB_DEV_ABSTRACTION_LUKS2:
+ grub_util_pull_devmapper (os_dev);
+ return;
diff --git a/grub.default b/grub.default
new file mode 100644
index 000000000000..6fd21c7fd223
--- /dev/null
+++ b/grub.default
@@ -0,0 +1,57 @@
+# GRUB boot loader configuration
+
+GRUB_DEFAULT=0
+GRUB_TIMEOUT=5
+GRUB_DISTRIBUTOR="Arch"
+GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet"
+GRUB_CMDLINE_LINUX=""
+
+# Preload both GPT and MBR modules so that they are not missed
+GRUB_PRELOAD_MODULES="part_gpt part_msdos"
+
+# Uncomment to enable booting from LUKS encrypted devices
+#GRUB_ENABLE_CRYPTODISK=y
+
+# Set to 'countdown' or 'hidden' to change timeout behavior,
+# press ESC key to display menu.
+GRUB_TIMEOUT_STYLE=menu
+
+# Uncomment to use basic console
+GRUB_TERMINAL_INPUT=console
+
+# Uncomment to disable graphical terminal
+#GRUB_TERMINAL_OUTPUT=console
+
+# The resolution used on graphical terminal
+# note that you can use only modes which your graphic card supports via VBE
+# you can see them in real GRUB with the command `vbeinfo'
+GRUB_GFXMODE=auto
+
+# Uncomment to allow the kernel use the same resolution used by grub
+GRUB_GFXPAYLOAD_LINUX=keep
+
+# Uncomment if you want GRUB to pass to the Linux kernel the old parameter
+# format "root=/dev/xxx" instead of "root=/dev/disk/by-uuid/xxx"
+#GRUB_DISABLE_LINUX_UUID=true
+
+# Uncomment to disable generation of recovery mode menu entries
+GRUB_DISABLE_RECOVERY=true
+
+# Uncomment and set to the desired menu colors. Used by normal and wallpaper
+# modes only. Entries specified as foreground/background.
+#GRUB_COLOR_NORMAL="light-blue/black"
+#GRUB_COLOR_HIGHLIGHT="light-cyan/blue"
+
+# Uncomment one of them for the gfx desired, a image background or a gfxtheme
+#GRUB_BACKGROUND="/path/to/wallpaper"
+#GRUB_THEME="/path/to/gfxtheme"
+
+# Uncomment to get a beep at GRUB start
+#GRUB_INIT_TUNE="480 440 1"
+
+# Uncomment to make GRUB remember the last selection. This requires
+# setting 'GRUB_DEFAULT=saved' above.
+#GRUB_SAVEDEFAULT=true
+
+# Uncomment to disable submenus in boot menu
+#GRUB_DISABLE_SUBMENU=y
diff --git a/mm_1.patch b/mm_1.patch
new file mode 100644
index 000000000000..146dcefc911f
--- /dev/null
+++ b/mm_1.patch
@@ -0,0 +1,87 @@
+---
+ 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 48f8a7907..a62dbeebb 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -803,23 +803,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 c070afc62..e0e580270 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -360,14 +360,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 b3753c9ca..536717776 100644
+--- a/include/grub/dl.h
++++ b/include/grub/dl.h
+@@ -203,7 +203,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);
+--
+2.32.0
+
+
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEEF9hrgiFbCdvenl/rVbJhu7ckPpQFAmEY9dUACgkQVbJhu7ck
+PpQ9xg/9E2CLh95L+w3TAgbclAkA6/KaVDnOy+woDUwGRv2yVxtTqMWakOSbZruD
+JTFCNPQdug+HHjqGFkjsS0nBu9U+DRlb/5RTOSyK+BKEnp3f9/OlaJnvHwy1AKe1
+Vhg4KdkXdmQ99ER8at7JMLs7n0KaetMegpLHVRCOuxr7VbtiGaJD1VcQS8ubIbwh
+jkvzJQVmJPt4dyD1I88oB2Xm/QKLimPtMCLNcWh0fXTUBBctOS6vZiacvMlF2/HX
+e7tWaNQMMayS1uZJL8B4Bl31iWFF7pm6CEZrPA4LK9Oggj7NUri+W1QLpzjUeBSw
+lJ6ZMfZXccUwrdqF7NDpxPuVe7cYUUIgcHmzxHWK028JHicaeA2v7/rZxlBkFqS5
+OF7JSD7ncngu8TAYFzhaHKRFouj9APY3x7q/IV1yuBOgw8yhD8T+hevoekqj8Dvg
+jbxIBaWulR/IyPcCEofapIr6xGSpQxPtwQIzTnXa8yTdguf832rUG3wguHeWfHQq
+uTiBYjzDMglon/ySlpPnv6z33TRZLHRcyhXeLjc9DJTgQIl3n4XZGLAf+itGTKOL
+EUPTs2b30oX7wYTLgBxtPpbmtNRVxEfY1nNxDp3U9ffQHkEaKkvfrtI8Fl3dK1nB
+XtjvaGDt/DfYOlWoyT9qwSsSKO7P/GRp2Fjiz5r9kISxwFuPLdA=
+=jVOn
+-----END PGP SIGNATURE-----
+
+
diff --git a/mm_2.patch b/mm_2.patch
new file mode 100644
index 000000000000..817b017e2b39
--- /dev/null
+++ b/mm_2.patch
@@ -0,0 +1,89 @@
+---
+ grub-core/kern/mm.c | 10 ++++++++++
+ include/grub/mm.h | 16 ++++++++++++++++
+ 2 files changed, 26 insertions(+)
+
+diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
+index e0e580270..2df835392 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -81,6 +81,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
+@@ -360,6 +361,15 @@ grub_memalign (grub_size_t align, grub_size_t size)
+ count++;
+ goto again;
+
++ case 1:
++ /* Request additional pages. */
++ count++;
++
++ if (grub_mm_add_region_fn && grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE)
++ goto again;
++
++ /* fallthrough */
++
+ default:
+ break;
+ }
+diff --git a/include/grub/mm.h b/include/grub/mm.h
+index 9c38dd3ca..afde57d2e 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 <config.h>
+@@ -28,6 +29,21 @@
+ # 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.
++ */
++extern grub_mm_add_region_func_t EXPORT_VAR(grub_mm_add_region_fn);
++
+ 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);
+--
+2.32.0
+
+
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEEF9hrgiFbCdvenl/rVbJhu7ckPpQFAmEY9dkACgkQVbJhu7ck
+PpScOQ//UbROjKLOAviqmbQoJLJHxwcOKGzpSWDmHI4mjXxc+wafFL6rPOa75//8
+R5QoYbEN1uCSkrK4Mgjn4aqwCHp9PyL+thJXuryzHNVtyPrz96aUi4kwXWfsX6Jw
+O6a1JpqTJieJyRcTWG91i6k8SMdtPuNXAt/tsllbRy6jp/fYDz4inJHgtG6p//WI
+4ORbW4OcFO7n3FCFa1l4EYqsaWJDSkAuKLk5QUKgpAKn3YEc1uL32TgFt77jIjSi
+4RIVZT4kNv6aVhCfwLQQW8g1BZkTYO5ehzDXB6SnI+4CjxeGwVMgeZFF6NbU68LX
+B4ZBO+SfTpwMoexHykM3VtVEzAQfmY8idIeS0m0ptC5j8rlz/oxI3TrqHkoTxgSU
+ZhyrqNOdMOnYx2jLqnh79qmizEebai1nPA/bl2Jke0lQvWSORH9h/HpfN3vCFTW3
+Vw8nfZS7MgbU0hk/14rFd/1TWV9m+aEgUITYxL1cnOI70V/Ne+HO41O+NJh6fT14
+5yZScrJ3FD8BkvJi/IW4PBZ2Iq8n7u9/UIvhKiNisQuHr13jgaGF2NYm6RYYZANg
+1qz7wkf3ora3nN74fu26ohWejlC9hcNGYlIjBI0iRF5E6IJ/mT4jq8PVJ0DJnrUc
+8AeLPgnW6BiPgTUevUOODo5jGZQ3oJ6zFumZNLl28wN0Lr9Mqnw=
+=+47H
+-----END PGP SIGNATURE-----
+
+
diff --git a/mm_3.patch b/mm_3.patch
new file mode 100644
index 000000000000..8f709d90dd77
--- /dev/null
+++ b/mm_3.patch
@@ -0,0 +1,99 @@
+---
+ 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 9838fb2f5..4d276bc87 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;
+@@ -478,23 +477,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,
+@@ -583,8 +565,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;
+
+ /* Prepare a memory region to store two memory maps. */
+@@ -624,22 +604,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. */
+--
+2.32.0
+
+
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEEF9hrgiFbCdvenl/rVbJhu7ckPpQFAmEY9d0ACgkQVbJhu7ck
+PpQn3w//WJu1uNsOVPLPU6TPLWVvEuPApH97bUrMjNnvzNYbPlR82ym+u+zMGoJ7
+Es77CEqgMDhCOxdD3oEi9PMZtXASgnw7uGKJycdGZOObzGBu4IZ4ZWQdWVfwlIZp
+4Qlc+ROTQoEWyLWpB/mJwrcXX8ILOdeRSX071zfHhJNcauEWMKEE88M/HH0VxCeT
+ZHGrmSzBE9gu3HQ8kir9wibroBeI4siW1feR5PWDmp/3R96z5MKN2xyy6BkH3Z0M
+sbl7zrlSu+NSnsmLzcH8oyfCBI+2soXgmGHQ1QCY8v8rbNx77sXKxTZniK7lH70Z
+X+0pcRm8aEYaT4ReWAxqJFykMn/9zfX4XRqEUBXTK/vWzSB4/5v0RLiUftvLfl7A
+Du8w+mocoOELAwCi4+VydHO9jUMnHJAlR+HAazd2jifi9jWsU7gxkD7FO+zFlble
+Eq5XFRgKzYmDHzPbD3udEH1+8792eGa0BjXwmIGpvFYfHpo4Jm24obykVVpH2m6j
+be99L+9A7PIxUg3GB6RAerR2Lc6a+nPRC47Jrp63BGtQ7SHPKCY7lzvw7q0nv0d+
+FmlcXQvOoeQeUNUzCaEmHaRP/WKSeeKL86Rp6pUIOXho6ON5llwSexJYEJlWA6rj
+p9wPIz8BA0iHFMix/Ch9DmUg1BNIE2vGaf+qhPmPNMF1ZFonbl8=
+=L7Ky
+-----END PGP SIGNATURE-----
+
+
diff --git a/mm_4.patch b/mm_4.patch
new file mode 100644
index 000000000000..6a141025b67f
--- /dev/null
+++ b/mm_4.patch
@@ -0,0 +1,101 @@
+---
+ grub-core/kern/efi/mm.c | 23 ++++++++++++++++-------
+ 1 file changed, 16 insertions(+), 7 deletions(-)
+
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index 4d276bc87..cfc6a67fc 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -504,7 +504,7 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
+
+ addr = grub_efi_allocate_pages_real (start, pages,
+ GRUB_EFI_ALLOCATE_ADDRESS,
+- GRUB_EFI_LOADER_CODE);
++ GRUB_EFI_LOADER_CODE);
+ if (! addr)
+ grub_fatal ("cannot allocate conventional memory %p with %u pages",
+ (void *) ((grub_addr_t) start),
+@@ -556,8 +556,8 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map,
+ }
+ #endif
+
+-void
+-grub_efi_mm_init (void)
++static grub_err_t
++grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes)
+ {
+ grub_efi_memory_descriptor_t *memory_map;
+ grub_efi_memory_descriptor_t *memory_map_end;
+@@ -570,7 +570,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");
+
+ /* Obtain descriptors for available memory. */
+ map_size = MEMORY_MAP_SIZE;
+@@ -588,14 +588,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");
+
+ 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, "cannot get memory map");
+
+ memory_map_end = NEXT_MEMORY_DESCRIPTOR (memory_map, map_size);
+
+@@ -610,7 +610,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. */
+@@ -628,6 +628,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)
+--
+2.32.0
+
+
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEEF9hrgiFbCdvenl/rVbJhu7ckPpQFAmEY9eEACgkQVbJhu7ck
+PpToNRAAmgY8k/pUck1W5suQpoJ3Ck6Kxuh6IUodllFPZskfgMAsddwHnGZCyqMA
+rQhxvAizZyS8yoeuQyNeWZQT1QA66XgZNJ7V1jO2Yr3o1fZ4SkNs7pszZbgdfU91
+1koyjg070O7CsdJZsOstCw9BbfuJxb6cfICZzcJjKC1ecOPKsHUzbH8V03IImnes
+dBM/VGoGXvazBg7eEVA6O6OvtpCtftHrhokdTDDL0dfhRNf9ps/FDI1sddmycmex
+0GBljoPIT7ymCxJ0UxSHotwMExm/odh86jfihcfhWGh16MeAYTaMJIl6Q6RaK9jr
+Gzdn65ZHHB7kUAt3JEi72oYw7tnaBOX8wcWe/vgp4XJ8d63T5E44svzUxetS+BvQ
+hvuASM2hciIo4Pj33v96rzs9cth549DsBswra3yJlrTKZzyIcDLbGyuCs+cpa1Ek
+02I0vlTbZLTAh86vGHESKmLaANDIxzh505fY8unQ61xe4SgLNa6B3Nf/KkwQh0uY
+ceClslAq1WgLwoDMeyvCIGO4W7FGvoirH36CXgfOYVGiL4SsZ58FsGNO+7SS7FM7
+68DpuvpzxMUPTD4YOpNE7VIZV59S0/9g3+yL+fcn229jaCzbo48PvBfOUUyYBqw3
+onAqs5TQhn0KS+5zrm1ORnGjN5IXjxu8c+FPm9JGYLw+o6DcwBE=
+=8bqP
+-----END PGP SIGNATURE-----
+
+
diff --git a/mm_5.patch b/mm_5.patch
new file mode 100644
index 000000000000..06ecaefab503
--- /dev/null
+++ b/mm_5.patch
@@ -0,0 +1,85 @@
+---
+ grub-core/kern/efi/mm.c | 20 +++++++++++++-------
+ 1 file changed, 13 insertions(+), 7 deletions(-)
+
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index cfc6a67fc..ced3ee5e7 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -478,7 +478,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,
+@@ -506,9 +506,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,
++ "cannot allocate conventional memory %p with %u pages",
++ (void *) ((grub_addr_t) start), (unsigned) pages);
+
+ grub_mm_init_region (addr, PAGES_TO_BYTES (pages));
+
+@@ -518,7 +518,9 @@ 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, "too little memory");
++
++ return GRUB_ERR_NONE;
+ }
+
+ void
+@@ -565,6 +567,7 @@ grub_efi_mm_add_regions (grub_efi_uint64_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;
+
+ /* Prepare a memory region to store two memory maps. */
+@@ -609,8 +612,11 @@ grub_efi_mm_add_regions (grub_efi_uint64_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. */
+--
+2.32.0
+
+
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEEF9hrgiFbCdvenl/rVbJhu7ckPpQFAmEY9eYACgkQVbJhu7ck
+PpQ8oA//VdC2Bv1hz/RkaRrhMM2vg/MSOeCer4RUrDhXWh8Kvt8koc1D7ZoE9MO7
+p8h1wkIsEEOrxkF5rwf+D0ZTg6joJcAmXPU/A2BY3oXuMSbKgOY/9/vJfDJio2dt
+UNeduTlAJ9YuFtEHEfGEGRVq5egajEoHlas91ScsiYKRqdQmHgkfXeEKGGTr3XMo
+RE/FI1duWhmqgzS9kjDq0dbvTtXEBKRndcDPVxyXpFbl1GE+swJzAUsVRNW7PZe8
+IYopqz3+6wlp7jo80REtV6ndIw2/N1nvScCF/Mfn5VHf/ObDoWw4cnZvgI/5YEnZ
+48v1gMPft95CBjijnoD+F29jFBB6zmK8lFUN4FNY+edoGtlNrmEoZB0FkQJLXWNp
+TS6y4EEx9pJzPuxf2VAF5+eMBzqU6f8qZDoty3NMDPNTDXMr0SjeiSJGMfDdU1Qg
+Ouk9/I7XOLi91QzbyJP4dpfsI78002rzyibOim8jZ8JFv4InKG1krj1JU2BnVj0h
++7OYIfmDkGZs5ZvZ5PdFgpzqqmlH6wXWZYUMaYHlK2c/mOnJ3ty4NV14cWb8YqrF
+VQ3U5EUzUL+8sTQAxwGGCDuC+E6ZuqZ7qVx0O1c5OeOxVh7o3rPLQ24D9a+6J0iv
+eGvcgaHX+abwi/1fVL2ItovrGiGtfLtxd8y9G0zctgDBrpqVfvU=
+=u8uk
+-----END PGP SIGNATURE-----
+
+
diff --git a/mm_6.patch b/mm_6.patch
new file mode 100644
index 000000000000..c7b370863461
--- /dev/null
+++ b/mm_6.patch
@@ -0,0 +1,81 @@
+---
+ 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 ced3ee5e7..f3d2e2b99 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -482,7 +482,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;
+
+@@ -496,6 +497,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);
+@@ -559,7 +564,7 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map,
+ #endif
+
+ static grub_err_t
+-grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes)
++grub_efi_mm_add_regions (grub_efi_uint64_t required_bytes, unsigned int flags)
+ {
+ grub_efi_memory_descriptor_t *memory_map;
+ grub_efi_memory_descriptor_t *memory_map_end;
+@@ -614,7 +619,8 @@ grub_efi_mm_add_regions (grub_efi_uint64_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;
+
+@@ -641,8 +647,9 @@ grub_efi_mm_add_regions (grub_efi_uint64_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)
+--
+2.32.0
+
+
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEEF9hrgiFbCdvenl/rVbJhu7ckPpQFAmEY9eoACgkQVbJhu7ck
+PpSFbQ//Y5G9FkVKWEwCrB7KhbF9pcmTobET1Q7lvrVtK+XArMuZQn/aDTxjoXM/
+87qMkF2OTko79/z1nzveDODPtR1E48jqR41+Qz7CICOH+8oG2Ur+MZt5J2T2M/Gf
+JsqJ26Fk36A86IoZHZ73yfHCWgtQo4+jckOLJkGbTmlriOWSOCfvCKIt7aF0Z2Wf
+SkfEt0UMV6i81HKkZ6v+nPJJQmZQp+pTpOWr7hrjx/6nUT1QadVQoVL8YYKKxHcX
+zMkT7hAg+D6vAVJhfOSt/VoMcBJeBK8Or2OD5gDOKcqZ19nixa1u3r6NnkkG10OH
+PyVL35svdUMMiIC2LXy2YCf7hbrOCOuCk10sT8Q05TrDvFpkvOn6QcGhvcSXtzmB
+5wju6EVqCtIrrcSYl3Y2bWjrKFZXL3w1vOUnObF3yae2soR2h3Nvgyg98J3Qoee+
+7dNYGs3WmDb3wF9p/0TY54g89ZotKwZUEuaVu7qtcp3y6HpmcZ1XbnA8Y3aWmdmm
+EeiUKAMSacyqxt1QBWciQTs7BaXWwxj8hI8xDjpCEMVFCux4nxdw6aXQXqocAaor
+mDhjjriqmwTRNpZnUlUkScwczSJuh5WqnLWj5RKC01drUlcbnJjvdsaU1VAvzEju
+24KGNqanC+jc1ZqKcx4eeCQHF21x8+xgsmgjYJZ8PGptT0bg/Xc=
+=PvkK
+-----END PGP SIGNATURE-----
+
+