2014-04-16 05:59:30 +04:00
/*
* Extensible Firmware Interface
*
* Based on Extensible Firmware Interface Specification version 2.4
*
* Copyright ( C ) 2013 , 2014 Linaro Ltd .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
*/
2014-10-04 19:46:43 +04:00
# include <linux/dmi.h>
2014-04-16 05:59:30 +04:00
# include <linux/efi.h>
# include <linux/export.h>
# include <linux/memblock.h>
# include <linux/bootmem.h>
# include <linux/of.h>
# include <linux/of_fdt.h>
# include <linux/sched.h>
# include <linux/slab.h>
# include <asm/cacheflush.h>
# include <asm/efi.h>
# include <asm/tlbflush.h>
# include <asm/mmu_context.h>
struct efi_memory_map memmap ;
static efi_runtime_services_t * runtime ;
static u64 efi_system_table ;
static int uefi_debug __initdata ;
static int __init uefi_debug_setup ( char * str )
{
uefi_debug = 1 ;
return 0 ;
}
early_param ( " uefi_debug " , uefi_debug_setup ) ;
static int __init is_normal_ram ( efi_memory_desc_t * md )
{
if ( md - > attribute & EFI_MEMORY_WB )
return 1 ;
return 0 ;
}
static void __init efi_setup_idmap ( void )
{
struct memblock_region * r ;
efi_memory_desc_t * md ;
u64 paddr , npages , size ;
for_each_memblock ( memory , r )
create_id_mapping ( r - > base , r - > size , 0 ) ;
/* map runtime io spaces */
for_each_efi_memory_desc ( & memmap , md ) {
if ( ! ( md - > attribute & EFI_MEMORY_RUNTIME ) | | is_normal_ram ( md ) )
continue ;
paddr = md - > phys_addr ;
npages = md - > num_pages ;
memrange_efi_to_native ( & paddr , & npages ) ;
size = npages < < PAGE_SHIFT ;
create_id_mapping ( paddr , size , 1 ) ;
}
}
static int __init uefi_init ( void )
{
efi_char16_t * c16 ;
char vendor [ 100 ] = " unknown " ;
int i , retval ;
efi . systab = early_memremap ( efi_system_table ,
sizeof ( efi_system_table_t ) ) ;
if ( efi . systab = = NULL ) {
pr_warn ( " Unable to map EFI system table. \n " ) ;
return - ENOMEM ;
}
set_bit ( EFI_BOOT , & efi . flags ) ;
set_bit ( EFI_64BIT , & efi . flags ) ;
/*
* Verify the EFI Table
*/
if ( efi . systab - > hdr . signature ! = EFI_SYSTEM_TABLE_SIGNATURE ) {
pr_err ( " System table signature incorrect \n " ) ;
2014-08-14 13:15:29 +04:00
retval = - EINVAL ;
goto out ;
2014-04-16 05:59:30 +04:00
}
if ( ( efi . systab - > hdr . revision > > 16 ) < 2 )
pr_warn ( " Warning: EFI system table version %d.%02d, expected 2.00 or greater \n " ,
efi . systab - > hdr . revision > > 16 ,
efi . systab - > hdr . revision & 0xffff ) ;
/* Show what we know for posterity */
c16 = early_memremap ( efi . systab - > fw_vendor ,
sizeof ( vendor ) ) ;
if ( c16 ) {
for ( i = 0 ; i < ( int ) sizeof ( vendor ) - 1 & & * c16 ; + + i )
vendor [ i ] = c16 [ i ] ;
vendor [ i ] = ' \0 ' ;
2014-08-14 13:15:29 +04:00
early_memunmap ( c16 , sizeof ( vendor ) ) ;
2014-04-16 05:59:30 +04:00
}
pr_info ( " EFI v%u.%.02u by %s \n " ,
efi . systab - > hdr . revision > > 16 ,
efi . systab - > hdr . revision & 0xffff , vendor ) ;
retval = efi_config_init ( NULL ) ;
2014-08-14 13:15:29 +04:00
out :
2014-04-16 05:59:30 +04:00
early_memunmap ( efi . systab , sizeof ( efi_system_table_t ) ) ;
return retval ;
}
/*
* Return true for RAM regions we want to permanently reserve .
*/
static __init int is_reserve_region ( efi_memory_desc_t * md )
{
2014-10-20 17:31:57 +04:00
switch ( md - > type ) {
case EFI_LOADER_CODE :
case EFI_LOADER_DATA :
case EFI_BOOT_SERVICES_CODE :
case EFI_BOOT_SERVICES_DATA :
case EFI_CONVENTIONAL_MEMORY :
2014-04-16 05:59:30 +04:00
return 0 ;
2014-10-20 17:31:57 +04:00
default :
break ;
}
return is_normal_ram ( md ) ;
2014-04-16 05:59:30 +04:00
}
static __init void reserve_regions ( void )
{
efi_memory_desc_t * md ;
u64 paddr , npages , size ;
if ( uefi_debug )
pr_info ( " Processing EFI memory map: \n " ) ;
for_each_efi_memory_desc ( & memmap , md ) {
paddr = md - > phys_addr ;
npages = md - > num_pages ;
2014-09-03 15:32:23 +04:00
if ( uefi_debug ) {
char buf [ 64 ] ;
pr_info ( " 0x%012llx-0x%012llx %s " ,
2014-04-16 05:59:30 +04:00
paddr , paddr + ( npages < < EFI_PAGE_SHIFT ) - 1 ,
2014-09-03 15:32:23 +04:00
efi_md_typeattr_format ( buf , sizeof ( buf ) , md ) ) ;
}
2014-04-16 05:59:30 +04:00
memrange_efi_to_native ( & paddr , & npages ) ;
size = npages < < PAGE_SHIFT ;
if ( is_normal_ram ( md ) )
early_init_dt_add_memory_arch ( paddr , size ) ;
if ( is_reserve_region ( md ) | |
md - > type = = EFI_BOOT_SERVICES_CODE | |
md - > type = = EFI_BOOT_SERVICES_DATA ) {
memblock_reserve ( paddr , size ) ;
if ( uefi_debug )
pr_cont ( " * " ) ;
}
if ( uefi_debug )
pr_cont ( " \n " ) ;
}
2014-07-28 22:03:03 +04:00
set_bit ( EFI_MEMMAP , & efi . flags ) ;
2014-04-16 05:59:30 +04:00
}
static u64 __init free_one_region ( u64 start , u64 end )
{
u64 size = end - start ;
if ( uefi_debug )
pr_info ( " EFI freeing: 0x%012llx-0x%012llx \n " , start , end - 1 ) ;
free_bootmem_late ( start , size ) ;
return size ;
}
static u64 __init free_region ( u64 start , u64 end )
{
u64 map_start , map_end , total = 0 ;
if ( end < = start )
return total ;
map_start = ( u64 ) memmap . phys_map ;
map_end = PAGE_ALIGN ( map_start + ( memmap . map_end - memmap . map ) ) ;
map_start & = PAGE_MASK ;
if ( start < map_end & & end > map_start ) {
/* region overlaps UEFI memmap */
if ( start < map_start )
total + = free_one_region ( start , map_start ) ;
if ( map_end < end )
total + = free_one_region ( map_end , end ) ;
} else
total + = free_one_region ( start , end ) ;
return total ;
}
static void __init free_boot_services ( void )
{
u64 total_freed = 0 ;
u64 keep_end , free_start , free_end ;
efi_memory_desc_t * md ;
/*
* If kernel uses larger pages than UEFI , we have to be careful
* not to inadvertantly free memory we want to keep if there is
* overlap at the kernel page size alignment . We do not want to
* free is_reserve_region ( ) memory nor the UEFI memmap itself .
*
* The memory map is sorted , so we keep track of the end of
* any previous region we want to keep , remember any region
* we want to free and defer freeing it until we encounter
* the next region we want to keep . This way , before freeing
* it , we can clip it as needed to avoid freeing memory we
* want to keep for UEFI .
*/
keep_end = 0 ;
free_start = 0 ;
for_each_efi_memory_desc ( & memmap , md ) {
u64 paddr , npages , size ;
if ( is_reserve_region ( md ) ) {
/*
* We don ' t want to free any memory from this region .
*/
if ( free_start ) {
/* adjust free_end then free region */
if ( free_end > md - > phys_addr )
free_end - = PAGE_SIZE ;
total_freed + = free_region ( free_start , free_end ) ;
free_start = 0 ;
}
keep_end = md - > phys_addr + ( md - > num_pages < < EFI_PAGE_SHIFT ) ;
continue ;
}
if ( md - > type ! = EFI_BOOT_SERVICES_CODE & &
md - > type ! = EFI_BOOT_SERVICES_DATA ) {
/* no need to free this region */
continue ;
}
/*
* We want to free memory from this region .
*/
paddr = md - > phys_addr ;
npages = md - > num_pages ;
memrange_efi_to_native ( & paddr , & npages ) ;
size = npages < < PAGE_SHIFT ;
if ( free_start ) {
if ( paddr < = free_end )
free_end = paddr + size ;
else {
total_freed + = free_region ( free_start , free_end ) ;
free_start = paddr ;
free_end = paddr + size ;
}
} else {
free_start = paddr ;
free_end = paddr + size ;
}
if ( free_start < keep_end ) {
free_start + = PAGE_SIZE ;
if ( free_start > = free_end )
free_start = 0 ;
}
}
if ( free_start )
total_freed + = free_region ( free_start , free_end ) ;
if ( total_freed )
pr_info ( " Freed 0x%llx bytes of EFI boot services memory " ,
total_freed ) ;
}
void __init efi_init ( void )
{
struct efi_fdt_params params ;
/* Grab UEFI information placed in FDT by stub */
if ( ! efi_get_fdt_params ( & params , uefi_debug ) )
return ;
efi_system_table = params . system_table ;
memblock_reserve ( params . mmap & PAGE_MASK ,
PAGE_ALIGN ( params . mmap_size + ( params . mmap & ~ PAGE_MASK ) ) ) ;
memmap . phys_map = ( void * ) params . mmap ;
memmap . map = early_memremap ( params . mmap , params . mmap_size ) ;
memmap . map_end = memmap . map + params . mmap_size ;
memmap . desc_size = params . desc_size ;
memmap . desc_version = params . desc_ver ;
if ( uefi_init ( ) < 0 )
return ;
reserve_regions ( ) ;
}
void __init efi_idmap_init ( void )
{
2014-05-23 17:16:56 +04:00
if ( ! efi_enabled ( EFI_BOOT ) )
return ;
2014-04-16 05:59:30 +04:00
/* boot time idmap_pg_dir is incomplete, so fill in missing parts */
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 " ) ;
return - 1 ;
}
mapsize = memmap . map_end - memmap . map ;
early_memunmap ( memmap . map , mapsize ) ;
2014-08-18 05:30:07 +04:00
if ( efi_runtime_disabled ( ) ) {
pr_info ( " EFI runtime services will be disabled. \n " ) ;
return - 1 ;
}
pr_info ( " Remapping and enabling EFI services. \n " ) ;
/* replace early memmap mapping with permanent mapping */
2014-04-16 05:59:30 +04:00
memmap . map = ( __force void * ) ioremap_cache ( ( phys_addr_t ) memmap . phys_map ,
mapsize ) ;
memmap . map_end = memmap . map + mapsize ;
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 ;
2014-07-04 19:25:09 +04:00
if ( ! remap_region ( md , & virt_md ) )
goto err_unmap ;
+ + count ;
2014-04-16 05:59:30 +04:00
}
efi . systab = ( __force void * ) efi_lookup_mapped_addr ( efi_system_table ) ;
2014-07-04 19:25:09 +04:00
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 ;
}
set_bit ( EFI_SYSTEM_TABLES , & efi . flags ) ;
2014-04-16 05:59:30 +04:00
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 ;
2014-07-04 21:41:53 +04:00
efi_native_runtime_setup ( ) ;
2014-04-16 05:59:30 +04:00
set_bit ( EFI_RUNTIME_SERVICES , & efi . flags ) ;
2014-08-15 17:22:44 +04:00
efi . runtime_version = efi . systab - > hdr . revision ;
2014-04-16 05:59:30 +04:00
return 0 ;
2014-07-04 19:25:09 +04:00
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 ;
2014-04-16 05:59:30 +04:00
}
early_initcall ( arm64_enter_virtual_mode ) ;
2014-10-04 19:46:43 +04:00
static int __init arm64_dmi_init ( void )
{
/*
* On arm64 , DMI depends on UEFI , and dmi_scan_machine ( ) needs to
* be called early because dmi_id_init ( ) , which is an arch_initcall
* itself , depends on dmi_scan_machine ( ) having been called already .
*/
dmi_scan_machine ( ) ;
return 0 ;
}
core_initcall ( arm64_dmi_init ) ;