From 512cce07708630e546e071d7050b98da64438a77 Mon Sep 17 00:00:00 2001 From: Leah Rowe Date: Tue, 23 Dec 2025 19:19:07 +0100 Subject: GRUB: update to rev 2.14-rc1 December 2025 The argon2 patches were dropped (PHC implementation), because GRUB has now its own Argon2 KDF implementation as part of its recent libgcrypt update. Argon2 support is therefore retained, but GNU's implementation has replaced the one that Libreboot previously used. This brings in the following upstream changes: * 280715ec6 Release 2.14~rc1 * e549317e1 windows: Fix symbol table generation during module conversion from PE to ELF * a340750f9 windows: Fix relocation sections generation during module conversion from PE to ELF * c602035a9 loader/efi/linux: Fix compile error with Clang * f62269767 build: Add tpm2key.asn file for reference to dist archive * 46be4488f build: Include new zstd test support files in dist archive * fa79d5ea9 build: Include MAINTAINERS and SECURITY files in dist archive * 8271bcc13 build: Add appended signatures header file to EXTRA_DIST * 11845da2b lib/xzembed/xz_dec_stream: Replace grub_memcpy() call with memcpy() * 7ded35fea bootstrap: Fix patching warnings * 4129e9ad6 tss2: Always init out buffer before calling tpm2_submit_command_real() * 000e48b42 fs/ntfs: Correct next_attribute validation * 5ff9c43cf kern/ieee1275/init: Use net config for boot location instead of firmware bootpath * c2cae77ab net/tftp: Fix NULL pointer dereference in grub_net_udp_close() * fadc94b91 net/dns: Prevent UAF and double free * cd24e2591 net/bootp: Prevent a UAF in network interface unregister * fca6c0afd docs: Document lsmemregions and memtools commands * 42c099786 commands/memtools: Add lsmemregions command * 20211246a tests/file_filter: Add zstd tests * 092449f63 tests/file_filter: Add zstd test file * 356dcac9a tests/file_filter: Regenerate gpg keys * 8ea83c3ee io/zstdio: Implement zstdio decompression * 7c22c1000 fs/btrfs: Update doc link for bootloader support * 6435551a6 docs: Add Btrfs env block and special env vars * b63447748 util/grub.d/00_header.in: Wire grub.cfg to use env_block when present * e4e177661 fs/btrfs: Add environment block to reserved header area * d6525f0e6 util/grub-editenv: Add probe call for external envblk * 4b5ea8dca util/grub-editenv: Wire list_variables() to optional fs_envblk * 84e2bc2f1 util/grub-editenv: Wire unset_variables() to optional fs_envblk * c7c901916 util/grub-editenv: Wire set_variables() to optional fs_envblk * 2abdd8cd2 util/grub-editenv: Add fs_envblk write helper * e4d684cc4 util/grub-editenv: Add fs_envblk open helper * 512e33ec7 tests: Add "z" length modifier printf tests * 3c9762b12 kern/misc: Add the "z" length modifier support * 91ddada64 disk/cryptodisk: Add --hw-accel to enable hardware acceleration * f8f68f14a libgcrypt: Add hardware acceleration for gcry_sha512 * 70b2f5f08 libgcrypt: Add hardware acceleration for gcry_sha256 * 2158d8e8a libgcrypt: Declare the sha256 shaext function * 0ff5faf8c libgcrypt: Implement _gcry_get_hw_features() * 812356191 libgcrypt: Copy sha512 x86_64 assembly files * 7f9c590af libgcrypt: Copy sha256 x86_64 assembly files * 8423176f1 lib/hwfeatures-gcry: Enable SSE and AVX for x86_64 EFI * 06a5b88ba lib/hwfeatures-gcry: Introduce functions to manage hardware features * d01abd713 configure: Tweak autoconf/automake files to detect x86_64 features * a122e0262 lib/pbkdf2: Optimize PBKDF2 by reusing HMAC handle * 961e38b2b lib/crypto: Introduce new HMAC functions to reuse buffers * 59304a7b5 docs: Document argon2 and argon2_test modules * 28dbe8a3b kern/misc: Implement faster grub_memcpy() for aligned buffers * da01eb0c5 tests/util/grub-fs-tester: Use Argon2id for LUKS2 test * c1bd9fc82 tests: Integrate Argon2 tests into functional_test * 6a525ee64 tests: Import Argon2 tests from libgcrypt * 6052fc2cf disk/luks2: Add Argon2 support * 66b8718f9 argon2: Introduce grub_crypto_argon2() * de201105d libgcrypt/kdf: Fix 64-bit modulus on 32-bit platforms * 93544861b libgcrypt/kdf: Remove unsupported KDFs * 1ff720641 libgcrypt/kdf: Get rid of gpg_err_code_from_errno() * 0c06a454f libgcrypt/kdf: Implement hash_buffers() for BLAKE2b-512 * bc94dfd54 crypto: Update crypto.h for libgcrypt KDF functions * 5b81f490c util/import_gcry: Import kdf.c for Argon2 * 6b5c671d3 commands/menuentry: Fix for out of bound access * 21cdcb125 tests/tpm2_key_protector_test: Add a test for PCR Capping * afddba012 tpm2_key_protector: Support PCR capping * ae7a39900 tss2: Implement grub_tcg2_cap_pcr() for emu * 7b39970e9 tss2: Implement grub_tcg2_cap_pcr() for ieee1275 * 39f98e471 tss2: Implement grub_tcg2_cap_pcr() for EFI * d47d261ec tss2: Introduce grub_tcg2_cap_pcr() * b2549b4d3 tss2: Add TPM2_PCR_Event command * e1b9d92a8 loader/i386/linux: Transfer EDID information to kernel * a8379e693 fs/hfsplus: Allow reading files created by Mac OS 9 * c5ff0d616 docs: Fix build warnings in libgcrypt and blsuki doc * fa93f2412 kern/command,commands/extcmd: Perform explicit NULL check in both the unregister helpers * 9a725391f commands/efi/tpm: Call get_active_pcr_banks() only with TCG2 1.1 or newer * 894241c85 kern: Include function name on debug and error print functions * 75a20cc14 kern: Make grub_error() more verbose * 8abbafa49 net/tcp: Fix TCP port number reused on reboot * 3dff10a97 docs/grub: Document appended signature * 0f2dda8cf docs/grub: Document signing GRUB with an appended signature * 0b59d379f docs/grub: Document signing GRUB under UEFI * dbfa3d7d7 appended signatures: Verification tests * 7f68c7195 appended signatures: GRUB commands to manage the hashes * 6cb58b1c9 appended signatures: GRUB commands to manage the certificates * ab7b17717 appended signatures: Using db and dbx lists for signature verification * 97f7001e1 appended signatures: Create db and dbx lists * b5e872417 appended signatures: Introducing key management environment variable * 76158ed1a powerpc/ieee1275: Read the db and dbx secure boot variables * 069f3614e appended signatures: Support verifying appended signatures * f8e8779d8 powerpc/ieee1275: Enter lockdown based on /ibm, secure-boot * e95c52f1f appended signatures: Parse X.509 certificates * a33754979 appended signatures: Parse PKCS#7 signed data * 3e4ff6ffb appended signatures: Parse ASN1 node * 7d28bdb0b appended signatures: Import GNUTLS's ASN.1 description files * 1fca5f397 grub-install: Support embedding x509 certificates * aefe0de22 pgp: Rename OBJ_TYPE_PUBKEY to OBJ_TYPE_GPG_PUBKEY * f826cc8b0 crypto: Move storage for grub_crypto_pk_* to crypto.c * 31cc7dfe5 powerpc/ieee1275: Add support for signing GRUB with an appended signature * ee789e1a6 lib/b64dec: Use grub_size_t instead of size_t for _gpgrt_b64dec_proc() function definition * abb8fb6d1 util/grub-mkimagexx: Fix riscv32 relocation offset * 1f9092bfd libgcrypt: Allow GRUB to build with Clang * 1d2ee8f8b tests: Add test ISO files to dist package * dfa3dbf61 tests: Test dates outside of 32-bit Unix range * 6837293b8 lib/datetime: Support dates outside of 1901..2038 range * 02788bfdf bootstrap: Ensure shallow gnulib clone works on newer git * 4e42199f3 docs: Correct some URLs * 733cc28eb docs: Update Future section to reflect current release * 54c8573ef docs: Document new libgrypt modules * 1562dee69 docs: Clarify section heading and fix wording * cf1b75a14 BUGS: Update to point to bug tracking system * 236663dfb INSTALL: Document libtasn1 needed for grub-protect * 7bfb38627 po: Update translations to build with gettext 0.26 * 49e76ad16 term/efi/console: Treat key.scan_code 0x0102 (suspend) as Enter * de72f3998 util/bash-completion.d/Makefile.am: s/mkrescure/mkrescue/g * 14c2966c7 blsuki: Add uki command to load Unified Kernel Image entries * 5190df851 blsuki: Check for mounted /boot in emu * 51b960132 util/misc.c: Change offset type for grub_util_write_image_at() * 8cee1c284 blsuki: Add blscfg command to parse Boot Loader Specification snippets * e016d6d60 kern/misc: Implement grub_strtok() * 587db89af kern/xen: Add Xen command line parsing * b2a975bc5 include/xen/xen.h: Add warning comment for cmd_line * 19c698d12 zfs: Fix LINUX_ROOT_DEVICE when grub-probe fails * 6898fcf74 relocator: Switch to own page table while moving chunks * 67a95527b configure: Generate tar-ustar tarball instead of tar-v7 * 29d515b4c build: Add new libgcrypt and libtasn1 related files to EXTRA_DISTS * eb76b064d build: Add util/import_gcrypt_inth.sed to EXTRA_DISTS * eb56a6af9 include/xen/xen.h: Rename MAX_GUEST_CMDLINE to GRUB_XEN_MAX_GUEST_CMDLINE * 80df5e132 loader/arm64/xen_boot: Set correctly bootargs property for modules * 6831d242a loader/efi/linux: Return correct size from LoadFile2 * f326c5c47 commands/bli: Set LoaderTpm2ActivePcrBanks runtime variable * 0e367796c docs: Write how to import new libgcrypt * b930bfa37 libgcrypt: Fix a memory leak * d48c277c4 libgcrypt: Don't use 64-bit division on platforms where it's slow * de49514c9 util/import_gcry: Fix pylint warnings * 334353a97 util/import_gcry: Make compatible with Python 3.4 * 2a6de4209 libgcrypt: Import blake family of hashes * e54187912 libgcrypt: Ignore sign-compare warnings * e3b78e49c libgcrypt: Remove now unneeded compilation flag * e23704ad4 libgcrypt: Fix Coverity warnings * d65810b01 keccak: Disable acceleration with SSE asm * f808ef0d2 tests: Add DSA and RSA SEXP tests * 0739d24cd libgcrypt: Adjust import script, definitions and API users for libgcrypt 1.11 * 3e1c2890b b64dec: Add harness for compilation in GRUB environment * 5ca0d5e41 b64dec: Import b64dec from gpg-error * 3312af6e0 libgcrypt: Import libgcrypt 1.11 * a0d4c94ef loader/efi/linux: Use shim loader image handle where available * 1b9a84e63 loader/efi/chainloader: Use shim loader image handle where available * e31d0cd7f efi/sb: Add API for retrieving shim loader image handles * ed7e053a3 efi/sb: Add support for the shim loader protocol * 70897d3d3 efi: Provide wrappers for load_image, start_image and unload_image * 030a70fca loader/arm64/xen_boot: Consider alignment calling grub_arch_efi_linux_boot_image() * e82609a47 loader/arm64/xen_boot: Use bool instead of int * d1a470b69 loader/arm64/xen_boot: Remove correctly all modules loaded by xen_module command * cf5e52fa8 dl: Fix grub_dl_is_persistent() for emu --- ...ub-s-missing-characters-for-borders-arrow.patch | 6 +- ...2-say-the-name-libreboot-in-the-grub-menu.patch | 10 +- .../default/patches/0003-Add-CC0-license.patch | 42 - ...board-coreboot-force-scancodes2-translate.patch | 107 + .../patches/0004-Define-GRUB_UINT32_MAX.patch | 39 - ...eylayouts-don-t-print-Unknown-key-message.patch | 38 + .../patches/0005-Add-Argon2-algorithm.patch | 2612 ------------------ ...print-missing-prefix-errors-on-the-screen.patch | 102 + ...0006-Error-on-missing-Argon2id-parameters.patch | 58 - ...006-don-t-print-error-if-module-not-found.patch | 34 + .../0007-Compile-with-Argon2id-support.patch | 83 - .../0007-don-t-print-empty-error-messages.patch | 31 + .../0008-Make-grub-install-work-with-Argon2.patch | 26 - .../0008-kern-coreboot-mmap-Map-to-reserved.patch | 37 + ...board-coreboot-force-scancodes2-translate.patch | 107 - ...eylayouts-don-t-print-Unknown-key-message.patch | 38 - ...print-missing-prefix-errors-on-the-screen.patch | 102 - ...012-don-t-print-error-if-module-not-found.patch | 34 - .../0013-don-t-print-empty-error-messages.patch | 31 - .../0014-kern-coreboot-mmap-Map-to-reserved.patch | 37 - config/grub/default/target.cfg | 2 +- ...ub-s-missing-characters-for-borders-arrow.patch | 6 +- ...2-say-the-name-libreboot-in-the-grub-menu.patch | 10 +- .../grub/nvme/patches/0003-Add-CC0-license.patch | 42 - ...board-coreboot-force-scancodes2-translate.patch | 107 + .../nvme/patches/0004-Define-GRUB_UINT32_MAX.patch | 39 - ...eylayouts-don-t-print-Unknown-key-message.patch | 38 + .../nvme/patches/0005-Add-Argon2-algorithm.patch | 2612 ------------------ ...print-missing-prefix-errors-on-the-screen.patch | 102 + ...0006-Error-on-missing-Argon2id-parameters.patch | 58 - ...006-don-t-print-error-if-module-not-found.patch | 34 + .../0007-Compile-with-Argon2id-support.patch | 83 - .../0007-don-t-print-empty-error-messages.patch | 31 + ...8-Add-native-NVMe-driver-based-on-SeaBIOS.patch | 1074 ++++++++ .../0008-Make-grub-install-work-with-Argon2.patch | 26 - ...board-coreboot-force-scancodes2-translate.patch | 107 - .../0009-kern-coreboot-mmap-Map-to-reserved.patch | 37 + ...eylayouts-don-t-print-Unknown-key-message.patch | 38 - ...print-missing-prefix-errors-on-the-screen.patch | 102 - ...012-don-t-print-error-if-module-not-found.patch | 34 - .../0013-don-t-print-empty-error-messages.patch | 31 - ...4-Add-native-NVMe-driver-based-on-SeaBIOS.patch | 1074 -------- .../0015-kern-coreboot-mmap-Map-to-reserved.patch | 37 - config/grub/nvme/target.cfg | 2 +- ...ub-s-missing-characters-for-borders-arrow.patch | 6 +- ...2-say-the-name-libreboot-in-the-grub-menu.patch | 10 +- .../xhci_nvme/patches/0003-Add-CC0-license.patch | 42 - ...board-coreboot-force-scancodes2-translate.patch | 107 + .../patches/0004-Define-GRUB_UINT32_MAX.patch | 39 - ...eylayouts-don-t-print-Unknown-key-message.patch | 38 + .../patches/0005-Add-Argon2-algorithm.patch | 2612 ------------------ ...print-missing-prefix-errors-on-the-screen.patch | 102 + ...0006-Error-on-missing-Argon2id-parameters.patch | 58 - ...006-don-t-print-error-if-module-not-found.patch | 34 + .../0007-Compile-with-Argon2id-support.patch | 83 - .../0007-don-t-print-empty-error-messages.patch | 31 + .../0008-Make-grub-install-work-with-Argon2.patch | 26 - ...us-usb-Parse-SuperSpeed-companion-descrip.patch | 246 ++ ...board-coreboot-force-scancodes2-translate.patch | 107 - .../patches/0009-usb-Add-enum-for-xHCI.patch | 29 + ...eylayouts-don-t-print-Unknown-key-message.patch | 38 - ...-usbtrans-Set-default-maximum-packet-size.patch | 33 + ...print-missing-prefix-errors-on-the-screen.patch | 102 - ...us-usb-Add-function-pointer-for-attach-de.patch | 121 + ...012-don-t-print-error-if-module-not-found.patch | 34 - ...us-usb-usbhub-Add-new-private-fields-for-.patch | 77 + .../0013-don-t-print-empty-error-messages.patch | 31 - .../0013-grub-core-bus-usb-Add-xhci-support.patch | 2807 ++++++++++++++++++++ ...us-usb-Parse-SuperSpeed-companion-descrip.patch | 246 -- ...us-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch | 127 + .../patches/0015-usb-Add-enum-for-xHCI.patch | 29 - .../0015-xHCI-also-accept-SBRN-0x31-and-0x32.patch | 26 + ...-usbtrans-Set-default-maximum-packet-size.patch | 33 - .../patches/0016-xhci-fix-port-indexing.patch | 43 + ...us-usb-Add-function-pointer-for-attach-de.patch | 121 - .../0017-xhci-configure-TT-for-non-root-hubs.patch | 98 + .../patches/0018-Fix-compilation-on-x86_64.patch | 90 + ...us-usb-usbhub-Add-new-private-fields-for-.patch | 77 - ...9-Add-native-NVMe-driver-based-on-SeaBIOS.patch | 1074 ++++++++ .../0019-grub-core-bus-usb-Add-xhci-support.patch | 2807 -------------------- ...us-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch | 127 - .../0020-kern-coreboot-mmap-Map-to-reserved.patch | 37 + .../0021-xHCI-also-accept-SBRN-0x31-and-0x32.patch | 26 - .../patches/0022-xhci-fix-port-indexing.patch | 43 - .../0023-xhci-configure-TT-for-non-root-hubs.patch | 98 - .../patches/0024-Fix-compilation-on-x86_64.patch | 90 - ...5-Add-native-NVMe-driver-based-on-SeaBIOS.patch | 1074 -------- .../0026-kern-coreboot-mmap-Map-to-reserved.patch | 37 - config/grub/xhci_nvme/target.cfg | 2 +- 89 files changed, 6919 insertions(+), 15499 deletions(-) delete mode 100644 config/grub/default/patches/0003-Add-CC0-license.patch create mode 100644 config/grub/default/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch delete mode 100644 config/grub/default/patches/0004-Define-GRUB_UINT32_MAX.patch create mode 100644 config/grub/default/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch delete mode 100644 config/grub/default/patches/0005-Add-Argon2-algorithm.patch create mode 100644 config/grub/default/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch delete mode 100644 config/grub/default/patches/0006-Error-on-missing-Argon2id-parameters.patch create mode 100644 config/grub/default/patches/0006-don-t-print-error-if-module-not-found.patch delete mode 100644 config/grub/default/patches/0007-Compile-with-Argon2id-support.patch create mode 100644 config/grub/default/patches/0007-don-t-print-empty-error-messages.patch delete mode 100644 config/grub/default/patches/0008-Make-grub-install-work-with-Argon2.patch create mode 100644 config/grub/default/patches/0008-kern-coreboot-mmap-Map-to-reserved.patch delete mode 100644 config/grub/default/patches/0009-at_keyboard-coreboot-force-scancodes2-translate.patch delete mode 100644 config/grub/default/patches/0010-keylayouts-don-t-print-Unknown-key-message.patch delete mode 100644 config/grub/default/patches/0011-don-t-print-missing-prefix-errors-on-the-screen.patch delete mode 100644 config/grub/default/patches/0012-don-t-print-error-if-module-not-found.patch delete mode 100644 config/grub/default/patches/0013-don-t-print-empty-error-messages.patch delete mode 100644 config/grub/default/patches/0014-kern-coreboot-mmap-Map-to-reserved.patch delete mode 100644 config/grub/nvme/patches/0003-Add-CC0-license.patch create mode 100644 config/grub/nvme/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch delete mode 100644 config/grub/nvme/patches/0004-Define-GRUB_UINT32_MAX.patch create mode 100644 config/grub/nvme/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch delete mode 100644 config/grub/nvme/patches/0005-Add-Argon2-algorithm.patch create mode 100644 config/grub/nvme/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch delete mode 100644 config/grub/nvme/patches/0006-Error-on-missing-Argon2id-parameters.patch create mode 100644 config/grub/nvme/patches/0006-don-t-print-error-if-module-not-found.patch delete mode 100644 config/grub/nvme/patches/0007-Compile-with-Argon2id-support.patch create mode 100644 config/grub/nvme/patches/0007-don-t-print-empty-error-messages.patch create mode 100644 config/grub/nvme/patches/0008-Add-native-NVMe-driver-based-on-SeaBIOS.patch delete mode 100644 config/grub/nvme/patches/0008-Make-grub-install-work-with-Argon2.patch delete mode 100644 config/grub/nvme/patches/0009-at_keyboard-coreboot-force-scancodes2-translate.patch create mode 100644 config/grub/nvme/patches/0009-kern-coreboot-mmap-Map-to-reserved.patch delete mode 100644 config/grub/nvme/patches/0010-keylayouts-don-t-print-Unknown-key-message.patch delete mode 100644 config/grub/nvme/patches/0011-don-t-print-missing-prefix-errors-on-the-screen.patch delete mode 100644 config/grub/nvme/patches/0012-don-t-print-error-if-module-not-found.patch delete mode 100644 config/grub/nvme/patches/0013-don-t-print-empty-error-messages.patch delete mode 100644 config/grub/nvme/patches/0014-Add-native-NVMe-driver-based-on-SeaBIOS.patch delete mode 100644 config/grub/nvme/patches/0015-kern-coreboot-mmap-Map-to-reserved.patch delete mode 100644 config/grub/xhci_nvme/patches/0003-Add-CC0-license.patch create mode 100644 config/grub/xhci_nvme/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch delete mode 100644 config/grub/xhci_nvme/patches/0004-Define-GRUB_UINT32_MAX.patch create mode 100644 config/grub/xhci_nvme/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch delete mode 100644 config/grub/xhci_nvme/patches/0005-Add-Argon2-algorithm.patch create mode 100644 config/grub/xhci_nvme/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch delete mode 100644 config/grub/xhci_nvme/patches/0006-Error-on-missing-Argon2id-parameters.patch create mode 100644 config/grub/xhci_nvme/patches/0006-don-t-print-error-if-module-not-found.patch delete mode 100644 config/grub/xhci_nvme/patches/0007-Compile-with-Argon2id-support.patch create mode 100644 config/grub/xhci_nvme/patches/0007-don-t-print-empty-error-messages.patch delete mode 100644 config/grub/xhci_nvme/patches/0008-Make-grub-install-work-with-Argon2.patch create mode 100644 config/grub/xhci_nvme/patches/0008-grub-core-bus-usb-Parse-SuperSpeed-companion-descrip.patch delete mode 100644 config/grub/xhci_nvme/patches/0009-at_keyboard-coreboot-force-scancodes2-translate.patch create mode 100644 config/grub/xhci_nvme/patches/0009-usb-Add-enum-for-xHCI.patch delete mode 100644 config/grub/xhci_nvme/patches/0010-keylayouts-don-t-print-Unknown-key-message.patch create mode 100644 config/grub/xhci_nvme/patches/0010-usbtrans-Set-default-maximum-packet-size.patch delete mode 100644 config/grub/xhci_nvme/patches/0011-don-t-print-missing-prefix-errors-on-the-screen.patch create mode 100644 config/grub/xhci_nvme/patches/0011-grub-core-bus-usb-Add-function-pointer-for-attach-de.patch delete mode 100644 config/grub/xhci_nvme/patches/0012-don-t-print-error-if-module-not-found.patch create mode 100644 config/grub/xhci_nvme/patches/0012-grub-core-bus-usb-usbhub-Add-new-private-fields-for-.patch delete mode 100644 config/grub/xhci_nvme/patches/0013-don-t-print-empty-error-messages.patch create mode 100644 config/grub/xhci_nvme/patches/0013-grub-core-bus-usb-Add-xhci-support.patch delete mode 100644 config/grub/xhci_nvme/patches/0014-grub-core-bus-usb-Parse-SuperSpeed-companion-descrip.patch create mode 100644 config/grub/xhci_nvme/patches/0014-grub-core-bus-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch delete mode 100644 config/grub/xhci_nvme/patches/0015-usb-Add-enum-for-xHCI.patch create mode 100644 config/grub/xhci_nvme/patches/0015-xHCI-also-accept-SBRN-0x31-and-0x32.patch delete mode 100644 config/grub/xhci_nvme/patches/0016-usbtrans-Set-default-maximum-packet-size.patch create mode 100644 config/grub/xhci_nvme/patches/0016-xhci-fix-port-indexing.patch delete mode 100644 config/grub/xhci_nvme/patches/0017-grub-core-bus-usb-Add-function-pointer-for-attach-de.patch create mode 100644 config/grub/xhci_nvme/patches/0017-xhci-configure-TT-for-non-root-hubs.patch create mode 100644 config/grub/xhci_nvme/patches/0018-Fix-compilation-on-x86_64.patch delete mode 100644 config/grub/xhci_nvme/patches/0018-grub-core-bus-usb-usbhub-Add-new-private-fields-for-.patch create mode 100644 config/grub/xhci_nvme/patches/0019-Add-native-NVMe-driver-based-on-SeaBIOS.patch delete mode 100644 config/grub/xhci_nvme/patches/0019-grub-core-bus-usb-Add-xhci-support.patch delete mode 100644 config/grub/xhci_nvme/patches/0020-grub-core-bus-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch create mode 100644 config/grub/xhci_nvme/patches/0020-kern-coreboot-mmap-Map-to-reserved.patch delete mode 100644 config/grub/xhci_nvme/patches/0021-xHCI-also-accept-SBRN-0x31-and-0x32.patch delete mode 100644 config/grub/xhci_nvme/patches/0022-xhci-fix-port-indexing.patch delete mode 100644 config/grub/xhci_nvme/patches/0023-xhci-configure-TT-for-non-root-hubs.patch delete mode 100644 config/grub/xhci_nvme/patches/0024-Fix-compilation-on-x86_64.patch delete mode 100644 config/grub/xhci_nvme/patches/0025-Add-native-NVMe-driver-based-on-SeaBIOS.patch delete mode 100644 config/grub/xhci_nvme/patches/0026-kern-coreboot-mmap-Map-to-reserved.patch diff --git a/config/grub/default/patches/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 c41f2d4d..f3ec1935 100644 --- a/config/grub/default/patches/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 dae0cfdbb484eb3576300ad9c4d2c362f4e8fa64 Mon Sep 17 00:00:00 2001 +From 3334727192bca5c64e9e1321da23c4b1e745deb2 Mon Sep 17 00:00:00 2001 From: Leah Rowe Date: Sun, 31 Oct 2021 03:47:05 +0000 -Subject: [PATCH 01/14] mitigate grub's missing characters for borders/arrow +Subject: [PATCH 1/8] mitigate grub's missing characters for borders/arrow characters This cleans up the display on the main screen in GRUB. @@ -86,5 +86,5 @@ index 9c383e64a..8ec1dd1e8 100644 grub_term_highlight_color = old_color_highlight; geo->timeout_y = geo->first_entry_y + geo->num_entries -- -2.39.5 +2.47.3 diff --git a/config/grub/default/patches/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 e30f1386..a833d0f9 100644 --- a/config/grub/default/patches/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,17 +1,17 @@ -From 25ae072be49c23abffff657085c16ac3780b8cda Mon Sep 17 00:00:00 2001 +From cc6d74da1a6a77935e094601f4f212cd410f5b53 Mon Sep 17 00:00:00 2001 From: Leah Rowe Date: Sat, 19 Nov 2022 16:30:24 +0000 -Subject: [PATCH 02/14] say the name libreboot, in the grub menu +Subject: [PATCH 2/8] 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 96abfda2f..d806db9c4 100644 +index de9a3f961..1fabb9c86 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); @@ -21,5 +21,5 @@ index 96abfda2f..d806db9c4 100644 return; -- -2.39.5 +2.47.3 diff --git a/config/grub/default/patches/0003-Add-CC0-license.patch b/config/grub/default/patches/0003-Add-CC0-license.patch deleted file mode 100644 index 09b70f1c..00000000 --- a/config/grub/default/patches/0003-Add-CC0-license.patch +++ /dev/null @@ -1,42 +0,0 @@ -From e9969b4ee38e3d9fda1fdff02e127830d7fdf2ec Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 03/14] Add CC0 license - -Signed-off-by: Nicholas Johnson ---- - 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 de8c3aa8d..4a3be8568 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -495,7 +495,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.5 - diff --git a/config/grub/default/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch b/config/grub/default/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch new file mode 100644 index 00000000..6ba279b9 --- /dev/null +++ b/config/grub/default/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch @@ -0,0 +1,107 @@ +From d5aead07155d6eeb36971c0a2e5ee1392a025f91 Mon Sep 17 00:00:00 2001 +From: Leah Rowe +Date: Mon, 30 Oct 2023 22:19:21 +0000 +Subject: [PATCH 3/8] 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 +--- + 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/default/patches/0004-Define-GRUB_UINT32_MAX.patch b/config/grub/default/patches/0004-Define-GRUB_UINT32_MAX.patch deleted file mode 100644 index 6d413bae..00000000 --- a/config/grub/default/patches/0004-Define-GRUB_UINT32_MAX.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 421a44b2f8211fa46ea523fc0feeaba9940af0e7 Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 04/14] Define GRUB_UINT32_MAX - -Signed-off-by: Nicholas Johnson ---- - include/grub/types.h | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/include/grub/types.h b/include/grub/types.h -index 45079bf65..8c0b30395 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.5 - diff --git a/config/grub/default/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch b/config/grub/default/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch new file mode 100644 index 00000000..b25fbd33 --- /dev/null +++ b/config/grub/default/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch @@ -0,0 +1,38 @@ +From 22a0e4608428f7f0131789b6bc0e0203b994163f Mon Sep 17 00:00:00 2001 +From: Leah Rowe +Date: Tue, 31 Oct 2023 10:33:28 +0000 +Subject: [PATCH 4/8] 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 +--- + 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/default/patches/0005-Add-Argon2-algorithm.patch b/config/grub/default/patches/0005-Add-Argon2-algorithm.patch deleted file mode 100644 index 26a150b7..00000000 --- a/config/grub/default/patches/0005-Add-Argon2-algorithm.patch +++ /dev/null @@ -1,2612 +0,0 @@ -From a31496a4fb9dc85dfbfc3442898aca4b64716986 Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 05/14] Add Argon2 algorithm - -Signed-off-by: Nicholas Johnson ---- - 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 f4367f895..9d96cedf9 100644 ---- a/docs/grub-dev.texi -+++ b/docs/grub-dev.texi -@@ -503,12 +503,76 @@ GRUB includes some code from other projects, and it is sometimes necessary - to update it. - - @menu -+* Argon2:: - * Gnulib:: - * jsmn:: - * minilzo:: - * libtasn1:: - @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 and to "argon2.h". -+@item Add include 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 24e8c8437..0ee65d54d 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -1219,6 +1219,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 -+ -+#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 -+#include -+ -+#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 -+#include /* 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.. 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 -+ */ -+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.5 - diff --git a/config/grub/default/patches/0005-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 new file mode 100644 index 00000000..68191318 --- /dev/null +++ b/config/grub/default/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch @@ -0,0 +1,102 @@ +From d04a862006aaf754af4d0ec8efee33e9a59c7d0c Mon Sep 17 00:00:00 2001 +From: Leah Rowe +Date: Sun, 5 Nov 2023 16:14:58 +0000 +Subject: [PATCH 5/8] 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 +--- + 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/default/patches/0006-Error-on-missing-Argon2id-parameters.patch b/config/grub/default/patches/0006-Error-on-missing-Argon2id-parameters.patch deleted file mode 100644 index 1531d60c..00000000 --- a/config/grub/default/patches/0006-Error-on-missing-Argon2id-parameters.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 594a7011d551af530bbbdf5e39b941811a0b7811 Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 06/14] Error on missing Argon2id parameters - -Signed-off-by: Nicholas Johnson ---- - 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 b17cd2115..bbd8f5579 100644 ---- a/grub-core/disk/luks2.c -+++ b/grub-core/disk/luks2.c -@@ -39,6 +39,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; -@@ -91,7 +92,7 @@ struct grub_luks2_keyslot - grub_int64_t time; - grub_int64_t memory; - grub_int64_t cpus; -- } argon2i; -+ } argon2; - struct - { - const char *hash; -@@ -161,10 +162,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")) -@@ -460,6 +462,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.5 - diff --git a/config/grub/default/patches/0006-don-t-print-error-if-module-not-found.patch b/config/grub/default/patches/0006-don-t-print-error-if-module-not-found.patch new file mode 100644 index 00000000..ef805b48 --- /dev/null +++ b/config/grub/default/patches/0006-don-t-print-error-if-module-not-found.patch @@ -0,0 +1,34 @@ +From 1d72be25322037c703c5fa95ee29b8ee7b7d7106 Mon Sep 17 00:00:00 2001 +From: Leah Rowe +Date: Sun, 5 Nov 2023 16:36:22 +0000 +Subject: [PATCH 6/8] 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 +--- + 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/default/patches/0007-Compile-with-Argon2id-support.patch b/config/grub/default/patches/0007-Compile-with-Argon2id-support.patch deleted file mode 100644 index 344dfb1d..00000000 --- a/config/grub/default/patches/0007-Compile-with-Argon2id-support.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 6a757a3cdf22e840162bb222a87446a32d9b94a2 Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 07/14] Compile with Argon2id support - -Signed-off-by: Nicholas Johnson ---- - 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 038253b37..2f19569c9 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 0ee65d54d..cd29a9df8 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -1242,7 +1242,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 bbd8f5579..02cd615d9 100644 ---- a/grub-core/disk/luks2.c -+++ b/grub-core/disk/luks2.c -@@ -28,6 +28,7 @@ - #include - #include - -+#include - #include - #include - -@@ -463,8 +464,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.5 - diff --git a/config/grub/default/patches/0007-don-t-print-empty-error-messages.patch b/config/grub/default/patches/0007-don-t-print-empty-error-messages.patch new file mode 100644 index 00000000..5dfdb676 --- /dev/null +++ b/config/grub/default/patches/0007-don-t-print-empty-error-messages.patch @@ -0,0 +1,31 @@ +From a0e49c6ae97114afa386286f6005dd9b3a896797 Mon Sep 17 00:00:00 2001 +From: Leah Rowe +Date: Sun, 5 Nov 2023 17:25:20 +0000 +Subject: [PATCH 7/8] 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 +--- + 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/default/patches/0008-Make-grub-install-work-with-Argon2.patch b/config/grub/default/patches/0008-Make-grub-install-work-with-Argon2.patch deleted file mode 100644 index b7ea852a..00000000 --- a/config/grub/default/patches/0008-Make-grub-install-work-with-Argon2.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 4e4ded3f127f5567bdb41de7b671bd9b2a478125 Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 08/14] Make grub-install work with Argon2 - -Signed-off-by: Nicholas Johnson ---- - util/grub-install.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/util/grub-install.c b/util/grub-install.c -index 060246589..059036d3c 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.5 - 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..a14e118b --- /dev/null +++ b/config/grub/default/patches/0008-kern-coreboot-mmap-Map-to-reserved.patch @@ -0,0 +1,37 @@ +From b6f5e33972320c171d0fe44ac2afe4eac0b4b3eb Mon Sep 17 00:00:00 2001 +From: Paul Menzel +Date: Mon, 17 May 2021 10:24:36 +0200 +Subject: [PATCH 8/8] kern/coreboot/mmap: Map to reserved + +https://git.savannah.gnu.org/cgit/grub.git/commit/?id=6de9ee86bf9ae50967413e6a73b5dfd13e5ffb50 + +Signed-off-by: Paul Menzel +--- + 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-at_keyboard-coreboot-force-scancodes2-translate.patch b/config/grub/default/patches/0009-at_keyboard-coreboot-force-scancodes2-translate.patch deleted file mode 100644 index 12f6f111..00000000 --- a/config/grub/default/patches/0009-at_keyboard-coreboot-force-scancodes2-translate.patch +++ /dev/null @@ -1,107 +0,0 @@ -From fc815438e70cbb13166ab6711b6f6460521b1fd4 Mon Sep 17 00:00:00 2001 -From: Leah Rowe -Date: Mon, 30 Oct 2023 22:19:21 +0000 -Subject: [PATCH 09/14] 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 ---- - 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.39.5 - diff --git a/config/grub/default/patches/0010-keylayouts-don-t-print-Unknown-key-message.patch b/config/grub/default/patches/0010-keylayouts-don-t-print-Unknown-key-message.patch deleted file mode 100644 index 8c0a5054..00000000 --- a/config/grub/default/patches/0010-keylayouts-don-t-print-Unknown-key-message.patch +++ /dev/null @@ -1,38 +0,0 @@ -From defb7ad35579c321d32b81af7ddd6fecf34cb618 Mon Sep 17 00:00:00 2001 -From: Leah Rowe -Date: Tue, 31 Oct 2023 10:33:28 +0000 -Subject: [PATCH 10/14] 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 ---- - 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.39.5 - diff --git a/config/grub/default/patches/0011-don-t-print-missing-prefix-errors-on-the-screen.patch b/config/grub/default/patches/0011-don-t-print-missing-prefix-errors-on-the-screen.patch deleted file mode 100644 index cef7a273..00000000 --- a/config/grub/default/patches/0011-don-t-print-missing-prefix-errors-on-the-screen.patch +++ /dev/null @@ -1,102 +0,0 @@ -From d0345db429be8089145e0c072db9ac8db0b644bd Mon Sep 17 00:00:00 2001 -From: Leah Rowe -Date: Sun, 5 Nov 2023 16:14:58 +0000 -Subject: [PATCH 11/14] 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 ---- - 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 4a3be8568..6ae3d73f8 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -881,7 +881,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.39.5 - diff --git a/config/grub/default/patches/0012-don-t-print-error-if-module-not-found.patch b/config/grub/default/patches/0012-don-t-print-error-if-module-not-found.patch deleted file mode 100644 index e30c3f9a..00000000 --- a/config/grub/default/patches/0012-don-t-print-error-if-module-not-found.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 2fe963570ac19e3390a792ca2c195112d4efdc24 Mon Sep 17 00:00:00 2001 -From: Leah Rowe -Date: Sun, 5 Nov 2023 16:36:22 +0000 -Subject: [PATCH 12/14] 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 ---- - 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 6ae3d73f8..4c15027fe 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -511,7 +511,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.39.5 - diff --git a/config/grub/default/patches/0013-don-t-print-empty-error-messages.patch b/config/grub/default/patches/0013-don-t-print-empty-error-messages.patch deleted file mode 100644 index 0cdadbe9..00000000 --- a/config/grub/default/patches/0013-don-t-print-empty-error-messages.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 5a1dd3c19307859aac7d1a22a7a0c0c7ffb09ddb Mon Sep 17 00:00:00 2001 -From: Leah Rowe -Date: Sun, 5 Nov 2023 17:25:20 +0000 -Subject: [PATCH 13/14] 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 ---- - 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 53c734de7..7cac53983 100644 ---- a/grub-core/kern/err.c -+++ b/grub-core/kern/err.c -@@ -107,7 +107,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.39.5 - diff --git a/config/grub/default/patches/0014-kern-coreboot-mmap-Map-to-reserved.patch b/config/grub/default/patches/0014-kern-coreboot-mmap-Map-to-reserved.patch deleted file mode 100644 index 78e4eafc..00000000 --- a/config/grub/default/patches/0014-kern-coreboot-mmap-Map-to-reserved.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 818f1b19f32e355cc2a0ebe29eee2a2bac7bcb3f Mon Sep 17 00:00:00 2001 -From: Paul Menzel -Date: Mon, 17 May 2021 10:24:36 +0200 -Subject: [PATCH 14/14] kern/coreboot/mmap: Map to reserved - -https://git.savannah.gnu.org/cgit/grub.git/commit/?id=6de9ee86bf9ae50967413e6a73b5dfd13e5ffb50 - -Signed-off-by: Paul Menzel ---- - 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.39.5 - diff --git a/config/grub/default/target.cfg b/config/grub/default/target.cfg index 6a13a189..2319d1a2 100644 --- a/config/grub/default/target.cfg +++ b/config/grub/default/target.cfg @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-3.0-or-later tree="default" -rev="a68a7dece464c35b1c8d20b98502b6881b103911" +rev="280715ec63a3424f5cf1289302cb4ab4e98768f4" 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 index 1c55b85a..3fd43739 100644 --- 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 @@ -1,7 +1,7 @@ -From 759a673b3c4601a32837f2b26661d2998f6cb8d6 Mon Sep 17 00:00:00 2001 +From 248018d7623fa1dc0e1b4ef3a430eac04cbe51bf Mon Sep 17 00:00:00 2001 From: Leah Rowe Date: Sun, 31 Oct 2021 03:47:05 +0000 -Subject: [PATCH 01/15] mitigate grub's missing characters for borders/arrow +Subject: [PATCH 1/9] mitigate grub's missing characters for borders/arrow characters This cleans up the display on the main screen in GRUB. @@ -86,5 +86,5 @@ index 9c383e64a..8ec1dd1e8 100644 grub_term_highlight_color = old_color_highlight; geo->timeout_y = geo->first_entry_y + geo->num_entries -- -2.39.5 +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 index 8515f2a8..d3b273ce 100644 --- 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 @@ -1,17 +1,17 @@ -From 88007c24f8bceb97d0aecf31545c3b49b380b1a6 Mon Sep 17 00:00:00 2001 +From d029792781fe280b8dac1bed457ef78b2af84ee2 Mon Sep 17 00:00:00 2001 From: Leah Rowe Date: Sat, 19 Nov 2022 16:30:24 +0000 -Subject: [PATCH 02/15] say the name libreboot, in the grub menu +Subject: [PATCH 2/9] 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 96abfda2f..d806db9c4 100644 +index de9a3f961..1fabb9c86 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); @@ -21,5 +21,5 @@ index 96abfda2f..d806db9c4 100644 return; -- -2.39.5 +2.47.3 diff --git a/config/grub/nvme/patches/0003-Add-CC0-license.patch b/config/grub/nvme/patches/0003-Add-CC0-license.patch deleted file mode 100644 index 5b09922b..00000000 --- a/config/grub/nvme/patches/0003-Add-CC0-license.patch +++ /dev/null @@ -1,42 +0,0 @@ -From d1925aadf848c269b35a3004c104e014df582536 Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 03/15] Add CC0 license - -Signed-off-by: Nicholas Johnson ---- - 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 de8c3aa8d..4a3be8568 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -495,7 +495,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.5 - 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..8397b689 --- /dev/null +++ b/config/grub/nvme/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch @@ -0,0 +1,107 @@ +From b42452eca17efb562e1ffe809ff8d3bdbbda3728 Mon Sep 17 00:00:00 2001 +From: Leah Rowe +Date: Mon, 30 Oct 2023 22:19:21 +0000 +Subject: [PATCH 3/9] 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 +--- + 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-Define-GRUB_UINT32_MAX.patch b/config/grub/nvme/patches/0004-Define-GRUB_UINT32_MAX.patch deleted file mode 100644 index be0e6b13..00000000 --- a/config/grub/nvme/patches/0004-Define-GRUB_UINT32_MAX.patch +++ /dev/null @@ -1,39 +0,0 @@ -From b0adafee9fcd820dd9d1c03a9619953cb3407854 Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 04/15] Define GRUB_UINT32_MAX - -Signed-off-by: Nicholas Johnson ---- - include/grub/types.h | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/include/grub/types.h b/include/grub/types.h -index 45079bf65..8c0b30395 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.5 - 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..c6a9ee64 --- /dev/null +++ b/config/grub/nvme/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch @@ -0,0 +1,38 @@ +From 831d6824c79032db08a68acbbea6ea374399dba4 Mon Sep 17 00:00:00 2001 +From: Leah Rowe +Date: Tue, 31 Oct 2023 10:33:28 +0000 +Subject: [PATCH 4/9] 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 +--- + 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-Add-Argon2-algorithm.patch b/config/grub/nvme/patches/0005-Add-Argon2-algorithm.patch deleted file mode 100644 index 772a05d9..00000000 --- a/config/grub/nvme/patches/0005-Add-Argon2-algorithm.patch +++ /dev/null @@ -1,2612 +0,0 @@ -From c42e09330674005d8b2d74f75fca387af87e5465 Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 05/15] Add Argon2 algorithm - -Signed-off-by: Nicholas Johnson ---- - 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 f4367f895..9d96cedf9 100644 ---- a/docs/grub-dev.texi -+++ b/docs/grub-dev.texi -@@ -503,12 +503,76 @@ GRUB includes some code from other projects, and it is sometimes necessary - to update it. - - @menu -+* Argon2:: - * Gnulib:: - * jsmn:: - * minilzo:: - * libtasn1:: - @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 and to "argon2.h". -+@item Add include 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 24e8c8437..0ee65d54d 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -1219,6 +1219,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 -+ -+#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 -+#include -+ -+#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 -+#include /* 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.. 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 -+ */ -+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.5 - 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..abdd93ff --- /dev/null +++ b/config/grub/nvme/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch @@ -0,0 +1,102 @@ +From 095ecdc8ad06ac2581a06e4dacbf4091aba8ec6a Mon Sep 17 00:00:00 2001 +From: Leah Rowe +Date: Sun, 5 Nov 2023 16:14:58 +0000 +Subject: [PATCH 5/9] 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 +--- + 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-Error-on-missing-Argon2id-parameters.patch b/config/grub/nvme/patches/0006-Error-on-missing-Argon2id-parameters.patch deleted file mode 100644 index 508fd740..00000000 --- a/config/grub/nvme/patches/0006-Error-on-missing-Argon2id-parameters.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 6c74f4ff91f741e74dca1accc6c173c277f4ca5b Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 06/15] Error on missing Argon2id parameters - -Signed-off-by: Nicholas Johnson ---- - 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 b17cd2115..bbd8f5579 100644 ---- a/grub-core/disk/luks2.c -+++ b/grub-core/disk/luks2.c -@@ -39,6 +39,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; -@@ -91,7 +92,7 @@ struct grub_luks2_keyslot - grub_int64_t time; - grub_int64_t memory; - grub_int64_t cpus; -- } argon2i; -+ } argon2; - struct - { - const char *hash; -@@ -161,10 +162,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")) -@@ -460,6 +462,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.5 - 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..339160d6 --- /dev/null +++ b/config/grub/nvme/patches/0006-don-t-print-error-if-module-not-found.patch @@ -0,0 +1,34 @@ +From 198cb517f44ada4eb561e3182e61b1598535c51b Mon Sep 17 00:00:00 2001 +From: Leah Rowe +Date: Sun, 5 Nov 2023 16:36:22 +0000 +Subject: [PATCH 6/9] 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 +--- + 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-Compile-with-Argon2id-support.patch b/config/grub/nvme/patches/0007-Compile-with-Argon2id-support.patch deleted file mode 100644 index 1cfe1ab7..00000000 --- a/config/grub/nvme/patches/0007-Compile-with-Argon2id-support.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 50157401f90366e5b7c8f80ae7bc59c2276f7c35 Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 07/15] Compile with Argon2id support - -Signed-off-by: Nicholas Johnson ---- - 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 038253b37..2f19569c9 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 0ee65d54d..cd29a9df8 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -1242,7 +1242,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 bbd8f5579..02cd615d9 100644 ---- a/grub-core/disk/luks2.c -+++ b/grub-core/disk/luks2.c -@@ -28,6 +28,7 @@ - #include - #include - -+#include - #include - #include - -@@ -463,8 +464,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.5 - 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..9bec9774 --- /dev/null +++ b/config/grub/nvme/patches/0007-don-t-print-empty-error-messages.patch @@ -0,0 +1,31 @@ +From e344c1bb1bc0bc4df4cf9c049e1e4ba2daf8c2af Mon Sep 17 00:00:00 2001 +From: Leah Rowe +Date: Sun, 5 Nov 2023 17:25:20 +0000 +Subject: [PATCH 7/9] 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 +--- + 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..e3007b05 --- /dev/null +++ b/config/grub/nvme/patches/0008-Add-native-NVMe-driver-based-on-SeaBIOS.patch @@ -0,0 +1,1074 @@ +From e390ed303e135f6509889ff1ef3f5e3bcb28e89f Mon Sep 17 00:00:00 2001 +From: Mate Kukri +Date: Mon, 20 May 2024 11:43:35 +0100 +Subject: [PATCH 8/9] Add native NVMe driver based on SeaBIOS + +Tested to successfully boot Debian on QEMU and OptiPlex 3050. + +Signed-off-by: Mate Kukri +--- + 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 fa4bc54aa..c608d0450 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2768,3 +2768,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 ++ ++/* 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 ++#include ++#include ++#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/0008-Make-grub-install-work-with-Argon2.patch b/config/grub/nvme/patches/0008-Make-grub-install-work-with-Argon2.patch deleted file mode 100644 index bdf9343e..00000000 --- a/config/grub/nvme/patches/0008-Make-grub-install-work-with-Argon2.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 2f7814e55cbae04cb2b307fee559f40cdc70609c Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 08/15] Make grub-install work with Argon2 - -Signed-off-by: Nicholas Johnson ---- - util/grub-install.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/util/grub-install.c b/util/grub-install.c -index 060246589..059036d3c 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.5 - diff --git a/config/grub/nvme/patches/0009-at_keyboard-coreboot-force-scancodes2-translate.patch b/config/grub/nvme/patches/0009-at_keyboard-coreboot-force-scancodes2-translate.patch deleted file mode 100644 index 3a8591d1..00000000 --- a/config/grub/nvme/patches/0009-at_keyboard-coreboot-force-scancodes2-translate.patch +++ /dev/null @@ -1,107 +0,0 @@ -From a90a11f02d5bfc8b9f9e1253a67906fde9102a14 Mon Sep 17 00:00:00 2001 -From: Leah Rowe -Date: Mon, 30 Oct 2023 22:19:21 +0000 -Subject: [PATCH 09/15] 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 ---- - 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.39.5 - 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..f85bbb66 --- /dev/null +++ b/config/grub/nvme/patches/0009-kern-coreboot-mmap-Map-to-reserved.patch @@ -0,0 +1,37 @@ +From 53e9097777bfc3830b9d986e9fd2ff00f40b2aa8 Mon Sep 17 00:00:00 2001 +From: Paul Menzel +Date: Mon, 17 May 2021 10:24:36 +0200 +Subject: [PATCH 9/9] kern/coreboot/mmap: Map to reserved + +https://git.savannah.gnu.org/cgit/grub.git/commit/?id=6de9ee86bf9ae50967413e6a73b5dfd13e5ffb50 + +Signed-off-by: Paul Menzel +--- + 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-keylayouts-don-t-print-Unknown-key-message.patch b/config/grub/nvme/patches/0010-keylayouts-don-t-print-Unknown-key-message.patch deleted file mode 100644 index 8cc2f1b6..00000000 --- a/config/grub/nvme/patches/0010-keylayouts-don-t-print-Unknown-key-message.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 86d06a8075d87cdaece0c5495f7505ff01f1e752 Mon Sep 17 00:00:00 2001 -From: Leah Rowe -Date: Tue, 31 Oct 2023 10:33:28 +0000 -Subject: [PATCH 10/15] 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 ---- - 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.39.5 - diff --git a/config/grub/nvme/patches/0011-don-t-print-missing-prefix-errors-on-the-screen.patch b/config/grub/nvme/patches/0011-don-t-print-missing-prefix-errors-on-the-screen.patch deleted file mode 100644 index 4f7014d8..00000000 --- a/config/grub/nvme/patches/0011-don-t-print-missing-prefix-errors-on-the-screen.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 92aab8e78e0a9dc400376f31fdd7eee980aa33aa Mon Sep 17 00:00:00 2001 -From: Leah Rowe -Date: Sun, 5 Nov 2023 16:14:58 +0000 -Subject: [PATCH 11/15] 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 ---- - 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 4a3be8568..6ae3d73f8 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -881,7 +881,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.39.5 - diff --git a/config/grub/nvme/patches/0012-don-t-print-error-if-module-not-found.patch b/config/grub/nvme/patches/0012-don-t-print-error-if-module-not-found.patch deleted file mode 100644 index fb4c836a..00000000 --- a/config/grub/nvme/patches/0012-don-t-print-error-if-module-not-found.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 62f4bd17485c3d65649de2cef398ec708f35ea9d Mon Sep 17 00:00:00 2001 -From: Leah Rowe -Date: Sun, 5 Nov 2023 16:36:22 +0000 -Subject: [PATCH 12/15] 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 ---- - 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 6ae3d73f8..4c15027fe 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -511,7 +511,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.39.5 - diff --git a/config/grub/nvme/patches/0013-don-t-print-empty-error-messages.patch b/config/grub/nvme/patches/0013-don-t-print-empty-error-messages.patch deleted file mode 100644 index 90aefde6..00000000 --- a/config/grub/nvme/patches/0013-don-t-print-empty-error-messages.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 97381d8c85c0934ca500f07339d89f9f6245b079 Mon Sep 17 00:00:00 2001 -From: Leah Rowe -Date: Sun, 5 Nov 2023 17:25:20 +0000 -Subject: [PATCH 13/15] 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 ---- - 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 53c734de7..7cac53983 100644 ---- a/grub-core/kern/err.c -+++ b/grub-core/kern/err.c -@@ -107,7 +107,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.39.5 - diff --git a/config/grub/nvme/patches/0014-Add-native-NVMe-driver-based-on-SeaBIOS.patch b/config/grub/nvme/patches/0014-Add-native-NVMe-driver-based-on-SeaBIOS.patch deleted file mode 100644 index a181ddc9..00000000 --- a/config/grub/nvme/patches/0014-Add-native-NVMe-driver-based-on-SeaBIOS.patch +++ /dev/null @@ -1,1074 +0,0 @@ -From c8d5481586133d7738a9e2d27b5554470bef719d Mon Sep 17 00:00:00 2001 -From: Mate Kukri -Date: Mon, 20 May 2024 11:43:35 +0100 -Subject: [PATCH 14/15] Add native NVMe driver based on SeaBIOS - -Tested to successfully boot Debian on QEMU and OptiPlex 3050. - -Signed-off-by: Mate Kukri ---- - 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 cd29a9df8..0034f8c61 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -2682,3 +2682,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 -+ -+/* 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 -+#include -+#include -+#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.39.5 - diff --git a/config/grub/nvme/patches/0015-kern-coreboot-mmap-Map-to-reserved.patch b/config/grub/nvme/patches/0015-kern-coreboot-mmap-Map-to-reserved.patch deleted file mode 100644 index 06ebc37c..00000000 --- a/config/grub/nvme/patches/0015-kern-coreboot-mmap-Map-to-reserved.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 9228fa35d5af64e67a33372231baa3862f6fad67 Mon Sep 17 00:00:00 2001 -From: Paul Menzel -Date: Mon, 17 May 2021 10:24:36 +0200 -Subject: [PATCH 15/15] kern/coreboot/mmap: Map to reserved - -https://git.savannah.gnu.org/cgit/grub.git/commit/?id=6de9ee86bf9ae50967413e6a73b5dfd13e5ffb50 - -Signed-off-by: Paul Menzel ---- - 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.39.5 - diff --git a/config/grub/nvme/target.cfg b/config/grub/nvme/target.cfg index 0aff1315..887b9bf7 100644 --- a/config/grub/nvme/target.cfg +++ b/config/grub/nvme/target.cfg @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-3.0-or-later tree="nvme" -rev="a68a7dece464c35b1c8d20b98502b6881b103911" +rev="280715ec63a3424f5cf1289302cb4ab4e98768f4" 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 index d480d60a..46e5059f 100644 --- 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 @@ -1,7 +1,7 @@ -From 6a04ceb244366ddab75ce229afd19687ce35d15a Mon Sep 17 00:00:00 2001 +From 5e70ef9fa3a6474ec827c15329d13c9c984f147a Mon Sep 17 00:00:00 2001 From: Leah Rowe Date: Sun, 31 Oct 2021 03:47:05 +0000 -Subject: [PATCH 01/26] mitigate grub's missing characters for borders/arrow +Subject: [PATCH 01/20] mitigate grub's missing characters for borders/arrow characters This cleans up the display on the main screen in GRUB. @@ -86,5 +86,5 @@ index 9c383e64a..8ec1dd1e8 100644 grub_term_highlight_color = old_color_highlight; geo->timeout_y = geo->first_entry_y + geo->num_entries -- -2.39.5 +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 index e50e6c6a..ace80aa7 100644 --- 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 @@ -1,17 +1,17 @@ -From c18175417d4fa4501dac21ef26b9c30f67ece0fd Mon Sep 17 00:00:00 2001 +From f87a74e198cea4ee79051fc789a06ad3695ad1db Mon Sep 17 00:00:00 2001 From: Leah Rowe Date: Sat, 19 Nov 2022 16:30:24 +0000 -Subject: [PATCH 02/26] say the name libreboot, in the grub menu +Subject: [PATCH 02/20] 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 96abfda2f..d806db9c4 100644 +index de9a3f961..1fabb9c86 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); @@ -21,5 +21,5 @@ index 96abfda2f..d806db9c4 100644 return; -- -2.39.5 +2.47.3 diff --git a/config/grub/xhci_nvme/patches/0003-Add-CC0-license.patch b/config/grub/xhci_nvme/patches/0003-Add-CC0-license.patch deleted file mode 100644 index c2fd1c01..00000000 --- a/config/grub/xhci_nvme/patches/0003-Add-CC0-license.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 72b0b0f76b3cc7f03e42322b77400b89c3ccf766 Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 03/26] Add CC0 license - -Signed-off-by: Nicholas Johnson ---- - 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 de8c3aa8d..4a3be8568 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -495,7 +495,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.5 - 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..d3547d11 --- /dev/null +++ b/config/grub/xhci_nvme/patches/0003-at_keyboard-coreboot-force-scancodes2-translate.patch @@ -0,0 +1,107 @@ +From e647f6b06788022a746e8f38ed2b092013d1d570 Mon Sep 17 00:00:00 2001 +From: Leah Rowe +Date: Mon, 30 Oct 2023 22:19:21 +0000 +Subject: [PATCH 03/20] 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 +--- + 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-Define-GRUB_UINT32_MAX.patch b/config/grub/xhci_nvme/patches/0004-Define-GRUB_UINT32_MAX.patch deleted file mode 100644 index d41c802e..00000000 --- a/config/grub/xhci_nvme/patches/0004-Define-GRUB_UINT32_MAX.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 451ca97719aa9178f3202554c74ab636baece616 Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 04/26] Define GRUB_UINT32_MAX - -Signed-off-by: Nicholas Johnson ---- - include/grub/types.h | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/include/grub/types.h b/include/grub/types.h -index 45079bf65..8c0b30395 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.5 - 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..b3fd8956 --- /dev/null +++ b/config/grub/xhci_nvme/patches/0004-keylayouts-don-t-print-Unknown-key-message.patch @@ -0,0 +1,38 @@ +From 1f0c3362178d1ad44998a98782bcb1e412af9d79 Mon Sep 17 00:00:00 2001 +From: Leah Rowe +Date: Tue, 31 Oct 2023 10:33:28 +0000 +Subject: [PATCH 04/20] 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 +--- + 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-Add-Argon2-algorithm.patch b/config/grub/xhci_nvme/patches/0005-Add-Argon2-algorithm.patch deleted file mode 100644 index d2d202db..00000000 --- a/config/grub/xhci_nvme/patches/0005-Add-Argon2-algorithm.patch +++ /dev/null @@ -1,2612 +0,0 @@ -From 93404ba667dae9a5da9953f7a17245adfe529c78 Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 05/26] Add Argon2 algorithm - -Signed-off-by: Nicholas Johnson ---- - 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 f4367f895..9d96cedf9 100644 ---- a/docs/grub-dev.texi -+++ b/docs/grub-dev.texi -@@ -503,12 +503,76 @@ GRUB includes some code from other projects, and it is sometimes necessary - to update it. - - @menu -+* Argon2:: - * Gnulib:: - * jsmn:: - * minilzo:: - * libtasn1:: - @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 and to "argon2.h". -+@item Add include 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 24e8c8437..0ee65d54d 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -1219,6 +1219,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 -+ -+#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 -+#include -+ -+#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 -+#include /* 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.. 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 -+ */ -+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.5 - 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..0d49f993 --- /dev/null +++ b/config/grub/xhci_nvme/patches/0005-don-t-print-missing-prefix-errors-on-the-screen.patch @@ -0,0 +1,102 @@ +From b902f68dacba764fe4d4200cae000cf23385df8e Mon Sep 17 00:00:00 2001 +From: Leah Rowe +Date: Sun, 5 Nov 2023 16:14:58 +0000 +Subject: [PATCH 05/20] 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 +--- + 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-Error-on-missing-Argon2id-parameters.patch b/config/grub/xhci_nvme/patches/0006-Error-on-missing-Argon2id-parameters.patch deleted file mode 100644 index 3fc6d3dc..00000000 --- a/config/grub/xhci_nvme/patches/0006-Error-on-missing-Argon2id-parameters.patch +++ /dev/null @@ -1,58 +0,0 @@ -From c75424efa3a6357d4785c7a66721809a642b3968 Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 06/26] Error on missing Argon2id parameters - -Signed-off-by: Nicholas Johnson ---- - 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 b17cd2115..bbd8f5579 100644 ---- a/grub-core/disk/luks2.c -+++ b/grub-core/disk/luks2.c -@@ -39,6 +39,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; -@@ -91,7 +92,7 @@ struct grub_luks2_keyslot - grub_int64_t time; - grub_int64_t memory; - grub_int64_t cpus; -- } argon2i; -+ } argon2; - struct - { - const char *hash; -@@ -161,10 +162,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")) -@@ -460,6 +462,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.5 - 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..07c5713f --- /dev/null +++ b/config/grub/xhci_nvme/patches/0006-don-t-print-error-if-module-not-found.patch @@ -0,0 +1,34 @@ +From 2da7fd383afee0a91c1eeb5120a46e165b9386c3 Mon Sep 17 00:00:00 2001 +From: Leah Rowe +Date: Sun, 5 Nov 2023 16:36:22 +0000 +Subject: [PATCH 06/20] 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 +--- + 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-Compile-with-Argon2id-support.patch b/config/grub/xhci_nvme/patches/0007-Compile-with-Argon2id-support.patch deleted file mode 100644 index 0f9d92ee..00000000 --- a/config/grub/xhci_nvme/patches/0007-Compile-with-Argon2id-support.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 801aa8b85d8f3b999f4660cc299a3517e811f0bb Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 07/26] Compile with Argon2id support - -Signed-off-by: Nicholas Johnson ---- - 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 038253b37..2f19569c9 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 0ee65d54d..cd29a9df8 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -1242,7 +1242,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 bbd8f5579..02cd615d9 100644 ---- a/grub-core/disk/luks2.c -+++ b/grub-core/disk/luks2.c -@@ -28,6 +28,7 @@ - #include - #include - -+#include - #include - #include - -@@ -463,8 +464,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.5 - 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..108f4b5f --- /dev/null +++ b/config/grub/xhci_nvme/patches/0007-don-t-print-empty-error-messages.patch @@ -0,0 +1,31 @@ +From 5c26d4bb0cc69cb9f4b9e4f6de794f309d5210f4 Mon Sep 17 00:00:00 2001 +From: Leah Rowe +Date: Sun, 5 Nov 2023 17:25:20 +0000 +Subject: [PATCH 07/20] 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 +--- + 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/xhci_nvme/patches/0008-Make-grub-install-work-with-Argon2.patch b/config/grub/xhci_nvme/patches/0008-Make-grub-install-work-with-Argon2.patch deleted file mode 100644 index 21ad8855..00000000 --- a/config/grub/xhci_nvme/patches/0008-Make-grub-install-work-with-Argon2.patch +++ /dev/null @@ -1,26 +0,0 @@ -From c114684bb103af427296e40b78adc0d036a9b237 Mon Sep 17 00:00:00 2001 -From: Ax333l -Date: Thu, 17 Aug 2023 00:00:00 +0000 -Subject: [PATCH 08/26] Make grub-install work with Argon2 - -Signed-off-by: Nicholas Johnson ---- - util/grub-install.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/util/grub-install.c b/util/grub-install.c -index 060246589..059036d3c 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.5 - diff --git a/config/grub/xhci_nvme/patches/0008-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 new file mode 100644 index 00000000..6144f1e0 --- /dev/null +++ b/config/grub/xhci_nvme/patches/0008-grub-core-bus-usb-Parse-SuperSpeed-companion-descrip.patch @@ -0,0 +1,246 @@ +From b47687966ebad85b16d58469237b048c10f86610 Mon Sep 17 00:00:00 2001 +From: Patrick Rudolph +Date: Sun, 15 Nov 2020 19:00:27 +0100 +Subject: [PATCH 08/20] 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 +to the endpoint descriptor as it's no longer an continous array. + +Signed-off-by: Patrick Rudolph +--- + grub-core/bus/usb/serial/common.c | 2 +- + grub-core/bus/usb/usb.c | 44 +++++++++++++++++++------------ + grub-core/bus/usb/usbhub.c | 22 ++++++++++++---- + grub-core/commands/usbtest.c | 2 +- + grub-core/disk/usbms.c | 2 +- + grub-core/term/usb_keyboard.c | 2 +- + include/grub/usb.h | 2 +- + include/grub/usbdesc.h | 11 +++++++- + 8 files changed, 59 insertions(+), 28 deletions(-) + +diff --git a/grub-core/bus/usb/serial/common.c b/grub-core/bus/usb/serial/common.c +index e9c995a0a..fc847d66d 100644 +--- a/grub-core/bus/usb/serial/common.c ++++ b/grub-core/bus/usb/serial/common.c +@@ -72,7 +72,7 @@ grub_usbserial_attach (grub_usb_device_t usbdev, int configno, int interfno, + for (j = 0; j < interf->endpointcnt; j++) + { + struct grub_usb_desc_endp *endp; +- endp = &usbdev->config[0].interf[interfno].descendp[j]; ++ endp = usbdev->config[0].interf[interfno].descendp[j]; + + if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2 + && (in_endp == GRUB_USB_SERIAL_ENDPOINT_LAST_MATCHING +diff --git a/grub-core/bus/usb/usb.c b/grub-core/bus/usb/usb.c +index 7bd49d201..e578af793 100644 +--- a/grub-core/bus/usb/usb.c ++++ b/grub-core/bus/usb/usb.c +@@ -118,7 +118,7 @@ grub_usb_device_initialize (grub_usb_device_t dev) + struct grub_usb_desc_device *descdev; + struct grub_usb_desc_config config; + grub_usb_err_t err; +- int i; ++ int i, j; + + /* First we have to read first 8 bytes only and determine + * max. size of packet */ +@@ -152,6 +152,7 @@ grub_usb_device_initialize (grub_usb_device_t dev) + int currif; + char *data; + struct grub_usb_desc *desc; ++ struct grub_usb_desc_endp *endp; + + /* First just read the first 4 bytes of the configuration + descriptor, after that it is known how many bytes really have +@@ -201,24 +202,27 @@ grub_usb_device_initialize (grub_usb_device_t dev) + = (struct grub_usb_desc_if *) &data[pos]; + pos += dev->config[i].interf[currif].descif->length; + ++ dev->config[i].interf[currif].descendp = grub_malloc ( ++ dev->config[i].interf[currif].descif->endpointcnt * ++ sizeof(struct grub_usb_desc_endp)); ++ ++ j = 0; + while (pos < config.totallen) + { + desc = (struct grub_usb_desc *)&data[pos]; +- if (desc->type == GRUB_USB_DESCRIPTOR_ENDPOINT) +- break; +- if (!desc->length) +- { +- err = GRUB_USB_ERR_BADDEVICE; +- goto fail; +- } +- pos += desc->length; +- } +- +- /* Point to the first endpoint. */ +- dev->config[i].interf[currif].descendp +- = (struct grub_usb_desc_endp *) &data[pos]; +- pos += (sizeof (struct grub_usb_desc_endp) +- * dev->config[i].interf[currif].descif->endpointcnt); ++ if (desc->type == GRUB_USB_DESCRIPTOR_ENDPOINT) { ++ endp = (struct grub_usb_desc_endp *) &data[pos]; ++ dev->config[i].interf[currif].descendp[j++] = endp; ++ pos += desc->length; ++ } else { ++ if (!desc->length) ++ { ++ err = GRUB_USB_ERR_BADDEVICE; ++ goto fail; ++ } ++ pos += desc->length; ++ } ++ } + } + } + +@@ -226,8 +230,14 @@ grub_usb_device_initialize (grub_usb_device_t dev) + + fail: + +- for (i = 0; i < GRUB_USB_MAX_CONF; i++) ++ for (i = 0; i < GRUB_USB_MAX_CONF; i++) { ++ int currif; ++ ++ for (currif = 0; currif < dev->config[i].descconf->numif; currif++) ++ grub_free (dev->config[i].interf[currif].descendp); ++ + grub_free (dev->config[i].descconf); ++ } + + return err; + } +diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c +index f5608e330..2ae29cba1 100644 +--- a/grub-core/bus/usb/usbhub.c ++++ b/grub-core/bus/usb/usbhub.c +@@ -82,8 +82,14 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, + if (i == GRUB_USBHUB_MAX_DEVICES) + { + grub_error (GRUB_ERR_IO, "can't assign address to USB device"); +- for (i = 0; i < GRUB_USB_MAX_CONF; i++) +- grub_free (dev->config[i].descconf); ++ for (i = 0; i < GRUB_USB_MAX_CONF; i++) { ++ int currif; ++ ++ for (currif = 0; currif < dev->config[i].descconf->numif; currif++) ++ grub_free (dev->config[i].interf[currif].descendp); ++ ++ grub_free (dev->config[i].descconf); ++ } + grub_free (dev); + return NULL; + } +@@ -96,8 +102,14 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, + i, 0, 0, NULL); + if (err) + { +- for (i = 0; i < GRUB_USB_MAX_CONF; i++) +- grub_free (dev->config[i].descconf); ++ for (i = 0; i < GRUB_USB_MAX_CONF; i++) { ++ int currif; ++ ++ for (currif = 0; currif < dev->config[i].descconf->numif; currif++) ++ grub_free (dev->config[i].interf[currif].descendp); ++ ++ grub_free (dev->config[i].descconf); ++ } + grub_free (dev); + return NULL; + } +@@ -176,7 +188,7 @@ grub_usb_add_hub (grub_usb_device_t dev) + i++) + { + struct grub_usb_desc_endp *endp = NULL; +- endp = &dev->config[0].interf[0].descendp[i]; ++ endp = dev->config[0].interf[0].descendp[i]; + + 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 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))) + for (j = 0; j < interf->endpointcnt; j++) + { + struct grub_usb_desc_endp *endp; +- endp = &dev->config[0].interf[i].descendp[j]; ++ endp = dev->config[0].interf[i].descendp[j]; + + grub_printf ("Endpoint #%d: %s, max packed size: %d, transfer type: %s, latency: %d\n", + endp->endp_addr & 15, +diff --git a/grub-core/disk/usbms.c b/grub-core/disk/usbms.c +index b81e3ad9d..b1512dc12 100644 +--- a/grub-core/disk/usbms.c ++++ b/grub-core/disk/usbms.c +@@ -184,7 +184,7 @@ grub_usbms_attach (grub_usb_device_t usbdev, int configno, int interfno) + for (j = 0; j < interf->endpointcnt; j++) + { + struct grub_usb_desc_endp *endp; +- endp = &usbdev->config[0].interf[interfno].descendp[j]; ++ endp = usbdev->config[0].interf[interfno].descendp[j]; + + if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2) + /* Bulk IN endpoint. */ +diff --git a/grub-core/term/usb_keyboard.c b/grub-core/term/usb_keyboard.c +index 7322d8dff..d590979f5 100644 +--- a/grub-core/term/usb_keyboard.c ++++ b/grub-core/term/usb_keyboard.c +@@ -175,7 +175,7 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) + for (j = 0; j < usbdev->config[configno].interf[interfno].descif->endpointcnt; + j++) + { +- endp = &usbdev->config[configno].interf[interfno].descendp[j]; ++ endp = usbdev->config[configno].interf[interfno].descendp[j]; + + if ((endp->endp_addr & 128) && grub_usb_get_ep_type(endp) + == GRUB_USB_EP_INTERRUPT) +diff --git a/include/grub/usb.h b/include/grub/usb.h +index 0f346af12..688c11f6d 100644 +--- a/include/grub/usb.h ++++ b/include/grub/usb.h +@@ -153,7 +153,7 @@ struct grub_usb_interface + { + struct grub_usb_desc_if *descif; + +- struct grub_usb_desc_endp *descendp; ++ struct grub_usb_desc_endp **descendp; + + /* A driver is handling this interface. Do we need to support multiple drivers + for single interface? +diff --git a/include/grub/usbdesc.h b/include/grub/usbdesc.h +index aac5ab05a..bb2ab2e27 100644 +--- a/include/grub/usbdesc.h ++++ b/include/grub/usbdesc.h +@@ -29,7 +29,8 @@ typedef enum { + GRUB_USB_DESCRIPTOR_INTERFACE, + GRUB_USB_DESCRIPTOR_ENDPOINT, + GRUB_USB_DESCRIPTOR_DEBUG = 10, +- GRUB_USB_DESCRIPTOR_HUB = 0x29 ++ GRUB_USB_DESCRIPTOR_HUB = 0x29, ++ GRUB_USB_DESCRIPTOR_SS_ENDPOINT_COMPANION = 0x30 + } grub_usb_descriptor_t; + + struct grub_usb_desc +@@ -105,6 +106,14 @@ struct grub_usb_desc_endp + grub_uint8_t interval; + } GRUB_PACKED; + ++struct grub_usb_desc_ssep { ++ grub_uint8_t length; ++ grub_uint8_t type; ++ grub_uint8_t maxburst; ++ grub_uint8_t attrib; ++ grub_uint16_t interval; ++} GRUB_PACKED; ++ + struct grub_usb_desc_str + { + grub_uint8_t length; +-- +2.47.3 + diff --git a/config/grub/xhci_nvme/patches/0009-at_keyboard-coreboot-force-scancodes2-translate.patch b/config/grub/xhci_nvme/patches/0009-at_keyboard-coreboot-force-scancodes2-translate.patch deleted file mode 100644 index 87164461..00000000 --- a/config/grub/xhci_nvme/patches/0009-at_keyboard-coreboot-force-scancodes2-translate.patch +++ /dev/null @@ -1,107 +0,0 @@ -From dfbfe525d6f138e3db1e683096302045c064096f Mon Sep 17 00:00:00 2001 -From: Leah Rowe -Date: Mon, 30 Oct 2023 22:19:21 +0000 -Subject: [PATCH 09/26] 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 ---- - 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.39.5 - diff --git a/config/grub/xhci_nvme/patches/0009-usb-Add-enum-for-xHCI.patch b/config/grub/xhci_nvme/patches/0009-usb-Add-enum-for-xHCI.patch new file mode 100644 index 00000000..4f88de35 --- /dev/null +++ b/config/grub/xhci_nvme/patches/0009-usb-Add-enum-for-xHCI.patch @@ -0,0 +1,29 @@ +From 05b2607120d0ccfb826bc83d4f4d2741f4f0a6a1 Mon Sep 17 00:00:00 2001 +From: Patrick Rudolph +Date: Mon, 7 Dec 2020 08:41:22 +0100 +Subject: [PATCH 09/20] usb: Add enum for xHCI + +Will be used in future patches. + +Signed-off-by: Patrick Rudolph +--- + include/grub/usb.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/include/grub/usb.h b/include/grub/usb.h +index 688c11f6d..ea6ee8c2c 100644 +--- a/include/grub/usb.h ++++ b/include/grub/usb.h +@@ -51,7 +51,8 @@ typedef enum + GRUB_USB_SPEED_NONE, + GRUB_USB_SPEED_LOW, + GRUB_USB_SPEED_FULL, +- GRUB_USB_SPEED_HIGH ++ GRUB_USB_SPEED_HIGH, ++ GRUB_USB_SPEED_SUPER + } grub_usb_speed_t; + + typedef int (*grub_usb_iterate_hook_t) (grub_usb_device_t dev, void *data); +-- +2.47.3 + diff --git a/config/grub/xhci_nvme/patches/0010-keylayouts-don-t-print-Unknown-key-message.patch b/config/grub/xhci_nvme/patches/0010-keylayouts-don-t-print-Unknown-key-message.patch deleted file mode 100644 index 607f3541..00000000 --- a/config/grub/xhci_nvme/patches/0010-keylayouts-don-t-print-Unknown-key-message.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 18f88785a46e6657e1404e1914638f4768d65008 Mon Sep 17 00:00:00 2001 -From: Leah Rowe -Date: Tue, 31 Oct 2023 10:33:28 +0000 -Subject: [PATCH 10/26] 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 ---- - 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.39.5 - diff --git a/config/grub/xhci_nvme/patches/0010-usbtrans-Set-default-maximum-packet-size.patch b/config/grub/xhci_nvme/patches/0010-usbtrans-Set-default-maximum-packet-size.patch new file mode 100644 index 00000000..938b2266 --- /dev/null +++ b/config/grub/xhci_nvme/patches/0010-usbtrans-Set-default-maximum-packet-size.patch @@ -0,0 +1,33 @@ +From 8de1eafa067bfaae5d58ca0c5616e159356dc6c8 Mon Sep 17 00:00:00 2001 +From: Patrick Rudolph +Date: Mon, 7 Dec 2020 08:41:23 +0100 +Subject: [PATCH 10/20] usbtrans: Set default maximum packet size + +Set the maximum packet size to 512 for SuperSpeed devices. + +Signed-off-by: Patrick Rudolph +--- + grub-core/bus/usb/usbtrans.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/grub-core/bus/usb/usbtrans.c b/grub-core/bus/usb/usbtrans.c +index c5680b33a..c1080bb33 100644 +--- a/grub-core/bus/usb/usbtrans.c ++++ b/grub-core/bus/usb/usbtrans.c +@@ -128,8 +128,12 @@ grub_usb_control_msg (grub_usb_device_t dev, + setupdata_addr = grub_dma_get_phys (setupdata_chunk); + + /* Determine the maximum packet size. */ +- if (dev->descdev.maxsize0) ++ if (dev->descdev.maxsize0 && dev->speed != GRUB_USB_SPEED_SUPER) + max = dev->descdev.maxsize0; ++ else if (dev->descdev.maxsize0 && dev->speed == GRUB_USB_SPEED_SUPER) ++ max = 1UL << dev->descdev.maxsize0; ++ else if (dev->speed == GRUB_USB_SPEED_SUPER) ++ max = 512; + else + max = 64; + +-- +2.47.3 + diff --git a/config/grub/xhci_nvme/patches/0011-don-t-print-missing-prefix-errors-on-the-screen.patch b/config/grub/xhci_nvme/patches/0011-don-t-print-missing-prefix-errors-on-the-screen.patch deleted file mode 100644 index 4f03515e..00000000 --- a/config/grub/xhci_nvme/patches/0011-don-t-print-missing-prefix-errors-on-the-screen.patch +++ /dev/null @@ -1,102 +0,0 @@ -From afd68d1e132970e4fa8e26e9ca0ccb7efb69dc37 Mon Sep 17 00:00:00 2001 -From: Leah Rowe -Date: Sun, 5 Nov 2023 16:14:58 +0000 -Subject: [PATCH 11/26] 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 ---- - 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 4a3be8568..6ae3d73f8 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -881,7 +881,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.39.5 - diff --git a/config/grub/xhci_nvme/patches/0011-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 new file mode 100644 index 00000000..41f5c1e3 --- /dev/null +++ b/config/grub/xhci_nvme/patches/0011-grub-core-bus-usb-Add-function-pointer-for-attach-de.patch @@ -0,0 +1,121 @@ +From 4cda4c986931067b1442c165d6d207d6948529b8 Mon Sep 17 00:00:00 2001 +From: Patrick Rudolph +Date: Sun, 15 Nov 2020 19:51:42 +0100 +Subject: [PATCH 11/20] 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. + +Will be used in future commits, currently this doesn't change any functionality. + +Signed-off-by: Patrick Rudolph +--- + grub-core/bus/usb/ehci.c | 2 ++ + grub-core/bus/usb/ohci.c | 2 ++ + grub-core/bus/usb/uhci.c | 2 ++ + grub-core/bus/usb/usbhub.c | 19 +++++++++++++++++++ + include/grub/usb.h | 4 ++++ + 5 files changed, 29 insertions(+) + +diff --git a/grub-core/bus/usb/ehci.c b/grub-core/bus/usb/ehci.c +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 = { + .hubports = grub_ehci_hubports, + .portstatus = grub_ehci_portstatus, + .detect_dev = grub_ehci_detect_dev, ++ .attach_dev = NULL, ++ .detach_dev = NULL, + /* estimated max. count of TDs for one bulk transfer */ + .max_bulk_tds = GRUB_EHCI_N_TD * 3 / 4 + }; +diff --git a/grub-core/bus/usb/ohci.c b/grub-core/bus/usb/ohci.c +index 5363a61f6..7a3f3e154 100644 +--- a/grub-core/bus/usb/ohci.c ++++ b/grub-core/bus/usb/ohci.c +@@ -1440,6 +1440,8 @@ static struct grub_usb_controller_dev usb_controller = + .hubports = grub_ohci_hubports, + .portstatus = grub_ohci_portstatus, + .detect_dev = grub_ohci_detect_dev, ++ .attach_dev = NULL, ++ .detach_dev = NULL, + /* estimated max. count of TDs for one bulk transfer */ + .max_bulk_tds = GRUB_OHCI_TDS * 3 / 4 + }; +diff --git a/grub-core/bus/usb/uhci.c b/grub-core/bus/usb/uhci.c +index 0fdea4c1e..03c4605b2 100644 +--- a/grub-core/bus/usb/uhci.c ++++ b/grub-core/bus/usb/uhci.c +@@ -845,6 +845,8 @@ static struct grub_usb_controller_dev usb_controller = + .hubports = grub_uhci_hubports, + .portstatus = grub_uhci_portstatus, + .detect_dev = grub_uhci_detect_dev, ++ .attach_dev = NULL, ++ .detach_dev = NULL, + /* estimated max. count of TDs for one bulk transfer */ + .max_bulk_tds = N_TD * 3 / 4 + }; +diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c +index 2ae29cba1..8e963e84b 100644 +--- a/grub-core/bus/usb/usbhub.c ++++ b/grub-core/bus/usb/usbhub.c +@@ -66,6 +66,15 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, + dev->split_hubport = split_hubport; + dev->split_hubaddr = split_hubaddr; + ++ if (controller->dev->attach_dev) { ++ err = controller->dev->attach_dev (controller, dev); ++ if (err) ++ { ++ grub_free (dev); ++ return NULL; ++ } ++ } ++ + err = grub_usb_device_initialize (dev); + if (err) + { +@@ -405,6 +414,8 @@ static void + detach_device (grub_usb_device_t dev) + { + unsigned i; ++ grub_usb_err_t err; ++ + int k; + if (!dev) + return; +@@ -425,6 +436,14 @@ detach_device (grub_usb_device_t dev) + if (inter && inter->detach_hook) + inter->detach_hook (dev, i, k); + } ++ if (dev->controller.dev->detach_dev) { ++ err = dev->controller.dev->detach_dev (&dev->controller, dev); ++ if (err) ++ { ++ // XXX ++ } ++ } ++ + grub_usb_devs[dev->addr] = 0; + } + +diff --git a/include/grub/usb.h b/include/grub/usb.h +index ea6ee8c2c..4dd179db2 100644 +--- a/include/grub/usb.h ++++ b/include/grub/usb.h +@@ -126,6 +126,10 @@ struct grub_usb_controller_dev + + grub_usb_speed_t (*detect_dev) (grub_usb_controller_t dev, int port, int *changed); + ++ grub_usb_err_t (*attach_dev) (grub_usb_controller_t ctrl, grub_usb_device_t dev); ++ ++ grub_usb_err_t (*detach_dev) (grub_usb_controller_t ctrl, grub_usb_device_t dev); ++ + /* Per controller flag - port reset pending, don't do another reset */ + grub_uint64_t pending_reset; + +-- +2.47.3 + diff --git a/config/grub/xhci_nvme/patches/0012-don-t-print-error-if-module-not-found.patch b/config/grub/xhci_nvme/patches/0012-don-t-print-error-if-module-not-found.patch deleted file mode 100644 index e817ca85..00000000 --- a/config/grub/xhci_nvme/patches/0012-don-t-print-error-if-module-not-found.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 06f9480a670d374e1599bf9871f6cd26656418a7 Mon Sep 17 00:00:00 2001 -From: Leah Rowe -Date: Sun, 5 Nov 2023 16:36:22 +0000 -Subject: [PATCH 12/26] 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 ---- - 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 6ae3d73f8..4c15027fe 100644 ---- a/grub-core/kern/dl.c -+++ b/grub-core/kern/dl.c -@@ -511,7 +511,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.39.5 - diff --git a/config/grub/xhci_nvme/patches/0012-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 new file mode 100644 index 00000000..9e947020 --- /dev/null +++ b/config/grub/xhci_nvme/patches/0012-grub-core-bus-usb-usbhub-Add-new-private-fields-for-.patch @@ -0,0 +1,77 @@ +From e29dd6f6ccc73f2e4c04261c0367e1c6a0dbbce6 Mon Sep 17 00:00:00 2001 +From: Patrick Rudolph +Date: Mon, 7 Dec 2020 08:41:25 +0100 +Subject: [PATCH 12/20] 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. + +Signed-off-by: Patrick Rudolph +--- + grub-core/bus/usb/usbhub.c | 11 ++++++++--- + include/grub/usb.h | 5 +++++ + 2 files changed, 13 insertions(+), 3 deletions(-) + +diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c +index 8e963e84b..b4b3a1a61 100644 +--- a/grub-core/bus/usb/usbhub.c ++++ b/grub-core/bus/usb/usbhub.c +@@ -49,7 +49,9 @@ static grub_usb_controller_dev_t grub_usb_list; + static grub_usb_device_t + grub_usb_hub_add_dev (grub_usb_controller_t controller, + grub_usb_speed_t speed, +- int split_hubport, int split_hubaddr) ++ int split_hubport, int split_hubaddr, ++ int root_portno, ++ grub_uint32_t route) + { + grub_usb_device_t dev; + int i; +@@ -65,6 +67,8 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, + dev->speed = speed; + dev->split_hubport = split_hubport; + dev->split_hubaddr = split_hubaddr; ++ dev->root_port = root_portno; ++ dev->route = route; + + if (controller->dev->attach_dev) { + err = controller->dev->attach_dev (controller, dev); +@@ -245,7 +249,7 @@ attach_root_port (struct grub_usb_hub *hub, int portno, + and full/low speed device connected to OHCI/UHCI needs not + transaction translation - e.g. hubport and hubaddr should be + always none (zero) for any device connected to any root hub. */ +- dev = grub_usb_hub_add_dev (hub->controller, speed, 0, 0); ++ dev = grub_usb_hub_add_dev (hub->controller, speed, 0, 0, portno, 0); + hub->controller->dev->pending_reset = 0; + npending--; + if (! dev) +@@ -676,7 +680,8 @@ poll_nonroot_hub (grub_usb_device_t dev) + + /* Add the device and assign a device address to it. */ + next_dev = grub_usb_hub_add_dev (&dev->controller, speed, +- split_hubport, split_hubaddr); ++ split_hubport, split_hubaddr, dev->root_port, ++ dev->route << 4 | (i & 0xf)); + if (dev->controller.dev->pending_reset) + { + dev->controller.dev->pending_reset = 0; +diff --git a/include/grub/usb.h b/include/grub/usb.h +index 4dd179db2..609faf7d0 100644 +--- a/include/grub/usb.h ++++ b/include/grub/usb.h +@@ -237,6 +237,11 @@ struct grub_usb_device + int split_hubport; + + int split_hubaddr; ++ ++ /* xHCI specific information */ ++ int root_port; ++ grub_uint32_t route; ++ void *xhci_priv; + }; + + +-- +2.47.3 + diff --git a/config/grub/xhci_nvme/patches/0013-don-t-print-empty-error-messages.patch b/config/grub/xhci_nvme/patches/0013-don-t-print-empty-error-messages.patch deleted file mode 100644 index 4bf96b50..00000000 --- a/config/grub/xhci_nvme/patches/0013-don-t-print-empty-error-messages.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 272c5f5724c0790aff48b0d6ba75928de2275b33 Mon Sep 17 00:00:00 2001 -From: Leah Rowe -Date: Sun, 5 Nov 2023 17:25:20 +0000 -Subject: [PATCH 13/26] 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 ---- - 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 53c734de7..7cac53983 100644 ---- a/grub-core/kern/err.c -+++ b/grub-core/kern/err.c -@@ -107,7 +107,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.39.5 - diff --git a/config/grub/xhci_nvme/patches/0013-grub-core-bus-usb-Add-xhci-support.patch b/config/grub/xhci_nvme/patches/0013-grub-core-bus-usb-Add-xhci-support.patch new file mode 100644 index 00000000..9661a425 --- /dev/null +++ b/config/grub/xhci_nvme/patches/0013-grub-core-bus-usb-Add-xhci-support.patch @@ -0,0 +1,2807 @@ +From aa09b16597347353c561f55a32eb27f662b41053 Mon Sep 17 00:00:00 2001 +From: Patrick Rudolph +Date: Mon, 7 Dec 2020 08:41:26 +0100 +Subject: [PATCH 13/20] grub-core/bus/usb: Add xhci support + +Add support for xHCI USB controllers. +The code is based on seabios implementation, but has been heavily +modified to match grubs internals. + +Changes done in version 2: +* Code cleanup +* Code style fixes +* Don't leak memory buffers +* Compile without warnings +* Add more defines +* Add more helper functions +* Don't assume a 1:1 virtual to physical mapping +* Flush cachelines after writing buffers +* Don't use hardcoded page size +* Proper scratchpad register setup +* xHCI bios ownership handoff + +Changes done in version 3: +* Fixed a race condition detecting events, which doesn't appear on + qemu based xHCI controllers +* Don't accidently disable USB3.0 devices after first command +* Support arbitrary protocol speed IDs +* Coding style cleanup + +Tested: +* Qemu system x86_64 + * virtual USB HID keyboard (usb-kbd) + * virtual USB HID mass storage (usb-storage) +* init Supermicro X11SSH-F + * iKVM HID keyboard + * USB3 HID mass storage (controller root port) + * USB HID keyboard + +TODO: + * Test on more hardware + * Test on USB3 hubs + * Support for USB 3.1 and USB 3.2 controllers + +Signed-off-by: Patrick Rudolph +Signed-off-by: sylv +--- + Makefile.am | 2 +- + grub-core/Makefile.core.def | 7 + + grub-core/bus/usb/xhci-pci.c | 195 +++ + grub-core/bus/usb/xhci.c | 2496 ++++++++++++++++++++++++++++++++++ + include/grub/usb.h | 4 + + 5 files changed, 2703 insertions(+), 1 deletion(-) + create mode 100644 grub-core/bus/usb/xhci-pci.c + create mode 100644 grub-core/bus/usb/xhci.c + +diff --git a/Makefile.am b/Makefile.am +index 43635d5ff..65016f856 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 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 fa4bc54aa..208badbdf 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -675,6 +675,13 @@ module = { + enable = arm_coreboot; + }; + ++module = { ++ name = xhci; ++ common = bus/usb/xhci.c; ++ pci = bus/usb/xhci-pci.c; ++ enable = pci; ++}; ++ + module = { + name = pci; + common = bus/pci.c; +diff --git a/grub-core/bus/usb/xhci-pci.c b/grub-core/bus/usb/xhci-pci.c +new file mode 100644 +index 000000000..a5bd3c97d +--- /dev/null ++++ b/grub-core/bus/usb/xhci-pci.c +@@ -0,0 +1,195 @@ ++/* xhci.c - XHCI Support. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 9elements Cyber Security ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define GRUB_XHCI_PCI_SBRN_REG 0x60 ++#define GRUB_XHCI_ADDR_MEM_MASK (~0xff) ++ ++/* USBLEGSUP bits and related OS OWNED byte offset */ ++enum ++{ ++ GRUB_XHCI_BIOS_OWNED = (1 << 16), ++ GRUB_XHCI_OS_OWNED = (1 << 24) ++}; ++ ++/* PCI iteration function... */ ++static int ++grub_xhci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid, ++ void *data __attribute__ ((unused))) ++{ ++ volatile grub_uint32_t *regs; ++ grub_uint32_t base, base_h; ++ grub_uint32_t eecp_offset; ++ grub_uint32_t usblegsup = 0; ++ grub_uint64_t maxtime; ++ grub_uint32_t interf; ++ grub_uint32_t subclass; ++ grub_uint32_t class; ++ grub_uint8_t release; ++ grub_uint32_t class_code; ++ ++ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: begin\n"); ++ ++ if (pciid == GRUB_CS5536_PCIID) ++ { ++ grub_dprintf ("xhci", "CS5536 not supported\n"); ++ return 0; ++ } ++ else ++ { ++ grub_pci_address_t addr; ++ addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); ++ class_code = grub_pci_read (addr) >> 8; ++ interf = class_code & 0xFF; ++ subclass = (class_code >> 8) & 0xFF; ++ class = class_code >> 16; ++ ++ /* If this is not an XHCI controller, just return. */ ++ if (class != 0x0c || subclass != 0x03 || interf != 0x30) ++ return 0; ++ ++ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: class OK\n"); ++ ++ /* 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) ++ { ++ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: Wrong SBRN: %0x\n", ++ release); ++ return 0; ++ } ++ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: bus rev. num. OK\n"); ++ ++ /* Determine XHCI XHCC registers base address. */ ++ addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); ++ base = grub_pci_read (addr); ++ addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG1); ++ base_h = grub_pci_read (addr); ++ /* Stop if registers are mapped above 4G - GRUB does not currently ++ * work with registers mapped above 4G */ ++ if (((base & GRUB_PCI_ADDR_MEM_TYPE_MASK) != GRUB_PCI_ADDR_MEM_TYPE_32) ++ && (base_h != 0)) ++ { ++ grub_dprintf ("xhci", ++ "XHCI grub_xhci_pci_iter: registers above 4G are not supported\n"); ++ return 0; ++ } ++ base &= GRUB_PCI_ADDR_MEM_MASK; ++ if (!base) ++ { ++ grub_dprintf ("xhci", ++ "XHCI: XHCI is not mapped\n"); ++ return 0; ++ } ++ ++ /* Set bus master - needed for coreboot, VMware, broken BIOSes etc. */ ++ addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND); ++ grub_pci_write_word(addr, ++ GRUB_PCI_COMMAND_MEM_ENABLED ++ | GRUB_PCI_COMMAND_BUS_MASTER ++ | grub_pci_read_word(addr)); ++ ++ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: 32-bit XHCI OK\n"); ++ } ++ ++ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: iobase of XHCC: %08x\n", ++ (base & GRUB_XHCI_ADDR_MEM_MASK)); ++ ++ regs = grub_pci_device_map_range (dev, ++ (base & GRUB_XHCI_ADDR_MEM_MASK), ++ 0x100); ++ ++ /* Is there EECP ? */ ++ eecp_offset = (grub_le_to_cpu32 (regs[2]) >> 8) & 0xff; ++ ++ /* Determine and change ownership. */ ++ /* EECP offset valid in HCCPARAMS */ ++ /* Ownership can be changed via EECP only */ ++ if (pciid != GRUB_CS5536_PCIID && eecp_offset >= 0x40) ++ { ++ grub_pci_address_t pciaddr_eecp; ++ pciaddr_eecp = grub_pci_make_address (dev, eecp_offset); ++ ++ usblegsup = grub_pci_read (pciaddr_eecp); ++ if (usblegsup & GRUB_XHCI_BIOS_OWNED) ++ { ++ grub_boot_time ("Taking ownership of XHCI controller"); ++ grub_dprintf ("xhci", ++ "XHCI grub_xhci_pci_iter: XHCI owned by: BIOS\n"); ++ /* Ownership change - set OS_OWNED bit */ ++ grub_pci_write (pciaddr_eecp, usblegsup | GRUB_XHCI_OS_OWNED); ++ /* Ensure PCI register is written */ ++ grub_pci_read (pciaddr_eecp); ++ ++ /* Wait for finish of ownership change, XHCI specification ++ * doesn't say how long it can take... */ ++ maxtime = grub_get_time_ms () + 1000; ++ while ((grub_pci_read (pciaddr_eecp) & GRUB_XHCI_BIOS_OWNED) ++ && (grub_get_time_ms () < maxtime)); ++ if (grub_pci_read (pciaddr_eecp) & GRUB_XHCI_BIOS_OWNED) ++ { ++ grub_dprintf ("xhci", ++ "XHCI grub_xhci_pci_iter: XHCI change ownership timeout"); ++ /* Change ownership in "hard way" - reset BIOS ownership */ ++ grub_pci_write (pciaddr_eecp, GRUB_XHCI_OS_OWNED); ++ /* Ensure PCI register is written */ ++ grub_pci_read (pciaddr_eecp); ++ } ++ } ++ else if (usblegsup & GRUB_XHCI_OS_OWNED) ++ /* XXX: What to do in this case - nothing ? Can it happen ? */ ++ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: XHCI owned by: OS\n"); ++ else ++ { ++ grub_dprintf ("xhci", ++ "XHCI grub_Xhci_pci_iter: XHCI owned by: NONE\n"); ++ /* XXX: What to do in this case ? Can it happen ? ++ * Is code below correct ? */ ++ /* Ownership change - set OS_OWNED bit */ ++ grub_pci_write (pciaddr_eecp, GRUB_XHCI_OS_OWNED); ++ /* Ensure PCI register is written */ ++ grub_pci_read (pciaddr_eecp); ++ } ++ ++ /* Disable SMI, just to be sure. */ ++ pciaddr_eecp = grub_pci_make_address (dev, eecp_offset + 4); ++ grub_pci_write (pciaddr_eecp, 0); ++ /* Ensure PCI register is written */ ++ grub_pci_read (pciaddr_eecp); ++ } ++ ++ grub_dprintf ("xhci", "inithw: XHCI grub_xhci_pci_iter: ownership OK\n"); ++ ++ grub_xhci_init_device (regs); ++ return 0; ++} ++ ++void ++grub_xhci_pci_scan (void) ++{ ++ grub_pci_iterate (grub_xhci_pci_iter, NULL); ++} +diff --git a/grub-core/bus/usb/xhci.c b/grub-core/bus/usb/xhci.c +new file mode 100644 +index 000000000..f4591ffb5 +--- /dev/null ++++ b/grub-core/bus/usb/xhci.c +@@ -0,0 +1,2496 @@ ++/* xhci.c - XHCI Support. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 9elements Cyber Security ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ * ++ * Big parts of this software are inspired by seabios XHCI implementation ++ * Released under LGPLv3. Credits to: ++ * ++ * Copyright (C) 2013 Gerd Hoffmann ++ * Copyright (C) 2014 Kevin O'Connor ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++/* This simple GRUB implementation of XHCI driver */ ++/* Based on the specification ++ * "eXtensible Host Controller Interface for Universal Serial Bus" Revision 1.2 ++ */ ++ ++ ++#define xhci_get_field(data, field) \ ++ (((data) >> field##_SHIFT) & field##_MASK) ++#define XHCI_PORTSC_PLS_MASK 0xf ++#define XHCI_PORTSC_PLS_SHIFT 5 ++#define XHCI_PORTSC_SPEED_MASK 0xf ++#define XHCI_PORTSC_SPEED_SHIFT 10 ++ ++enum ++{ ++ XHCI_USB_FULLSPEED = 1, ++ XHCI_USB_LOWSPEED, ++ XHCI_USB_HIGHSPEED, ++ XHCI_USB_SUPERSPEED ++}; ++ ++/* Chapter 5.3 Host Controller Capability Registers */ ++struct grub_xhci_caps { ++ grub_uint8_t caplength; ++ grub_uint8_t reserved_01; ++ grub_uint16_t hciversion; ++ grub_uint32_t hcsparams1; ++ grub_uint32_t hcsparams2; ++ grub_uint32_t hcsparams3; ++ grub_uint32_t hccparams; ++ grub_uint32_t dboff; ++ grub_uint32_t rtsoff; ++ grub_uint32_t hccparams2; ++} GRUB_PACKED; ++ ++/* extended capabilities */ ++struct grub_xhci_xcap { ++ grub_uint32_t cap; ++ grub_uint32_t data[]; ++} GRUB_PACKED; ++ ++#define XHCI_CAP_LEGACY_SUPPORT 1 ++#define XHCI_CAP_SUPPORTED_PROTOCOL 2 ++ ++struct xhci_portmap { ++ grub_uint8_t start; ++ grub_uint8_t count; ++} GRUB_PACKED; ++ ++struct grub_xhci_op { ++ grub_uint32_t usbcmd; ++ grub_uint32_t usbsts; ++ grub_uint32_t pagesize; ++ grub_uint32_t reserved_01[2]; ++ grub_uint32_t dnctl; ++ grub_uint32_t crcr_low; ++ grub_uint32_t crcr_high; ++ grub_uint32_t reserved_02[4]; ++ grub_uint32_t dcbaap_low; ++ grub_uint32_t dcbaap_high; ++ grub_uint32_t config; ++} GRUB_PACKED; ++ ++enum ++{ ++ GRUB_XHCI_CMD_RS = (1<<0), ++ GRUB_XHCI_CMD_HCRST = (1<<1), ++ GRUB_XHCI_CMD_INTE = (1<<2), ++ GRUB_XHCI_CMD_HSEE = (1<<3), ++ GRUB_XHCI_CMD_LHCRST = (1<<7), ++ GRUB_XHCI_CMD_CSS = (1<<8), ++ GRUB_XHCI_CMD_CRS = (1<<9), ++ GRUB_XHCI_CMD_EWE = (1<<10), ++ GRUB_XHCI_CMD_EU3S = (1<<11) ++}; ++ ++enum ++{ ++ GRUB_XHCI_STS_HCH = (1<<0), ++ GRUB_XHCI_STS_HSE = (1<<2), ++ GRUB_XHCI_STS_EINT = (1<<3), ++ GRUB_XHCI_STS_PCD = (1<<4), ++ GRUB_XHCI_STS_SSS = (1<<8), ++ GRUB_XHCI_STS_RSS = (1<<9), ++ GRUB_XHCI_STS_SRE = (1<<10), ++ GRUB_XHCI_STS_CNR = (1<<11), ++ GRUB_XHCI_STS_HCE = (1<<12) ++}; ++ ++ ++/* Port Registers Offset */ ++#define GRUB_XHCI_PR_OFFSET 0x400 ++/* Interrupter Registers Offset */ ++#define GRUB_XHCI_IR_OFFSET 0x20 ++ ++/* Port Status and Control registers offsets */ ++ ++/* Chapter 6 Data Structures */ ++#define ALIGN_SPBA 64 ++#define ALIGN_DCBAA 64 ++#define ALIGN_CMD_RING_SEG 64 ++#define ALIGN_EVT_RING_SEG 64 ++#define ALIGN_EVT_RING_TABLE 64 ++#define ALIGN_TRB 16 ++#define ALIGN_INCTX 64 ++#define ALIGN_SLOTCTX 32 ++ ++#define BOUNDARY_RING 0x10000 ++ ++enum ++{ ++ GRUB_XHCI_PORTSC_CCS = (1<<0), ++ GRUB_XHCI_PORTSC_PED = (1<<1), ++ GRUB_XHCI_PORTSC_OCA = (1<<3), ++ GRUB_XHCI_PORTSC_PR = (1<<4), ++ GRUB_XHCI_PORTSC_PP = (1<<9), ++ GRUB_XHCI_PORTSC_SPEED_FULL = (1<<10), ++ GRUB_XHCI_PORTSC_SPEED_LOW = (2<<10), ++ GRUB_XHCI_PORTSC_SPEED_HIGH = (3<<10), ++ GRUB_XHCI_PORTSC_SPEED_SUPER = (4<<10), ++ GRUB_XHCI_PORTSC_LWS = (1<<16), ++ GRUB_XHCI_PORTSC_CSC = (1<<17), ++ GRUB_XHCI_PORTSC_PEC = (1<<18), ++ GRUB_XHCI_PORTSC_WRC = (1<<19), ++ GRUB_XHCI_PORTSC_OCC = (1<<20), ++ GRUB_XHCI_PORTSC_PRC = (1<<21), ++ GRUB_XHCI_PORTSC_PLC = (1<<22), ++ GRUB_XHCI_PORTSC_CEC = (1<<23), ++ GRUB_XHCI_PORTSC_CAS = (1<<24), ++ GRUB_XHCI_PORTSC_WCE = (1<<25), ++ GRUB_XHCI_PORTSC_WDE = (1<<26), ++ GRUB_XHCI_PORTSC_WOE = (1<<27), ++ GRUB_XHCI_PORTSC_DR = (1<<30), ++ GRUB_XHCI_PORTSC_WPR = (1<<31) ++}; ++ ++/* XHCI memory data structs */ ++#define GRUB_XHCI_MAX_ENDPOINTS 32 ++ ++#define GRUB_XHCI_RING_ITEMS 128 ++#define GRUB_XHCI_RING_SIZE (GRUB_XHCI_RING_ITEMS*sizeof(struct grub_xhci_trb)) ++/* ++ * xhci_ring structs are allocated with XHCI_RING_SIZE alignment, ++ * then we can get it from a trb pointer (provided by evt ring). ++ */ ++#define XHCI_RING(_trb) \ ++ ((struct grub_xhci_ring*)((grub_uint32_t)(_trb) & ~(GRUB_XHCI_RING_SIZE-1))) ++ ++/* slot context */ ++struct grub_xhci_slotctx { ++ grub_uint32_t ctx[4]; ++ grub_uint32_t reserved_01[4]; ++} GRUB_PACKED; ++ ++/* endpoint context */ ++struct grub_xhci_epctx { ++ grub_uint32_t ctx[2]; ++ grub_uint32_t deq_low; ++ grub_uint32_t deq_high; ++ grub_uint32_t length; ++ grub_uint32_t reserved_01[3]; ++} GRUB_PACKED; ++ ++/* device context array element */ ++struct grub_xhci_devlist { ++ grub_uint32_t ptr_low; ++ grub_uint32_t ptr_high; ++} GRUB_PACKED; ++ ++/* input context */ ++struct grub_xhci_inctx { ++ grub_uint32_t del; ++ grub_uint32_t add; ++ grub_uint32_t reserved_01[6]; ++} GRUB_PACKED; ++ ++/* transfer block (ring element) */ ++struct grub_xhci_trb { ++ grub_uint32_t ptr_low; ++ grub_uint32_t ptr_high; ++ grub_uint32_t status; ++ grub_uint32_t control; ++} GRUB_PACKED; ++ ++#define TRB_C (1<<0) ++#define TRB_TYPE_SHIFT 10 ++#define TRB_TYPE_MASK 0x3f ++#define TRB_TYPE(t) (((t) >> TRB_TYPE_SHIFT) & TRB_TYPE_MASK) ++ ++#define TRB_EV_ED (1<<2) ++ ++#define TRB_TR_ENT (1<<1) ++#define TRB_TR_ISP (1<<2) ++#define TRB_TR_NS (1<<3) ++#define TRB_TR_CH (1<<4) ++#define TRB_TR_IOC (1<<5) ++#define TRB_TR_IDT (1<<6) ++#define TRB_TR_TBC_SHIFT 7 ++#define TRB_TR_TBC_MASK 0x3 ++#define TRB_TR_BEI (1<<9) ++#define TRB_TR_TLBPC_SHIFT 16 ++#define TRB_TR_TLBPC_MASK 0xf ++#define TRB_TR_FRAMEID_SHIFT 20 ++#define TRB_TR_FRAMEID_MASK 0x7ff ++#define TRB_TR_SIA (1<<31) ++ ++#define TRB_TR_DIR (1<<16) ++ ++#define TRB_CR_SLOTID_SHIFT 24 ++#define TRB_CR_SLOTID_MASK 0xff ++#define TRB_CR_EPID_SHIFT 16 ++#define TRB_CR_EPID_MASK 0x1f ++ ++#define TRB_CR_BSR (1<<9) ++#define TRB_CR_DC (1<<9) ++ ++#define TRB_LK_TC (1<<1) ++ ++#define TRB_INTR_SHIFT 22 ++#define TRB_INTR_MASK 0x3ff ++#define TRB_INTR(t) (((t).status >> TRB_INTR_SHIFT) & TRB_INTR_MASK) ++ ++typedef enum TRBType { ++ TRB_RESERVED = 0, ++ TR_NORMAL, ++ TR_SETUP, ++ TR_DATA, ++ TR_STATUS, ++ TR_ISOCH, ++ TR_LINK, ++ TR_EVDATA, ++ TR_NOOP, ++ CR_ENABLE_SLOT, ++ CR_DISABLE_SLOT, ++ CR_ADDRESS_DEVICE, ++ CR_CONFIGURE_ENDPOINT, ++ CR_EVALUATE_CONTEXT, ++ CR_RESET_ENDPOINT, ++ CR_STOP_ENDPOINT, ++ CR_SET_TR_DEQUEUE, ++ CR_RESET_DEVICE, ++ CR_FORCE_EVENT, ++ CR_NEGOTIATE_BW, ++ CR_SET_LATENCY_TOLERANCE, ++ CR_GET_PORT_BANDWIDTH, ++ CR_FORCE_HEADER, ++ CR_NOOP, ++ ER_TRANSFER = 32, ++ ER_COMMAND_COMPLETE, ++ ER_PORT_STATUS_CHANGE, ++ ER_BANDWIDTH_REQUEST, ++ ER_DOORBELL, ++ ER_HOST_CONTROLLER, ++ ER_DEVICE_NOTIFICATION, ++ ER_MFINDEX_WRAP, ++} TRBType; ++ ++typedef enum TRBCCode { ++ CC_INVALID = 0, ++ CC_SUCCESS, ++ CC_DATA_BUFFER_ERROR, ++ CC_BABBLE_DETECTED, ++ CC_USB_TRANSACTION_ERROR, ++ CC_TRB_ERROR, ++ CC_STALL_ERROR, ++ CC_RESOURCE_ERROR, ++ CC_BANDWIDTH_ERROR, ++ CC_NO_SLOTS_ERROR, ++ CC_INVALID_STREAM_TYPE_ERROR, ++ CC_SLOT_NOT_ENABLED_ERROR, ++ CC_EP_NOT_ENABLED_ERROR, ++ CC_SHORT_PACKET, ++ CC_RING_UNDERRUN, ++ CC_RING_OVERRUN, ++ CC_VF_ER_FULL, ++ CC_PARAMETER_ERROR, ++ CC_BANDWIDTH_OVERRUN, ++ CC_CONTEXT_STATE_ERROR, ++ CC_NO_PING_RESPONSE_ERROR, ++ CC_EVENT_RING_FULL_ERROR, ++ CC_INCOMPATIBLE_DEVICE_ERROR, ++ CC_MISSED_SERVICE_ERROR, ++ CC_COMMAND_RING_STOPPED, ++ CC_COMMAND_ABORTED, ++ CC_STOPPED, ++ CC_STOPPED_LENGTH_INVALID, ++ CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR = 29, ++ CC_ISOCH_BUFFER_OVERRUN = 31, ++ CC_EVENT_LOST_ERROR, ++ CC_UNDEFINED_ERROR, ++ CC_INVALID_STREAM_ID_ERROR, ++ CC_SECONDARY_BANDWIDTH_ERROR, ++ CC_SPLIT_TRANSACTION_ERROR ++} TRBCCode; ++ ++enum { ++ PLS_U0 = 0, ++ PLS_U1 = 1, ++ PLS_U2 = 2, ++ PLS_U3 = 3, ++ PLS_DISABLED = 4, ++ PLS_RX_DETECT = 5, ++ PLS_INACTIVE = 6, ++ PLS_POLLING = 7, ++ PLS_RECOVERY = 8, ++ PLS_HOT_RESET = 9, ++ PLS_COMPILANCE_MODE = 10, ++ PLS_TEST_MODE = 11, ++ PLS_RESUME = 15, ++}; ++ ++/* event ring segment */ ++struct grub_xhci_er_seg { ++ grub_uint32_t ptr_low; ++ grub_uint32_t ptr_high; ++ grub_uint32_t size; ++ grub_uint32_t reserved_01; ++} GRUB_PACKED; ++ ++struct grub_xhci_ring { ++ struct grub_xhci_trb ring[GRUB_XHCI_RING_ITEMS]; ++ struct grub_xhci_trb evt; ++ grub_uint32_t eidx; ++ grub_uint32_t nidx; ++ grub_uint32_t cs; ++}; ++ ++/* port registers */ ++struct grub_xhci_pr { ++ grub_uint32_t portsc; ++ grub_uint32_t portpmsc; ++ grub_uint32_t portli; ++ grub_uint32_t reserved_01; ++} GRUB_PACKED; ++ ++/* doorbell registers */ ++struct grub_xhci_db { ++ grub_uint32_t doorbell; ++} GRUB_PACKED; ++ ++/* runtime registers */ ++struct grub_xhci_rts { ++ grub_uint32_t mfindex; ++} GRUB_PACKED; ++ ++/* interrupter registers */ ++struct grub_xhci_ir { ++ grub_uint32_t iman; ++ grub_uint32_t imod; ++ grub_uint32_t erstsz; ++ grub_uint32_t reserved_01; ++ grub_uint32_t erstba_low; ++ grub_uint32_t erstba_high; ++ grub_uint32_t erdp_low; ++ grub_uint32_t erdp_high; ++} GRUB_PACKED; ++ ++struct grub_xhci_psid { ++ grub_uint8_t id; ++ grub_uint8_t psie; ++ grub_uint16_t psim; ++ grub_uint64_t bitrate; ++ grub_usb_speed_t grub_usb_speed; ++}; ++ ++struct grub_xhci_psids { ++ grub_uint8_t major; ++ grub_uint8_t minor; ++ struct grub_xhci_psid psids[16]; ++}; ++ ++struct grub_xhci ++{ ++ grub_uint8_t shutdown; /* 1 if preparing shutdown of controller */ ++ /* xhci registers */ ++ volatile struct grub_xhci_caps *caps; /* Capability registers */ ++ volatile struct grub_xhci_op *op; /* Operational registers */ ++ volatile struct grub_xhci_pr *pr; /* Port Registers */ ++ volatile struct grub_xhci_db *db; /* doorbell */ ++ volatile struct grub_xhci_ir *ir; /* Interrupt Registers */ ++ /* devinfo */ ++ grub_uint32_t xcap; ++ grub_uint32_t ports; ++ grub_uint32_t slots; ++ grub_uint8_t flag64; ++ grub_uint16_t spb; ++ grub_uint32_t pagesize; ++ struct xhci_portmap usb2; ++ struct xhci_portmap usb3; ++ struct grub_xhci_psids *psids; ++ /* xhci data structures */ ++ struct grub_pci_dma_chunk *devs_dma; ++ volatile struct grub_xhci_devlist *devs; ++ struct grub_pci_dma_chunk *cmds_dma; ++ volatile struct grub_xhci_ring *cmds; ++ struct grub_pci_dma_chunk *evts_dma; ++ volatile struct grub_xhci_ring *evts; ++ struct grub_pci_dma_chunk *eseg_dma; ++ volatile struct grub_xhci_er_seg *eseg; ++ struct grub_pci_dma_chunk *spba_dma; ++ struct grub_pci_dma_chunk *spad_dma; ++ ++ struct grub_xhci *next; ++}; ++ ++struct grub_xhci_priv { ++ grub_uint8_t slotid; ++ grub_uint32_t max_packet; ++ struct grub_pci_dma_chunk *enpoint_trbs_dma[32]; ++ volatile struct grub_xhci_ring *enpoint_trbs[32]; ++ struct grub_pci_dma_chunk *slotctx_dma; ++}; ++ ++struct grub_xhci_port { ++ grub_uint32_t portsc; ++ grub_uint32_t portpmsc; ++ grub_uint32_t portli; ++ grub_uint32_t reserved_01; ++}; ++ ++struct grub_xhci_transfer_controller_data { ++ grub_uint32_t transfer_size; ++}; ++ ++static struct grub_xhci *xhci; ++ ++/**************************************************************** ++ * general access functions ++ ****************************************************************/ ++ ++static inline void ++grub_xhci_write32(volatile void *addr, grub_uint32_t val) { ++ *(volatile grub_uint32_t *)addr = val; ++} ++static inline void ++grub_xhci_write16(volatile void *addr, grub_uint16_t val) { ++ *(volatile grub_uint16_t *)addr = val; ++} ++static inline void ++grub_xhci_write8(void *addr, grub_uint8_t val) { ++ *(volatile grub_uint8_t *)addr = val; ++} ++ ++static inline grub_uint32_t ++grub_xhci_read32(volatile void *addr) { ++ return grub_le_to_cpu32 (*((volatile grub_uint32_t *)addr)); ++} ++ ++static inline grub_uint16_t ++grub_xhci_read16(volatile void *addr) { ++ return grub_le_to_cpu16 (*((volatile grub_uint32_t *)addr)); ++} ++static inline grub_uint8_t ++grub_xhci_read8(volatile void *addr) { ++ return (*((volatile grub_uint32_t *)addr)); ++} ++ ++static inline grub_uint32_t ++grub_xhci_port_read (struct grub_xhci *x, grub_uint32_t port) ++{ ++ return grub_xhci_read32(&x->pr[port].portsc); ++} ++ ++static inline void ++grub_xhci_port_write (struct grub_xhci *x, grub_uint32_t port, ++ grub_uint32_t and_mask, grub_uint32_t or_mask) ++{ ++ grub_uint32_t reg = grub_xhci_port_read(x, port); ++ reg &= and_mask; ++ reg |= or_mask; ++ ++ grub_xhci_write32(&x->pr[port].portsc, reg); ++} ++ ++/**************************************************************** ++ * xhci status and support functions ++ ****************************************************************/ ++ ++static grub_uint32_t xhci_get_pagesize(struct grub_xhci *x) ++{ ++ /* Chapter 5.4.3 Page Size Register (PAGESIZE) */ ++ for (grub_uint8_t i = 0; i < 16; i++) ++ { ++ if (grub_xhci_read32(&x->op->pagesize) & (1 << i)) ++ return 1 << (12 + i); ++ } ++ return 0; ++} ++ ++static grub_uint8_t xhci_is_halted(struct grub_xhci *x) ++{ ++ return !!(grub_xhci_read32(&x->op->usbsts) & 1); ++} ++ ++/* Just for debugging */ ++static void xhci_check_status(struct grub_xhci *x) ++{ ++ grub_uint32_t reg; ++ ++ reg = grub_xhci_read32(&x->op->usbsts); ++ if (reg & 1) ++ grub_dprintf("xhci", "%s: xHCI halted\n", __func__); ++ if (reg & 2) ++ grub_dprintf("xhci", "%s: Host system error detected\n", __func__); ++ if (reg & (1 << 12)) ++ grub_dprintf("xhci", "%s: Internal error detected\n", __func__); ++ reg = grub_xhci_read32(&x->op->crcr_low); ++ if (reg & (1 << 3)) ++ grub_dprintf("xhci", "%s: Command ring running\n", __func__); ++} ++ ++/* xhci_memalign_dma32 allocates DMA memory satisfying alignment and boundary ++ * requirements without wasting to much memory */ ++static struct grub_pci_dma_chunk * ++xhci_memalign_dma32(grub_size_t align, ++ grub_size_t size, ++ grub_size_t boundary) ++{ ++ struct grub_pci_dma_chunk *tmp; ++ const grub_uint32_t mask = boundary - 1; ++ grub_uint32_t start, end; ++ ++ /* Allocate some memory and check if it doesn't cross boundary */ ++ tmp = grub_memalign_dma32(align, size); ++ start = grub_dma_get_phys(tmp); ++ end = start + size - 1; ++ if ((start & mask) == (end & mask)) ++ return tmp; ++ /* Buffer isn't usable, allocate bigger one */ ++ grub_dma_free(tmp); ++ ++ return grub_memalign_dma32(boundary, size); ++} ++ ++/**************************************************************** ++ * helper functions for in context DMA buffer ++ ****************************************************************/ ++ ++static int ++grub_xhci_inctx_size(struct grub_xhci *x) ++{ ++ const grub_uint8_t cnt = GRUB_XHCI_MAX_ENDPOINTS + 1; ++ return (sizeof(struct grub_xhci_inctx) * cnt) << x->flag64; ++} ++ ++static void ++grub_xhci_inctx_sync_dma_caches(struct grub_xhci *x, struct grub_pci_dma_chunk *inctx) ++{ ++ grub_arch_sync_dma_caches(inctx, grub_xhci_inctx_size(x)); ++} ++ ++static struct grub_pci_dma_chunk * ++grub_xhci_alloc_inctx(struct grub_xhci *x, int maxepid, ++ struct grub_usb_device *dev) ++{ ++ int size = grub_xhci_inctx_size(x); ++ struct grub_pci_dma_chunk *dma = xhci_memalign_dma32(ALIGN_INCTX, size, ++ x->pagesize); ++ if (!dma) ++ return NULL; ++ ++ volatile struct grub_xhci_inctx *in = grub_dma_get_virt(dma); ++ grub_memset((void *)in, 0, size); ++ ++ struct grub_xhci_slotctx *slot = (void*)&in[1 << x->flag64]; ++ slot->ctx[0] |= maxepid << 27; /* context entries */ ++ grub_dprintf("xhci", "%s: speed=%d root_port=%d\n", __func__, dev->speed, dev->root_port); ++ switch (dev->speed) { ++ case GRUB_USB_SPEED_FULL: ++ slot->ctx[0] |= XHCI_USB_FULLSPEED << 20; ++ break; ++ case GRUB_USB_SPEED_HIGH: ++ slot->ctx[0] |= XHCI_USB_HIGHSPEED << 20; ++ break; ++ case GRUB_USB_SPEED_LOW: ++ slot->ctx[0] |= XHCI_USB_LOWSPEED << 20; ++ break; ++ case GRUB_USB_SPEED_SUPER: ++ slot->ctx[0] |= XHCI_USB_SUPERSPEED << 20; ++ break; ++ case GRUB_USB_SPEED_NONE: ++ slot->ctx[0] |= 0 << 20; ++ 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 */ ++ } ++ slot->ctx[0] |= dev->route; ++ slot->ctx[1] |= (dev->root_port+1) << 16; ++ ++ grub_arch_sync_dma_caches(in, size); ++ ++ return dma; ++} ++ ++/**************************************************************** ++ * xHCI event processing ++ ****************************************************************/ ++ ++/* Dequeue events on the XHCI event ring generated by the hardware */ ++static void xhci_process_events(struct grub_xhci *x) ++{ ++ volatile struct grub_xhci_ring *evts = x->evts; ++ /* XXX invalidate caches */ ++ ++ for (;;) { ++ /* check for event */ ++ grub_uint32_t nidx = grub_xhci_read32(&evts->nidx); ++ grub_uint32_t cs = grub_xhci_read32(&evts->cs); ++ volatile struct grub_xhci_trb *etrb = evts->ring + nidx; ++ grub_uint32_t control = grub_xhci_read32(&etrb->control); ++ if ((control & TRB_C) != (cs ? 1 : 0)) ++ return; ++ ++ /* process event */ ++ grub_uint32_t evt_type = TRB_TYPE(control); ++ grub_uint32_t evt_cc = (grub_xhci_read32(&etrb->status) >> 24) & 0xff; ++ ++ switch (evt_type) ++ { ++ case ER_TRANSFER: ++ case ER_COMMAND_COMPLETE: ++ { ++ struct grub_xhci_trb *rtrb = (void*)grub_xhci_read32(&etrb->ptr_low); ++ struct grub_xhci_ring *ring = XHCI_RING(rtrb); ++ volatile struct grub_xhci_trb *evt = &ring->evt; ++ grub_uint32_t eidx = rtrb - ring->ring + 1; ++ grub_dprintf("xhci", "%s: ring %p [trb %p, evt %p, type %d, eidx %d, cc %d]\n", ++ __func__, ring, rtrb, evt, evt_type, eidx, evt_cc); ++ *evt = *etrb; ++ grub_xhci_write32(&ring->eidx, eidx); ++ break; ++ } ++ case ER_PORT_STATUS_CHANGE: ++ { ++ /* Nothing to do here. grub_xhci_detect_dev will handle it */ ++ break; ++ } ++ default: ++ { ++ grub_dprintf("xhci", "%s: unknown event, type %d, cc %d\n", ++ __func__, evt_type, evt_cc); ++ break; ++ } ++ } ++ ++ /* move ring index, notify xhci */ ++ nidx++; ++ if (nidx == GRUB_XHCI_RING_ITEMS) ++ { ++ nidx = 0; ++ cs = cs ? 0 : 1; ++ grub_xhci_write32(&evts->cs, cs); ++ } ++ grub_xhci_write32(&evts->nidx, nidx); ++ volatile struct grub_xhci_ir *ir = x->ir; ++ grub_uint32_t erdp = (grub_uint32_t)(evts->ring + nidx); ++ grub_xhci_write32(&ir->erdp_low, erdp); ++ grub_xhci_write32(&ir->erdp_high, 0); ++ } ++} ++ ++/**************************************************************** ++ * TRB handling ++ ****************************************************************/ ++ ++/* Signal the hardware to process events on a TRB ring */ ++static void xhci_doorbell(struct grub_xhci *x, grub_uint32_t slotid, grub_uint32_t value) ++{ ++ xhci_check_status(x); ++ grub_dprintf("xhci", "%s: slotid %d, epid %d\n", __func__, slotid, value); ++ grub_xhci_write32(&x->db[slotid].doorbell, value); ++} ++ ++/* Check if a ring has any pending TRBs */ ++static int xhci_ring_busy(volatile struct grub_xhci_ring *ring) ++{ ++ grub_uint32_t eidx = grub_xhci_read32(&ring->eidx); ++ grub_uint32_t nidx = grub_xhci_read32(&ring->nidx); ++ ++ return (eidx != nidx); ++} ++ ++/* Returns free space in ring */ ++static int xhci_ring_free_space(volatile struct grub_xhci_ring *ring) ++{ ++ grub_uint32_t eidx = grub_xhci_read32(&ring->eidx); ++ grub_uint32_t nidx = grub_xhci_read32(&ring->nidx); ++ ++ /* nidx is never 0, so reduce ring buffer size by one */ ++ return (eidx > nidx) ? eidx-nidx ++ : (ARRAY_SIZE(ring->ring) - 1) - nidx + eidx; ++} ++ ++/* Check if a ring is full */ ++static int xhci_ring_full(volatile struct grub_xhci_ring *ring) ++{ ++ /* Might need to insert one link TRB */ ++ return xhci_ring_free_space(ring) <= 1; ++} ++ ++/* Check if a ring is almost full */ ++static int xhci_ring_almost_full(volatile struct grub_xhci_ring *ring) ++{ ++ /* Might need to insert one link TRB */ ++ return xhci_ring_free_space(ring) <= 2; ++} ++ ++/* Wait for a ring to empty (all TRBs processed by hardware) */ ++static int xhci_event_wait(struct grub_xhci *x, ++ volatile struct grub_xhci_ring *ring, ++ grub_uint32_t timeout) ++{ ++ grub_uint32_t end = grub_get_time_ms () + timeout; ++ ++ for (;;) ++ { ++ xhci_check_status(x); ++ xhci_process_events(x); ++ if (!xhci_ring_busy(ring)) ++ { ++ grub_uint32_t status = ring->evt.status; ++ return (status >> 24) & 0xff; ++ } ++ if (grub_get_time_ms () > end) ++ { ++ xhci_check_status(x); ++ grub_dprintf("xhci", "%s: Timeout waiting for event\n", __func__); ++ return -1; ++ } ++ } ++} ++ ++/* Add a TRB to the given ring, either regular or inline */ ++static void xhci_trb_fill(volatile struct grub_xhci_ring *ring, ++ grub_uint64_t ptr, grub_uint32_t xferlen, ++ grub_uint32_t flags) ++{ ++ volatile struct grub_xhci_trb *dst = &ring->ring[ring->nidx]; ++ dst->ptr_low = ptr & 0xffffffff; ++ dst->ptr_high = ptr >> 32; ++ dst->status = xferlen; ++ dst->control = flags | (ring->cs ? TRB_C : 0); ++ ++ grub_arch_sync_dma_caches(dst, sizeof(ring->ring[0])); ++} ++ ++/* ++ * Queue a TRB onto a ring. ++ * ++ * The caller must pass a pointer to the data in physical address-space or the ++ * data itself (but no more than 8 bytes) in data_or_addr. Inline data must have ++ * the flag TRB_TR_IDT set. ++ */ ++static void xhci_trb_queue(volatile struct grub_xhci_ring *ring, ++ grub_uint64_t data_or_addr, ++ 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__, ++ ring, data_or_addr, xferlen & 0x1ffff, flags, xferlen >> 17); ++ ++ if (xhci_ring_full(ring)) ++ { ++ grub_dprintf("xhci", "%s: ERROR: ring %p is full, discarding TRB\n", ++ __func__, ring); ++ return; ++ } ++ ++ if (ring->nidx >= ARRAY_SIZE(ring->ring) - 1) ++ { ++ /* Reset to command buffer pointer to the first element */ ++ xhci_trb_fill(ring, (grub_addr_t)ring->ring, 0, (TR_LINK << 10) | TRB_LK_TC); ++ ring->nidx = 0; ++ ring->cs ^= 1; ++ grub_dprintf("xhci", "%s: ring %p [linked]\n", __func__, ring); ++ } ++ ++ xhci_trb_fill(ring, data_or_addr, xferlen, flags); ++ ring->nidx++; ++ grub_dprintf("xhci", "%s: ring %p [nidx %d, len %d]\n", ++ __func__, ring, ring->nidx, xferlen); ++} ++ ++/* ++ * Queue a TRB onto a ring and flush it if necessary. ++ * ++ * The caller must pass a pointer to the data in physical address-space or the ++ * data itself (but no more than 8 bytes) in data_or_addr. Inline data must have ++ * the flag TRB_TR_IDT set. ++ */ ++static int xhci_trb_queue_and_flush(struct grub_xhci *x, ++ grub_uint32_t slotid, ++ grub_uint32_t epid, ++ volatile struct grub_xhci_ring *ring, ++ grub_uint64_t data_or_addr, ++ grub_uint32_t xferlen, grub_uint32_t flags) ++{ ++ grub_uint8_t submit = 0; ++ if (xhci_ring_almost_full(ring)) ++ { ++ grub_dprintf("xhci", "%s: almost full e %d n %d\n", __func__, ring->eidx, ring->nidx); ++ flags |= TRB_TR_IOC; ++ submit = 1; ++ } ++ /* Note: xhci_trb_queue might queue on or two elements, if the end of the TRB ++ * has been reached. The caller must account for that when filling the TRB. */ ++ xhci_trb_queue(ring, data_or_addr, xferlen, flags); ++ /* Submit if less no free slot is remaining, we might need an additional ++ * one on the next call to this function. */ ++ if (submit) ++ { ++ xhci_doorbell(x, slotid, epid); ++ int rc = xhci_event_wait(x, ring, 1000); ++ grub_dprintf("xhci", "%s: xhci_event_wait = %d\n", __func__, rc); ++ return rc; ++ } ++ return 0; ++} ++ ++/**************************************************************** ++ * xHCI command functions ++ ****************************************************************/ ++ ++/* Submit a command to the xHCI command TRB */ ++static int xhci_cmd_submit(struct grub_xhci *x, ++ struct grub_pci_dma_chunk *inctx_dma, ++ grub_uint32_t flags) ++{ ++ volatile struct grub_xhci_inctx *inctx; ++ /* Don't submit if halted, it will fail */ ++ if (xhci_is_halted(x)) ++ return -1; ++ ++ if (inctx_dma) ++ { ++ grub_xhci_inctx_sync_dma_caches(x, inctx_dma); ++ ++ inctx = grub_dma_get_virt(inctx_dma); ++ ++ struct grub_xhci_slotctx *slot = (void*)&inctx[1 << x->flag64]; ++ grub_uint32_t port = ((slot->ctx[1] >> 16) & 0xff) - 1; ++ grub_uint32_t portsc = grub_xhci_port_read(x, port); ++ if (!(portsc & GRUB_XHCI_PORTSC_CCS)) ++ { ++ grub_dprintf("xhci", "%s: root port %d no longer connected\n", ++ __func__, port); ++ return -1; ++ } ++ xhci_trb_queue(x->cmds, grub_dma_get_phys(inctx_dma), 0, flags); ++ } ++ else ++ { ++ xhci_trb_queue(x->cmds, 0, 0, flags); ++ } ++ ++ xhci_doorbell(x, 0, 0); ++ int rc = xhci_event_wait(x, x->cmds, 1000); ++ grub_dprintf("xhci", "%s: xhci_event_wait = %d\n", __func__, rc); ++ ++ return rc; ++} ++ ++static int xhci_cmd_enable_slot(struct grub_xhci *x) ++{ ++ grub_uint32_t flags = 0; ++ flags |= (CR_ENABLE_SLOT << 10); ++ ++ grub_dprintf("xhci", "%s:\n", __func__); ++ int cc = xhci_cmd_submit(x, NULL, flags); ++ if (cc != CC_SUCCESS) ++ return -1; ++ grub_dprintf("xhci", "%s: %p\n", __func__, &x->cmds->evt.control); ++ grub_dprintf("xhci", "%s: %x\n", __func__, grub_xhci_read32(&x->cmds->evt.control)); ++ ++ return (grub_xhci_read32(&x->cmds->evt.control) >> 24) & 0xff; ++} ++ ++static int xhci_cmd_disable_slot(struct grub_xhci *x, grub_uint32_t slotid) ++{ ++ grub_uint32_t flags = 0; ++ flags |= (CR_DISABLE_SLOT << 10); ++ flags |= (slotid << 24); ++ ++ grub_dprintf("xhci", "%s: slotid %d\n", __func__, slotid); ++ return xhci_cmd_submit(x, NULL, flags); ++} ++ ++static int xhci_cmd_stop_endpoint(struct grub_xhci *x, grub_uint32_t slotid ++ , grub_uint32_t epid ++ , grub_uint32_t suspend) ++{ ++ grub_uint32_t flags = 0; ++ flags |= (CR_STOP_ENDPOINT << 10); ++ flags |= (epid << 16); ++ flags |= (suspend << 23) ; ++ flags |= (slotid << 24); ++ ++ return xhci_cmd_submit(x, NULL, flags); ++} ++ ++static int xhci_cmd_reset_endpoint(struct grub_xhci *x, grub_uint32_t slotid ++ , grub_uint32_t epid ++ , grub_uint32_t preserve) ++{ ++ grub_uint32_t flags = 0; ++ flags |= (preserve << 9); ++ flags |= (CR_RESET_ENDPOINT << 10); ++ flags |= (epid << 16); ++ flags |= (slotid << 24); ++ ++ return xhci_cmd_submit(x, NULL, flags); ++} ++ ++static int xhci_cmd_set_dequeue_pointer(struct grub_xhci *x, grub_uint32_t slotid ++ , grub_uint32_t epid ++ , grub_addr_t tr_deque_pointer) ++{ ++ grub_uint32_t flags = 0; ++ flags |= (CR_SET_TR_DEQUEUE << 10); ++ flags |= (epid << 16); ++ flags |= (slotid << 24); ++ ++ xhci_trb_queue(x->cmds, tr_deque_pointer, 0, flags); ++ ++ xhci_doorbell(x, 0, 0); ++ int rc = xhci_event_wait(x, x->cmds, 1000); ++ grub_dprintf("xhci", "%s: xhci_event_wait = %d\n", __func__, rc); ++ ++ return rc; ++} ++ ++static int xhci_cmd_address_device(struct grub_xhci *x, grub_uint32_t slotid, ++ struct grub_pci_dma_chunk *inctx_dma) ++{ ++ grub_uint32_t flags = 0; ++ flags |= (CR_ADDRESS_DEVICE << 10); ++ flags |= (slotid << 24); ++ ++ grub_dprintf("xhci", "%s: slotid %d\n", __func__, slotid); ++ return xhci_cmd_submit(x, inctx_dma, flags); ++} ++ ++static int xhci_cmd_configure_endpoint(struct grub_xhci *x, grub_uint32_t slotid, ++ struct grub_pci_dma_chunk *inctx_dma) ++{ ++ grub_uint32_t flags = 0; ++ flags |= (CR_CONFIGURE_ENDPOINT << 10); ++ flags |= (slotid << 24); ++ ++ grub_dprintf("xhci", "%s: slotid %d\n", __func__, slotid); ++ return xhci_cmd_submit(x, inctx_dma, flags); ++} ++ ++static int xhci_cmd_evaluate_context(struct grub_xhci *x, grub_uint32_t slotid, ++ struct grub_pci_dma_chunk *inctx_dma) ++{ ++ grub_uint32_t flags = 0; ++ flags |= (CR_EVALUATE_CONTEXT << 10); ++ flags |= (slotid << 24); ++ ++ grub_dprintf("xhci", "%s: slotid %d\n", __func__, slotid); ++ return xhci_cmd_submit(x, inctx_dma, flags); ++} ++ ++/**************************************************************** ++ * xHCI host controller initialization ++ ****************************************************************/ ++ ++static grub_usb_err_t ++grub_xhci_reset (struct grub_xhci *x) ++{ ++ grub_uint32_t reg; ++ grub_uint32_t end; ++ ++ reg = grub_xhci_read32(&x->op->usbcmd); ++ if (reg & GRUB_XHCI_CMD_RS) ++ { ++ reg &= ~GRUB_XHCI_CMD_RS; ++ grub_xhci_write32(&x->op->usbcmd, reg); ++ ++ end = grub_get_time_ms () + 32; ++ while (grub_xhci_read32(&x->op->usbcmd) & GRUB_XHCI_STS_HCH) ++ { ++ if (grub_get_time_ms () > end) ++ return GRUB_USB_ERR_TIMEOUT; ++ ++ grub_millisleep(1); ++ } ++ } ++ ++ grub_dprintf("xhci", "grub_xhci_reset: resetting HC\n"); ++ grub_xhci_write32(&x->op->usbcmd, GRUB_XHCI_CMD_HCRST); ++ ++ /* Wait for device to complete reset and be enabled */ ++ end = grub_get_time_ms () + 100; ++ while (grub_xhci_read32(&x->op->usbcmd) & GRUB_XHCI_CMD_HCRST) ++ { ++ if (grub_get_time_ms () > end) ++ return GRUB_USB_ERR_TIMEOUT; ++ ++ grub_millisleep(1); ++ } ++ ++ /* Wait for device to complete reset and be enabled */ ++ end = grub_get_time_ms () + 100; ++ while (grub_xhci_read32(&x->op->usbsts) & GRUB_XHCI_STS_CNR) ++ { ++ if (grub_get_time_ms () > end) ++ return GRUB_USB_ERR_TIMEOUT; ++ ++ grub_millisleep(1); ++ } ++ ++ grub_xhci_write32(&x->op->config, x->slots); ++ grub_xhci_write32(&x->op->dcbaap_low, grub_dma_get_phys(x->devs_dma)); ++ grub_xhci_write32(&x->op->dcbaap_high, 0); ++ grub_xhci_write32(&x->op->crcr_low, grub_dma_get_phys(x->cmds_dma)| 1); ++ grub_xhci_write32(&x->op->crcr_high, 0); ++ x->cmds->cs = 1; ++ ++ grub_arch_sync_dma_caches(x->cmds, sizeof(*x->cmds)); ++ ++ x->eseg->ptr_low = grub_dma_get_phys(x->evts_dma); ++ x->eseg->ptr_high = 0; ++ x->eseg->size = GRUB_XHCI_RING_ITEMS; ++ ++ grub_arch_sync_dma_caches(x->eseg, sizeof(*x->eseg)); ++ ++ grub_xhci_write32(&x->ir->erstsz, 1); ++ grub_xhci_write32(&x->ir->erdp_low, grub_dma_get_phys(x->evts_dma)); ++ grub_xhci_write32(&x->ir->erdp_high, 0); ++ grub_xhci_write32(&x->ir->erstba_low, grub_dma_get_phys(x->eseg_dma)); ++ grub_xhci_write32(&x->ir->erstba_high, 0); ++ x->evts->cs = 1; ++ ++ grub_arch_sync_dma_caches(x->evts, sizeof(*x->eseg)); ++ ++ xhci_check_status(x); ++ ++ grub_dprintf ("xhci", "XHCI OP COMMAND: %08x\n", ++ grub_xhci_read32 (&x->op->usbcmd)); ++ grub_dprintf ("xhci", "XHCI OP STATUS: %08x\n", ++ grub_xhci_read32 (&x->op->usbsts)); ++ grub_dprintf ("xhci", "XHCI OP PAGESIZE: %08x\n", ++ grub_xhci_read32 (&x->op->pagesize)); ++ grub_dprintf ("xhci", "XHCI OP DNCTRL: %08x\n", ++ grub_xhci_read32 (&x->op->dnctl)); ++ grub_dprintf ("xhci", "XHCI OP CRCR_LOW: %08x\n", ++ grub_xhci_read32 (&x->op->crcr_low)); ++ grub_dprintf ("xhci", "XHCI OP CRCR_HIGH: %08x\n", ++ grub_xhci_read32 (&x->op->crcr_high)); ++ grub_dprintf ("xhci", "XHCI OP DCBAAP_LOW: %08x\n", ++ grub_xhci_read32 (&x->op->dcbaap_low)); ++ grub_dprintf ("xhci", "XHCI OP DCBAAP_HIGH: %08x\n", ++ grub_xhci_read32 (&x->op->dcbaap_high)); ++ grub_dprintf ("xhci", "XHCI OP CONFIG: %08x\n", ++ grub_xhci_read32 (&x->op->config)); ++ grub_dprintf ("xhci", "XHCI IR ERSTSZ: %08x\n", ++ grub_xhci_read32 (&x->ir->erstsz)); ++ grub_dprintf ("xhci", "XHCI IR ERDP: %08x\n", ++ grub_xhci_read32 (&x->ir->erdp_low)); ++ grub_dprintf ("xhci", "XHCI IR ERSTBA: %08x\n", ++ grub_xhci_read32 (&x->ir->erstba_low)); ++ ++ xhci_check_status(x); ++ ++ return GRUB_USB_ERR_NONE; ++} ++ ++static grub_usb_err_t ++grub_xhci_request_legacy_handoff(volatile struct grub_xhci_xcap *xcap) ++{ ++ grub_uint32_t end; ++ ++ end = grub_get_time_ms () + 10; ++ for (;;) ++ { ++ grub_uint32_t cap = grub_xhci_read32(&xcap->cap); ++ if (cap & (1 << 16)) ++ grub_xhci_write32(&xcap->cap, cap | (1 << 24)); ++ else ++ break; ++ ++ if (grub_get_time_ms () > end) ++ { ++ grub_dprintf ("xhci","ERROR: %s TIMEOUT\n", __func__); ++ return GRUB_USB_ERR_TIMEOUT; ++ } ++ grub_millisleep(1); ++ } ++ return GRUB_USB_ERR_NONE; ++} ++ ++static void ++grub_xhci_fill_default_speed_mapping(struct grub_xhci_psids *ids) ++{ ++ /* Chapter 7.2.2.1.1 "Default USB Speed ID Mapping" */ ++ ids->psids[0].id = 1; ++ ids->psids[0].psie = 2; ++ ids->psids[0].psim = 12; ++ ids->psids[1].id = 2; ++ ids->psids[1].psie = 1; ++ ids->psids[1].psim = 1500; ++ ids->psids[2].id = 3; ++ ids->psids[2].psie = 2; ++ ids->psids[2].psim = 480; ++ ids->psids[3].id = 4; ++ ids->psids[3].psie = 3; ++ ids->psids[3].psim = 5; ++ ids->psids[4].id = 5; ++ ids->psids[4].psie = 3; ++ ids->psids[4].psim = 10; ++ ids->psids[5].id = 6; ++ ids->psids[5].psie = 3; ++ ids->psids[5].psim = 10; ++ ids->psids[6].id = 7; ++ ids->psids[6].psie = 3; ++ ids->psids[6].psim = 20; ++} ++ ++static void ++grub_xhci_calc_speed_mapping(struct grub_xhci_psids *ids) ++{ ++ const grub_uint64_t mult[4] = {1ULL, 1000ULL, 1000000ULL, 1000000000ULL}; ++ ++ for (grub_uint8_t i = 0; i < 16; i++) ++ { ++ if (ids->psids[i].id == 0) ++ continue; ++ ids->psids[i].bitrate = mult[ids->psids[i].psie & 3] * (grub_uint64_t)ids->psids[i].psim; ++ if (ids->psids[i].bitrate < 12000000ULL) ++ ids->psids[i].grub_usb_speed = GRUB_USB_SPEED_LOW; ++ else if (ids->psids[i].bitrate < 480000000ULL) ++ ids->psids[i].grub_usb_speed = GRUB_USB_SPEED_FULL; ++ else if (ids->psids[i].bitrate > 1200000000ULL) ++ ids->psids[i].grub_usb_speed = GRUB_USB_SPEED_SUPER; ++ else ++ ids->psids[i].grub_usb_speed = GRUB_USB_SPEED_HIGH; ++ } ++} ++ ++ ++/* PCI iteration function... */ ++void ++grub_xhci_init_device (volatile void *regs) ++{ ++ struct grub_xhci *x; ++ grub_uint32_t hcs1, hcc, reg; ++ ++ /* Allocate memory for the controller and fill basic values. */ ++ x = grub_zalloc (sizeof (*x)); ++ if (!x) ++ { ++ grub_dprintf("xhci", "Failed to allocate memory\n"); ++ return; ++ } ++ x->caps = (volatile struct grub_xhci_caps *) regs; ++ x->op = (volatile struct grub_xhci_op *) (((grub_uint8_t *)regs) + ++ grub_xhci_read8(&x->caps->caplength)); ++ x->pr = (volatile struct grub_xhci_pr *) (((grub_uint8_t *)x->op) + ++ GRUB_XHCI_PR_OFFSET); ++ x->db = (volatile struct grub_xhci_db *) (((grub_uint8_t *)regs) + ++ grub_xhci_read32(&x->caps->dboff)); ++ x->ir = (volatile struct grub_xhci_ir *) (((grub_uint8_t *)regs) + ++ grub_xhci_read32(&x->caps->rtsoff) + GRUB_XHCI_IR_OFFSET); ++ ++ grub_dprintf ("xhci", "XHCI init: CAPLENGTH: 0x%02x\n", ++ grub_xhci_read8 (&x->caps->caplength)); ++ grub_dprintf ("xhci", "XHCI init: HCIVERSION: 0x%04x\n", ++ grub_xhci_read16 (&x->caps->hciversion)); ++ grub_dprintf ("xhci", "XHCI init: HCSPARAMS1: 0x%08x\n", ++ grub_xhci_read32 (&x->caps->hcsparams1)); ++ grub_dprintf ("xhci", "XHCI init: HCSPARAMS2: 0x%08x\n", ++ grub_xhci_read32 (&x->caps->hcsparams2)); ++ grub_dprintf ("xhci", "XHCI init: HCSPARAMS3: 0x%08x\n", ++ grub_xhci_read32 (&x->caps->hcsparams3)); ++ grub_dprintf ("xhci", "XHCI init: HCCPARAMS: 0x%08x\n", ++ grub_xhci_read32 (&x->caps->hcsparams3)); ++ grub_dprintf ("xhci", "XHCI init: DBOFF: 0x%08x\n", ++ grub_xhci_read32 (&x->caps->dboff)); ++ grub_dprintf ("xhci", "XHCI init: RTOFF: 0x%08x\n", ++ grub_xhci_read32 (&x->caps->rtsoff)); ++ ++ hcs1 = grub_xhci_read32(&x->caps->hcsparams1); ++ hcc = grub_xhci_read32(&x->caps->hccparams); ++ x->ports = (grub_uint32_t) ((hcs1 >> 24) & 0xff); ++ x->slots = (grub_uint32_t) (hcs1 & 0xff); ++ x->xcap = (grub_uint32_t) ((hcc >> 16) & 0xffff) * sizeof(grub_uint32_t); ++ x->flag64 = (grub_uint8_t) ((hcc & 0x04) ? 1 : 0); ++ grub_dprintf("xhci", "XHCI init: %d ports, %d slots, %d byte contexts\n" ++ , x->ports, x->slots, x->flag64 ? 64 : 32); ++ ++ x->psids = grub_zalloc (sizeof (struct grub_xhci_psids) * x->ports); ++ if (x->xcap) ++ { ++ grub_uint32_t off; ++ volatile grub_uint8_t *addr = (grub_uint8_t *) x->caps + x->xcap; ++ do ++ { ++ volatile struct grub_xhci_xcap *xcap = (void *)addr; ++ grub_uint32_t ports, name, cap = grub_xhci_read32(&xcap->cap); ++ switch (cap & 0xff) { ++ case XHCI_CAP_LEGACY_SUPPORT: ++ { ++ if (grub_xhci_request_legacy_handoff(xcap) != GRUB_USB_ERR_NONE) ++ { ++ grub_dprintf("xhci", "XHCI init: Failed to get xHCI ownership\n"); ++ goto fail; ++ } ++ break; ++ } ++ case XHCI_CAP_SUPPORTED_PROTOCOL: ++ { ++ name = grub_xhci_read32(&xcap->data[0]); ++ ports = grub_xhci_read32(&xcap->data[1]); ++ const grub_uint8_t major = (cap >> 24) & 0xff; ++ const grub_uint8_t minor = (cap >> 16) & 0xff; ++ const grub_uint8_t psic = (ports >> 28) & 0xf; ++ const grub_uint8_t count = (ports >> 8) & 0xff; ++ const grub_uint8_t start = (ports >> 0) & 0xff; ++ grub_dprintf("xhci", "XHCI init: protocol %c%c%c%c %x.%02x" ++ ", %d ports (offset %d), def %x, psic %d\n" ++ , (name >> 0) & 0xff ++ , (name >> 8) & 0xff ++ , (name >> 16) & 0xff ++ , (name >> 24) & 0xff ++ , major, minor ++ , count, start ++ , ports >> 16 ++ , psic); ++ if (name == 0x20425355 /* "USB " */) ++ { ++ if (major == 2) ++ { ++ x->usb2.start = start; ++ x->usb2.count = count; ++ } ++ else if (major == 3) ++ { ++ x->usb3.start = start; ++ x->usb3.count = count; ++ } ++ ++ for (grub_uint32_t p = start - 1; p < start + count - 1UL; p++) ++ { ++ x->psids[p].major = major; ++ x->psids[p].minor = minor; ++ grub_xhci_fill_default_speed_mapping(&x->psids[p]); ++ for (grub_uint8_t i = 0; i < psic; i++) ++ { ++ grub_uint32_t psid = grub_xhci_read32(&xcap->data[3 + i]); ++ x->psids[p].psids[i].id = (psid >> 0) & 0xf; ++ x->psids[p].psids[i].psie = (psid >> 4) & 0x3; ++ x->psids[p].psids[i].psim = (psid >> 16) & 0xfffff; ++ } ++ grub_xhci_calc_speed_mapping(&x->psids[p]); ++ } ++ } ++ ++ break; ++ } ++ default: ++ { ++ grub_dprintf("xhci", "XHCI extcap 0x%x @ %p\n", cap & 0xff, addr); ++ break; ++ } ++ } ++ off = (cap >> 8) & 0xff; ++ addr += off << 2; ++ } ++ while (off > 0); ++ } ++ ++ x->pagesize = xhci_get_pagesize(x); ++ grub_dprintf("xhci", "XHCI init: Minimum supported page size 0x%x\n", ++ x->pagesize); ++ ++ /* Chapter 6.1 Device Context Base Address Array */ ++ x->devs_dma = xhci_memalign_dma32(ALIGN_DCBAA, ++ sizeof(*x->devs) * (x->slots + 1), ++ x->pagesize); ++ if (!x->devs_dma) ++ goto fail; ++ x->devs = grub_dma_get_virt(x->devs_dma); ++ grub_memset((void *)x->devs, 0, sizeof(*x->devs) * (x->slots + 1)); ++ grub_arch_sync_dma_caches(x->devs, sizeof(*x->devs) * (x->slots + 1)); ++ grub_dprintf ("xhci", "XHCI init: device memory %p (%x)\n", ++ grub_dma_get_virt(x->devs_dma), ++ grub_dma_get_phys(x->devs_dma)); ++ ++ /* Chapter 6.5 Event Ring Segment Table */ ++ x->eseg_dma = xhci_memalign_dma32(ALIGN_EVT_RING_TABLE, sizeof(*x->eseg), 0); ++ if (!x->eseg_dma) ++ goto fail; ++ x->eseg = grub_dma_get_virt(x->eseg_dma); ++ grub_memset((void *)x->eseg, 0, sizeof(*x->eseg)); ++ grub_arch_sync_dma_caches(x->eseg, sizeof(*x->eseg)); ++ grub_dprintf ("xhci", "XHCI init: event ring table memory %p (%x)\n", ++ grub_dma_get_virt(x->eseg_dma), ++ grub_dma_get_phys(x->eseg_dma)); ++ ++ x->cmds_dma = xhci_memalign_dma32(ALIGN_CMD_RING_SEG, sizeof(*x->cmds), ++ BOUNDARY_RING); ++ if (!x->cmds_dma) ++ goto fail; ++ x->cmds = grub_dma_get_virt(x->cmds_dma); ++ grub_memset((void *)x->cmds, 0, sizeof(*x->cmds)); ++ grub_arch_sync_dma_caches(x->cmds, sizeof(*x->cmds)); ++ grub_dprintf ("xhci", "XHCI init: command ring memory %p (%x)\n", ++ grub_dma_get_virt(x->cmds_dma), ++ grub_dma_get_phys(x->cmds_dma)); ++ ++ x->evts_dma = xhci_memalign_dma32(ALIGN_EVT_RING_SEG, sizeof(*x->evts), ++ BOUNDARY_RING); ++ if (!x->evts_dma) ++ goto fail; ++ x->evts = grub_dma_get_virt(x->evts_dma); ++ grub_memset((void *)x->evts, 0, sizeof(*x->evts)); ++ grub_arch_sync_dma_caches(x->evts, sizeof(*x->evts)); ++ grub_dprintf ("xhci", "XHCI init: event ring memory %p (%x)\n", ++ grub_dma_get_virt(x->evts_dma), ++ grub_dma_get_phys(x->evts_dma)); ++ ++ /* Chapter 4.20 Scratchpad Buffers */ ++ reg = grub_xhci_read32(&x->caps->hcsparams2); ++ x->spb = (reg >> 21 & 0x1f) << 5 | reg >> 27; ++ if (x->spb) ++ { ++ volatile grub_uint64_t *spba; ++ grub_dprintf("xhci", "XHCI init: set up %d scratch pad buffers\n", ++ x->spb); ++ x->spba_dma = xhci_memalign_dma32(ALIGN_SPBA, sizeof(*spba) * x->spb, ++ x->pagesize); ++ if (!x->spba_dma) ++ goto fail; ++ ++ x->spad_dma = xhci_memalign_dma32(x->pagesize, x->pagesize * x->spb, ++ x->pagesize); ++ if (!x->spad_dma) ++ { ++ grub_dma_free(x->spba_dma); ++ goto fail; ++ } ++ ++ spba = grub_dma_get_virt(x->spba_dma); ++ for (grub_uint32_t i = 0; i < x->spb; i++) ++ spba[i] = (grub_addr_t)grub_dma_get_phys(x->spad_dma) + (i * x->pagesize); ++ grub_arch_sync_dma_caches(x->spba_dma, sizeof(*spba) * x->spb); ++ ++ x->devs[0].ptr_low = grub_dma_get_phys(x->spba_dma); ++ x->devs[0].ptr_high = 0; ++ grub_arch_sync_dma_caches(x->devs_dma, sizeof(x->devs[0])); ++ grub_dprintf ("xhci", "XHCI init: Allocated %d scratch buffers of size 0x%x\n", ++ x->spb, x->pagesize); ++ } ++ ++ grub_xhci_reset(x); ++ ++ /* Set the running bit */ ++ reg = grub_xhci_read32 (&x->op->usbcmd); ++ reg |= GRUB_XHCI_CMD_RS; ++ grub_xhci_write32 (&x->op->usbcmd, reg); ++ ++ ++ /* Link to xhci now that initialisation is successful. */ ++ x->next = xhci; ++ xhci = x; ++ ++ return; ++ ++fail: ++ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: FAILED!\n"); ++ if (x) ++ { ++ if (x->devs_dma) ++ grub_dma_free (x->devs_dma); ++ if (x->eseg_dma) ++ grub_dma_free (x->eseg_dma); ++ if (x->cmds_dma) ++ grub_dma_free (x->cmds_dma); ++ if (x->evts_dma) ++ grub_dma_free (x->evts_dma); ++ if (x->spad_dma) ++ grub_dma_free (x->spad_dma); ++ if (x->spba_dma) ++ grub_dma_free (x->spba_dma); ++ } ++ grub_free (x); ++ ++ return; ++} ++ ++static int ++grub_xhci_iterate (grub_usb_controller_iterate_hook_t hook, void *hook_data) ++{ ++ struct grub_xhci *x; ++ struct grub_usb_controller dev; ++ ++ for (x = xhci; x; x = x->next) ++ { ++ dev.data = x; ++ if (hook (&dev, hook_data)) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/**************************************************************** ++ * xHCI maintainance functions ++ ****************************************************************/ ++ ++static grub_usb_err_t ++grub_xhci_update_hub_portcount (struct grub_xhci *x, ++ grub_usb_transfer_t transfer, ++ grub_uint32_t slotid) ++{ ++ struct grub_pci_dma_chunk *in_dma; ++ volatile struct grub_xhci_slotctx *hdslot; ++ grub_uint32_t epid = 0; ++ ++ if (!transfer || !transfer->dev || !transfer->dev->nports) ++ return GRUB_USB_ERR_NONE; ++ ++ hdslot = grub_dma_phys2virt(x->devs[slotid].ptr_low, x->devs_dma); ++ if ((hdslot->ctx[3] >> 27) == 3) ++ /* Already configured */ ++ return 0; ++ ++ grub_dprintf("xhci", "%s: updating hub config to %d ports\n", __func__, ++ transfer->dev->nports); ++ ++ xhci_check_status(x); ++ ++ /* Allocate input context and initialize endpoint info. */ ++ in_dma = grub_xhci_alloc_inctx(x, epid, transfer->dev); ++ if (!in_dma) ++ return GRUB_USB_ERR_INTERNAL; ++ volatile struct grub_xhci_inctx *in = grub_dma_get_virt(in_dma); ++ ++ in->add = (1 << epid); ++ ++ struct grub_xhci_epctx *ep = (void*)&in[(epid+1) << x->flag64]; ++ ep->ctx[0] |= 1 << 26; ++ ep->ctx[1] |= transfer->dev->nports << 24; ++ ++ int cc = xhci_cmd_configure_endpoint(x, slotid, in_dma); ++ grub_dma_free(in_dma); ++ ++ if (cc != CC_SUCCESS) ++ { ++ grub_dprintf("xhci", "%s: reconf ctl endpoint: failed (cc %d)\n", ++ __func__, cc); ++ return GRUB_USB_ERR_BADDEVICE; ++ } ++ ++ return GRUB_USB_ERR_NONE; ++} ++ ++static grub_usb_err_t ++grub_xhci_update_max_paket_size (struct grub_xhci *x, ++ grub_usb_transfer_t transfer, ++ grub_uint32_t slotid, ++ grub_uint32_t max_packet) ++{ ++ struct grub_pci_dma_chunk *in_dma; ++ grub_uint32_t epid = 1; ++ ++ if (!transfer || !transfer->dev || !max_packet) ++ return GRUB_USB_ERR_NONE; ++ ++ grub_dprintf("xhci", "%s: updating max packet size to 0x%x\n", __func__, ++ max_packet); ++ ++ xhci_check_status(x); ++ ++ /* Allocate input context and initialize endpoint info. */ ++ in_dma = grub_xhci_alloc_inctx(x, epid, transfer->dev); ++ if (!in_dma) ++ return GRUB_USB_ERR_INTERNAL; ++ volatile struct grub_xhci_inctx *in = grub_dma_get_virt(in_dma); ++ in->add = (1 << epid); ++ ++ struct grub_xhci_epctx *ep = (void*)&in[(epid+1) << x->flag64]; ++ ep->ctx[1] |= max_packet << 16; ++ ++ int cc = xhci_cmd_evaluate_context(x, slotid, in_dma); ++ grub_dma_free(in_dma); ++ ++ if (cc != CC_SUCCESS) ++ { ++ grub_dprintf("xhci", "%s: reconf ctl endpoint: failed (cc %d)\n", ++ __func__, cc); ++ return GRUB_USB_ERR_BADDEVICE; ++ } ++ ++ return GRUB_USB_ERR_NONE; ++} ++ ++/**************************************************************** ++ * xHCI endpoint enablement functions ++ ****************************************************************/ ++ ++static grub_usb_err_t ++grub_xhci_prepare_endpoint (struct grub_xhci *x, ++ struct grub_usb_device *dev, ++ grub_uint8_t endpoint, ++ grub_transfer_type_t dir, ++ grub_transaction_type_t type, ++ grub_uint32_t maxpaket, ++ struct grub_xhci_priv *priv) ++{ ++ grub_uint32_t epid; ++ struct grub_pci_dma_chunk *reqs_dma; ++ struct grub_pci_dma_chunk *in_dma; ++ volatile struct grub_xhci_ring *reqs; ++ volatile struct grub_xhci_slotctx *slotctx; ++ ++ if (!x || !priv) ++ return GRUB_USB_ERR_INTERNAL; ++ ++ xhci_check_status(x); ++ ++ if (endpoint == 0) ++ { ++ epid = 1; ++ } ++ else ++ { ++ epid = (endpoint & 0x0f) * 2; ++ epid += (dir == GRUB_USB_TRANSFER_TYPE_IN) ? 1 : 0; ++ } ++ grub_dprintf("xhci", "%s: epid %d\n", __func__, epid); ++ ++ /* Test if already prepared */ ++ if (priv->slotid > 0 && priv->enpoint_trbs[epid] != NULL) ++ return GRUB_USB_ERR_NONE; ++ ++ /* Allocate DMA buffer as endpoint cmd TRB */ ++ reqs_dma = xhci_memalign_dma32(ALIGN_TRB, sizeof(*reqs), ++ BOUNDARY_RING); ++ if (!reqs_dma) ++ return GRUB_USB_ERR_INTERNAL; ++ reqs = grub_dma_get_virt(reqs_dma); ++ grub_memset((void *)reqs, 0, sizeof(*reqs)); ++ reqs->cs = 1; ++ ++ grub_arch_sync_dma_caches(reqs, sizeof(*reqs)); ++ ++ /* Allocate input context and initialize endpoint info. */ ++ in_dma = grub_xhci_alloc_inctx(x, epid, dev); ++ if (!in_dma) ++ { ++ grub_dma_free(reqs_dma); ++ return GRUB_USB_ERR_INTERNAL; ++ } ++ volatile struct grub_xhci_inctx *in = grub_dma_get_virt(in_dma); ++ in->add = 0x01 | (1 << epid); ++ ++ struct grub_xhci_epctx *ep = (void*)&in[(epid+1) << x->flag64]; ++ switch (type) ++ { ++ case GRUB_USB_TRANSACTION_TYPE_CONTROL: ++ ep->ctx[1] |= 0 << 3; ++ break; ++ case GRUB_USB_TRANSACTION_TYPE_BULK: ++ ep->ctx[1] |= 2 << 3; ++ break; ++ } ++ if (dir == GRUB_USB_TRANSFER_TYPE_IN ++ || type== GRUB_USB_TRANSACTION_TYPE_CONTROL) ++ ep->ctx[1] |= 1 << 5; ++ ep->ctx[1] |= maxpaket << 16; ++ ep->deq_low = grub_dma_get_phys(reqs_dma); ++ ep->deq_low |= 1; /* dcs */ ++ ep->length = maxpaket; ++ ++ grub_dprintf("xhci", "%s: ring %p, epid %d, max %d\n", __func__, ++ reqs, epid, maxpaket); ++ if (epid == 1 || priv->slotid == 0) { ++ /* Enable slot. */ ++ int slotid = xhci_cmd_enable_slot(x); ++ if (slotid < 0) ++ { ++ grub_dprintf("xhci", "%s: enable slot: failed\n", __func__); ++ grub_dma_free(reqs_dma); ++ grub_dma_free(in_dma); ++ return GRUB_USB_ERR_BADDEVICE; ++ } ++ grub_dprintf("xhci", "%s: get slot %d assigned\n", __func__, slotid); ++ ++ grub_uint32_t size = (sizeof(struct grub_xhci_slotctx) * GRUB_XHCI_MAX_ENDPOINTS) << x->flag64; ++ ++ /* Allocate memory for the device specific slot context */ ++ priv->slotctx_dma = xhci_memalign_dma32(ALIGN_SLOTCTX, size, ++ x->pagesize); ++ if (!priv->slotctx_dma) ++ { ++ grub_dprintf("xhci", "%s: grub_memalign_dma32 failed\n", __func__); ++ grub_dma_free(reqs_dma); ++ grub_dma_free(in_dma); ++ return GRUB_USB_ERR_INTERNAL; ++ } ++ slotctx = grub_dma_get_virt(priv->slotctx_dma); ++ ++ grub_dprintf("xhci", "%s: enable slot: got slotid %d\n", __func__, slotid); ++ grub_memset((void *)slotctx, 0, size); ++ grub_arch_sync_dma_caches(slotctx, size); ++ ++ x->devs[slotid].ptr_low = grub_dma_get_phys(priv->slotctx_dma); ++ x->devs[slotid].ptr_high = 0; ++ grub_arch_sync_dma_caches(&x->devs[slotid], sizeof(x->devs[0])); ++ ++ /* Send set_address command. */ ++ int cc = xhci_cmd_address_device(x, slotid, in_dma); ++ if (cc != CC_SUCCESS) ++ { ++ grub_dprintf("xhci","%s: address device: failed (cc %d)\n", __func__, cc); ++ cc = xhci_cmd_disable_slot(x, slotid); ++ if (cc != CC_SUCCESS) { ++ grub_dprintf("xhci", "%s: disable failed (cc %d)\n", __func__, cc); ++ } else { ++ x->devs[slotid].ptr_low = 0; ++ x->devs[slotid].ptr_high = 0; ++ grub_arch_sync_dma_caches(&x->devs[slotid], sizeof(x->devs[0])); ++ } ++ grub_dma_free(priv->slotctx_dma); ++ grub_dma_free(reqs_dma); ++ grub_dma_free(in_dma); ++ return GRUB_USB_ERR_BADDEVICE; ++ } ++ priv->enpoint_trbs[epid] = reqs; ++ priv->enpoint_trbs_dma[epid] = reqs_dma; ++ priv->slotid = slotid; ++ priv->max_packet = 0; ++ } ++ if (epid != 1) ++ { ++ /* Send configure command. */ ++ int cc = xhci_cmd_configure_endpoint(x, priv->slotid, in_dma); ++ if (cc != CC_SUCCESS) ++ { ++ grub_dprintf("xhci", "%s: configure endpoint: failed (cc %d)\n", ++ __func__, cc); ++ grub_dma_free(reqs_dma); ++ grub_dma_free(in_dma); ++ return GRUB_USB_ERR_BADDEVICE; ++ } ++ priv->enpoint_trbs[epid] = reqs; ++ priv->enpoint_trbs_dma[epid] = reqs_dma; ++ } ++ ++ grub_dprintf("xhci", "%s: done\n", __func__); ++ grub_dma_free(in_dma); ++ ++ return GRUB_USB_ERR_NONE; ++} ++ ++ ++/**************************************************************** ++ * xHCI transfer helper functions ++ ****************************************************************/ ++ ++static grub_usb_err_t ++grub_xhci_usb_to_grub_err (unsigned char status) ++{ ++ if (status != CC_SUCCESS) ++ grub_dprintf("xhci", "%s: xfer failed (cc %d)\n", __func__, status); ++ else ++ grub_dprintf("xhci", "%s: xfer done (cc %d)\n", __func__, status); ++ ++ if (status == CC_BABBLE_DETECTED) ++ return GRUB_USB_ERR_BABBLE; ++ else if (status == CC_DATA_BUFFER_ERROR) ++ return GRUB_USB_ERR_DATA; ++ else if (status == CC_STALL_ERROR) ++ return GRUB_USB_ERR_STALL; ++ else if (status != CC_SUCCESS) ++ return GRUB_USB_ERR_NAK; ++ ++ return GRUB_USB_ERR_NONE; ++} ++ ++static int ++grub_xhci_transfer_is_zlp(grub_usb_transfer_t transfer, int idx) ++{ ++ if (idx >= transfer->transcnt) ++ return 0; ++ ++ grub_usb_transaction_t tr = &transfer->transactions[idx]; ++ ++ return (tr->size == 0) && ++ ((tr->pid == GRUB_USB_TRANSFER_TYPE_OUT) || ++ (tr->pid == GRUB_USB_TRANSFER_TYPE_IN)); ++} ++ ++static int ++grub_xhci_transfer_is_last(grub_usb_transfer_t transfer, int idx) ++{ ++ return (idx + 1) == transfer->transcnt; ++} ++ ++static int ++grub_xhci_transfer_is_data(grub_usb_transfer_t transfer, int idx) ++{ ++ grub_usb_transaction_t tr; ++ ++ if (idx >= transfer->transcnt) ++ return 0; ++ ++ tr = &transfer->transactions[idx]; ++ if (tr->size == 0 || ++ (tr->pid == GRUB_USB_TRANSFER_TYPE_SETUP)) ++ return 0; ++ ++ /* If there's are no DATA pakets before it's a DATA paket */ ++ for (int i = idx - 1; i >= 0; i--) ++ { ++ tr = &transfer->transactions[i]; ++ if (tr->size > 0 && ++ ((tr->pid == GRUB_USB_TRANSFER_TYPE_OUT) || ++ (tr->pid == GRUB_USB_TRANSFER_TYPE_IN))) ++ return 0; ++ } ++ return 1; ++} ++ ++static int ++grub_xhci_transfer_is_in(grub_usb_transfer_t transfer, int idx) ++{ ++ grub_usb_transaction_t tr; ++ ++ if (idx >= transfer->transcnt) ++ return 0; ++ ++ tr = &transfer->transactions[idx]; ++ ++ return tr->pid == GRUB_USB_TRANSFER_TYPE_IN; ++} ++ ++static int ++grub_xhci_transfer_is_normal(grub_usb_transfer_t transfer, int idx) ++{ ++ grub_usb_transaction_t tr; ++ ++ if (idx >= transfer->transcnt) ++ return 0; ++ ++ tr = &transfer->transactions[idx]; ++ if (tr->size == 0 || ++ (tr->pid == GRUB_USB_TRANSFER_TYPE_SETUP)) ++ return 0; ++ ++ /* If there's at least one DATA paket before it's a normal */ ++ for (int i = idx - 1; i >= 0; i--) ++ { ++ tr = &transfer->transactions[i]; ++ if (tr->size > 0 && ++ ((tr->pid == GRUB_USB_TRANSFER_TYPE_OUT) || ++ (tr->pid == GRUB_USB_TRANSFER_TYPE_IN))) ++ return 1; ++ ++ } ++ return 0; ++} ++ ++static int ++grub_xhci_transfer_next_is_normal(grub_usb_transfer_t transfer, int idx) ++{ ++ return grub_xhci_transfer_is_normal(transfer, idx + 1); ++} ++ ++static int ++grub_xhci_transfer_next_is_in(grub_usb_transfer_t transfer, int idx) ++{ ++ return grub_xhci_transfer_is_in(transfer, idx + 1); ++} ++ ++static grub_uint8_t grub_xhci_epid_from_transfer(grub_usb_transfer_t transfer) ++{ ++ grub_uint8_t epid; ++ ++ if (transfer->endpoint == 0) { ++ epid = 1; ++ } else { ++ epid = (transfer->endpoint & 0x0f) * 2; ++ epid += (transfer->dir == GRUB_USB_TRANSFER_TYPE_IN) ? 1 : 0; ++ } ++ return epid; ++} ++ ++/**************************************************************** ++ * xHCI transfer functions ++ ****************************************************************/ ++ ++static grub_usb_err_t ++grub_xhci_setup_transfer (grub_usb_controller_t dev, ++ grub_usb_transfer_t transfer) ++{ ++ struct grub_xhci_transfer_controller_data *cdata; ++ struct grub_xhci *x = (struct grub_xhci *) dev->data; ++ grub_uint8_t epid; ++ grub_usb_err_t err; ++ volatile struct grub_xhci_ring *reqs; ++ int rc; ++ struct grub_xhci_priv *priv; ++ ++ xhci_check_status(x); ++ ++ if (!dev || !transfer || !transfer->dev || !transfer->dev->xhci_priv) ++ return GRUB_USB_ERR_INTERNAL; ++ ++ priv = transfer->dev->xhci_priv; ++ err = grub_xhci_prepare_endpoint(x, transfer->dev, ++ transfer->endpoint, ++ transfer->dir, ++ transfer->type, ++ transfer->max, ++ priv); ++ ++ if (err != GRUB_USB_ERR_NONE) ++ return err; ++ ++ epid = grub_xhci_epid_from_transfer(transfer); ++ ++ /* Update the max packet size once descdev.maxsize0 is valid */ ++ if (epid == 1 && ++ (priv->max_packet == 0) && ++ (transfer->dev->descdev.maxsize0 > 0)) ++ { ++ if (transfer->dev->speed == GRUB_USB_SPEED_SUPER) ++ priv->max_packet = 1UL << transfer->dev->descdev.maxsize0; ++ else ++ priv->max_packet = transfer->dev->descdev.maxsize0; ++ err = grub_xhci_update_max_paket_size(x, transfer, priv->slotid, priv->max_packet); ++ if (err != GRUB_USB_ERR_NONE) ++ { ++ grub_dprintf("xhci", "%s: Updating max paket size failed\n", __func__); ++ return err; ++ } ++ } ++ if (epid == 1 && ++ transfer->dev->descdev.class == 9 && ++ transfer->dev->nports > 0) ++ { ++ err = grub_xhci_update_hub_portcount(x, transfer, priv->slotid); ++ if (err != GRUB_USB_ERR_NONE) ++ { ++ grub_dprintf("xhci", "%s: Updating max paket size failed\n", __func__); ++ return err; ++ } ++ } ++ ++ /* Allocate private data for the transfer */ ++ cdata = grub_zalloc(sizeof(*cdata)); ++ if (!cdata) ++ return GRUB_USB_ERR_INTERNAL; ++ ++ reqs = priv->enpoint_trbs[epid]; ++ ++ transfer->controller_data = cdata; ++ ++ /* Now queue the transfer onto the TRB */ ++ if (transfer->type == GRUB_USB_TRANSACTION_TYPE_CONTROL) ++ { ++ volatile struct grub_usb_packet_setup *setupdata; ++ setupdata = (void *)transfer->transactions[0].data; ++ grub_dprintf("xhci", "%s: CONTROLL TRANS req %d\n", __func__, setupdata->request); ++ grub_dprintf("xhci", "%s: CONTROLL TRANS length %d\n", __func__, setupdata->length); ++ ++ if (setupdata && setupdata->request == GRUB_USB_REQ_SET_ADDRESS) ++ return GRUB_USB_ERR_NONE; ++ ++ if (transfer->transcnt < 2) ++ return GRUB_USB_ERR_INTERNAL; ++ ++ for (int i = 0; i < transfer->transcnt; i++) ++ { ++ grub_uint32_t flags = 0; ++ grub_uint64_t inline_data; ++ grub_usb_transaction_t tr = &transfer->transactions[i]; ++ ++ switch (tr->pid) ++ { ++ case GRUB_USB_TRANSFER_TYPE_SETUP: ++ { ++ grub_dprintf("xhci", "%s: SETUP PKG\n", __func__); ++ grub_dprintf("xhci", "%s: transfer->size %d\n", __func__, transfer->size); ++ grub_dprintf("xhci", "%s: tr->size %d SETUP PKG\n", __func__, tr->size); ++ ++ flags |= (TR_SETUP << 10); ++ flags |= TRB_TR_IDT; ++ ++ if (transfer->size > 0) ++ { ++ if (grub_xhci_transfer_next_is_in(transfer, i)) ++ flags |= (3 << 16); /* TRT IN */ ++ else ++ flags |= (2 << 16); /* TRT OUT */ ++ } ++ break; ++ } ++ case GRUB_USB_TRANSFER_TYPE_OUT: ++ { ++ grub_dprintf("xhci", "%s: OUT PKG\n", __func__); ++ cdata->transfer_size += tr->size; ++ break; ++ } ++ case GRUB_USB_TRANSFER_TYPE_IN: ++ { ++ grub_dprintf("xhci", "%s: IN PKG\n", __func__); ++ cdata->transfer_size += tr->size; ++ flags |= TRB_TR_DIR; ++ break; ++ } ++ } ++ ++ if (grub_xhci_transfer_is_normal(transfer, i)) ++ flags |= (TR_NORMAL << 10); ++ else if (grub_xhci_transfer_is_data(transfer, i)) ++ flags |= (TR_DATA << 10); ++ else if (grub_xhci_transfer_is_zlp(transfer, i)) ++ flags |= (TR_STATUS << 10); ++ ++ if (grub_xhci_transfer_next_is_normal(transfer, i)) ++ flags |= TRB_TR_CH; ++ ++ if (grub_xhci_transfer_is_last(transfer, i)) ++ flags |= TRB_TR_IOC; ++ ++ /* Assume the ring has enough free space for all TRBs */ ++ if (flags & TRB_TR_IDT && tr->size <= (int)sizeof(inline_data)) ++ { ++ grub_memcpy(&inline_data, (void *)tr->data, tr->size); ++ xhci_trb_queue(reqs, inline_data, tr->size, flags); ++ } ++ else ++ { ++ xhci_trb_queue(reqs, tr->data, tr->size, flags); ++ } ++ } ++ } ++ else if (transfer->type == GRUB_USB_TRANSACTION_TYPE_BULK) ++ { ++ for (int i = 0; i < transfer->transcnt; i++) ++ { ++ grub_uint32_t flags = (TR_NORMAL << 10); ++ grub_usb_transaction_t tr = &transfer->transactions[i]; ++ switch (tr->pid) ++ { ++ case GRUB_USB_TRANSFER_TYPE_OUT: ++ { ++ grub_dprintf("xhci", "%s: OUT PKG\n", __func__); ++ cdata->transfer_size += tr->size; ++ break; ++ } ++ case GRUB_USB_TRANSFER_TYPE_IN: ++ { ++ grub_dprintf("xhci", "%s: IN PKG\n", __func__); ++ cdata->transfer_size += tr->size; ++ flags |= TRB_TR_DIR; ++ break; ++ } ++ case GRUB_USB_TRANSFER_TYPE_SETUP: ++ break; ++ } ++ if (grub_xhci_transfer_is_last(transfer, i)) ++ flags |= TRB_TR_IOC; ++ ++ /* The ring might be to small, submit while adding new entries */ ++ rc = xhci_trb_queue_and_flush(x, priv->slotid, epid, ++ reqs, tr->data, tr->size, flags); ++ if (rc < 0) ++ return GRUB_USB_ERR_TIMEOUT; ++ else if (rc > 1) ++ return grub_xhci_usb_to_grub_err(rc); ++ ++ } ++ } ++ xhci_doorbell(x, priv->slotid, epid); ++ ++ return GRUB_USB_ERR_NONE; ++} ++ ++static grub_usb_err_t ++grub_xhci_check_transfer (grub_usb_controller_t dev, ++ grub_usb_transfer_t transfer, grub_size_t * actual) ++{ ++ grub_uint32_t status; ++ grub_uint32_t remaining; ++ grub_uint8_t epid; ++ volatile struct grub_xhci_ring *reqs; ++ grub_usb_err_t err; ++ int rc; ++ ++ if (!dev->data || !transfer->controller_data || !transfer->dev || ++ !transfer->dev->xhci_priv) ++ return GRUB_USB_ERR_INTERNAL; ++ ++ ++ struct grub_xhci_priv *priv = transfer->dev->xhci_priv; ++ struct grub_xhci *x = (struct grub_xhci *) dev->data; ++ struct grub_xhci_transfer_controller_data *cdata = ++ transfer->controller_data; ++ ++ xhci_check_status(x); ++ xhci_process_events(x); ++ ++ epid = grub_xhci_epid_from_transfer(transfer); ++ ++ reqs = priv->enpoint_trbs[epid]; ++ ++ /* XXX: invalidate caches */ ++ ++ /* Get current status from event ring buffer */ ++ status = (reqs->evt.status>> 24) & 0xff; ++ remaining = reqs->evt.status & 0xffffff; ++ ++ if (status != CC_STOPPED_LENGTH_INVALID) ++ *actual = cdata->transfer_size - remaining; ++ else ++ *actual = 0; ++ ++ if (xhci_ring_busy(reqs)) ++ return GRUB_USB_ERR_WAIT; ++ ++ grub_free(cdata); ++ ++ grub_dprintf("xhci", "%s: xfer done\n", __func__); ++ ++ err = grub_xhci_usb_to_grub_err(status); ++ if (err != GRUB_USB_ERR_NONE) ++ { ++ if (status == CC_STALL_ERROR) ++ { ++ /* Clear the stall by resetting the endpoint */ ++ rc = xhci_cmd_reset_endpoint(x, priv->slotid, epid, 1); ++ ++ if (rc < 0) ++ return GRUB_USB_ERR_TIMEOUT; ++ ++ return GRUB_USB_ERR_STALL; ++ } ++ else if (remaining > 0) ++ { ++ return GRUB_USB_ERR_DATA; ++ } ++ } ++ ++ return err; ++} ++ ++static grub_usb_err_t ++grub_xhci_cancel_transfer (grub_usb_controller_t dev, ++ grub_usb_transfer_t transfer) ++{ ++ grub_uint8_t epid; ++ volatile struct grub_xhci_ring *reqs; ++ struct grub_pci_dma_chunk *enpoint_trbs_dma; ++ grub_addr_t deque_pointer; ++ int rc; ++ ++ if (!dev->data || !transfer->controller_data || !transfer->dev || ++ !transfer->dev->xhci_priv) ++ return GRUB_USB_ERR_INTERNAL; ++ ++ struct grub_xhci *x = (struct grub_xhci *) dev->data; ++ struct grub_xhci_transfer_controller_data *cdata = ++ transfer->controller_data; ++ struct grub_xhci_priv *priv = transfer->dev->xhci_priv; ++ ++ epid = grub_xhci_epid_from_transfer(transfer); ++ ++ enpoint_trbs_dma = priv->enpoint_trbs_dma[epid]; ++ reqs = priv->enpoint_trbs[epid]; ++ ++ /* Abort current command */ ++ rc = xhci_cmd_stop_endpoint(x, priv->slotid, epid, 0); ++ if (rc < 0) ++ return GRUB_USB_ERR_TIMEOUT; ++ ++ /* Reset state */ ++ reqs->nidx = 0; ++ reqs->eidx = 0; ++ reqs->cs = 1; ++ ++ grub_arch_sync_dma_caches(reqs, sizeof(*reqs)); ++ ++ /* Reset the dequeue pointer to the begging of the TRB */ ++ deque_pointer = grub_dma_get_phys(enpoint_trbs_dma); ++ rc = xhci_cmd_set_dequeue_pointer(x, priv->slotid, epid, deque_pointer| 1 ); ++ if (rc < 0) ++ return GRUB_USB_ERR_TIMEOUT; ++ ++ reqs->evt.ptr_low = 0; ++ reqs->evt.ptr_high = 0; ++ reqs->evt.control = 0; ++ reqs->evt.status = 0; ++ ++ grub_arch_sync_dma_caches(reqs, sizeof(*reqs)); ++ ++ /* Restart ring buffer processing */ ++ xhci_doorbell(x, priv->slotid, epid); ++ ++ grub_free (cdata); ++ ++ return GRUB_USB_ERR_NONE; ++} ++ ++/**************************************************************** ++ * xHCI port status functions ++ ****************************************************************/ ++ ++static int ++grub_xhci_hubports (grub_usb_controller_t dev) ++{ ++ struct grub_xhci *x = (struct grub_xhci *) dev->data; ++ grub_uint32_t portinfo; ++ ++ portinfo = x->ports; ++ grub_dprintf ("xhci", "root hub ports=%d\n", portinfo); ++ return portinfo; ++} ++ ++static grub_usb_err_t ++grub_xhci_portstatus (grub_usb_controller_t dev, ++ unsigned int port, unsigned int enable) ++{ ++ struct grub_xhci *x = (struct grub_xhci *) dev->data; ++ grub_uint32_t portsc, pls; ++ grub_uint32_t end; ++ ++ portsc = grub_xhci_port_read(x, port); ++ pls = xhci_get_field(portsc, XHCI_PORTSC_PLS); ++ ++ grub_dprintf("xhci", "grub_xhci_portstatus port #%d: 0x%08x,%s%s pls %d enable %d\n", ++ port, portsc, ++ (portsc & GRUB_XHCI_PORTSC_PP) ? " powered," : "", ++ (portsc & GRUB_XHCI_PORTSC_PED) ? " enabled," : "", ++ pls, enable); ++ xhci_check_status(x); ++ ++ if ((enable && (portsc & GRUB_XHCI_PORTSC_PED)) || ++ (!enable && !(portsc & GRUB_XHCI_PORTSC_PED))) ++ return GRUB_USB_ERR_NONE; ++ ++ if (!enable) ++ { ++ /* Disable port */ ++ grub_xhci_port_write(x, port, ~0, GRUB_XHCI_PORTSC_PED); ++ return GRUB_USB_ERR_NONE; ++ } ++ ++ grub_dprintf ("xhci", "portstatus: XHCI STATUS: %08x\n", ++ grub_xhci_read32(&x->op->usbsts)); ++ grub_dprintf ("xhci", ++ "portstatus: begin, iobase=%p, port=%d, status=0x%08x\n", ++ x->caps, port, portsc); ++ ++ switch (pls) ++ { ++ case PLS_U0: ++ /* A USB3 port - controller automatically performs reset */ ++ break; ++ case PLS_POLLING: ++ /* A USB2 port - perform device reset */ ++ grub_xhci_port_write(x, port, ~GRUB_XHCI_PORTSC_PED, GRUB_XHCI_PORTSC_PR); ++ break; ++ default: ++ return GRUB_USB_ERR_NONE; ++ } ++ ++ /* Wait for device to complete reset and be enabled */ ++ end = grub_get_time_ms () + 100; ++ for (;;) ++ { ++ portsc = grub_xhci_port_read(x, port); ++ if (!(portsc & GRUB_XHCI_PORTSC_CCS)) ++ { ++ /* Device disconnected during reset */ ++ grub_dprintf ("xhci","ERROR: %s device disconnected\n", __func__); ++ return GRUB_USB_ERR_BADDEVICE; ++ } ++ if (portsc & GRUB_XHCI_PORTSC_PED) ++ /* Reset complete */ ++ break; ++ if (grub_get_time_ms () > end) ++ { ++ grub_dprintf ("xhci","ERROR: %s TIMEOUT\n", __func__); ++ return GRUB_USB_ERR_TIMEOUT; ++ } ++ } ++ xhci_check_status(x); ++ ++ return GRUB_USB_ERR_NONE; ++} ++ ++/**************************************************************** ++ * xHCI detect device functions ++ ****************************************************************/ ++ ++static grub_usb_speed_t ++grub_xhci_detect_dev (grub_usb_controller_t dev, int port, int *changed) ++{ ++ struct grub_xhci *x = (struct grub_xhci *) dev->data; ++ grub_uint32_t portsc, speed; ++ ++ *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); ++ ++ /* On shutdown advertise all ports as disconnected. This will trigger ++ * a gracefull detatch. */ ++ if (x->shutdown) ++ { ++ *changed = 1; ++ return GRUB_USB_SPEED_NONE; ++ } ++ ++ /* Don't advertise new devices, connecting will fail if halted */ ++ if (xhci_is_halted(x)) ++ return GRUB_USB_SPEED_NONE; ++ ++ portsc = grub_xhci_port_read(x, port); ++ speed = xhci_get_field(portsc, XHCI_PORTSC_SPEED); ++ grub_uint8_t pls = xhci_get_field(portsc, XHCI_PORTSC_PLS); ++ ++ grub_dprintf("xhci", "grub_xhci_portstatus port #%d: 0x%08x,%s%s pls %d\n", ++ port, portsc, ++ (portsc & GRUB_XHCI_PORTSC_PP) ? " powered," : "", ++ (portsc & GRUB_XHCI_PORTSC_PED) ? " enabled," : "", ++ pls); ++ ++ /* Connect Status Change bit - it detects change of connection */ ++ if (portsc & GRUB_XHCI_PORTSC_CSC) ++ { ++ *changed = 1; ++ ++ grub_xhci_port_write(x, port, ~GRUB_XHCI_PORTSC_PED, GRUB_XHCI_PORTSC_CSC); ++ } ++ ++ 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++) ++ { ++ if (x->psids[port-1].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; ++ } ++ } ++ ++ return GRUB_USB_SPEED_NONE; ++} ++ ++/**************************************************************** ++ * xHCI attach/detach functions ++ ****************************************************************/ ++ ++static grub_usb_err_t ++grub_xhci_attach_dev (grub_usb_controller_t ctrl, grub_usb_device_t dev) ++{ ++ struct grub_xhci *x = (struct grub_xhci *) ctrl->data; ++ grub_usb_err_t err; ++ grub_uint32_t max; ++ ++ grub_dprintf("xhci", "%s: dev=%p\n", __func__, dev); ++ ++ if (!dev || !x) ++ return GRUB_USB_ERR_INTERNAL; ++ ++ dev->xhci_priv = grub_zalloc (sizeof (struct grub_xhci_priv)); ++ if (!dev->xhci_priv) ++ return GRUB_USB_ERR_INTERNAL; ++ ++ ++ switch (dev->speed) ++ { ++ case GRUB_USB_SPEED_LOW: ++ { ++ max = 8; ++ break; ++ } ++ case GRUB_USB_SPEED_FULL: ++ case GRUB_USB_SPEED_HIGH: ++ { ++ max = 64; ++ break; ++ } ++ case GRUB_USB_SPEED_SUPER: ++ { ++ max = 512; ++ break; ++ } ++ default: ++ case GRUB_USB_SPEED_NONE: ++ { ++ max = 0; ++ } ++ } ++ ++ /* Assign a slot, assign an address and configure endpoint 0 */ ++ err = grub_xhci_prepare_endpoint(x, dev, ++ 0, ++ 0, ++ GRUB_USB_TRANSACTION_TYPE_CONTROL, ++ max, ++ dev->xhci_priv); ++ ++ return err; ++} ++ ++static grub_usb_err_t ++grub_xhci_detach_dev (grub_usb_controller_t ctrl, grub_usb_device_t dev) ++{ ++ struct grub_xhci *x = (struct grub_xhci *) ctrl->data; ++ struct grub_xhci_priv *priv; ++ int cc = CC_SUCCESS; ++ ++ grub_dprintf("xhci", "%s: dev=%p\n", __func__, dev); ++ ++ if (!dev) ++ return GRUB_USB_ERR_INTERNAL; ++ ++ if (dev->xhci_priv) ++ { ++ priv = dev->xhci_priv; ++ /* Stop endpoints and free ring buffer */ ++ for (int i = 0; i < GRUB_XHCI_MAX_ENDPOINTS; i++) ++ { ++ if (priv->enpoint_trbs[i] != NULL) ++ { ++ cc = xhci_cmd_stop_endpoint(x, priv->slotid, i, 1); ++ if (cc != CC_SUCCESS) ++ grub_dprintf("xhci", "Failed to disable EP%d on slot %d\n", i, ++ priv->slotid); ++ ++ grub_dprintf("xhci", "grub_dma_free[%d]\n", i); ++ ++ grub_dma_free(priv->enpoint_trbs_dma[i]); ++ priv->enpoint_trbs[i] = NULL; ++ priv->enpoint_trbs_dma[i] = NULL; ++ } ++ } ++ ++ cc = xhci_cmd_disable_slot(x, priv->slotid); ++ if (cc == CC_SUCCESS) ++ { ++ if (priv->slotctx_dma) ++ grub_dma_free(priv->slotctx_dma); ++ x->devs[priv->slotid].ptr_low = 0; ++ x->devs[priv->slotid].ptr_high = 0; ++ grub_arch_sync_dma_caches(&x->devs[priv->slotid], sizeof(x->devs[0])); ++ } ++ else ++ grub_dprintf("xhci", "Failed to disable slot %d\n", priv->slotid); ++ ++ grub_free(dev->xhci_priv); ++ } ++ ++ dev->xhci_priv = NULL; ++ ++ if (cc != CC_SUCCESS) ++ return GRUB_USB_ERR_BADDEVICE; ++ return GRUB_USB_ERR_NONE; ++} ++ ++/**************************************************************** ++ * xHCI terminate functions ++ ****************************************************************/ ++ ++static void ++grub_xhci_halt(struct grub_xhci *x) ++{ ++ grub_uint32_t reg; ++ ++ /* Halt the command ring */ ++ reg = grub_xhci_read32(&x->op->crcr_low); ++ grub_xhci_write32(&x->op->crcr_low, reg | 4); ++ ++ int rc = xhci_event_wait(x, x->cmds, 100); ++ grub_dprintf("xhci", "%s: xhci_event_wait = %d\n", __func__, rc); ++ if (rc < 0) ++ return; ++ ++ /* Stop the controller */ ++ reg = grub_xhci_read32(&x->op->usbcmd); ++ if (reg & GRUB_XHCI_CMD_RS) ++ { ++ reg &= ~GRUB_XHCI_CMD_RS; ++ grub_xhci_write32(&x->op->usbcmd, reg); ++ } ++ ++ return; ++} ++ ++static grub_err_t ++grub_xhci_fini_hw (int noreturn __attribute__ ((unused))) ++{ ++ struct grub_xhci *x; ++ ++ /* We should disable all XHCI HW to prevent any DMA access etc. */ ++ for (x = xhci; x; x = x->next) ++ { ++ x->shutdown = 1; ++ ++ /* Gracefully detach active devices */ ++ grub_usb_poll_devices(0); ++ ++ /* Check if xHCI is halted and halt it if not */ ++ grub_xhci_halt (x); ++ ++ /* Reset xHCI */ ++ if (grub_xhci_reset (x) != GRUB_USB_ERR_NONE) ++ return GRUB_ERR_BAD_DEVICE; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static struct grub_usb_controller_dev usb_controller = { ++ .name = "xhci", ++ .iterate = grub_xhci_iterate, ++ .setup_transfer = grub_xhci_setup_transfer, ++ .check_transfer = grub_xhci_check_transfer, ++ .cancel_transfer = grub_xhci_cancel_transfer, ++ .hubports = grub_xhci_hubports, ++ .portstatus = grub_xhci_portstatus, ++ .detect_dev = grub_xhci_detect_dev, ++ .attach_dev = grub_xhci_attach_dev, ++ .detach_dev = grub_xhci_detach_dev, ++ /* estimated max. count of TDs for one bulk transfer */ ++ .max_bulk_tds = GRUB_XHCI_RING_ITEMS - 3 ++}; ++ ++GRUB_MOD_INIT (xhci) ++{ ++ grub_stop_disk_firmware (); ++ ++ grub_boot_time ("Initing XHCI hardware"); ++ grub_xhci_pci_scan (); ++ grub_boot_time ("Registering XHCI driver"); ++ grub_usb_controller_dev_register (&usb_controller); ++ grub_boot_time ("XHCI driver registered"); ++} ++ ++GRUB_MOD_FINI (xhci) ++{ ++ grub_xhci_fini_hw (0); ++ grub_usb_controller_dev_unregister (&usb_controller); ++} +diff --git a/include/grub/usb.h b/include/grub/usb.h +index 609faf7d0..eb71fa1c7 100644 +--- a/include/grub/usb.h ++++ b/include/grub/usb.h +@@ -338,6 +338,10 @@ grub_usb_cancel_transfer (grub_usb_transfer_t trans); + void + grub_ehci_init_device (volatile void *regs); + void ++grub_xhci_init_device (volatile void *regs); ++void + grub_ehci_pci_scan (void); ++void ++grub_xhci_pci_scan (void); + + #endif /* GRUB_USB_H */ +-- +2.47.3 + diff --git a/config/grub/xhci_nvme/patches/0014-grub-core-bus-usb-Parse-SuperSpeed-companion-descrip.patch b/config/grub/xhci_nvme/patches/0014-grub-core-bus-usb-Parse-SuperSpeed-companion-descrip.patch deleted file mode 100644 index c04e138e..00000000 --- a/config/grub/xhci_nvme/patches/0014-grub-core-bus-usb-Parse-SuperSpeed-companion-descrip.patch +++ /dev/null @@ -1,246 +0,0 @@ -From 1c5716f42deb27b1111839b9782fd06b077eaa90 Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph -Date: Sun, 15 Nov 2020 19:00:27 +0100 -Subject: [PATCH 14/26] 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 -to the endpoint descriptor as it's no longer an continous array. - -Signed-off-by: Patrick Rudolph ---- - grub-core/bus/usb/serial/common.c | 2 +- - grub-core/bus/usb/usb.c | 44 +++++++++++++++++++------------ - grub-core/bus/usb/usbhub.c | 22 ++++++++++++---- - grub-core/commands/usbtest.c | 2 +- - grub-core/disk/usbms.c | 2 +- - grub-core/term/usb_keyboard.c | 2 +- - include/grub/usb.h | 2 +- - include/grub/usbdesc.h | 11 +++++++- - 8 files changed, 59 insertions(+), 28 deletions(-) - -diff --git a/grub-core/bus/usb/serial/common.c b/grub-core/bus/usb/serial/common.c -index e9c995a0a..fc847d66d 100644 ---- a/grub-core/bus/usb/serial/common.c -+++ b/grub-core/bus/usb/serial/common.c -@@ -72,7 +72,7 @@ grub_usbserial_attach (grub_usb_device_t usbdev, int configno, int interfno, - for (j = 0; j < interf->endpointcnt; j++) - { - struct grub_usb_desc_endp *endp; -- endp = &usbdev->config[0].interf[interfno].descendp[j]; -+ endp = usbdev->config[0].interf[interfno].descendp[j]; - - if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2 - && (in_endp == GRUB_USB_SERIAL_ENDPOINT_LAST_MATCHING -diff --git a/grub-core/bus/usb/usb.c b/grub-core/bus/usb/usb.c -index 7bd49d201..e578af793 100644 ---- a/grub-core/bus/usb/usb.c -+++ b/grub-core/bus/usb/usb.c -@@ -118,7 +118,7 @@ grub_usb_device_initialize (grub_usb_device_t dev) - struct grub_usb_desc_device *descdev; - struct grub_usb_desc_config config; - grub_usb_err_t err; -- int i; -+ int i, j; - - /* First we have to read first 8 bytes only and determine - * max. size of packet */ -@@ -152,6 +152,7 @@ grub_usb_device_initialize (grub_usb_device_t dev) - int currif; - char *data; - struct grub_usb_desc *desc; -+ struct grub_usb_desc_endp *endp; - - /* First just read the first 4 bytes of the configuration - descriptor, after that it is known how many bytes really have -@@ -201,24 +202,27 @@ grub_usb_device_initialize (grub_usb_device_t dev) - = (struct grub_usb_desc_if *) &data[pos]; - pos += dev->config[i].interf[currif].descif->length; - -+ dev->config[i].interf[currif].descendp = grub_malloc ( -+ dev->config[i].interf[currif].descif->endpointcnt * -+ sizeof(struct grub_usb_desc_endp)); -+ -+ j = 0; - while (pos < config.totallen) - { - desc = (struct grub_usb_desc *)&data[pos]; -- if (desc->type == GRUB_USB_DESCRIPTOR_ENDPOINT) -- break; -- if (!desc->length) -- { -- err = GRUB_USB_ERR_BADDEVICE; -- goto fail; -- } -- pos += desc->length; -- } -- -- /* Point to the first endpoint. */ -- dev->config[i].interf[currif].descendp -- = (struct grub_usb_desc_endp *) &data[pos]; -- pos += (sizeof (struct grub_usb_desc_endp) -- * dev->config[i].interf[currif].descif->endpointcnt); -+ if (desc->type == GRUB_USB_DESCRIPTOR_ENDPOINT) { -+ endp = (struct grub_usb_desc_endp *) &data[pos]; -+ dev->config[i].interf[currif].descendp[j++] = endp; -+ pos += desc->length; -+ } else { -+ if (!desc->length) -+ { -+ err = GRUB_USB_ERR_BADDEVICE; -+ goto fail; -+ } -+ pos += desc->length; -+ } -+ } - } - } - -@@ -226,8 +230,14 @@ grub_usb_device_initialize (grub_usb_device_t dev) - - fail: - -- for (i = 0; i < GRUB_USB_MAX_CONF; i++) -+ for (i = 0; i < GRUB_USB_MAX_CONF; i++) { -+ int currif; -+ -+ for (currif = 0; currif < dev->config[i].descconf->numif; currif++) -+ grub_free (dev->config[i].interf[currif].descendp); -+ - grub_free (dev->config[i].descconf); -+ } - - return err; - } -diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c -index f5608e330..2ae29cba1 100644 ---- a/grub-core/bus/usb/usbhub.c -+++ b/grub-core/bus/usb/usbhub.c -@@ -82,8 +82,14 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, - if (i == GRUB_USBHUB_MAX_DEVICES) - { - grub_error (GRUB_ERR_IO, "can't assign address to USB device"); -- for (i = 0; i < GRUB_USB_MAX_CONF; i++) -- grub_free (dev->config[i].descconf); -+ for (i = 0; i < GRUB_USB_MAX_CONF; i++) { -+ int currif; -+ -+ for (currif = 0; currif < dev->config[i].descconf->numif; currif++) -+ grub_free (dev->config[i].interf[currif].descendp); -+ -+ grub_free (dev->config[i].descconf); -+ } - grub_free (dev); - return NULL; - } -@@ -96,8 +102,14 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, - i, 0, 0, NULL); - if (err) - { -- for (i = 0; i < GRUB_USB_MAX_CONF; i++) -- grub_free (dev->config[i].descconf); -+ for (i = 0; i < GRUB_USB_MAX_CONF; i++) { -+ int currif; -+ -+ for (currif = 0; currif < dev->config[i].descconf->numif; currif++) -+ grub_free (dev->config[i].interf[currif].descendp); -+ -+ grub_free (dev->config[i].descconf); -+ } - grub_free (dev); - return NULL; - } -@@ -176,7 +188,7 @@ grub_usb_add_hub (grub_usb_device_t dev) - i++) - { - struct grub_usb_desc_endp *endp = NULL; -- endp = &dev->config[0].interf[0].descendp[i]; -+ endp = dev->config[0].interf[0].descendp[i]; - - 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 ---- 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))) - for (j = 0; j < interf->endpointcnt; j++) - { - struct grub_usb_desc_endp *endp; -- endp = &dev->config[0].interf[i].descendp[j]; -+ endp = dev->config[0].interf[i].descendp[j]; - - grub_printf ("Endpoint #%d: %s, max packed size: %d, transfer type: %s, latency: %d\n", - endp->endp_addr & 15, -diff --git a/grub-core/disk/usbms.c b/grub-core/disk/usbms.c -index b81e3ad9d..b1512dc12 100644 ---- a/grub-core/disk/usbms.c -+++ b/grub-core/disk/usbms.c -@@ -184,7 +184,7 @@ grub_usbms_attach (grub_usb_device_t usbdev, int configno, int interfno) - for (j = 0; j < interf->endpointcnt; j++) - { - struct grub_usb_desc_endp *endp; -- endp = &usbdev->config[0].interf[interfno].descendp[j]; -+ endp = usbdev->config[0].interf[interfno].descendp[j]; - - if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2) - /* Bulk IN endpoint. */ -diff --git a/grub-core/term/usb_keyboard.c b/grub-core/term/usb_keyboard.c -index 7322d8dff..d590979f5 100644 ---- a/grub-core/term/usb_keyboard.c -+++ b/grub-core/term/usb_keyboard.c -@@ -175,7 +175,7 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) - for (j = 0; j < usbdev->config[configno].interf[interfno].descif->endpointcnt; - j++) - { -- endp = &usbdev->config[configno].interf[interfno].descendp[j]; -+ endp = usbdev->config[configno].interf[interfno].descendp[j]; - - if ((endp->endp_addr & 128) && grub_usb_get_ep_type(endp) - == GRUB_USB_EP_INTERRUPT) -diff --git a/include/grub/usb.h b/include/grub/usb.h -index 0f346af12..688c11f6d 100644 ---- a/include/grub/usb.h -+++ b/include/grub/usb.h -@@ -153,7 +153,7 @@ struct grub_usb_interface - { - struct grub_usb_desc_if *descif; - -- struct grub_usb_desc_endp *descendp; -+ struct grub_usb_desc_endp **descendp; - - /* A driver is handling this interface. Do we need to support multiple drivers - for single interface? -diff --git a/include/grub/usbdesc.h b/include/grub/usbdesc.h -index aac5ab05a..bb2ab2e27 100644 ---- a/include/grub/usbdesc.h -+++ b/include/grub/usbdesc.h -@@ -29,7 +29,8 @@ typedef enum { - GRUB_USB_DESCRIPTOR_INTERFACE, - GRUB_USB_DESCRIPTOR_ENDPOINT, - GRUB_USB_DESCRIPTOR_DEBUG = 10, -- GRUB_USB_DESCRIPTOR_HUB = 0x29 -+ GRUB_USB_DESCRIPTOR_HUB = 0x29, -+ GRUB_USB_DESCRIPTOR_SS_ENDPOINT_COMPANION = 0x30 - } grub_usb_descriptor_t; - - struct grub_usb_desc -@@ -105,6 +106,14 @@ struct grub_usb_desc_endp - grub_uint8_t interval; - } GRUB_PACKED; - -+struct grub_usb_desc_ssep { -+ grub_uint8_t length; -+ grub_uint8_t type; -+ grub_uint8_t maxburst; -+ grub_uint8_t attrib; -+ grub_uint16_t interval; -+} GRUB_PACKED; -+ - struct grub_usb_desc_str - { - grub_uint8_t length; --- -2.39.5 - diff --git a/config/grub/xhci_nvme/patches/0014-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 new file mode 100644 index 00000000..98f38569 --- /dev/null +++ b/config/grub/xhci_nvme/patches/0014-grub-core-bus-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch @@ -0,0 +1,127 @@ +From 861b218be772b8abf090647fc24eb7c7ccc1d2db Mon Sep 17 00:00:00 2001 +From: Patrick Rudolph +Date: Mon, 7 Dec 2020 08:41:27 +0100 +Subject: [PATCH 14/20] grub-core/bus/usb/usbhub: Add xHCI non root hub support + +Tested on Intel PCH C246, the USB3 hub can be configured by grub. + +Issues: +* USB3 devices connected behind that hub are sometimes not detected. + +Signed-off-by: Patrick Rudolph +--- + grub-core/bus/usb/usbhub.c | 38 +++++++++++++++++++++++++++++++++----- + include/grub/usbdesc.h | 1 + + include/grub/usbtrans.h | 4 ++++ + 3 files changed, 38 insertions(+), 5 deletions(-) + +diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c +index b4b3a1a61..e96505aa9 100644 +--- a/grub-core/bus/usb/usbhub.c ++++ b/grub-core/bus/usb/usbhub.c +@@ -148,19 +148,32 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, + return dev; + } + +- ++static grub_usb_err_t ++grub_usb_set_hub_depth(grub_usb_device_t dev, grub_uint8_t depth) ++{ ++ return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT ++ | GRUB_USB_REQTYPE_CLASS ++ | GRUB_USB_REQTYPE_TARGET_DEV), ++ GRUB_USB_HUB_REQ_SET_HUB_DEPTH, depth, ++ 0, 0, NULL); ++} ++ + static grub_usb_err_t + grub_usb_add_hub (grub_usb_device_t dev) + { + struct grub_usb_usb_hubdesc hubdesc; + grub_usb_err_t err; ++ grub_uint16_t req; + int i; + ++ req = (dev->speed == GRUB_USB_SPEED_SUPER) ? GRUB_USB_DESCRIPTOR_SS_HUB : ++ GRUB_USB_DESCRIPTOR_HUB; ++ + err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_DEV), +- GRUB_USB_REQ_GET_DESCRIPTOR, +- (GRUB_USB_DESCRIPTOR_HUB << 8) | 0, ++ GRUB_USB_REQ_GET_DESCRIPTOR, ++ (req << 8) | 0, + 0, sizeof (hubdesc), (char *) &hubdesc); + if (err) + return err; +@@ -183,6 +196,19 @@ grub_usb_add_hub (grub_usb_device_t dev) + return GRUB_USB_ERR_INTERNAL; + } + ++ if (dev->speed == GRUB_USB_SPEED_SUPER) ++ { ++ grub_uint8_t depth; ++ grub_uint32_t route; ++ /* Depth maximum value is 5, but root hubs doesn't count */ ++ for (depth = 0, route = dev->route; (route & 0xf) > 0; route >>= 4) ++ depth++; ++ ++ err = grub_usb_set_hub_depth(dev, depth); ++ if (err) ++ return err; ++ } ++ + /* Power on all Hub ports. */ + for (i = 1; i <= hubdesc.portcnt; i++) + { +@@ -637,7 +663,9 @@ poll_nonroot_hub (grub_usb_device_t dev) + int split_hubaddr = 0; + + /* Determine the device speed. */ +- if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED) ++ if (dev->speed == GRUB_USB_SPEED_SUPER) ++ speed = GRUB_USB_SPEED_SUPER; ++ else if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED) + speed = GRUB_USB_SPEED_LOW; + else + { +@@ -651,7 +679,7 @@ poll_nonroot_hub (grub_usb_device_t dev) + grub_millisleep (10); + + /* Find correct values for SPLIT hubport and hubaddr */ +- if (speed == GRUB_USB_SPEED_HIGH) ++ if (speed == GRUB_USB_SPEED_HIGH || speed == GRUB_USB_SPEED_SUPER) + { + /* HIGH speed device needs not transaction translation */ + split_hubport = 0; +diff --git a/include/grub/usbdesc.h b/include/grub/usbdesc.h +index bb2ab2e27..1697aa465 100644 +--- a/include/grub/usbdesc.h ++++ b/include/grub/usbdesc.h +@@ -30,6 +30,7 @@ typedef enum { + GRUB_USB_DESCRIPTOR_ENDPOINT, + GRUB_USB_DESCRIPTOR_DEBUG = 10, + GRUB_USB_DESCRIPTOR_HUB = 0x29, ++ GRUB_USB_DESCRIPTOR_SS_HUB = 0x2a, + GRUB_USB_DESCRIPTOR_SS_ENDPOINT_COMPANION = 0x30 + } grub_usb_descriptor_t; + +diff --git a/include/grub/usbtrans.h b/include/grub/usbtrans.h +index 039ebed65..d6c3f71dc 100644 +--- a/include/grub/usbtrans.h ++++ b/include/grub/usbtrans.h +@@ -110,6 +110,10 @@ enum + GRUB_USB_REQ_SET_INTERFACE = 0x0B, + GRUB_USB_REQ_SYNC_FRAME = 0x0C + }; ++enum ++ { ++ GRUB_USB_HUB_REQ_SET_HUB_DEPTH = 0x0C, ++ }; + + #define GRUB_USB_FEATURE_ENDP_HALT 0x00 + #define GRUB_USB_FEATURE_DEV_REMOTE_WU 0x01 +-- +2.47.3 + diff --git a/config/grub/xhci_nvme/patches/0015-usb-Add-enum-for-xHCI.patch b/config/grub/xhci_nvme/patches/0015-usb-Add-enum-for-xHCI.patch deleted file mode 100644 index 4de9d894..00000000 --- a/config/grub/xhci_nvme/patches/0015-usb-Add-enum-for-xHCI.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 260f27e1ea1dbcdeb63d4411dbdddb97ebb39668 Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph -Date: Mon, 7 Dec 2020 08:41:22 +0100 -Subject: [PATCH 15/26] usb: Add enum for xHCI - -Will be used in future patches. - -Signed-off-by: Patrick Rudolph ---- - include/grub/usb.h | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/include/grub/usb.h b/include/grub/usb.h -index 688c11f6d..ea6ee8c2c 100644 ---- a/include/grub/usb.h -+++ b/include/grub/usb.h -@@ -51,7 +51,8 @@ typedef enum - GRUB_USB_SPEED_NONE, - GRUB_USB_SPEED_LOW, - GRUB_USB_SPEED_FULL, -- GRUB_USB_SPEED_HIGH -+ GRUB_USB_SPEED_HIGH, -+ GRUB_USB_SPEED_SUPER - } grub_usb_speed_t; - - typedef int (*grub_usb_iterate_hook_t) (grub_usb_device_t dev, void *data); --- -2.39.5 - 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..69d0e653 --- /dev/null +++ b/config/grub/xhci_nvme/patches/0015-xHCI-also-accept-SBRN-0x31-and-0x32.patch @@ -0,0 +1,26 @@ +From 0a1a2f3a2f4b3908f094133c86fda0e882dabda5 Mon Sep 17 00:00:00 2001 +From: Sven Anderson +Date: Sat, 28 May 2022 21:39:23 +0200 +Subject: [PATCH 15/20] xHCI: also accept SBRN 0x31 and 0x32 + +Signed-off-by: Sven Anderson +--- + 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-usbtrans-Set-default-maximum-packet-size.patch b/config/grub/xhci_nvme/patches/0016-usbtrans-Set-default-maximum-packet-size.patch deleted file mode 100644 index 908c3adb..00000000 --- a/config/grub/xhci_nvme/patches/0016-usbtrans-Set-default-maximum-packet-size.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 97f71a34c011ad9d37b96c02eb7483fe253c6025 Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph -Date: Mon, 7 Dec 2020 08:41:23 +0100 -Subject: [PATCH 16/26] usbtrans: Set default maximum packet size - -Set the maximum packet size to 512 for SuperSpeed devices. - -Signed-off-by: Patrick Rudolph ---- - grub-core/bus/usb/usbtrans.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/grub-core/bus/usb/usbtrans.c b/grub-core/bus/usb/usbtrans.c -index c5680b33a..c1080bb33 100644 ---- a/grub-core/bus/usb/usbtrans.c -+++ b/grub-core/bus/usb/usbtrans.c -@@ -128,8 +128,12 @@ grub_usb_control_msg (grub_usb_device_t dev, - setupdata_addr = grub_dma_get_phys (setupdata_chunk); - - /* Determine the maximum packet size. */ -- if (dev->descdev.maxsize0) -+ if (dev->descdev.maxsize0 && dev->speed != GRUB_USB_SPEED_SUPER) - max = dev->descdev.maxsize0; -+ else if (dev->descdev.maxsize0 && dev->speed == GRUB_USB_SPEED_SUPER) -+ max = 1UL << dev->descdev.maxsize0; -+ else if (dev->speed == GRUB_USB_SPEED_SUPER) -+ max = 512; - else - max = 64; - --- -2.39.5 - 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..bdbaf417 --- /dev/null +++ b/config/grub/xhci_nvme/patches/0016-xhci-fix-port-indexing.patch @@ -0,0 +1,43 @@ +From 9343cdda106d47561f25ce1e39a86d62cb0bfd08 Mon Sep 17 00:00:00 2001 +From: Sven Anderson +Date: Mon, 13 Jan 2025 19:51:41 +0100 +Subject: [PATCH 16/20] 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-grub-core-bus-usb-Add-function-pointer-for-attach-de.patch b/config/grub/xhci_nvme/patches/0017-grub-core-bus-usb-Add-function-pointer-for-attach-de.patch deleted file mode 100644 index e4798a8d..00000000 --- a/config/grub/xhci_nvme/patches/0017-grub-core-bus-usb-Add-function-pointer-for-attach-de.patch +++ /dev/null @@ -1,121 +0,0 @@ -From ea5081844c3112b582f52360cfb14ef95b56f5e1 Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph -Date: Sun, 15 Nov 2020 19:51:42 +0100 -Subject: [PATCH 17/26] 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. - -Will be used in future commits, currently this doesn't change any functionality. - -Signed-off-by: Patrick Rudolph ---- - grub-core/bus/usb/ehci.c | 2 ++ - grub-core/bus/usb/ohci.c | 2 ++ - grub-core/bus/usb/uhci.c | 2 ++ - grub-core/bus/usb/usbhub.c | 19 +++++++++++++++++++ - include/grub/usb.h | 4 ++++ - 5 files changed, 29 insertions(+) - -diff --git a/grub-core/bus/usb/ehci.c b/grub-core/bus/usb/ehci.c -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 = { - .hubports = grub_ehci_hubports, - .portstatus = grub_ehci_portstatus, - .detect_dev = grub_ehci_detect_dev, -+ .attach_dev = NULL, -+ .detach_dev = NULL, - /* estimated max. count of TDs for one bulk transfer */ - .max_bulk_tds = GRUB_EHCI_N_TD * 3 / 4 - }; -diff --git a/grub-core/bus/usb/ohci.c b/grub-core/bus/usb/ohci.c -index 5363a61f6..7a3f3e154 100644 ---- a/grub-core/bus/usb/ohci.c -+++ b/grub-core/bus/usb/ohci.c -@@ -1440,6 +1440,8 @@ static struct grub_usb_controller_dev usb_controller = - .hubports = grub_ohci_hubports, - .portstatus = grub_ohci_portstatus, - .detect_dev = grub_ohci_detect_dev, -+ .attach_dev = NULL, -+ .detach_dev = NULL, - /* estimated max. count of TDs for one bulk transfer */ - .max_bulk_tds = GRUB_OHCI_TDS * 3 / 4 - }; -diff --git a/grub-core/bus/usb/uhci.c b/grub-core/bus/usb/uhci.c -index 0fdea4c1e..03c4605b2 100644 ---- a/grub-core/bus/usb/uhci.c -+++ b/grub-core/bus/usb/uhci.c -@@ -845,6 +845,8 @@ static struct grub_usb_controller_dev usb_controller = - .hubports = grub_uhci_hubports, - .portstatus = grub_uhci_portstatus, - .detect_dev = grub_uhci_detect_dev, -+ .attach_dev = NULL, -+ .detach_dev = NULL, - /* estimated max. count of TDs for one bulk transfer */ - .max_bulk_tds = N_TD * 3 / 4 - }; -diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c -index 2ae29cba1..8e963e84b 100644 ---- a/grub-core/bus/usb/usbhub.c -+++ b/grub-core/bus/usb/usbhub.c -@@ -66,6 +66,15 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, - dev->split_hubport = split_hubport; - dev->split_hubaddr = split_hubaddr; - -+ if (controller->dev->attach_dev) { -+ err = controller->dev->attach_dev (controller, dev); -+ if (err) -+ { -+ grub_free (dev); -+ return NULL; -+ } -+ } -+ - err = grub_usb_device_initialize (dev); - if (err) - { -@@ -405,6 +414,8 @@ static void - detach_device (grub_usb_device_t dev) - { - unsigned i; -+ grub_usb_err_t err; -+ - int k; - if (!dev) - return; -@@ -425,6 +436,14 @@ detach_device (grub_usb_device_t dev) - if (inter && inter->detach_hook) - inter->detach_hook (dev, i, k); - } -+ if (dev->controller.dev->detach_dev) { -+ err = dev->controller.dev->detach_dev (&dev->controller, dev); -+ if (err) -+ { -+ // XXX -+ } -+ } -+ - grub_usb_devs[dev->addr] = 0; - } - -diff --git a/include/grub/usb.h b/include/grub/usb.h -index ea6ee8c2c..4dd179db2 100644 ---- a/include/grub/usb.h -+++ b/include/grub/usb.h -@@ -126,6 +126,10 @@ struct grub_usb_controller_dev - - grub_usb_speed_t (*detect_dev) (grub_usb_controller_t dev, int port, int *changed); - -+ grub_usb_err_t (*attach_dev) (grub_usb_controller_t ctrl, grub_usb_device_t dev); -+ -+ grub_usb_err_t (*detach_dev) (grub_usb_controller_t ctrl, grub_usb_device_t dev); -+ - /* Per controller flag - port reset pending, don't do another reset */ - grub_uint64_t pending_reset; - --- -2.39.5 - 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..83410e2e --- /dev/null +++ b/config/grub/xhci_nvme/patches/0017-xhci-configure-TT-for-non-root-hubs.patch @@ -0,0 +1,98 @@ +From 41e966e3054862e1921e14bd2ecec3bfb20cba8f Mon Sep 17 00:00:00 2001 +From: Sven Anderson +Date: Mon, 13 Jan 2025 20:26:32 +0100 +Subject: [PATCH 17/20] 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/xhci_nvme/patches/0018-Fix-compilation-on-x86_64.patch b/config/grub/xhci_nvme/patches/0018-Fix-compilation-on-x86_64.patch new file mode 100644 index 00000000..405cfeb9 --- /dev/null +++ b/config/grub/xhci_nvme/patches/0018-Fix-compilation-on-x86_64.patch @@ -0,0 +1,90 @@ +From 114346473d1e5d3660ea0dae4ed9f4c8ad98bbeb Mon Sep 17 00:00:00 2001 +From: Patrick Rudolph +Date: Wed, 24 Feb 2021 08:25:41 +0100 +Subject: [PATCH 18/20] Fix compilation on x86_64 + +Signed-off-by: Patrick Rudolph +--- + grub-core/bus/usb/xhci.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/grub-core/bus/usb/xhci.c b/grub-core/bus/usb/xhci.c +index 88c9ac57f..9b9bae6e5 100644 +--- a/grub-core/bus/usb/xhci.c ++++ b/grub-core/bus/usb/xhci.c +@@ -184,7 +184,7 @@ enum + * then we can get it from a trb pointer (provided by evt ring). + */ + #define XHCI_RING(_trb) \ +- ((struct grub_xhci_ring*)((grub_uint32_t)(_trb) & ~(GRUB_XHCI_RING_SIZE-1))) ++ ((struct grub_xhci_ring*)((grub_addr_t)(_trb) & ~(GRUB_XHCI_RING_SIZE-1))) + + /* slot context */ + struct grub_xhci_slotctx { +@@ -495,6 +495,14 @@ grub_xhci_read8(volatile void *addr) { + return (*((volatile grub_uint32_t *)addr)); + } + ++static inline void * ++grub_xhci_read_etrb_ptr(volatile struct grub_xhci_trb *trb) { ++ grub_uint64_t tmp; ++ tmp = (grub_uint64_t)grub_xhci_read32(&trb->ptr_low); ++ tmp |= ((grub_uint64_t)grub_xhci_read32(&trb->ptr_high)) << 32; ++ return (void *)(grub_addr_t)tmp; ++} ++ + static inline grub_uint32_t + grub_xhci_port_read (struct grub_xhci *x, grub_uint32_t port) + { +@@ -697,7 +705,7 @@ static void xhci_process_events(struct grub_xhci *x) + case ER_TRANSFER: + case ER_COMMAND_COMPLETE: + { +- struct grub_xhci_trb *rtrb = (void*)grub_xhci_read32(&etrb->ptr_low); ++ struct grub_xhci_trb *rtrb = grub_xhci_read_etrb_ptr(etrb); + struct grub_xhci_ring *ring = XHCI_RING(rtrb); + volatile struct grub_xhci_trb *evt = &ring->evt; + grub_uint32_t eidx = rtrb - ring->ring + 1; +@@ -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; +- grub_uint32_t erdp = (grub_uint32_t)(evts->ring + nidx); +- grub_xhci_write32(&ir->erdp_low, erdp); +- grub_xhci_write32(&ir->erdp_high, 0); ++ grub_uint64_t erdp = (grub_addr_t)(void *)(&evts->ring[nidx]); ++ grub_xhci_write32(&ir->erdp_low, erdp & 0xffffffff); ++ grub_xhci_write32(&ir->erdp_high, erdp >> 32); + } + } + +@@ -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__, +- ring, data_or_addr, xferlen & 0x1ffff, flags, xferlen >> 17); ++ ring, (unsigned long long)data_or_addr, xferlen & 0x1ffff, flags, xferlen >> 17); + + if (xhci_ring_full(ring)) + { +@@ -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; +- setupdata = (void *)transfer->transactions[0].data; ++ setupdata = (void *)(grub_addr_t)transfer->transactions[0].data; + grub_dprintf("xhci", "%s: CONTROLL TRANS req %d\n", __func__, setupdata->request); + grub_dprintf("xhci", "%s: CONTROLL TRANS length %d\n", __func__, setupdata->length); + +@@ -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)) + { +- grub_memcpy(&inline_data, (void *)tr->data, tr->size); ++ grub_memcpy(&inline_data, (void *)(grub_addr_t)tr->data, tr->size); + xhci_trb_queue(reqs, inline_data, tr->size, flags); + } + else +-- +2.47.3 + diff --git a/config/grub/xhci_nvme/patches/0018-grub-core-bus-usb-usbhub-Add-new-private-fields-for-.patch b/config/grub/xhci_nvme/patches/0018-grub-core-bus-usb-usbhub-Add-new-private-fields-for-.patch deleted file mode 100644 index d2067637..00000000 --- a/config/grub/xhci_nvme/patches/0018-grub-core-bus-usb-usbhub-Add-new-private-fields-for-.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 7db1cdd1cdbb79a8da04648dcbf7318d200f72a4 Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph -Date: Mon, 7 Dec 2020 08:41:25 +0100 -Subject: [PATCH 18/26] 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. - -Signed-off-by: Patrick Rudolph ---- - grub-core/bus/usb/usbhub.c | 11 ++++++++--- - include/grub/usb.h | 5 +++++ - 2 files changed, 13 insertions(+), 3 deletions(-) - -diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c -index 8e963e84b..b4b3a1a61 100644 ---- a/grub-core/bus/usb/usbhub.c -+++ b/grub-core/bus/usb/usbhub.c -@@ -49,7 +49,9 @@ static grub_usb_controller_dev_t grub_usb_list; - static grub_usb_device_t - grub_usb_hub_add_dev (grub_usb_controller_t controller, - grub_usb_speed_t speed, -- int split_hubport, int split_hubaddr) -+ int split_hubport, int split_hubaddr, -+ int root_portno, -+ grub_uint32_t route) - { - grub_usb_device_t dev; - int i; -@@ -65,6 +67,8 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, - dev->speed = speed; - dev->split_hubport = split_hubport; - dev->split_hubaddr = split_hubaddr; -+ dev->root_port = root_portno; -+ dev->route = route; - - if (controller->dev->attach_dev) { - err = controller->dev->attach_dev (controller, dev); -@@ -245,7 +249,7 @@ attach_root_port (struct grub_usb_hub *hub, int portno, - and full/low speed device connected to OHCI/UHCI needs not - transaction translation - e.g. hubport and hubaddr should be - always none (zero) for any device connected to any root hub. */ -- dev = grub_usb_hub_add_dev (hub->controller, speed, 0, 0); -+ dev = grub_usb_hub_add_dev (hub->controller, speed, 0, 0, portno, 0); - hub->controller->dev->pending_reset = 0; - npending--; - if (! dev) -@@ -676,7 +680,8 @@ poll_nonroot_hub (grub_usb_device_t dev) - - /* Add the device and assign a device address to it. */ - next_dev = grub_usb_hub_add_dev (&dev->controller, speed, -- split_hubport, split_hubaddr); -+ split_hubport, split_hubaddr, dev->root_port, -+ dev->route << 4 | (i & 0xf)); - if (dev->controller.dev->pending_reset) - { - dev->controller.dev->pending_reset = 0; -diff --git a/include/grub/usb.h b/include/grub/usb.h -index 4dd179db2..609faf7d0 100644 ---- a/include/grub/usb.h -+++ b/include/grub/usb.h -@@ -237,6 +237,11 @@ struct grub_usb_device - int split_hubport; - - int split_hubaddr; -+ -+ /* xHCI specific information */ -+ int root_port; -+ grub_uint32_t route; -+ void *xhci_priv; - }; - - --- -2.39.5 - 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..57762843 --- /dev/null +++ b/config/grub/xhci_nvme/patches/0019-Add-native-NVMe-driver-based-on-SeaBIOS.patch @@ -0,0 +1,1074 @@ +From 2b255ee97a48f280a20acd807386bec52ea447c8 Mon Sep 17 00:00:00 2001 +From: Mate Kukri +Date: Mon, 20 May 2024 11:43:35 +0100 +Subject: [PATCH 19/20] Add native NVMe driver based on SeaBIOS + +Tested to successfully boot Debian on QEMU and OptiPlex 3050. + +Signed-off-by: Mate Kukri +--- + 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 208badbdf..219282524 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2775,3 +2775,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 ++ ++/* 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 ++#include ++#include ++#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/0019-grub-core-bus-usb-Add-xhci-support.patch b/config/grub/xhci_nvme/patches/0019-grub-core-bus-usb-Add-xhci-support.patch deleted file mode 100644 index b4d6e956..00000000 --- a/config/grub/xhci_nvme/patches/0019-grub-core-bus-usb-Add-xhci-support.patch +++ /dev/null @@ -1,2807 +0,0 @@ -From 6b34ac2449362da5139e702e484a432d828a505d Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph -Date: Mon, 7 Dec 2020 08:41:26 +0100 -Subject: [PATCH 19/26] grub-core/bus/usb: Add xhci support - -Add support for xHCI USB controllers. -The code is based on seabios implementation, but has been heavily -modified to match grubs internals. - -Changes done in version 2: -* Code cleanup -* Code style fixes -* Don't leak memory buffers -* Compile without warnings -* Add more defines -* Add more helper functions -* Don't assume a 1:1 virtual to physical mapping -* Flush cachelines after writing buffers -* Don't use hardcoded page size -* Proper scratchpad register setup -* xHCI bios ownership handoff - -Changes done in version 3: -* Fixed a race condition detecting events, which doesn't appear on - qemu based xHCI controllers -* Don't accidently disable USB3.0 devices after first command -* Support arbitrary protocol speed IDs -* Coding style cleanup - -Tested: -* Qemu system x86_64 - * virtual USB HID keyboard (usb-kbd) - * virtual USB HID mass storage (usb-storage) -* init Supermicro X11SSH-F - * iKVM HID keyboard - * USB3 HID mass storage (controller root port) - * USB HID keyboard - -TODO: - * Test on more hardware - * Test on USB3 hubs - * Support for USB 3.1 and USB 3.2 controllers - -Signed-off-by: Patrick Rudolph -Signed-off-by: sylv ---- - Makefile.am | 2 +- - grub-core/Makefile.core.def | 7 + - grub-core/bus/usb/xhci-pci.c | 195 +++ - grub-core/bus/usb/xhci.c | 2496 ++++++++++++++++++++++++++++++++++ - include/grub/usb.h | 4 + - 5 files changed, 2703 insertions(+), 1 deletion(-) - create mode 100644 grub-core/bus/usb/xhci-pci.c - create mode 100644 grub-core/bus/usb/xhci.c - -diff --git a/Makefile.am b/Makefile.am -index 43635d5ff..65016f856 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 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 cd29a9df8..d3947739f 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -667,6 +667,13 @@ module = { - enable = arm_coreboot; - }; - -+module = { -+ name = xhci; -+ common = bus/usb/xhci.c; -+ pci = bus/usb/xhci-pci.c; -+ enable = pci; -+}; -+ - module = { - name = pci; - common = bus/pci.c; -diff --git a/grub-core/bus/usb/xhci-pci.c b/grub-core/bus/usb/xhci-pci.c -new file mode 100644 -index 000000000..a5bd3c97d ---- /dev/null -+++ b/grub-core/bus/usb/xhci-pci.c -@@ -0,0 +1,195 @@ -+/* xhci.c - XHCI Support. */ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2020 9elements Cyber Security -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define GRUB_XHCI_PCI_SBRN_REG 0x60 -+#define GRUB_XHCI_ADDR_MEM_MASK (~0xff) -+ -+/* USBLEGSUP bits and related OS OWNED byte offset */ -+enum -+{ -+ GRUB_XHCI_BIOS_OWNED = (1 << 16), -+ GRUB_XHCI_OS_OWNED = (1 << 24) -+}; -+ -+/* PCI iteration function... */ -+static int -+grub_xhci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid, -+ void *data __attribute__ ((unused))) -+{ -+ volatile grub_uint32_t *regs; -+ grub_uint32_t base, base_h; -+ grub_uint32_t eecp_offset; -+ grub_uint32_t usblegsup = 0; -+ grub_uint64_t maxtime; -+ grub_uint32_t interf; -+ grub_uint32_t subclass; -+ grub_uint32_t class; -+ grub_uint8_t release; -+ grub_uint32_t class_code; -+ -+ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: begin\n"); -+ -+ if (pciid == GRUB_CS5536_PCIID) -+ { -+ grub_dprintf ("xhci", "CS5536 not supported\n"); -+ return 0; -+ } -+ else -+ { -+ grub_pci_address_t addr; -+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); -+ class_code = grub_pci_read (addr) >> 8; -+ interf = class_code & 0xFF; -+ subclass = (class_code >> 8) & 0xFF; -+ class = class_code >> 16; -+ -+ /* If this is not an XHCI controller, just return. */ -+ if (class != 0x0c || subclass != 0x03 || interf != 0x30) -+ return 0; -+ -+ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: class OK\n"); -+ -+ /* 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) -+ { -+ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: Wrong SBRN: %0x\n", -+ release); -+ return 0; -+ } -+ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: bus rev. num. OK\n"); -+ -+ /* Determine XHCI XHCC registers base address. */ -+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); -+ base = grub_pci_read (addr); -+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG1); -+ base_h = grub_pci_read (addr); -+ /* Stop if registers are mapped above 4G - GRUB does not currently -+ * work with registers mapped above 4G */ -+ if (((base & GRUB_PCI_ADDR_MEM_TYPE_MASK) != GRUB_PCI_ADDR_MEM_TYPE_32) -+ && (base_h != 0)) -+ { -+ grub_dprintf ("xhci", -+ "XHCI grub_xhci_pci_iter: registers above 4G are not supported\n"); -+ return 0; -+ } -+ base &= GRUB_PCI_ADDR_MEM_MASK; -+ if (!base) -+ { -+ grub_dprintf ("xhci", -+ "XHCI: XHCI is not mapped\n"); -+ return 0; -+ } -+ -+ /* Set bus master - needed for coreboot, VMware, broken BIOSes etc. */ -+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND); -+ grub_pci_write_word(addr, -+ GRUB_PCI_COMMAND_MEM_ENABLED -+ | GRUB_PCI_COMMAND_BUS_MASTER -+ | grub_pci_read_word(addr)); -+ -+ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: 32-bit XHCI OK\n"); -+ } -+ -+ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: iobase of XHCC: %08x\n", -+ (base & GRUB_XHCI_ADDR_MEM_MASK)); -+ -+ regs = grub_pci_device_map_range (dev, -+ (base & GRUB_XHCI_ADDR_MEM_MASK), -+ 0x100); -+ -+ /* Is there EECP ? */ -+ eecp_offset = (grub_le_to_cpu32 (regs[2]) >> 8) & 0xff; -+ -+ /* Determine and change ownership. */ -+ /* EECP offset valid in HCCPARAMS */ -+ /* Ownership can be changed via EECP only */ -+ if (pciid != GRUB_CS5536_PCIID && eecp_offset >= 0x40) -+ { -+ grub_pci_address_t pciaddr_eecp; -+ pciaddr_eecp = grub_pci_make_address (dev, eecp_offset); -+ -+ usblegsup = grub_pci_read (pciaddr_eecp); -+ if (usblegsup & GRUB_XHCI_BIOS_OWNED) -+ { -+ grub_boot_time ("Taking ownership of XHCI controller"); -+ grub_dprintf ("xhci", -+ "XHCI grub_xhci_pci_iter: XHCI owned by: BIOS\n"); -+ /* Ownership change - set OS_OWNED bit */ -+ grub_pci_write (pciaddr_eecp, usblegsup | GRUB_XHCI_OS_OWNED); -+ /* Ensure PCI register is written */ -+ grub_pci_read (pciaddr_eecp); -+ -+ /* Wait for finish of ownership change, XHCI specification -+ * doesn't say how long it can take... */ -+ maxtime = grub_get_time_ms () + 1000; -+ while ((grub_pci_read (pciaddr_eecp) & GRUB_XHCI_BIOS_OWNED) -+ && (grub_get_time_ms () < maxtime)); -+ if (grub_pci_read (pciaddr_eecp) & GRUB_XHCI_BIOS_OWNED) -+ { -+ grub_dprintf ("xhci", -+ "XHCI grub_xhci_pci_iter: XHCI change ownership timeout"); -+ /* Change ownership in "hard way" - reset BIOS ownership */ -+ grub_pci_write (pciaddr_eecp, GRUB_XHCI_OS_OWNED); -+ /* Ensure PCI register is written */ -+ grub_pci_read (pciaddr_eecp); -+ } -+ } -+ else if (usblegsup & GRUB_XHCI_OS_OWNED) -+ /* XXX: What to do in this case - nothing ? Can it happen ? */ -+ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: XHCI owned by: OS\n"); -+ else -+ { -+ grub_dprintf ("xhci", -+ "XHCI grub_Xhci_pci_iter: XHCI owned by: NONE\n"); -+ /* XXX: What to do in this case ? Can it happen ? -+ * Is code below correct ? */ -+ /* Ownership change - set OS_OWNED bit */ -+ grub_pci_write (pciaddr_eecp, GRUB_XHCI_OS_OWNED); -+ /* Ensure PCI register is written */ -+ grub_pci_read (pciaddr_eecp); -+ } -+ -+ /* Disable SMI, just to be sure. */ -+ pciaddr_eecp = grub_pci_make_address (dev, eecp_offset + 4); -+ grub_pci_write (pciaddr_eecp, 0); -+ /* Ensure PCI register is written */ -+ grub_pci_read (pciaddr_eecp); -+ } -+ -+ grub_dprintf ("xhci", "inithw: XHCI grub_xhci_pci_iter: ownership OK\n"); -+ -+ grub_xhci_init_device (regs); -+ return 0; -+} -+ -+void -+grub_xhci_pci_scan (void) -+{ -+ grub_pci_iterate (grub_xhci_pci_iter, NULL); -+} -diff --git a/grub-core/bus/usb/xhci.c b/grub-core/bus/usb/xhci.c -new file mode 100644 -index 000000000..f4591ffb5 ---- /dev/null -+++ b/grub-core/bus/usb/xhci.c -@@ -0,0 +1,2496 @@ -+/* xhci.c - XHCI Support. */ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2020 9elements Cyber Security -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ * -+ * Big parts of this software are inspired by seabios XHCI implementation -+ * Released under LGPLv3. Credits to: -+ * -+ * Copyright (C) 2013 Gerd Hoffmann -+ * Copyright (C) 2014 Kevin O'Connor -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+GRUB_MOD_LICENSE ("GPLv3+"); -+ -+/* This simple GRUB implementation of XHCI driver */ -+/* Based on the specification -+ * "eXtensible Host Controller Interface for Universal Serial Bus" Revision 1.2 -+ */ -+ -+ -+#define xhci_get_field(data, field) \ -+ (((data) >> field##_SHIFT) & field##_MASK) -+#define XHCI_PORTSC_PLS_MASK 0xf -+#define XHCI_PORTSC_PLS_SHIFT 5 -+#define XHCI_PORTSC_SPEED_MASK 0xf -+#define XHCI_PORTSC_SPEED_SHIFT 10 -+ -+enum -+{ -+ XHCI_USB_FULLSPEED = 1, -+ XHCI_USB_LOWSPEED, -+ XHCI_USB_HIGHSPEED, -+ XHCI_USB_SUPERSPEED -+}; -+ -+/* Chapter 5.3 Host Controller Capability Registers */ -+struct grub_xhci_caps { -+ grub_uint8_t caplength; -+ grub_uint8_t reserved_01; -+ grub_uint16_t hciversion; -+ grub_uint32_t hcsparams1; -+ grub_uint32_t hcsparams2; -+ grub_uint32_t hcsparams3; -+ grub_uint32_t hccparams; -+ grub_uint32_t dboff; -+ grub_uint32_t rtsoff; -+ grub_uint32_t hccparams2; -+} GRUB_PACKED; -+ -+/* extended capabilities */ -+struct grub_xhci_xcap { -+ grub_uint32_t cap; -+ grub_uint32_t data[]; -+} GRUB_PACKED; -+ -+#define XHCI_CAP_LEGACY_SUPPORT 1 -+#define XHCI_CAP_SUPPORTED_PROTOCOL 2 -+ -+struct xhci_portmap { -+ grub_uint8_t start; -+ grub_uint8_t count; -+} GRUB_PACKED; -+ -+struct grub_xhci_op { -+ grub_uint32_t usbcmd; -+ grub_uint32_t usbsts; -+ grub_uint32_t pagesize; -+ grub_uint32_t reserved_01[2]; -+ grub_uint32_t dnctl; -+ grub_uint32_t crcr_low; -+ grub_uint32_t crcr_high; -+ grub_uint32_t reserved_02[4]; -+ grub_uint32_t dcbaap_low; -+ grub_uint32_t dcbaap_high; -+ grub_uint32_t config; -+} GRUB_PACKED; -+ -+enum -+{ -+ GRUB_XHCI_CMD_RS = (1<<0), -+ GRUB_XHCI_CMD_HCRST = (1<<1), -+ GRUB_XHCI_CMD_INTE = (1<<2), -+ GRUB_XHCI_CMD_HSEE = (1<<3), -+ GRUB_XHCI_CMD_LHCRST = (1<<7), -+ GRUB_XHCI_CMD_CSS = (1<<8), -+ GRUB_XHCI_CMD_CRS = (1<<9), -+ GRUB_XHCI_CMD_EWE = (1<<10), -+ GRUB_XHCI_CMD_EU3S = (1<<11) -+}; -+ -+enum -+{ -+ GRUB_XHCI_STS_HCH = (1<<0), -+ GRUB_XHCI_STS_HSE = (1<<2), -+ GRUB_XHCI_STS_EINT = (1<<3), -+ GRUB_XHCI_STS_PCD = (1<<4), -+ GRUB_XHCI_STS_SSS = (1<<8), -+ GRUB_XHCI_STS_RSS = (1<<9), -+ GRUB_XHCI_STS_SRE = (1<<10), -+ GRUB_XHCI_STS_CNR = (1<<11), -+ GRUB_XHCI_STS_HCE = (1<<12) -+}; -+ -+ -+/* Port Registers Offset */ -+#define GRUB_XHCI_PR_OFFSET 0x400 -+/* Interrupter Registers Offset */ -+#define GRUB_XHCI_IR_OFFSET 0x20 -+ -+/* Port Status and Control registers offsets */ -+ -+/* Chapter 6 Data Structures */ -+#define ALIGN_SPBA 64 -+#define ALIGN_DCBAA 64 -+#define ALIGN_CMD_RING_SEG 64 -+#define ALIGN_EVT_RING_SEG 64 -+#define ALIGN_EVT_RING_TABLE 64 -+#define ALIGN_TRB 16 -+#define ALIGN_INCTX 64 -+#define ALIGN_SLOTCTX 32 -+ -+#define BOUNDARY_RING 0x10000 -+ -+enum -+{ -+ GRUB_XHCI_PORTSC_CCS = (1<<0), -+ GRUB_XHCI_PORTSC_PED = (1<<1), -+ GRUB_XHCI_PORTSC_OCA = (1<<3), -+ GRUB_XHCI_PORTSC_PR = (1<<4), -+ GRUB_XHCI_PORTSC_PP = (1<<9), -+ GRUB_XHCI_PORTSC_SPEED_FULL = (1<<10), -+ GRUB_XHCI_PORTSC_SPEED_LOW = (2<<10), -+ GRUB_XHCI_PORTSC_SPEED_HIGH = (3<<10), -+ GRUB_XHCI_PORTSC_SPEED_SUPER = (4<<10), -+ GRUB_XHCI_PORTSC_LWS = (1<<16), -+ GRUB_XHCI_PORTSC_CSC = (1<<17), -+ GRUB_XHCI_PORTSC_PEC = (1<<18), -+ GRUB_XHCI_PORTSC_WRC = (1<<19), -+ GRUB_XHCI_PORTSC_OCC = (1<<20), -+ GRUB_XHCI_PORTSC_PRC = (1<<21), -+ GRUB_XHCI_PORTSC_PLC = (1<<22), -+ GRUB_XHCI_PORTSC_CEC = (1<<23), -+ GRUB_XHCI_PORTSC_CAS = (1<<24), -+ GRUB_XHCI_PORTSC_WCE = (1<<25), -+ GRUB_XHCI_PORTSC_WDE = (1<<26), -+ GRUB_XHCI_PORTSC_WOE = (1<<27), -+ GRUB_XHCI_PORTSC_DR = (1<<30), -+ GRUB_XHCI_PORTSC_WPR = (1<<31) -+}; -+ -+/* XHCI memory data structs */ -+#define GRUB_XHCI_MAX_ENDPOINTS 32 -+ -+#define GRUB_XHCI_RING_ITEMS 128 -+#define GRUB_XHCI_RING_SIZE (GRUB_XHCI_RING_ITEMS*sizeof(struct grub_xhci_trb)) -+/* -+ * xhci_ring structs are allocated with XHCI_RING_SIZE alignment, -+ * then we can get it from a trb pointer (provided by evt ring). -+ */ -+#define XHCI_RING(_trb) \ -+ ((struct grub_xhci_ring*)((grub_uint32_t)(_trb) & ~(GRUB_XHCI_RING_SIZE-1))) -+ -+/* slot context */ -+struct grub_xhci_slotctx { -+ grub_uint32_t ctx[4]; -+ grub_uint32_t reserved_01[4]; -+} GRUB_PACKED; -+ -+/* endpoint context */ -+struct grub_xhci_epctx { -+ grub_uint32_t ctx[2]; -+ grub_uint32_t deq_low; -+ grub_uint32_t deq_high; -+ grub_uint32_t length; -+ grub_uint32_t reserved_01[3]; -+} GRUB_PACKED; -+ -+/* device context array element */ -+struct grub_xhci_devlist { -+ grub_uint32_t ptr_low; -+ grub_uint32_t ptr_high; -+} GRUB_PACKED; -+ -+/* input context */ -+struct grub_xhci_inctx { -+ grub_uint32_t del; -+ grub_uint32_t add; -+ grub_uint32_t reserved_01[6]; -+} GRUB_PACKED; -+ -+/* transfer block (ring element) */ -+struct grub_xhci_trb { -+ grub_uint32_t ptr_low; -+ grub_uint32_t ptr_high; -+ grub_uint32_t status; -+ grub_uint32_t control; -+} GRUB_PACKED; -+ -+#define TRB_C (1<<0) -+#define TRB_TYPE_SHIFT 10 -+#define TRB_TYPE_MASK 0x3f -+#define TRB_TYPE(t) (((t) >> TRB_TYPE_SHIFT) & TRB_TYPE_MASK) -+ -+#define TRB_EV_ED (1<<2) -+ -+#define TRB_TR_ENT (1<<1) -+#define TRB_TR_ISP (1<<2) -+#define TRB_TR_NS (1<<3) -+#define TRB_TR_CH (1<<4) -+#define TRB_TR_IOC (1<<5) -+#define TRB_TR_IDT (1<<6) -+#define TRB_TR_TBC_SHIFT 7 -+#define TRB_TR_TBC_MASK 0x3 -+#define TRB_TR_BEI (1<<9) -+#define TRB_TR_TLBPC_SHIFT 16 -+#define TRB_TR_TLBPC_MASK 0xf -+#define TRB_TR_FRAMEID_SHIFT 20 -+#define TRB_TR_FRAMEID_MASK 0x7ff -+#define TRB_TR_SIA (1<<31) -+ -+#define TRB_TR_DIR (1<<16) -+ -+#define TRB_CR_SLOTID_SHIFT 24 -+#define TRB_CR_SLOTID_MASK 0xff -+#define TRB_CR_EPID_SHIFT 16 -+#define TRB_CR_EPID_MASK 0x1f -+ -+#define TRB_CR_BSR (1<<9) -+#define TRB_CR_DC (1<<9) -+ -+#define TRB_LK_TC (1<<1) -+ -+#define TRB_INTR_SHIFT 22 -+#define TRB_INTR_MASK 0x3ff -+#define TRB_INTR(t) (((t).status >> TRB_INTR_SHIFT) & TRB_INTR_MASK) -+ -+typedef enum TRBType { -+ TRB_RESERVED = 0, -+ TR_NORMAL, -+ TR_SETUP, -+ TR_DATA, -+ TR_STATUS, -+ TR_ISOCH, -+ TR_LINK, -+ TR_EVDATA, -+ TR_NOOP, -+ CR_ENABLE_SLOT, -+ CR_DISABLE_SLOT, -+ CR_ADDRESS_DEVICE, -+ CR_CONFIGURE_ENDPOINT, -+ CR_EVALUATE_CONTEXT, -+ CR_RESET_ENDPOINT, -+ CR_STOP_ENDPOINT, -+ CR_SET_TR_DEQUEUE, -+ CR_RESET_DEVICE, -+ CR_FORCE_EVENT, -+ CR_NEGOTIATE_BW, -+ CR_SET_LATENCY_TOLERANCE, -+ CR_GET_PORT_BANDWIDTH, -+ CR_FORCE_HEADER, -+ CR_NOOP, -+ ER_TRANSFER = 32, -+ ER_COMMAND_COMPLETE, -+ ER_PORT_STATUS_CHANGE, -+ ER_BANDWIDTH_REQUEST, -+ ER_DOORBELL, -+ ER_HOST_CONTROLLER, -+ ER_DEVICE_NOTIFICATION, -+ ER_MFINDEX_WRAP, -+} TRBType; -+ -+typedef enum TRBCCode { -+ CC_INVALID = 0, -+ CC_SUCCESS, -+ CC_DATA_BUFFER_ERROR, -+ CC_BABBLE_DETECTED, -+ CC_USB_TRANSACTION_ERROR, -+ CC_TRB_ERROR, -+ CC_STALL_ERROR, -+ CC_RESOURCE_ERROR, -+ CC_BANDWIDTH_ERROR, -+ CC_NO_SLOTS_ERROR, -+ CC_INVALID_STREAM_TYPE_ERROR, -+ CC_SLOT_NOT_ENABLED_ERROR, -+ CC_EP_NOT_ENABLED_ERROR, -+ CC_SHORT_PACKET, -+ CC_RING_UNDERRUN, -+ CC_RING_OVERRUN, -+ CC_VF_ER_FULL, -+ CC_PARAMETER_ERROR, -+ CC_BANDWIDTH_OVERRUN, -+ CC_CONTEXT_STATE_ERROR, -+ CC_NO_PING_RESPONSE_ERROR, -+ CC_EVENT_RING_FULL_ERROR, -+ CC_INCOMPATIBLE_DEVICE_ERROR, -+ CC_MISSED_SERVICE_ERROR, -+ CC_COMMAND_RING_STOPPED, -+ CC_COMMAND_ABORTED, -+ CC_STOPPED, -+ CC_STOPPED_LENGTH_INVALID, -+ CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR = 29, -+ CC_ISOCH_BUFFER_OVERRUN = 31, -+ CC_EVENT_LOST_ERROR, -+ CC_UNDEFINED_ERROR, -+ CC_INVALID_STREAM_ID_ERROR, -+ CC_SECONDARY_BANDWIDTH_ERROR, -+ CC_SPLIT_TRANSACTION_ERROR -+} TRBCCode; -+ -+enum { -+ PLS_U0 = 0, -+ PLS_U1 = 1, -+ PLS_U2 = 2, -+ PLS_U3 = 3, -+ PLS_DISABLED = 4, -+ PLS_RX_DETECT = 5, -+ PLS_INACTIVE = 6, -+ PLS_POLLING = 7, -+ PLS_RECOVERY = 8, -+ PLS_HOT_RESET = 9, -+ PLS_COMPILANCE_MODE = 10, -+ PLS_TEST_MODE = 11, -+ PLS_RESUME = 15, -+}; -+ -+/* event ring segment */ -+struct grub_xhci_er_seg { -+ grub_uint32_t ptr_low; -+ grub_uint32_t ptr_high; -+ grub_uint32_t size; -+ grub_uint32_t reserved_01; -+} GRUB_PACKED; -+ -+struct grub_xhci_ring { -+ struct grub_xhci_trb ring[GRUB_XHCI_RING_ITEMS]; -+ struct grub_xhci_trb evt; -+ grub_uint32_t eidx; -+ grub_uint32_t nidx; -+ grub_uint32_t cs; -+}; -+ -+/* port registers */ -+struct grub_xhci_pr { -+ grub_uint32_t portsc; -+ grub_uint32_t portpmsc; -+ grub_uint32_t portli; -+ grub_uint32_t reserved_01; -+} GRUB_PACKED; -+ -+/* doorbell registers */ -+struct grub_xhci_db { -+ grub_uint32_t doorbell; -+} GRUB_PACKED; -+ -+/* runtime registers */ -+struct grub_xhci_rts { -+ grub_uint32_t mfindex; -+} GRUB_PACKED; -+ -+/* interrupter registers */ -+struct grub_xhci_ir { -+ grub_uint32_t iman; -+ grub_uint32_t imod; -+ grub_uint32_t erstsz; -+ grub_uint32_t reserved_01; -+ grub_uint32_t erstba_low; -+ grub_uint32_t erstba_high; -+ grub_uint32_t erdp_low; -+ grub_uint32_t erdp_high; -+} GRUB_PACKED; -+ -+struct grub_xhci_psid { -+ grub_uint8_t id; -+ grub_uint8_t psie; -+ grub_uint16_t psim; -+ grub_uint64_t bitrate; -+ grub_usb_speed_t grub_usb_speed; -+}; -+ -+struct grub_xhci_psids { -+ grub_uint8_t major; -+ grub_uint8_t minor; -+ struct grub_xhci_psid psids[16]; -+}; -+ -+struct grub_xhci -+{ -+ grub_uint8_t shutdown; /* 1 if preparing shutdown of controller */ -+ /* xhci registers */ -+ volatile struct grub_xhci_caps *caps; /* Capability registers */ -+ volatile struct grub_xhci_op *op; /* Operational registers */ -+ volatile struct grub_xhci_pr *pr; /* Port Registers */ -+ volatile struct grub_xhci_db *db; /* doorbell */ -+ volatile struct grub_xhci_ir *ir; /* Interrupt Registers */ -+ /* devinfo */ -+ grub_uint32_t xcap; -+ grub_uint32_t ports; -+ grub_uint32_t slots; -+ grub_uint8_t flag64; -+ grub_uint16_t spb; -+ grub_uint32_t pagesize; -+ struct xhci_portmap usb2; -+ struct xhci_portmap usb3; -+ struct grub_xhci_psids *psids; -+ /* xhci data structures */ -+ struct grub_pci_dma_chunk *devs_dma; -+ volatile struct grub_xhci_devlist *devs; -+ struct grub_pci_dma_chunk *cmds_dma; -+ volatile struct grub_xhci_ring *cmds; -+ struct grub_pci_dma_chunk *evts_dma; -+ volatile struct grub_xhci_ring *evts; -+ struct grub_pci_dma_chunk *eseg_dma; -+ volatile struct grub_xhci_er_seg *eseg; -+ struct grub_pci_dma_chunk *spba_dma; -+ struct grub_pci_dma_chunk *spad_dma; -+ -+ struct grub_xhci *next; -+}; -+ -+struct grub_xhci_priv { -+ grub_uint8_t slotid; -+ grub_uint32_t max_packet; -+ struct grub_pci_dma_chunk *enpoint_trbs_dma[32]; -+ volatile struct grub_xhci_ring *enpoint_trbs[32]; -+ struct grub_pci_dma_chunk *slotctx_dma; -+}; -+ -+struct grub_xhci_port { -+ grub_uint32_t portsc; -+ grub_uint32_t portpmsc; -+ grub_uint32_t portli; -+ grub_uint32_t reserved_01; -+}; -+ -+struct grub_xhci_transfer_controller_data { -+ grub_uint32_t transfer_size; -+}; -+ -+static struct grub_xhci *xhci; -+ -+/**************************************************************** -+ * general access functions -+ ****************************************************************/ -+ -+static inline void -+grub_xhci_write32(volatile void *addr, grub_uint32_t val) { -+ *(volatile grub_uint32_t *)addr = val; -+} -+static inline void -+grub_xhci_write16(volatile void *addr, grub_uint16_t val) { -+ *(volatile grub_uint16_t *)addr = val; -+} -+static inline void -+grub_xhci_write8(void *addr, grub_uint8_t val) { -+ *(volatile grub_uint8_t *)addr = val; -+} -+ -+static inline grub_uint32_t -+grub_xhci_read32(volatile void *addr) { -+ return grub_le_to_cpu32 (*((volatile grub_uint32_t *)addr)); -+} -+ -+static inline grub_uint16_t -+grub_xhci_read16(volatile void *addr) { -+ return grub_le_to_cpu16 (*((volatile grub_uint32_t *)addr)); -+} -+static inline grub_uint8_t -+grub_xhci_read8(volatile void *addr) { -+ return (*((volatile grub_uint32_t *)addr)); -+} -+ -+static inline grub_uint32_t -+grub_xhci_port_read (struct grub_xhci *x, grub_uint32_t port) -+{ -+ return grub_xhci_read32(&x->pr[port].portsc); -+} -+ -+static inline void -+grub_xhci_port_write (struct grub_xhci *x, grub_uint32_t port, -+ grub_uint32_t and_mask, grub_uint32_t or_mask) -+{ -+ grub_uint32_t reg = grub_xhci_port_read(x, port); -+ reg &= and_mask; -+ reg |= or_mask; -+ -+ grub_xhci_write32(&x->pr[port].portsc, reg); -+} -+ -+/**************************************************************** -+ * xhci status and support functions -+ ****************************************************************/ -+ -+static grub_uint32_t xhci_get_pagesize(struct grub_xhci *x) -+{ -+ /* Chapter 5.4.3 Page Size Register (PAGESIZE) */ -+ for (grub_uint8_t i = 0; i < 16; i++) -+ { -+ if (grub_xhci_read32(&x->op->pagesize) & (1 << i)) -+ return 1 << (12 + i); -+ } -+ return 0; -+} -+ -+static grub_uint8_t xhci_is_halted(struct grub_xhci *x) -+{ -+ return !!(grub_xhci_read32(&x->op->usbsts) & 1); -+} -+ -+/* Just for debugging */ -+static void xhci_check_status(struct grub_xhci *x) -+{ -+ grub_uint32_t reg; -+ -+ reg = grub_xhci_read32(&x->op->usbsts); -+ if (reg & 1) -+ grub_dprintf("xhci", "%s: xHCI halted\n", __func__); -+ if (reg & 2) -+ grub_dprintf("xhci", "%s: Host system error detected\n", __func__); -+ if (reg & (1 << 12)) -+ grub_dprintf("xhci", "%s: Internal error detected\n", __func__); -+ reg = grub_xhci_read32(&x->op->crcr_low); -+ if (reg & (1 << 3)) -+ grub_dprintf("xhci", "%s: Command ring running\n", __func__); -+} -+ -+/* xhci_memalign_dma32 allocates DMA memory satisfying alignment and boundary -+ * requirements without wasting to much memory */ -+static struct grub_pci_dma_chunk * -+xhci_memalign_dma32(grub_size_t align, -+ grub_size_t size, -+ grub_size_t boundary) -+{ -+ struct grub_pci_dma_chunk *tmp; -+ const grub_uint32_t mask = boundary - 1; -+ grub_uint32_t start, end; -+ -+ /* Allocate some memory and check if it doesn't cross boundary */ -+ tmp = grub_memalign_dma32(align, size); -+ start = grub_dma_get_phys(tmp); -+ end = start + size - 1; -+ if ((start & mask) == (end & mask)) -+ return tmp; -+ /* Buffer isn't usable, allocate bigger one */ -+ grub_dma_free(tmp); -+ -+ return grub_memalign_dma32(boundary, size); -+} -+ -+/**************************************************************** -+ * helper functions for in context DMA buffer -+ ****************************************************************/ -+ -+static int -+grub_xhci_inctx_size(struct grub_xhci *x) -+{ -+ const grub_uint8_t cnt = GRUB_XHCI_MAX_ENDPOINTS + 1; -+ return (sizeof(struct grub_xhci_inctx) * cnt) << x->flag64; -+} -+ -+static void -+grub_xhci_inctx_sync_dma_caches(struct grub_xhci *x, struct grub_pci_dma_chunk *inctx) -+{ -+ grub_arch_sync_dma_caches(inctx, grub_xhci_inctx_size(x)); -+} -+ -+static struct grub_pci_dma_chunk * -+grub_xhci_alloc_inctx(struct grub_xhci *x, int maxepid, -+ struct grub_usb_device *dev) -+{ -+ int size = grub_xhci_inctx_size(x); -+ struct grub_pci_dma_chunk *dma = xhci_memalign_dma32(ALIGN_INCTX, size, -+ x->pagesize); -+ if (!dma) -+ return NULL; -+ -+ volatile struct grub_xhci_inctx *in = grub_dma_get_virt(dma); -+ grub_memset((void *)in, 0, size); -+ -+ struct grub_xhci_slotctx *slot = (void*)&in[1 << x->flag64]; -+ slot->ctx[0] |= maxepid << 27; /* context entries */ -+ grub_dprintf("xhci", "%s: speed=%d root_port=%d\n", __func__, dev->speed, dev->root_port); -+ switch (dev->speed) { -+ case GRUB_USB_SPEED_FULL: -+ slot->ctx[0] |= XHCI_USB_FULLSPEED << 20; -+ break; -+ case GRUB_USB_SPEED_HIGH: -+ slot->ctx[0] |= XHCI_USB_HIGHSPEED << 20; -+ break; -+ case GRUB_USB_SPEED_LOW: -+ slot->ctx[0] |= XHCI_USB_LOWSPEED << 20; -+ break; -+ case GRUB_USB_SPEED_SUPER: -+ slot->ctx[0] |= XHCI_USB_SUPERSPEED << 20; -+ break; -+ case GRUB_USB_SPEED_NONE: -+ slot->ctx[0] |= 0 << 20; -+ 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 */ -+ } -+ slot->ctx[0] |= dev->route; -+ slot->ctx[1] |= (dev->root_port+1) << 16; -+ -+ grub_arch_sync_dma_caches(in, size); -+ -+ return dma; -+} -+ -+/**************************************************************** -+ * xHCI event processing -+ ****************************************************************/ -+ -+/* Dequeue events on the XHCI event ring generated by the hardware */ -+static void xhci_process_events(struct grub_xhci *x) -+{ -+ volatile struct grub_xhci_ring *evts = x->evts; -+ /* XXX invalidate caches */ -+ -+ for (;;) { -+ /* check for event */ -+ grub_uint32_t nidx = grub_xhci_read32(&evts->nidx); -+ grub_uint32_t cs = grub_xhci_read32(&evts->cs); -+ volatile struct grub_xhci_trb *etrb = evts->ring + nidx; -+ grub_uint32_t control = grub_xhci_read32(&etrb->control); -+ if ((control & TRB_C) != (cs ? 1 : 0)) -+ return; -+ -+ /* process event */ -+ grub_uint32_t evt_type = TRB_TYPE(control); -+ grub_uint32_t evt_cc = (grub_xhci_read32(&etrb->status) >> 24) & 0xff; -+ -+ switch (evt_type) -+ { -+ case ER_TRANSFER: -+ case ER_COMMAND_COMPLETE: -+ { -+ struct grub_xhci_trb *rtrb = (void*)grub_xhci_read32(&etrb->ptr_low); -+ struct grub_xhci_ring *ring = XHCI_RING(rtrb); -+ volatile struct grub_xhci_trb *evt = &ring->evt; -+ grub_uint32_t eidx = rtrb - ring->ring + 1; -+ grub_dprintf("xhci", "%s: ring %p [trb %p, evt %p, type %d, eidx %d, cc %d]\n", -+ __func__, ring, rtrb, evt, evt_type, eidx, evt_cc); -+ *evt = *etrb; -+ grub_xhci_write32(&ring->eidx, eidx); -+ break; -+ } -+ case ER_PORT_STATUS_CHANGE: -+ { -+ /* Nothing to do here. grub_xhci_detect_dev will handle it */ -+ break; -+ } -+ default: -+ { -+ grub_dprintf("xhci", "%s: unknown event, type %d, cc %d\n", -+ __func__, evt_type, evt_cc); -+ break; -+ } -+ } -+ -+ /* move ring index, notify xhci */ -+ nidx++; -+ if (nidx == GRUB_XHCI_RING_ITEMS) -+ { -+ nidx = 0; -+ cs = cs ? 0 : 1; -+ grub_xhci_write32(&evts->cs, cs); -+ } -+ grub_xhci_write32(&evts->nidx, nidx); -+ volatile struct grub_xhci_ir *ir = x->ir; -+ grub_uint32_t erdp = (grub_uint32_t)(evts->ring + nidx); -+ grub_xhci_write32(&ir->erdp_low, erdp); -+ grub_xhci_write32(&ir->erdp_high, 0); -+ } -+} -+ -+/**************************************************************** -+ * TRB handling -+ ****************************************************************/ -+ -+/* Signal the hardware to process events on a TRB ring */ -+static void xhci_doorbell(struct grub_xhci *x, grub_uint32_t slotid, grub_uint32_t value) -+{ -+ xhci_check_status(x); -+ grub_dprintf("xhci", "%s: slotid %d, epid %d\n", __func__, slotid, value); -+ grub_xhci_write32(&x->db[slotid].doorbell, value); -+} -+ -+/* Check if a ring has any pending TRBs */ -+static int xhci_ring_busy(volatile struct grub_xhci_ring *ring) -+{ -+ grub_uint32_t eidx = grub_xhci_read32(&ring->eidx); -+ grub_uint32_t nidx = grub_xhci_read32(&ring->nidx); -+ -+ return (eidx != nidx); -+} -+ -+/* Returns free space in ring */ -+static int xhci_ring_free_space(volatile struct grub_xhci_ring *ring) -+{ -+ grub_uint32_t eidx = grub_xhci_read32(&ring->eidx); -+ grub_uint32_t nidx = grub_xhci_read32(&ring->nidx); -+ -+ /* nidx is never 0, so reduce ring buffer size by one */ -+ return (eidx > nidx) ? eidx-nidx -+ : (ARRAY_SIZE(ring->ring) - 1) - nidx + eidx; -+} -+ -+/* Check if a ring is full */ -+static int xhci_ring_full(volatile struct grub_xhci_ring *ring) -+{ -+ /* Might need to insert one link TRB */ -+ return xhci_ring_free_space(ring) <= 1; -+} -+ -+/* Check if a ring is almost full */ -+static int xhci_ring_almost_full(volatile struct grub_xhci_ring *ring) -+{ -+ /* Might need to insert one link TRB */ -+ return xhci_ring_free_space(ring) <= 2; -+} -+ -+/* Wait for a ring to empty (all TRBs processed by hardware) */ -+static int xhci_event_wait(struct grub_xhci *x, -+ volatile struct grub_xhci_ring *ring, -+ grub_uint32_t timeout) -+{ -+ grub_uint32_t end = grub_get_time_ms () + timeout; -+ -+ for (;;) -+ { -+ xhci_check_status(x); -+ xhci_process_events(x); -+ if (!xhci_ring_busy(ring)) -+ { -+ grub_uint32_t status = ring->evt.status; -+ return (status >> 24) & 0xff; -+ } -+ if (grub_get_time_ms () > end) -+ { -+ xhci_check_status(x); -+ grub_dprintf("xhci", "%s: Timeout waiting for event\n", __func__); -+ return -1; -+ } -+ } -+} -+ -+/* Add a TRB to the given ring, either regular or inline */ -+static void xhci_trb_fill(volatile struct grub_xhci_ring *ring, -+ grub_uint64_t ptr, grub_uint32_t xferlen, -+ grub_uint32_t flags) -+{ -+ volatile struct grub_xhci_trb *dst = &ring->ring[ring->nidx]; -+ dst->ptr_low = ptr & 0xffffffff; -+ dst->ptr_high = ptr >> 32; -+ dst->status = xferlen; -+ dst->control = flags | (ring->cs ? TRB_C : 0); -+ -+ grub_arch_sync_dma_caches(dst, sizeof(ring->ring[0])); -+} -+ -+/* -+ * Queue a TRB onto a ring. -+ * -+ * The caller must pass a pointer to the data in physical address-space or the -+ * data itself (but no more than 8 bytes) in data_or_addr. Inline data must have -+ * the flag TRB_TR_IDT set. -+ */ -+static void xhci_trb_queue(volatile struct grub_xhci_ring *ring, -+ grub_uint64_t data_or_addr, -+ 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__, -+ ring, data_or_addr, xferlen & 0x1ffff, flags, xferlen >> 17); -+ -+ if (xhci_ring_full(ring)) -+ { -+ grub_dprintf("xhci", "%s: ERROR: ring %p is full, discarding TRB\n", -+ __func__, ring); -+ return; -+ } -+ -+ if (ring->nidx >= ARRAY_SIZE(ring->ring) - 1) -+ { -+ /* Reset to command buffer pointer to the first element */ -+ xhci_trb_fill(ring, (grub_addr_t)ring->ring, 0, (TR_LINK << 10) | TRB_LK_TC); -+ ring->nidx = 0; -+ ring->cs ^= 1; -+ grub_dprintf("xhci", "%s: ring %p [linked]\n", __func__, ring); -+ } -+ -+ xhci_trb_fill(ring, data_or_addr, xferlen, flags); -+ ring->nidx++; -+ grub_dprintf("xhci", "%s: ring %p [nidx %d, len %d]\n", -+ __func__, ring, ring->nidx, xferlen); -+} -+ -+/* -+ * Queue a TRB onto a ring and flush it if necessary. -+ * -+ * The caller must pass a pointer to the data in physical address-space or the -+ * data itself (but no more than 8 bytes) in data_or_addr. Inline data must have -+ * the flag TRB_TR_IDT set. -+ */ -+static int xhci_trb_queue_and_flush(struct grub_xhci *x, -+ grub_uint32_t slotid, -+ grub_uint32_t epid, -+ volatile struct grub_xhci_ring *ring, -+ grub_uint64_t data_or_addr, -+ grub_uint32_t xferlen, grub_uint32_t flags) -+{ -+ grub_uint8_t submit = 0; -+ if (xhci_ring_almost_full(ring)) -+ { -+ grub_dprintf("xhci", "%s: almost full e %d n %d\n", __func__, ring->eidx, ring->nidx); -+ flags |= TRB_TR_IOC; -+ submit = 1; -+ } -+ /* Note: xhci_trb_queue might queue on or two elements, if the end of the TRB -+ * has been reached. The caller must account for that when filling the TRB. */ -+ xhci_trb_queue(ring, data_or_addr, xferlen, flags); -+ /* Submit if less no free slot is remaining, we might need an additional -+ * one on the next call to this function. */ -+ if (submit) -+ { -+ xhci_doorbell(x, slotid, epid); -+ int rc = xhci_event_wait(x, ring, 1000); -+ grub_dprintf("xhci", "%s: xhci_event_wait = %d\n", __func__, rc); -+ return rc; -+ } -+ return 0; -+} -+ -+/**************************************************************** -+ * xHCI command functions -+ ****************************************************************/ -+ -+/* Submit a command to the xHCI command TRB */ -+static int xhci_cmd_submit(struct grub_xhci *x, -+ struct grub_pci_dma_chunk *inctx_dma, -+ grub_uint32_t flags) -+{ -+ volatile struct grub_xhci_inctx *inctx; -+ /* Don't submit if halted, it will fail */ -+ if (xhci_is_halted(x)) -+ return -1; -+ -+ if (inctx_dma) -+ { -+ grub_xhci_inctx_sync_dma_caches(x, inctx_dma); -+ -+ inctx = grub_dma_get_virt(inctx_dma); -+ -+ struct grub_xhci_slotctx *slot = (void*)&inctx[1 << x->flag64]; -+ grub_uint32_t port = ((slot->ctx[1] >> 16) & 0xff) - 1; -+ grub_uint32_t portsc = grub_xhci_port_read(x, port); -+ if (!(portsc & GRUB_XHCI_PORTSC_CCS)) -+ { -+ grub_dprintf("xhci", "%s: root port %d no longer connected\n", -+ __func__, port); -+ return -1; -+ } -+ xhci_trb_queue(x->cmds, grub_dma_get_phys(inctx_dma), 0, flags); -+ } -+ else -+ { -+ xhci_trb_queue(x->cmds, 0, 0, flags); -+ } -+ -+ xhci_doorbell(x, 0, 0); -+ int rc = xhci_event_wait(x, x->cmds, 1000); -+ grub_dprintf("xhci", "%s: xhci_event_wait = %d\n", __func__, rc); -+ -+ return rc; -+} -+ -+static int xhci_cmd_enable_slot(struct grub_xhci *x) -+{ -+ grub_uint32_t flags = 0; -+ flags |= (CR_ENABLE_SLOT << 10); -+ -+ grub_dprintf("xhci", "%s:\n", __func__); -+ int cc = xhci_cmd_submit(x, NULL, flags); -+ if (cc != CC_SUCCESS) -+ return -1; -+ grub_dprintf("xhci", "%s: %p\n", __func__, &x->cmds->evt.control); -+ grub_dprintf("xhci", "%s: %x\n", __func__, grub_xhci_read32(&x->cmds->evt.control)); -+ -+ return (grub_xhci_read32(&x->cmds->evt.control) >> 24) & 0xff; -+} -+ -+static int xhci_cmd_disable_slot(struct grub_xhci *x, grub_uint32_t slotid) -+{ -+ grub_uint32_t flags = 0; -+ flags |= (CR_DISABLE_SLOT << 10); -+ flags |= (slotid << 24); -+ -+ grub_dprintf("xhci", "%s: slotid %d\n", __func__, slotid); -+ return xhci_cmd_submit(x, NULL, flags); -+} -+ -+static int xhci_cmd_stop_endpoint(struct grub_xhci *x, grub_uint32_t slotid -+ , grub_uint32_t epid -+ , grub_uint32_t suspend) -+{ -+ grub_uint32_t flags = 0; -+ flags |= (CR_STOP_ENDPOINT << 10); -+ flags |= (epid << 16); -+ flags |= (suspend << 23) ; -+ flags |= (slotid << 24); -+ -+ return xhci_cmd_submit(x, NULL, flags); -+} -+ -+static int xhci_cmd_reset_endpoint(struct grub_xhci *x, grub_uint32_t slotid -+ , grub_uint32_t epid -+ , grub_uint32_t preserve) -+{ -+ grub_uint32_t flags = 0; -+ flags |= (preserve << 9); -+ flags |= (CR_RESET_ENDPOINT << 10); -+ flags |= (epid << 16); -+ flags |= (slotid << 24); -+ -+ return xhci_cmd_submit(x, NULL, flags); -+} -+ -+static int xhci_cmd_set_dequeue_pointer(struct grub_xhci *x, grub_uint32_t slotid -+ , grub_uint32_t epid -+ , grub_addr_t tr_deque_pointer) -+{ -+ grub_uint32_t flags = 0; -+ flags |= (CR_SET_TR_DEQUEUE << 10); -+ flags |= (epid << 16); -+ flags |= (slotid << 24); -+ -+ xhci_trb_queue(x->cmds, tr_deque_pointer, 0, flags); -+ -+ xhci_doorbell(x, 0, 0); -+ int rc = xhci_event_wait(x, x->cmds, 1000); -+ grub_dprintf("xhci", "%s: xhci_event_wait = %d\n", __func__, rc); -+ -+ return rc; -+} -+ -+static int xhci_cmd_address_device(struct grub_xhci *x, grub_uint32_t slotid, -+ struct grub_pci_dma_chunk *inctx_dma) -+{ -+ grub_uint32_t flags = 0; -+ flags |= (CR_ADDRESS_DEVICE << 10); -+ flags |= (slotid << 24); -+ -+ grub_dprintf("xhci", "%s: slotid %d\n", __func__, slotid); -+ return xhci_cmd_submit(x, inctx_dma, flags); -+} -+ -+static int xhci_cmd_configure_endpoint(struct grub_xhci *x, grub_uint32_t slotid, -+ struct grub_pci_dma_chunk *inctx_dma) -+{ -+ grub_uint32_t flags = 0; -+ flags |= (CR_CONFIGURE_ENDPOINT << 10); -+ flags |= (slotid << 24); -+ -+ grub_dprintf("xhci", "%s: slotid %d\n", __func__, slotid); -+ return xhci_cmd_submit(x, inctx_dma, flags); -+} -+ -+static int xhci_cmd_evaluate_context(struct grub_xhci *x, grub_uint32_t slotid, -+ struct grub_pci_dma_chunk *inctx_dma) -+{ -+ grub_uint32_t flags = 0; -+ flags |= (CR_EVALUATE_CONTEXT << 10); -+ flags |= (slotid << 24); -+ -+ grub_dprintf("xhci", "%s: slotid %d\n", __func__, slotid); -+ return xhci_cmd_submit(x, inctx_dma, flags); -+} -+ -+/**************************************************************** -+ * xHCI host controller initialization -+ ****************************************************************/ -+ -+static grub_usb_err_t -+grub_xhci_reset (struct grub_xhci *x) -+{ -+ grub_uint32_t reg; -+ grub_uint32_t end; -+ -+ reg = grub_xhci_read32(&x->op->usbcmd); -+ if (reg & GRUB_XHCI_CMD_RS) -+ { -+ reg &= ~GRUB_XHCI_CMD_RS; -+ grub_xhci_write32(&x->op->usbcmd, reg); -+ -+ end = grub_get_time_ms () + 32; -+ while (grub_xhci_read32(&x->op->usbcmd) & GRUB_XHCI_STS_HCH) -+ { -+ if (grub_get_time_ms () > end) -+ return GRUB_USB_ERR_TIMEOUT; -+ -+ grub_millisleep(1); -+ } -+ } -+ -+ grub_dprintf("xhci", "grub_xhci_reset: resetting HC\n"); -+ grub_xhci_write32(&x->op->usbcmd, GRUB_XHCI_CMD_HCRST); -+ -+ /* Wait for device to complete reset and be enabled */ -+ end = grub_get_time_ms () + 100; -+ while (grub_xhci_read32(&x->op->usbcmd) & GRUB_XHCI_CMD_HCRST) -+ { -+ if (grub_get_time_ms () > end) -+ return GRUB_USB_ERR_TIMEOUT; -+ -+ grub_millisleep(1); -+ } -+ -+ /* Wait for device to complete reset and be enabled */ -+ end = grub_get_time_ms () + 100; -+ while (grub_xhci_read32(&x->op->usbsts) & GRUB_XHCI_STS_CNR) -+ { -+ if (grub_get_time_ms () > end) -+ return GRUB_USB_ERR_TIMEOUT; -+ -+ grub_millisleep(1); -+ } -+ -+ grub_xhci_write32(&x->op->config, x->slots); -+ grub_xhci_write32(&x->op->dcbaap_low, grub_dma_get_phys(x->devs_dma)); -+ grub_xhci_write32(&x->op->dcbaap_high, 0); -+ grub_xhci_write32(&x->op->crcr_low, grub_dma_get_phys(x->cmds_dma)| 1); -+ grub_xhci_write32(&x->op->crcr_high, 0); -+ x->cmds->cs = 1; -+ -+ grub_arch_sync_dma_caches(x->cmds, sizeof(*x->cmds)); -+ -+ x->eseg->ptr_low = grub_dma_get_phys(x->evts_dma); -+ x->eseg->ptr_high = 0; -+ x->eseg->size = GRUB_XHCI_RING_ITEMS; -+ -+ grub_arch_sync_dma_caches(x->eseg, sizeof(*x->eseg)); -+ -+ grub_xhci_write32(&x->ir->erstsz, 1); -+ grub_xhci_write32(&x->ir->erdp_low, grub_dma_get_phys(x->evts_dma)); -+ grub_xhci_write32(&x->ir->erdp_high, 0); -+ grub_xhci_write32(&x->ir->erstba_low, grub_dma_get_phys(x->eseg_dma)); -+ grub_xhci_write32(&x->ir->erstba_high, 0); -+ x->evts->cs = 1; -+ -+ grub_arch_sync_dma_caches(x->evts, sizeof(*x->eseg)); -+ -+ xhci_check_status(x); -+ -+ grub_dprintf ("xhci", "XHCI OP COMMAND: %08x\n", -+ grub_xhci_read32 (&x->op->usbcmd)); -+ grub_dprintf ("xhci", "XHCI OP STATUS: %08x\n", -+ grub_xhci_read32 (&x->op->usbsts)); -+ grub_dprintf ("xhci", "XHCI OP PAGESIZE: %08x\n", -+ grub_xhci_read32 (&x->op->pagesize)); -+ grub_dprintf ("xhci", "XHCI OP DNCTRL: %08x\n", -+ grub_xhci_read32 (&x->op->dnctl)); -+ grub_dprintf ("xhci", "XHCI OP CRCR_LOW: %08x\n", -+ grub_xhci_read32 (&x->op->crcr_low)); -+ grub_dprintf ("xhci", "XHCI OP CRCR_HIGH: %08x\n", -+ grub_xhci_read32 (&x->op->crcr_high)); -+ grub_dprintf ("xhci", "XHCI OP DCBAAP_LOW: %08x\n", -+ grub_xhci_read32 (&x->op->dcbaap_low)); -+ grub_dprintf ("xhci", "XHCI OP DCBAAP_HIGH: %08x\n", -+ grub_xhci_read32 (&x->op->dcbaap_high)); -+ grub_dprintf ("xhci", "XHCI OP CONFIG: %08x\n", -+ grub_xhci_read32 (&x->op->config)); -+ grub_dprintf ("xhci", "XHCI IR ERSTSZ: %08x\n", -+ grub_xhci_read32 (&x->ir->erstsz)); -+ grub_dprintf ("xhci", "XHCI IR ERDP: %08x\n", -+ grub_xhci_read32 (&x->ir->erdp_low)); -+ grub_dprintf ("xhci", "XHCI IR ERSTBA: %08x\n", -+ grub_xhci_read32 (&x->ir->erstba_low)); -+ -+ xhci_check_status(x); -+ -+ return GRUB_USB_ERR_NONE; -+} -+ -+static grub_usb_err_t -+grub_xhci_request_legacy_handoff(volatile struct grub_xhci_xcap *xcap) -+{ -+ grub_uint32_t end; -+ -+ end = grub_get_time_ms () + 10; -+ for (;;) -+ { -+ grub_uint32_t cap = grub_xhci_read32(&xcap->cap); -+ if (cap & (1 << 16)) -+ grub_xhci_write32(&xcap->cap, cap | (1 << 24)); -+ else -+ break; -+ -+ if (grub_get_time_ms () > end) -+ { -+ grub_dprintf ("xhci","ERROR: %s TIMEOUT\n", __func__); -+ return GRUB_USB_ERR_TIMEOUT; -+ } -+ grub_millisleep(1); -+ } -+ return GRUB_USB_ERR_NONE; -+} -+ -+static void -+grub_xhci_fill_default_speed_mapping(struct grub_xhci_psids *ids) -+{ -+ /* Chapter 7.2.2.1.1 "Default USB Speed ID Mapping" */ -+ ids->psids[0].id = 1; -+ ids->psids[0].psie = 2; -+ ids->psids[0].psim = 12; -+ ids->psids[1].id = 2; -+ ids->psids[1].psie = 1; -+ ids->psids[1].psim = 1500; -+ ids->psids[2].id = 3; -+ ids->psids[2].psie = 2; -+ ids->psids[2].psim = 480; -+ ids->psids[3].id = 4; -+ ids->psids[3].psie = 3; -+ ids->psids[3].psim = 5; -+ ids->psids[4].id = 5; -+ ids->psids[4].psie = 3; -+ ids->psids[4].psim = 10; -+ ids->psids[5].id = 6; -+ ids->psids[5].psie = 3; -+ ids->psids[5].psim = 10; -+ ids->psids[6].id = 7; -+ ids->psids[6].psie = 3; -+ ids->psids[6].psim = 20; -+} -+ -+static void -+grub_xhci_calc_speed_mapping(struct grub_xhci_psids *ids) -+{ -+ const grub_uint64_t mult[4] = {1ULL, 1000ULL, 1000000ULL, 1000000000ULL}; -+ -+ for (grub_uint8_t i = 0; i < 16; i++) -+ { -+ if (ids->psids[i].id == 0) -+ continue; -+ ids->psids[i].bitrate = mult[ids->psids[i].psie & 3] * (grub_uint64_t)ids->psids[i].psim; -+ if (ids->psids[i].bitrate < 12000000ULL) -+ ids->psids[i].grub_usb_speed = GRUB_USB_SPEED_LOW; -+ else if (ids->psids[i].bitrate < 480000000ULL) -+ ids->psids[i].grub_usb_speed = GRUB_USB_SPEED_FULL; -+ else if (ids->psids[i].bitrate > 1200000000ULL) -+ ids->psids[i].grub_usb_speed = GRUB_USB_SPEED_SUPER; -+ else -+ ids->psids[i].grub_usb_speed = GRUB_USB_SPEED_HIGH; -+ } -+} -+ -+ -+/* PCI iteration function... */ -+void -+grub_xhci_init_device (volatile void *regs) -+{ -+ struct grub_xhci *x; -+ grub_uint32_t hcs1, hcc, reg; -+ -+ /* Allocate memory for the controller and fill basic values. */ -+ x = grub_zalloc (sizeof (*x)); -+ if (!x) -+ { -+ grub_dprintf("xhci", "Failed to allocate memory\n"); -+ return; -+ } -+ x->caps = (volatile struct grub_xhci_caps *) regs; -+ x->op = (volatile struct grub_xhci_op *) (((grub_uint8_t *)regs) + -+ grub_xhci_read8(&x->caps->caplength)); -+ x->pr = (volatile struct grub_xhci_pr *) (((grub_uint8_t *)x->op) + -+ GRUB_XHCI_PR_OFFSET); -+ x->db = (volatile struct grub_xhci_db *) (((grub_uint8_t *)regs) + -+ grub_xhci_read32(&x->caps->dboff)); -+ x->ir = (volatile struct grub_xhci_ir *) (((grub_uint8_t *)regs) + -+ grub_xhci_read32(&x->caps->rtsoff) + GRUB_XHCI_IR_OFFSET); -+ -+ grub_dprintf ("xhci", "XHCI init: CAPLENGTH: 0x%02x\n", -+ grub_xhci_read8 (&x->caps->caplength)); -+ grub_dprintf ("xhci", "XHCI init: HCIVERSION: 0x%04x\n", -+ grub_xhci_read16 (&x->caps->hciversion)); -+ grub_dprintf ("xhci", "XHCI init: HCSPARAMS1: 0x%08x\n", -+ grub_xhci_read32 (&x->caps->hcsparams1)); -+ grub_dprintf ("xhci", "XHCI init: HCSPARAMS2: 0x%08x\n", -+ grub_xhci_read32 (&x->caps->hcsparams2)); -+ grub_dprintf ("xhci", "XHCI init: HCSPARAMS3: 0x%08x\n", -+ grub_xhci_read32 (&x->caps->hcsparams3)); -+ grub_dprintf ("xhci", "XHCI init: HCCPARAMS: 0x%08x\n", -+ grub_xhci_read32 (&x->caps->hcsparams3)); -+ grub_dprintf ("xhci", "XHCI init: DBOFF: 0x%08x\n", -+ grub_xhci_read32 (&x->caps->dboff)); -+ grub_dprintf ("xhci", "XHCI init: RTOFF: 0x%08x\n", -+ grub_xhci_read32 (&x->caps->rtsoff)); -+ -+ hcs1 = grub_xhci_read32(&x->caps->hcsparams1); -+ hcc = grub_xhci_read32(&x->caps->hccparams); -+ x->ports = (grub_uint32_t) ((hcs1 >> 24) & 0xff); -+ x->slots = (grub_uint32_t) (hcs1 & 0xff); -+ x->xcap = (grub_uint32_t) ((hcc >> 16) & 0xffff) * sizeof(grub_uint32_t); -+ x->flag64 = (grub_uint8_t) ((hcc & 0x04) ? 1 : 0); -+ grub_dprintf("xhci", "XHCI init: %d ports, %d slots, %d byte contexts\n" -+ , x->ports, x->slots, x->flag64 ? 64 : 32); -+ -+ x->psids = grub_zalloc (sizeof (struct grub_xhci_psids) * x->ports); -+ if (x->xcap) -+ { -+ grub_uint32_t off; -+ volatile grub_uint8_t *addr = (grub_uint8_t *) x->caps + x->xcap; -+ do -+ { -+ volatile struct grub_xhci_xcap *xcap = (void *)addr; -+ grub_uint32_t ports, name, cap = grub_xhci_read32(&xcap->cap); -+ switch (cap & 0xff) { -+ case XHCI_CAP_LEGACY_SUPPORT: -+ { -+ if (grub_xhci_request_legacy_handoff(xcap) != GRUB_USB_ERR_NONE) -+ { -+ grub_dprintf("xhci", "XHCI init: Failed to get xHCI ownership\n"); -+ goto fail; -+ } -+ break; -+ } -+ case XHCI_CAP_SUPPORTED_PROTOCOL: -+ { -+ name = grub_xhci_read32(&xcap->data[0]); -+ ports = grub_xhci_read32(&xcap->data[1]); -+ const grub_uint8_t major = (cap >> 24) & 0xff; -+ const grub_uint8_t minor = (cap >> 16) & 0xff; -+ const grub_uint8_t psic = (ports >> 28) & 0xf; -+ const grub_uint8_t count = (ports >> 8) & 0xff; -+ const grub_uint8_t start = (ports >> 0) & 0xff; -+ grub_dprintf("xhci", "XHCI init: protocol %c%c%c%c %x.%02x" -+ ", %d ports (offset %d), def %x, psic %d\n" -+ , (name >> 0) & 0xff -+ , (name >> 8) & 0xff -+ , (name >> 16) & 0xff -+ , (name >> 24) & 0xff -+ , major, minor -+ , count, start -+ , ports >> 16 -+ , psic); -+ if (name == 0x20425355 /* "USB " */) -+ { -+ if (major == 2) -+ { -+ x->usb2.start = start; -+ x->usb2.count = count; -+ } -+ else if (major == 3) -+ { -+ x->usb3.start = start; -+ x->usb3.count = count; -+ } -+ -+ for (grub_uint32_t p = start - 1; p < start + count - 1UL; p++) -+ { -+ x->psids[p].major = major; -+ x->psids[p].minor = minor; -+ grub_xhci_fill_default_speed_mapping(&x->psids[p]); -+ for (grub_uint8_t i = 0; i < psic; i++) -+ { -+ grub_uint32_t psid = grub_xhci_read32(&xcap->data[3 + i]); -+ x->psids[p].psids[i].id = (psid >> 0) & 0xf; -+ x->psids[p].psids[i].psie = (psid >> 4) & 0x3; -+ x->psids[p].psids[i].psim = (psid >> 16) & 0xfffff; -+ } -+ grub_xhci_calc_speed_mapping(&x->psids[p]); -+ } -+ } -+ -+ break; -+ } -+ default: -+ { -+ grub_dprintf("xhci", "XHCI extcap 0x%x @ %p\n", cap & 0xff, addr); -+ break; -+ } -+ } -+ off = (cap >> 8) & 0xff; -+ addr += off << 2; -+ } -+ while (off > 0); -+ } -+ -+ x->pagesize = xhci_get_pagesize(x); -+ grub_dprintf("xhci", "XHCI init: Minimum supported page size 0x%x\n", -+ x->pagesize); -+ -+ /* Chapter 6.1 Device Context Base Address Array */ -+ x->devs_dma = xhci_memalign_dma32(ALIGN_DCBAA, -+ sizeof(*x->devs) * (x->slots + 1), -+ x->pagesize); -+ if (!x->devs_dma) -+ goto fail; -+ x->devs = grub_dma_get_virt(x->devs_dma); -+ grub_memset((void *)x->devs, 0, sizeof(*x->devs) * (x->slots + 1)); -+ grub_arch_sync_dma_caches(x->devs, sizeof(*x->devs) * (x->slots + 1)); -+ grub_dprintf ("xhci", "XHCI init: device memory %p (%x)\n", -+ grub_dma_get_virt(x->devs_dma), -+ grub_dma_get_phys(x->devs_dma)); -+ -+ /* Chapter 6.5 Event Ring Segment Table */ -+ x->eseg_dma = xhci_memalign_dma32(ALIGN_EVT_RING_TABLE, sizeof(*x->eseg), 0); -+ if (!x->eseg_dma) -+ goto fail; -+ x->eseg = grub_dma_get_virt(x->eseg_dma); -+ grub_memset((void *)x->eseg, 0, sizeof(*x->eseg)); -+ grub_arch_sync_dma_caches(x->eseg, sizeof(*x->eseg)); -+ grub_dprintf ("xhci", "XHCI init: event ring table memory %p (%x)\n", -+ grub_dma_get_virt(x->eseg_dma), -+ grub_dma_get_phys(x->eseg_dma)); -+ -+ x->cmds_dma = xhci_memalign_dma32(ALIGN_CMD_RING_SEG, sizeof(*x->cmds), -+ BOUNDARY_RING); -+ if (!x->cmds_dma) -+ goto fail; -+ x->cmds = grub_dma_get_virt(x->cmds_dma); -+ grub_memset((void *)x->cmds, 0, sizeof(*x->cmds)); -+ grub_arch_sync_dma_caches(x->cmds, sizeof(*x->cmds)); -+ grub_dprintf ("xhci", "XHCI init: command ring memory %p (%x)\n", -+ grub_dma_get_virt(x->cmds_dma), -+ grub_dma_get_phys(x->cmds_dma)); -+ -+ x->evts_dma = xhci_memalign_dma32(ALIGN_EVT_RING_SEG, sizeof(*x->evts), -+ BOUNDARY_RING); -+ if (!x->evts_dma) -+ goto fail; -+ x->evts = grub_dma_get_virt(x->evts_dma); -+ grub_memset((void *)x->evts, 0, sizeof(*x->evts)); -+ grub_arch_sync_dma_caches(x->evts, sizeof(*x->evts)); -+ grub_dprintf ("xhci", "XHCI init: event ring memory %p (%x)\n", -+ grub_dma_get_virt(x->evts_dma), -+ grub_dma_get_phys(x->evts_dma)); -+ -+ /* Chapter 4.20 Scratchpad Buffers */ -+ reg = grub_xhci_read32(&x->caps->hcsparams2); -+ x->spb = (reg >> 21 & 0x1f) << 5 | reg >> 27; -+ if (x->spb) -+ { -+ volatile grub_uint64_t *spba; -+ grub_dprintf("xhci", "XHCI init: set up %d scratch pad buffers\n", -+ x->spb); -+ x->spba_dma = xhci_memalign_dma32(ALIGN_SPBA, sizeof(*spba) * x->spb, -+ x->pagesize); -+ if (!x->spba_dma) -+ goto fail; -+ -+ x->spad_dma = xhci_memalign_dma32(x->pagesize, x->pagesize * x->spb, -+ x->pagesize); -+ if (!x->spad_dma) -+ { -+ grub_dma_free(x->spba_dma); -+ goto fail; -+ } -+ -+ spba = grub_dma_get_virt(x->spba_dma); -+ for (grub_uint32_t i = 0; i < x->spb; i++) -+ spba[i] = (grub_addr_t)grub_dma_get_phys(x->spad_dma) + (i * x->pagesize); -+ grub_arch_sync_dma_caches(x->spba_dma, sizeof(*spba) * x->spb); -+ -+ x->devs[0].ptr_low = grub_dma_get_phys(x->spba_dma); -+ x->devs[0].ptr_high = 0; -+ grub_arch_sync_dma_caches(x->devs_dma, sizeof(x->devs[0])); -+ grub_dprintf ("xhci", "XHCI init: Allocated %d scratch buffers of size 0x%x\n", -+ x->spb, x->pagesize); -+ } -+ -+ grub_xhci_reset(x); -+ -+ /* Set the running bit */ -+ reg = grub_xhci_read32 (&x->op->usbcmd); -+ reg |= GRUB_XHCI_CMD_RS; -+ grub_xhci_write32 (&x->op->usbcmd, reg); -+ -+ -+ /* Link to xhci now that initialisation is successful. */ -+ x->next = xhci; -+ xhci = x; -+ -+ return; -+ -+fail: -+ grub_dprintf ("xhci", "XHCI grub_xhci_pci_iter: FAILED!\n"); -+ if (x) -+ { -+ if (x->devs_dma) -+ grub_dma_free (x->devs_dma); -+ if (x->eseg_dma) -+ grub_dma_free (x->eseg_dma); -+ if (x->cmds_dma) -+ grub_dma_free (x->cmds_dma); -+ if (x->evts_dma) -+ grub_dma_free (x->evts_dma); -+ if (x->spad_dma) -+ grub_dma_free (x->spad_dma); -+ if (x->spba_dma) -+ grub_dma_free (x->spba_dma); -+ } -+ grub_free (x); -+ -+ return; -+} -+ -+static int -+grub_xhci_iterate (grub_usb_controller_iterate_hook_t hook, void *hook_data) -+{ -+ struct grub_xhci *x; -+ struct grub_usb_controller dev; -+ -+ for (x = xhci; x; x = x->next) -+ { -+ dev.data = x; -+ if (hook (&dev, hook_data)) -+ return 1; -+ } -+ -+ return 0; -+} -+ -+/**************************************************************** -+ * xHCI maintainance functions -+ ****************************************************************/ -+ -+static grub_usb_err_t -+grub_xhci_update_hub_portcount (struct grub_xhci *x, -+ grub_usb_transfer_t transfer, -+ grub_uint32_t slotid) -+{ -+ struct grub_pci_dma_chunk *in_dma; -+ volatile struct grub_xhci_slotctx *hdslot; -+ grub_uint32_t epid = 0; -+ -+ if (!transfer || !transfer->dev || !transfer->dev->nports) -+ return GRUB_USB_ERR_NONE; -+ -+ hdslot = grub_dma_phys2virt(x->devs[slotid].ptr_low, x->devs_dma); -+ if ((hdslot->ctx[3] >> 27) == 3) -+ /* Already configured */ -+ return 0; -+ -+ grub_dprintf("xhci", "%s: updating hub config to %d ports\n", __func__, -+ transfer->dev->nports); -+ -+ xhci_check_status(x); -+ -+ /* Allocate input context and initialize endpoint info. */ -+ in_dma = grub_xhci_alloc_inctx(x, epid, transfer->dev); -+ if (!in_dma) -+ return GRUB_USB_ERR_INTERNAL; -+ volatile struct grub_xhci_inctx *in = grub_dma_get_virt(in_dma); -+ -+ in->add = (1 << epid); -+ -+ struct grub_xhci_epctx *ep = (void*)&in[(epid+1) << x->flag64]; -+ ep->ctx[0] |= 1 << 26; -+ ep->ctx[1] |= transfer->dev->nports << 24; -+ -+ int cc = xhci_cmd_configure_endpoint(x, slotid, in_dma); -+ grub_dma_free(in_dma); -+ -+ if (cc != CC_SUCCESS) -+ { -+ grub_dprintf("xhci", "%s: reconf ctl endpoint: failed (cc %d)\n", -+ __func__, cc); -+ return GRUB_USB_ERR_BADDEVICE; -+ } -+ -+ return GRUB_USB_ERR_NONE; -+} -+ -+static grub_usb_err_t -+grub_xhci_update_max_paket_size (struct grub_xhci *x, -+ grub_usb_transfer_t transfer, -+ grub_uint32_t slotid, -+ grub_uint32_t max_packet) -+{ -+ struct grub_pci_dma_chunk *in_dma; -+ grub_uint32_t epid = 1; -+ -+ if (!transfer || !transfer->dev || !max_packet) -+ return GRUB_USB_ERR_NONE; -+ -+ grub_dprintf("xhci", "%s: updating max packet size to 0x%x\n", __func__, -+ max_packet); -+ -+ xhci_check_status(x); -+ -+ /* Allocate input context and initialize endpoint info. */ -+ in_dma = grub_xhci_alloc_inctx(x, epid, transfer->dev); -+ if (!in_dma) -+ return GRUB_USB_ERR_INTERNAL; -+ volatile struct grub_xhci_inctx *in = grub_dma_get_virt(in_dma); -+ in->add = (1 << epid); -+ -+ struct grub_xhci_epctx *ep = (void*)&in[(epid+1) << x->flag64]; -+ ep->ctx[1] |= max_packet << 16; -+ -+ int cc = xhci_cmd_evaluate_context(x, slotid, in_dma); -+ grub_dma_free(in_dma); -+ -+ if (cc != CC_SUCCESS) -+ { -+ grub_dprintf("xhci", "%s: reconf ctl endpoint: failed (cc %d)\n", -+ __func__, cc); -+ return GRUB_USB_ERR_BADDEVICE; -+ } -+ -+ return GRUB_USB_ERR_NONE; -+} -+ -+/**************************************************************** -+ * xHCI endpoint enablement functions -+ ****************************************************************/ -+ -+static grub_usb_err_t -+grub_xhci_prepare_endpoint (struct grub_xhci *x, -+ struct grub_usb_device *dev, -+ grub_uint8_t endpoint, -+ grub_transfer_type_t dir, -+ grub_transaction_type_t type, -+ grub_uint32_t maxpaket, -+ struct grub_xhci_priv *priv) -+{ -+ grub_uint32_t epid; -+ struct grub_pci_dma_chunk *reqs_dma; -+ struct grub_pci_dma_chunk *in_dma; -+ volatile struct grub_xhci_ring *reqs; -+ volatile struct grub_xhci_slotctx *slotctx; -+ -+ if (!x || !priv) -+ return GRUB_USB_ERR_INTERNAL; -+ -+ xhci_check_status(x); -+ -+ if (endpoint == 0) -+ { -+ epid = 1; -+ } -+ else -+ { -+ epid = (endpoint & 0x0f) * 2; -+ epid += (dir == GRUB_USB_TRANSFER_TYPE_IN) ? 1 : 0; -+ } -+ grub_dprintf("xhci", "%s: epid %d\n", __func__, epid); -+ -+ /* Test if already prepared */ -+ if (priv->slotid > 0 && priv->enpoint_trbs[epid] != NULL) -+ return GRUB_USB_ERR_NONE; -+ -+ /* Allocate DMA buffer as endpoint cmd TRB */ -+ reqs_dma = xhci_memalign_dma32(ALIGN_TRB, sizeof(*reqs), -+ BOUNDARY_RING); -+ if (!reqs_dma) -+ return GRUB_USB_ERR_INTERNAL; -+ reqs = grub_dma_get_virt(reqs_dma); -+ grub_memset((void *)reqs, 0, sizeof(*reqs)); -+ reqs->cs = 1; -+ -+ grub_arch_sync_dma_caches(reqs, sizeof(*reqs)); -+ -+ /* Allocate input context and initialize endpoint info. */ -+ in_dma = grub_xhci_alloc_inctx(x, epid, dev); -+ if (!in_dma) -+ { -+ grub_dma_free(reqs_dma); -+ return GRUB_USB_ERR_INTERNAL; -+ } -+ volatile struct grub_xhci_inctx *in = grub_dma_get_virt(in_dma); -+ in->add = 0x01 | (1 << epid); -+ -+ struct grub_xhci_epctx *ep = (void*)&in[(epid+1) << x->flag64]; -+ switch (type) -+ { -+ case GRUB_USB_TRANSACTION_TYPE_CONTROL: -+ ep->ctx[1] |= 0 << 3; -+ break; -+ case GRUB_USB_TRANSACTION_TYPE_BULK: -+ ep->ctx[1] |= 2 << 3; -+ break; -+ } -+ if (dir == GRUB_USB_TRANSFER_TYPE_IN -+ || type== GRUB_USB_TRANSACTION_TYPE_CONTROL) -+ ep->ctx[1] |= 1 << 5; -+ ep->ctx[1] |= maxpaket << 16; -+ ep->deq_low = grub_dma_get_phys(reqs_dma); -+ ep->deq_low |= 1; /* dcs */ -+ ep->length = maxpaket; -+ -+ grub_dprintf("xhci", "%s: ring %p, epid %d, max %d\n", __func__, -+ reqs, epid, maxpaket); -+ if (epid == 1 || priv->slotid == 0) { -+ /* Enable slot. */ -+ int slotid = xhci_cmd_enable_slot(x); -+ if (slotid < 0) -+ { -+ grub_dprintf("xhci", "%s: enable slot: failed\n", __func__); -+ grub_dma_free(reqs_dma); -+ grub_dma_free(in_dma); -+ return GRUB_USB_ERR_BADDEVICE; -+ } -+ grub_dprintf("xhci", "%s: get slot %d assigned\n", __func__, slotid); -+ -+ grub_uint32_t size = (sizeof(struct grub_xhci_slotctx) * GRUB_XHCI_MAX_ENDPOINTS) << x->flag64; -+ -+ /* Allocate memory for the device specific slot context */ -+ priv->slotctx_dma = xhci_memalign_dma32(ALIGN_SLOTCTX, size, -+ x->pagesize); -+ if (!priv->slotctx_dma) -+ { -+ grub_dprintf("xhci", "%s: grub_memalign_dma32 failed\n", __func__); -+ grub_dma_free(reqs_dma); -+ grub_dma_free(in_dma); -+ return GRUB_USB_ERR_INTERNAL; -+ } -+ slotctx = grub_dma_get_virt(priv->slotctx_dma); -+ -+ grub_dprintf("xhci", "%s: enable slot: got slotid %d\n", __func__, slotid); -+ grub_memset((void *)slotctx, 0, size); -+ grub_arch_sync_dma_caches(slotctx, size); -+ -+ x->devs[slotid].ptr_low = grub_dma_get_phys(priv->slotctx_dma); -+ x->devs[slotid].ptr_high = 0; -+ grub_arch_sync_dma_caches(&x->devs[slotid], sizeof(x->devs[0])); -+ -+ /* Send set_address command. */ -+ int cc = xhci_cmd_address_device(x, slotid, in_dma); -+ if (cc != CC_SUCCESS) -+ { -+ grub_dprintf("xhci","%s: address device: failed (cc %d)\n", __func__, cc); -+ cc = xhci_cmd_disable_slot(x, slotid); -+ if (cc != CC_SUCCESS) { -+ grub_dprintf("xhci", "%s: disable failed (cc %d)\n", __func__, cc); -+ } else { -+ x->devs[slotid].ptr_low = 0; -+ x->devs[slotid].ptr_high = 0; -+ grub_arch_sync_dma_caches(&x->devs[slotid], sizeof(x->devs[0])); -+ } -+ grub_dma_free(priv->slotctx_dma); -+ grub_dma_free(reqs_dma); -+ grub_dma_free(in_dma); -+ return GRUB_USB_ERR_BADDEVICE; -+ } -+ priv->enpoint_trbs[epid] = reqs; -+ priv->enpoint_trbs_dma[epid] = reqs_dma; -+ priv->slotid = slotid; -+ priv->max_packet = 0; -+ } -+ if (epid != 1) -+ { -+ /* Send configure command. */ -+ int cc = xhci_cmd_configure_endpoint(x, priv->slotid, in_dma); -+ if (cc != CC_SUCCESS) -+ { -+ grub_dprintf("xhci", "%s: configure endpoint: failed (cc %d)\n", -+ __func__, cc); -+ grub_dma_free(reqs_dma); -+ grub_dma_free(in_dma); -+ return GRUB_USB_ERR_BADDEVICE; -+ } -+ priv->enpoint_trbs[epid] = reqs; -+ priv->enpoint_trbs_dma[epid] = reqs_dma; -+ } -+ -+ grub_dprintf("xhci", "%s: done\n", __func__); -+ grub_dma_free(in_dma); -+ -+ return GRUB_USB_ERR_NONE; -+} -+ -+ -+/**************************************************************** -+ * xHCI transfer helper functions -+ ****************************************************************/ -+ -+static grub_usb_err_t -+grub_xhci_usb_to_grub_err (unsigned char status) -+{ -+ if (status != CC_SUCCESS) -+ grub_dprintf("xhci", "%s: xfer failed (cc %d)\n", __func__, status); -+ else -+ grub_dprintf("xhci", "%s: xfer done (cc %d)\n", __func__, status); -+ -+ if (status == CC_BABBLE_DETECTED) -+ return GRUB_USB_ERR_BABBLE; -+ else if (status == CC_DATA_BUFFER_ERROR) -+ return GRUB_USB_ERR_DATA; -+ else if (status == CC_STALL_ERROR) -+ return GRUB_USB_ERR_STALL; -+ else if (status != CC_SUCCESS) -+ return GRUB_USB_ERR_NAK; -+ -+ return GRUB_USB_ERR_NONE; -+} -+ -+static int -+grub_xhci_transfer_is_zlp(grub_usb_transfer_t transfer, int idx) -+{ -+ if (idx >= transfer->transcnt) -+ return 0; -+ -+ grub_usb_transaction_t tr = &transfer->transactions[idx]; -+ -+ return (tr->size == 0) && -+ ((tr->pid == GRUB_USB_TRANSFER_TYPE_OUT) || -+ (tr->pid == GRUB_USB_TRANSFER_TYPE_IN)); -+} -+ -+static int -+grub_xhci_transfer_is_last(grub_usb_transfer_t transfer, int idx) -+{ -+ return (idx + 1) == transfer->transcnt; -+} -+ -+static int -+grub_xhci_transfer_is_data(grub_usb_transfer_t transfer, int idx) -+{ -+ grub_usb_transaction_t tr; -+ -+ if (idx >= transfer->transcnt) -+ return 0; -+ -+ tr = &transfer->transactions[idx]; -+ if (tr->size == 0 || -+ (tr->pid == GRUB_USB_TRANSFER_TYPE_SETUP)) -+ return 0; -+ -+ /* If there's are no DATA pakets before it's a DATA paket */ -+ for (int i = idx - 1; i >= 0; i--) -+ { -+ tr = &transfer->transactions[i]; -+ if (tr->size > 0 && -+ ((tr->pid == GRUB_USB_TRANSFER_TYPE_OUT) || -+ (tr->pid == GRUB_USB_TRANSFER_TYPE_IN))) -+ return 0; -+ } -+ return 1; -+} -+ -+static int -+grub_xhci_transfer_is_in(grub_usb_transfer_t transfer, int idx) -+{ -+ grub_usb_transaction_t tr; -+ -+ if (idx >= transfer->transcnt) -+ return 0; -+ -+ tr = &transfer->transactions[idx]; -+ -+ return tr->pid == GRUB_USB_TRANSFER_TYPE_IN; -+} -+ -+static int -+grub_xhci_transfer_is_normal(grub_usb_transfer_t transfer, int idx) -+{ -+ grub_usb_transaction_t tr; -+ -+ if (idx >= transfer->transcnt) -+ return 0; -+ -+ tr = &transfer->transactions[idx]; -+ if (tr->size == 0 || -+ (tr->pid == GRUB_USB_TRANSFER_TYPE_SETUP)) -+ return 0; -+ -+ /* If there's at least one DATA paket before it's a normal */ -+ for (int i = idx - 1; i >= 0; i--) -+ { -+ tr = &transfer->transactions[i]; -+ if (tr->size > 0 && -+ ((tr->pid == GRUB_USB_TRANSFER_TYPE_OUT) || -+ (tr->pid == GRUB_USB_TRANSFER_TYPE_IN))) -+ return 1; -+ -+ } -+ return 0; -+} -+ -+static int -+grub_xhci_transfer_next_is_normal(grub_usb_transfer_t transfer, int idx) -+{ -+ return grub_xhci_transfer_is_normal(transfer, idx + 1); -+} -+ -+static int -+grub_xhci_transfer_next_is_in(grub_usb_transfer_t transfer, int idx) -+{ -+ return grub_xhci_transfer_is_in(transfer, idx + 1); -+} -+ -+static grub_uint8_t grub_xhci_epid_from_transfer(grub_usb_transfer_t transfer) -+{ -+ grub_uint8_t epid; -+ -+ if (transfer->endpoint == 0) { -+ epid = 1; -+ } else { -+ epid = (transfer->endpoint & 0x0f) * 2; -+ epid += (transfer->dir == GRUB_USB_TRANSFER_TYPE_IN) ? 1 : 0; -+ } -+ return epid; -+} -+ -+/**************************************************************** -+ * xHCI transfer functions -+ ****************************************************************/ -+ -+static grub_usb_err_t -+grub_xhci_setup_transfer (grub_usb_controller_t dev, -+ grub_usb_transfer_t transfer) -+{ -+ struct grub_xhci_transfer_controller_data *cdata; -+ struct grub_xhci *x = (struct grub_xhci *) dev->data; -+ grub_uint8_t epid; -+ grub_usb_err_t err; -+ volatile struct grub_xhci_ring *reqs; -+ int rc; -+ struct grub_xhci_priv *priv; -+ -+ xhci_check_status(x); -+ -+ if (!dev || !transfer || !transfer->dev || !transfer->dev->xhci_priv) -+ return GRUB_USB_ERR_INTERNAL; -+ -+ priv = transfer->dev->xhci_priv; -+ err = grub_xhci_prepare_endpoint(x, transfer->dev, -+ transfer->endpoint, -+ transfer->dir, -+ transfer->type, -+ transfer->max, -+ priv); -+ -+ if (err != GRUB_USB_ERR_NONE) -+ return err; -+ -+ epid = grub_xhci_epid_from_transfer(transfer); -+ -+ /* Update the max packet size once descdev.maxsize0 is valid */ -+ if (epid == 1 && -+ (priv->max_packet == 0) && -+ (transfer->dev->descdev.maxsize0 > 0)) -+ { -+ if (transfer->dev->speed == GRUB_USB_SPEED_SUPER) -+ priv->max_packet = 1UL << transfer->dev->descdev.maxsize0; -+ else -+ priv->max_packet = transfer->dev->descdev.maxsize0; -+ err = grub_xhci_update_max_paket_size(x, transfer, priv->slotid, priv->max_packet); -+ if (err != GRUB_USB_ERR_NONE) -+ { -+ grub_dprintf("xhci", "%s: Updating max paket size failed\n", __func__); -+ return err; -+ } -+ } -+ if (epid == 1 && -+ transfer->dev->descdev.class == 9 && -+ transfer->dev->nports > 0) -+ { -+ err = grub_xhci_update_hub_portcount(x, transfer, priv->slotid); -+ if (err != GRUB_USB_ERR_NONE) -+ { -+ grub_dprintf("xhci", "%s: Updating max paket size failed\n", __func__); -+ return err; -+ } -+ } -+ -+ /* Allocate private data for the transfer */ -+ cdata = grub_zalloc(sizeof(*cdata)); -+ if (!cdata) -+ return GRUB_USB_ERR_INTERNAL; -+ -+ reqs = priv->enpoint_trbs[epid]; -+ -+ transfer->controller_data = cdata; -+ -+ /* Now queue the transfer onto the TRB */ -+ if (transfer->type == GRUB_USB_TRANSACTION_TYPE_CONTROL) -+ { -+ volatile struct grub_usb_packet_setup *setupdata; -+ setupdata = (void *)transfer->transactions[0].data; -+ grub_dprintf("xhci", "%s: CONTROLL TRANS req %d\n", __func__, setupdata->request); -+ grub_dprintf("xhci", "%s: CONTROLL TRANS length %d\n", __func__, setupdata->length); -+ -+ if (setupdata && setupdata->request == GRUB_USB_REQ_SET_ADDRESS) -+ return GRUB_USB_ERR_NONE; -+ -+ if (transfer->transcnt < 2) -+ return GRUB_USB_ERR_INTERNAL; -+ -+ for (int i = 0; i < transfer->transcnt; i++) -+ { -+ grub_uint32_t flags = 0; -+ grub_uint64_t inline_data; -+ grub_usb_transaction_t tr = &transfer->transactions[i]; -+ -+ switch (tr->pid) -+ { -+ case GRUB_USB_TRANSFER_TYPE_SETUP: -+ { -+ grub_dprintf("xhci", "%s: SETUP PKG\n", __func__); -+ grub_dprintf("xhci", "%s: transfer->size %d\n", __func__, transfer->size); -+ grub_dprintf("xhci", "%s: tr->size %d SETUP PKG\n", __func__, tr->size); -+ -+ flags |= (TR_SETUP << 10); -+ flags |= TRB_TR_IDT; -+ -+ if (transfer->size > 0) -+ { -+ if (grub_xhci_transfer_next_is_in(transfer, i)) -+ flags |= (3 << 16); /* TRT IN */ -+ else -+ flags |= (2 << 16); /* TRT OUT */ -+ } -+ break; -+ } -+ case GRUB_USB_TRANSFER_TYPE_OUT: -+ { -+ grub_dprintf("xhci", "%s: OUT PKG\n", __func__); -+ cdata->transfer_size += tr->size; -+ break; -+ } -+ case GRUB_USB_TRANSFER_TYPE_IN: -+ { -+ grub_dprintf("xhci", "%s: IN PKG\n", __func__); -+ cdata->transfer_size += tr->size; -+ flags |= TRB_TR_DIR; -+ break; -+ } -+ } -+ -+ if (grub_xhci_transfer_is_normal(transfer, i)) -+ flags |= (TR_NORMAL << 10); -+ else if (grub_xhci_transfer_is_data(transfer, i)) -+ flags |= (TR_DATA << 10); -+ else if (grub_xhci_transfer_is_zlp(transfer, i)) -+ flags |= (TR_STATUS << 10); -+ -+ if (grub_xhci_transfer_next_is_normal(transfer, i)) -+ flags |= TRB_TR_CH; -+ -+ if (grub_xhci_transfer_is_last(transfer, i)) -+ flags |= TRB_TR_IOC; -+ -+ /* Assume the ring has enough free space for all TRBs */ -+ if (flags & TRB_TR_IDT && tr->size <= (int)sizeof(inline_data)) -+ { -+ grub_memcpy(&inline_data, (void *)tr->data, tr->size); -+ xhci_trb_queue(reqs, inline_data, tr->size, flags); -+ } -+ else -+ { -+ xhci_trb_queue(reqs, tr->data, tr->size, flags); -+ } -+ } -+ } -+ else if (transfer->type == GRUB_USB_TRANSACTION_TYPE_BULK) -+ { -+ for (int i = 0; i < transfer->transcnt; i++) -+ { -+ grub_uint32_t flags = (TR_NORMAL << 10); -+ grub_usb_transaction_t tr = &transfer->transactions[i]; -+ switch (tr->pid) -+ { -+ case GRUB_USB_TRANSFER_TYPE_OUT: -+ { -+ grub_dprintf("xhci", "%s: OUT PKG\n", __func__); -+ cdata->transfer_size += tr->size; -+ break; -+ } -+ case GRUB_USB_TRANSFER_TYPE_IN: -+ { -+ grub_dprintf("xhci", "%s: IN PKG\n", __func__); -+ cdata->transfer_size += tr->size; -+ flags |= TRB_TR_DIR; -+ break; -+ } -+ case GRUB_USB_TRANSFER_TYPE_SETUP: -+ break; -+ } -+ if (grub_xhci_transfer_is_last(transfer, i)) -+ flags |= TRB_TR_IOC; -+ -+ /* The ring might be to small, submit while adding new entries */ -+ rc = xhci_trb_queue_and_flush(x, priv->slotid, epid, -+ reqs, tr->data, tr->size, flags); -+ if (rc < 0) -+ return GRUB_USB_ERR_TIMEOUT; -+ else if (rc > 1) -+ return grub_xhci_usb_to_grub_err(rc); -+ -+ } -+ } -+ xhci_doorbell(x, priv->slotid, epid); -+ -+ return GRUB_USB_ERR_NONE; -+} -+ -+static grub_usb_err_t -+grub_xhci_check_transfer (grub_usb_controller_t dev, -+ grub_usb_transfer_t transfer, grub_size_t * actual) -+{ -+ grub_uint32_t status; -+ grub_uint32_t remaining; -+ grub_uint8_t epid; -+ volatile struct grub_xhci_ring *reqs; -+ grub_usb_err_t err; -+ int rc; -+ -+ if (!dev->data || !transfer->controller_data || !transfer->dev || -+ !transfer->dev->xhci_priv) -+ return GRUB_USB_ERR_INTERNAL; -+ -+ -+ struct grub_xhci_priv *priv = transfer->dev->xhci_priv; -+ struct grub_xhci *x = (struct grub_xhci *) dev->data; -+ struct grub_xhci_transfer_controller_data *cdata = -+ transfer->controller_data; -+ -+ xhci_check_status(x); -+ xhci_process_events(x); -+ -+ epid = grub_xhci_epid_from_transfer(transfer); -+ -+ reqs = priv->enpoint_trbs[epid]; -+ -+ /* XXX: invalidate caches */ -+ -+ /* Get current status from event ring buffer */ -+ status = (reqs->evt.status>> 24) & 0xff; -+ remaining = reqs->evt.status & 0xffffff; -+ -+ if (status != CC_STOPPED_LENGTH_INVALID) -+ *actual = cdata->transfer_size - remaining; -+ else -+ *actual = 0; -+ -+ if (xhci_ring_busy(reqs)) -+ return GRUB_USB_ERR_WAIT; -+ -+ grub_free(cdata); -+ -+ grub_dprintf("xhci", "%s: xfer done\n", __func__); -+ -+ err = grub_xhci_usb_to_grub_err(status); -+ if (err != GRUB_USB_ERR_NONE) -+ { -+ if (status == CC_STALL_ERROR) -+ { -+ /* Clear the stall by resetting the endpoint */ -+ rc = xhci_cmd_reset_endpoint(x, priv->slotid, epid, 1); -+ -+ if (rc < 0) -+ return GRUB_USB_ERR_TIMEOUT; -+ -+ return GRUB_USB_ERR_STALL; -+ } -+ else if (remaining > 0) -+ { -+ return GRUB_USB_ERR_DATA; -+ } -+ } -+ -+ return err; -+} -+ -+static grub_usb_err_t -+grub_xhci_cancel_transfer (grub_usb_controller_t dev, -+ grub_usb_transfer_t transfer) -+{ -+ grub_uint8_t epid; -+ volatile struct grub_xhci_ring *reqs; -+ struct grub_pci_dma_chunk *enpoint_trbs_dma; -+ grub_addr_t deque_pointer; -+ int rc; -+ -+ if (!dev->data || !transfer->controller_data || !transfer->dev || -+ !transfer->dev->xhci_priv) -+ return GRUB_USB_ERR_INTERNAL; -+ -+ struct grub_xhci *x = (struct grub_xhci *) dev->data; -+ struct grub_xhci_transfer_controller_data *cdata = -+ transfer->controller_data; -+ struct grub_xhci_priv *priv = transfer->dev->xhci_priv; -+ -+ epid = grub_xhci_epid_from_transfer(transfer); -+ -+ enpoint_trbs_dma = priv->enpoint_trbs_dma[epid]; -+ reqs = priv->enpoint_trbs[epid]; -+ -+ /* Abort current command */ -+ rc = xhci_cmd_stop_endpoint(x, priv->slotid, epid, 0); -+ if (rc < 0) -+ return GRUB_USB_ERR_TIMEOUT; -+ -+ /* Reset state */ -+ reqs->nidx = 0; -+ reqs->eidx = 0; -+ reqs->cs = 1; -+ -+ grub_arch_sync_dma_caches(reqs, sizeof(*reqs)); -+ -+ /* Reset the dequeue pointer to the begging of the TRB */ -+ deque_pointer = grub_dma_get_phys(enpoint_trbs_dma); -+ rc = xhci_cmd_set_dequeue_pointer(x, priv->slotid, epid, deque_pointer| 1 ); -+ if (rc < 0) -+ return GRUB_USB_ERR_TIMEOUT; -+ -+ reqs->evt.ptr_low = 0; -+ reqs->evt.ptr_high = 0; -+ reqs->evt.control = 0; -+ reqs->evt.status = 0; -+ -+ grub_arch_sync_dma_caches(reqs, sizeof(*reqs)); -+ -+ /* Restart ring buffer processing */ -+ xhci_doorbell(x, priv->slotid, epid); -+ -+ grub_free (cdata); -+ -+ return GRUB_USB_ERR_NONE; -+} -+ -+/**************************************************************** -+ * xHCI port status functions -+ ****************************************************************/ -+ -+static int -+grub_xhci_hubports (grub_usb_controller_t dev) -+{ -+ struct grub_xhci *x = (struct grub_xhci *) dev->data; -+ grub_uint32_t portinfo; -+ -+ portinfo = x->ports; -+ grub_dprintf ("xhci", "root hub ports=%d\n", portinfo); -+ return portinfo; -+} -+ -+static grub_usb_err_t -+grub_xhci_portstatus (grub_usb_controller_t dev, -+ unsigned int port, unsigned int enable) -+{ -+ struct grub_xhci *x = (struct grub_xhci *) dev->data; -+ grub_uint32_t portsc, pls; -+ grub_uint32_t end; -+ -+ portsc = grub_xhci_port_read(x, port); -+ pls = xhci_get_field(portsc, XHCI_PORTSC_PLS); -+ -+ grub_dprintf("xhci", "grub_xhci_portstatus port #%d: 0x%08x,%s%s pls %d enable %d\n", -+ port, portsc, -+ (portsc & GRUB_XHCI_PORTSC_PP) ? " powered," : "", -+ (portsc & GRUB_XHCI_PORTSC_PED) ? " enabled," : "", -+ pls, enable); -+ xhci_check_status(x); -+ -+ if ((enable && (portsc & GRUB_XHCI_PORTSC_PED)) || -+ (!enable && !(portsc & GRUB_XHCI_PORTSC_PED))) -+ return GRUB_USB_ERR_NONE; -+ -+ if (!enable) -+ { -+ /* Disable port */ -+ grub_xhci_port_write(x, port, ~0, GRUB_XHCI_PORTSC_PED); -+ return GRUB_USB_ERR_NONE; -+ } -+ -+ grub_dprintf ("xhci", "portstatus: XHCI STATUS: %08x\n", -+ grub_xhci_read32(&x->op->usbsts)); -+ grub_dprintf ("xhci", -+ "portstatus: begin, iobase=%p, port=%d, status=0x%08x\n", -+ x->caps, port, portsc); -+ -+ switch (pls) -+ { -+ case PLS_U0: -+ /* A USB3 port - controller automatically performs reset */ -+ break; -+ case PLS_POLLING: -+ /* A USB2 port - perform device reset */ -+ grub_xhci_port_write(x, port, ~GRUB_XHCI_PORTSC_PED, GRUB_XHCI_PORTSC_PR); -+ break; -+ default: -+ return GRUB_USB_ERR_NONE; -+ } -+ -+ /* Wait for device to complete reset and be enabled */ -+ end = grub_get_time_ms () + 100; -+ for (;;) -+ { -+ portsc = grub_xhci_port_read(x, port); -+ if (!(portsc & GRUB_XHCI_PORTSC_CCS)) -+ { -+ /* Device disconnected during reset */ -+ grub_dprintf ("xhci","ERROR: %s device disconnected\n", __func__); -+ return GRUB_USB_ERR_BADDEVICE; -+ } -+ if (portsc & GRUB_XHCI_PORTSC_PED) -+ /* Reset complete */ -+ break; -+ if (grub_get_time_ms () > end) -+ { -+ grub_dprintf ("xhci","ERROR: %s TIMEOUT\n", __func__); -+ return GRUB_USB_ERR_TIMEOUT; -+ } -+ } -+ xhci_check_status(x); -+ -+ return GRUB_USB_ERR_NONE; -+} -+ -+/**************************************************************** -+ * xHCI detect device functions -+ ****************************************************************/ -+ -+static grub_usb_speed_t -+grub_xhci_detect_dev (grub_usb_controller_t dev, int port, int *changed) -+{ -+ struct grub_xhci *x = (struct grub_xhci *) dev->data; -+ grub_uint32_t portsc, speed; -+ -+ *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); -+ -+ /* On shutdown advertise all ports as disconnected. This will trigger -+ * a gracefull detatch. */ -+ if (x->shutdown) -+ { -+ *changed = 1; -+ return GRUB_USB_SPEED_NONE; -+ } -+ -+ /* Don't advertise new devices, connecting will fail if halted */ -+ if (xhci_is_halted(x)) -+ return GRUB_USB_SPEED_NONE; -+ -+ portsc = grub_xhci_port_read(x, port); -+ speed = xhci_get_field(portsc, XHCI_PORTSC_SPEED); -+ grub_uint8_t pls = xhci_get_field(portsc, XHCI_PORTSC_PLS); -+ -+ grub_dprintf("xhci", "grub_xhci_portstatus port #%d: 0x%08x,%s%s pls %d\n", -+ port, portsc, -+ (portsc & GRUB_XHCI_PORTSC_PP) ? " powered," : "", -+ (portsc & GRUB_XHCI_PORTSC_PED) ? " enabled," : "", -+ pls); -+ -+ /* Connect Status Change bit - it detects change of connection */ -+ if (portsc & GRUB_XHCI_PORTSC_CSC) -+ { -+ *changed = 1; -+ -+ grub_xhci_port_write(x, port, ~GRUB_XHCI_PORTSC_PED, GRUB_XHCI_PORTSC_CSC); -+ } -+ -+ 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++) -+ { -+ if (x->psids[port-1].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; -+ } -+ } -+ -+ return GRUB_USB_SPEED_NONE; -+} -+ -+/**************************************************************** -+ * xHCI attach/detach functions -+ ****************************************************************/ -+ -+static grub_usb_err_t -+grub_xhci_attach_dev (grub_usb_controller_t ctrl, grub_usb_device_t dev) -+{ -+ struct grub_xhci *x = (struct grub_xhci *) ctrl->data; -+ grub_usb_err_t err; -+ grub_uint32_t max; -+ -+ grub_dprintf("xhci", "%s: dev=%p\n", __func__, dev); -+ -+ if (!dev || !x) -+ return GRUB_USB_ERR_INTERNAL; -+ -+ dev->xhci_priv = grub_zalloc (sizeof (struct grub_xhci_priv)); -+ if (!dev->xhci_priv) -+ return GRUB_USB_ERR_INTERNAL; -+ -+ -+ switch (dev->speed) -+ { -+ case GRUB_USB_SPEED_LOW: -+ { -+ max = 8; -+ break; -+ } -+ case GRUB_USB_SPEED_FULL: -+ case GRUB_USB_SPEED_HIGH: -+ { -+ max = 64; -+ break; -+ } -+ case GRUB_USB_SPEED_SUPER: -+ { -+ max = 512; -+ break; -+ } -+ default: -+ case GRUB_USB_SPEED_NONE: -+ { -+ max = 0; -+ } -+ } -+ -+ /* Assign a slot, assign an address and configure endpoint 0 */ -+ err = grub_xhci_prepare_endpoint(x, dev, -+ 0, -+ 0, -+ GRUB_USB_TRANSACTION_TYPE_CONTROL, -+ max, -+ dev->xhci_priv); -+ -+ return err; -+} -+ -+static grub_usb_err_t -+grub_xhci_detach_dev (grub_usb_controller_t ctrl, grub_usb_device_t dev) -+{ -+ struct grub_xhci *x = (struct grub_xhci *) ctrl->data; -+ struct grub_xhci_priv *priv; -+ int cc = CC_SUCCESS; -+ -+ grub_dprintf("xhci", "%s: dev=%p\n", __func__, dev); -+ -+ if (!dev) -+ return GRUB_USB_ERR_INTERNAL; -+ -+ if (dev->xhci_priv) -+ { -+ priv = dev->xhci_priv; -+ /* Stop endpoints and free ring buffer */ -+ for (int i = 0; i < GRUB_XHCI_MAX_ENDPOINTS; i++) -+ { -+ if (priv->enpoint_trbs[i] != NULL) -+ { -+ cc = xhci_cmd_stop_endpoint(x, priv->slotid, i, 1); -+ if (cc != CC_SUCCESS) -+ grub_dprintf("xhci", "Failed to disable EP%d on slot %d\n", i, -+ priv->slotid); -+ -+ grub_dprintf("xhci", "grub_dma_free[%d]\n", i); -+ -+ grub_dma_free(priv->enpoint_trbs_dma[i]); -+ priv->enpoint_trbs[i] = NULL; -+ priv->enpoint_trbs_dma[i] = NULL; -+ } -+ } -+ -+ cc = xhci_cmd_disable_slot(x, priv->slotid); -+ if (cc == CC_SUCCESS) -+ { -+ if (priv->slotctx_dma) -+ grub_dma_free(priv->slotctx_dma); -+ x->devs[priv->slotid].ptr_low = 0; -+ x->devs[priv->slotid].ptr_high = 0; -+ grub_arch_sync_dma_caches(&x->devs[priv->slotid], sizeof(x->devs[0])); -+ } -+ else -+ grub_dprintf("xhci", "Failed to disable slot %d\n", priv->slotid); -+ -+ grub_free(dev->xhci_priv); -+ } -+ -+ dev->xhci_priv = NULL; -+ -+ if (cc != CC_SUCCESS) -+ return GRUB_USB_ERR_BADDEVICE; -+ return GRUB_USB_ERR_NONE; -+} -+ -+/**************************************************************** -+ * xHCI terminate functions -+ ****************************************************************/ -+ -+static void -+grub_xhci_halt(struct grub_xhci *x) -+{ -+ grub_uint32_t reg; -+ -+ /* Halt the command ring */ -+ reg = grub_xhci_read32(&x->op->crcr_low); -+ grub_xhci_write32(&x->op->crcr_low, reg | 4); -+ -+ int rc = xhci_event_wait(x, x->cmds, 100); -+ grub_dprintf("xhci", "%s: xhci_event_wait = %d\n", __func__, rc); -+ if (rc < 0) -+ return; -+ -+ /* Stop the controller */ -+ reg = grub_xhci_read32(&x->op->usbcmd); -+ if (reg & GRUB_XHCI_CMD_RS) -+ { -+ reg &= ~GRUB_XHCI_CMD_RS; -+ grub_xhci_write32(&x->op->usbcmd, reg); -+ } -+ -+ return; -+} -+ -+static grub_err_t -+grub_xhci_fini_hw (int noreturn __attribute__ ((unused))) -+{ -+ struct grub_xhci *x; -+ -+ /* We should disable all XHCI HW to prevent any DMA access etc. */ -+ for (x = xhci; x; x = x->next) -+ { -+ x->shutdown = 1; -+ -+ /* Gracefully detach active devices */ -+ grub_usb_poll_devices(0); -+ -+ /* Check if xHCI is halted and halt it if not */ -+ grub_xhci_halt (x); -+ -+ /* Reset xHCI */ -+ if (grub_xhci_reset (x) != GRUB_USB_ERR_NONE) -+ return GRUB_ERR_BAD_DEVICE; -+ } -+ -+ return GRUB_ERR_NONE; -+} -+ -+static struct grub_usb_controller_dev usb_controller = { -+ .name = "xhci", -+ .iterate = grub_xhci_iterate, -+ .setup_transfer = grub_xhci_setup_transfer, -+ .check_transfer = grub_xhci_check_transfer, -+ .cancel_transfer = grub_xhci_cancel_transfer, -+ .hubports = grub_xhci_hubports, -+ .portstatus = grub_xhci_portstatus, -+ .detect_dev = grub_xhci_detect_dev, -+ .attach_dev = grub_xhci_attach_dev, -+ .detach_dev = grub_xhci_detach_dev, -+ /* estimated max. count of TDs for one bulk transfer */ -+ .max_bulk_tds = GRUB_XHCI_RING_ITEMS - 3 -+}; -+ -+GRUB_MOD_INIT (xhci) -+{ -+ grub_stop_disk_firmware (); -+ -+ grub_boot_time ("Initing XHCI hardware"); -+ grub_xhci_pci_scan (); -+ grub_boot_time ("Registering XHCI driver"); -+ grub_usb_controller_dev_register (&usb_controller); -+ grub_boot_time ("XHCI driver registered"); -+} -+ -+GRUB_MOD_FINI (xhci) -+{ -+ grub_xhci_fini_hw (0); -+ grub_usb_controller_dev_unregister (&usb_controller); -+} -diff --git a/include/grub/usb.h b/include/grub/usb.h -index 609faf7d0..eb71fa1c7 100644 ---- a/include/grub/usb.h -+++ b/include/grub/usb.h -@@ -338,6 +338,10 @@ grub_usb_cancel_transfer (grub_usb_transfer_t trans); - void - grub_ehci_init_device (volatile void *regs); - void -+grub_xhci_init_device (volatile void *regs); -+void - grub_ehci_pci_scan (void); -+void -+grub_xhci_pci_scan (void); - - #endif /* GRUB_USB_H */ --- -2.39.5 - diff --git a/config/grub/xhci_nvme/patches/0020-grub-core-bus-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch b/config/grub/xhci_nvme/patches/0020-grub-core-bus-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch deleted file mode 100644 index 31e831ec..00000000 --- a/config/grub/xhci_nvme/patches/0020-grub-core-bus-usb-usbhub-Add-xHCI-non-root-hub-suppo.patch +++ /dev/null @@ -1,127 +0,0 @@ -From d84ac94dc55baad9a2297980b2017cd22e4ecb3c Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph -Date: Mon, 7 Dec 2020 08:41:27 +0100 -Subject: [PATCH 20/26] grub-core/bus/usb/usbhub: Add xHCI non root hub support - -Tested on Intel PCH C246, the USB3 hub can be configured by grub. - -Issues: -* USB3 devices connected behind that hub are sometimes not detected. - -Signed-off-by: Patrick Rudolph ---- - grub-core/bus/usb/usbhub.c | 38 +++++++++++++++++++++++++++++++++----- - include/grub/usbdesc.h | 1 + - include/grub/usbtrans.h | 4 ++++ - 3 files changed, 38 insertions(+), 5 deletions(-) - -diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c -index b4b3a1a61..e96505aa9 100644 ---- a/grub-core/bus/usb/usbhub.c -+++ b/grub-core/bus/usb/usbhub.c -@@ -148,19 +148,32 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, - return dev; - } - -- -+static grub_usb_err_t -+grub_usb_set_hub_depth(grub_usb_device_t dev, grub_uint8_t depth) -+{ -+ return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT -+ | GRUB_USB_REQTYPE_CLASS -+ | GRUB_USB_REQTYPE_TARGET_DEV), -+ GRUB_USB_HUB_REQ_SET_HUB_DEPTH, depth, -+ 0, 0, NULL); -+} -+ - static grub_usb_err_t - grub_usb_add_hub (grub_usb_device_t dev) - { - struct grub_usb_usb_hubdesc hubdesc; - grub_usb_err_t err; -+ grub_uint16_t req; - int i; - -+ req = (dev->speed == GRUB_USB_SPEED_SUPER) ? GRUB_USB_DESCRIPTOR_SS_HUB : -+ GRUB_USB_DESCRIPTOR_HUB; -+ - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_DEV), -- GRUB_USB_REQ_GET_DESCRIPTOR, -- (GRUB_USB_DESCRIPTOR_HUB << 8) | 0, -+ GRUB_USB_REQ_GET_DESCRIPTOR, -+ (req << 8) | 0, - 0, sizeof (hubdesc), (char *) &hubdesc); - if (err) - return err; -@@ -183,6 +196,19 @@ grub_usb_add_hub (grub_usb_device_t dev) - return GRUB_USB_ERR_INTERNAL; - } - -+ if (dev->speed == GRUB_USB_SPEED_SUPER) -+ { -+ grub_uint8_t depth; -+ grub_uint32_t route; -+ /* Depth maximum value is 5, but root hubs doesn't count */ -+ for (depth = 0, route = dev->route; (route & 0xf) > 0; route >>= 4) -+ depth++; -+ -+ err = grub_usb_set_hub_depth(dev, depth); -+ if (err) -+ return err; -+ } -+ - /* Power on all Hub ports. */ - for (i = 1; i <= hubdesc.portcnt; i++) - { -@@ -637,7 +663,9 @@ poll_nonroot_hub (grub_usb_device_t dev) - int split_hubaddr = 0; - - /* Determine the device speed. */ -- if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED) -+ if (dev->speed == GRUB_USB_SPEED_SUPER) -+ speed = GRUB_USB_SPEED_SUPER; -+ else if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED) - speed = GRUB_USB_SPEED_LOW; - else - { -@@ -651,7 +679,7 @@ poll_nonroot_hub (grub_usb_device_t dev) - grub_millisleep (10); - - /* Find correct values for SPLIT hubport and hubaddr */ -- if (speed == GRUB_USB_SPEED_HIGH) -+ if (speed == GRUB_USB_SPEED_HIGH || speed == GRUB_USB_SPEED_SUPER) - { - /* HIGH speed device needs not transaction translation */ - split_hubport = 0; -diff --git a/include/grub/usbdesc.h b/include/grub/usbdesc.h -index bb2ab2e27..1697aa465 100644 ---- a/include/grub/usbdesc.h -+++ b/include/grub/usbdesc.h -@@ -30,6 +30,7 @@ typedef enum { - GRUB_USB_DESCRIPTOR_ENDPOINT, - GRUB_USB_DESCRIPTOR_DEBUG = 10, - GRUB_USB_DESCRIPTOR_HUB = 0x29, -+ GRUB_USB_DESCRIPTOR_SS_HUB = 0x2a, - GRUB_USB_DESCRIPTOR_SS_ENDPOINT_COMPANION = 0x30 - } grub_usb_descriptor_t; - -diff --git a/include/grub/usbtrans.h b/include/grub/usbtrans.h -index 039ebed65..d6c3f71dc 100644 ---- a/include/grub/usbtrans.h -+++ b/include/grub/usbtrans.h -@@ -110,6 +110,10 @@ enum - GRUB_USB_REQ_SET_INTERFACE = 0x0B, - GRUB_USB_REQ_SYNC_FRAME = 0x0C - }; -+enum -+ { -+ GRUB_USB_HUB_REQ_SET_HUB_DEPTH = 0x0C, -+ }; - - #define GRUB_USB_FEATURE_ENDP_HALT 0x00 - #define GRUB_USB_FEATURE_DEV_REMOTE_WU 0x01 --- -2.39.5 - 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..9cf94a25 --- /dev/null +++ b/config/grub/xhci_nvme/patches/0020-kern-coreboot-mmap-Map-to-reserved.patch @@ -0,0 +1,37 @@ +From 4ece79a5e4708b96c2fd06a80b1aac0b6e232675 Mon Sep 17 00:00:00 2001 +From: Paul Menzel +Date: Mon, 17 May 2021 10:24:36 +0200 +Subject: [PATCH 20/20] kern/coreboot/mmap: Map to reserved + +https://git.savannah.gnu.org/cgit/grub.git/commit/?id=6de9ee86bf9ae50967413e6a73b5dfd13e5ffb50 + +Signed-off-by: Paul Menzel +--- + 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-xHCI-also-accept-SBRN-0x31-and-0x32.patch b/config/grub/xhci_nvme/patches/0021-xHCI-also-accept-SBRN-0x31-and-0x32.patch deleted file mode 100644 index f6e0f366..00000000 --- a/config/grub/xhci_nvme/patches/0021-xHCI-also-accept-SBRN-0x31-and-0x32.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0433c5bb1e40fba93205e1c9fd6b1b397d31ae5a Mon Sep 17 00:00:00 2001 -From: Sven Anderson -Date: Sat, 28 May 2022 21:39:23 +0200 -Subject: [PATCH 21/26] xHCI: also accept SBRN 0x31 and 0x32 - -Signed-off-by: Sven Anderson ---- - 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.39.5 - diff --git a/config/grub/xhci_nvme/patches/0022-xhci-fix-port-indexing.patch b/config/grub/xhci_nvme/patches/0022-xhci-fix-port-indexing.patch deleted file mode 100644 index edfcca2c..00000000 --- a/config/grub/xhci_nvme/patches/0022-xhci-fix-port-indexing.patch +++ /dev/null @@ -1,43 +0,0 @@ -From d300f12cb624998f3d5ab5948c3fc64d6d7baf4f Mon Sep 17 00:00:00 2001 -From: Sven Anderson -Date: Mon, 13 Jan 2025 19:51:41 +0100 -Subject: [PATCH 22/26] 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.39.5 - diff --git a/config/grub/xhci_nvme/patches/0023-xhci-configure-TT-for-non-root-hubs.patch b/config/grub/xhci_nvme/patches/0023-xhci-configure-TT-for-non-root-hubs.patch deleted file mode 100644 index b41db45f..00000000 --- a/config/grub/xhci_nvme/patches/0023-xhci-configure-TT-for-non-root-hubs.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 0a669ef9815267de4fb14f3c329431ac531755c9 Mon Sep 17 00:00:00 2001 -From: Sven Anderson -Date: Mon, 13 Jan 2025 20:26:32 +0100 -Subject: [PATCH 23/26] 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.39.5 - diff --git a/config/grub/xhci_nvme/patches/0024-Fix-compilation-on-x86_64.patch b/config/grub/xhci_nvme/patches/0024-Fix-compilation-on-x86_64.patch deleted file mode 100644 index cdc692d6..00000000 --- a/config/grub/xhci_nvme/patches/0024-Fix-compilation-on-x86_64.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 625fdcf42f2cf11a4bfe644412450c9e4f551d25 Mon Sep 17 00:00:00 2001 -From: Patrick Rudolph -Date: Wed, 24 Feb 2021 08:25:41 +0100 -Subject: [PATCH 24/26] Fix compilation on x86_64 - -Signed-off-by: Patrick Rudolph ---- - grub-core/bus/usb/xhci.c | 24 ++++++++++++++++-------- - 1 file changed, 16 insertions(+), 8 deletions(-) - -diff --git a/grub-core/bus/usb/xhci.c b/grub-core/bus/usb/xhci.c -index 88c9ac57f..9b9bae6e5 100644 ---- a/grub-core/bus/usb/xhci.c -+++ b/grub-core/bus/usb/xhci.c -@@ -184,7 +184,7 @@ enum - * then we can get it from a trb pointer (provided by evt ring). - */ - #define XHCI_RING(_trb) \ -- ((struct grub_xhci_ring*)((grub_uint32_t)(_trb) & ~(GRUB_XHCI_RING_SIZE-1))) -+ ((struct grub_xhci_ring*)((grub_addr_t)(_trb) & ~(GRUB_XHCI_RING_SIZE-1))) - - /* slot context */ - struct grub_xhci_slotctx { -@@ -495,6 +495,14 @@ grub_xhci_read8(volatile void *addr) { - return (*((volatile grub_uint32_t *)addr)); - } - -+static inline void * -+grub_xhci_read_etrb_ptr(volatile struct grub_xhci_trb *trb) { -+ grub_uint64_t tmp; -+ tmp = (grub_uint64_t)grub_xhci_read32(&trb->ptr_low); -+ tmp |= ((grub_uint64_t)grub_xhci_read32(&trb->ptr_high)) << 32; -+ return (void *)(grub_addr_t)tmp; -+} -+ - static inline grub_uint32_t - grub_xhci_port_read (struct grub_xhci *x, grub_uint32_t port) - { -@@ -697,7 +705,7 @@ static void xhci_process_events(struct grub_xhci *x) - case ER_TRANSFER: - case ER_COMMAND_COMPLETE: - { -- struct grub_xhci_trb *rtrb = (void*)grub_xhci_read32(&etrb->ptr_low); -+ struct grub_xhci_trb *rtrb = grub_xhci_read_etrb_ptr(etrb); - struct grub_xhci_ring *ring = XHCI_RING(rtrb); - volatile struct grub_xhci_trb *evt = &ring->evt; - grub_uint32_t eidx = rtrb - ring->ring + 1; -@@ -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; -- grub_uint32_t erdp = (grub_uint32_t)(evts->ring + nidx); -- grub_xhci_write32(&ir->erdp_low, erdp); -- grub_xhci_write32(&ir->erdp_high, 0); -+ grub_uint64_t erdp = (grub_addr_t)(void *)(&evts->ring[nidx]); -+ grub_xhci_write32(&ir->erdp_low, erdp & 0xffffffff); -+ grub_xhci_write32(&ir->erdp_high, erdp >> 32); - } - } - -@@ -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__, -- ring, data_or_addr, xferlen & 0x1ffff, flags, xferlen >> 17); -+ ring, (unsigned long long)data_or_addr, xferlen & 0x1ffff, flags, xferlen >> 17); - - if (xhci_ring_full(ring)) - { -@@ -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; -- setupdata = (void *)transfer->transactions[0].data; -+ setupdata = (void *)(grub_addr_t)transfer->transactions[0].data; - grub_dprintf("xhci", "%s: CONTROLL TRANS req %d\n", __func__, setupdata->request); - grub_dprintf("xhci", "%s: CONTROLL TRANS length %d\n", __func__, setupdata->length); - -@@ -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)) - { -- grub_memcpy(&inline_data, (void *)tr->data, tr->size); -+ grub_memcpy(&inline_data, (void *)(grub_addr_t)tr->data, tr->size); - xhci_trb_queue(reqs, inline_data, tr->size, flags); - } - else --- -2.39.5 - diff --git a/config/grub/xhci_nvme/patches/0025-Add-native-NVMe-driver-based-on-SeaBIOS.patch b/config/grub/xhci_nvme/patches/0025-Add-native-NVMe-driver-based-on-SeaBIOS.patch deleted file mode 100644 index e9dc54b5..00000000 --- a/config/grub/xhci_nvme/patches/0025-Add-native-NVMe-driver-based-on-SeaBIOS.patch +++ /dev/null @@ -1,1074 +0,0 @@ -From 1ede42b39a87ccb2cc43d919f3ee4803d6551102 Mon Sep 17 00:00:00 2001 -From: Mate Kukri -Date: Mon, 20 May 2024 11:43:35 +0100 -Subject: [PATCH 25/26] Add native NVMe driver based on SeaBIOS - -Tested to successfully boot Debian on QEMU and OptiPlex 3050. - -Signed-off-by: Mate Kukri ---- - 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 d3947739f..fb9f24c0f 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -2689,3 +2689,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 -+ -+/* 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 -+#include -+#include -+#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.39.5 - diff --git a/config/grub/xhci_nvme/patches/0026-kern-coreboot-mmap-Map-to-reserved.patch b/config/grub/xhci_nvme/patches/0026-kern-coreboot-mmap-Map-to-reserved.patch deleted file mode 100644 index 712d2218..00000000 --- a/config/grub/xhci_nvme/patches/0026-kern-coreboot-mmap-Map-to-reserved.patch +++ /dev/null @@ -1,37 +0,0 @@ -From d73ca74ef879bf602274bee6eb24f0080a45d235 Mon Sep 17 00:00:00 2001 -From: Paul Menzel -Date: Mon, 17 May 2021 10:24:36 +0200 -Subject: [PATCH 26/26] kern/coreboot/mmap: Map to reserved - -https://git.savannah.gnu.org/cgit/grub.git/commit/?id=6de9ee86bf9ae50967413e6a73b5dfd13e5ffb50 - -Signed-off-by: Paul Menzel ---- - 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.39.5 - diff --git a/config/grub/xhci_nvme/target.cfg b/config/grub/xhci_nvme/target.cfg index c3c8127d..618d15a4 100644 --- a/config/grub/xhci_nvme/target.cfg +++ b/config/grub/xhci_nvme/target.cfg @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-3.0-or-later tree="xhci_nvme" -rev="a68a7dece464c35b1c8d20b98502b6881b103911" +rev="280715ec63a3424f5cf1289302cb4ab4e98768f4" -- cgit v1.2.1