summaryrefslogtreecommitdiff
path: root/config/grub
diff options
context:
space:
mode:
Diffstat (limited to 'config/grub')
-rw-r--r--config/grub/background/COPYING3
-rw-r--r--config/grub/background/background1024x768.pngbin4935 -> 0 bytes
-rw-r--r--config/grub/background/background1280x800.pngbin3451 -> 0 bytes
-rw-r--r--config/grub/bootorder1
-rw-r--r--config/grub/config/AUTHORS2
-rw-r--r--config/grub/config/COPYING695
-rw-r--r--config/grub/config/grub_memdisk.cfg7
-rw-r--r--config/grub/default/config/payload (renamed from config/grub/config/grub.cfg)172
-rw-r--r--config/grub/default/patches/0001-mitigate-grub-s-missing-characters-for-borders-arrow.patch (renamed from config/grub/patches/0001-borderfix/0001-mitigate-grub-s-missing-characters-for-borders-arrow.patch)10
-rw-r--r--config/grub/default/patches/0002-say-the-name-libreboot-in-the-grub-menu.patch (renamed from config/grub/patches/0001-borderfix/0002-say-the-name-libreboot-in-the-grub-menu.patch)12
-rw-r--r--config/grub/default/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch (renamed from config/grub/patches/0003-keyboardfix/0001-at_keyboard-coreboot-force-scancodes2-translate.patch)6
-rw-r--r--config/grub/default/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch (renamed from config/grub/patches/0003-keyboardfix/0002-keylayouts-don-t-print-Unknown-key-message.patch)6
-rw-r--r--config/grub/default/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch (renamed from config/grub/patches/0004-prefix/0001-don-t-print-missing-prefix-errors-on-the-screen.patch)10
-rw-r--r--config/grub/default/patches/0006-don-t-print-error-if-module-not-found.patch (renamed from config/grub/patches/0004-prefix/0002-don-t-print-error-if-module-not-found.patch)10
-rw-r--r--config/grub/default/patches/0007-don-t-print-empty-error-messages.patch (renamed from config/grub/patches/0004-prefix/0003-don-t-print-empty-error-messages.patch)10
-rw-r--r--config/grub/default/patches/0008-kern-coreboot-mmap-Map-to-reserved.patch37
-rw-r--r--config/grub/default/patches/0009-Revert-configure-Check-linker-for-image-base-support.patch70
-rw-r--r--config/grub/default/patches/0010-Revert-configure-Print-a-more-helpful-error-if-autoc.patch30
-rw-r--r--config/grub/default/target.cfg4
-rw-r--r--config/grub/keymap/colemak.gkbbin488 -> 0 bytes
-rw-r--r--config/grub/keymap/deqwertz.gkbbin508 -> 0 bytes
-rw-r--r--config/grub/keymap/esqwerty.gkbbin492 -> 0 bytes
-rw-r--r--config/grub/keymap/frazerty.gkbbin496 -> 0 bytes
-rw-r--r--config/grub/keymap/frdvbepo.gkbbin516 -> 0 bytes
-rw-r--r--config/grub/keymap/itqwerty.gkbbin488 -> 0 bytes
-rw-r--r--config/grub/keymap/svenska.gkbbin488 -> 0 bytes
-rw-r--r--config/grub/keymap/trqwerty.gkbbin476 -> 0 bytes
-rw-r--r--config/grub/keymap/ukdvorak.gkbbin372 -> 0 bytes
-rw-r--r--config/grub/keymap/ukqwerty.gkbbin488 -> 0 bytes
-rw-r--r--config/grub/keymap/usdvorak.gkbbin364 -> 0 bytes
-rw-r--r--config/grub/keymap/usqwerty.gkbbin344 -> 0 bytes
-rw-r--r--config/grub/modules.list157
-rw-r--r--config/grub/nvme/config/payload320
-rw-r--r--config/grub/nvme/patches/0001-mitigate-grub-s-missing-characters-for-borders-arrow.patch90
-rw-r--r--config/grub/nvme/patches/0002-say-the-name-libreboot-in-the-grub-menu.patch25
-rw-r--r--config/grub/nvme/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch107
-rw-r--r--config/grub/nvme/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch38
-rw-r--r--config/grub/nvme/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch102
-rw-r--r--config/grub/nvme/patches/0006-don-t-print-error-if-module-not-found.patch34
-rw-r--r--config/grub/nvme/patches/0007-don-t-print-empty-error-messages.patch31
-rw-r--r--config/grub/nvme/patches/0008-Add-native-NVMe-driver-based-on-SeaBIOS.patch1074
-rw-r--r--config/grub/nvme/patches/0009-kern-coreboot-mmap-Map-to-reserved.patch37
-rw-r--r--config/grub/nvme/patches/0010-Revert-configure-Check-linker-for-image-base-support.patch70
-rw-r--r--config/grub/nvme/patches/0011-Revert-configure-Print-a-more-helpful-error-if-autoc.patch30
-rw-r--r--config/grub/nvme/target.cfg4
-rw-r--r--config/grub/patches/0002-luks2/0003-Add-CC0-license.patch42
-rw-r--r--config/grub/patches/0002-luks2/0004-Define-GRUB_UINT32_MAX.patch39
-rw-r--r--config/grub/patches/0002-luks2/0005-Add-Argon2-algorithm.patch2611
-rw-r--r--config/grub/patches/0002-luks2/0006-Error-on-missing-Argon2id-parameters.patch58
-rw-r--r--config/grub/patches/0002-luks2/0007-Compile-with-Argon2id-support.patch83
-rw-r--r--config/grub/patches/0002-luks2/0008-Make-grub-install-work-with-Argon2.patch26
-rw-r--r--config/grub/target.cfg3
-rw-r--r--config/grub/xhci_nvme/config/payload321
-rw-r--r--config/grub/xhci_nvme/patches/0001-mitigate-grub-s-missing-characters-for-borders-arrow.patch90
-rw-r--r--config/grub/xhci_nvme/patches/0002-say-the-name-libreboot-in-the-grub-menu.patch25
-rw-r--r--config/grub/xhci_nvme/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch107
-rw-r--r--config/grub/xhci_nvme/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch38
-rw-r--r--config/grub/xhci_nvme/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch102
-rw-r--r--config/grub/xhci_nvme/patches/0006-don-t-print-error-if-module-not-found.patch34
-rw-r--r--config/grub/xhci_nvme/patches/0007-don-t-print-empty-error-messages.patch31
-rw-r--r--config/grub/xhci_nvme/patches/0008-grub-core-bus-usb-Parse-SuperSpeed-companion-descrip.patch (renamed from config/grub/patches/0005-xhci/0001-grub-core-bus-usb-Parse-SuperSpeed-companion-descrip.patch)9
-rw-r--r--config/grub/xhci_nvme/patches/0009-usb-Add-enum-for-xHCI.patch (renamed from config/grub/patches/0005-xhci/0002-usb-Add-enum-for-xHCI.patch)8
-rw-r--r--config/grub/xhci_nvme/patches/0010-usbtrans-Set-default-maximum-packet-size.patch (renamed from config/grub/patches/0005-xhci/0003-usbtrans-Set-default-maximum-packet-size.patch)8
-rw-r--r--config/grub/xhci_nvme/patches/0011-grub-core-bus-usb-Add-function-pointer-for-attach-de.patch (renamed from config/grub/patches/0005-xhci/0004-grub-core-bus-usb-Add-function-pointer-for-attach-de.patch)10
-rw-r--r--config/grub/xhci_nvme/patches/0012-grub-core-bus-usb-usbhub-Add-new-private-fields-for-.patch (renamed from config/grub/patches/0005-xhci/0005-grub-core-bus-usb-usbhub-Add-new-private-fields-for-.patch)10
-rw-r--r--config/grub/xhci_nvme/patches/0013-grub-core-bus-usb-Add-xhci-support.patch (renamed from config/grub/patches/0005-xhci/0006-grub-core-bus-usb-Add-xhci-support.patch)19
-rw-r--r--config/grub/xhci_nvme/patches/0014-grub-core-bus-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch (renamed from config/grub/patches/0005-xhci/0007-grub-core-bus-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch)8
-rw-r--r--config/grub/xhci_nvme/patches/0015-xHCI-also-accept-SBRN-0x31-and-0x32.patch26
-rw-r--r--config/grub/xhci_nvme/patches/0016-xhci-fix-port-indexing.patch43
-rw-r--r--config/grub/xhci_nvme/patches/0017-xhci-configure-TT-for-non-root-hubs.patch98
-rw-r--r--config/grub/xhci_nvme/patches/0018-Fix-compilation-on-x86_64.patch (renamed from config/grub/patches/0005-xhci/0008-Fix-compilation-on-x86_64.patch)18
-rw-r--r--config/grub/xhci_nvme/patches/0019-Add-native-NVMe-driver-based-on-SeaBIOS.patch1074
-rw-r--r--config/grub/xhci_nvme/patches/0020-kern-coreboot-mmap-Map-to-reserved.patch37
-rw-r--r--config/grub/xhci_nvme/patches/0021-Revert-configure-Check-linker-for-image-base-support.patch70
-rw-r--r--config/grub/xhci_nvme/patches/0022-Revert-configure-Print-a-more-helpful-error-if-autoc.patch30
-rw-r--r--config/grub/xhci_nvme/target.cfg4
76 files changed, 4421 insertions, 3865 deletions
diff --git a/config/grub/background/COPYING b/config/grub/background/COPYING
deleted file mode 100644
index 9a5f81c6..00000000
--- a/config/grub/background/COPYING
+++ /dev/null
@@ -1,3 +0,0 @@
-The deer logo for Libreboot is copyright 2014 Marcus Moeller and released under
-CC-0: https://creativecommons.org/publicdomain/zero/1.0/legalcode
-The grey backgrounds with it were made by Leah Rowe in 2016, also CC-0
diff --git a/config/grub/background/background1024x768.png b/config/grub/background/background1024x768.png
deleted file mode 100644
index 181909db..00000000
--- a/config/grub/background/background1024x768.png
+++ /dev/null
Binary files differ
diff --git a/config/grub/background/background1280x800.png b/config/grub/background/background1280x800.png
deleted file mode 100644
index f563ea63..00000000
--- a/config/grub/background/background1280x800.png
+++ /dev/null
Binary files differ
diff --git a/config/grub/bootorder b/config/grub/bootorder
deleted file mode 100644
index b33e1295..00000000
--- a/config/grub/bootorder
+++ /dev/null
@@ -1 +0,0 @@
-/rom@img/grub2
diff --git a/config/grub/config/AUTHORS b/config/grub/config/AUTHORS
deleted file mode 100644
index 542739ce..00000000
--- a/config/grub/config/AUTHORS
+++ /dev/null
@@ -1,2 +0,0 @@
-Copyright (C) 2014, 2015, 2016, 2020, 2021, 2023 Leah Rowe <leah@libreboot.org>
-Copyright (C) 2015 Klemens Nanni <contact@autoboot.org>
diff --git a/config/grub/config/COPYING b/config/grub/config/COPYING
deleted file mode 100644
index f74bc54d..00000000
--- a/config/grub/config/COPYING
+++ /dev/null
@@ -1,695 +0,0 @@
-# GRUB configuration files under resources/grub/config/
-
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-
-# See AUTHORS for copyright holder information.
-
-# Full terms of GPLv3 below, taken from https://www.gnu.org/licenses/licenses.html
-________________________________________________________________________
-
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- <program> Copyright (C) <year> <name of author>
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<http://www.gnu.org/licenses/>.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/config/grub/config/grub_memdisk.cfg b/config/grub/config/grub_memdisk.cfg
deleted file mode 100644
index 0763801b..00000000
--- a/config/grub/config/grub_memdisk.cfg
+++ /dev/null
@@ -1,7 +0,0 @@
-set prefix=(memdisk)/boot/grub
-
-if [ -f (cbfsdisk)/grub.cfg ]; then
- source (cbfsdisk)/grub.cfg
-else
- source (memdisk)/boot/grub/grub_default.cfg
-fi
diff --git a/config/grub/config/grub.cfg b/config/grub/default/config/payload
index 3bbd2ecc..3d84413e 100644
--- a/config/grub/config/grub.cfg
+++ b/config/grub/default/config/payload
@@ -1,3 +1,7 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+# Copyright (C) 2014-2016,2020-2021,2023-2025 Leah Rowe <leah@libreboot.org>
+# Copyright (C) 2015 Klemens Nanni <contact@autoboot.org>
+
set prefix=(memdisk)/boot/grub
insmod at_keyboard
@@ -22,13 +26,14 @@ else
gfxpayload=keep
terminal_output --append gfxterm
- if [ -f (cbfsdisk)/background.png ]; then
- insmod png
- background_image (cbfsdisk)/background.png
- elif [ -f (cbfsdisk)/background.jpg ]; then
- insmod jpeg
- background_image (cbfsdisk)/background.jpg
- fi
+ for dt in cbfsdisk memdisk; do
+ for it in png jpg; do
+ if [ -f (${dt})/background.${it} ]; then
+ insmod ${it}
+ background_image (${dt})/background.${it}
+ fi
+ done
+ done
fi
# Keep CTRL pressed to enable default serial terminal (COM1 or the like)
@@ -48,9 +53,9 @@ set default="0"
if [ -f (cbfsdisk)/timeout.cfg ]; then
source (cbfsdisk)/timeout.cfg
else
- set timeout=5
+ set timeout=8
fi
-set grub_scan_disk="both"
+set grub_scan_disk="ahci ata"
if [ -f (cbfsdisk)/scan.cfg ]; then
source (cbfsdisk)/scan.cfg
fi
@@ -59,34 +64,43 @@ if [ -f (cbfsdisk)/keymap.gkb ]; then
keymap (cbfsdisk)/keymap.gkb
fi
-function try_user_config {
+function really_try_user_config {
set root="${1}"
+ if [ -f /"${2}"/grub.cfg ]; then
+ unset superusers
+ configfile /"${2}"/grub.cfg
+ fi
+}
+
+function try_user_config {
# The @/... entries are for cases where the BTRFS filesystem is being used
- for dir in boot grub grub2 boot/grub boot/grub2 @/boot @/grub @/grub2 @/boot/grub @/boot/grub2; do
- for name in '' osboot_ autoboot_ libreboot_ coreboot_; do
- if [ -f /"${dir}"/"${name}"grub.cfg ]; then
- unset superusers
- configfile /"${dir}"/"${name}"grub.cfg
- fi
- done
+ for dir in grub boot/grub @/grub @/boot/grub grub2 boot/grub2 @/grub2 @/boot/grub2 boot @/boot; do
+ really_try_user_config "${1}" "${dir}"
+ done
+ for dir in ubuntu debian redhat; do
+ really_try_user_config "${1}" "EFI/${dir}"
done
}
function search_grub {
echo -n "Attempting to load grub.cfg from '${1}' devices"
- for i in 0 1 2 3 4 5 6 7 8 9 10 11; do
- for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
- try_user_config "(${1}${i},${part})"
+ for i in 0 1 2 3 4 5 6 7 8; do
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12; do
+ if [ "${1}" != "nvme" ]; then
+ try_user_config "(${1}${i},${part})"
+ fi
done
- # raw devices e.g. (ahci0) instead of (ahci0,1)
- try_user_config "(${1}${i})"
+ if [ "${1}" != "nvme" ]; then
+ # raw devices e.g. (ahci0) instead of (ahci0,1)
+ try_user_config "(${1}${i})"
+ fi
done
echo # Insert newline
}
function try_isolinux_config {
set root="${1}"
- for dir in '' /boot /EFI /boot/EFI /@ /@/boot /@/boot/EFI /@/EFI; do
+ for dir in '' /boot /EFI /@ /@/boot; do
if [ -f "${dir}"/isolinux/isolinux.cfg ]; then
syslinux_configfile -i "${dir}"/isolinux/isolinux.cfg
elif [ -f "${dir}"/syslinux/syslinux.cfg ]; then
@@ -100,12 +114,16 @@ function try_isolinux_config {
}
function search_isolinux {
echo "\nAttempting to parse iso/sys/extlinux config from '${1}' devices"
- for i in 0 1 2 3 4 5 6 7 8 9 10 11; do
- for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
- try_isolinux_config "(${1}${i},${part})"
+ for i in 0 1 2 3 4 5 6 7 8; do
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12; do
+ if [ "${1}" != "nvme" ]; then
+ try_isolinux_config "(${1}${i},${part})"
+ fi
done
- # raw devices e.g. (usb0) instead of (usb0,1)
- try_isolinux_config "(${1}${i})"
+ if [ "${1}" != "nvme" ]; then
+ # raw devices e.g. (usb0) instead of (usb0,1)
+ try_isolinux_config "(${1}${i})"
+ fi
done
echo # Insert newline
}
@@ -119,60 +137,70 @@ function search_bootcfg {
}
menuentry 'Load Operating System (incl. fully encrypted disks) [o]' --hotkey='o' {
- if [ "${grub_scan_disk}" != "ata" ]; then
- search_bootcfg ahci
- fi
- if [ "${grub_scan_disk}" != "ahci" ]; then
- search_bootcfg ata
- fi
+ for grub_disk in ${grub_scan_disk}; do
+ search_bootcfg ${grub_disk}
+ done
# grub device enumeration is very slow, so checks are hardcoded
- # TODO: add more strings, based on what distros set up when
- # the user select auto-partitioning on those installers
- lvmvol="lvm/grubcrypt-bootvol lvm/grubcrypt-rootvol"
-
raidvol="md/0 md/1 md/2 md/3 md/4 md/5 md/6 md/7 md/8 md/9"
- # in practise, doing multiple redundant checks is perfectly fast and
+ # in practise, doing multiple redundant checks is perfectly fast
# TODO: optimize grub itself, and use */? here for everything
- for vol in ${lvmvol} ${raidvol} ; do
+ for vol in ${raidvol} ; do
try_bootcfg "${vol}"
done
- unset ahcidev
- unset atadev
- for i in 11 10 9 8 7 6 5 4 3 2 1 0; do
- for part in 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1; do
- if [ "${grub_scan_disk}" != "ata" ]; then
- ahcidev="(ahci${i},${part}) ${ahcidev}"
- fi
- if [ "${grub_scan_disk}" != "ahci" ]; then
- atadev="(ata${i},${part}) ${atadev}"
- fi
+ unset bootdev
+ for grub_disk in ${grub_scan_disk}; do
+ for i in 0 1 2 3 4 5 6 7 8; do
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12; do
+ if [ "${grub_disk}" = "ahci" ]; then
+ bootdev="${bootdev} (ahci${i},${part})"
+ elif [ "${grub_disk}" = "ata" ]; then
+ bootdev="${bootdev} (ata${i},${part})"
+ elif [ "${grub_disk}" = "nvme" ]; then
+ # TODO: do we care about other namesapces
+ bootdev="${bootdev} (nvme${i}n1,${part})"
+ fi
+ done
done
done
set pager=0
echo -n "Attempting to unlock encrypted volumes"
- for dev in ${ahcidev} ${atadev} ${lvmvol} ${raidvol}; do
+ for dev in ${bootdev} ${raidvol}; do
if cryptomount "${dev}" ; then break ; fi
done
set pager=1
echo
+ search_bootcfg crypto
+
+ lvmvol=""
+
# after cryptomount, lvm volumes might be available
+ # using * is slow on some machines, but we use it here,
+ # just once. in so doing, we find every lvm volume
+ for vol in (*); do
+ if regexp ^\\(lvm/ $vol; then
+ lvmvol="${lvmvol} ${vol}"
+ try_bootcfg "${vol}"
+ fi
+ done
+
+ # user might have put luks inside lvm
+ set pager=0
+ echo "Attempting to unlock encrypted LVMs"
for vol in ${lvmvol}; do
- try_bootcfg "${vol}"
+ cryptomount "$vol"
done
+ set pager=1
+ echo
search_bootcfg crypto
- for vol in lvm/* ; do
- try_bootcfg "${vol}"
- done
-
true # Prevent pager requiring to accept each line instead of whole screen
}
@@ -185,6 +213,14 @@ menuentry 'Search for GRUB/SYSLINUX/EXTLINUX/ISOLINUX on AHCI [a]' --hotkey='a'
menuentry 'Search for GRUB/SYSLINUX/EXTLINUX/ISOLINUX on ATA/IDE [d]' --hotkey='d' {
search_bootcfg ata
}
+if [ -f (cbfsdisk)/grub.cfg ]; then
+menuentry 'Load configuration (grub.cfg) in CBFS [t]' --hotkey='t' {
+ set root='(cbfsdisk)'
+ if [ -f /grub.cfg ]; then
+ configfile /grub.cfg
+ fi
+}
+fi
if [ -f (cbfsdisk)/grubtest.cfg ]; then
menuentry 'Load test configuration (grubtest.cfg) inside of CBFS [t]' --hotkey='t' {
set root='(cbfsdisk)'
@@ -193,18 +229,38 @@ menuentry 'Load test configuration (grubtest.cfg) inside of CBFS [t]' --hotkey=
fi
}
fi
+if [ -f (cbfsdisk)/u-boot ]; then
+menuentry 'U-Boot i386 payload (experimental) [u]' --hotkey='u' {
+ set root='cbfsdisk'
+ chainloader /u-boot
+}
+fi
if [ -f (cbfsdisk)/seabios.elf ]; then
-menuentry 'Load SeaBIOS (payload) [b]' --hotkey='b' {
+if [ -f (cbfsdisk)/img/u-boot ]; then
+menuentry 'Load SeaBIOS (U-Boot UEFI available in the ESC menu) [b]' --hotkey='b' {
set root='cbfsdisk'
chainloader /seabios.elf
}
+else
+menuentry 'Load SeaBIOS [b]' --hotkey='b' {
+ set root='cbfsdisk'
+ chainloader /seabios.elf
+}
+fi
fi
if [ -f (cbfsdisk)/img/grub2 ]; then
+if [ -f (cbfsdisk)/img/u-boot ]; then
+menuentry 'Return to SeaBIOS (U-Boot UEFI available in the ESC menu) [b]' --hotkey='b' {
+ set root='cbfsdisk'
+ chainloader /fallback/payload
+}
+else
menuentry 'Return to SeaBIOS [b]' --hotkey='b' {
set root='cbfsdisk'
chainloader /fallback/payload
}
fi
+fi
menuentry 'Poweroff [p]' --hotkey='p' {
halt
}
@@ -246,4 +302,4 @@ submenu 'Other [z]' --hotkey='z' {
menuentry 'Disable spkmodem [z]' --hotkey='z' {
terminal_output --remove spkmodem
}
-} \ No newline at end of file
+}
diff --git a/config/grub/patches/0001-borderfix/0001-mitigate-grub-s-missing-characters-for-borders-arrow.patch b/config/grub/default/patches/0001-mitigate-grub-s-missing-characters-for-borders-arrow.patch
index 183f5a91..7112b0aa 100644
--- a/config/grub/patches/0001-borderfix/0001-mitigate-grub-s-missing-characters-for-borders-arrow.patch
+++ b/config/grub/default/patches/0001-mitigate-grub-s-missing-characters-for-borders-arrow.patch
@@ -1,7 +1,7 @@
-From ce13539fe2103abbd991814d995e06cf96e485f7 Mon Sep 17 00:00:00 2001
+From 5a2c887181e7cdbd6b38d544e460d02623c902e6 Mon Sep 17 00:00:00 2001
From: Leah Rowe <leah@libreboot.org>
Date: Sun, 31 Oct 2021 03:47:05 +0000
-Subject: [PATCH 1/3] mitigate grub's missing characters for borders/arrow
+Subject: [PATCH 01/10] mitigate grub's missing characters for borders/arrow
characters
This cleans up the display on the main screen in GRUB.
@@ -12,7 +12,7 @@ Just don't draw a border, at all.
1 file changed, 2 insertions(+), 47 deletions(-)
diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
-index b1321eb26..e76094dfd 100644
+index 9c383e64a..8ec1dd1e8 100644
--- a/grub-core/normal/menu_text.c
+++ b/grub-core/normal/menu_text.c
@@ -108,47 +108,6 @@ grub_print_message_indented (const char *msg, int margin_left, int margin_right,
@@ -76,7 +76,7 @@ index b1321eb26..e76094dfd 100644
if (!msg_translated)
return 0;
ret += grub_print_message_indented_real (msg_translated, STANDARD_MARGIN,
-@@ -410,8 +367,6 @@ grub_menu_init_page (int nested, int edit,
+@@ -413,8 +370,6 @@ grub_menu_init_page (int nested, int edit,
grub_term_normal_color = grub_color_menu_normal;
grub_term_highlight_color = grub_color_menu_highlight;
@@ -86,5 +86,5 @@ index b1321eb26..e76094dfd 100644
grub_term_highlight_color = old_color_highlight;
geo->timeout_y = geo->first_entry_y + geo->num_entries
--
-2.25.1
+2.47.3
diff --git a/config/grub/patches/0001-borderfix/0002-say-the-name-libreboot-in-the-grub-menu.patch b/config/grub/default/patches/0002-say-the-name-libreboot-in-the-grub-menu.patch
index 6ff97979..1d137b4c 100644
--- a/config/grub/patches/0001-borderfix/0002-say-the-name-libreboot-in-the-grub-menu.patch
+++ b/config/grub/default/patches/0002-say-the-name-libreboot-in-the-grub-menu.patch
@@ -1,25 +1,25 @@
-From 70f9e72c3ff6381fe3519612de3b649c0cf26b9a Mon Sep 17 00:00:00 2001
+From 25d7d35e0af74361a5510c3e6313b8ce5e00cd6a Mon Sep 17 00:00:00 2001
From: Leah Rowe <leah@libreboot.org>
Date: Sat, 19 Nov 2022 16:30:24 +0000
-Subject: [PATCH 2/3] say the name libreboot, in the grub menu
+Subject: [PATCH 02/10] say the name libreboot, in the grub menu
---
grub-core/normal/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
-index bd4431000..31308e16a 100644
+index de9a3f961..bed502cde 100644
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
-@@ -209,7 +209,7 @@ grub_normal_init_page (struct grub_term_output *term,
+@@ -215,7 +215,7 @@ grub_normal_init_page (struct grub_term_output *term,
grub_term_cls (term);
- msg_formatted = grub_xasprintf (_("GNU GRUB version %s"), PACKAGE_VERSION);
-+ msg_formatted = grub_xasprintf (_("Libreboot 20240504 release, based on coreboot. https://libreboot.org/"));
++ msg_formatted = grub_xasprintf (_("Libreboot 26.01 RC4 Magnanimous Max (GRUB menu): https://libreboot.org/"));
if (!msg_formatted)
return;
--
-2.25.1
+2.47.3
diff --git a/config/grub/patches/0003-keyboardfix/0001-at_keyboard-coreboot-force-scancodes2-translate.patch b/config/grub/default/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch
index 21e8630b..bb07abd6 100644
--- a/config/grub/patches/0003-keyboardfix/0001-at_keyboard-coreboot-force-scancodes2-translate.patch
+++ b/config/grub/default/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch
@@ -1,7 +1,7 @@
-From 96c0bbe5d406b616360a7fce7cee67d7692c0d6d Mon Sep 17 00:00:00 2001
+From acff2df937bb4172f9bdb46d12e82edbbcad7996 Mon Sep 17 00:00:00 2001
From: Leah Rowe <leah@libreboot.org>
Date: Mon, 30 Oct 2023 22:19:21 +0000
-Subject: [PATCH 1/1] at_keyboard coreboot: force scancodes2+translate
+Subject: [PATCH 03/10] at_keyboard coreboot: force scancodes2+translate
Scan code set 2 with translation should be assumed in
every case, as the default starting position.
@@ -103,5 +103,5 @@ index f8a129eb7..8207225c2 100644
grub_dprintf ("atkeyb", "returned set %d\n", ps2_state.current_set);
if (ps2_state.current_set == 2)
--
-2.39.2
+2.47.3
diff --git a/config/grub/patches/0003-keyboardfix/0002-keylayouts-don-t-print-Unknown-key-message.patch b/config/grub/default/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch
index fbef86a4..fbcbb2c3 100644
--- a/config/grub/patches/0003-keyboardfix/0002-keylayouts-don-t-print-Unknown-key-message.patch
+++ b/config/grub/default/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch
@@ -1,7 +1,7 @@
-From 0a6abeb40ac4284fbff6ef5958989d561b6290a7 Mon Sep 17 00:00:00 2001
+From 247133e1f9820bcb81f7d27fc1395d64dc7b0a89 Mon Sep 17 00:00:00 2001
From: Leah Rowe <leah@libreboot.org>
Date: Tue, 31 Oct 2023 10:33:28 +0000
-Subject: [PATCH 1/1] keylayouts: don't print "Unknown key" message
+Subject: [PATCH 04/10] keylayouts: don't print "Unknown key" message
on keyboards with stuck keys, this results in GRUB just
spewing it repeatedly, preventing use of GRUB.
@@ -34,5 +34,5 @@ index aa3ba34f2..445fa0601 100644
}
--
-2.39.2
+2.47.3
diff --git a/config/grub/patches/0004-prefix/0001-don-t-print-missing-prefix-errors-on-the-screen.patch b/config/grub/default/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch
index 25091d16..93b0c505 100644
--- a/config/grub/patches/0004-prefix/0001-don-t-print-missing-prefix-errors-on-the-screen.patch
+++ b/config/grub/default/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch
@@ -1,7 +1,7 @@
-From 9e7a651a0f15f2e9dec65a77765c3c4fd97b4165 Mon Sep 17 00:00:00 2001
+From c5ad46b7ba93136764fd1eae1bd0c0c32ce1c5b2 Mon Sep 17 00:00:00 2001
From: Leah Rowe <leah@libreboot.org>
Date: Sun, 5 Nov 2023 16:14:58 +0000
-Subject: [PATCH 1/1] don't print missing prefix errors on the screen
+Subject: [PATCH 05/10] don't print missing prefix errors on the screen
we do actually set the prefix. this patch modifies
grub to still set grub_errno and return accordingly,
@@ -85,10 +85,10 @@ index 18de52562..2a0fea6c8 100644
}
file = try_open_from_prefix (prefix, filename);
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
-index 4011e2d15..af3bd00d0 100644
+index de8c3aa8d..eac3ea48d 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
-@@ -758,7 +758,7 @@ grub_dl_load (const char *name)
+@@ -880,7 +880,7 @@ grub_dl_load (const char *name)
return 0;
if (! grub_dl_dir) {
@@ -98,5 +98,5 @@ index 4011e2d15..af3bd00d0 100644
}
--
-2.39.2
+2.47.3
diff --git a/config/grub/patches/0004-prefix/0002-don-t-print-error-if-module-not-found.patch b/config/grub/default/patches/0006-don-t-print-error-if-module-not-found.patch
index f4cf939e..2dbf6d87 100644
--- a/config/grub/patches/0004-prefix/0002-don-t-print-error-if-module-not-found.patch
+++ b/config/grub/default/patches/0006-don-t-print-error-if-module-not-found.patch
@@ -1,7 +1,7 @@
-From 6237c5762edccc1e1fa4746b1d4aa5e8d81e4883 Mon Sep 17 00:00:00 2001
+From 6522ceca8949105b2e1575ada2f05b3061bfe8f3 Mon Sep 17 00:00:00 2001
From: Leah Rowe <leah@libreboot.org>
Date: Sun, 5 Nov 2023 16:36:22 +0000
-Subject: [PATCH 1/1] don't print error if module not found
+Subject: [PATCH 06/10] don't print error if module not found
still set grub_errno accordingly, and otherwise
behave the same. in libreboot, we remove a lot of
@@ -17,10 +17,10 @@ Signed-off-by: Leah Rowe <leah@libreboot.org>
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
-index af3bd00d0..21d0cedb1 100644
+index eac3ea48d..6d67ba54f 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
-@@ -486,7 +486,7 @@ grub_dl_resolve_name (grub_dl_t mod, Elf_Ehdr *e)
+@@ -510,7 +510,7 @@ grub_dl_resolve_name (grub_dl_t mod, Elf_Ehdr *e)
s = grub_dl_find_section (e, ".modname");
if (!s)
@@ -30,5 +30,5 @@ index af3bd00d0..21d0cedb1 100644
mod->name = grub_strdup ((char *) e + s->sh_offset);
if (! mod->name)
--
-2.39.2
+2.47.3
diff --git a/config/grub/patches/0004-prefix/0003-don-t-print-empty-error-messages.patch b/config/grub/default/patches/0007-don-t-print-empty-error-messages.patch
index 25221c9c..67ae7d66 100644
--- a/config/grub/patches/0004-prefix/0003-don-t-print-empty-error-messages.patch
+++ b/config/grub/default/patches/0007-don-t-print-empty-error-messages.patch
@@ -1,7 +1,7 @@
-From e5b7ec81421487e71bcaf8b6b5a27f3649a62753 Mon Sep 17 00:00:00 2001
+From 557d3e583e6aaa887d7b3876c6980ba0e0e671a3 Mon Sep 17 00:00:00 2001
From: Leah Rowe <leah@libreboot.org>
Date: Sun, 5 Nov 2023 17:25:20 +0000
-Subject: [PATCH 1/1] don't print empty error messages
+Subject: [PATCH 07/10] don't print empty error messages
this is part two of the quest to kill the prefix
error message. after i disabled prefix-related
@@ -13,10 +13,10 @@ Signed-off-by: Leah Rowe <leah@libreboot.org>
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/grub-core/kern/err.c b/grub-core/kern/err.c
-index 53c734de7..7cac53983 100644
+index ba04b57fb..dab62646d 100644
--- a/grub-core/kern/err.c
+++ b/grub-core/kern/err.c
-@@ -107,7 +107,8 @@ grub_print_error (void)
+@@ -116,7 +116,8 @@ grub_print_error (void)
{
if (grub_errno != GRUB_ERR_NONE)
{
@@ -27,5 +27,5 @@ index 53c734de7..7cac53983 100644
}
}
--
-2.39.2
+2.47.3
diff --git a/config/grub/default/patches/0008-kern-coreboot-mmap-Map-to-reserved.patch b/config/grub/default/patches/0008-kern-coreboot-mmap-Map-to-reserved.patch
new file mode 100644
index 00000000..7ce1bf09
--- /dev/null
+++ b/config/grub/default/patches/0008-kern-coreboot-mmap-Map-to-reserved.patch
@@ -0,0 +1,37 @@
+From 101ea5afcfbe459e624df27c422f59b4ded07000 Mon Sep 17 00:00:00 2001
+From: Paul Menzel <pmenzel@molgen.mpg.de>
+Date: Mon, 17 May 2021 10:24:36 +0200
+Subject: [PATCH 08/10] kern/coreboot/mmap: Map to reserved
+
+https://git.savannah.gnu.org/cgit/grub.git/commit/?id=6de9ee86bf9ae50967413e6a73b5dfd13e5ffb50
+
+Signed-off-by: Paul Menzel <pmenzel@molgen.mpg.de>
+---
+ grub-core/kern/coreboot/mmap.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/kern/coreboot/mmap.c b/grub-core/kern/coreboot/mmap.c
+index caf8f7cef..2fc316e8d 100644
+--- a/grub-core/kern/coreboot/mmap.c
++++ b/grub-core/kern/coreboot/mmap.c
+@@ -59,7 +59,7 @@ iterate_linuxbios_table (grub_linuxbios_table_item_t table_item, void *data)
+ /* Multiboot mmaps match with the coreboot mmap
+ definition. Therefore, we can just pass type
+ through. */
+- mem_region->type,
++ (mem_region->type >= 13) ? 2 : mem_region->type,
+ ctx->hook_data))
+ return 1;
+ if (start < 0xa0000)
+@@ -81,7 +81,7 @@ iterate_linuxbios_table (grub_linuxbios_table_item_t table_item, void *data)
+ /* Multiboot mmaps match with the coreboot mmap
+ definition. Therefore, we can just pass type
+ through. */
+- mem_region->type,
++ (mem_region->type >= 13) ? 2 : mem_region->type,
+ ctx->hook_data))
+ return 1;
+ }
+--
+2.47.3
+
diff --git a/config/grub/default/patches/0009-Revert-configure-Check-linker-for-image-base-support.patch b/config/grub/default/patches/0009-Revert-configure-Check-linker-for-image-base-support.patch
new file mode 100644
index 00000000..9bb2563d
--- /dev/null
+++ b/config/grub/default/patches/0009-Revert-configure-Check-linker-for-image-base-support.patch
@@ -0,0 +1,70 @@
+From a56ceedd60bd6515ad3c84ec6aa4c3d66a8bac87 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Wed, 24 Dec 2025 01:42:17 +0100
+Subject: [PATCH 09/10] Revert "configure: Check linker for --image-base
+ support"
+
+This reverts commit 1a5417f39a0ccefcdd5440f2a67f84d2d2e26960.
+---
+ acinclude.m4 | 5 -----
+ configure.ac | 14 ++------------
+ 2 files changed, 2 insertions(+), 17 deletions(-)
+
+diff --git a/acinclude.m4 b/acinclude.m4
+index 70c1912f8..fa7840f09 100644
+--- a/acinclude.m4
++++ b/acinclude.m4
+@@ -79,11 +79,6 @@ AC_DEFUN([grub_PROG_OBJCOPY_ABSOLUTE],
+ [AC_MSG_CHECKING([whether ${TARGET_OBJCOPY} works for absolute addresses])
+ AC_CACHE_VAL(grub_cv_prog_objcopy_absolute,
+ [cat > conftest.c <<\EOF
+-asm (
+- ".globl start, _start, __start\n"
+- ".ifdef cmain; .set start = _start = __start = cmain\n.endif\n"
+- ".ifdef _cmain; .set start = _start = __start = _cmain\n.endif\n"
+-);
+ void cmain (void);
+ void
+ cmain (void)
+diff --git a/configure.ac b/configure.ac
+index d8ca1b7c1..041cfbab4 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1461,6 +1461,7 @@ elif test x$grub_cv_target_cc_link_format = x-mi386pe || test x$grub_cv_target_c
+ TARGET_IMG_LDSCRIPT='$(top_srcdir)'"/conf/i386-cygwin-img-ld.sc"
+ TARGET_IMG_LDFLAGS="-Wl,-T${TARGET_IMG_LDSCRIPT}"
+ TARGET_IMG_LDFLAGS_AC="-Wl,-T${srcdir}/conf/i386-cygwin-img-ld.sc"
++ TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"
+ TARGET_IMG_CFLAGS=
+ else
+ TARGET_APPLE_LINKER=0
+@@ -1468,6 +1469,7 @@ else
+ TARGET_IMG_LDSCRIPT=
+ TARGET_IMG_LDFLAGS='-Wl,-N'
+ TARGET_IMG_LDFLAGS_AC='-Wl,-N'
++ TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"
+ TARGET_IMG_CFLAGS=
+ fi
+
+@@ -1798,18 +1800,6 @@ grub_PROG_TARGET_CC
+ m4_ifndef([AX_CHECK_LINK_FLAG], [m4_fatal([autoconf-archive is missing. You must install it to generate the configure script.])])
+
+ if test "x$TARGET_APPLE_LINKER" != x1 ; then
+-AX_CHECK_LINK_FLAG([-Wl,--image-base,0x400000],
+- [TARGET_IMG_BASE_LDOPT="-Wl,--image-base"],
+- [TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"],
+- [],
+- [AC_LANG_SOURCE([
+-asm (".globl start; start:");
+-asm (".globl _start; _start:");
+-asm (".globl __start; __start:");
+-void __main (void);
+-void __main (void) {}
+-int main (void);
+- ])])
+ grub_PROG_OBJCOPY_ABSOLUTE
+ fi
+ grub_PROG_LD_BUILD_ID_NONE
+--
+2.47.3
+
diff --git a/config/grub/default/patches/0010-Revert-configure-Print-a-more-helpful-error-if-autoc.patch b/config/grub/default/patches/0010-Revert-configure-Print-a-more-helpful-error-if-autoc.patch
new file mode 100644
index 00000000..0c968993
--- /dev/null
+++ b/config/grub/default/patches/0010-Revert-configure-Print-a-more-helpful-error-if-autoc.patch
@@ -0,0 +1,30 @@
+From 66028b6bc149a25894fe5ca395b22804f389a18e Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Mon, 19 Jan 2026 15:27:23 +0000
+Subject: [PATCH 10/10] Revert "configure: Print a more helpful error if
+ autoconf-archive is not installed"
+
+This reverts commit ac042f3f58d33ce9cd5ff61750f06da1a1d7b0eb.
+---
+ configure.ac | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 041cfbab4..209c0fb11 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1794,11 +1794,6 @@ LIBS=""
+ # Defined in acinclude.m4.
+ grub_ASM_USCORE
+ grub_PROG_TARGET_CC
+-
+-# The error message produced by autoconf if autoconf-archive is not installed is
+-# quite misleading and not very helpful. So, try point people in the right direction.
+-m4_ifndef([AX_CHECK_LINK_FLAG], [m4_fatal([autoconf-archive is missing. You must install it to generate the configure script.])])
+-
+ if test "x$TARGET_APPLE_LINKER" != x1 ; then
+ grub_PROG_OBJCOPY_ABSOLUTE
+ fi
+--
+2.47.3
+
diff --git a/config/grub/default/target.cfg b/config/grub/default/target.cfg
new file mode 100644
index 00000000..2ce61fff
--- /dev/null
+++ b/config/grub/default/target.cfg
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+tree="default"
+rev="eaa3b8f0f90605a82c6bfda4c5c4b73c58eb81ac"
diff --git a/config/grub/keymap/colemak.gkb b/config/grub/keymap/colemak.gkb
deleted file mode 100644
index d357816b..00000000
--- a/config/grub/keymap/colemak.gkb
+++ /dev/null
Binary files differ
diff --git a/config/grub/keymap/deqwertz.gkb b/config/grub/keymap/deqwertz.gkb
deleted file mode 100644
index 4928d026..00000000
--- a/config/grub/keymap/deqwertz.gkb
+++ /dev/null
Binary files differ
diff --git a/config/grub/keymap/esqwerty.gkb b/config/grub/keymap/esqwerty.gkb
deleted file mode 100644
index 6ce76330..00000000
--- a/config/grub/keymap/esqwerty.gkb
+++ /dev/null
Binary files differ
diff --git a/config/grub/keymap/frazerty.gkb b/config/grub/keymap/frazerty.gkb
deleted file mode 100644
index f8455154..00000000
--- a/config/grub/keymap/frazerty.gkb
+++ /dev/null
Binary files differ
diff --git a/config/grub/keymap/frdvbepo.gkb b/config/grub/keymap/frdvbepo.gkb
deleted file mode 100644
index 20702607..00000000
--- a/config/grub/keymap/frdvbepo.gkb
+++ /dev/null
Binary files differ
diff --git a/config/grub/keymap/itqwerty.gkb b/config/grub/keymap/itqwerty.gkb
deleted file mode 100644
index db10a54c..00000000
--- a/config/grub/keymap/itqwerty.gkb
+++ /dev/null
Binary files differ
diff --git a/config/grub/keymap/svenska.gkb b/config/grub/keymap/svenska.gkb
deleted file mode 100644
index 75ca762d..00000000
--- a/config/grub/keymap/svenska.gkb
+++ /dev/null
Binary files differ
diff --git a/config/grub/keymap/trqwerty.gkb b/config/grub/keymap/trqwerty.gkb
deleted file mode 100644
index 452100d5..00000000
--- a/config/grub/keymap/trqwerty.gkb
+++ /dev/null
Binary files differ
diff --git a/config/grub/keymap/ukdvorak.gkb b/config/grub/keymap/ukdvorak.gkb
deleted file mode 100644
index 76b9e380..00000000
--- a/config/grub/keymap/ukdvorak.gkb
+++ /dev/null
Binary files differ
diff --git a/config/grub/keymap/ukqwerty.gkb b/config/grub/keymap/ukqwerty.gkb
deleted file mode 100644
index 5f513d85..00000000
--- a/config/grub/keymap/ukqwerty.gkb
+++ /dev/null
Binary files differ
diff --git a/config/grub/keymap/usdvorak.gkb b/config/grub/keymap/usdvorak.gkb
deleted file mode 100644
index ef88232c..00000000
--- a/config/grub/keymap/usdvorak.gkb
+++ /dev/null
Binary files differ
diff --git a/config/grub/keymap/usqwerty.gkb b/config/grub/keymap/usqwerty.gkb
deleted file mode 100644
index 0ea130f2..00000000
--- a/config/grub/keymap/usqwerty.gkb
+++ /dev/null
Binary files differ
diff --git a/config/grub/modules.list b/config/grub/modules.list
deleted file mode 100644
index f3768adb..00000000
--- a/config/grub/modules.list
+++ /dev/null
@@ -1,157 +0,0 @@
-# Install modules (installed, but not automatically loaded)
-grub_install_modules=" \
-hexdump \
-newc \
-odc \
-usbserial_common \
-usbserial_ftdi \
-usbserial_pl2303 \
-usbserial_usbdebug \
-video_colors \
-"
-
-# Modules (and always loaded)
-grub_modules=" \
-acpi \
-ahci \
-at_keyboard \
-all_video \
-ata \
-bitmap \
-bitmap_scale \
-boot \
-bsd \
-btrfs \
-cat \
-cbfs \
-cbls \
-cbmemc \
-cbtime \
-chain \
-configfile \
-cpio \
-cpio_be \
-crc64 \
-crypto \
-cryptodisk \
-diskfilter \
-echo \
-xhci \
-ehci \
-eval \
-exfat \
-elf \
-ext2 \
-fat \
-f2fs \
-gcry_arcfour \
-gcry_blowfish \
-gcry_camellia \
-gcry_cast5 \
-gcry_crc \
-gcry_des \
-gcry_dsa \
-gcry_idea \
-gcry_md4 \
-gcry_md5 \
-gcry_rfc2268 \
-gcry_rijndael \
-gcry_rmd160 \
-gcry_rsa \
-gcry_seed \
-gcry_serpent \
-gcry_sha1 \
-gcry_sha256 \
-gcry_sha512 \
-gcry_tiger \
-gcry_twofish \
-gcry_whirlpool \
-geli \
-gfxmenu \
-gfxterm_background \
-gfxterm_menu \
-gzio \
-hashsum \
-halt \
-help \
-iorw \
-iso9660 \
-jpeg \
-json \
-keylayouts \
-keystatus \
-linux \
-linux16 \
-loadenv \
-loopback \
-ls \
-lsacpi \
-lsmmap \
-lspci \
-luks \
-luks2 \
-argon2 \
-lvm \
-lzopio \
-mdraid09 \
-mdraid09_be \
-mdraid1x \
-memdisk \
-memrw \
-minicmd \
-mmap \
-multiboot \
-multiboot2 \
-nativedisk \
-normal \
-ntfs \
-ohci \
-part_bsd \
-part_dfly \
-part_gpt \
-part_msdos \
-password \
-password_pbkdf2 \
-pata \
-pbkdf2 \
-pcidump \
-pgp \
-play \
-png \
-procfs \
-raid5rec \
-raid6rec \
-read \
-reboot \
-regexp \
-romfs \
-scsi \
-search \
-search_fs_file \
-search_fs_uuid \
-search_label \
-serial \
-syslinuxcfg \
-setjmp \
-setpci \
-spkmodem \
-squash4 \
-sleep \
-tar \
-test \
-true \
-uhci \
-udf \
-ufs1 \
-ufs1_be \
-ufs2 \
-usb \
-usb_keyboard \
-usbms \
-xfs \
-xzio \
-zfs \
-zfscrypt \
-zfsinfo \
-zstd \
-"
diff --git a/config/grub/nvme/config/payload b/config/grub/nvme/config/payload
new file mode 100644
index 00000000..4f3de36e
--- /dev/null
+++ b/config/grub/nvme/config/payload
@@ -0,0 +1,320 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+# Copyright (C) 2014-2016,2020-2021,2023-2025 Leah Rowe <leah@libreboot.org>
+# Copyright (C) 2015 Klemens Nanni <contact@autoboot.org>
+
+set prefix=(memdisk)/boot/grub
+
+insmod at_keyboard
+insmod usb_keyboard
+insmod nativedisk
+insmod ehci
+insmod ohci
+insmod uhci
+insmod usb
+insmod usbms
+insmod regexp
+
+terminal_input --append at_keyboard
+terminal_input --append usb_keyboard
+terminal_output --append cbmemc
+
+# User interface overrides wherever "keystatus" is supported
+# Keep SHIFT key pressed before powering on to disable graphics
+if keystatus --shift; then
+ terminal_output --append vga_text
+else
+ gfxpayload=keep
+ terminal_output --append gfxterm
+
+ for dt in cbfsdisk memdisk; do
+ for it in png jpg; do
+ if [ -f (${dt})/background.${it} ]; then
+ insmod ${it}
+ background_image (${dt})/background.${it}
+ fi
+ done
+ done
+fi
+
+# Keep CTRL pressed to enable default serial terminal (COM1 or the like)
+if keystatus --ctrl; then
+ serial
+ terminal_input --append serial
+ terminal_output --append serial
+fi
+
+# Keep ALT pressed to enable spkmodem
+if keystatus --alt; then
+ terminal_output --append spkmodem
+fi
+
+
+set default="0"
+if [ -f (cbfsdisk)/timeout.cfg ]; then
+ source (cbfsdisk)/timeout.cfg
+else
+ set timeout=8
+fi
+set grub_scan_disk="nvme ahci ata"
+if [ -f (cbfsdisk)/scan.cfg ]; then
+ source (cbfsdisk)/scan.cfg
+fi
+
+if [ -f (cbfsdisk)/keymap.gkb ]; then
+ keymap (cbfsdisk)/keymap.gkb
+fi
+
+function really_try_user_config {
+ set root="${1}"
+
+ if [ -f /"${2}"/grub.cfg ]; then
+ unset superusers
+ configfile /"${2}"/grub.cfg
+ fi
+}
+
+function try_user_config {
+ # The @/... entries are for cases where the BTRFS filesystem is being used
+ for dir in grub boot/grub @/grub @/boot/grub grub2 boot/grub2 @/grub2 @/boot/grub2 boot @/boot; do
+ really_try_user_config "${1}" "${dir}"
+ done
+ for dir in ubuntu debian redhat; do
+ really_try_user_config "${1}" "EFI/${dir}"
+ done
+}
+function search_grub {
+ echo -n "Attempting to load grub.cfg from '${1}' devices"
+ for i in 0 1 2 3 4 5 6 7 8; do
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12; do
+ if [ "${1}" != "nvme" ]; then
+ try_user_config "(${1}${i},${part})"
+ else
+ # TODO: do we care about other namesapces
+ try_user_config "(nvme${i}n1,${part})"
+ fi
+ done
+ if [ "${1}" != "nvme" ]; then
+ # raw devices e.g. (ahci0) instead of (ahci0,1)
+ try_user_config "(${1}${i})"
+ else
+ # TODO: do we care about other namesapces
+ try_user_config "(nvme${i}n1)"
+ fi
+ done
+ echo # Insert newline
+}
+
+function try_isolinux_config {
+ set root="${1}"
+ for dir in '' /boot /EFI /@ /@/boot; do
+ if [ -f "${dir}"/isolinux/isolinux.cfg ]; then
+ syslinux_configfile -i "${dir}"/isolinux/isolinux.cfg
+ elif [ -f "${dir}"/syslinux/syslinux.cfg ]; then
+ syslinux_configfile -s "${dir}"/syslinux/syslinux.cfg
+ elif [ -f "${dir}"/syslinux/extlinux.conf ]; then
+ syslinux_configfile -s "${dir}"/syslinux/extlinux.conf
+ elif [ -f "${dir}"/extlinux/extlinux.conf ]; then
+ syslinux_configfile -s "${dir}"/extlinux/extlinux.conf
+ fi
+ done
+}
+function search_isolinux {
+ echo "\nAttempting to parse iso/sys/extlinux config from '${1}' devices"
+ for i in 0 1 2 3 4 5 6 7 8; do
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12; do
+ if [ "${1}" != "nvme" ]; then
+ try_isolinux_config "(${1}${i},${part})"
+ else
+ # TODO: see above
+ try_isolinux_config "(nvme${i}n1,${part})"
+ fi
+ done
+ if [ "${1}" != "nvme" ]; then
+ # raw devices e.g. (usb0) instead of (usb0,1)
+ try_isolinux_config "(${1}${i})"
+ else
+ # TODO: do we care about other namesapces
+ try_isolinux_config "(nvme${i}n1)"
+ fi
+ done
+ echo # Insert newline
+}
+function try_bootcfg {
+ try_user_config "${1}"
+ try_isolinux_config "${1}"
+}
+function search_bootcfg {
+ search_grub "${1}"
+ search_isolinux "${1}"
+}
+menuentry 'Load Operating System (incl. fully encrypted disks) [o]' --hotkey='o' {
+
+ for grub_disk in ${grub_scan_disk}; do
+ search_bootcfg ${grub_disk}
+ done
+
+ # grub device enumeration is very slow, so checks are hardcoded
+
+ raidvol="md/0 md/1 md/2 md/3 md/4 md/5 md/6 md/7 md/8 md/9"
+
+ # in practise, doing multiple redundant checks is perfectly fast
+ # TODO: optimize grub itself, and use */? here for everything
+
+ for vol in ${raidvol} ; do
+ try_bootcfg "${vol}"
+ done
+
+ unset bootdev
+ for grub_disk in ${grub_scan_disk}; do
+ for i in 0 1 2 3 4 5 6 7 8; do
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12; do
+ if [ "${grub_disk}" = "ahci" ]; then
+ bootdev="${bootdev} (ahci${i},${part})"
+ elif [ "${grub_disk}" = "ata" ]; then
+ bootdev="${bootdev} (ata${i},${part})"
+ elif [ "${grub_disk}" = "nvme" ]; then
+ # TODO: do we care about other namesapces
+ bootdev="${bootdev} (nvme${i}n1,${part})"
+ fi
+ done
+ done
+ done
+
+ set pager=0
+ echo -n "Attempting to unlock encrypted volumes"
+ for dev in ${bootdev} ${raidvol}; do
+ if cryptomount "${dev}" ; then break ; fi
+ done
+ set pager=1
+ echo
+
+ search_bootcfg crypto
+
+ lvmvol=""
+
+ # after cryptomount, lvm volumes might be available
+ # using * is slow on some machines, but we use it here,
+ # just once. in so doing, we find every lvm volume
+ for vol in (*); do
+ if regexp ^\\(lvm/ $vol; then
+ lvmvol="${lvmvol} ${vol}"
+ try_bootcfg "${vol}"
+ fi
+ done
+
+ # user might have put luks inside lvm
+ set pager=0
+ echo "Attempting to unlock encrypted LVMs"
+ for vol in ${lvmvol}; do
+ cryptomount "$vol"
+ done
+ set pager=1
+ echo
+
+ search_bootcfg crypto
+
+ true # Prevent pager requiring to accept each line instead of whole screen
+}
+
+menuentry 'Search for GRUB/SYSLINUX/EXTLINUX/ISOLINUX on USB [s]' --hotkey='s' {
+ search_bootcfg usb
+}
+menuentry 'Search for GRUB/SYSLINUX/EXTLINUX/ISOLINUX on AHCI [a]' --hotkey='a' {
+ search_bootcfg ahci
+}
+menuentry 'Search for GRUB/SYSLINUX/EXTLINUX/ISOLINUX on ATA/IDE [d]' --hotkey='d' {
+ search_bootcfg ata
+}
+menuentry 'Search for GRUB/SYSLINUX/EXTLINUX/ISOLINUX on NVMe [e]' --hotkey='e' {
+ search_bootcfg nvme
+}
+if [ -f (cbfsdisk)/grub.cfg ]; then
+menuentry 'Load configuration (grub.cfg) in CBFS [t]' --hotkey='t' {
+ set root='(cbfsdisk)'
+ if [ -f /grub.cfg ]; then
+ configfile /grub.cfg
+ fi
+}
+fi
+if [ -f (cbfsdisk)/grubtest.cfg ]; then
+menuentry 'Load test configuration (grubtest.cfg) inside of CBFS [t]' --hotkey='t' {
+ set root='(cbfsdisk)'
+ if [ -f /grubtest.cfg ]; then
+ configfile /grubtest.cfg
+ fi
+}
+fi
+if [ -f (cbfsdisk)/u-boot ]; then
+menuentry 'U-Boot i386 payload (experimental) [u]' --hotkey='u' {
+ set root='cbfsdisk'
+ chainloader /u-boot
+}
+fi
+if [ -f (cbfsdisk)/seabios.elf ]; then
+if [ -f (cbfsdisk)/img/u-boot ]; then
+menuentry 'Load SeaBIOS (U-Boot UEFI available in the ESC menu) [b]' --hotkey='b' {
+ set root='cbfsdisk'
+ chainloader /seabios.elf
+}
+else
+menuentry 'Load SeaBIOS [b]' --hotkey='b' {
+ set root='cbfsdisk'
+ chainloader /seabios.elf
+}
+fi
+fi
+if [ -f (cbfsdisk)/img/grub2 ]; then
+if [ -f (cbfsdisk)/img/u-boot ]; then
+menuentry 'Return to SeaBIOS (U-Boot UEFI available in the ESC menu) [b]' --hotkey='b' {
+ set root='cbfsdisk'
+ chainloader /fallback/payload
+}
+else
+menuentry 'Return to SeaBIOS [b]' --hotkey='b' {
+ set root='cbfsdisk'
+ chainloader /fallback/payload
+}
+fi
+fi
+menuentry 'Poweroff [p]' --hotkey='p' {
+ halt
+}
+menuentry 'Reboot [r]' --hotkey='r' {
+ reboot
+}
+if [ -f (cbfsdisk)/img/memtest ]; then
+menuentry 'Load MemTest86+ [m]' --hotkey='m' {
+ set root='cbfsdisk'
+ chainloader /img/memtest
+}
+fi
+
+submenu 'Other [z]' --hotkey='z' {
+ menuentry 'Enable default serial terminal [s]' --hotkey='s' {
+ serial
+ terminal_input --append serial
+ terminal_output --append serial
+ }
+
+ menuentry 'Disable default serial terminal' {
+ terminal_input --remove serial
+ terminal_output --remove serial
+ }
+
+ menuentry 'Enable gfxterm' {
+ terminal_output --append gfxterm
+ terminal_output --remove vga_text
+ }
+ menuentry 'Disable gfxterm [g]' --hotkey='g' {
+ terminal_output --remove gfxterm
+ terminal_output --append vga_text
+ }
+
+ menuentry 'Enable spkmodem [a]' --hotkey='a' {
+ terminal_output --append spkmodem
+ }
+
+ menuentry 'Disable spkmodem [z]' --hotkey='z' {
+ terminal_output --remove spkmodem
+ }
+}
diff --git a/config/grub/nvme/patches/0001-mitigate-grub-s-missing-characters-for-borders-arrow.patch b/config/grub/nvme/patches/0001-mitigate-grub-s-missing-characters-for-borders-arrow.patch
new file mode 100644
index 00000000..41194e98
--- /dev/null
+++ b/config/grub/nvme/patches/0001-mitigate-grub-s-missing-characters-for-borders-arrow.patch
@@ -0,0 +1,90 @@
+From 2c953c9160cbed357437891cf1790aeb1c2bd0f5 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Sun, 31 Oct 2021 03:47:05 +0000
+Subject: [PATCH 01/10] mitigate grub's missing characters for borders/arrow
+ characters
+
+This cleans up the display on the main screen in GRUB.
+
+Just don't draw a border, at all.
+---
+ grub-core/normal/menu_text.c | 49 ++----------------------------------
+ 1 file changed, 2 insertions(+), 47 deletions(-)
+
+diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
+index 9c383e64a..8ec1dd1e8 100644
+--- a/grub-core/normal/menu_text.c
++++ b/grub-core/normal/menu_text.c
+@@ -108,47 +108,6 @@ grub_print_message_indented (const char *msg, int margin_left, int margin_right,
+ grub_print_message_indented_real (msg, margin_left, margin_right, term, 0);
+ }
+
+-static void
+-draw_border (struct grub_term_output *term, const struct grub_term_screen_geometry *geo)
+-{
+- int i;
+-
+- grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
+-
+- grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1,
+- geo->first_entry_y - 1 });
+- grub_putcode (GRUB_UNICODE_CORNER_UL, term);
+- for (i = 0; i < geo->entry_width + 1; i++)
+- grub_putcode (GRUB_UNICODE_HLINE, term);
+- grub_putcode (GRUB_UNICODE_CORNER_UR, term);
+-
+- for (i = 0; i < geo->num_entries; i++)
+- {
+- grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1,
+- geo->first_entry_y + i });
+- grub_putcode (GRUB_UNICODE_VLINE, term);
+- grub_term_gotoxy (term,
+- (struct grub_term_coordinate) { geo->first_entry_x + geo->entry_width + 1,
+- geo->first_entry_y + i });
+- grub_putcode (GRUB_UNICODE_VLINE, term);
+- }
+-
+- grub_term_gotoxy (term,
+- (struct grub_term_coordinate) { geo->first_entry_x - 1,
+- geo->first_entry_y - 1 + geo->num_entries + 1 });
+- grub_putcode (GRUB_UNICODE_CORNER_LL, term);
+- for (i = 0; i < geo->entry_width + 1; i++)
+- grub_putcode (GRUB_UNICODE_HLINE, term);
+- grub_putcode (GRUB_UNICODE_CORNER_LR, term);
+-
+- grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
+-
+- grub_term_gotoxy (term,
+- (struct grub_term_coordinate) { geo->first_entry_x - 1,
+- (geo->first_entry_y - 1 + geo->num_entries
+- + GRUB_TERM_MARGIN + 1) });
+-}
+-
+ static int
+ print_message (int nested, int edit, struct grub_term_output *term, int dry_run)
+ {
+@@ -167,10 +126,8 @@ command-line or ESC to discard edits and return to the GRUB menu."),
+ {
+ char *msg_translated;
+
+- msg_translated = grub_xasprintf (_("Use the %C and %C keys to select which "
+- "entry is highlighted."),
+- GRUB_UNICODE_UPARROW,
+- GRUB_UNICODE_DOWNARROW);
++ msg_translated = grub_xasprintf (_("Use the arrow keys to select which "
++ "entry is highlighted."));
+ if (!msg_translated)
+ return 0;
+ ret += grub_print_message_indented_real (msg_translated, STANDARD_MARGIN,
+@@ -413,8 +370,6 @@ grub_menu_init_page (int nested, int edit,
+
+ grub_term_normal_color = grub_color_menu_normal;
+ grub_term_highlight_color = grub_color_menu_highlight;
+- if (geo->border)
+- draw_border (term, geo);
+ grub_term_normal_color = old_color_normal;
+ grub_term_highlight_color = old_color_highlight;
+ geo->timeout_y = geo->first_entry_y + geo->num_entries
+--
+2.47.3
+
diff --git a/config/grub/nvme/patches/0002-say-the-name-libreboot-in-the-grub-menu.patch b/config/grub/nvme/patches/0002-say-the-name-libreboot-in-the-grub-menu.patch
new file mode 100644
index 00000000..83e95902
--- /dev/null
+++ b/config/grub/nvme/patches/0002-say-the-name-libreboot-in-the-grub-menu.patch
@@ -0,0 +1,25 @@
+From 71623385f90580b2138110cf00ee66b7a05abcf6 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Sat, 19 Nov 2022 16:30:24 +0000
+Subject: [PATCH 02/10] say the name libreboot, in the grub menu
+
+---
+ grub-core/normal/main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index de9a3f961..bed502cde 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -215,7 +215,7 @@ grub_normal_init_page (struct grub_term_output *term,
+
+ grub_term_cls (term);
+
+- msg_formatted = grub_xasprintf (_("GNU GRUB version %s"), PACKAGE_VERSION);
++ msg_formatted = grub_xasprintf (_("Libreboot 26.01 RC4 Magnanimous Max (GRUB menu): https://libreboot.org/"));
+ if (!msg_formatted)
+ return;
+
+--
+2.47.3
+
diff --git a/config/grub/nvme/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch b/config/grub/nvme/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch
new file mode 100644
index 00000000..ab26c6b2
--- /dev/null
+++ b/config/grub/nvme/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch
@@ -0,0 +1,107 @@
+From a21c5e997d6247d713717745b5f7bd380b98fce1 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Mon, 30 Oct 2023 22:19:21 +0000
+Subject: [PATCH 03/10] at_keyboard coreboot: force scancodes2+translate
+
+Scan code set 2 with translation should be assumed in
+every case, as the default starting position.
+
+However, GRUB is trying to detect and use other modes
+such as set 2 without translation, or set 1 without
+translation from set 2; it also detects no-mode and
+assumes mode 1, on really old keyboards.
+
+The current behaviour has been retained, for everything
+except GRUB_MACHINE_COREBOOT; for the latter, scan code
+set 2 with translation is hardcoded, and forced in code.
+
+This is required to make keyboard initialisation work on
+the MEC5035 EC used by the Dell Latitude E6400, when
+running GRUB as a coreboot payload on that laptop. The
+EC reports scancode set 2 with translation when probed,
+but actually only outputs scancode set 1.
+
+Since GRUB is attempting to use it without translation,
+and since the machine reports set 2 with translation,
+but only ever outputs set 1 scancodes, this results in
+wrong keypresses for every key.
+
+This fix fixed that, by forcing set 2 with translation,
+treating it as set 1, but only on coreboot. This is the
+same behaviour used in GNU+Linux systems and SeaBIOS.
+With this change, GRUB keyboard initialisation now works
+just fine on those machines.
+
+This has *also* been tested on other coreboot machines
+running GRUB; several HP EliteBooks, ThinkPads and
+Dell Precision T1650. All seems to work just fine.
+
+Signed-off-by: Leah Rowe <leah@libreboot.org>
+---
+ grub-core/term/at_keyboard.c | 20 ++++++++++++++++++--
+ 1 file changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c
+index f8a129eb7..8207225c2 100644
+--- a/grub-core/term/at_keyboard.c
++++ b/grub-core/term/at_keyboard.c
+@@ -138,6 +138,7 @@ write_mode (int mode)
+ return (i != GRUB_AT_TRIES);
+ }
+
++#if !defined (GRUB_MACHINE_COREBOOT)
+ static int
+ query_mode (void)
+ {
+@@ -161,10 +162,12 @@ query_mode (void)
+ return 3;
+ return 0;
+ }
++#endif
+
+ static void
+ set_scancodes (void)
+ {
++#if !defined (GRUB_MACHINE_COREBOOT)
+ /* You must have visited computer museum. Keyboard without scancode set
+ knowledge. Assume XT. */
+ if (!grub_keyboard_orig_set)
+@@ -173,20 +176,33 @@ set_scancodes (void)
+ ps2_state.current_set = 1;
+ return;
+ }
++#endif
+
+ #if !USE_SCANCODE_SET
+ ps2_state.current_set = 1;
+ return;
+-#else
++#endif
+
++#if defined (GRUB_MACHINE_COREBOOT)
++ /* enable translation */
++ grub_keyboard_controller_write (grub_keyboard_controller_orig
++ & ~KEYBOARD_AT_DISABLE);
++#else
++ /* if not coreboot, disable translation and try mode 2 first, before 1 */
+ grub_keyboard_controller_write (grub_keyboard_controller_orig
+ & ~KEYBOARD_AT_TRANSLATE
+ & ~KEYBOARD_AT_DISABLE);
++#endif
+
+ keyboard_controller_wait_until_ready ();
+ grub_outb (KEYBOARD_COMMAND_ENABLE, KEYBOARD_REG_DATA);
+-
+ write_mode (2);
++
++#if defined (GRUB_MACHINE_COREBOOT)
++ /* mode 2 with translation, so make grub treat as set 1 */
++ ps2_state.current_set = 1;
++#else
++ /* if not coreboot, translation isn't set; test 2 and fall back to 1 */
+ ps2_state.current_set = query_mode ();
+ grub_dprintf ("atkeyb", "returned set %d\n", ps2_state.current_set);
+ if (ps2_state.current_set == 2)
+--
+2.47.3
+
diff --git a/config/grub/nvme/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch b/config/grub/nvme/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch
new file mode 100644
index 00000000..68dfb2f7
--- /dev/null
+++ b/config/grub/nvme/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch
@@ -0,0 +1,38 @@
+From 062379b1cd5a4f99324c625fb371c29eb00ad4a2 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Tue, 31 Oct 2023 10:33:28 +0000
+Subject: [PATCH 04/10] keylayouts: don't print "Unknown key" message
+
+on keyboards with stuck keys, this results in GRUB just
+spewing it repeatedly, preventing use of GRUB.
+
+in such cases, it's still possible to use the keyboard,
+and we should let the user at least boot.
+
+it often appears when people plug in faulty usb keyboards,
+but can appear for laptop keyboards too; one of my e6400
+has stuck keys.
+
+with this patch, grub should be a bit more reliable in
+terms of user experience, when the keyboard is faulty.
+
+Signed-off-by: Leah Rowe <leah@libreboot.org>
+---
+ grub-core/commands/keylayouts.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/grub-core/commands/keylayouts.c b/grub-core/commands/keylayouts.c
+index aa3ba34f2..445fa0601 100644
+--- a/grub-core/commands/keylayouts.c
++++ b/grub-core/commands/keylayouts.c
+@@ -174,7 +174,6 @@ grub_term_map_key (grub_keyboard_key_t code, int status)
+ key = map_key_core (code, status, &alt_gr_consumed);
+
+ if (key == 0 || key == GRUB_TERM_SHIFT) {
+- grub_printf ("Unknown key 0x%x detected\n", code);
+ return GRUB_TERM_NO_KEY;
+ }
+
+--
+2.47.3
+
diff --git a/config/grub/nvme/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch b/config/grub/nvme/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch
new file mode 100644
index 00000000..53dbdd87
--- /dev/null
+++ b/config/grub/nvme/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch
@@ -0,0 +1,102 @@
+From e77ca67985c1bef8afd93587232da3d298a8dd51 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Sun, 5 Nov 2023 16:14:58 +0000
+Subject: [PATCH 05/10] don't print missing prefix errors on the screen
+
+we do actually set the prefix. this patch modifies
+grub to still set grub_errno and return accordingly,
+so the behaviour is otherwise identical, but it will
+no longer print a warning message on the screen.
+
+Signed-off-by: Leah Rowe <leah@libreboot.org>
+---
+ grub-core/commands/keylayouts.c | 2 +-
+ grub-core/commands/loadenv.c | 2 +-
+ grub-core/commands/nativedisk.c | 2 +-
+ grub-core/efiemu/main.c | 3 +--
+ grub-core/font/font.c | 2 +-
+ grub-core/kern/dl.c | 2 +-
+ 6 files changed, 6 insertions(+), 7 deletions(-)
+
+diff --git a/grub-core/commands/keylayouts.c b/grub-core/commands/keylayouts.c
+index 445fa0601..00bcf7025 100644
+--- a/grub-core/commands/keylayouts.c
++++ b/grub-core/commands/keylayouts.c
+@@ -211,7 +211,7 @@ grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)),
+ {
+ const char *prefix = grub_env_get ("prefix");
+ if (!prefix)
+- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("variable `%s' isn't set"), "prefix");
++ return (grub_errno = GRUB_ERR_BAD_ARGUMENT);
+ filename = grub_xasprintf ("%s/layouts/%s.gkb", prefix, argv[0]);
+ if (!filename)
+ return grub_errno;
+diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c
+index 166445849..699b39bfa 100644
+--- a/grub-core/commands/loadenv.c
++++ b/grub-core/commands/loadenv.c
+@@ -58,7 +58,7 @@ open_envblk_file (char *filename,
+ prefix = grub_env_get ("prefix");
+ if (! prefix)
+ {
+- grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix");
++ grub_errno = GRUB_ERR_FILE_NOT_FOUND;
+ return 0;
+ }
+
+diff --git a/grub-core/commands/nativedisk.c b/grub-core/commands/nativedisk.c
+index 580c8d3b0..6806bff9c 100644
+--- a/grub-core/commands/nativedisk.c
++++ b/grub-core/commands/nativedisk.c
+@@ -186,7 +186,7 @@ grub_cmd_nativedisk (grub_command_t cmd __attribute__ ((unused)),
+ prefix = grub_env_get ("prefix");
+
+ if (! prefix)
+- return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix");
++ return (grub_errno = GRUB_ERR_FILE_NOT_FOUND);
+
+ if (prefix)
+ path_prefix = (prefix[0] == '(') ? grub_strchr (prefix, ')') : NULL;
+diff --git a/grub-core/efiemu/main.c b/grub-core/efiemu/main.c
+index e7037f4ed..e5d4dbff1 100644
+--- a/grub-core/efiemu/main.c
++++ b/grub-core/efiemu/main.c
+@@ -231,8 +231,7 @@ grub_efiemu_autocore (void)
+ prefix = grub_env_get ("prefix");
+
+ if (! prefix)
+- return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+- N_("variable `%s' isn't set"), "prefix");
++ return (grub_errno = GRUB_ERR_FILE_NOT_FOUND);
+
+ suffix = grub_efiemu_get_default_core_name ();
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index 18de52562..2a0fea6c8 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -461,7 +461,7 @@ grub_font_load (const char *filename)
+
+ if (!prefix)
+ {
+- grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix");
++ grub_errno = GRUB_ERR_FILE_NOT_FOUND;
+ goto fail;
+ }
+ file = try_open_from_prefix (prefix, filename);
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index de8c3aa8d..eac3ea48d 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -880,7 +880,7 @@ grub_dl_load (const char *name)
+ return 0;
+
+ if (! grub_dl_dir) {
+- grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix");
++ grub_errno = GRUB_ERR_FILE_NOT_FOUND;
+ return 0;
+ }
+
+--
+2.47.3
+
diff --git a/config/grub/nvme/patches/0006-don-t-print-error-if-module-not-found.patch b/config/grub/nvme/patches/0006-don-t-print-error-if-module-not-found.patch
new file mode 100644
index 00000000..3851c7fe
--- /dev/null
+++ b/config/grub/nvme/patches/0006-don-t-print-error-if-module-not-found.patch
@@ -0,0 +1,34 @@
+From 9412b6be27bce2d79f154761387d35f44184c069 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Sun, 5 Nov 2023 16:36:22 +0000
+Subject: [PATCH 06/10] don't print error if module not found
+
+still set grub_errno accordingly, and otherwise
+behave the same. in libreboot, we remove a lot of
+modules but then rely on loading a grub.cfg
+provided by a distro; in almost all cases that works,
+but also in almost all cases, that will try to load
+a module we don't actually need, but then it prints
+a message. this can annoy some users, so silence it.
+
+Signed-off-by: Leah Rowe <leah@libreboot.org>
+---
+ grub-core/kern/dl.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index eac3ea48d..6d67ba54f 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -510,7 +510,7 @@ grub_dl_resolve_name (grub_dl_t mod, Elf_Ehdr *e)
+
+ s = grub_dl_find_section (e, ".modname");
+ if (!s)
+- return grub_error (GRUB_ERR_BAD_MODULE, "no module name found");
++ return (grub_errno = GRUB_ERR_BAD_MODULE);
+
+ mod->name = grub_strdup ((char *) e + s->sh_offset);
+ if (! mod->name)
+--
+2.47.3
+
diff --git a/config/grub/nvme/patches/0007-don-t-print-empty-error-messages.patch b/config/grub/nvme/patches/0007-don-t-print-empty-error-messages.patch
new file mode 100644
index 00000000..aa42420f
--- /dev/null
+++ b/config/grub/nvme/patches/0007-don-t-print-empty-error-messages.patch
@@ -0,0 +1,31 @@
+From 2ad50d482cae148df832ccd68f90b8111684ecde Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Sun, 5 Nov 2023 17:25:20 +0000
+Subject: [PATCH 07/10] don't print empty error messages
+
+this is part two of the quest to kill the prefix
+error message. after i disabled prefix-related
+messages, it still printed "error: ." on screen.
+
+Signed-off-by: Leah Rowe <leah@libreboot.org>
+---
+ grub-core/kern/err.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/err.c b/grub-core/kern/err.c
+index ba04b57fb..dab62646d 100644
+--- a/grub-core/kern/err.c
++++ b/grub-core/kern/err.c
+@@ -116,7 +116,8 @@ grub_print_error (void)
+ {
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+- grub_err_printf (_("error: %s.\n"), grub_errmsg);
++ if (grub_strlen(grub_errmsg) > 0)
++ grub_err_printf (_("error: %s.\n"), grub_errmsg);
+ grub_err_printed_errors++;
+ }
+ }
+--
+2.47.3
+
diff --git a/config/grub/nvme/patches/0008-Add-native-NVMe-driver-based-on-SeaBIOS.patch b/config/grub/nvme/patches/0008-Add-native-NVMe-driver-based-on-SeaBIOS.patch
new file mode 100644
index 00000000..e0b40f2f
--- /dev/null
+++ b/config/grub/nvme/patches/0008-Add-native-NVMe-driver-based-on-SeaBIOS.patch
@@ -0,0 +1,1074 @@
+From 202e20bef3766480aee18e679b9306387be615dc Mon Sep 17 00:00:00 2001
+From: Mate Kukri <km@mkukri.xyz>
+Date: Mon, 20 May 2024 11:43:35 +0100
+Subject: [PATCH 08/10] Add native NVMe driver based on SeaBIOS
+
+Tested to successfully boot Debian on QEMU and OptiPlex 3050.
+
+Signed-off-by: Mate Kukri <km@mkukri.xyz>
+---
+ Makefile.am | 2 +-
+ grub-core/Makefile.core.def | 6 +
+ grub-core/commands/nativedisk.c | 1 +
+ grub-core/disk/nvme-int.h | 208 +++++++++
+ grub-core/disk/nvme.c | 781 ++++++++++++++++++++++++++++++++
+ include/grub/disk.h | 1 +
+ 6 files changed, 998 insertions(+), 1 deletion(-)
+ create mode 100644 grub-core/disk/nvme-int.h
+ create mode 100644 grub-core/disk/nvme.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 43635d5ff..2c86dbbf6 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -434,7 +434,7 @@ if COND_i386_coreboot
+ FS_PAYLOAD_MODULES ?= $(shell cat grub-core/fs.lst)
+ default_payload.elf: grub-mkstandalone grub-mkimage FORCE
+ test -f $@ && rm $@ || true
+- pkgdatadir=. ./grub-mkstandalone --grub-mkimage=./grub-mkimage -O i386-coreboot -o $@ --modules='ahci pata ehci uhci ohci usb_keyboard usbms part_msdos ext2 fat at_keyboard part_gpt usbserial_usbdebug cbfs' --install-modules='ls linux search configfile normal cbtime cbls memrw iorw minicmd lsmmap lspci halt reboot hexdump pcidump regexp setpci lsacpi chain test serial multiboot cbmemc linux16 gzio echo help syslinuxcfg xnu $(FS_PAYLOAD_MODULES) password_pbkdf2 $(EXTRA_PAYLOAD_MODULES)' --fonts= --themes= --locales= -d grub-core/ /boot/grub/grub.cfg=$(srcdir)/coreboot.cfg
++ pkgdatadir=. ./grub-mkstandalone --grub-mkimage=./grub-mkimage -O i386-coreboot -o $@ --modules='ahci pata nvme ehci uhci ohci usb_keyboard usbms part_msdos ext2 fat at_keyboard part_gpt usbserial_usbdebug cbfs' --install-modules='ls linux search configfile normal cbtime cbls memrw iorw minicmd lsmmap lspci halt reboot hexdump pcidump regexp setpci lsacpi chain test serial multiboot cbmemc linux16 gzio echo help syslinuxcfg xnu $(FS_PAYLOAD_MODULES) password_pbkdf2 $(EXTRA_PAYLOAD_MODULES)' --fonts= --themes= --locales= -d grub-core/ /boot/grub/grub.cfg=$(srcdir)/coreboot.cfg
+ endif
+
+ endif
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 0cf155128..176d35364 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -2773,3 +2773,9 @@ module = {
+ cflags = '-Wno-uninitialized';
+ cppflags = '-I$(srcdir)/lib/libtasn1-grub -I$(srcdir)/tests/asn1/';
+ };
++
++module = {
++ name = nvme;
++ common = disk/nvme.c;
++ enable = pci;
++};
+diff --git a/grub-core/commands/nativedisk.c b/grub-core/commands/nativedisk.c
+index 6806bff9c..fd68a513e 100644
+--- a/grub-core/commands/nativedisk.c
++++ b/grub-core/commands/nativedisk.c
+@@ -78,6 +78,7 @@ get_uuid (const char *name, char **uuid, int getnative)
+ case GRUB_DISK_DEVICE_ATA_ID:
+ case GRUB_DISK_DEVICE_SCSI_ID:
+ case GRUB_DISK_DEVICE_XEN:
++ case GRUB_DISK_DEVICE_NVME_ID:
+ if (getnative)
+ break;
+ /* FALLTHROUGH */
+diff --git a/grub-core/disk/nvme-int.h b/grub-core/disk/nvme-int.h
+new file mode 100644
+index 000000000..1295b58aa
+--- /dev/null
++++ b/grub-core/disk/nvme-int.h
+@@ -0,0 +1,208 @@
++// NVMe datastructures and constants
++//
++// Copyright 2017 Amazon.com, Inc. or its affiliates.
++//
++// This file may be distributed under the terms of the GNU LGPLv3 license.
++
++#ifndef __NVME_INT_H
++#define __NVME_INT_H
++
++#include <grub/types.h>
++
++/* Data structures */
++
++/* The register file of a NVMe host controller. This struct follows the naming
++ scheme in the NVMe specification. */
++struct nvme_reg {
++ grub_uint64_t cap; /* controller capabilities */
++ grub_uint32_t vs; /* version */
++ grub_uint32_t intms; /* interrupt mask set */
++ grub_uint32_t intmc; /* interrupt mask clear */
++ grub_uint32_t cc; /* controller configuration */
++ grub_uint32_t _res0;
++ grub_uint32_t csts; /* controller status */
++ grub_uint32_t _res1;
++ grub_uint32_t aqa; /* admin queue attributes */
++ grub_uint64_t asq; /* admin submission queue base address */
++ grub_uint64_t acq; /* admin completion queue base address */
++};
++
++/* Submission queue entry */
++struct nvme_sqe {
++ union {
++ grub_uint32_t dword[16];
++ struct {
++ grub_uint32_t cdw0; /* Command DWORD 0 */
++ grub_uint32_t nsid; /* Namespace ID */
++ grub_uint64_t _res0;
++ grub_uint64_t mptr; /* metadata ptr */
++
++ grub_uint64_t dptr_prp1;
++ grub_uint64_t dptr_prp2;
++ };
++ };
++};
++
++/* Completion queue entry */
++struct nvme_cqe {
++ union {
++ grub_uint32_t dword[4];
++ struct {
++ grub_uint32_t cdw0;
++ grub_uint32_t _res0;
++ grub_uint16_t sq_head;
++ grub_uint16_t sq_id;
++ grub_uint16_t cid;
++ grub_uint16_t status;
++ };
++ };
++};
++
++/* The common part of every submission or completion queue. */
++struct nvme_queue {
++ grub_uint32_t *dbl; /* doorbell */
++ grub_uint16_t mask; /* length - 1 */
++};
++
++struct nvme_cq {
++ struct nvme_queue common;
++ struct nvme_cqe *cqe;
++
++ /* We have read upto (but not including) this entry in the queue. */
++ grub_uint16_t head;
++
++ /* The current phase bit the controller uses to indicate that it has written
++ a new entry. This is inverted after each wrap. */
++ unsigned phase : 1;
++};
++
++struct nvme_sq {
++ struct nvme_queue common;
++ struct nvme_sqe *sqe;
++
++ /* Corresponding completion queue. We only support a single SQ per CQ. */
++ struct nvme_cq *cq;
++
++ /* The last entry the controller has fetched. */
++ grub_uint16_t head;
++
++ /* The last value we have written to the tail doorbell. */
++ grub_uint16_t tail;
++};
++
++struct nvme_ctrl {
++ grub_pci_device_t pci;
++ struct nvme_reg volatile *reg;
++
++ grub_uint32_t ctrlnum;
++
++ grub_uint32_t doorbell_stride; /* in bytes */
++
++ struct nvme_sq admin_sq;
++ struct nvme_cq admin_cq;
++
++ grub_uint32_t ns_count;
++
++ struct nvme_sq io_sq;
++ struct nvme_cq io_cq;
++};
++
++struct nvme_namespace {
++ struct nvme_namespace *next;
++ struct nvme_namespace **prev;
++
++ char *devname;
++
++ grub_uint32_t nsnum;
++
++ struct nvme_ctrl *ctrl;
++
++ grub_uint32_t ns_id;
++
++ grub_uint64_t lba_count; /* The total amount of sectors. */
++
++ grub_uint32_t block_size;
++ grub_uint32_t metadata_size;
++ grub_uint32_t max_req_size;
++};
++
++/* Data structures for NVMe admin identify commands */
++
++struct nvme_identify_ctrl {
++ grub_uint16_t vid;
++ grub_uint16_t ssvid;
++ char sn[20];
++ char mn[40];
++ char fr[8];
++
++ grub_uint8_t rab;
++ grub_uint8_t ieee[3];
++ grub_uint8_t cmic;
++ grub_uint8_t mdts;
++
++ char _boring[516 - 78];
++
++ grub_uint32_t nn; /* number of namespaces */
++};
++
++struct nvme_identify_ns_list {
++ grub_uint32_t ns_id[1024];
++};
++
++struct nvme_lba_format {
++ grub_uint16_t ms;
++ grub_uint8_t lbads;
++ grub_uint8_t rp;
++};
++
++struct nvme_identify_ns {
++ grub_uint64_t nsze;
++ grub_uint64_t ncap;
++ grub_uint64_t nuse;
++ grub_uint8_t nsfeat;
++ grub_uint8_t nlbaf;
++ grub_uint8_t flbas;
++
++ char _boring[128 - 27];
++
++ struct nvme_lba_format lbaf[16];
++};
++
++union nvme_identify {
++ struct nvme_identify_ns ns;
++ struct nvme_identify_ctrl ctrl;
++ struct nvme_identify_ns_list ns_list;
++};
++
++/* NVMe constants */
++
++#define NVME_CAP_CSS_NVME (1ULL << 37)
++
++#define NVME_CSTS_FATAL (1U << 1)
++#define NVME_CSTS_RDY (1U << 0)
++
++#define NVME_CC_EN (1U << 0)
++
++#define NVME_SQE_OPC_ADMIN_CREATE_IO_SQ 1U
++#define NVME_SQE_OPC_ADMIN_CREATE_IO_CQ 5U
++#define NVME_SQE_OPC_ADMIN_IDENTIFY 6U
++
++#define NVME_SQE_OPC_IO_WRITE 1U
++#define NVME_SQE_OPC_IO_READ 2U
++
++#define NVME_ADMIN_IDENTIFY_CNS_ID_NS 0U
++#define NVME_ADMIN_IDENTIFY_CNS_ID_CTRL 1U
++#define NVME_ADMIN_IDENTIFY_CNS_GET_NS_LIST 2U
++
++#define NVME_CQE_DW3_P (1U << 16)
++
++#define NVME_PAGE_SIZE 4096
++#define NVME_PAGE_MASK ~(NVME_PAGE_SIZE - 1)
++
++/* Length for the queue entries. */
++#define NVME_SQE_SIZE_LOG 6
++#define NVME_CQE_SIZE_LOG 4
++
++#endif
++
++/* EOF */
+diff --git a/grub-core/disk/nvme.c b/grub-core/disk/nvme.c
+new file mode 100644
+index 000000000..093237c70
+--- /dev/null
++++ b/grub-core/disk/nvme.c
+@@ -0,0 +1,781 @@
++// Low level NVMe disk access
++//
++// Based on SeaBIOS NVMe driver - Copyright 2017 Amazon.com, Inc. or its affiliates.
++// Port to GRUB2 done by Mate Kukri
++//
++// This file may be distributed under the terms of the GNU LGPLv3 license.
++
++#include <grub/disk.h>
++#include <grub/dl.h>
++#include <grub/pci.h>
++#include "nvme-int.h"
++
++GRUB_MOD_LICENSE ("GPLv3"); /* LGPLv3 in reality but it is GPLv3 compatible */
++
++static grub_uint32_t grub_nvme_ctrlcnt;
++static grub_uint32_t grub_nvme_nscnt;
++
++static struct nvme_namespace *grub_nvme_namespaces;
++
++// Page aligned "dma bounce buffer" of size NVME_PAGE_SIZE
++static void *nvme_dma_buffer;
++
++static void *
++zalloc_page_aligned(grub_uint32_t size)
++{
++ void *res = grub_memalign(NVME_PAGE_SIZE, size);
++ if (res) grub_memset(res, 0, size);
++ return res;
++}
++
++static void
++nvme_init_queue_common(struct nvme_ctrl *ctrl, struct nvme_queue *q, grub_uint16_t q_idx,
++ grub_uint16_t length)
++{
++ grub_memset(q, 0, sizeof(*q));
++ q->dbl = (grub_uint32_t *)((char *)ctrl->reg + 0x1000 + q_idx * ctrl->doorbell_stride);
++ grub_dprintf("nvme", " q %p q_idx %u dbl %p\n", q, q_idx, q->dbl);
++ q->mask = length - 1;
++}
++
++static int
++nvme_init_sq(struct nvme_ctrl *ctrl, struct nvme_sq *sq, grub_uint16_t q_idx, grub_uint16_t length,
++ struct nvme_cq *cq)
++{
++ nvme_init_queue_common(ctrl, &sq->common, q_idx, length);
++ sq->sqe = zalloc_page_aligned(sizeof(*sq->sqe) * length);
++
++ if (!sq->sqe) {
++ return -1;
++ }
++
++ grub_dprintf("nvme", "sq %p q_idx %u sqe %p\n", sq, q_idx, sq->sqe);
++ sq->cq = cq;
++ sq->head = 0;
++ sq->tail = 0;
++
++ return 0;
++}
++
++static int
++nvme_init_cq(struct nvme_ctrl *ctrl, struct nvme_cq *cq, grub_uint16_t q_idx, grub_uint16_t length)
++{
++ nvme_init_queue_common(ctrl, &cq->common, q_idx, length);
++ cq->cqe = zalloc_page_aligned(sizeof(*cq->cqe) * length);
++ if (!cq->cqe) {
++ return -1;
++ }
++
++ cq->head = 0;
++
++ /* All CQE phase bits are initialized to zero. This means initially we wait
++ for the host controller to set these to 1. */
++ cq->phase = 1;
++
++ return 0;
++}
++
++static int
++nvme_poll_cq(struct nvme_cq *cq)
++{
++ grub_uint32_t dw3 = *(volatile grub_uint32_t *) &cq->cqe[cq->head].dword[3];
++ return (!!(dw3 & NVME_CQE_DW3_P) == cq->phase);
++}
++
++static int
++nvme_is_cqe_success(struct nvme_cqe const *cqe)
++{
++ return ((cqe->status >> 1) & 0xFF) == 0;
++}
++
++static struct nvme_cqe
++nvme_error_cqe(void)
++{
++ struct nvme_cqe r;
++
++ /* 0xFF is a vendor specific status code != success. Should be okay for
++ indicating failure. */
++ grub_memset(&r, 0xFF, sizeof(r));
++ return r;
++}
++
++static struct nvme_cqe
++nvme_consume_cqe(struct nvme_sq *sq)
++{
++ struct nvme_cq *cq = sq->cq;
++
++ if (!nvme_poll_cq(cq)) {
++ /* Cannot consume a completion queue entry, if there is none ready. */
++ return nvme_error_cqe();
++ }
++
++ struct nvme_cqe *cqe = &cq->cqe[cq->head];
++ grub_uint16_t cq_next_head = (cq->head + 1) & cq->common.mask;
++ grub_dprintf("nvme", "cq %p head %u -> %u\n", cq, cq->head, cq_next_head);
++ if (cq_next_head < cq->head) {
++ grub_dprintf("nvme", "cq %p wrap\n", cq);
++ cq->phase = ~cq->phase;
++ }
++ cq->head = cq_next_head;
++
++ /* Update the submission queue head. */
++ if (cqe->sq_head != sq->head) {
++ sq->head = cqe->sq_head;
++ grub_dprintf("nvme", "sq %p advanced to %u\n", sq, cqe->sq_head);
++ }
++
++ /* Tell the controller that we consumed the completion. */
++ *(volatile grub_uint32_t *) cq->common.dbl = cq->head;
++
++ return *cqe;
++}
++
++static struct nvme_cqe
++nvme_wait(struct nvme_sq *sq)
++{
++ // static const unsigned nvme_timeout = 5000 /* ms */;
++ // grub_uint32_t to = timer_calc(nvme_timeout);
++ while (!nvme_poll_cq(sq->cq)) {
++ /* FIXME
++ yield();
++
++ if (timer_check(to)) {
++ warn_timeout();
++ return nvme_error_cqe();
++ }*/
++ }
++
++ return nvme_consume_cqe(sq);
++}
++
++/* Returns the next submission queue entry (or NULL if the queue is full). It
++ also fills out Command Dword 0 and clears the rest. */
++static struct nvme_sqe *
++nvme_get_next_sqe(struct nvme_sq *sq, grub_uint8_t opc, void *metadata, void *data, void *data2)
++{
++ if (((sq->head + 1) & sq->common.mask) == sq->tail) {
++ grub_dprintf("nvme", "submission queue is full\n");
++ return NULL;
++ }
++
++ struct nvme_sqe *sqe = &sq->sqe[sq->tail];
++ grub_dprintf("nvme", "sq %p next_sqe %u\n", sq, sq->tail);
++
++ grub_memset(sqe, 0, sizeof(*sqe));
++ sqe->cdw0 = opc | (sq->tail << 16 /* CID */);
++ sqe->mptr = (grub_uint32_t)metadata;
++ sqe->dptr_prp1 = (grub_uint32_t)data;
++ sqe->dptr_prp2 = (grub_uint32_t)data2;
++
++ return sqe;
++}
++
++/* Call this after you've filled out an sqe that you've got from nvme_get_next_sqe. */
++static void
++nvme_commit_sqe(struct nvme_sq *sq)
++{
++ grub_dprintf("nvme", "sq %p commit_sqe %u\n", sq, sq->tail);
++ sq->tail = (sq->tail + 1) & sq->common.mask;
++ *(volatile grub_uint32_t *) sq->common.dbl = sq->tail;
++}
++
++/* Perform an identify command on the admin queue and return the resulting
++ buffer. This may be a NULL pointer, if something failed. This function
++ cannot be used after initialization, because it uses buffers in tmp zone. */
++static union nvme_identify *
++nvme_admin_identify(struct nvme_ctrl *ctrl, grub_uint8_t cns, grub_uint32_t nsid)
++{
++ union nvme_identify *identify_buf = zalloc_page_aligned(4096);
++ if (!identify_buf)
++ return NULL;
++
++ struct nvme_sqe *cmd_identify;
++ cmd_identify = nvme_get_next_sqe(&ctrl->admin_sq,
++ NVME_SQE_OPC_ADMIN_IDENTIFY, NULL,
++ identify_buf, NULL);
++ if (!cmd_identify)
++ goto error;
++
++ cmd_identify->nsid = nsid;
++ cmd_identify->dword[10] = cns;
++
++ nvme_commit_sqe(&ctrl->admin_sq);
++
++ struct nvme_cqe cqe = nvme_wait(&ctrl->admin_sq);
++
++ if (!nvme_is_cqe_success(&cqe)) {
++ goto error;
++ }
++
++ return identify_buf;
++ error:
++ grub_free(identify_buf);
++ return NULL;
++}
++
++static struct nvme_identify_ctrl *
++nvme_admin_identify_ctrl(struct nvme_ctrl *ctrl)
++{
++ return &nvme_admin_identify(ctrl, NVME_ADMIN_IDENTIFY_CNS_ID_CTRL, 0)->ctrl;
++}
++
++static struct nvme_identify_ns *
++nvme_admin_identify_ns(struct nvme_ctrl *ctrl, grub_uint32_t ns_id)
++{
++ return &nvme_admin_identify(ctrl, NVME_ADMIN_IDENTIFY_CNS_ID_NS,
++ ns_id)->ns;
++}
++
++static void
++nvme_probe_ns(struct nvme_ctrl *ctrl, grub_uint32_t ns_idx, grub_uint8_t mdts)
++{
++ grub_uint32_t ns_id = ns_idx + 1;
++
++ struct nvme_identify_ns *id = nvme_admin_identify_ns(ctrl, ns_id);
++ if (!id) {
++ grub_dprintf("nvme", "NVMe couldn't identify namespace %u.\n", ns_id);
++ goto free_buffer;
++ }
++
++ grub_uint8_t current_lba_format = id->flbas & 0xF;
++ if (current_lba_format > id->nlbaf) {
++ grub_dprintf("nvme", "NVMe NS %u: current LBA format %u is beyond what the "
++ " namespace supports (%u)?\n",
++ ns_id, current_lba_format, id->nlbaf + 1);
++ goto free_buffer;
++ }
++
++ if (!id->nsze) {
++ grub_dprintf("nvme", "NVMe NS %u is inactive.\n", ns_id);
++ goto free_buffer;
++ }
++
++ if (!nvme_dma_buffer) {
++ nvme_dma_buffer = zalloc_page_aligned(NVME_PAGE_SIZE);
++ if (!nvme_dma_buffer) {
++ goto free_buffer;
++ }
++ }
++
++ struct nvme_namespace *ns = grub_malloc(sizeof(*ns));
++ if (!ns) {
++ goto free_buffer;
++ }
++ grub_memset(ns, 0, sizeof(*ns));
++ ns->ctrl = ctrl;
++ ns->ns_id = ns_id;
++ ns->lba_count = id->nsze;
++
++ struct nvme_lba_format *fmt = &id->lbaf[current_lba_format];
++
++ ns->block_size = 1U << fmt->lbads;
++ ns->metadata_size = fmt->ms;
++
++ if (ns->block_size > NVME_PAGE_SIZE) {
++ /* If we see devices that trigger this path, we need to increase our
++ buffer size. */
++ grub_free(ns);
++ goto free_buffer;
++ }
++
++ if (mdts) {
++ ns->max_req_size = ((1U << mdts) * NVME_PAGE_SIZE) / ns->block_size;
++ grub_dprintf("nvme", "NVME NS %u max request size: %d sectors\n",
++ ns_id, ns->max_req_size);
++ } else {
++ ns->max_req_size = -1U;
++ }
++
++ ns->devname = grub_xasprintf("nvme%un%u", ctrl->ctrlnum, ns_id);
++ ns->nsnum = grub_nvme_nscnt++;
++
++ grub_list_push (GRUB_AS_LIST_P (&grub_nvme_namespaces), GRUB_AS_LIST (ns));
++
++free_buffer:
++ grub_free(id);
++}
++
++
++/* Release memory allocated for a completion queue */
++static void
++nvme_destroy_cq(struct nvme_cq *cq)
++{
++ grub_free(cq->cqe);
++ cq->cqe = NULL;
++}
++
++/* Release memory allocated for a submission queue */
++static void
++nvme_destroy_sq(struct nvme_sq *sq)
++{
++ grub_free(sq->sqe);
++ sq->sqe = NULL;
++}
++
++/* Returns 0 on success. */
++static int
++nvme_create_io_cq(struct nvme_ctrl *ctrl, struct nvme_cq *cq, grub_uint16_t q_idx)
++{
++ int rc;
++ struct nvme_sqe *cmd_create_cq;
++ grub_uint32_t length = 1 + (ctrl->reg->cap & 0xffff);
++ if (length > NVME_PAGE_SIZE / sizeof(struct nvme_cqe))
++ length = NVME_PAGE_SIZE / sizeof(struct nvme_cqe);
++
++ rc = nvme_init_cq(ctrl, cq, q_idx, length);
++ if (rc) {
++ goto err;
++ }
++
++ cmd_create_cq = nvme_get_next_sqe(&ctrl->admin_sq,
++ NVME_SQE_OPC_ADMIN_CREATE_IO_CQ, NULL,
++ cq->cqe, NULL);
++ if (!cmd_create_cq) {
++ goto err_destroy_cq;
++ }
++
++ cmd_create_cq->dword[10] = (cq->common.mask << 16) | (q_idx >> 1);
++ cmd_create_cq->dword[11] = 1 /* physically contiguous */;
++
++ nvme_commit_sqe(&ctrl->admin_sq);
++
++ struct nvme_cqe cqe = nvme_wait(&ctrl->admin_sq);
++
++ if (!nvme_is_cqe_success(&cqe)) {
++ grub_dprintf("nvme", "create io cq failed: %08x %08x %08x %08x\n",
++ cqe.dword[0], cqe.dword[1], cqe.dword[2], cqe.dword[3]);
++
++ goto err_destroy_cq;
++ }
++
++ return 0;
++
++err_destroy_cq:
++ nvme_destroy_cq(cq);
++err:
++ return -1;
++}
++
++/* Returns 0 on success. */
++static int
++nvme_create_io_sq(struct nvme_ctrl *ctrl, struct nvme_sq *sq, grub_uint16_t q_idx, struct nvme_cq *cq)
++{
++ int rc;
++ struct nvme_sqe *cmd_create_sq;
++ grub_uint32_t length = 1 + (ctrl->reg->cap & 0xffff);
++ if (length > NVME_PAGE_SIZE / sizeof(struct nvme_cqe))
++ length = NVME_PAGE_SIZE / sizeof(struct nvme_cqe);
++
++ rc = nvme_init_sq(ctrl, sq, q_idx, length, cq);
++ if (rc) {
++ goto err;
++ }
++
++ cmd_create_sq = nvme_get_next_sqe(&ctrl->admin_sq,
++ NVME_SQE_OPC_ADMIN_CREATE_IO_SQ, NULL,
++ sq->sqe, NULL);
++ if (!cmd_create_sq) {
++ goto err_destroy_sq;
++ }
++
++ cmd_create_sq->dword[10] = (sq->common.mask << 16) | (q_idx >> 1);
++ cmd_create_sq->dword[11] = (q_idx >> 1) << 16 | 1 /* contiguous */;
++ grub_dprintf("nvme", "sq %p create dword10 %08x dword11 %08x\n", sq,
++ cmd_create_sq->dword[10], cmd_create_sq->dword[11]);
++
++ nvme_commit_sqe(&ctrl->admin_sq);
++
++ struct nvme_cqe cqe = nvme_wait(&ctrl->admin_sq);
++
++ if (!nvme_is_cqe_success(&cqe)) {
++ grub_dprintf("nvme", "create io sq failed: %08x %08x %08x %08x\n",
++ cqe.dword[0], cqe.dword[1], cqe.dword[2], cqe.dword[3]);
++ goto err_destroy_sq;
++ }
++
++ return 0;
++
++err_destroy_sq:
++ nvme_destroy_sq(sq);
++err:
++ return -1;
++}
++
++/* Reads count sectors into buf. The buffer cannot cross page boundaries. */
++static int
++nvme_io_xfer(struct nvme_namespace *ns, grub_uint64_t lba, void *prp1, void *prp2,
++ grub_uint16_t count, int write)
++{
++ if (((grub_uint32_t)prp1 & 0x3) || ((grub_uint32_t)prp2 & 0x3)) {
++ /* Buffer is misaligned */
++ return -1;
++ }
++
++ struct nvme_sqe *io_read = nvme_get_next_sqe(&ns->ctrl->io_sq,
++ write ? NVME_SQE_OPC_IO_WRITE
++ : NVME_SQE_OPC_IO_READ,
++ NULL, prp1, prp2);
++ io_read->nsid = ns->ns_id;
++ io_read->dword[10] = (grub_uint32_t)lba;
++ io_read->dword[11] = (grub_uint32_t)(lba >> 32);
++ io_read->dword[12] = (1U << 31 /* limited retry */) | (count - 1);
++
++ nvme_commit_sqe(&ns->ctrl->io_sq);
++
++ struct nvme_cqe cqe = nvme_wait(&ns->ctrl->io_sq);
++
++ if (!nvme_is_cqe_success(&cqe)) {
++ grub_dprintf("nvme", "read io: %08x %08x %08x %08x\n",
++ cqe.dword[0], cqe.dword[1], cqe.dword[2], cqe.dword[3]);
++
++ return -1;
++ }
++
++ grub_dprintf("nvme", "ns %u %s lba %llu+%u\n", ns->ns_id, write ? "write" : "read",
++ lba, count);
++ return count;
++}
++
++// Transfer up to one page of data using the internal dma bounce buffer
++static int
++nvme_bounce_xfer(struct nvme_namespace *ns, grub_uint64_t lba, void *buf, grub_uint16_t count,
++ int write)
++{
++ grub_uint16_t const max_blocks = NVME_PAGE_SIZE / ns->block_size;
++ grub_uint16_t blocks = count < max_blocks ? count : max_blocks;
++
++ if (write)
++ grub_memcpy(nvme_dma_buffer, buf, blocks * ns->block_size);
++
++ int res = nvme_io_xfer(ns, lba, nvme_dma_buffer, NULL, blocks, write);
++
++ if (!write && res >= 0)
++ grub_memcpy(buf, nvme_dma_buffer, res * ns->block_size);
++
++ return res;
++}
++
++#define NVME_MAX_PRPL_ENTRIES 15 /* Allows requests up to 64kb */
++
++// Transfer data using page list (if applicable)
++static int
++nvme_prpl_xfer(struct nvme_namespace *ns, grub_uint64_t lba, void *buf, grub_uint16_t count,
++ int write)
++{
++ grub_uint32_t base = (long)buf;
++ grub_int32_t size;
++
++ if (count > ns->max_req_size)
++ count = ns->max_req_size;
++
++ size = count * ns->block_size;
++ /* Special case for transfers that fit into PRP1, but are unaligned */
++ if (((size + (base & ~NVME_PAGE_MASK)) <= NVME_PAGE_SIZE))
++ goto single;
++
++ /* Every request has to be page aligned */
++ if (base & ~NVME_PAGE_MASK)
++ goto bounce;
++
++ /* Make sure a full block fits into the last chunk */
++ if (size & (ns->block_size - 1ULL))
++ goto bounce;
++
++ /* Build PRP list if we need to describe more than 2 pages */
++ if ((ns->block_size * count) > (NVME_PAGE_SIZE * 2)) {
++ grub_uint32_t prpl_len = 0;
++ grub_uint64_t *prpl = nvme_dma_buffer;
++ int first_page = 1;
++ for (; size > 0; base += NVME_PAGE_SIZE, size -= NVME_PAGE_SIZE) {
++ if (first_page) {
++ /* First page is special */
++ first_page = 0;
++ continue;
++ }
++ if (prpl_len >= NVME_MAX_PRPL_ENTRIES)
++ goto bounce;
++ prpl[prpl_len++] = base;
++ }
++ return nvme_io_xfer(ns, lba, buf, prpl, count, write);
++ }
++
++ /* Directly embed the 2nd page if we only need 2 pages */
++ if ((ns->block_size * count) > NVME_PAGE_SIZE)
++ return nvme_io_xfer(ns, lba, buf, (char *) buf + NVME_PAGE_SIZE, count, write);
++
++single:
++ /* One page is enough, don't expose anything else */
++ return nvme_io_xfer(ns, lba, buf, NULL, count, write);
++
++bounce:
++ /* Use bounce buffer to make transfer */
++ return nvme_bounce_xfer(ns, lba, buf, count, write);
++}
++
++static int
++nvme_create_io_queues(struct nvme_ctrl *ctrl)
++{
++ if (nvme_create_io_cq(ctrl, &ctrl->io_cq, 3))
++ goto err;
++
++ if (nvme_create_io_sq(ctrl, &ctrl->io_sq, 2, &ctrl->io_cq))
++ goto err_free_cq;
++
++ return 0;
++
++ err_free_cq:
++ nvme_destroy_cq(&ctrl->io_cq);
++ err:
++ return -1;
++}
++
++/* Waits for CSTS.RDY to match rdy. Returns 0 on success. */
++static int
++nvme_wait_csts_rdy(struct nvme_ctrl *ctrl, unsigned rdy)
++{
++ // grub_uint32_t const max_to = 500 /* ms */ * ((ctrl->reg->cap >> 24) & 0xFFU);
++ // grub_uint32_t to = timer_calc(max_to);
++ grub_uint32_t csts;
++
++ while (rdy != ((csts = ctrl->reg->csts) & NVME_CSTS_RDY)) {
++ // FIXME
++ //yield();
++
++ if (csts & NVME_CSTS_FATAL) {
++ grub_dprintf("nvme", "NVMe fatal error during controller shutdown\n");
++ return -1;
++ }
++
++ /*
++ if (timer_check(to)) {
++ warn_timeout();
++ return -1;
++ }*/
++ }
++
++ return 0;
++}
++
++/* Returns 0 on success. */
++static int grub_nvme_controller_enable(struct nvme_ctrl *ctrl)
++{
++ grub_pci_address_t addr;
++ int rc;
++
++ addr = grub_pci_make_address (ctrl->pci, GRUB_PCI_REG_COMMAND);
++ grub_pci_write_word (addr, grub_pci_read_word (addr) | GRUB_PCI_COMMAND_BUS_MASTER);
++
++ /* Turn the controller off. */
++ ctrl->reg->cc = 0;
++ if (nvme_wait_csts_rdy(ctrl, 0)) {
++ grub_dprintf("nvme", "NVMe fatal error during controller shutdown\n");
++ return -1;
++ }
++
++ ctrl->doorbell_stride = 4U << ((ctrl->reg->cap >> 32) & 0xF);
++
++ rc = nvme_init_cq(ctrl, &ctrl->admin_cq, 1,
++ NVME_PAGE_SIZE / sizeof(struct nvme_cqe));
++ if (rc) {
++ return -1;
++ }
++
++ rc = nvme_init_sq(ctrl, &ctrl->admin_sq, 0,
++ NVME_PAGE_SIZE / sizeof(struct nvme_sqe), &ctrl->admin_cq);
++ if (rc) {
++ goto err_destroy_admin_cq;
++ }
++
++ ctrl->reg->aqa = ctrl->admin_cq.common.mask << 16
++ | ctrl->admin_sq.common.mask;
++
++ ctrl->reg->asq = (grub_uint32_t)ctrl->admin_sq.sqe;
++ ctrl->reg->acq = (grub_uint32_t)ctrl->admin_cq.cqe;
++
++ grub_dprintf("nvme", " admin submission queue: %p\n", ctrl->admin_sq.sqe);
++ grub_dprintf("nvme", " admin completion queue: %p\n", ctrl->admin_cq.cqe);
++
++ ctrl->reg->cc = NVME_CC_EN | (NVME_CQE_SIZE_LOG << 20)
++ | (NVME_SQE_SIZE_LOG << 16 /* IOSQES */);
++
++ if (nvme_wait_csts_rdy(ctrl, 1)) {
++ grub_dprintf("nvme", "NVMe fatal error while enabling controller\n");
++ goto err_destroy_admin_sq;
++ }
++
++ /* The admin queue is set up and the controller is ready. Let's figure out
++ what namespaces we have. */
++
++ struct nvme_identify_ctrl *identify = nvme_admin_identify_ctrl(ctrl);
++
++ if (!identify) {
++ grub_dprintf("nvme", "NVMe couldn't identify controller.\n");
++ goto err_destroy_admin_sq;
++ }
++
++ grub_dprintf("nvme", "NVMe has %u namespace%s.\n",
++ identify->nn, (identify->nn == 1) ? "" : "s");
++
++ ctrl->ns_count = identify->nn;
++ grub_uint8_t mdts = identify->mdts;
++ grub_free(identify);
++
++ if ((ctrl->ns_count == 0) || nvme_create_io_queues(ctrl)) {
++ /* No point to continue, if the controller says it doesn't have
++ namespaces or we couldn't create I/O queues. */
++ goto err_destroy_admin_sq;
++ }
++
++ /* Give the controller a global number */
++ ctrl->ctrlnum = grub_nvme_ctrlcnt++;
++
++ /* Populate namespace IDs */
++ for (grub_uint32_t ns_idx = 0; ns_idx < ctrl->ns_count; ns_idx++) {
++ nvme_probe_ns(ctrl, ns_idx, mdts);
++ }
++
++ grub_dprintf("nvme", "NVMe initialization complete!\n");
++ return 0;
++
++ err_destroy_admin_sq:
++ nvme_destroy_sq(&ctrl->admin_sq);
++ err_destroy_admin_cq:
++ nvme_destroy_cq(&ctrl->admin_cq);
++ return -1;
++}
++
++static int grub_nvme_pci_probe(grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ ((unused)), void *data __attribute__ ((unused)))
++{
++ grub_pci_address_t addr;
++ grub_uint32_t class, bar, version;
++ struct nvme_reg volatile *reg;
++
++ class = grub_pci_read (grub_pci_make_address (dev, GRUB_PCI_REG_CLASS));
++ if (class >> 16 != 0x0108)
++ return 0;
++ if ((class >> 8 & 0xff) != 2) { /* as of NVM 1.0e */
++ grub_dprintf("nvme", "Found incompatble NVMe: prog-if=%02x\n", class >> 8 & 0xff);
++ return 0;
++ }
++
++ bar = grub_pci_read (grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0));
++ reg = grub_pci_device_map_range (dev, bar & GRUB_PCI_ADDR_MEM_MASK, sizeof (*reg));
++
++ addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
++ grub_pci_write_word (addr, grub_pci_read_word (addr) | GRUB_PCI_COMMAND_MEM_ENABLED);
++
++ version = reg->vs;
++ grub_dprintf("nvme", "Found NVMe controller with version %u.%u.%u.\n", version >> 16, (version >> 8) & 0xFF, version & 0xFF);
++ grub_dprintf("nvme", " Capabilities %016llx\n", reg->cap);
++
++ if (~reg->cap & NVME_CAP_CSS_NVME) {
++ grub_dprintf("nvme", "Controller doesn't speak NVMe command set. Skipping.\n");
++ goto err;
++ }
++
++ struct nvme_ctrl *ctrl = grub_malloc(sizeof(*ctrl));
++ if (!ctrl)
++ goto err;
++
++ grub_memset(ctrl, 0, sizeof(*ctrl));
++
++ ctrl->reg = reg;
++ ctrl->pci = dev;
++
++ if (grub_nvme_controller_enable(ctrl))
++ goto err_free_ctrl;
++
++ return 0;
++
++ err_free_ctrl:
++ grub_free(ctrl);
++ err:
++ grub_dprintf("nvme", "Failed to enable NVMe controller.\n");
++ return 0;
++}
++
++static int
++grub_nvme_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, grub_disk_pull_t pull)
++{
++ struct nvme_namespace *ns;
++
++ if (pull != GRUB_DISK_PULL_NONE)
++ return 0;
++
++ FOR_LIST_ELEMENTS(ns, grub_nvme_namespaces)
++ if (hook (ns->devname, hook_data))
++ return 1;
++
++ return 0;
++}
++
++static grub_err_t
++grub_nvme_open (const char *name __attribute ((unused)), grub_disk_t disk __attribute ((unused)))
++{
++ struct nvme_namespace *ns;
++
++ FOR_LIST_ELEMENTS(ns, grub_nvme_namespaces)
++ if (grub_strcmp (ns->devname, name) == 0)
++ break;
++
++ if (! ns)
++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
++
++ disk->total_sectors = ns->lba_count;
++ disk->max_agglomerate = ns->max_req_size;
++
++ disk->id = ns->nsnum; /* global id of the namespace */
++
++ disk->data = ns;
++
++ return 0;
++}
++
++static grub_err_t
++nvme_readwrite(struct nvme_namespace *ns, grub_disk_addr_t sector, grub_size_t num_sectors, char *buf, int write)
++{
++ for (int i = 0; i < num_sectors;) {
++ grub_uint16_t blocks_remaining = num_sectors - i;
++ char *op_buf = buf + i * ns->block_size;
++ int blocks = nvme_prpl_xfer(ns, sector + i, op_buf, blocks_remaining, write);
++ if (blocks < 0)
++ return GRUB_ERR_IO;
++ i += blocks;
++ }
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_nvme_read (grub_disk_t disk, grub_disk_addr_t sector, grub_size_t num_sectors, char *buf)
++{
++ return nvme_readwrite((struct nvme_namespace *) disk->data, sector, num_sectors, buf, 0);
++}
++
++static grub_err_t
++grub_nvme_write (grub_disk_t disk, grub_disk_addr_t sector, grub_size_t num_sectors, const char *buf)
++{
++ return nvme_readwrite((struct nvme_namespace *) disk->data, sector, num_sectors, buf, 1);
++}
++
++static struct grub_disk_dev grub_nvme_dev =
++ {
++ .name = "nvme",
++ .id = GRUB_DISK_DEVICE_NVME_ID,
++ .disk_iterate = grub_nvme_iterate,
++ .disk_open = grub_nvme_open,
++ .disk_read = grub_nvme_read,
++ .disk_write = grub_nvme_write,
++ .next = 0
++ };
++
++GRUB_MOD_INIT(nvme)
++{
++ grub_stop_disk_firmware ();
++ grub_pci_iterate (grub_nvme_pci_probe, NULL);
++ grub_disk_dev_register (&grub_nvme_dev);
++}
++
++GRUB_MOD_FINI(nvme)
++{
++ grub_disk_dev_unregister (&grub_nvme_dev);
++}
+diff --git a/include/grub/disk.h b/include/grub/disk.h
+index fbf23df7f..186e76f0b 100644
+--- a/include/grub/disk.h
++++ b/include/grub/disk.h
+@@ -52,6 +52,7 @@ enum grub_disk_dev_id
+ GRUB_DISK_DEVICE_UBOOTDISK_ID,
+ GRUB_DISK_DEVICE_XEN,
+ GRUB_DISK_DEVICE_OBDISK_ID,
++ GRUB_DISK_DEVICE_NVME_ID
+ };
+
+ struct grub_disk;
+--
+2.47.3
+
diff --git a/config/grub/nvme/patches/0009-kern-coreboot-mmap-Map-to-reserved.patch b/config/grub/nvme/patches/0009-kern-coreboot-mmap-Map-to-reserved.patch
new file mode 100644
index 00000000..11b82429
--- /dev/null
+++ b/config/grub/nvme/patches/0009-kern-coreboot-mmap-Map-to-reserved.patch
@@ -0,0 +1,37 @@
+From 9ec8534a4d27db37cf4feebd44fd9f8973a89e59 Mon Sep 17 00:00:00 2001
+From: Paul Menzel <pmenzel@molgen.mpg.de>
+Date: Mon, 17 May 2021 10:24:36 +0200
+Subject: [PATCH 09/10] kern/coreboot/mmap: Map to reserved
+
+https://git.savannah.gnu.org/cgit/grub.git/commit/?id=6de9ee86bf9ae50967413e6a73b5dfd13e5ffb50
+
+Signed-off-by: Paul Menzel <pmenzel@molgen.mpg.de>
+---
+ grub-core/kern/coreboot/mmap.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/kern/coreboot/mmap.c b/grub-core/kern/coreboot/mmap.c
+index caf8f7cef..2fc316e8d 100644
+--- a/grub-core/kern/coreboot/mmap.c
++++ b/grub-core/kern/coreboot/mmap.c
+@@ -59,7 +59,7 @@ iterate_linuxbios_table (grub_linuxbios_table_item_t table_item, void *data)
+ /* Multiboot mmaps match with the coreboot mmap
+ definition. Therefore, we can just pass type
+ through. */
+- mem_region->type,
++ (mem_region->type >= 13) ? 2 : mem_region->type,
+ ctx->hook_data))
+ return 1;
+ if (start < 0xa0000)
+@@ -81,7 +81,7 @@ iterate_linuxbios_table (grub_linuxbios_table_item_t table_item, void *data)
+ /* Multiboot mmaps match with the coreboot mmap
+ definition. Therefore, we can just pass type
+ through. */
+- mem_region->type,
++ (mem_region->type >= 13) ? 2 : mem_region->type,
+ ctx->hook_data))
+ return 1;
+ }
+--
+2.47.3
+
diff --git a/config/grub/nvme/patches/0010-Revert-configure-Check-linker-for-image-base-support.patch b/config/grub/nvme/patches/0010-Revert-configure-Check-linker-for-image-base-support.patch
new file mode 100644
index 00000000..8e78e8b7
--- /dev/null
+++ b/config/grub/nvme/patches/0010-Revert-configure-Check-linker-for-image-base-support.patch
@@ -0,0 +1,70 @@
+From 7b0d621389fc1857c918058f82093f9630ea7730 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Wed, 24 Dec 2025 01:42:17 +0100
+Subject: [PATCH 10/10] Revert "configure: Check linker for --image-base
+ support"
+
+This reverts commit 1a5417f39a0ccefcdd5440f2a67f84d2d2e26960.
+---
+ acinclude.m4 | 5 -----
+ configure.ac | 14 ++------------
+ 2 files changed, 2 insertions(+), 17 deletions(-)
+
+diff --git a/acinclude.m4 b/acinclude.m4
+index 70c1912f8..fa7840f09 100644
+--- a/acinclude.m4
++++ b/acinclude.m4
+@@ -79,11 +79,6 @@ AC_DEFUN([grub_PROG_OBJCOPY_ABSOLUTE],
+ [AC_MSG_CHECKING([whether ${TARGET_OBJCOPY} works for absolute addresses])
+ AC_CACHE_VAL(grub_cv_prog_objcopy_absolute,
+ [cat > conftest.c <<\EOF
+-asm (
+- ".globl start, _start, __start\n"
+- ".ifdef cmain; .set start = _start = __start = cmain\n.endif\n"
+- ".ifdef _cmain; .set start = _start = __start = _cmain\n.endif\n"
+-);
+ void cmain (void);
+ void
+ cmain (void)
+diff --git a/configure.ac b/configure.ac
+index d8ca1b7c1..041cfbab4 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1461,6 +1461,7 @@ elif test x$grub_cv_target_cc_link_format = x-mi386pe || test x$grub_cv_target_c
+ TARGET_IMG_LDSCRIPT='$(top_srcdir)'"/conf/i386-cygwin-img-ld.sc"
+ TARGET_IMG_LDFLAGS="-Wl,-T${TARGET_IMG_LDSCRIPT}"
+ TARGET_IMG_LDFLAGS_AC="-Wl,-T${srcdir}/conf/i386-cygwin-img-ld.sc"
++ TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"
+ TARGET_IMG_CFLAGS=
+ else
+ TARGET_APPLE_LINKER=0
+@@ -1468,6 +1469,7 @@ else
+ TARGET_IMG_LDSCRIPT=
+ TARGET_IMG_LDFLAGS='-Wl,-N'
+ TARGET_IMG_LDFLAGS_AC='-Wl,-N'
++ TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"
+ TARGET_IMG_CFLAGS=
+ fi
+
+@@ -1798,18 +1800,6 @@ grub_PROG_TARGET_CC
+ m4_ifndef([AX_CHECK_LINK_FLAG], [m4_fatal([autoconf-archive is missing. You must install it to generate the configure script.])])
+
+ if test "x$TARGET_APPLE_LINKER" != x1 ; then
+-AX_CHECK_LINK_FLAG([-Wl,--image-base,0x400000],
+- [TARGET_IMG_BASE_LDOPT="-Wl,--image-base"],
+- [TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"],
+- [],
+- [AC_LANG_SOURCE([
+-asm (".globl start; start:");
+-asm (".globl _start; _start:");
+-asm (".globl __start; __start:");
+-void __main (void);
+-void __main (void) {}
+-int main (void);
+- ])])
+ grub_PROG_OBJCOPY_ABSOLUTE
+ fi
+ grub_PROG_LD_BUILD_ID_NONE
+--
+2.47.3
+
diff --git a/config/grub/nvme/patches/0011-Revert-configure-Print-a-more-helpful-error-if-autoc.patch b/config/grub/nvme/patches/0011-Revert-configure-Print-a-more-helpful-error-if-autoc.patch
new file mode 100644
index 00000000..c0a504ff
--- /dev/null
+++ b/config/grub/nvme/patches/0011-Revert-configure-Print-a-more-helpful-error-if-autoc.patch
@@ -0,0 +1,30 @@
+From abf2bf6e2973ccaa994f63ff851ba11cbd45f1eb Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Mon, 19 Jan 2026 15:27:23 +0000
+Subject: [PATCH 1/1] Revert "configure: Print a more helpful error if
+ autoconf-archive is not installed"
+
+This reverts commit ac042f3f58d33ce9cd5ff61750f06da1a1d7b0eb.
+---
+ configure.ac | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 041cfbab4..209c0fb11 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1794,11 +1794,6 @@ LIBS=""
+ # Defined in acinclude.m4.
+ grub_ASM_USCORE
+ grub_PROG_TARGET_CC
+-
+-# The error message produced by autoconf if autoconf-archive is not installed is
+-# quite misleading and not very helpful. So, try point people in the right direction.
+-m4_ifndef([AX_CHECK_LINK_FLAG], [m4_fatal([autoconf-archive is missing. You must install it to generate the configure script.])])
+-
+ if test "x$TARGET_APPLE_LINKER" != x1 ; then
+ grub_PROG_OBJCOPY_ABSOLUTE
+ fi
+--
+2.47.3
+
diff --git a/config/grub/nvme/target.cfg b/config/grub/nvme/target.cfg
new file mode 100644
index 00000000..e2a67cc0
--- /dev/null
+++ b/config/grub/nvme/target.cfg
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+tree="nvme"
+rev="eaa3b8f0f90605a82c6bfda4c5c4b73c58eb81ac"
diff --git a/config/grub/patches/0002-luks2/0003-Add-CC0-license.patch b/config/grub/patches/0002-luks2/0003-Add-CC0-license.patch
deleted file mode 100644
index dc9060c3..00000000
--- a/config/grub/patches/0002-luks2/0003-Add-CC0-license.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From de6e7cc62522ce1be21bd2f06e7c15cd234b5426 Mon Sep 17 00:00:00 2001
-From: Ax333l <main@axelen.xyz>
-Date: Thu, 17 Aug 2023 00:00:00 +0000
-Subject: [PATCH 1/6] Add CC0 license
-
-Signed-off-by: Nicholas Johnson <nick@nicholasjohnson.ch>
----
- 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 0bf40caa6..4011e2d15 100644
---- a/grub-core/kern/dl.c
-+++ b/grub-core/kern/dl.c
-@@ -470,7 +470,8 @@ grub_dl_check_license (grub_dl_t mod, Elf_Ehdr *e)
-
- 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 a42c20bd1..7157a30aa 100644
---- a/util/grub-module-verifierXX.c
-+++ b/util/grub-module-verifierXX.c
-@@ -236,7 +236,8 @@ check_license (const char * const filename,
- Elf_Shdr *s = find_section (arch, e, ".module_license", module_size);
- 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.39.2
-
diff --git a/config/grub/patches/0002-luks2/0004-Define-GRUB_UINT32_MAX.patch b/config/grub/patches/0002-luks2/0004-Define-GRUB_UINT32_MAX.patch
deleted file mode 100644
index be875e67..00000000
--- a/config/grub/patches/0002-luks2/0004-Define-GRUB_UINT32_MAX.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From 9edaaffac91d593a439e44bac3b6f5558f5a8245 Mon Sep 17 00:00:00 2001
-From: Ax333l <main@axelen.xyz>
-Date: Thu, 17 Aug 2023 00:00:00 +0000
-Subject: [PATCH 2/6] Define GRUB_UINT32_MAX
-
-Signed-off-by: Nicholas Johnson <nick@nicholasjohnson.ch>
----
- include/grub/types.h | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/include/grub/types.h b/include/grub/types.h
-index 0d96006fe..a13f3a60b 100644
---- a/include/grub/types.h
-+++ b/include/grub/types.h
-@@ -156,6 +156,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
-@@ -177,6 +178,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.39.2
-
diff --git a/config/grub/patches/0002-luks2/0005-Add-Argon2-algorithm.patch b/config/grub/patches/0002-luks2/0005-Add-Argon2-algorithm.patch
deleted file mode 100644
index 1c6b4f04..00000000
--- a/config/grub/patches/0002-luks2/0005-Add-Argon2-algorithm.patch
+++ /dev/null
@@ -1,2611 +0,0 @@
-From 5b63da5c4267933f573ca37ce39a073098c443ba Mon Sep 17 00:00:00 2001
-From: Ax333l <main@axelen.xyz>
-Date: Thu, 17 Aug 2023 00:00:00 +0000
-Subject: [PATCH 3/6] Add Argon2 algorithm
-
-Signed-off-by: Nicholas Johnson <nick@nicholasjohnson.ch>
----
- 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 a695b02f0..313335a53 100644
---- a/docs/grub-dev.texi
-+++ b/docs/grub-dev.texi
-@@ -503,11 +503,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 d2cf29584..4a06789e5 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -1215,6 +1215,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..97aae2925
---- /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.39.2
-
diff --git a/config/grub/patches/0002-luks2/0006-Error-on-missing-Argon2id-parameters.patch b/config/grub/patches/0002-luks2/0006-Error-on-missing-Argon2id-parameters.patch
deleted file mode 100644
index 5d56bd61..00000000
--- a/config/grub/patches/0002-luks2/0006-Error-on-missing-Argon2id-parameters.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-From 0044d32121bf52c4547c6b3c78f12d7305f57e6b Mon Sep 17 00:00:00 2001
-From: Ax333l <main@axelen.xyz>
-Date: Thu, 17 Aug 2023 00:00:00 +0000
-Subject: [PATCH 4/6] Error on missing Argon2id parameters
-
-Signed-off-by: Nicholas Johnson <nick@nicholasjohnson.ch>
----
- 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 d5106402f..bc818ea69 100644
---- a/grub-core/disk/luks2.c
-+++ b/grub-core/disk/luks2.c
-@@ -38,6 +38,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;
-@@ -90,7 +91,7 @@ struct grub_luks2_keyslot
- grub_int64_t time;
- grub_int64_t memory;
- grub_int64_t cpus;
-- } argon2i;
-+ } argon2;
- struct
- {
- const char *hash;
-@@ -160,10 +161,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"))
-@@ -459,6 +461,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.39.2
-
diff --git a/config/grub/patches/0002-luks2/0007-Compile-with-Argon2id-support.patch b/config/grub/patches/0002-luks2/0007-Compile-with-Argon2id-support.patch
deleted file mode 100644
index f2e26fd4..00000000
--- a/config/grub/patches/0002-luks2/0007-Compile-with-Argon2id-support.patch
+++ /dev/null
@@ -1,83 +0,0 @@
-From 0a21695c55f76f1c958bb633481d55b3168562f7 Mon Sep 17 00:00:00 2001
-From: Ax333l <main@axelen.xyz>
-Date: Thu, 17 Aug 2023 00:00:00 +0000
-Subject: [PATCH 5/6] Compile with Argon2id support
-
-Signed-off-by: Nicholas Johnson <nick@nicholasjohnson.ch>
----
- 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 1e9a13d3e..a167825c3 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 4a06789e5..e939dcc99 100644
---- a/grub-core/Makefile.core.def
-+++ b/grub-core/Makefile.core.def
-@@ -1238,7 +1238,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 bc818ea69..5b9eaa599 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>
-
-@@ -462,8 +463,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.39.2
-
diff --git a/config/grub/patches/0002-luks2/0008-Make-grub-install-work-with-Argon2.patch b/config/grub/patches/0002-luks2/0008-Make-grub-install-work-with-Argon2.patch
deleted file mode 100644
index dc65b7a6..00000000
--- a/config/grub/patches/0002-luks2/0008-Make-grub-install-work-with-Argon2.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From 6c9a6625c0dc038d1bdbdc13665f40e269e86496 Mon Sep 17 00:00:00 2001
-From: Ax333l <main@axelen.xyz>
-Date: Thu, 17 Aug 2023 00:00:00 +0000
-Subject: [PATCH 6/6] Make grub-install work with Argon2
-
-Signed-off-by: Nicholas Johnson <nick@nicholasjohnson.ch>
----
- util/grub-install.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/util/grub-install.c b/util/grub-install.c
-index 1ad04db36..a8a3330b8 100644
---- a/util/grub-install.c
-+++ b/util/grub-install.c
-@@ -448,6 +448,8 @@ probe_mods (grub_disk_t disk)
- {
- grub_util_cryptodisk_get_abstraction (disk,
- push_cryptodisk_module, NULL);
-+ /* HACK: always push argon2 */
-+ grub_install_push_module ("argon2");
- have_abstractions = 1;
- have_cryptodisk = 1;
- }
---
-2.39.2
-
diff --git a/config/grub/target.cfg b/config/grub/target.cfg
deleted file mode 100644
index 2aaeb559..00000000
--- a/config/grub/target.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-bootstrapargs="--gnulib-srcdir=gnulib/ --no-git"
-autoconfargs="--with-platform=coreboot --disable-werror"
-makeargs="FS_PAYLOAD_MODULES=\"\""
diff --git a/config/grub/xhci_nvme/config/payload b/config/grub/xhci_nvme/config/payload
new file mode 100644
index 00000000..9db22fe2
--- /dev/null
+++ b/config/grub/xhci_nvme/config/payload
@@ -0,0 +1,321 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+# Copyright (C) 2014-2016,2020-2021,2023-2025 Leah Rowe <leah@libreboot.org>
+# Copyright (C) 2015 Klemens Nanni <contact@autoboot.org>
+
+set prefix=(memdisk)/boot/grub
+
+insmod at_keyboard
+insmod usb_keyboard
+insmod nativedisk
+insmod xhci
+insmod ehci
+insmod ohci
+insmod uhci
+insmod usb
+insmod usbms
+insmod regexp
+
+terminal_input --append at_keyboard
+terminal_input --append usb_keyboard
+terminal_output --append cbmemc
+
+# User interface overrides wherever "keystatus" is supported
+# Keep SHIFT key pressed before powering on to disable graphics
+if keystatus --shift; then
+ terminal_output --append vga_text
+else
+ gfxpayload=keep
+ terminal_output --append gfxterm
+
+ for dt in cbfsdisk memdisk; do
+ for it in png jpg; do
+ if [ -f (${dt})/background.${it} ]; then
+ insmod ${it}
+ background_image (${dt})/background.${it}
+ fi
+ done
+ done
+fi
+
+# Keep CTRL pressed to enable default serial terminal (COM1 or the like)
+if keystatus --ctrl; then
+ serial
+ terminal_input --append serial
+ terminal_output --append serial
+fi
+
+# Keep ALT pressed to enable spkmodem
+if keystatus --alt; then
+ terminal_output --append spkmodem
+fi
+
+
+set default="0"
+if [ -f (cbfsdisk)/timeout.cfg ]; then
+ source (cbfsdisk)/timeout.cfg
+else
+ set timeout=8
+fi
+set grub_scan_disk="nvme ahci ata"
+if [ -f (cbfsdisk)/scan.cfg ]; then
+ source (cbfsdisk)/scan.cfg
+fi
+
+if [ -f (cbfsdisk)/keymap.gkb ]; then
+ keymap (cbfsdisk)/keymap.gkb
+fi
+
+function really_try_user_config {
+ set root="${1}"
+
+ if [ -f /"${2}"/grub.cfg ]; then
+ unset superusers
+ configfile /"${2}"/grub.cfg
+ fi
+}
+
+function try_user_config {
+ # The @/... entries are for cases where the BTRFS filesystem is being used
+ for dir in grub boot/grub @/grub @/boot/grub grub2 boot/grub2 @/grub2 @/boot/grub2 boot @/boot; do
+ really_try_user_config "${1}" "${dir}"
+ done
+ for dir in ubuntu debian redhat; do
+ really_try_user_config "${1}" "EFI/${dir}"
+ done
+}
+function search_grub {
+ echo -n "Attempting to load grub.cfg from '${1}' devices"
+ for i in 0 1 2 3 4 5 6 7 8; do
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12; do
+ if [ "${1}" != "nvme" ]; then
+ try_user_config "(${1}${i},${part})"
+ else
+ # TODO: do we care about other namesapces
+ try_user_config "(nvme${i}n1,${part})"
+ fi
+ done
+ if [ "${1}" != "nvme" ]; then
+ # raw devices e.g. (ahci0) instead of (ahci0,1)
+ try_user_config "(${1}${i})"
+ else
+ # TODO: do we care about other namesapces
+ try_user_config "(nvme${i}n1)"
+ fi
+ done
+ echo # Insert newline
+}
+
+function try_isolinux_config {
+ set root="${1}"
+ for dir in '' /boot /EFI /@ /@/boot; do
+ if [ -f "${dir}"/isolinux/isolinux.cfg ]; then
+ syslinux_configfile -i "${dir}"/isolinux/isolinux.cfg
+ elif [ -f "${dir}"/syslinux/syslinux.cfg ]; then
+ syslinux_configfile -s "${dir}"/syslinux/syslinux.cfg
+ elif [ -f "${dir}"/syslinux/extlinux.conf ]; then
+ syslinux_configfile -s "${dir}"/syslinux/extlinux.conf
+ elif [ -f "${dir}"/extlinux/extlinux.conf ]; then
+ syslinux_configfile -s "${dir}"/extlinux/extlinux.conf
+ fi
+ done
+}
+function search_isolinux {
+ echo "\nAttempting to parse iso/sys/extlinux config from '${1}' devices"
+ for i in 0 1 2 3 4 5 6 7 8; do
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12; do
+ if [ "${1}" != "nvme" ]; then
+ try_isolinux_config "(${1}${i},${part})"
+ else
+ # TODO: see above
+ try_isolinux_config "(nvme${i}n1,${part})"
+ fi
+ done
+ if [ "${1}" != "nvme" ]; then
+ # raw devices e.g. (usb0) instead of (usb0,1)
+ try_isolinux_config "(${1}${i})"
+ else
+ # TODO: do we care about other namesapces
+ try_isolinux_config "(nvme${i}n1)"
+ fi
+ done
+ echo # Insert newline
+}
+function try_bootcfg {
+ try_user_config "${1}"
+ try_isolinux_config "${1}"
+}
+function search_bootcfg {
+ search_grub "${1}"
+ search_isolinux "${1}"
+}
+menuentry 'Load Operating System (incl. fully encrypted disks) [o]' --hotkey='o' {
+
+ for grub_disk in ${grub_scan_disk}; do
+ search_bootcfg ${grub_disk}
+ done
+
+ # grub device enumeration is very slow, so checks are hardcoded
+
+ raidvol="md/0 md/1 md/2 md/3 md/4 md/5 md/6 md/7 md/8 md/9"
+
+ # in practise, doing multiple redundant checks is perfectly fast
+ # TODO: optimize grub itself, and use */? here for everything
+
+ for vol in ${raidvol} ; do
+ try_bootcfg "${vol}"
+ done
+
+ unset bootdev
+ for grub_disk in ${grub_scan_disk}; do
+ for i in 0 1 2 3 4 5 6 7 8; do
+ for part in 1 2 3 4 5 6 7 8 9 10 11 12; do
+ if [ "${grub_disk}" = "ahci" ]; then
+ bootdev="${bootdev} (ahci${i},${part})"
+ elif [ "${grub_disk}" = "ata" ]; then
+ bootdev="${bootdev} (ata${i},${part})"
+ elif [ "${grub_disk}" = "nvme" ]; then
+ # TODO: do we care about other namesapces
+ bootdev="${bootdev} (nvme${i}n1,${part})"
+ fi
+ done
+ done
+ done
+
+ set pager=0
+ echo -n "Attempting to unlock encrypted volumes"
+ for dev in ${bootdev} ${raidvol}; do
+ if cryptomount "${dev}" ; then break ; fi
+ done
+ set pager=1
+ echo
+
+ search_bootcfg crypto
+
+ lvmvol=""
+
+ # after cryptomount, lvm volumes might be available
+ # using * is slow on some machines, but we use it here,
+ # just once. in so doing, we find every lvm volume
+ for vol in (*); do
+ if regexp ^\\(lvm/ $vol; then
+ lvmvol="${lvmvol} ${vol}"
+ try_bootcfg "${vol}"
+ fi
+ done
+
+ # user might have put luks inside lvm
+ set pager=0
+ echo "Attempting to unlock encrypted LVMs"
+ for vol in ${lvmvol}; do
+ cryptomount "$vol"
+ done
+ set pager=1
+ echo
+
+ search_bootcfg crypto
+
+ true # Prevent pager requiring to accept each line instead of whole screen
+}
+
+menuentry 'Search for GRUB/SYSLINUX/EXTLINUX/ISOLINUX on USB [s]' --hotkey='s' {
+ search_bootcfg usb
+}
+menuentry 'Search for GRUB/SYSLINUX/EXTLINUX/ISOLINUX on AHCI [a]' --hotkey='a' {
+ search_bootcfg ahci
+}
+menuentry 'Search for GRUB/SYSLINUX/EXTLINUX/ISOLINUX on ATA/IDE [d]' --hotkey='d' {
+ search_bootcfg ata
+}
+menuentry 'Search for GRUB/SYSLINUX/EXTLINUX/ISOLINUX on NVMe [e]' --hotkey='e' {
+ search_bootcfg nvme
+}
+if [ -f (cbfsdisk)/grub.cfg ]; then
+menuentry 'Load configuration (grub.cfg) in CBFS [t]' --hotkey='t' {
+ set root='(cbfsdisk)'
+ if [ -f /grub.cfg ]; then
+ configfile /grub.cfg
+ fi
+}
+fi
+if [ -f (cbfsdisk)/grubtest.cfg ]; then
+menuentry 'Load test configuration (grubtest.cfg) in CBFS [t]' --hotkey='t' {
+ set root='(cbfsdisk)'
+ if [ -f /grubtest.cfg ]; then
+ configfile /grubtest.cfg
+ fi
+}
+fi
+if [ -f (cbfsdisk)/u-boot ]; then
+menuentry 'U-Boot i386 payload (experimental) [u]' --hotkey='u' {
+ set root='cbfsdisk'
+ chainloader /u-boot
+}
+fi
+if [ -f (cbfsdisk)/seabios.elf ]; then
+if [ -f (cbfsdisk)/img/u-boot ]; then
+menuentry 'Load SeaBIOS (U-Boot UEFI available in the ESC menu) [b]' --hotkey='b' {
+ set root='cbfsdisk'
+ chainloader /seabios.elf
+}
+else
+menuentry 'Load SeaBIOS [b]' --hotkey='b' {
+ set root='cbfsdisk'
+ chainloader /seabios.elf
+}
+fi
+fi
+if [ -f (cbfsdisk)/img/grub2 ]; then
+if [ -f (cbfsdisk)/img/u-boot ]; then
+menuentry 'Return to SeaBIOS (U-Boot UEFI available in the ESC menu) [b]' --hotkey='b' {
+ set root='cbfsdisk'
+ chainloader /fallback/payload
+}
+else
+menuentry 'Return to SeaBIOS [b]' --hotkey='b' {
+ set root='cbfsdisk'
+ chainloader /fallback/payload
+}
+fi
+fi
+menuentry 'Poweroff [p]' --hotkey='p' {
+ halt
+}
+menuentry 'Reboot [r]' --hotkey='r' {
+ reboot
+}
+if [ -f (cbfsdisk)/img/memtest ]; then
+menuentry 'Load MemTest86+ [m]' --hotkey='m' {
+ set root='cbfsdisk'
+ chainloader /img/memtest
+}
+fi
+
+submenu 'Other [z]' --hotkey='z' {
+ menuentry 'Enable default serial terminal [s]' --hotkey='s' {
+ serial
+ terminal_input --append serial
+ terminal_output --append serial
+ }
+
+ menuentry 'Disable default serial terminal' {
+ terminal_input --remove serial
+ terminal_output --remove serial
+ }
+
+ menuentry 'Enable gfxterm' {
+ terminal_output --append gfxterm
+ terminal_output --remove vga_text
+ }
+ menuentry 'Disable gfxterm [g]' --hotkey='g' {
+ terminal_output --remove gfxterm
+ terminal_output --append vga_text
+ }
+
+ menuentry 'Enable spkmodem [a]' --hotkey='a' {
+ terminal_output --append spkmodem
+ }
+
+ menuentry 'Disable spkmodem [z]' --hotkey='z' {
+ terminal_output --remove spkmodem
+ }
+}
diff --git a/config/grub/xhci_nvme/patches/0001-mitigate-grub-s-missing-characters-for-borders-arrow.patch b/config/grub/xhci_nvme/patches/0001-mitigate-grub-s-missing-characters-for-borders-arrow.patch
new file mode 100644
index 00000000..7f489819
--- /dev/null
+++ b/config/grub/xhci_nvme/patches/0001-mitigate-grub-s-missing-characters-for-borders-arrow.patch
@@ -0,0 +1,90 @@
+From 8ce8095abbbcc69b50466cb2b890a59be5a9baed Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Sun, 31 Oct 2021 03:47:05 +0000
+Subject: [PATCH 01/21] mitigate grub's missing characters for borders/arrow
+ characters
+
+This cleans up the display on the main screen in GRUB.
+
+Just don't draw a border, at all.
+---
+ grub-core/normal/menu_text.c | 49 ++----------------------------------
+ 1 file changed, 2 insertions(+), 47 deletions(-)
+
+diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
+index 9c383e64a..8ec1dd1e8 100644
+--- a/grub-core/normal/menu_text.c
++++ b/grub-core/normal/menu_text.c
+@@ -108,47 +108,6 @@ grub_print_message_indented (const char *msg, int margin_left, int margin_right,
+ grub_print_message_indented_real (msg, margin_left, margin_right, term, 0);
+ }
+
+-static void
+-draw_border (struct grub_term_output *term, const struct grub_term_screen_geometry *geo)
+-{
+- int i;
+-
+- grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
+-
+- grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1,
+- geo->first_entry_y - 1 });
+- grub_putcode (GRUB_UNICODE_CORNER_UL, term);
+- for (i = 0; i < geo->entry_width + 1; i++)
+- grub_putcode (GRUB_UNICODE_HLINE, term);
+- grub_putcode (GRUB_UNICODE_CORNER_UR, term);
+-
+- for (i = 0; i < geo->num_entries; i++)
+- {
+- grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1,
+- geo->first_entry_y + i });
+- grub_putcode (GRUB_UNICODE_VLINE, term);
+- grub_term_gotoxy (term,
+- (struct grub_term_coordinate) { geo->first_entry_x + geo->entry_width + 1,
+- geo->first_entry_y + i });
+- grub_putcode (GRUB_UNICODE_VLINE, term);
+- }
+-
+- grub_term_gotoxy (term,
+- (struct grub_term_coordinate) { geo->first_entry_x - 1,
+- geo->first_entry_y - 1 + geo->num_entries + 1 });
+- grub_putcode (GRUB_UNICODE_CORNER_LL, term);
+- for (i = 0; i < geo->entry_width + 1; i++)
+- grub_putcode (GRUB_UNICODE_HLINE, term);
+- grub_putcode (GRUB_UNICODE_CORNER_LR, term);
+-
+- grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
+-
+- grub_term_gotoxy (term,
+- (struct grub_term_coordinate) { geo->first_entry_x - 1,
+- (geo->first_entry_y - 1 + geo->num_entries
+- + GRUB_TERM_MARGIN + 1) });
+-}
+-
+ static int
+ print_message (int nested, int edit, struct grub_term_output *term, int dry_run)
+ {
+@@ -167,10 +126,8 @@ command-line or ESC to discard edits and return to the GRUB menu."),
+ {
+ char *msg_translated;
+
+- msg_translated = grub_xasprintf (_("Use the %C and %C keys to select which "
+- "entry is highlighted."),
+- GRUB_UNICODE_UPARROW,
+- GRUB_UNICODE_DOWNARROW);
++ msg_translated = grub_xasprintf (_("Use the arrow keys to select which "
++ "entry is highlighted."));
+ if (!msg_translated)
+ return 0;
+ ret += grub_print_message_indented_real (msg_translated, STANDARD_MARGIN,
+@@ -413,8 +370,6 @@ grub_menu_init_page (int nested, int edit,
+
+ grub_term_normal_color = grub_color_menu_normal;
+ grub_term_highlight_color = grub_color_menu_highlight;
+- if (geo->border)
+- draw_border (term, geo);
+ grub_term_normal_color = old_color_normal;
+ grub_term_highlight_color = old_color_highlight;
+ geo->timeout_y = geo->first_entry_y + geo->num_entries
+--
+2.47.3
+
diff --git a/config/grub/xhci_nvme/patches/0002-say-the-name-libreboot-in-the-grub-menu.patch b/config/grub/xhci_nvme/patches/0002-say-the-name-libreboot-in-the-grub-menu.patch
new file mode 100644
index 00000000..cb0c831c
--- /dev/null
+++ b/config/grub/xhci_nvme/patches/0002-say-the-name-libreboot-in-the-grub-menu.patch
@@ -0,0 +1,25 @@
+From d073d6a6d3c63a2b37df754bb890f88482ef2a75 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Sat, 19 Nov 2022 16:30:24 +0000
+Subject: [PATCH 02/21] say the name libreboot, in the grub menu
+
+---
+ grub-core/normal/main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index de9a3f961..1fabb9c86 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -215,7 +215,7 @@ grub_normal_init_page (struct grub_term_output *term,
+
+ grub_term_cls (term);
+
+- msg_formatted = grub_xasprintf (_("GNU GRUB version %s"), PACKAGE_VERSION);
++ msg_formatted = grub_xasprintf (_("Libreboot 26.01 RC4 Magnanimous Max (GRUB menu): https://libreboot.org/"));
+ if (!msg_formatted)
+ return;
+
+--
+2.47.3
+
diff --git a/config/grub/xhci_nvme/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch b/config/grub/xhci_nvme/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch
new file mode 100644
index 00000000..3e6d9203
--- /dev/null
+++ b/config/grub/xhci_nvme/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch
@@ -0,0 +1,107 @@
+From befc0d1c61b4ba0c43981774eeff0f0f026f513d Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Mon, 30 Oct 2023 22:19:21 +0000
+Subject: [PATCH 03/21] at_keyboard coreboot: force scancodes2+translate
+
+Scan code set 2 with translation should be assumed in
+every case, as the default starting position.
+
+However, GRUB is trying to detect and use other modes
+such as set 2 without translation, or set 1 without
+translation from set 2; it also detects no-mode and
+assumes mode 1, on really old keyboards.
+
+The current behaviour has been retained, for everything
+except GRUB_MACHINE_COREBOOT; for the latter, scan code
+set 2 with translation is hardcoded, and forced in code.
+
+This is required to make keyboard initialisation work on
+the MEC5035 EC used by the Dell Latitude E6400, when
+running GRUB as a coreboot payload on that laptop. The
+EC reports scancode set 2 with translation when probed,
+but actually only outputs scancode set 1.
+
+Since GRUB is attempting to use it without translation,
+and since the machine reports set 2 with translation,
+but only ever outputs set 1 scancodes, this results in
+wrong keypresses for every key.
+
+This fix fixed that, by forcing set 2 with translation,
+treating it as set 1, but only on coreboot. This is the
+same behaviour used in GNU+Linux systems and SeaBIOS.
+With this change, GRUB keyboard initialisation now works
+just fine on those machines.
+
+This has *also* been tested on other coreboot machines
+running GRUB; several HP EliteBooks, ThinkPads and
+Dell Precision T1650. All seems to work just fine.
+
+Signed-off-by: Leah Rowe <leah@libreboot.org>
+---
+ grub-core/term/at_keyboard.c | 20 ++++++++++++++++++--
+ 1 file changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c
+index f8a129eb7..8207225c2 100644
+--- a/grub-core/term/at_keyboard.c
++++ b/grub-core/term/at_keyboard.c
+@@ -138,6 +138,7 @@ write_mode (int mode)
+ return (i != GRUB_AT_TRIES);
+ }
+
++#if !defined (GRUB_MACHINE_COREBOOT)
+ static int
+ query_mode (void)
+ {
+@@ -161,10 +162,12 @@ query_mode (void)
+ return 3;
+ return 0;
+ }
++#endif
+
+ static void
+ set_scancodes (void)
+ {
++#if !defined (GRUB_MACHINE_COREBOOT)
+ /* You must have visited computer museum. Keyboard without scancode set
+ knowledge. Assume XT. */
+ if (!grub_keyboard_orig_set)
+@@ -173,20 +176,33 @@ set_scancodes (void)
+ ps2_state.current_set = 1;
+ return;
+ }
++#endif
+
+ #if !USE_SCANCODE_SET
+ ps2_state.current_set = 1;
+ return;
+-#else
++#endif
+
++#if defined (GRUB_MACHINE_COREBOOT)
++ /* enable translation */
++ grub_keyboard_controller_write (grub_keyboard_controller_orig
++ & ~KEYBOARD_AT_DISABLE);
++#else
++ /* if not coreboot, disable translation and try mode 2 first, before 1 */
+ grub_keyboard_controller_write (grub_keyboard_controller_orig
+ & ~KEYBOARD_AT_TRANSLATE
+ & ~KEYBOARD_AT_DISABLE);
++#endif
+
+ keyboard_controller_wait_until_ready ();
+ grub_outb (KEYBOARD_COMMAND_ENABLE, KEYBOARD_REG_DATA);
+-
+ write_mode (2);
++
++#if defined (GRUB_MACHINE_COREBOOT)
++ /* mode 2 with translation, so make grub treat as set 1 */
++ ps2_state.current_set = 1;
++#else
++ /* if not coreboot, translation isn't set; test 2 and fall back to 1 */
+ ps2_state.current_set = query_mode ();
+ grub_dprintf ("atkeyb", "returned set %d\n", ps2_state.current_set);
+ if (ps2_state.current_set == 2)
+--
+2.47.3
+
diff --git a/config/grub/xhci_nvme/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch b/config/grub/xhci_nvme/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch
new file mode 100644
index 00000000..0fdcaac7
--- /dev/null
+++ b/config/grub/xhci_nvme/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch
@@ -0,0 +1,38 @@
+From abe0aa9a6edba181b0f964f3cf4bcd7155322ac1 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Tue, 31 Oct 2023 10:33:28 +0000
+Subject: [PATCH 04/21] keylayouts: don't print "Unknown key" message
+
+on keyboards with stuck keys, this results in GRUB just
+spewing it repeatedly, preventing use of GRUB.
+
+in such cases, it's still possible to use the keyboard,
+and we should let the user at least boot.
+
+it often appears when people plug in faulty usb keyboards,
+but can appear for laptop keyboards too; one of my e6400
+has stuck keys.
+
+with this patch, grub should be a bit more reliable in
+terms of user experience, when the keyboard is faulty.
+
+Signed-off-by: Leah Rowe <leah@libreboot.org>
+---
+ grub-core/commands/keylayouts.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/grub-core/commands/keylayouts.c b/grub-core/commands/keylayouts.c
+index aa3ba34f2..445fa0601 100644
+--- a/grub-core/commands/keylayouts.c
++++ b/grub-core/commands/keylayouts.c
+@@ -174,7 +174,6 @@ grub_term_map_key (grub_keyboard_key_t code, int status)
+ key = map_key_core (code, status, &alt_gr_consumed);
+
+ if (key == 0 || key == GRUB_TERM_SHIFT) {
+- grub_printf ("Unknown key 0x%x detected\n", code);
+ return GRUB_TERM_NO_KEY;
+ }
+
+--
+2.47.3
+
diff --git a/config/grub/xhci_nvme/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch b/config/grub/xhci_nvme/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch
new file mode 100644
index 00000000..cec589e1
--- /dev/null
+++ b/config/grub/xhci_nvme/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch
@@ -0,0 +1,102 @@
+From f8d8c00b9ff65bbaef029b087d6b2ad1091b39e4 Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Sun, 5 Nov 2023 16:14:58 +0000
+Subject: [PATCH 05/21] don't print missing prefix errors on the screen
+
+we do actually set the prefix. this patch modifies
+grub to still set grub_errno and return accordingly,
+so the behaviour is otherwise identical, but it will
+no longer print a warning message on the screen.
+
+Signed-off-by: Leah Rowe <leah@libreboot.org>
+---
+ grub-core/commands/keylayouts.c | 2 +-
+ grub-core/commands/loadenv.c | 2 +-
+ grub-core/commands/nativedisk.c | 2 +-
+ grub-core/efiemu/main.c | 3 +--
+ grub-core/font/font.c | 2 +-
+ grub-core/kern/dl.c | 2 +-
+ 6 files changed, 6 insertions(+), 7 deletions(-)
+
+diff --git a/grub-core/commands/keylayouts.c b/grub-core/commands/keylayouts.c
+index 445fa0601..00bcf7025 100644
+--- a/grub-core/commands/keylayouts.c
++++ b/grub-core/commands/keylayouts.c
+@@ -211,7 +211,7 @@ grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)),
+ {
+ const char *prefix = grub_env_get ("prefix");
+ if (!prefix)
+- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("variable `%s' isn't set"), "prefix");
++ return (grub_errno = GRUB_ERR_BAD_ARGUMENT);
+ filename = grub_xasprintf ("%s/layouts/%s.gkb", prefix, argv[0]);
+ if (!filename)
+ return grub_errno;
+diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c
+index 166445849..699b39bfa 100644
+--- a/grub-core/commands/loadenv.c
++++ b/grub-core/commands/loadenv.c
+@@ -58,7 +58,7 @@ open_envblk_file (char *filename,
+ prefix = grub_env_get ("prefix");
+ if (! prefix)
+ {
+- grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix");
++ grub_errno = GRUB_ERR_FILE_NOT_FOUND;
+ return 0;
+ }
+
+diff --git a/grub-core/commands/nativedisk.c b/grub-core/commands/nativedisk.c
+index 580c8d3b0..6806bff9c 100644
+--- a/grub-core/commands/nativedisk.c
++++ b/grub-core/commands/nativedisk.c
+@@ -186,7 +186,7 @@ grub_cmd_nativedisk (grub_command_t cmd __attribute__ ((unused)),
+ prefix = grub_env_get ("prefix");
+
+ if (! prefix)
+- return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix");
++ return (grub_errno = GRUB_ERR_FILE_NOT_FOUND);
+
+ if (prefix)
+ path_prefix = (prefix[0] == '(') ? grub_strchr (prefix, ')') : NULL;
+diff --git a/grub-core/efiemu/main.c b/grub-core/efiemu/main.c
+index e7037f4ed..e5d4dbff1 100644
+--- a/grub-core/efiemu/main.c
++++ b/grub-core/efiemu/main.c
+@@ -231,8 +231,7 @@ grub_efiemu_autocore (void)
+ prefix = grub_env_get ("prefix");
+
+ if (! prefix)
+- return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+- N_("variable `%s' isn't set"), "prefix");
++ return (grub_errno = GRUB_ERR_FILE_NOT_FOUND);
+
+ suffix = grub_efiemu_get_default_core_name ();
+
+diff --git a/grub-core/font/font.c b/grub-core/font/font.c
+index 18de52562..2a0fea6c8 100644
+--- a/grub-core/font/font.c
++++ b/grub-core/font/font.c
+@@ -461,7 +461,7 @@ grub_font_load (const char *filename)
+
+ if (!prefix)
+ {
+- grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix");
++ grub_errno = GRUB_ERR_FILE_NOT_FOUND;
+ goto fail;
+ }
+ file = try_open_from_prefix (prefix, filename);
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index de8c3aa8d..eac3ea48d 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -880,7 +880,7 @@ grub_dl_load (const char *name)
+ return 0;
+
+ if (! grub_dl_dir) {
+- grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix");
++ grub_errno = GRUB_ERR_FILE_NOT_FOUND;
+ return 0;
+ }
+
+--
+2.47.3
+
diff --git a/config/grub/xhci_nvme/patches/0006-don-t-print-error-if-module-not-found.patch b/config/grub/xhci_nvme/patches/0006-don-t-print-error-if-module-not-found.patch
new file mode 100644
index 00000000..afffefca
--- /dev/null
+++ b/config/grub/xhci_nvme/patches/0006-don-t-print-error-if-module-not-found.patch
@@ -0,0 +1,34 @@
+From 807a54732c3a9b056d33a0fdb0baedd44b581f0b Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Sun, 5 Nov 2023 16:36:22 +0000
+Subject: [PATCH 06/21] don't print error if module not found
+
+still set grub_errno accordingly, and otherwise
+behave the same. in libreboot, we remove a lot of
+modules but then rely on loading a grub.cfg
+provided by a distro; in almost all cases that works,
+but also in almost all cases, that will try to load
+a module we don't actually need, but then it prints
+a message. this can annoy some users, so silence it.
+
+Signed-off-by: Leah Rowe <leah@libreboot.org>
+---
+ grub-core/kern/dl.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index eac3ea48d..6d67ba54f 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -510,7 +510,7 @@ grub_dl_resolve_name (grub_dl_t mod, Elf_Ehdr *e)
+
+ s = grub_dl_find_section (e, ".modname");
+ if (!s)
+- return grub_error (GRUB_ERR_BAD_MODULE, "no module name found");
++ return (grub_errno = GRUB_ERR_BAD_MODULE);
+
+ mod->name = grub_strdup ((char *) e + s->sh_offset);
+ if (! mod->name)
+--
+2.47.3
+
diff --git a/config/grub/xhci_nvme/patches/0007-don-t-print-empty-error-messages.patch b/config/grub/xhci_nvme/patches/0007-don-t-print-empty-error-messages.patch
new file mode 100644
index 00000000..44a9c432
--- /dev/null
+++ b/config/grub/xhci_nvme/patches/0007-don-t-print-empty-error-messages.patch
@@ -0,0 +1,31 @@
+From 53ae675a60c53792b0296828fb66d414b2d3f70e Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Sun, 5 Nov 2023 17:25:20 +0000
+Subject: [PATCH 07/21] don't print empty error messages
+
+this is part two of the quest to kill the prefix
+error message. after i disabled prefix-related
+messages, it still printed "error: ." on screen.
+
+Signed-off-by: Leah Rowe <leah@libreboot.org>
+---
+ grub-core/kern/err.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/err.c b/grub-core/kern/err.c
+index ba04b57fb..dab62646d 100644
+--- a/grub-core/kern/err.c
++++ b/grub-core/kern/err.c
+@@ -116,7 +116,8 @@ grub_print_error (void)
+ {
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+- grub_err_printf (_("error: %s.\n"), grub_errmsg);
++ if (grub_strlen(grub_errmsg) > 0)
++ grub_err_printf (_("error: %s.\n"), grub_errmsg);
+ grub_err_printed_errors++;
+ }
+ }
+--
+2.47.3
+
diff --git a/config/grub/patches/0005-xhci/0001-grub-core-bus-usb-Parse-SuperSpeed-companion-descrip.patch b/config/grub/xhci_nvme/patches/0008-grub-core-bus-usb-Parse-SuperSpeed-companion-descrip.patch
index f533269f..95e9fb7b 100644
--- a/config/grub/patches/0005-xhci/0001-grub-core-bus-usb-Parse-SuperSpeed-companion-descrip.patch
+++ b/config/grub/xhci_nvme/patches/0008-grub-core-bus-usb-Parse-SuperSpeed-companion-descrip.patch
@@ -1,7 +1,8 @@
-From 90c9011f2e0350a97e3df44b0fc6dd022e04c276 Mon Sep 17 00:00:00 2001
+From 64769f3b285e8bf2c21a65fba81673a0a4f6dde3 Mon Sep 17 00:00:00 2001
From: Patrick Rudolph <patrick.rudolph@9elements.com>
Date: Sun, 15 Nov 2020 19:00:27 +0100
-Subject: [PATCH 1/8] grub-core/bus/usb: Parse SuperSpeed companion descriptors
+Subject: [PATCH 08/21] grub-core/bus/usb: Parse SuperSpeed companion
+ descriptors
Parse the SS_ENDPOINT_COMPANION descriptor, which is only present on USB 3.0
capable devices and xHCI controllers. Make the descendp an array of pointers
@@ -160,7 +161,7 @@ index f5608e330..2ae29cba1 100644
if ((endp->endp_addr & 128) && grub_usb_get_ep_type(endp)
== GRUB_USB_EP_INTERRUPT)
diff --git a/grub-core/commands/usbtest.c b/grub-core/commands/usbtest.c
-index 2c6d93fe6..55a657635 100644
+index 3184ac9af..7d128449d 100644
--- a/grub-core/commands/usbtest.c
+++ b/grub-core/commands/usbtest.c
@@ -185,7 +185,7 @@ usb_iterate (grub_usb_device_t dev, void *data __attribute__ ((unused)))
@@ -241,5 +242,5 @@ index aac5ab05a..bb2ab2e27 100644
{
grub_uint8_t length;
--
-2.39.2
+2.47.3
diff --git a/config/grub/patches/0005-xhci/0002-usb-Add-enum-for-xHCI.patch b/config/grub/xhci_nvme/patches/0009-usb-Add-enum-for-xHCI.patch
index d61da615..5b79d33c 100644
--- a/config/grub/patches/0005-xhci/0002-usb-Add-enum-for-xHCI.patch
+++ b/config/grub/xhci_nvme/patches/0009-usb-Add-enum-for-xHCI.patch
@@ -1,7 +1,7 @@
-From e111983ca5e2a52bfe2bdc5cd639b06bb2f7902d Mon Sep 17 00:00:00 2001
+From 43522cfb0ec375be1b6a226103e9a55d4b88ee1d Mon Sep 17 00:00:00 2001
From: Patrick Rudolph <patrick.rudolph@9elements.com>
-Date: Sun, 15 Nov 2020 19:47:06 +0100
-Subject: [PATCH 2/8] usb: Add enum for xHCI
+Date: Mon, 7 Dec 2020 08:41:22 +0100
+Subject: [PATCH 09/21] usb: Add enum for xHCI
Will be used in future patches.
@@ -25,5 +25,5 @@ index 688c11f6d..ea6ee8c2c 100644
typedef int (*grub_usb_iterate_hook_t) (grub_usb_device_t dev, void *data);
--
-2.39.2
+2.47.3
diff --git a/config/grub/patches/0005-xhci/0003-usbtrans-Set-default-maximum-packet-size.patch b/config/grub/xhci_nvme/patches/0010-usbtrans-Set-default-maximum-packet-size.patch
index 70e73ca2..c6196f87 100644
--- a/config/grub/patches/0005-xhci/0003-usbtrans-Set-default-maximum-packet-size.patch
+++ b/config/grub/xhci_nvme/patches/0010-usbtrans-Set-default-maximum-packet-size.patch
@@ -1,7 +1,7 @@
-From 3e25c83a1d1c6e149c7e9f0660ddadb2beca2476 Mon Sep 17 00:00:00 2001
+From 296f9b732393315bc3a91f8531f6ac9e7b9f43e0 Mon Sep 17 00:00:00 2001
From: Patrick Rudolph <patrick.rudolph@9elements.com>
-Date: Sun, 15 Nov 2020 19:48:03 +0100
-Subject: [PATCH 3/8] usbtrans: Set default maximum packet size
+Date: Mon, 7 Dec 2020 08:41:23 +0100
+Subject: [PATCH 10/21] usbtrans: Set default maximum packet size
Set the maximum packet size to 512 for SuperSpeed devices.
@@ -29,5 +29,5 @@ index c5680b33a..c1080bb33 100644
max = 64;
--
-2.39.2
+2.47.3
diff --git a/config/grub/patches/0005-xhci/0004-grub-core-bus-usb-Add-function-pointer-for-attach-de.patch b/config/grub/xhci_nvme/patches/0011-grub-core-bus-usb-Add-function-pointer-for-attach-de.patch
index a090e0ea..ac53118a 100644
--- a/config/grub/patches/0005-xhci/0004-grub-core-bus-usb-Add-function-pointer-for-attach-de.patch
+++ b/config/grub/xhci_nvme/patches/0011-grub-core-bus-usb-Add-function-pointer-for-attach-de.patch
@@ -1,8 +1,8 @@
-From 89701aba00caa81bb566ab10da0c89264393be30 Mon Sep 17 00:00:00 2001
+From de471d16aeaab3cf12956d783604f22944ea7ed0 Mon Sep 17 00:00:00 2001
From: Patrick Rudolph <patrick.rudolph@9elements.com>
Date: Sun, 15 Nov 2020 19:51:42 +0100
-Subject: [PATCH 4/8] grub-core/bus/usb: Add function pointer for attach/detach
- events
+Subject: [PATCH 11/21] grub-core/bus/usb: Add function pointer for
+ attach/detach events
The xHCI code needs to be called for attaching or detaching a device.
Introduce two functions pointers and call it from the USB hub code.
@@ -19,7 +19,7 @@ Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
5 files changed, 29 insertions(+)
diff --git a/grub-core/bus/usb/ehci.c b/grub-core/bus/usb/ehci.c
-index 9abebc6bd..953b851c0 100644
+index 2db07c7c0..1ee056015 100644
--- a/grub-core/bus/usb/ehci.c
+++ b/grub-core/bus/usb/ehci.c
@@ -1812,6 +1812,8 @@ static struct grub_usb_controller_dev usb_controller = {
@@ -117,5 +117,5 @@ index ea6ee8c2c..4dd179db2 100644
grub_uint64_t pending_reset;
--
-2.39.2
+2.47.3
diff --git a/config/grub/patches/0005-xhci/0005-grub-core-bus-usb-usbhub-Add-new-private-fields-for-.patch b/config/grub/xhci_nvme/patches/0012-grub-core-bus-usb-usbhub-Add-new-private-fields-for-.patch
index 7d69c3a6..fbedfc77 100644
--- a/config/grub/patches/0005-xhci/0005-grub-core-bus-usb-usbhub-Add-new-private-fields-for-.patch
+++ b/config/grub/xhci_nvme/patches/0012-grub-core-bus-usb-usbhub-Add-new-private-fields-for-.patch
@@ -1,8 +1,8 @@
-From 5e5d74a4531770258e21dedd45c33f1a9d3afa6b Mon Sep 17 00:00:00 2001
+From 8966fadb8c19fd5c30dd585a53f465767c1cd627 Mon Sep 17 00:00:00 2001
From: Patrick Rudolph <patrick.rudolph@9elements.com>
-Date: Sun, 15 Nov 2020 19:54:40 +0100
-Subject: [PATCH 5/8] grub-core/bus/usb/usbhub: Add new private fields for xHCI
- controller
+Date: Mon, 7 Dec 2020 08:41:25 +0100
+Subject: [PATCH 12/21] grub-core/bus/usb/usbhub: Add new private fields for
+ xHCI controller
Store the root port number, the route, consisting out of the port ID
in each nibble, and a pointer to driver private data.
@@ -73,5 +73,5 @@ index 4dd179db2..609faf7d0 100644
--
-2.39.2
+2.47.3
diff --git a/config/grub/patches/0005-xhci/0006-grub-core-bus-usb-Add-xhci-support.patch b/config/grub/xhci_nvme/patches/0013-grub-core-bus-usb-Add-xhci-support.patch
index 11df42d8..1393092a 100644
--- a/config/grub/patches/0005-xhci/0006-grub-core-bus-usb-Add-xhci-support.patch
+++ b/config/grub/xhci_nvme/patches/0013-grub-core-bus-usb-Add-xhci-support.patch
@@ -1,7 +1,7 @@
-From fe3a0bce527e059e9121eb5ad2c3cc099f07a4bf Mon Sep 17 00:00:00 2001
+From 764e79efa273fadb8fc4b5ec286dd9e5688a58e8 Mon Sep 17 00:00:00 2001
From: Patrick Rudolph <patrick.rudolph@9elements.com>
-Date: Sun, 15 Nov 2020 19:59:25 +0100
-Subject: [PATCH 6/8] grub-core/bus/usb: Add xhci support
+Date: Mon, 7 Dec 2020 08:41:26 +0100
+Subject: [PATCH 13/21] grub-core/bus/usb: Add xhci support
Add support for xHCI USB controllers.
The code is based on seabios implementation, but has been heavily
@@ -41,13 +41,6 @@ TODO:
* Test on USB3 hubs
* Support for USB 3.1 and USB 3.2 controllers
-Tested on qemu using coreboot and grub as payload:
-
-qemu-system-x86_64 -M q35 -bios $firmware -device qemu-xhci,id=xhci -accel kvm -m 1024M \
- -device usb-storage,drive=thumbdrive,bus=xhci.0,port=3 \
- -drive if=none,format=raw,id=thumbdrive,file=ubuntu-20.04.1-desktop-amd64.iso \
- -device usb-kbd,bus=xhci.0
-
Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Signed-off-by: sylv <sylv@sylv.io>
---
@@ -74,10 +67,10 @@ index 43635d5ff..65016f856 100644
endif
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
-index fb6078a34..64c3806ab 100644
+index 0cf155128..ec4c76ea8 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
-@@ -667,6 +667,13 @@ module = {
+@@ -675,6 +675,13 @@ module = {
enable = arm_coreboot;
};
@@ -2810,5 +2803,5 @@ index 609faf7d0..eb71fa1c7 100644
#endif /* GRUB_USB_H */
--
-2.39.2
+2.47.3
diff --git a/config/grub/patches/0005-xhci/0007-grub-core-bus-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch b/config/grub/xhci_nvme/patches/0014-grub-core-bus-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch
index a37bbd6b..bb5c4fd8 100644
--- a/config/grub/patches/0005-xhci/0007-grub-core-bus-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch
+++ b/config/grub/xhci_nvme/patches/0014-grub-core-bus-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch
@@ -1,7 +1,7 @@
-From 2a2c64f6ea62337c1263a70f6ca9a9bade66b78b Mon Sep 17 00:00:00 2001
+From f289290da21c2eafdf52ae4859623971a3da07bb Mon Sep 17 00:00:00 2001
From: Patrick Rudolph <patrick.rudolph@9elements.com>
-Date: Thu, 3 Dec 2020 13:44:55 +0100
-Subject: [PATCH 7/8] grub-core/bus/usb/usbhub: Add xHCI non root hub support
+Date: Mon, 7 Dec 2020 08:41:27 +0100
+Subject: [PATCH 14/21] grub-core/bus/usb/usbhub: Add xHCI non root hub support
Tested on Intel PCH C246, the USB3 hub can be configured by grub.
@@ -123,5 +123,5 @@ index 039ebed65..d6c3f71dc 100644
#define GRUB_USB_FEATURE_ENDP_HALT 0x00
#define GRUB_USB_FEATURE_DEV_REMOTE_WU 0x01
--
-2.39.2
+2.47.3
diff --git a/config/grub/xhci_nvme/patches/0015-xHCI-also-accept-SBRN-0x31-and-0x32.patch b/config/grub/xhci_nvme/patches/0015-xHCI-also-accept-SBRN-0x31-and-0x32.patch
new file mode 100644
index 00000000..9deb581d
--- /dev/null
+++ b/config/grub/xhci_nvme/patches/0015-xHCI-also-accept-SBRN-0x31-and-0x32.patch
@@ -0,0 +1,26 @@
+From e8bb5e7445dad3514c88d5286563781f27233e5e Mon Sep 17 00:00:00 2001
+From: Sven Anderson <sven@anderson.de>
+Date: Sat, 28 May 2022 21:39:23 +0200
+Subject: [PATCH 15/21] xHCI: also accept SBRN 0x31 and 0x32
+
+Signed-off-by: Sven Anderson <sven@anderson.de>
+---
+ grub-core/bus/usb/xhci-pci.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/bus/usb/xhci-pci.c b/grub-core/bus/usb/xhci-pci.c
+index a5bd3c97d..cde21f57a 100644
+--- a/grub-core/bus/usb/xhci-pci.c
++++ b/grub-core/bus/usb/xhci-pci.c
+@@ -76,7 +76,7 @@ grub_xhci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
+ /* Check Serial Bus Release Number */
+ addr = grub_pci_make_address (dev, GRUB_XHCI_PCI_SBRN_REG);
+ release = grub_pci_read_byte (addr);
+- if (release != 0x30)
++ if (release != 0x30 && release != 0x31 &&release != 0x32)
+ {
+ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: Wrong SBRN: %0x\n",
+ release);
+--
+2.47.3
+
diff --git a/config/grub/xhci_nvme/patches/0016-xhci-fix-port-indexing.patch b/config/grub/xhci_nvme/patches/0016-xhci-fix-port-indexing.patch
new file mode 100644
index 00000000..b1cb368a
--- /dev/null
+++ b/config/grub/xhci_nvme/patches/0016-xhci-fix-port-indexing.patch
@@ -0,0 +1,43 @@
+From 3db55ea63bc2c4fb41f7489a77a42c821256bbf5 Mon Sep 17 00:00:00 2001
+From: Sven Anderson <sven@anderson.de>
+Date: Mon, 13 Jan 2025 19:51:41 +0100
+Subject: [PATCH 16/21] xhci: fix port indexing
+
+---
+ grub-core/bus/usb/xhci.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/bus/usb/xhci.c b/grub-core/bus/usb/xhci.c
+index f4591ffb5..dc89b9619 100644
+--- a/grub-core/bus/usb/xhci.c
++++ b/grub-core/bus/usb/xhci.c
+@@ -2250,7 +2250,7 @@ grub_xhci_detect_dev (grub_usb_controller_t dev, int port, int *changed)
+
+ *changed = 0;
+ grub_dprintf("xhci", "%s: dev=%p USB%d_%d port %d\n", __func__, dev,
+- x->psids[port-1].major, x->psids[port-1].minor, port);
++ x->psids[port].major, x->psids[port].minor, port);
+
+ /* On shutdown advertise all ports as disconnected. This will trigger
+ * a gracefull detatch. */
+@@ -2285,13 +2285,13 @@ grub_xhci_detect_dev (grub_usb_controller_t dev, int port, int *changed)
+ if (!(portsc & GRUB_XHCI_PORTSC_CCS))
+ return GRUB_USB_SPEED_NONE;
+
+- for (grub_uint8_t i = 0; i < 16 && x->psids[port-1].psids[i].id > 0; i++)
++ for (grub_uint8_t i = 0; i < 16 && x->psids[port].psids[i].id > 0; i++)
+ {
+- if (x->psids[port-1].psids[i].id == speed)
++ if (x->psids[port].psids[i].id == speed)
+ {
+ grub_dprintf("xhci", "%s: grub_usb_speed = %d\n", __func__,
+- x->psids[port-1].psids[i].grub_usb_speed );
+- return x->psids[port-1].psids[i].grub_usb_speed;
++ x->psids[port].psids[i].grub_usb_speed );
++ return x->psids[port].psids[i].grub_usb_speed;
+ }
+ }
+
+--
+2.47.3
+
diff --git a/config/grub/xhci_nvme/patches/0017-xhci-configure-TT-for-non-root-hubs.patch b/config/grub/xhci_nvme/patches/0017-xhci-configure-TT-for-non-root-hubs.patch
new file mode 100644
index 00000000..fb8ed0b4
--- /dev/null
+++ b/config/grub/xhci_nvme/patches/0017-xhci-configure-TT-for-non-root-hubs.patch
@@ -0,0 +1,98 @@
+From a82ef95fffc0a869e90467ce4f7c28282c084518 Mon Sep 17 00:00:00 2001
+From: Sven Anderson <sven@anderson.de>
+Date: Mon, 13 Jan 2025 20:26:32 +0100
+Subject: [PATCH 17/21] xhci: configure TT for non-root-hubs
+
+---
+ grub-core/bus/usb/usbhub.c | 6 +++++
+ grub-core/bus/usb/xhci.c | 45 +++++++++++++++++++++++++++++++++-----
+ include/grub/usb.h | 2 ++
+ 3 files changed, 47 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c
+index e96505aa9..629b3ed53 100644
+--- a/grub-core/bus/usb/usbhub.c
++++ b/grub-core/bus/usb/usbhub.c
+@@ -818,3 +818,9 @@ grub_usb_iterate (grub_usb_iterate_hook_t hook, void *hook_data)
+
+ return 0;
+ }
++
++grub_usb_device_t
++grub_usb_get_dev (int addr)
++{
++ return grub_usb_devs[addr];
++}
+diff --git a/grub-core/bus/usb/xhci.c b/grub-core/bus/usb/xhci.c
+index dc89b9619..88c9ac57f 100644
+--- a/grub-core/bus/usb/xhci.c
++++ b/grub-core/bus/usb/xhci.c
+@@ -623,13 +623,46 @@ grub_xhci_alloc_inctx(struct grub_xhci *x, int maxepid,
+ break;
+ }
+
+- /* Route is greater zero on devices that are connected to a non root hub */
+- if (dev->route)
+- {
+- /* FIXME: Implement this code for non SuperSpeed hub devices */
++ /* Set routing string */
++ slot->ctx[0] |= dev->route;
++
++ /* Set root hub port number */
++ slot->ctx[1] |= (dev->root_port + 1) << 16;
++
++ if (dev->split_hubaddr && (dev->speed == GRUB_USB_SPEED_LOW ||
++ dev->speed == GRUB_USB_SPEED_FULL)) {
++
++ grub_usb_device_t hubdev = grub_usb_get_dev(dev->split_hubaddr);
++
++ if (!hubdev || hubdev->descdev.class != GRUB_USB_CLASS_HUB) {
++ grub_dprintf("xhci", "Invalid hub device at addr %d!\n", dev->split_hubaddr);
++ return NULL;
++ }
++
++ struct grub_xhci_priv *hub_priv = hubdev->xhci_priv;
++ if (!hub_priv) {
++ grub_dprintf("xhci", "Hub has no xhci_priv!\n");
++ return NULL;
++ }
++
++ if (hubdev->speed == GRUB_USB_SPEED_HIGH) {
++ /* Direct connection to high-speed hub - set up TT */
++ grub_dprintf("xhci", "Direct high-speed hub connection - configuring TT with "
++ "hub slot %d port %d\n", hub_priv->slotid, dev->split_hubport);
++ slot->ctx[2] |= hub_priv->slotid;
++ slot->ctx[2] |= dev->split_hubport << 8;
+ }
+- slot->ctx[0] |= dev->route;
+- slot->ctx[1] |= (dev->root_port+1) << 16;
++ else {
++ /* Hub is not high-speed, inherit TT settings from parent */
++ volatile struct grub_xhci_slotctx *hubslot;
++ grub_dprintf("xhci", "Non high-speed hub - inheriting TT settings from parent\n");
++ hubslot = grub_dma_phys2virt(x->devs[hub_priv->slotid].ptr_low, x->devs_dma);
++ slot->ctx[2] = hubslot->ctx[2];
++ }
++ }
++
++ grub_dprintf("xhci", "Slot context: ctx[0]=0x%08x ctx[1]=0x%08x ctx[2]=0x%08x\n",
++ slot->ctx[0], slot->ctx[1], slot->ctx[2]);
+
+ grub_arch_sync_dma_caches(in, size);
+
+diff --git a/include/grub/usb.h b/include/grub/usb.h
+index eb71fa1c7..df97a60cc 100644
+--- a/include/grub/usb.h
++++ b/include/grub/usb.h
+@@ -62,6 +62,8 @@ typedef int (*grub_usb_controller_iterate_hook_t) (grub_usb_controller_t dev,
+ /* Call HOOK with each device, until HOOK returns non-zero. */
+ int grub_usb_iterate (grub_usb_iterate_hook_t hook, void *hook_data);
+
++grub_usb_device_t grub_usb_get_dev (int addr);
++
+ grub_usb_err_t grub_usb_device_initialize (grub_usb_device_t dev);
+
+ grub_usb_err_t grub_usb_get_descriptor (grub_usb_device_t dev,
+--
+2.47.3
+
diff --git a/config/grub/patches/0005-xhci/0008-Fix-compilation-on-x86_64.patch b/config/grub/xhci_nvme/patches/0018-Fix-compilation-on-x86_64.patch
index af79c3d0..70a1a22c 100644
--- a/config/grub/patches/0005-xhci/0008-Fix-compilation-on-x86_64.patch
+++ b/config/grub/xhci_nvme/patches/0018-Fix-compilation-on-x86_64.patch
@@ -1,7 +1,7 @@
-From 871d768f8c5c960cb0d9761a9028b16882e1a7d3 Mon Sep 17 00:00:00 2001
+From cc671d76816c8370a85e289d5ac7bdf1f687ff3a Mon Sep 17 00:00:00 2001
From: Patrick Rudolph <patrick.rudolph@9elements.com>
Date: Wed, 24 Feb 2021 08:25:41 +0100
-Subject: [PATCH 8/8] Fix compilation on x86_64
+Subject: [PATCH 18/21] Fix compilation on x86_64
Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
---
@@ -9,7 +9,7 @@ Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/grub-core/bus/usb/xhci.c b/grub-core/bus/usb/xhci.c
-index f4591ffb5..3495bb919 100644
+index 88c9ac57f..9b9bae6e5 100644
--- a/grub-core/bus/usb/xhci.c
+++ b/grub-core/bus/usb/xhci.c
@@ -184,7 +184,7 @@ enum
@@ -36,7 +36,7 @@ index f4591ffb5..3495bb919 100644
static inline grub_uint32_t
grub_xhci_port_read (struct grub_xhci *x, grub_uint32_t port)
{
-@@ -664,7 +672,7 @@ static void xhci_process_events(struct grub_xhci *x)
+@@ -697,7 +705,7 @@ static void xhci_process_events(struct grub_xhci *x)
case ER_TRANSFER:
case ER_COMMAND_COMPLETE:
{
@@ -45,7 +45,7 @@ index f4591ffb5..3495bb919 100644
struct grub_xhci_ring *ring = XHCI_RING(rtrb);
volatile struct grub_xhci_trb *evt = &ring->evt;
grub_uint32_t eidx = rtrb - ring->ring + 1;
-@@ -697,9 +705,9 @@ static void xhci_process_events(struct grub_xhci *x)
+@@ -730,9 +738,9 @@ static void xhci_process_events(struct grub_xhci *x)
}
grub_xhci_write32(&evts->nidx, nidx);
volatile struct grub_xhci_ir *ir = x->ir;
@@ -58,7 +58,7 @@ index f4591ffb5..3495bb919 100644
}
}
-@@ -800,7 +808,7 @@ static void xhci_trb_queue(volatile struct grub_xhci_ring *ring,
+@@ -833,7 +841,7 @@ static void xhci_trb_queue(volatile struct grub_xhci_ring *ring,
grub_uint32_t xferlen, grub_uint32_t flags)
{
grub_dprintf("xhci", "%s: ring %p data %llx len %d flags 0x%x remain 0x%x\n", __func__,
@@ -67,7 +67,7 @@ index f4591ffb5..3495bb919 100644
if (xhci_ring_full(ring))
{
-@@ -1907,7 +1915,7 @@ grub_xhci_setup_transfer (grub_usb_controller_t dev,
+@@ -1940,7 +1948,7 @@ grub_xhci_setup_transfer (grub_usb_controller_t dev,
if (transfer->type == GRUB_USB_TRANSACTION_TYPE_CONTROL)
{
volatile struct grub_usb_packet_setup *setupdata;
@@ -76,7 +76,7 @@ index f4591ffb5..3495bb919 100644
grub_dprintf("xhci", "%s: CONTROLL TRANS req %d\n", __func__, setupdata->request);
grub_dprintf("xhci", "%s: CONTROLL TRANS length %d\n", __func__, setupdata->length);
-@@ -1974,7 +1982,7 @@ grub_xhci_setup_transfer (grub_usb_controller_t dev,
+@@ -2007,7 +2015,7 @@ grub_xhci_setup_transfer (grub_usb_controller_t dev,
/* Assume the ring has enough free space for all TRBs */
if (flags & TRB_TR_IDT && tr->size <= (int)sizeof(inline_data))
{
@@ -86,5 +86,5 @@ index f4591ffb5..3495bb919 100644
}
else
--
-2.39.2
+2.47.3
diff --git a/config/grub/xhci_nvme/patches/0019-Add-native-NVMe-driver-based-on-SeaBIOS.patch b/config/grub/xhci_nvme/patches/0019-Add-native-NVMe-driver-based-on-SeaBIOS.patch
new file mode 100644
index 00000000..f09ae69d
--- /dev/null
+++ b/config/grub/xhci_nvme/patches/0019-Add-native-NVMe-driver-based-on-SeaBIOS.patch
@@ -0,0 +1,1074 @@
+From 467fe4c5a98c0cfc1b357ec8acc360a03b5f7038 Mon Sep 17 00:00:00 2001
+From: Mate Kukri <km@mkukri.xyz>
+Date: Mon, 20 May 2024 11:43:35 +0100
+Subject: [PATCH 19/21] Add native NVMe driver based on SeaBIOS
+
+Tested to successfully boot Debian on QEMU and OptiPlex 3050.
+
+Signed-off-by: Mate Kukri <km@mkukri.xyz>
+---
+ Makefile.am | 2 +-
+ grub-core/Makefile.core.def | 6 +
+ grub-core/commands/nativedisk.c | 1 +
+ grub-core/disk/nvme-int.h | 208 +++++++++
+ grub-core/disk/nvme.c | 781 ++++++++++++++++++++++++++++++++
+ include/grub/disk.h | 1 +
+ 6 files changed, 998 insertions(+), 1 deletion(-)
+ create mode 100644 grub-core/disk/nvme-int.h
+ create mode 100644 grub-core/disk/nvme.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 65016f856..7bc0866ba 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -434,7 +434,7 @@ if COND_i386_coreboot
+ FS_PAYLOAD_MODULES ?= $(shell cat grub-core/fs.lst)
+ default_payload.elf: grub-mkstandalone grub-mkimage FORCE
+ test -f $@ && rm $@ || true
+- pkgdatadir=. ./grub-mkstandalone --grub-mkimage=./grub-mkimage -O i386-coreboot -o $@ --modules='ahci pata xhci ehci uhci ohci usb_keyboard usbms part_msdos ext2 fat at_keyboard part_gpt usbserial_usbdebug cbfs' --install-modules='ls linux search configfile normal cbtime cbls memrw iorw minicmd lsmmap lspci halt reboot hexdump pcidump regexp setpci lsacpi chain test serial multiboot cbmemc linux16 gzio echo help syslinuxcfg xnu $(FS_PAYLOAD_MODULES) password_pbkdf2 $(EXTRA_PAYLOAD_MODULES)' --fonts= --themes= --locales= -d grub-core/ /boot/grub/grub.cfg=$(srcdir)/coreboot.cfg
++ pkgdatadir=. ./grub-mkstandalone --grub-mkimage=./grub-mkimage -O i386-coreboot -o $@ --modules='ahci pata nvme xhci ehci uhci ohci usb_keyboard usbms part_msdos ext2 fat at_keyboard part_gpt usbserial_usbdebug cbfs' --install-modules='ls linux search configfile normal cbtime cbls memrw iorw minicmd lsmmap lspci halt reboot hexdump pcidump regexp setpci lsacpi chain test serial multiboot cbmemc linux16 gzio echo help syslinuxcfg xnu $(FS_PAYLOAD_MODULES) password_pbkdf2 $(EXTRA_PAYLOAD_MODULES)' --fonts= --themes= --locales= -d grub-core/ /boot/grub/grub.cfg=$(srcdir)/coreboot.cfg
+ endif
+
+ endif
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index ec4c76ea8..08b83ad06 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -2780,3 +2780,9 @@ module = {
+ cflags = '-Wno-uninitialized';
+ cppflags = '-I$(srcdir)/lib/libtasn1-grub -I$(srcdir)/tests/asn1/';
+ };
++
++module = {
++ name = nvme;
++ common = disk/nvme.c;
++ enable = pci;
++};
+diff --git a/grub-core/commands/nativedisk.c b/grub-core/commands/nativedisk.c
+index 6806bff9c..fd68a513e 100644
+--- a/grub-core/commands/nativedisk.c
++++ b/grub-core/commands/nativedisk.c
+@@ -78,6 +78,7 @@ get_uuid (const char *name, char **uuid, int getnative)
+ case GRUB_DISK_DEVICE_ATA_ID:
+ case GRUB_DISK_DEVICE_SCSI_ID:
+ case GRUB_DISK_DEVICE_XEN:
++ case GRUB_DISK_DEVICE_NVME_ID:
+ if (getnative)
+ break;
+ /* FALLTHROUGH */
+diff --git a/grub-core/disk/nvme-int.h b/grub-core/disk/nvme-int.h
+new file mode 100644
+index 000000000..1295b58aa
+--- /dev/null
++++ b/grub-core/disk/nvme-int.h
+@@ -0,0 +1,208 @@
++// NVMe datastructures and constants
++//
++// Copyright 2017 Amazon.com, Inc. or its affiliates.
++//
++// This file may be distributed under the terms of the GNU LGPLv3 license.
++
++#ifndef __NVME_INT_H
++#define __NVME_INT_H
++
++#include <grub/types.h>
++
++/* Data structures */
++
++/* The register file of a NVMe host controller. This struct follows the naming
++ scheme in the NVMe specification. */
++struct nvme_reg {
++ grub_uint64_t cap; /* controller capabilities */
++ grub_uint32_t vs; /* version */
++ grub_uint32_t intms; /* interrupt mask set */
++ grub_uint32_t intmc; /* interrupt mask clear */
++ grub_uint32_t cc; /* controller configuration */
++ grub_uint32_t _res0;
++ grub_uint32_t csts; /* controller status */
++ grub_uint32_t _res1;
++ grub_uint32_t aqa; /* admin queue attributes */
++ grub_uint64_t asq; /* admin submission queue base address */
++ grub_uint64_t acq; /* admin completion queue base address */
++};
++
++/* Submission queue entry */
++struct nvme_sqe {
++ union {
++ grub_uint32_t dword[16];
++ struct {
++ grub_uint32_t cdw0; /* Command DWORD 0 */
++ grub_uint32_t nsid; /* Namespace ID */
++ grub_uint64_t _res0;
++ grub_uint64_t mptr; /* metadata ptr */
++
++ grub_uint64_t dptr_prp1;
++ grub_uint64_t dptr_prp2;
++ };
++ };
++};
++
++/* Completion queue entry */
++struct nvme_cqe {
++ union {
++ grub_uint32_t dword[4];
++ struct {
++ grub_uint32_t cdw0;
++ grub_uint32_t _res0;
++ grub_uint16_t sq_head;
++ grub_uint16_t sq_id;
++ grub_uint16_t cid;
++ grub_uint16_t status;
++ };
++ };
++};
++
++/* The common part of every submission or completion queue. */
++struct nvme_queue {
++ grub_uint32_t *dbl; /* doorbell */
++ grub_uint16_t mask; /* length - 1 */
++};
++
++struct nvme_cq {
++ struct nvme_queue common;
++ struct nvme_cqe *cqe;
++
++ /* We have read upto (but not including) this entry in the queue. */
++ grub_uint16_t head;
++
++ /* The current phase bit the controller uses to indicate that it has written
++ a new entry. This is inverted after each wrap. */
++ unsigned phase : 1;
++};
++
++struct nvme_sq {
++ struct nvme_queue common;
++ struct nvme_sqe *sqe;
++
++ /* Corresponding completion queue. We only support a single SQ per CQ. */
++ struct nvme_cq *cq;
++
++ /* The last entry the controller has fetched. */
++ grub_uint16_t head;
++
++ /* The last value we have written to the tail doorbell. */
++ grub_uint16_t tail;
++};
++
++struct nvme_ctrl {
++ grub_pci_device_t pci;
++ struct nvme_reg volatile *reg;
++
++ grub_uint32_t ctrlnum;
++
++ grub_uint32_t doorbell_stride; /* in bytes */
++
++ struct nvme_sq admin_sq;
++ struct nvme_cq admin_cq;
++
++ grub_uint32_t ns_count;
++
++ struct nvme_sq io_sq;
++ struct nvme_cq io_cq;
++};
++
++struct nvme_namespace {
++ struct nvme_namespace *next;
++ struct nvme_namespace **prev;
++
++ char *devname;
++
++ grub_uint32_t nsnum;
++
++ struct nvme_ctrl *ctrl;
++
++ grub_uint32_t ns_id;
++
++ grub_uint64_t lba_count; /* The total amount of sectors. */
++
++ grub_uint32_t block_size;
++ grub_uint32_t metadata_size;
++ grub_uint32_t max_req_size;
++};
++
++/* Data structures for NVMe admin identify commands */
++
++struct nvme_identify_ctrl {
++ grub_uint16_t vid;
++ grub_uint16_t ssvid;
++ char sn[20];
++ char mn[40];
++ char fr[8];
++
++ grub_uint8_t rab;
++ grub_uint8_t ieee[3];
++ grub_uint8_t cmic;
++ grub_uint8_t mdts;
++
++ char _boring[516 - 78];
++
++ grub_uint32_t nn; /* number of namespaces */
++};
++
++struct nvme_identify_ns_list {
++ grub_uint32_t ns_id[1024];
++};
++
++struct nvme_lba_format {
++ grub_uint16_t ms;
++ grub_uint8_t lbads;
++ grub_uint8_t rp;
++};
++
++struct nvme_identify_ns {
++ grub_uint64_t nsze;
++ grub_uint64_t ncap;
++ grub_uint64_t nuse;
++ grub_uint8_t nsfeat;
++ grub_uint8_t nlbaf;
++ grub_uint8_t flbas;
++
++ char _boring[128 - 27];
++
++ struct nvme_lba_format lbaf[16];
++};
++
++union nvme_identify {
++ struct nvme_identify_ns ns;
++ struct nvme_identify_ctrl ctrl;
++ struct nvme_identify_ns_list ns_list;
++};
++
++/* NVMe constants */
++
++#define NVME_CAP_CSS_NVME (1ULL << 37)
++
++#define NVME_CSTS_FATAL (1U << 1)
++#define NVME_CSTS_RDY (1U << 0)
++
++#define NVME_CC_EN (1U << 0)
++
++#define NVME_SQE_OPC_ADMIN_CREATE_IO_SQ 1U
++#define NVME_SQE_OPC_ADMIN_CREATE_IO_CQ 5U
++#define NVME_SQE_OPC_ADMIN_IDENTIFY 6U
++
++#define NVME_SQE_OPC_IO_WRITE 1U
++#define NVME_SQE_OPC_IO_READ 2U
++
++#define NVME_ADMIN_IDENTIFY_CNS_ID_NS 0U
++#define NVME_ADMIN_IDENTIFY_CNS_ID_CTRL 1U
++#define NVME_ADMIN_IDENTIFY_CNS_GET_NS_LIST 2U
++
++#define NVME_CQE_DW3_P (1U << 16)
++
++#define NVME_PAGE_SIZE 4096
++#define NVME_PAGE_MASK ~(NVME_PAGE_SIZE - 1)
++
++/* Length for the queue entries. */
++#define NVME_SQE_SIZE_LOG 6
++#define NVME_CQE_SIZE_LOG 4
++
++#endif
++
++/* EOF */
+diff --git a/grub-core/disk/nvme.c b/grub-core/disk/nvme.c
+new file mode 100644
+index 000000000..093237c70
+--- /dev/null
++++ b/grub-core/disk/nvme.c
+@@ -0,0 +1,781 @@
++// Low level NVMe disk access
++//
++// Based on SeaBIOS NVMe driver - Copyright 2017 Amazon.com, Inc. or its affiliates.
++// Port to GRUB2 done by Mate Kukri
++//
++// This file may be distributed under the terms of the GNU LGPLv3 license.
++
++#include <grub/disk.h>
++#include <grub/dl.h>
++#include <grub/pci.h>
++#include "nvme-int.h"
++
++GRUB_MOD_LICENSE ("GPLv3"); /* LGPLv3 in reality but it is GPLv3 compatible */
++
++static grub_uint32_t grub_nvme_ctrlcnt;
++static grub_uint32_t grub_nvme_nscnt;
++
++static struct nvme_namespace *grub_nvme_namespaces;
++
++// Page aligned "dma bounce buffer" of size NVME_PAGE_SIZE
++static void *nvme_dma_buffer;
++
++static void *
++zalloc_page_aligned(grub_uint32_t size)
++{
++ void *res = grub_memalign(NVME_PAGE_SIZE, size);
++ if (res) grub_memset(res, 0, size);
++ return res;
++}
++
++static void
++nvme_init_queue_common(struct nvme_ctrl *ctrl, struct nvme_queue *q, grub_uint16_t q_idx,
++ grub_uint16_t length)
++{
++ grub_memset(q, 0, sizeof(*q));
++ q->dbl = (grub_uint32_t *)((char *)ctrl->reg + 0x1000 + q_idx * ctrl->doorbell_stride);
++ grub_dprintf("nvme", " q %p q_idx %u dbl %p\n", q, q_idx, q->dbl);
++ q->mask = length - 1;
++}
++
++static int
++nvme_init_sq(struct nvme_ctrl *ctrl, struct nvme_sq *sq, grub_uint16_t q_idx, grub_uint16_t length,
++ struct nvme_cq *cq)
++{
++ nvme_init_queue_common(ctrl, &sq->common, q_idx, length);
++ sq->sqe = zalloc_page_aligned(sizeof(*sq->sqe) * length);
++
++ if (!sq->sqe) {
++ return -1;
++ }
++
++ grub_dprintf("nvme", "sq %p q_idx %u sqe %p\n", sq, q_idx, sq->sqe);
++ sq->cq = cq;
++ sq->head = 0;
++ sq->tail = 0;
++
++ return 0;
++}
++
++static int
++nvme_init_cq(struct nvme_ctrl *ctrl, struct nvme_cq *cq, grub_uint16_t q_idx, grub_uint16_t length)
++{
++ nvme_init_queue_common(ctrl, &cq->common, q_idx, length);
++ cq->cqe = zalloc_page_aligned(sizeof(*cq->cqe) * length);
++ if (!cq->cqe) {
++ return -1;
++ }
++
++ cq->head = 0;
++
++ /* All CQE phase bits are initialized to zero. This means initially we wait
++ for the host controller to set these to 1. */
++ cq->phase = 1;
++
++ return 0;
++}
++
++static int
++nvme_poll_cq(struct nvme_cq *cq)
++{
++ grub_uint32_t dw3 = *(volatile grub_uint32_t *) &cq->cqe[cq->head].dword[3];
++ return (!!(dw3 & NVME_CQE_DW3_P) == cq->phase);
++}
++
++static int
++nvme_is_cqe_success(struct nvme_cqe const *cqe)
++{
++ return ((cqe->status >> 1) & 0xFF) == 0;
++}
++
++static struct nvme_cqe
++nvme_error_cqe(void)
++{
++ struct nvme_cqe r;
++
++ /* 0xFF is a vendor specific status code != success. Should be okay for
++ indicating failure. */
++ grub_memset(&r, 0xFF, sizeof(r));
++ return r;
++}
++
++static struct nvme_cqe
++nvme_consume_cqe(struct nvme_sq *sq)
++{
++ struct nvme_cq *cq = sq->cq;
++
++ if (!nvme_poll_cq(cq)) {
++ /* Cannot consume a completion queue entry, if there is none ready. */
++ return nvme_error_cqe();
++ }
++
++ struct nvme_cqe *cqe = &cq->cqe[cq->head];
++ grub_uint16_t cq_next_head = (cq->head + 1) & cq->common.mask;
++ grub_dprintf("nvme", "cq %p head %u -> %u\n", cq, cq->head, cq_next_head);
++ if (cq_next_head < cq->head) {
++ grub_dprintf("nvme", "cq %p wrap\n", cq);
++ cq->phase = ~cq->phase;
++ }
++ cq->head = cq_next_head;
++
++ /* Update the submission queue head. */
++ if (cqe->sq_head != sq->head) {
++ sq->head = cqe->sq_head;
++ grub_dprintf("nvme", "sq %p advanced to %u\n", sq, cqe->sq_head);
++ }
++
++ /* Tell the controller that we consumed the completion. */
++ *(volatile grub_uint32_t *) cq->common.dbl = cq->head;
++
++ return *cqe;
++}
++
++static struct nvme_cqe
++nvme_wait(struct nvme_sq *sq)
++{
++ // static const unsigned nvme_timeout = 5000 /* ms */;
++ // grub_uint32_t to = timer_calc(nvme_timeout);
++ while (!nvme_poll_cq(sq->cq)) {
++ /* FIXME
++ yield();
++
++ if (timer_check(to)) {
++ warn_timeout();
++ return nvme_error_cqe();
++ }*/
++ }
++
++ return nvme_consume_cqe(sq);
++}
++
++/* Returns the next submission queue entry (or NULL if the queue is full). It
++ also fills out Command Dword 0 and clears the rest. */
++static struct nvme_sqe *
++nvme_get_next_sqe(struct nvme_sq *sq, grub_uint8_t opc, void *metadata, void *data, void *data2)
++{
++ if (((sq->head + 1) & sq->common.mask) == sq->tail) {
++ grub_dprintf("nvme", "submission queue is full\n");
++ return NULL;
++ }
++
++ struct nvme_sqe *sqe = &sq->sqe[sq->tail];
++ grub_dprintf("nvme", "sq %p next_sqe %u\n", sq, sq->tail);
++
++ grub_memset(sqe, 0, sizeof(*sqe));
++ sqe->cdw0 = opc | (sq->tail << 16 /* CID */);
++ sqe->mptr = (grub_uint32_t)metadata;
++ sqe->dptr_prp1 = (grub_uint32_t)data;
++ sqe->dptr_prp2 = (grub_uint32_t)data2;
++
++ return sqe;
++}
++
++/* Call this after you've filled out an sqe that you've got from nvme_get_next_sqe. */
++static void
++nvme_commit_sqe(struct nvme_sq *sq)
++{
++ grub_dprintf("nvme", "sq %p commit_sqe %u\n", sq, sq->tail);
++ sq->tail = (sq->tail + 1) & sq->common.mask;
++ *(volatile grub_uint32_t *) sq->common.dbl = sq->tail;
++}
++
++/* Perform an identify command on the admin queue and return the resulting
++ buffer. This may be a NULL pointer, if something failed. This function
++ cannot be used after initialization, because it uses buffers in tmp zone. */
++static union nvme_identify *
++nvme_admin_identify(struct nvme_ctrl *ctrl, grub_uint8_t cns, grub_uint32_t nsid)
++{
++ union nvme_identify *identify_buf = zalloc_page_aligned(4096);
++ if (!identify_buf)
++ return NULL;
++
++ struct nvme_sqe *cmd_identify;
++ cmd_identify = nvme_get_next_sqe(&ctrl->admin_sq,
++ NVME_SQE_OPC_ADMIN_IDENTIFY, NULL,
++ identify_buf, NULL);
++ if (!cmd_identify)
++ goto error;
++
++ cmd_identify->nsid = nsid;
++ cmd_identify->dword[10] = cns;
++
++ nvme_commit_sqe(&ctrl->admin_sq);
++
++ struct nvme_cqe cqe = nvme_wait(&ctrl->admin_sq);
++
++ if (!nvme_is_cqe_success(&cqe)) {
++ goto error;
++ }
++
++ return identify_buf;
++ error:
++ grub_free(identify_buf);
++ return NULL;
++}
++
++static struct nvme_identify_ctrl *
++nvme_admin_identify_ctrl(struct nvme_ctrl *ctrl)
++{
++ return &nvme_admin_identify(ctrl, NVME_ADMIN_IDENTIFY_CNS_ID_CTRL, 0)->ctrl;
++}
++
++static struct nvme_identify_ns *
++nvme_admin_identify_ns(struct nvme_ctrl *ctrl, grub_uint32_t ns_id)
++{
++ return &nvme_admin_identify(ctrl, NVME_ADMIN_IDENTIFY_CNS_ID_NS,
++ ns_id)->ns;
++}
++
++static void
++nvme_probe_ns(struct nvme_ctrl *ctrl, grub_uint32_t ns_idx, grub_uint8_t mdts)
++{
++ grub_uint32_t ns_id = ns_idx + 1;
++
++ struct nvme_identify_ns *id = nvme_admin_identify_ns(ctrl, ns_id);
++ if (!id) {
++ grub_dprintf("nvme", "NVMe couldn't identify namespace %u.\n", ns_id);
++ goto free_buffer;
++ }
++
++ grub_uint8_t current_lba_format = id->flbas & 0xF;
++ if (current_lba_format > id->nlbaf) {
++ grub_dprintf("nvme", "NVMe NS %u: current LBA format %u is beyond what the "
++ " namespace supports (%u)?\n",
++ ns_id, current_lba_format, id->nlbaf + 1);
++ goto free_buffer;
++ }
++
++ if (!id->nsze) {
++ grub_dprintf("nvme", "NVMe NS %u is inactive.\n", ns_id);
++ goto free_buffer;
++ }
++
++ if (!nvme_dma_buffer) {
++ nvme_dma_buffer = zalloc_page_aligned(NVME_PAGE_SIZE);
++ if (!nvme_dma_buffer) {
++ goto free_buffer;
++ }
++ }
++
++ struct nvme_namespace *ns = grub_malloc(sizeof(*ns));
++ if (!ns) {
++ goto free_buffer;
++ }
++ grub_memset(ns, 0, sizeof(*ns));
++ ns->ctrl = ctrl;
++ ns->ns_id = ns_id;
++ ns->lba_count = id->nsze;
++
++ struct nvme_lba_format *fmt = &id->lbaf[current_lba_format];
++
++ ns->block_size = 1U << fmt->lbads;
++ ns->metadata_size = fmt->ms;
++
++ if (ns->block_size > NVME_PAGE_SIZE) {
++ /* If we see devices that trigger this path, we need to increase our
++ buffer size. */
++ grub_free(ns);
++ goto free_buffer;
++ }
++
++ if (mdts) {
++ ns->max_req_size = ((1U << mdts) * NVME_PAGE_SIZE) / ns->block_size;
++ grub_dprintf("nvme", "NVME NS %u max request size: %d sectors\n",
++ ns_id, ns->max_req_size);
++ } else {
++ ns->max_req_size = -1U;
++ }
++
++ ns->devname = grub_xasprintf("nvme%un%u", ctrl->ctrlnum, ns_id);
++ ns->nsnum = grub_nvme_nscnt++;
++
++ grub_list_push (GRUB_AS_LIST_P (&grub_nvme_namespaces), GRUB_AS_LIST (ns));
++
++free_buffer:
++ grub_free(id);
++}
++
++
++/* Release memory allocated for a completion queue */
++static void
++nvme_destroy_cq(struct nvme_cq *cq)
++{
++ grub_free(cq->cqe);
++ cq->cqe = NULL;
++}
++
++/* Release memory allocated for a submission queue */
++static void
++nvme_destroy_sq(struct nvme_sq *sq)
++{
++ grub_free(sq->sqe);
++ sq->sqe = NULL;
++}
++
++/* Returns 0 on success. */
++static int
++nvme_create_io_cq(struct nvme_ctrl *ctrl, struct nvme_cq *cq, grub_uint16_t q_idx)
++{
++ int rc;
++ struct nvme_sqe *cmd_create_cq;
++ grub_uint32_t length = 1 + (ctrl->reg->cap & 0xffff);
++ if (length > NVME_PAGE_SIZE / sizeof(struct nvme_cqe))
++ length = NVME_PAGE_SIZE / sizeof(struct nvme_cqe);
++
++ rc = nvme_init_cq(ctrl, cq, q_idx, length);
++ if (rc) {
++ goto err;
++ }
++
++ cmd_create_cq = nvme_get_next_sqe(&ctrl->admin_sq,
++ NVME_SQE_OPC_ADMIN_CREATE_IO_CQ, NULL,
++ cq->cqe, NULL);
++ if (!cmd_create_cq) {
++ goto err_destroy_cq;
++ }
++
++ cmd_create_cq->dword[10] = (cq->common.mask << 16) | (q_idx >> 1);
++ cmd_create_cq->dword[11] = 1 /* physically contiguous */;
++
++ nvme_commit_sqe(&ctrl->admin_sq);
++
++ struct nvme_cqe cqe = nvme_wait(&ctrl->admin_sq);
++
++ if (!nvme_is_cqe_success(&cqe)) {
++ grub_dprintf("nvme", "create io cq failed: %08x %08x %08x %08x\n",
++ cqe.dword[0], cqe.dword[1], cqe.dword[2], cqe.dword[3]);
++
++ goto err_destroy_cq;
++ }
++
++ return 0;
++
++err_destroy_cq:
++ nvme_destroy_cq(cq);
++err:
++ return -1;
++}
++
++/* Returns 0 on success. */
++static int
++nvme_create_io_sq(struct nvme_ctrl *ctrl, struct nvme_sq *sq, grub_uint16_t q_idx, struct nvme_cq *cq)
++{
++ int rc;
++ struct nvme_sqe *cmd_create_sq;
++ grub_uint32_t length = 1 + (ctrl->reg->cap & 0xffff);
++ if (length > NVME_PAGE_SIZE / sizeof(struct nvme_cqe))
++ length = NVME_PAGE_SIZE / sizeof(struct nvme_cqe);
++
++ rc = nvme_init_sq(ctrl, sq, q_idx, length, cq);
++ if (rc) {
++ goto err;
++ }
++
++ cmd_create_sq = nvme_get_next_sqe(&ctrl->admin_sq,
++ NVME_SQE_OPC_ADMIN_CREATE_IO_SQ, NULL,
++ sq->sqe, NULL);
++ if (!cmd_create_sq) {
++ goto err_destroy_sq;
++ }
++
++ cmd_create_sq->dword[10] = (sq->common.mask << 16) | (q_idx >> 1);
++ cmd_create_sq->dword[11] = (q_idx >> 1) << 16 | 1 /* contiguous */;
++ grub_dprintf("nvme", "sq %p create dword10 %08x dword11 %08x\n", sq,
++ cmd_create_sq->dword[10], cmd_create_sq->dword[11]);
++
++ nvme_commit_sqe(&ctrl->admin_sq);
++
++ struct nvme_cqe cqe = nvme_wait(&ctrl->admin_sq);
++
++ if (!nvme_is_cqe_success(&cqe)) {
++ grub_dprintf("nvme", "create io sq failed: %08x %08x %08x %08x\n",
++ cqe.dword[0], cqe.dword[1], cqe.dword[2], cqe.dword[3]);
++ goto err_destroy_sq;
++ }
++
++ return 0;
++
++err_destroy_sq:
++ nvme_destroy_sq(sq);
++err:
++ return -1;
++}
++
++/* Reads count sectors into buf. The buffer cannot cross page boundaries. */
++static int
++nvme_io_xfer(struct nvme_namespace *ns, grub_uint64_t lba, void *prp1, void *prp2,
++ grub_uint16_t count, int write)
++{
++ if (((grub_uint32_t)prp1 & 0x3) || ((grub_uint32_t)prp2 & 0x3)) {
++ /* Buffer is misaligned */
++ return -1;
++ }
++
++ struct nvme_sqe *io_read = nvme_get_next_sqe(&ns->ctrl->io_sq,
++ write ? NVME_SQE_OPC_IO_WRITE
++ : NVME_SQE_OPC_IO_READ,
++ NULL, prp1, prp2);
++ io_read->nsid = ns->ns_id;
++ io_read->dword[10] = (grub_uint32_t)lba;
++ io_read->dword[11] = (grub_uint32_t)(lba >> 32);
++ io_read->dword[12] = (1U << 31 /* limited retry */) | (count - 1);
++
++ nvme_commit_sqe(&ns->ctrl->io_sq);
++
++ struct nvme_cqe cqe = nvme_wait(&ns->ctrl->io_sq);
++
++ if (!nvme_is_cqe_success(&cqe)) {
++ grub_dprintf("nvme", "read io: %08x %08x %08x %08x\n",
++ cqe.dword[0], cqe.dword[1], cqe.dword[2], cqe.dword[3]);
++
++ return -1;
++ }
++
++ grub_dprintf("nvme", "ns %u %s lba %llu+%u\n", ns->ns_id, write ? "write" : "read",
++ lba, count);
++ return count;
++}
++
++// Transfer up to one page of data using the internal dma bounce buffer
++static int
++nvme_bounce_xfer(struct nvme_namespace *ns, grub_uint64_t lba, void *buf, grub_uint16_t count,
++ int write)
++{
++ grub_uint16_t const max_blocks = NVME_PAGE_SIZE / ns->block_size;
++ grub_uint16_t blocks = count < max_blocks ? count : max_blocks;
++
++ if (write)
++ grub_memcpy(nvme_dma_buffer, buf, blocks * ns->block_size);
++
++ int res = nvme_io_xfer(ns, lba, nvme_dma_buffer, NULL, blocks, write);
++
++ if (!write && res >= 0)
++ grub_memcpy(buf, nvme_dma_buffer, res * ns->block_size);
++
++ return res;
++}
++
++#define NVME_MAX_PRPL_ENTRIES 15 /* Allows requests up to 64kb */
++
++// Transfer data using page list (if applicable)
++static int
++nvme_prpl_xfer(struct nvme_namespace *ns, grub_uint64_t lba, void *buf, grub_uint16_t count,
++ int write)
++{
++ grub_uint32_t base = (long)buf;
++ grub_int32_t size;
++
++ if (count > ns->max_req_size)
++ count = ns->max_req_size;
++
++ size = count * ns->block_size;
++ /* Special case for transfers that fit into PRP1, but are unaligned */
++ if (((size + (base & ~NVME_PAGE_MASK)) <= NVME_PAGE_SIZE))
++ goto single;
++
++ /* Every request has to be page aligned */
++ if (base & ~NVME_PAGE_MASK)
++ goto bounce;
++
++ /* Make sure a full block fits into the last chunk */
++ if (size & (ns->block_size - 1ULL))
++ goto bounce;
++
++ /* Build PRP list if we need to describe more than 2 pages */
++ if ((ns->block_size * count) > (NVME_PAGE_SIZE * 2)) {
++ grub_uint32_t prpl_len = 0;
++ grub_uint64_t *prpl = nvme_dma_buffer;
++ int first_page = 1;
++ for (; size > 0; base += NVME_PAGE_SIZE, size -= NVME_PAGE_SIZE) {
++ if (first_page) {
++ /* First page is special */
++ first_page = 0;
++ continue;
++ }
++ if (prpl_len >= NVME_MAX_PRPL_ENTRIES)
++ goto bounce;
++ prpl[prpl_len++] = base;
++ }
++ return nvme_io_xfer(ns, lba, buf, prpl, count, write);
++ }
++
++ /* Directly embed the 2nd page if we only need 2 pages */
++ if ((ns->block_size * count) > NVME_PAGE_SIZE)
++ return nvme_io_xfer(ns, lba, buf, (char *) buf + NVME_PAGE_SIZE, count, write);
++
++single:
++ /* One page is enough, don't expose anything else */
++ return nvme_io_xfer(ns, lba, buf, NULL, count, write);
++
++bounce:
++ /* Use bounce buffer to make transfer */
++ return nvme_bounce_xfer(ns, lba, buf, count, write);
++}
++
++static int
++nvme_create_io_queues(struct nvme_ctrl *ctrl)
++{
++ if (nvme_create_io_cq(ctrl, &ctrl->io_cq, 3))
++ goto err;
++
++ if (nvme_create_io_sq(ctrl, &ctrl->io_sq, 2, &ctrl->io_cq))
++ goto err_free_cq;
++
++ return 0;
++
++ err_free_cq:
++ nvme_destroy_cq(&ctrl->io_cq);
++ err:
++ return -1;
++}
++
++/* Waits for CSTS.RDY to match rdy. Returns 0 on success. */
++static int
++nvme_wait_csts_rdy(struct nvme_ctrl *ctrl, unsigned rdy)
++{
++ // grub_uint32_t const max_to = 500 /* ms */ * ((ctrl->reg->cap >> 24) & 0xFFU);
++ // grub_uint32_t to = timer_calc(max_to);
++ grub_uint32_t csts;
++
++ while (rdy != ((csts = ctrl->reg->csts) & NVME_CSTS_RDY)) {
++ // FIXME
++ //yield();
++
++ if (csts & NVME_CSTS_FATAL) {
++ grub_dprintf("nvme", "NVMe fatal error during controller shutdown\n");
++ return -1;
++ }
++
++ /*
++ if (timer_check(to)) {
++ warn_timeout();
++ return -1;
++ }*/
++ }
++
++ return 0;
++}
++
++/* Returns 0 on success. */
++static int grub_nvme_controller_enable(struct nvme_ctrl *ctrl)
++{
++ grub_pci_address_t addr;
++ int rc;
++
++ addr = grub_pci_make_address (ctrl->pci, GRUB_PCI_REG_COMMAND);
++ grub_pci_write_word (addr, grub_pci_read_word (addr) | GRUB_PCI_COMMAND_BUS_MASTER);
++
++ /* Turn the controller off. */
++ ctrl->reg->cc = 0;
++ if (nvme_wait_csts_rdy(ctrl, 0)) {
++ grub_dprintf("nvme", "NVMe fatal error during controller shutdown\n");
++ return -1;
++ }
++
++ ctrl->doorbell_stride = 4U << ((ctrl->reg->cap >> 32) & 0xF);
++
++ rc = nvme_init_cq(ctrl, &ctrl->admin_cq, 1,
++ NVME_PAGE_SIZE / sizeof(struct nvme_cqe));
++ if (rc) {
++ return -1;
++ }
++
++ rc = nvme_init_sq(ctrl, &ctrl->admin_sq, 0,
++ NVME_PAGE_SIZE / sizeof(struct nvme_sqe), &ctrl->admin_cq);
++ if (rc) {
++ goto err_destroy_admin_cq;
++ }
++
++ ctrl->reg->aqa = ctrl->admin_cq.common.mask << 16
++ | ctrl->admin_sq.common.mask;
++
++ ctrl->reg->asq = (grub_uint32_t)ctrl->admin_sq.sqe;
++ ctrl->reg->acq = (grub_uint32_t)ctrl->admin_cq.cqe;
++
++ grub_dprintf("nvme", " admin submission queue: %p\n", ctrl->admin_sq.sqe);
++ grub_dprintf("nvme", " admin completion queue: %p\n", ctrl->admin_cq.cqe);
++
++ ctrl->reg->cc = NVME_CC_EN | (NVME_CQE_SIZE_LOG << 20)
++ | (NVME_SQE_SIZE_LOG << 16 /* IOSQES */);
++
++ if (nvme_wait_csts_rdy(ctrl, 1)) {
++ grub_dprintf("nvme", "NVMe fatal error while enabling controller\n");
++ goto err_destroy_admin_sq;
++ }
++
++ /* The admin queue is set up and the controller is ready. Let's figure out
++ what namespaces we have. */
++
++ struct nvme_identify_ctrl *identify = nvme_admin_identify_ctrl(ctrl);
++
++ if (!identify) {
++ grub_dprintf("nvme", "NVMe couldn't identify controller.\n");
++ goto err_destroy_admin_sq;
++ }
++
++ grub_dprintf("nvme", "NVMe has %u namespace%s.\n",
++ identify->nn, (identify->nn == 1) ? "" : "s");
++
++ ctrl->ns_count = identify->nn;
++ grub_uint8_t mdts = identify->mdts;
++ grub_free(identify);
++
++ if ((ctrl->ns_count == 0) || nvme_create_io_queues(ctrl)) {
++ /* No point to continue, if the controller says it doesn't have
++ namespaces or we couldn't create I/O queues. */
++ goto err_destroy_admin_sq;
++ }
++
++ /* Give the controller a global number */
++ ctrl->ctrlnum = grub_nvme_ctrlcnt++;
++
++ /* Populate namespace IDs */
++ for (grub_uint32_t ns_idx = 0; ns_idx < ctrl->ns_count; ns_idx++) {
++ nvme_probe_ns(ctrl, ns_idx, mdts);
++ }
++
++ grub_dprintf("nvme", "NVMe initialization complete!\n");
++ return 0;
++
++ err_destroy_admin_sq:
++ nvme_destroy_sq(&ctrl->admin_sq);
++ err_destroy_admin_cq:
++ nvme_destroy_cq(&ctrl->admin_cq);
++ return -1;
++}
++
++static int grub_nvme_pci_probe(grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ ((unused)), void *data __attribute__ ((unused)))
++{
++ grub_pci_address_t addr;
++ grub_uint32_t class, bar, version;
++ struct nvme_reg volatile *reg;
++
++ class = grub_pci_read (grub_pci_make_address (dev, GRUB_PCI_REG_CLASS));
++ if (class >> 16 != 0x0108)
++ return 0;
++ if ((class >> 8 & 0xff) != 2) { /* as of NVM 1.0e */
++ grub_dprintf("nvme", "Found incompatble NVMe: prog-if=%02x\n", class >> 8 & 0xff);
++ return 0;
++ }
++
++ bar = grub_pci_read (grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0));
++ reg = grub_pci_device_map_range (dev, bar & GRUB_PCI_ADDR_MEM_MASK, sizeof (*reg));
++
++ addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
++ grub_pci_write_word (addr, grub_pci_read_word (addr) | GRUB_PCI_COMMAND_MEM_ENABLED);
++
++ version = reg->vs;
++ grub_dprintf("nvme", "Found NVMe controller with version %u.%u.%u.\n", version >> 16, (version >> 8) & 0xFF, version & 0xFF);
++ grub_dprintf("nvme", " Capabilities %016llx\n", reg->cap);
++
++ if (~reg->cap & NVME_CAP_CSS_NVME) {
++ grub_dprintf("nvme", "Controller doesn't speak NVMe command set. Skipping.\n");
++ goto err;
++ }
++
++ struct nvme_ctrl *ctrl = grub_malloc(sizeof(*ctrl));
++ if (!ctrl)
++ goto err;
++
++ grub_memset(ctrl, 0, sizeof(*ctrl));
++
++ ctrl->reg = reg;
++ ctrl->pci = dev;
++
++ if (grub_nvme_controller_enable(ctrl))
++ goto err_free_ctrl;
++
++ return 0;
++
++ err_free_ctrl:
++ grub_free(ctrl);
++ err:
++ grub_dprintf("nvme", "Failed to enable NVMe controller.\n");
++ return 0;
++}
++
++static int
++grub_nvme_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, grub_disk_pull_t pull)
++{
++ struct nvme_namespace *ns;
++
++ if (pull != GRUB_DISK_PULL_NONE)
++ return 0;
++
++ FOR_LIST_ELEMENTS(ns, grub_nvme_namespaces)
++ if (hook (ns->devname, hook_data))
++ return 1;
++
++ return 0;
++}
++
++static grub_err_t
++grub_nvme_open (const char *name __attribute ((unused)), grub_disk_t disk __attribute ((unused)))
++{
++ struct nvme_namespace *ns;
++
++ FOR_LIST_ELEMENTS(ns, grub_nvme_namespaces)
++ if (grub_strcmp (ns->devname, name) == 0)
++ break;
++
++ if (! ns)
++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
++
++ disk->total_sectors = ns->lba_count;
++ disk->max_agglomerate = ns->max_req_size;
++
++ disk->id = ns->nsnum; /* global id of the namespace */
++
++ disk->data = ns;
++
++ return 0;
++}
++
++static grub_err_t
++nvme_readwrite(struct nvme_namespace *ns, grub_disk_addr_t sector, grub_size_t num_sectors, char *buf, int write)
++{
++ for (int i = 0; i < num_sectors;) {
++ grub_uint16_t blocks_remaining = num_sectors - i;
++ char *op_buf = buf + i * ns->block_size;
++ int blocks = nvme_prpl_xfer(ns, sector + i, op_buf, blocks_remaining, write);
++ if (blocks < 0)
++ return GRUB_ERR_IO;
++ i += blocks;
++ }
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_nvme_read (grub_disk_t disk, grub_disk_addr_t sector, grub_size_t num_sectors, char *buf)
++{
++ return nvme_readwrite((struct nvme_namespace *) disk->data, sector, num_sectors, buf, 0);
++}
++
++static grub_err_t
++grub_nvme_write (grub_disk_t disk, grub_disk_addr_t sector, grub_size_t num_sectors, const char *buf)
++{
++ return nvme_readwrite((struct nvme_namespace *) disk->data, sector, num_sectors, buf, 1);
++}
++
++static struct grub_disk_dev grub_nvme_dev =
++ {
++ .name = "nvme",
++ .id = GRUB_DISK_DEVICE_NVME_ID,
++ .disk_iterate = grub_nvme_iterate,
++ .disk_open = grub_nvme_open,
++ .disk_read = grub_nvme_read,
++ .disk_write = grub_nvme_write,
++ .next = 0
++ };
++
++GRUB_MOD_INIT(nvme)
++{
++ grub_stop_disk_firmware ();
++ grub_pci_iterate (grub_nvme_pci_probe, NULL);
++ grub_disk_dev_register (&grub_nvme_dev);
++}
++
++GRUB_MOD_FINI(nvme)
++{
++ grub_disk_dev_unregister (&grub_nvme_dev);
++}
+diff --git a/include/grub/disk.h b/include/grub/disk.h
+index fbf23df7f..186e76f0b 100644
+--- a/include/grub/disk.h
++++ b/include/grub/disk.h
+@@ -52,6 +52,7 @@ enum grub_disk_dev_id
+ GRUB_DISK_DEVICE_UBOOTDISK_ID,
+ GRUB_DISK_DEVICE_XEN,
+ GRUB_DISK_DEVICE_OBDISK_ID,
++ GRUB_DISK_DEVICE_NVME_ID
+ };
+
+ struct grub_disk;
+--
+2.47.3
+
diff --git a/config/grub/xhci_nvme/patches/0020-kern-coreboot-mmap-Map-to-reserved.patch b/config/grub/xhci_nvme/patches/0020-kern-coreboot-mmap-Map-to-reserved.patch
new file mode 100644
index 00000000..ffa01e7a
--- /dev/null
+++ b/config/grub/xhci_nvme/patches/0020-kern-coreboot-mmap-Map-to-reserved.patch
@@ -0,0 +1,37 @@
+From 331af0cc985aa5ec57964c6e3ab69f65c23f6481 Mon Sep 17 00:00:00 2001
+From: Paul Menzel <pmenzel@molgen.mpg.de>
+Date: Mon, 17 May 2021 10:24:36 +0200
+Subject: [PATCH 20/21] kern/coreboot/mmap: Map to reserved
+
+https://git.savannah.gnu.org/cgit/grub.git/commit/?id=6de9ee86bf9ae50967413e6a73b5dfd13e5ffb50
+
+Signed-off-by: Paul Menzel <pmenzel@molgen.mpg.de>
+---
+ grub-core/kern/coreboot/mmap.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/kern/coreboot/mmap.c b/grub-core/kern/coreboot/mmap.c
+index caf8f7cef..2fc316e8d 100644
+--- a/grub-core/kern/coreboot/mmap.c
++++ b/grub-core/kern/coreboot/mmap.c
+@@ -59,7 +59,7 @@ iterate_linuxbios_table (grub_linuxbios_table_item_t table_item, void *data)
+ /* Multiboot mmaps match with the coreboot mmap
+ definition. Therefore, we can just pass type
+ through. */
+- mem_region->type,
++ (mem_region->type >= 13) ? 2 : mem_region->type,
+ ctx->hook_data))
+ return 1;
+ if (start < 0xa0000)
+@@ -81,7 +81,7 @@ iterate_linuxbios_table (grub_linuxbios_table_item_t table_item, void *data)
+ /* Multiboot mmaps match with the coreboot mmap
+ definition. Therefore, we can just pass type
+ through. */
+- mem_region->type,
++ (mem_region->type >= 13) ? 2 : mem_region->type,
+ ctx->hook_data))
+ return 1;
+ }
+--
+2.47.3
+
diff --git a/config/grub/xhci_nvme/patches/0021-Revert-configure-Check-linker-for-image-base-support.patch b/config/grub/xhci_nvme/patches/0021-Revert-configure-Check-linker-for-image-base-support.patch
new file mode 100644
index 00000000..0e563fd5
--- /dev/null
+++ b/config/grub/xhci_nvme/patches/0021-Revert-configure-Check-linker-for-image-base-support.patch
@@ -0,0 +1,70 @@
+From cf791012987ea90f7a88edd21a0f619fbc40986d Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Wed, 24 Dec 2025 01:42:17 +0100
+Subject: [PATCH 21/21] Revert "configure: Check linker for --image-base
+ support"
+
+This reverts commit 1a5417f39a0ccefcdd5440f2a67f84d2d2e26960.
+---
+ acinclude.m4 | 5 -----
+ configure.ac | 14 ++------------
+ 2 files changed, 2 insertions(+), 17 deletions(-)
+
+diff --git a/acinclude.m4 b/acinclude.m4
+index 70c1912f8..fa7840f09 100644
+--- a/acinclude.m4
++++ b/acinclude.m4
+@@ -79,11 +79,6 @@ AC_DEFUN([grub_PROG_OBJCOPY_ABSOLUTE],
+ [AC_MSG_CHECKING([whether ${TARGET_OBJCOPY} works for absolute addresses])
+ AC_CACHE_VAL(grub_cv_prog_objcopy_absolute,
+ [cat > conftest.c <<\EOF
+-asm (
+- ".globl start, _start, __start\n"
+- ".ifdef cmain; .set start = _start = __start = cmain\n.endif\n"
+- ".ifdef _cmain; .set start = _start = __start = _cmain\n.endif\n"
+-);
+ void cmain (void);
+ void
+ cmain (void)
+diff --git a/configure.ac b/configure.ac
+index d8ca1b7c1..041cfbab4 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1461,6 +1461,7 @@ elif test x$grub_cv_target_cc_link_format = x-mi386pe || test x$grub_cv_target_c
+ TARGET_IMG_LDSCRIPT='$(top_srcdir)'"/conf/i386-cygwin-img-ld.sc"
+ TARGET_IMG_LDFLAGS="-Wl,-T${TARGET_IMG_LDSCRIPT}"
+ TARGET_IMG_LDFLAGS_AC="-Wl,-T${srcdir}/conf/i386-cygwin-img-ld.sc"
++ TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"
+ TARGET_IMG_CFLAGS=
+ else
+ TARGET_APPLE_LINKER=0
+@@ -1468,6 +1469,7 @@ else
+ TARGET_IMG_LDSCRIPT=
+ TARGET_IMG_LDFLAGS='-Wl,-N'
+ TARGET_IMG_LDFLAGS_AC='-Wl,-N'
++ TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"
+ TARGET_IMG_CFLAGS=
+ fi
+
+@@ -1798,18 +1800,6 @@ grub_PROG_TARGET_CC
+ m4_ifndef([AX_CHECK_LINK_FLAG], [m4_fatal([autoconf-archive is missing. You must install it to generate the configure script.])])
+
+ if test "x$TARGET_APPLE_LINKER" != x1 ; then
+-AX_CHECK_LINK_FLAG([-Wl,--image-base,0x400000],
+- [TARGET_IMG_BASE_LDOPT="-Wl,--image-base"],
+- [TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"],
+- [],
+- [AC_LANG_SOURCE([
+-asm (".globl start; start:");
+-asm (".globl _start; _start:");
+-asm (".globl __start; __start:");
+-void __main (void);
+-void __main (void) {}
+-int main (void);
+- ])])
+ grub_PROG_OBJCOPY_ABSOLUTE
+ fi
+ grub_PROG_LD_BUILD_ID_NONE
+--
+2.47.3
+
diff --git a/config/grub/xhci_nvme/patches/0022-Revert-configure-Print-a-more-helpful-error-if-autoc.patch b/config/grub/xhci_nvme/patches/0022-Revert-configure-Print-a-more-helpful-error-if-autoc.patch
new file mode 100644
index 00000000..c0a504ff
--- /dev/null
+++ b/config/grub/xhci_nvme/patches/0022-Revert-configure-Print-a-more-helpful-error-if-autoc.patch
@@ -0,0 +1,30 @@
+From abf2bf6e2973ccaa994f63ff851ba11cbd45f1eb Mon Sep 17 00:00:00 2001
+From: Leah Rowe <leah@libreboot.org>
+Date: Mon, 19 Jan 2026 15:27:23 +0000
+Subject: [PATCH 1/1] Revert "configure: Print a more helpful error if
+ autoconf-archive is not installed"
+
+This reverts commit ac042f3f58d33ce9cd5ff61750f06da1a1d7b0eb.
+---
+ configure.ac | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 041cfbab4..209c0fb11 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1794,11 +1794,6 @@ LIBS=""
+ # Defined in acinclude.m4.
+ grub_ASM_USCORE
+ grub_PROG_TARGET_CC
+-
+-# The error message produced by autoconf if autoconf-archive is not installed is
+-# quite misleading and not very helpful. So, try point people in the right direction.
+-m4_ifndef([AX_CHECK_LINK_FLAG], [m4_fatal([autoconf-archive is missing. You must install it to generate the configure script.])])
+-
+ if test "x$TARGET_APPLE_LINKER" != x1 ; then
+ grub_PROG_OBJCOPY_ABSOLUTE
+ fi
+--
+2.47.3
+
diff --git a/config/grub/xhci_nvme/target.cfg b/config/grub/xhci_nvme/target.cfg
new file mode 100644
index 00000000..15e3e00e
--- /dev/null
+++ b/config/grub/xhci_nvme/target.cfg
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+tree="xhci_nvme"
+rev="eaa3b8f0f90605a82c6bfda4c5c4b73c58eb81ac"