2019-02-02 12:41:15 +03:00
// SPDX-License-Identifier: GPL-2.0
2015-09-30 17:01:56 +03:00
/*
* fake_mem . c
*
* Copyright ( C ) 2015 FUJITSU LIMITED
* Author : Taku Izumi < izumi . taku @ jp . fujitsu . com >
*
* This code introduces new boot option named " efi_fake_mem "
* By specifying this parameter , you can add arbitrary attribute to
* specific memory range by updating original ( firmware provided ) EFI
* memmap .
*/
# include <linux/kernel.h>
# include <linux/efi.h>
# include <linux/init.h>
# include <linux/memblock.h>
# include <linux/types.h>
# include <linux/sort.h>
2019-11-07 04:43:26 +03:00
# include "fake_mem.h"
2015-09-30 17:01:56 +03:00
2019-11-07 04:43:26 +03:00
struct efi_mem_range efi_fake_mems [ EFI_MAX_FAKEMEM ] ;
int nr_fake_mem ;
2015-09-30 17:01:56 +03:00
static int __init cmp_fake_mem ( const void * x1 , const void * x2 )
{
2016-02-29 23:30:39 +03:00
const struct efi_mem_range * m1 = x1 ;
const struct efi_mem_range * m2 = x2 ;
2015-09-30 17:01:56 +03:00
if ( m1 - > range . start < m2 - > range . start )
return - 1 ;
if ( m1 - > range . start > m2 - > range . start )
return 1 ;
return 0 ;
}
2020-01-13 20:22:45 +03:00
static void __init efi_fake_range ( struct efi_mem_range * efi_range )
2015-09-30 17:01:56 +03:00
{
2020-01-13 20:22:43 +03:00
struct efi_memory_map_data data = { 0 } ;
2016-04-25 23:06:39 +03:00
int new_nr_map = efi . memmap . nr_map ;
2015-09-30 17:01:56 +03:00
efi_memory_desc_t * md ;
void * new_memmap ;
/* count up the number of EFI memory descriptor */
2020-01-13 20:22:45 +03:00
for_each_efi_memory_desc ( md )
new_nr_map + = efi_memmap_split_count ( md , & efi_range - > range ) ;
2015-09-30 17:01:56 +03:00
/* allocate memory for new EFI memmap */
2020-01-13 20:22:43 +03:00
if ( efi_memmap_alloc ( new_nr_map , & data ) ! = 0 )
2015-09-30 17:01:56 +03:00
return ;
/* create new EFI memmap */
2020-01-13 20:22:43 +03:00
new_memmap = early_memremap ( data . phys_map , data . size ) ;
2015-09-30 17:01:56 +03:00
if ( ! new_memmap ) {
2020-01-13 20:22:45 +03:00
__efi_memmap_free ( data . phys_map , data . size , data . flags ) ;
2015-09-30 17:01:56 +03:00
return ;
}
2020-01-13 20:22:45 +03:00
efi_memmap_insert ( & efi . memmap , new_memmap , efi_range ) ;
2015-09-30 17:01:56 +03:00
/* swap into new EFI memmap */
2020-01-13 20:22:43 +03:00
early_memunmap ( new_memmap , data . size ) ;
2016-02-27 00:22:05 +03:00
2020-01-13 20:22:43 +03:00
efi_memmap_install ( & data ) ;
2020-01-13 20:22:45 +03:00
}
void __init efi_fake_memmap ( void )
{
int i ;
if ( ! efi_enabled ( EFI_MEMMAP ) | | ! nr_fake_mem )
return ;
for ( i = 0 ; i < nr_fake_mem ; i + + )
efi_fake_range ( & efi_fake_mems [ i ] ) ;
2015-09-30 17:01:56 +03:00
/* print new EFI memmap */
efi_print_memmap ( ) ;
}
static int __init setup_fake_mem ( char * p )
{
u64 start = 0 , mem_size = 0 , attribute = 0 ;
int i ;
if ( ! p )
return - EINVAL ;
while ( * p ! = ' \0 ' ) {
mem_size = memparse ( p , & p ) ;
if ( * p = = ' @ ' )
start = memparse ( p + 1 , & p ) ;
else
break ;
if ( * p = = ' : ' )
attribute = simple_strtoull ( p + 1 , & p , 0 ) ;
else
break ;
if ( nr_fake_mem > = EFI_MAX_FAKEMEM )
break ;
2019-11-07 04:43:26 +03:00
efi_fake_mems [ nr_fake_mem ] . range . start = start ;
efi_fake_mems [ nr_fake_mem ] . range . end = start + mem_size - 1 ;
efi_fake_mems [ nr_fake_mem ] . attribute = attribute ;
2015-09-30 17:01:56 +03:00
nr_fake_mem + + ;
if ( * p = = ' , ' )
p + + ;
}
2019-11-07 04:43:26 +03:00
sort ( efi_fake_mems , nr_fake_mem , sizeof ( struct efi_mem_range ) ,
2015-09-30 17:01:56 +03:00
cmp_fake_mem , NULL ) ;
for ( i = 0 ; i < nr_fake_mem ; i + + )
pr_info ( " efi_fake_mem: add attr=0x%016llx to [mem 0x%016llx-0x%016llx] " ,
2019-11-07 04:43:26 +03:00
efi_fake_mems [ i ] . attribute , efi_fake_mems [ i ] . range . start ,
efi_fake_mems [ i ] . range . end ) ;
2015-09-30 17:01:56 +03:00
return * p = = ' \0 ' ? 0 : - EINVAL ;
}
early_param ( " efi_fake_mem " , setup_fake_mem ) ;