From patchwork Wed Feb 5 17:04:00 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Leif Lindholm X-Patchwork-Id: 3588051 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id A78D1C02DC for ; Wed, 5 Feb 2014 18:04:04 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 951D120154 for ; Wed, 5 Feb 2014 18:04:03 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5C42920149 for ; Wed, 5 Feb 2014 18:04:02 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WB5wu-0004P3-1D; Wed, 05 Feb 2014 17:07:45 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1WB5wG-0001mS-GR; Wed, 05 Feb 2014 17:07:04 +0000 Received: from mail-wg0-f46.google.com ([74.125.82.46]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WB5ux-0001YT-Kn for linux-arm-kernel@lists.infradead.org; Wed, 05 Feb 2014 17:05:51 +0000 Received: by mail-wg0-f46.google.com with SMTP id x12so489050wgg.25 for ; Wed, 05 Feb 2014 09:05:21 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=no75gOso99ve3RUf61J1TyXA06+Q3FqVeFvP9+KUjP4=; b=Zdf8nyHZWvhqhdpgI1koKRfwjySO7qHFkEMejAsJa/MsCtYMJT0N78si9quRP4fZat odhQVBaS2x/SHODPQb3dlkTjIMNYwoaYgcTicBi2VJDdNQIlODTp/aPkAx489qVyLhg5 P8kHcDl4ZaMwXvmvjY/oJpM26jdTJp+JJz568I7k+qjsMnoh1dDJL7c9DhYtW1sAVpOI EgNgns5DatkEeKcc4Ub32e/6OpWhHCtzFB1V/LstSpTwYijN1VkllaD1DkN/qKR4a5+X HVuCYWazIs1cM7M+BjDCEMsY8ciPhFVrpWpFkIc252GyS1uR0rrOKcy4AZeK0h66Atya kuHA== X-Gm-Message-State: ALoCoQkGZuoqzC3ymHM8PO7nb+baKKgcfWyyupTEiYIQirHs2RdxgZ7q58KDAAl4BEo4d6JDDGJK X-Received: by 10.180.219.66 with SMTP id pm2mr17204379wic.60.1391619921867; Wed, 05 Feb 2014 09:05:21 -0800 (PST) Received: from mohikan.mushroom.smurfnet.nu (cpc4-cmbg17-2-0-cust71.5-4.cable.virginm.net. [86.14.224.72]) by mx.google.com with ESMTPSA id p1sm47427211wie.1.2014.02.05.09.05.20 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 05 Feb 2014 09:05:21 -0800 (PST) From: Leif Lindholm To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-efi@vger.kernel.org Subject: [PATCH 09/22] Add shared arm/arm64 EFI stub Date: Wed, 5 Feb 2014 17:04:00 +0000 Message-Id: <1391619853-10601-10-git-send-email-leif.lindholm@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org> References: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140205_120544_112636_B4D9E773 X-CRM114-Status: GOOD ( 25.25 ) X-Spam-Score: -2.6 (--) Cc: Roy Franz , Leif Lindholm , patches@linaro.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.7 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Roy Franz This patch adds the EFI stub entry point that is shared by the arm/arm64 architectures. Each arch will implement the handle_kernel_image() function that handles the arch specific load address and boot protocol requirements. Signed-off-by: Roy Franz Signed-off-by: Leif Lindholm --- drivers/firmware/efi/arm-stub.c | 145 +++++++++++++++++++++++++++++++++++++++ drivers/firmware/efi/fdt.c | 31 +++++++-- 2 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 drivers/firmware/efi/arm-stub.c diff --git a/drivers/firmware/efi/arm-stub.c b/drivers/firmware/efi/arm-stub.c new file mode 100644 index 0000000..aefe963 --- /dev/null +++ b/drivers/firmware/efi/arm-stub.c @@ -0,0 +1,145 @@ +/* + * EFI stub implementation that is shared by arm and arm64 architectures. + * This should be #included by the EFI stub implementation files. + * + * Copyright (C) 2013,2014 Linaro Limited + * Roy Franz + * + * This file is part of the Linux kernel, and is made available under the + * terms of the GNU General Public License version 2. + * + */ + +/* + * This function handles the architcture specific differences between arm and + * arm64 regarding where the kernel image must be loaded and any memory that + * must be reserved. On failure it is required to free all + * all allocations it has made. + */ +static efi_status_t handle_kernel_image(efi_system_table_t *sys_table, + unsigned long *image_addr, + unsigned long *image_size, + unsigned long *reserve_addr, + unsigned long *reserve_size, + unsigned long dram_base, + efi_loaded_image_t *image); +/* + * EFI entry point for the arm/arm64 EFI stubs. This is the entrypoint + * that is described in the PE/COFF header. Most of the code is the same + * for both archictectures, with the arch-specific code provided in the + * handle_kernel_image() function. + */ +unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, + unsigned long *image_addr) +{ + efi_loaded_image_t *image; + efi_status_t status; + unsigned long image_size = 0; + unsigned long dram_base; + /* addr/point and size pairs for memory management*/ + unsigned long initrd_addr; + u64 initrd_size = 0; + unsigned long fdt_addr; /* Original DTB */ + u64 fdt_size = 0; /* We don't get size from configuration table */ + char *cmdline_ptr = NULL; + int cmdline_size = 0; + unsigned long new_fdt_addr; + efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID; + unsigned long reserve_addr = 0; + unsigned long reserve_size = 0; + + /* Check if we were booted by the EFI firmware */ + if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) + goto fail; + + pr_efi(sys_table, "Booting Linux Kernel...\n"); + + /* + * Get a handle to the loaded image protocol. This is used to get + * information about the running image, such as size and the command + * line. + */ + status = efi_call_phys3(sys_table->boottime->handle_protocol, + handle, &loaded_image_proto, (void *)&image); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table, "Failed to get loaded image protocol\n"); + goto fail; + } + + dram_base = get_dram_base(sys_table); + if (dram_base == EFI_ERROR) { + pr_efi_err(sys_table, "Failed to find DRAM base\n"); + goto fail; + } + status = handle_kernel_image(sys_table, image_addr, &image_size, + &reserve_addr, + &reserve_size, + dram_base, image); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table, "Failed to relocate kernel\n"); + goto fail; + } + + /* + * Get the command line from EFI, using the LOADED_IMAGE + * protocol. We are going to copy the command line into the + * device tree, so this can be allocated anywhere. + */ + cmdline_ptr = efi_convert_cmdline_to_ascii(sys_table, image, + &cmdline_size); + if (!cmdline_ptr) { + pr_efi_err(sys_table, "getting command line via LOADED_IMAGE_PROTOCOL\n"); + goto fail_free_image; + } + + /* Load a device tree from the configuration table, if present. */ + fdt_addr = (uintptr_t)get_fdt(sys_table); + if (!fdt_addr) { + status = handle_cmdline_files(sys_table, image, cmdline_ptr, + "dtb=", + ~0UL, (unsigned long *)&fdt_addr, + (unsigned long *)&fdt_size); + + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table, "Failed to load device tree!\n"); + goto fail_free_cmdline; + } + } + + status = handle_cmdline_files(sys_table, image, cmdline_ptr, + "initrd=", dram_base + SZ_512M, + (unsigned long *)&initrd_addr, + (unsigned long *)&initrd_size); + if (status != EFI_SUCCESS) + pr_efi_err(sys_table, "Failed initrd from command line!\n"); + + new_fdt_addr = fdt_addr; + status = allocate_new_fdt_and_exit_boot(sys_table, handle, + &new_fdt_addr, dram_base + MAX_FDT_OFFSET, + initrd_addr, initrd_size, cmdline_ptr, + fdt_addr, fdt_size); + + /* + * If all went well, we need to return the FDT address to the + * calling function so it can be passed to kernel as part of + * the kernel boot protocol. + */ + if (status == EFI_SUCCESS) + return new_fdt_addr; + + pr_efi_err(sys_table, "Failed to update FDT and exit boot services\n"); + + efi_free(sys_table, initrd_size, initrd_addr); + efi_free(sys_table, fdt_size, fdt_addr); + +fail_free_cmdline: + efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr); + +fail_free_image: + efi_free(sys_table, image_size, *image_addr); + efi_free(sys_table, reserve_size, reserve_addr); +fail: + return EFI_ERROR; +} diff --git a/drivers/firmware/efi/fdt.c b/drivers/firmware/efi/fdt.c index a602b0a..4510f97 100644 --- a/drivers/firmware/efi/fdt.c +++ b/drivers/firmware/efi/fdt.c @@ -11,6 +11,7 @@ */ static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, + unsigned long orig_fdt_size, void *fdt, int new_fdt_size, char *cmdline_ptr, u64 initrd_addr, u64 initrd_size, efi_memory_desc_t *memory_map, @@ -32,7 +33,27 @@ static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n"; - status = fdt_open_into(orig_fdt, fdt, new_fdt_size); + /* Do some checks on provided FDT, if it exists*/ + if (orig_fdt) { + if (fdt_check_header(orig_fdt)) { + pr_efi_err(sys_table, "Device Tree header not valid!\n"); + return EFI_LOAD_ERROR; + } + /* + * We don't get the size of the FDT if we get if from a + * configuration table. + */ + if (orig_fdt_size && fdt_totalsize(orig_fdt) > orig_fdt_size) { + pr_efi_err(sys_table, "Truncated device tree! foo!\n"); + return EFI_LOAD_ERROR; + } + } + + if (orig_fdt) + status = fdt_open_into(orig_fdt, fdt, new_fdt_size); + else + status = fdt_create_empty_tree(fdt, new_fdt_size); + if (status != 0) goto fdt_set_fail; @@ -180,10 +201,10 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, goto fail_free_new_fdt; status = update_fdt(sys_table, - (void *)fdt_addr, (void *)*new_fdt_addr, - new_fdt_size, cmdline_ptr, initrd_addr, - initrd_size, memory_map, map_size, - desc_size, desc_ver); + (void *)fdt_addr, fdt_size, + (void *)*new_fdt_addr, new_fdt_size, + cmdline_ptr, initrd_addr, initrd_size, + memory_map, map_size, desc_size, desc_ver); /* Succeeding the first time is the expected case. */ if (status == EFI_SUCCESS)