From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1mgC5G-0006fT-AV for mharc-grub-devel@gnu.org; Thu, 28 Oct 2021 16:33:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:55942) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mgC51-0006VG-Jv for grub-devel@gnu.org; Thu, 28 Oct 2021 16:32:59 -0400 Received: from mail-lf1-f45.google.com ([209.85.167.45]:37416) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mgC4x-0004W9-83 for grub-devel@gnu.org; Thu, 28 Oct 2021 16:32:53 -0400 Received: by mail-lf1-f45.google.com with SMTP id i13so6595123lfe.4 for ; Thu, 28 Oct 2021 13:32:50 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=E2L84hw3p7+ZKRueVkU+u1VmQGGc1vrBu/HDxV6XP4w=; b=aNfDPJrsssCravSgCYQ3RkJtjXCc5zkkcztrr5CGRY9vbHAnK3mZynR6FIX7pG/qMQ P7tb2ZmFeXDRh2XAw7PLjJjQb8O32wKY++waHvtpFkPmrZ9JhQSVOOzYaA+EHDWrPDNn aJukE2GxizD1DLl1NM4dDsJyHyvVp2j78gzDAJ3nmx4dFCJ8S1WskrcgPgVwx2cJEUUS 0M+oxj9CcvlLDsi32Pk1MkZuuxm2Qs3wQP7rFRzCUtvwqX2+f5q2ABs+eK6MIvuWEwmW CS4WYgsNDu9rjm9gB1moDvPSHL+xoMfvxoZ4L3PNwd92k2hMq3xfU7qn3LzzDw9eCjxN QYyA== X-Gm-Message-State: AOAM5329ARNr3mIHdbMJpzMFravoqaeyEBeMHoSxwt/ErXjVQqqbk2qZ r+qou+cdkqaHeIwcl/Wx/N60W1bPb4IMpoVX X-Google-Smtp-Source: ABdhPJw5o3BDHIg++AvJuOM3M8dUcbw77rpypmqyOFPeyuoaaO+5sxoHUihnYPGKDUecFNXIrHgPHA== X-Received: by 2002:ac2:5331:: with SMTP id f17mr6191520lfh.40.1635453169550; Thu, 28 Oct 2021 13:32:49 -0700 (PDT) Received: from amanita.localdomain ([2a00:1370:811f:5cd1:1618:c3ff:fe69:39f3]) by smtp.gmail.com with ESMTPSA id v22sm291719lfr.175.2021.10.28.13.32.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 Oct 2021 13:32:49 -0700 (PDT) From: Nikita Ermakov To: GRUB development mailing list Cc: Ard Biesheuvel , Atish Patra , Daniel Kiper , Heinrich Schuchardt , Leif Lindholm , Fu Wei , Nikita Ermakov Subject: [PATCH v3 3/7] efi: implemented LoadFile2 initrd loading protocol for Linux Date: Thu, 28 Oct 2021 23:31:16 +0300 Message-Id: <20211028203118.7908-4-arei@altlinux.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211028203118.7908-1-arei@altlinux.org> References: <20211028203118.7908-1-arei@altlinux.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=209.85.167.45; envelope-from=coffe92@gmail.com; helo=mail-lf1-f45.google.com X-Spam_score_int: -11 X-Spam_score: -1.2 X-Spam_bar: - X-Spam_report: (-1.2 / 5.0 requ) BAYES_00=-1.9, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FORGED_FROMDOMAIN=0.249, FREEMAIL_FROM=0.001, HEADER_FROM_DIFFERENT_DOMAINS=0.25, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Oct 2021 20:32:59 -0000 From: Ard Biesheuvel Recent Linux kernels will invoke the LoadFile2 protocol installed on a well-known vendor media path to load the initrd if it is exposed by the firmware. Using this method is preferred for two reasons: - the Linux kernel is in charge of allocating the memory, and so it can implement any placement policy it wants (given that these tend to change between kernel versions), - it is no longer necessary to modify the device tree provided by the firmware. So let's install this protocol when handling the 'initrd' command if such a recent kernel was detected (based on the PE/COFF image version), and defer loading the initrd contents until the point where the kernel invokes the LoadFile2 protocol. Signed-off-by: Ard Biesheuvel Signed-off-by: Nikita Ermakov --- grub-core/loader/arm64/linux.c | 117 ++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c index aed7a200b..6b03455d1 100644 --- a/grub-core/loader/arm64/linux.c +++ b/grub-core/loader/arm64/linux.c @@ -48,9 +48,18 @@ static grub_uint32_t cmdline_size; static grub_addr_t initrd_start; static grub_addr_t initrd_end; +static struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 }; +static grub_efi_handle_t initrd_lf2_handle; +static int initrd_use_loadfile2; +static grub_efi_guid_t load_file2_guid = GRUB_EFI_LOAD_FILE2_PROTOCOL_GUID; +static grub_efi_guid_t device_path_guid = GRUB_EFI_DEVICE_PATH_GUID; + grub_err_t grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh) { + struct grub_pe32_coff_header *coff_header; + struct grub_pe32_optional_header *optional_header; + if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE) return grub_error(GRUB_ERR_BAD_OS, "invalid magic number"); @@ -61,6 +70,21 @@ grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh) grub_dprintf ("linux", "UEFI stub kernel:\n"); grub_dprintf ("linux", "PE/COFF header @ %08x\n", lh->hdr_offset); + coff_header = (struct grub_pe32_coff_header *)((unsigned long)lh + lh->hdr_offset); + optional_header = (struct grub_pe32_optional_header *)(coff_header + 1); + + /* + * Linux kernels built for any architecture are guaranteed to support the + * LoadFile2 based initrd loading protocol if the image version is >= 1. + */ + if (optional_header->major_image_version >= 1) + initrd_use_loadfile2 = 1; + else + initrd_use_loadfile2 = 0; + + grub_dprintf ("linux", "LoadFile2 initrd loading %sabled\n", + initrd_use_loadfile2 ? "en" : "dis"); + return GRUB_ERR_NONE; } @@ -230,13 +254,86 @@ allocate_initrd_mem (int initrd_pages) GRUB_EFI_LOADER_DATA); } +struct initrd_media_device_path { + grub_efi_vendor_media_device_path_t vendor; + grub_efi_device_path_t end; +} GRUB_PACKED; + +#define LINUX_EFI_INITRD_MEDIA_GUID \ + { 0x5568e427, 0x68fc, 0x4f3d, \ + { 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68 } \ + } + +static struct initrd_media_device_path initrd_lf2_device_path = { + { + { + GRUB_EFI_MEDIA_DEVICE_PATH_TYPE, + GRUB_EFI_VENDOR_MEDIA_DEVICE_PATH_SUBTYPE, + sizeof(grub_efi_vendor_media_device_path_t), + }, + LINUX_EFI_INITRD_MEDIA_GUID + }, { + GRUB_EFI_END_DEVICE_PATH_TYPE, + GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE, + sizeof(grub_efi_device_path_t) + } +}; + +static grub_efi_status_t +grub_efi_initrd_load_file2(grub_efi_load_file2_t *this, + grub_efi_device_path_t *device_path, + grub_efi_boolean_t boot_policy, + grub_efi_uintn_t *buffer_size, + void *buffer); + +static grub_efi_load_file2_t initrd_lf2 = { + grub_efi_initrd_load_file2 +}; + +static grub_efi_status_t +grub_efi_initrd_load_file2(grub_efi_load_file2_t *this, + grub_efi_device_path_t *device_path, + grub_efi_boolean_t boot_policy, + grub_efi_uintn_t *buffer_size, + void *buffer) +{ + grub_efi_status_t status = GRUB_EFI_SUCCESS; + grub_efi_uintn_t initrd_size; + + if (!this || this != &initrd_lf2 || !buffer_size) + return GRUB_EFI_INVALID_PARAMETER; + + if (device_path->type != GRUB_EFI_END_DEVICE_PATH_TYPE || + device_path->subtype != GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE) + return GRUB_EFI_NOT_FOUND; + + if (boot_policy) + return GRUB_EFI_UNSUPPORTED; + + initrd_size = grub_get_initrd_size (&initrd_ctx); + if (!buffer || *buffer_size < initrd_size) + { + *buffer_size = initrd_size; + return GRUB_EFI_BUFFER_TOO_SMALL; + } + + grub_dprintf ("linux", "Providing initrd via LOAD_FILE2_PROTOCOL\n"); + + if (grub_initrd_load (&initrd_ctx, buffer)) + status = GRUB_EFI_LOAD_ERROR; + + grub_initrd_close (&initrd_ctx); + return status; +} + static grub_err_t grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { - struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 }; int initrd_size, initrd_pages; void *initrd_mem = NULL; + grub_efi_boot_services_t *b; + grub_efi_status_t status; if (argc == 0) { @@ -254,6 +351,24 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (grub_initrd_init (argc, argv, &initrd_ctx)) goto fail; + if (initrd_use_loadfile2 && !initrd_lf2_handle) + { + b = grub_efi_system_table->boot_services; + status = b->install_multiple_protocol_interfaces (&initrd_lf2_handle, + &load_file2_guid, + &initrd_lf2, + &device_path_guid, + &initrd_lf2_device_path, + NULL); + if (status == GRUB_EFI_OUT_OF_RESOURCES) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + return grub_errno; + } + grub_dprintf ("linux", "LoadFile2 initrd loading protocol installed\n"); + return GRUB_ERR_NONE; + } + initrd_size = grub_get_initrd_size (&initrd_ctx); grub_dprintf ("linux", "Loading initrd\n"); -- 2.33.1