18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Extensible Firmware Interface 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Based on Extensible Firmware Interface Specification version 1.0 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 1999 VA Linux Systems 88c2ecf20Sopenharmony_ci * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> 98c2ecf20Sopenharmony_ci * Copyright (C) 1999-2002 Hewlett-Packard Co. 108c2ecf20Sopenharmony_ci * David Mosberger-Tang <davidm@hpl.hp.com> 118c2ecf20Sopenharmony_ci * Stephane Eranian <eranian@hpl.hp.com> 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * All EFI Runtime Services are not implemented yet as EFI only 148c2ecf20Sopenharmony_ci * supports physical mode addressing on SoftSDV. This is to be fixed 158c2ecf20Sopenharmony_ci * in a future version. --drummond 1999-07-20 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Implemented EFI runtime services and virtual mode calls. --davidm 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Goutham Rao: <goutham.rao@intel.com> 208c2ecf20Sopenharmony_ci * Skip non-WB memory and ignore empty memory ranges. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/kernel.h> 248c2ecf20Sopenharmony_ci#include <linux/types.h> 258c2ecf20Sopenharmony_ci#include <linux/ioport.h> 268c2ecf20Sopenharmony_ci#include <linux/efi.h> 278c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <asm/io.h> 308c2ecf20Sopenharmony_ci#include <asm/desc.h> 318c2ecf20Sopenharmony_ci#include <asm/page.h> 328c2ecf20Sopenharmony_ci#include <asm/set_memory.h> 338c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 348c2ecf20Sopenharmony_ci#include <asm/efi.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_civoid __init efi_map_region(efi_memory_desc_t *md) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci u64 start_pfn, end_pfn, end; 398c2ecf20Sopenharmony_ci unsigned long size; 408c2ecf20Sopenharmony_ci void *va; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci start_pfn = PFN_DOWN(md->phys_addr); 438c2ecf20Sopenharmony_ci size = md->num_pages << PAGE_SHIFT; 448c2ecf20Sopenharmony_ci end = md->phys_addr + size; 458c2ecf20Sopenharmony_ci end_pfn = PFN_UP(end); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (pfn_range_is_mapped(start_pfn, end_pfn)) { 488c2ecf20Sopenharmony_ci va = __va(md->phys_addr); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (!(md->attribute & EFI_MEMORY_WB)) 518c2ecf20Sopenharmony_ci set_memory_uc((unsigned long)va, md->num_pages); 528c2ecf20Sopenharmony_ci } else { 538c2ecf20Sopenharmony_ci va = ioremap_cache(md->phys_addr, size); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci md->virt_addr = (unsigned long)va; 578c2ecf20Sopenharmony_ci if (!va) 588c2ecf20Sopenharmony_ci pr_err("ioremap of 0x%llX failed!\n", md->phys_addr); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * To make EFI call EFI runtime service in physical addressing mode we need 638c2ecf20Sopenharmony_ci * prolog/epilog before/after the invocation to claim the EFI runtime service 648c2ecf20Sopenharmony_ci * handler exclusively and to duplicate a memory mapping in low memory space, 658c2ecf20Sopenharmony_ci * say 0 - 3G. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ciint __init efi_alloc_page_tables(void) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_civoid efi_sync_low_kernel_mappings(void) {} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_civoid __init efi_dump_pagetable(void) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci#ifdef CONFIG_EFI_PGT_DUMP 788c2ecf20Sopenharmony_ci ptdump_walk_pgd_level(NULL, &init_mm); 798c2ecf20Sopenharmony_ci#endif 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ciint __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci return 0; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_civoid __init efi_map_region_fixed(efi_memory_desc_t *md) {} 888c2ecf20Sopenharmony_civoid __init parse_efi_setup(u64 phys_addr, u32 data_len) {} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ciefi_status_t efi_call_svam(efi_runtime_services_t * const *, 918c2ecf20Sopenharmony_ci u32, u32, u32, void *, u32); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ciefi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size, 948c2ecf20Sopenharmony_ci unsigned long descriptor_size, 958c2ecf20Sopenharmony_ci u32 descriptor_version, 968c2ecf20Sopenharmony_ci efi_memory_desc_t *virtual_map, 978c2ecf20Sopenharmony_ci unsigned long systab_phys) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci const efi_system_table_t *systab = (efi_system_table_t *)systab_phys; 1008c2ecf20Sopenharmony_ci struct desc_ptr gdt_descr; 1018c2ecf20Sopenharmony_ci efi_status_t status; 1028c2ecf20Sopenharmony_ci unsigned long flags; 1038c2ecf20Sopenharmony_ci pgd_t *save_pgd; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* Current pgd is swapper_pg_dir, we'll restore it later: */ 1068c2ecf20Sopenharmony_ci save_pgd = swapper_pg_dir; 1078c2ecf20Sopenharmony_ci load_cr3(initial_page_table); 1088c2ecf20Sopenharmony_ci __flush_tlb_all(); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci gdt_descr.address = get_cpu_gdt_paddr(0); 1118c2ecf20Sopenharmony_ci gdt_descr.size = GDT_SIZE - 1; 1128c2ecf20Sopenharmony_ci load_gdt(&gdt_descr); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* Disable interrupts around EFI calls: */ 1158c2ecf20Sopenharmony_ci local_irq_save(flags); 1168c2ecf20Sopenharmony_ci status = efi_call_svam(&systab->runtime, 1178c2ecf20Sopenharmony_ci memory_map_size, descriptor_size, 1188c2ecf20Sopenharmony_ci descriptor_version, virtual_map, 1198c2ecf20Sopenharmony_ci __pa(&efi.runtime)); 1208c2ecf20Sopenharmony_ci local_irq_restore(flags); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci load_fixmap_gdt(0); 1238c2ecf20Sopenharmony_ci load_cr3(save_pgd); 1248c2ecf20Sopenharmony_ci __flush_tlb_all(); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return status; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_civoid __init efi_runtime_update_mappings(void) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci if (__supported_pte_mask & _PAGE_NX) { 1328c2ecf20Sopenharmony_ci efi_memory_desc_t *md; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* Make EFI runtime service code area executable */ 1358c2ecf20Sopenharmony_ci for_each_efi_memory_desc(md) { 1368c2ecf20Sopenharmony_ci if (md->type != EFI_RUNTIME_SERVICES_CODE) 1378c2ecf20Sopenharmony_ci continue; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci set_memory_x(md->virt_addr, md->num_pages); 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci} 143