From patchwork Thu Jul 31 14:11:49 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 34653 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-pa0-f69.google.com (mail-pa0-f69.google.com [209.85.220.69]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 2BFC620792 for ; Thu, 31 Jul 2014 14:15:20 +0000 (UTC) Received: by mail-pa0-f69.google.com with SMTP id kx10sf17721701pab.0 for ; Thu, 31 Jul 2014 07:15:12 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:subject:date:message-id:cc :precedence:list-id:list-unsubscribe:list-archive:list-post :list-help:list-subscribe:mime-version:sender:errors-to :x-original-sender:x-original-authentication-results:mailing-list :content-type:content-transfer-encoding; bh=aAB/r3k07iX3QgQpvrf8jAtE+pgUJqGWE2UecPSXyNI=; b=R2JJahpRRonCaCzaxPPHzujKWAstiuGJiXdNmBXOsIxtzyhzW87L4uhADJ8zSvJz3+ On7k3uDhVCicBD7R/KpTmyd0Eg5Ac5Vs7/iwqnlNkyxgXdBwkhyqf7OSYQiq6eBt9YFP XA7jNaZSD5PzAJtIztOdY64V3IXJ9FnquTpErzr3P5e5ViN1UVjDByAixMizrf0TZ5OQ qA8vAZ2aHIXC/aUjN2GL2Qiyl/b62jrJPWMCpOpnOOeznzjlzE6X1/8tWJRqHntC/+ZG BTh48QSLAZnJUfX0VCGV7sKDnN3QD3oTPCZxwAR71nniJ9pU78fPTGWXqLW4eVVIKLOs PggA== X-Gm-Message-State: ALoCoQmJimhtAQz3hUX54mYh+zQDN/x+jzRpDzjooDmHjrMZZOLUBo3t4nY8CmODc+K+7uVpimMI X-Received: by 10.68.241.39 with SMTP id wf7mr1725588pbc.0.1406816112344; Thu, 31 Jul 2014 07:15:12 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.89.203 with SMTP id v69ls985593qgd.6.gmail; Thu, 31 Jul 2014 07:15:12 -0700 (PDT) X-Received: by 10.220.5.138 with SMTP id 10mr11363109vcv.67.1406816112136; Thu, 31 Jul 2014 07:15:12 -0700 (PDT) Received: from mail-vc0-f178.google.com (mail-vc0-f178.google.com [209.85.220.178]) by mx.google.com with ESMTPS id go5si4480102vec.42.2014.07.31.07.15.12 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 31 Jul 2014 07:15:12 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.178 as permitted sender) client-ip=209.85.220.178; Received: by mail-vc0-f178.google.com with SMTP id la4so4329103vcb.9 for ; Thu, 31 Jul 2014 07:15:12 -0700 (PDT) X-Received: by 10.220.131.207 with SMTP id y15mr2586135vcs.71.1406816111938; Thu, 31 Jul 2014 07:15:11 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.221.37.5 with SMTP id tc5csp21662vcb; Thu, 31 Jul 2014 07:15:11 -0700 (PDT) X-Received: by 10.68.111.36 with SMTP id if4mr4683068pbb.86.1406816111035; Thu, 31 Jul 2014 07:15:11 -0700 (PDT) Received: from bombadil.infradead.org (bombadil.infradead.org. [2001:1868:205::9]) by mx.google.com with ESMTPS id pg7si6069478pbb.205.2014.07.31.07.15.10 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 31 Jul 2014 07:15:10 -0700 (PDT) Received-SPF: none (google.com: linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org does not designate permitted sender hosts) client-ip=2001:1868:205::9; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XCr6W-0002Wz-T8; Thu, 31 Jul 2014 14:13:12 +0000 Received: from mail-wi0-f177.google.com ([209.85.212.177]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XCr6M-0002Li-Vf for linux-arm-kernel@lists.infradead.org; Thu, 31 Jul 2014 14:13:11 +0000 Received: by mail-wi0-f177.google.com with SMTP id ho1so4161280wib.4 for ; Thu, 31 Jul 2014 07:11:57 -0700 (PDT) X-Received: by 10.194.19.165 with SMTP id g5mr3175782wje.65.1406815916560; Thu, 31 Jul 2014 07:11:56 -0700 (PDT) Received: from ards-macbook-pro.local (adsl21mo82.tel.net.ba. [95.156.169.82]) by mx.google.com with ESMTPSA id 20sm13639000wjt.42.2014.07.31.07.11.53 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 31 Jul 2014 07:11:55 -0700 (PDT) From: Ard Biesheuvel To: linux-efi@vger.kernel.org, linux-arm-kernel@lists.infradead.org, mark.rutland@arm.com, leif.lindholm@linaro.org, msalter@redhat.com, will.deacon@arm.com Subject: [RFC PATCH] arm64/efi: use id mapping for Runtime Services Date: Thu, 31 Jul 2014 16:11:49 +0200 Message-Id: <1406815909-26825-1-git-send-email-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 1.8.3.2 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140731_071303_327762_A8EC158C X-CRM114-Status: GOOD ( 19.81 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.212.177 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [209.85.212.177 listed in wl.mailspike.net] -0.0 RCVD_IN_MSPIKE_WL Mailspike good senders Cc: matt.fleming@intel.com, Ard Biesheuvel X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 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+patch=linaro.org@lists.infradead.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: ard.biesheuvel@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.178 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 There are 2 interesting pieces of information in the UEFI spec section 2.3.6 regarding the mapping of runtime regions: (a) the firmware should not request a virtual mapping for configuration tables, even though they are marked as EfiRuntimeServicesData; (b) calling SetVirtualAddressMap() is optional, and it is equally appropriate to call Runtime Services using an identity mapping. So we can eliminate some of the complexity around UEFI Runtime Services by not using a virtual mapping at all, and calling the services at their physical address. This is especially useful under kexec, as SetVirtualAddressMap() may only be called once, and there is no guarantee that mappings are stable between different kexec'd kernels. The fallout for other in-kernel users of UEFI data structures should be negligible, as they cannot legally access those data structures through pre-existing virtual mappings anyway (point (a) above) It should also be noted that, as the kernel side of the address space (TTBR1) is retained, the stack and pointer function arguments remain accessible to the runtime service while the id mapping is active. Signed-off-by: Ard Biesheuvel --- arch/arm64/include/asm/efi.h | 24 ++++++++-- arch/arm64/kernel/efi.c | 106 ++----------------------------------------- 2 files changed, 23 insertions(+), 107 deletions(-) diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index a34fd3b12e2b..d42a21e79b39 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -1,8 +1,10 @@ #ifndef _ASM_EFI_H #define _ASM_EFI_H +#include #include #include +#include #ifdef CONFIG_EFI extern void efi_init(void); @@ -12,23 +14,37 @@ extern void efi_idmap_init(void); #define efi_idmap_init() #endif +static inline void switch_pgd(pgd_t *pgd, struct mm_struct *mm) +{ + cpu_switch_mm(pgd, mm); + flush_tlb_all(); + if (icache_is_aivivt()) + __flush_icache_all(); +} + #define efi_call_virt(f, ...) \ ({ \ - efi_##f##_t *__f = efi.systab->runtime->f; \ + efi_##f##_t *__f; \ efi_status_t __s; \ \ - kernel_neon_begin(); \ + kernel_neon_begin(); /* disables preemption */ \ + switch_pgd(idmap_pg_dir, &init_mm); \ + __f = efi.systab->runtime->f; \ __s = __f(__VA_ARGS__); \ + switch_pgd(current->active_mm->pgd, current->active_mm); \ kernel_neon_end(); \ __s; \ }) #define __efi_call_virt(f, ...) \ ({ \ - efi_##f##_t *__f = efi.systab->runtime->f; \ + efi_##f##_t *__f; \ \ - kernel_neon_begin(); \ + kernel_neon_begin(); /* disables preemption */ \ + switch_pgd(idmap_pg_dir, &init_mm); \ + __f = efi.systab->runtime->f; \ __f(__VA_ARGS__); \ + switch_pgd(current->active_mm->pgd, current->active_mm); \ kernel_neon_end(); \ }) diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index e72f3100958f..d620a031e7bf 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -27,8 +27,6 @@ struct efi_memory_map memmap; -static efi_runtime_services_t *runtime; - static u64 efi_system_table; static int uefi_debug __initdata; @@ -340,51 +338,9 @@ void __init efi_idmap_init(void) efi_setup_idmap(); } -static int __init remap_region(efi_memory_desc_t *md, void **new) -{ - u64 paddr, vaddr, npages, size; - - paddr = md->phys_addr; - npages = md->num_pages; - memrange_efi_to_native(&paddr, &npages); - size = npages << PAGE_SHIFT; - - if (is_normal_ram(md)) - vaddr = (__force u64)ioremap_cache(paddr, size); - else - vaddr = (__force u64)ioremap(paddr, size); - - if (!vaddr) { - pr_err("Unable to remap 0x%llx pages @ %p\n", - npages, (void *)paddr); - return 0; - } - - /* adjust for any rounding when EFI and system pagesize differs */ - md->virt_addr = vaddr + (md->phys_addr - paddr); - - if (uefi_debug) - pr_info(" EFI remap 0x%012llx => %p\n", - md->phys_addr, (void *)md->virt_addr); - - memcpy(*new, md, memmap.desc_size); - *new += memmap.desc_size; - - return 1; -} - -/* - * Switch UEFI from an identity map to a kernel virtual map - */ static int __init arm64_enter_virtual_mode(void) { - efi_memory_desc_t *md; - phys_addr_t virtmap_phys; - void *virtmap, *virt_md; - efi_status_t status; u64 mapsize; - int count = 0; - unsigned long flags; if (!efi_enabled(EFI_BOOT)) { pr_info("EFI services will not be available.\n"); @@ -402,76 +358,20 @@ static int __init arm64_enter_virtual_mode(void) efi.memmap = &memmap; - /* Map the runtime regions */ - virtmap = kmalloc(mapsize, GFP_KERNEL); - if (!virtmap) { - pr_err("Failed to allocate EFI virtual memmap\n"); - return -1; - } - virtmap_phys = virt_to_phys(virtmap); - virt_md = virtmap; - - for_each_efi_memory_desc(&memmap, md) { - if (!(md->attribute & EFI_MEMORY_RUNTIME)) - continue; - if (!remap_region(md, &virt_md)) - goto err_unmap; - ++count; - } - - efi.systab = (__force void *)efi_lookup_mapped_addr(efi_system_table); + efi.systab = (__force void *)ioremap_cache(efi_system_table, + sizeof(efi_system_table_t)); if (!efi.systab) { - /* - * If we have no virtual mapping for the System Table at this - * point, the memory map doesn't cover the physical offset where - * it resides. This means the System Table will be inaccessible - * to Runtime Services themselves once the virtual mapping is - * installed. - */ pr_err("Failed to remap EFI System Table -- buggy firmware?\n"); - goto err_unmap; + return -1; } set_bit(EFI_SYSTEM_TABLES, &efi.flags); - local_irq_save(flags); - cpu_switch_mm(idmap_pg_dir, &init_mm); - - /* Call SetVirtualAddressMap with the physical address of the map */ - runtime = efi.systab->runtime; - efi.set_virtual_address_map = runtime->set_virtual_address_map; - - status = efi.set_virtual_address_map(count * memmap.desc_size, - memmap.desc_size, - memmap.desc_version, - (efi_memory_desc_t *)virtmap_phys); - cpu_set_reserved_ttbr0(); - flush_tlb_all(); - local_irq_restore(flags); - - kfree(virtmap); - free_boot_services(); - if (status != EFI_SUCCESS) { - pr_err("Failed to set EFI virtual address map! [%lx]\n", - status); - return -1; - } - /* Set up runtime services function pointers */ - runtime = efi.systab->runtime; efi_native_runtime_setup(); set_bit(EFI_RUNTIME_SERVICES, &efi.flags); return 0; - -err_unmap: - /* unmap all mappings that succeeded: there are 'count' of those */ - for (virt_md = virtmap; count--; virt_md += memmap.desc_size) { - md = virt_md; - iounmap((__force void __iomem *)md->virt_addr); - } - kfree(virtmap); - return -1; } early_initcall(arm64_enter_virtual_mode);