From patchwork Tue Jan 22 15:06:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 156302 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp7683629jaa; Tue, 22 Jan 2019 07:06:34 -0800 (PST) X-Google-Smtp-Source: ALg8bN5VJB8ePOl2HzUjgUJFQGPDMVxZERd6LkbL4KfHnjmWV5k/ad4zxogt1scALmtd10H33z+E X-Received: by 2002:a17:902:6e0f:: with SMTP id u15mr34172244plk.175.1548169594566; Tue, 22 Jan 2019 07:06:34 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1548169594; cv=none; d=google.com; s=arc-20160816; b=K0XjEGktzytENpSVsLdMZFLEQ3RQfOuuWO2cQ6Ftru4gUaxwaVNRQobF36x5Rl+EFC eVnxoCHWt0jO0PfUQApT8fF4/W5Aq9n/vK7bBmQDv7tkWr5SFQYi/9Xig1z86ZGSApc2 VnjjS/6thzQMpC757QXJMQwXgeRhI3lqETiYXZ5/aS2w+Z5T5AQnoRF6T4kkueyhTv6q DSAIpTE9O97nJeamaf9s7grtaIA/Nvc9KifNjLv3ERQKylimzt2FxrzlWJq6EIJY9fLm SNH1/4lbED32lysSoGKzPceSn3HOZLLf6mBHl9DZ1uTsl7GE+KRwvyCLESiQxGXqLE8Y NiGA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=UOYKuSL5Mc3+i6V5yuN8VGLaRYUHqSjx2EoNQxQQYCw=; b=VnbQ0CVC443reH1Dl3LihtRES1Sg4B/w9eWsItceqcGK4oKNhflztpNn9E4YMpYD8X EEOwomUiqVKDS/XavsA5sLARtMVGXdQNPFHHckDo9ucTHGqadLhLE+oe8v77TJx51NJ3 kAE99ttRiDVg5XUbRfQ+8r/ZCW136yP//LiAeFBLEG9pU9u+zK9WobZdl1GBykiocOzF 7ydQNNIKy6Xo0rd9YWiSYXBc6rwvt6u5YQiCs3chO2HE7tfDxWXrQG3oJolOaImQukdb nsjpNuUJ5uIQyn44fQz9P5Av2/HYiAcAfNWOw8FzPDOhyr2WZUwO3xv2zDnnKvxQDnwE RwCw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=b2Li2h6b; spf=pass (google.com: best guess record for domain of linux-efi-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-efi-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id k11si16001726plt.68.2019.01.22.07.06.34; Tue, 22 Jan 2019 07:06:34 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-efi-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=b2Li2h6b; spf=pass (google.com: best guess record for domain of linux-efi-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-efi-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728934AbfAVPGe (ORCPT + 3 others); Tue, 22 Jan 2019 10:06:34 -0500 Received: from mail-wm1-f66.google.com ([209.85.128.66]:55137 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728687AbfAVPGd (ORCPT ); Tue, 22 Jan 2019 10:06:33 -0500 Received: by mail-wm1-f66.google.com with SMTP id a62so14483557wmh.4 for ; Tue, 22 Jan 2019 07:06:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=UOYKuSL5Mc3+i6V5yuN8VGLaRYUHqSjx2EoNQxQQYCw=; b=b2Li2h6bMiShx34TjIsFU/nm1RM4QxumLNL/RbWat606XkA11x17nbXRzYoh5KGPPA ORLFLzGm7kBro+GJ40vArFXa2F1z3/NQ8shK0F17NzNtrWfZSKsETzMF7acQGhDcU+pI Oxzfu3Znc93LtjyebaEon3IrQkpIQurTiFjlo= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=UOYKuSL5Mc3+i6V5yuN8VGLaRYUHqSjx2EoNQxQQYCw=; b=fj1Ajyim1xsmMzWoRQ1fnX64/5HQbGfNaoVdQia1VGOXTTvHD7lLwB/3RrFgGAuGkH hxXGdeyeIRsDA6s5z5QycIG/h9VZ0q05kfKKKj2DyIEo6T7hdvAV6r+lIdMqgNPz+mOn f0bj0n1H8W/Spmse3MjB4p1fktTAm/x/GgplwSFRT0AoXB36/k6J0qm7HkWMxlypR0vU 0zhvINPGaUd8HP26/7hX7Rg00DqPGR6rmdsZUveJCX1HkmyYoM2SIgyL71u8yuS9l8ST mKpXiAIgu5IWJYYmY1OdNZSFXDpZedLFXPrkcerJsmw8c4WZNU+3kLPtitQucdtpiQKS BxvQ== X-Gm-Message-State: AJcUukfeqBpT5iGFVaibMqlF+Uw35Z92BDaQ2Nxz18JS2jOGr/nHLK2a 9qykOV6ib0SJj7JDv19cOaUaVw== X-Received: by 2002:a7b:c399:: with SMTP id s25mr4264519wmj.90.1548169590997; Tue, 22 Jan 2019 07:06:30 -0800 (PST) Received: from localhost.localdomain (laubervilliers-657-1-83-120.w92-154.abo.wanadoo.fr. [92.154.90.120]) by smtp.gmail.com with ESMTPSA id b7sm88575484wrs.47.2019.01.22.07.06.29 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 22 Jan 2019 07:06:30 -0800 (PST) From: Ard Biesheuvel To: linux-acpi@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, harry.l.hsiung@intel.com, leif.lindholm@linaro.org, graeme.gregory@linaro.org, lorenzo.pieralisi@arm.com, astone@redhat.com, linux-efi@vger.kernel.org, rjw@rjwysocki.net, lenb@kernel.org, Ard Biesheuvel , Peter Jones Subject: [PATCH] acpi: bgrt: parse BGRT to obtain BMP address before it gets clobbered Date: Tue, 22 Jan 2019 16:06:16 +0100 Message-Id: <20190122150616.850-1-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Sender: linux-efi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-efi@vger.kernel.org The bitmap left in the framebuffer by the firmware is described by an ACPI table called "BGRT", which describes the size, pixel format and the address of a BMP image in memory. While the BGRT ACPI table is guaranteed to reside in a "ACPI reclaim" memory region, which is never touched by Linux. The BMP image, however, typically resides in EFI Boot Services Memory, which may have been overwritten by the time the BGRT discovery routine runs. So instead, drop the handling from the ACPI init code, and call the BGRT parsing code immediately after going over the EFI configuration table array, at which time no memory has been touched yet except for the .data/.bss regions covered by the static kernel image. Unfortunately, this involves a non-trivial amount of ACPI entry point and root table parsing, but we cannot rely on the normal ACPI infrastructure yet this early in the boot. Also note that we cannot take the 'acpi_disabled' global variable into account, since it may not have assumed the correct value yet (on arm64, the default value is '1' which is overridden to '0' if no DT description has been made available by the firmware) Cc: Peter Jones Signed-off-by: Ard Biesheuvel --- arch/arm64/kernel/acpi.c | 2 - arch/x86/kernel/acpi/boot.c | 2 - drivers/acpi/bgrt.c | 6 -- drivers/firmware/efi/efi-bgrt.c | 80 ++++++++++++++++++-- drivers/firmware/efi/efi.c | 13 ++++ include/linux/efi-bgrt.h | 4 +- 6 files changed, 89 insertions(+), 18 deletions(-) -- 2.20.1 diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 44e3c351e1ea..7429a811f76d 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -230,8 +230,6 @@ void __init acpi_boot_table_init(void) early_init_dt_scan_chosen_stdout(); } else { acpi_parse_spcr(earlycon_acpi_spcr_enable, true); - if (IS_ENABLED(CONFIG_ACPI_BGRT)) - acpi_table_parse(ACPI_SIG_BGRT, acpi_parse_bgrt); } } diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 2624de16cd7a..2d3535b62752 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1633,8 +1633,6 @@ int __init acpi_boot_init(void) acpi_process_madt(); acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet); - if (IS_ENABLED(CONFIG_ACPI_BGRT)) - acpi_table_parse(ACPI_SIG_BGRT, acpi_parse_bgrt); if (!acpi_noirq) x86_init.pci.init = pci_acpi_init; diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c index 75af78361ce5..048413e06898 100644 --- a/drivers/acpi/bgrt.c +++ b/drivers/acpi/bgrt.c @@ -81,12 +81,6 @@ static const struct attribute_group bgrt_attribute_group = { .bin_attrs = bgrt_bin_attributes, }; -int __init acpi_parse_bgrt(struct acpi_table_header *table) -{ - efi_bgrt_init(table); - return 0; -} - static int __init bgrt_init(void) { int ret; diff --git a/drivers/firmware/efi/efi-bgrt.c b/drivers/firmware/efi/efi-bgrt.c index b22ccfb0c991..8bd9b96942d2 100644 --- a/drivers/firmware/efi/efi-bgrt.c +++ b/drivers/firmware/efi/efi-bgrt.c @@ -27,24 +27,92 @@ struct bmp_header { u32 size; } __packed; -void __init efi_bgrt_init(struct acpi_table_header *table) +void __init efi_bgrt_init(unsigned long rsdp_phys) { void *image; struct bmp_header bmp_header; struct acpi_table_bgrt *bgrt = &bgrt_tab; + struct acpi_table_bgrt *table = NULL; + struct acpi_table_rsdp *rsdp; + struct acpi_table_header *hdr; + u64 xsdt_phys; + u32 rsdt_phys; + unsigned int len; - if (acpi_disabled) + if (!efi_enabled(EFI_MEMMAP)) return; - if (!efi_enabled(EFI_MEMMAP)) + /* map the root pointer table to find the xsdt/rsdt values */ + rsdp = early_memremap(rsdp_phys, sizeof(*rsdp)); + if (rsdp && ACPI_VALIDATE_RSDP_SIG(rsdp->signature)) { + xsdt_phys = rsdp->xsdt_physical_address; + rsdt_phys = rsdp->rsdt_physical_address; + } else { + WARN_ON(1); + return; + } + early_memunmap(rsdp, sizeof(*rsdp)); + + /* obtain the length of whichever table we will be using */ + hdr = early_memremap(xsdt_phys ?: rsdt_phys, sizeof(*hdr)); + if (WARN_ON(!hdr)) + return; + len = hdr->length; + early_memunmap(hdr, sizeof(*hdr)); + + if (xsdt_phys) { + struct acpi_table_xsdt *xsdt = early_memremap(xsdt_phys, len); + int i; + + if (WARN_ON(!xsdt)) + return; + + for (i = 0; i < (len - sizeof(*hdr)) / sizeof(u64); i++) { + table = early_memremap(xsdt->table_offset_entry[i], + sizeof(*table)); + if (WARN_ON(!table)) + break; + + if (ACPI_COMPARE_NAME(table->header.signature, + ACPI_SIG_BGRT)) + break; + early_memunmap(table, sizeof(*table)); + table = NULL; + } + early_memunmap(xsdt, len); + } else if (rsdt_phys) { + struct acpi_table_rsdt *rsdt = early_memremap(rsdt_phys, len); + int i; + + if (WARN_ON(!rsdt)) + return; + + for (i = 0; i < (len - sizeof(*hdr)) / sizeof(u32); i++) { + table = early_memremap(rsdt->table_offset_entry[i], + sizeof(*table)); + if (WARN_ON(!table)) + break; + + if (ACPI_COMPARE_NAME(table->header.signature, + ACPI_SIG_BGRT)) + break; + early_memunmap(table, sizeof(*table)); + table = NULL; + } + early_memunmap(rsdt, len); + } + + if (!table) return; - if (table->length < sizeof(bgrt_tab)) { + if (table->header.length < sizeof(bgrt_tab)) { pr_notice("Ignoring BGRT: invalid length %u (expected %zu)\n", - table->length, sizeof(bgrt_tab)); + table->header.length, sizeof(bgrt_tab)); return; } - *bgrt = *(struct acpi_table_bgrt *)table; + *bgrt = *table; + early_memunmap(table, sizeof(*table)); + if (bgrt->version != 1) { pr_notice("Ignoring BGRT: invalid version %u (expected 1)\n", bgrt->version); diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 4c46ff6f2242..e5ef5c0eacc1 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -592,6 +593,18 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz, early_memunmap(tbl, sizeof(*tbl)); } + + /* + * We need to parse the BGRT table (which is an ACPI table not a UEFI + * configuration table) by hand and figure out where the bitmap it + * describes lives in memory so we can reserve it early on. Otherwise, + * it may be clobbered by the time we get to it during the ordinary ACPI + * table init sequence. + */ + if (IS_ENABLED(CONFIG_ACPI_BGRT) && + efi.acpi20 != EFI_INVALID_TABLE_ADDR) + efi_bgrt_init(efi.acpi20); + return 0; } diff --git a/include/linux/efi-bgrt.h b/include/linux/efi-bgrt.h index e6cd51005633..528ea62d99ec 100644 --- a/include/linux/efi-bgrt.h +++ b/include/linux/efi-bgrt.h @@ -6,7 +6,7 @@ #ifdef CONFIG_ACPI_BGRT -void efi_bgrt_init(struct acpi_table_header *table); +void efi_bgrt_init(unsigned long rsdp_phys); int __init acpi_parse_bgrt(struct acpi_table_header *table); /* The BGRT data itself; only valid if bgrt_image != NULL. */ @@ -15,7 +15,7 @@ extern struct acpi_table_bgrt bgrt_tab; #else /* !CONFIG_ACPI_BGRT */ -static inline void efi_bgrt_init(struct acpi_table_header *table) {} +static inline void efi_bgrt_init(unsigned long rsdp_phys) {} static inline int __init acpi_parse_bgrt(struct acpi_table_header *table) { return 0;