2013-09-22 15:45:27 -07:00
/*
* Helper functions used by the EFI stub on multiple
* architectures . This should be # included by the EFI stub
* implementation files .
*
* Copyright 2011 Intel Corporation ; author Matt Fleming
*
* This file is part of the Linux kernel , and is made available
* under the terms of the GNU General Public License version 2.
*
*/
# define EFI_READ_CHUNK_SIZE (1024 * 1024)
2013-09-22 15:45:40 -07:00
struct file_info {
2013-09-22 15:45:27 -07:00
efi_file_handle_t * handle ;
u64 size ;
} ;
2013-09-22 15:45:28 -07:00
static void efi_char16_printk ( efi_system_table_t * sys_table_arg ,
efi_char16_t * str )
2013-09-22 15:45:27 -07:00
{
struct efi_simple_text_output_protocol * out ;
2013-09-22 15:45:28 -07:00
out = ( struct efi_simple_text_output_protocol * ) sys_table_arg - > con_out ;
2013-09-22 15:45:27 -07:00
efi_call_phys2 ( out - > output_string , out , str ) ;
}
2013-09-22 15:45:28 -07:00
static void efi_printk ( efi_system_table_t * sys_table_arg , char * str )
2013-09-22 15:45:27 -07:00
{
char * s8 ;
for ( s8 = str ; * s8 ; s8 + + ) {
efi_char16_t ch [ 2 ] = { 0 } ;
ch [ 0 ] = * s8 ;
if ( * s8 = = ' \n ' ) {
efi_char16_t nl [ 2 ] = { ' \r ' , 0 } ;
2013-09-22 15:45:28 -07:00
efi_char16_printk ( sys_table_arg , nl ) ;
2013-09-22 15:45:27 -07:00
}
2013-09-22 15:45:28 -07:00
efi_char16_printk ( sys_table_arg , ch ) ;
2013-09-22 15:45:27 -07:00
}
}
2013-09-22 15:45:35 -07:00
static efi_status_t efi_get_memory_map ( efi_system_table_t * sys_table_arg ,
efi_memory_desc_t * * map ,
unsigned long * map_size ,
2013-09-22 15:45:36 -07:00
unsigned long * desc_size ,
u32 * desc_ver ,
unsigned long * key_ptr )
2013-09-22 15:45:27 -07:00
{
efi_memory_desc_t * m = NULL ;
efi_status_t status ;
unsigned long key ;
u32 desc_version ;
* map_size = sizeof ( * m ) * 32 ;
again :
/*
* Add an additional efi_memory_desc_t because we ' re doing an
* allocation which may be in a new descriptor region .
*/
* map_size + = sizeof ( * m ) ;
2013-09-22 15:45:28 -07:00
status = efi_call_phys3 ( sys_table_arg - > boottime - > allocate_pool ,
2013-09-22 15:45:27 -07:00
EFI_LOADER_DATA , * map_size , ( void * * ) & m ) ;
if ( status ! = EFI_SUCCESS )
goto fail ;
2013-09-22 15:45:28 -07:00
status = efi_call_phys5 ( sys_table_arg - > boottime - > get_memory_map ,
map_size , m , & key , desc_size , & desc_version ) ;
2013-09-22 15:45:27 -07:00
if ( status = = EFI_BUFFER_TOO_SMALL ) {
2013-09-22 15:45:28 -07:00
efi_call_phys1 ( sys_table_arg - > boottime - > free_pool , m ) ;
2013-09-22 15:45:27 -07:00
goto again ;
}
if ( status ! = EFI_SUCCESS )
2013-09-22 15:45:28 -07:00
efi_call_phys1 ( sys_table_arg - > boottime - > free_pool , m ) ;
2013-09-22 15:45:36 -07:00
if ( key_ptr & & status = = EFI_SUCCESS )
* key_ptr = key ;
if ( desc_ver & & status = = EFI_SUCCESS )
* desc_ver = desc_version ;
2013-09-22 15:45:27 -07:00
fail :
* map = m ;
return status ;
}
/*
* Allocate at the highest possible address that is not above ' max ' .
*/
2013-09-22 15:45:29 -07:00
static efi_status_t efi_high_alloc ( efi_system_table_t * sys_table_arg ,
2013-09-22 15:45:28 -07:00
unsigned long size , unsigned long align ,
unsigned long * addr , unsigned long max )
2013-09-22 15:45:27 -07:00
{
unsigned long map_size , desc_size ;
efi_memory_desc_t * map ;
efi_status_t status ;
unsigned long nr_pages ;
u64 max_addr = 0 ;
int i ;
2013-09-22 15:45:36 -07:00
status = efi_get_memory_map ( sys_table_arg , & map , & map_size , & desc_size ,
NULL , NULL ) ;
2013-09-22 15:45:27 -07:00
if ( status ! = EFI_SUCCESS )
goto fail ;
2013-09-22 15:45:30 -07:00
/*
* Enforce minimum alignment that EFI requires when requesting
* a specific address . We are doing page - based allocations ,
* so we must be aligned to a page .
*/
if ( align < EFI_PAGE_SIZE )
align = EFI_PAGE_SIZE ;
2013-09-22 15:45:27 -07:00
nr_pages = round_up ( size , EFI_PAGE_SIZE ) / EFI_PAGE_SIZE ;
again :
for ( i = 0 ; i < map_size / desc_size ; i + + ) {
efi_memory_desc_t * desc ;
unsigned long m = ( unsigned long ) map ;
u64 start , end ;
desc = ( efi_memory_desc_t * ) ( m + ( i * desc_size ) ) ;
if ( desc - > type ! = EFI_CONVENTIONAL_MEMORY )
continue ;
if ( desc - > num_pages < nr_pages )
continue ;
start = desc - > phys_addr ;
end = start + desc - > num_pages * ( 1UL < < EFI_PAGE_SHIFT ) ;
if ( ( start + size ) > end | | ( start + size ) > max )
continue ;
if ( end - size > max )
end = max ;
if ( round_down ( end - size , align ) < start )
continue ;
start = round_down ( end - size , align ) ;
/*
* Don ' t allocate at 0x0 . It will confuse code that
* checks pointers against NULL .
*/
if ( start = = 0x0 )
continue ;
if ( start > max_addr )
max_addr = start ;
}
if ( ! max_addr )
status = EFI_NOT_FOUND ;
else {
2013-09-22 15:45:28 -07:00
status = efi_call_phys4 ( sys_table_arg - > boottime - > allocate_pages ,
2013-09-22 15:45:27 -07:00
EFI_ALLOCATE_ADDRESS , EFI_LOADER_DATA ,
nr_pages , & max_addr ) ;
if ( status ! = EFI_SUCCESS ) {
max = max_addr ;
max_addr = 0 ;
goto again ;
}
* addr = max_addr ;
}
2013-09-22 15:45:28 -07:00
efi_call_phys1 ( sys_table_arg - > boottime - > free_pool , map ) ;
2013-09-22 15:45:27 -07:00
fail :
return status ;
}
/*
* Allocate at the lowest possible address .
*/
2013-09-22 15:45:29 -07:00
static efi_status_t efi_low_alloc ( efi_system_table_t * sys_table_arg ,
unsigned long size , unsigned long align ,
2013-09-22 15:45:27 -07:00
unsigned long * addr )
{
unsigned long map_size , desc_size ;
efi_memory_desc_t * map ;
efi_status_t status ;
unsigned long nr_pages ;
int i ;
2013-09-22 15:45:36 -07:00
status = efi_get_memory_map ( sys_table_arg , & map , & map_size , & desc_size ,
NULL , NULL ) ;
2013-09-22 15:45:27 -07:00
if ( status ! = EFI_SUCCESS )
goto fail ;
2013-09-22 15:45:30 -07:00
/*
* Enforce minimum alignment that EFI requires when requesting
* a specific address . We are doing page - based allocations ,
* so we must be aligned to a page .
*/
if ( align < EFI_PAGE_SIZE )
align = EFI_PAGE_SIZE ;
2013-09-22 15:45:27 -07:00
nr_pages = round_up ( size , EFI_PAGE_SIZE ) / EFI_PAGE_SIZE ;
for ( i = 0 ; i < map_size / desc_size ; i + + ) {
efi_memory_desc_t * desc ;
unsigned long m = ( unsigned long ) map ;
u64 start , end ;
desc = ( efi_memory_desc_t * ) ( m + ( i * desc_size ) ) ;
if ( desc - > type ! = EFI_CONVENTIONAL_MEMORY )
continue ;
if ( desc - > num_pages < nr_pages )
continue ;
start = desc - > phys_addr ;
end = start + desc - > num_pages * ( 1UL < < EFI_PAGE_SHIFT ) ;
/*
* Don ' t allocate at 0x0 . It will confuse code that
* checks pointers against NULL . Skip the first 8
* bytes so we start at a nice even number .
*/
if ( start = = 0x0 )
start + = 8 ;
start = round_up ( start , align ) ;
if ( ( start + size ) > end )
continue ;
2013-09-22 15:45:28 -07:00
status = efi_call_phys4 ( sys_table_arg - > boottime - > allocate_pages ,
2013-09-22 15:45:27 -07:00
EFI_ALLOCATE_ADDRESS , EFI_LOADER_DATA ,
nr_pages , & start ) ;
if ( status = = EFI_SUCCESS ) {
* addr = start ;
break ;
}
}
if ( i = = map_size / desc_size )
status = EFI_NOT_FOUND ;
2013-09-22 15:45:28 -07:00
efi_call_phys1 ( sys_table_arg - > boottime - > free_pool , map ) ;
2013-09-22 15:45:27 -07:00
fail :
return status ;
}
2013-09-22 15:45:29 -07:00
static void efi_free ( efi_system_table_t * sys_table_arg , unsigned long size ,
2013-09-22 15:45:28 -07:00
unsigned long addr )
2013-09-22 15:45:27 -07:00
{
unsigned long nr_pages ;
2013-09-22 15:45:38 -07:00
if ( ! size )
return ;
2013-09-22 15:45:27 -07:00
nr_pages = round_up ( size , EFI_PAGE_SIZE ) / EFI_PAGE_SIZE ;
2013-09-22 15:45:28 -07:00
efi_call_phys2 ( sys_table_arg - > boottime - > free_pages , addr , nr_pages ) ;
2013-09-22 15:45:27 -07:00
}
/*
2013-09-22 15:45:40 -07:00
* Check the cmdline for a LILO - style file = arguments .
2013-09-22 15:45:27 -07:00
*
2013-09-22 15:45:40 -07:00
* We only support loading a file from the same filesystem as
* the kernel image .
2013-09-22 15:45:27 -07:00
*/
2013-09-22 15:45:39 -07:00
static efi_status_t handle_cmdline_files ( efi_system_table_t * sys_table_arg ,
efi_loaded_image_t * image ,
char * cmd_line , char * option_string ,
unsigned long max_addr ,
unsigned long * load_addr ,
unsigned long * load_size )
2013-09-22 15:45:27 -07:00
{
2013-09-22 15:45:40 -07:00
struct file_info * files ;
unsigned long file_addr ;
2013-09-22 15:45:27 -07:00
efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID ;
2013-09-22 15:45:40 -07:00
u64 file_size_total ;
2013-09-22 15:45:27 -07:00
efi_file_io_interface_t * io ;
efi_file_handle_t * fh ;
efi_status_t status ;
2013-09-22 15:45:40 -07:00
int nr_files ;
2013-09-22 15:45:27 -07:00
char * str ;
int i , j , k ;
2013-09-22 15:45:40 -07:00
file_addr = 0 ;
file_size_total = 0 ;
2013-09-22 15:45:27 -07:00
2013-09-22 15:45:39 -07:00
str = cmd_line ;
2013-09-22 15:45:27 -07:00
j = 0 ; /* See close_handles */
2013-09-22 15:45:39 -07:00
if ( ! load_addr | | ! load_size )
return EFI_INVALID_PARAMETER ;
* load_addr = 0 ;
* load_size = 0 ;
2013-09-22 15:45:27 -07:00
if ( ! str | | ! * str )
return EFI_SUCCESS ;
2013-09-22 15:45:40 -07:00
for ( nr_files = 0 ; * str ; nr_files + + ) {
2013-09-22 15:45:39 -07:00
str = strstr ( str , option_string ) ;
2013-09-22 15:45:27 -07:00
if ( ! str )
break ;
2013-09-22 15:45:39 -07:00
str + = strlen ( option_string ) ;
2013-09-22 15:45:27 -07:00
/* Skip any leading slashes */
while ( * str = = ' / ' | | * str = = ' \\ ' )
str + + ;
while ( * str & & * str ! = ' ' & & * str ! = ' \n ' )
str + + ;
}
2013-09-22 15:45:40 -07:00
if ( ! nr_files )
2013-09-22 15:45:27 -07:00
return EFI_SUCCESS ;
2013-09-22 15:45:28 -07:00
status = efi_call_phys3 ( sys_table_arg - > boottime - > allocate_pool ,
2013-09-22 15:45:27 -07:00
EFI_LOADER_DATA ,
2013-09-22 15:45:40 -07:00
nr_files * sizeof ( * files ) ,
2013-09-22 15:45:41 -07:00
( void * * ) & files ) ;
2013-09-22 15:45:27 -07:00
if ( status ! = EFI_SUCCESS ) {
2013-09-22 15:45:40 -07:00
efi_printk ( sys_table_arg , " Failed to alloc mem for file handle list \n " ) ;
2013-09-22 15:45:27 -07:00
goto fail ;
}
2013-09-22 15:45:39 -07:00
str = cmd_line ;
2013-09-22 15:45:40 -07:00
for ( i = 0 ; i < nr_files ; i + + ) {
struct file_info * file ;
2013-09-22 15:45:27 -07:00
efi_file_handle_t * h ;
efi_file_info_t * info ;
efi_char16_t filename_16 [ 256 ] ;
unsigned long info_sz ;
efi_guid_t info_guid = EFI_FILE_INFO_ID ;
efi_char16_t * p ;
u64 file_sz ;
2013-09-22 15:45:39 -07:00
str = strstr ( str , option_string ) ;
2013-09-22 15:45:27 -07:00
if ( ! str )
break ;
2013-09-22 15:45:39 -07:00
str + = strlen ( option_string ) ;
2013-09-22 15:45:27 -07:00
2013-09-22 15:45:40 -07:00
file = & files [ i ] ;
2013-09-22 15:45:27 -07:00
p = filename_16 ;
/* Skip any leading slashes */
while ( * str = = ' / ' | | * str = = ' \\ ' )
str + + ;
while ( * str & & * str ! = ' ' & & * str ! = ' \n ' ) {
if ( ( u8 * ) p > = ( u8 * ) filename_16 + sizeof ( filename_16 ) )
break ;
if ( * str = = ' / ' ) {
* p + + = ' \\ ' ;
2013-09-22 15:45:42 -07:00
str + + ;
2013-09-22 15:45:27 -07:00
} else {
* p + + = * str + + ;
}
}
* p = ' \0 ' ;
/* Only open the volume once. */
if ( ! i ) {
efi_boot_services_t * boottime ;
2013-09-22 15:45:28 -07:00
boottime = sys_table_arg - > boottime ;
2013-09-22 15:45:27 -07:00
status = efi_call_phys3 ( boottime - > handle_protocol ,
2013-09-22 15:45:41 -07:00
image - > device_handle , & fs_proto ,
( void * * ) & io ) ;
2013-09-22 15:45:27 -07:00
if ( status ! = EFI_SUCCESS ) {
2013-09-22 15:45:28 -07:00
efi_printk ( sys_table_arg , " Failed to handle fs_proto \n " ) ;
2013-09-22 15:45:40 -07:00
goto free_files ;
2013-09-22 15:45:27 -07:00
}
status = efi_call_phys2 ( io - > open_volume , io , & fh ) ;
if ( status ! = EFI_SUCCESS ) {
2013-09-22 15:45:28 -07:00
efi_printk ( sys_table_arg , " Failed to open volume \n " ) ;
2013-09-22 15:45:40 -07:00
goto free_files ;
2013-09-22 15:45:27 -07:00
}
}
status = efi_call_phys5 ( fh - > open , fh , & h , filename_16 ,
EFI_FILE_MODE_READ , ( u64 ) 0 ) ;
if ( status ! = EFI_SUCCESS ) {
2013-09-22 15:45:39 -07:00
efi_printk ( sys_table_arg , " Failed to open file: " ) ;
2013-09-22 15:45:28 -07:00
efi_char16_printk ( sys_table_arg , filename_16 ) ;
efi_printk ( sys_table_arg , " \n " ) ;
2013-09-22 15:45:27 -07:00
goto close_handles ;
}
2013-09-22 15:45:40 -07:00
file - > handle = h ;
2013-09-22 15:45:27 -07:00
info_sz = 0 ;
status = efi_call_phys4 ( h - > get_info , h , & info_guid ,
& info_sz , NULL ) ;
if ( status ! = EFI_BUFFER_TOO_SMALL ) {
2013-09-22 15:45:39 -07:00
efi_printk ( sys_table_arg , " Failed to get file info size \n " ) ;
2013-09-22 15:45:27 -07:00
goto close_handles ;
}
grow :
2013-09-22 15:45:28 -07:00
status = efi_call_phys3 ( sys_table_arg - > boottime - > allocate_pool ,
2013-09-22 15:45:41 -07:00
EFI_LOADER_DATA , info_sz ,
( void * * ) & info ) ;
2013-09-22 15:45:27 -07:00
if ( status ! = EFI_SUCCESS ) {
2013-09-22 15:45:39 -07:00
efi_printk ( sys_table_arg , " Failed to alloc mem for file info \n " ) ;
2013-09-22 15:45:27 -07:00
goto close_handles ;
}
status = efi_call_phys4 ( h - > get_info , h , & info_guid ,
& info_sz , info ) ;
if ( status = = EFI_BUFFER_TOO_SMALL ) {
2013-09-22 15:45:28 -07:00
efi_call_phys1 ( sys_table_arg - > boottime - > free_pool ,
info ) ;
2013-09-22 15:45:27 -07:00
goto grow ;
}
file_sz = info - > file_size ;
2013-09-22 15:45:28 -07:00
efi_call_phys1 ( sys_table_arg - > boottime - > free_pool , info ) ;
2013-09-22 15:45:27 -07:00
if ( status ! = EFI_SUCCESS ) {
2013-09-22 15:45:39 -07:00
efi_printk ( sys_table_arg , " Failed to get file info \n " ) ;
2013-09-22 15:45:27 -07:00
goto close_handles ;
}
2013-09-22 15:45:40 -07:00
file - > size = file_sz ;
file_size_total + = file_sz ;
2013-09-22 15:45:27 -07:00
}
2013-09-22 15:45:40 -07:00
if ( file_size_total ) {
2013-09-22 15:45:27 -07:00
unsigned long addr ;
/*
2013-09-22 15:45:40 -07:00
* Multiple files need to be at consecutive addresses in memory ,
* so allocate enough memory for all the files . This is used
* for loading multiple files .
2013-09-22 15:45:27 -07:00
*/
2013-09-22 15:45:40 -07:00
status = efi_high_alloc ( sys_table_arg , file_size_total , 0x1000 ,
& file_addr , max_addr ) ;
2013-09-22 15:45:27 -07:00
if ( status ! = EFI_SUCCESS ) {
2013-09-22 15:45:40 -07:00
efi_printk ( sys_table_arg , " Failed to alloc highmem for files \n " ) ;
2013-09-22 15:45:27 -07:00
goto close_handles ;
}
/* We've run out of free low memory. */
2013-09-22 15:45:40 -07:00
if ( file_addr > max_addr ) {
2013-09-22 15:45:28 -07:00
efi_printk ( sys_table_arg , " We've run out of free low memory \n " ) ;
2013-09-22 15:45:27 -07:00
status = EFI_INVALID_PARAMETER ;
2013-09-22 15:45:40 -07:00
goto free_file_total ;
2013-09-22 15:45:27 -07:00
}
2013-09-22 15:45:40 -07:00
addr = file_addr ;
for ( j = 0 ; j < nr_files ; j + + ) {
2013-09-22 15:45:41 -07:00
unsigned long size ;
2013-09-22 15:45:27 -07:00
2013-09-22 15:45:40 -07:00
size = files [ j ] . size ;
2013-09-22 15:45:27 -07:00
while ( size ) {
2013-09-22 15:45:41 -07:00
unsigned long chunksize ;
2013-09-22 15:45:27 -07:00
if ( size > EFI_READ_CHUNK_SIZE )
chunksize = EFI_READ_CHUNK_SIZE ;
else
chunksize = size ;
status = efi_call_phys3 ( fh - > read ,
2013-09-22 15:45:40 -07:00
files [ j ] . handle ,
2013-09-22 15:45:41 -07:00
& chunksize ,
( void * ) addr ) ;
2013-09-22 15:45:27 -07:00
if ( status ! = EFI_SUCCESS ) {
2013-09-22 15:45:39 -07:00
efi_printk ( sys_table_arg , " Failed to read file \n " ) ;
2013-09-22 15:45:40 -07:00
goto free_file_total ;
2013-09-22 15:45:27 -07:00
}
addr + = chunksize ;
size - = chunksize ;
}
2013-09-22 15:45:40 -07:00
efi_call_phys1 ( fh - > close , files [ j ] . handle ) ;
2013-09-22 15:45:27 -07:00
}
}
2013-09-22 15:45:40 -07:00
efi_call_phys1 ( sys_table_arg - > boottime - > free_pool , files ) ;
2013-09-22 15:45:27 -07:00
2013-09-22 15:45:40 -07:00
* load_addr = file_addr ;
* load_size = file_size_total ;
2013-09-22 15:45:27 -07:00
return status ;
2013-09-22 15:45:40 -07:00
free_file_total :
efi_free ( sys_table_arg , file_size_total , file_addr ) ;
2013-09-22 15:45:27 -07:00
close_handles :
for ( k = j ; k < i ; k + + )
2013-09-22 15:45:40 -07:00
efi_call_phys1 ( fh - > close , files [ k ] . handle ) ;
free_files :
efi_call_phys1 ( sys_table_arg - > boottime - > free_pool , files ) ;
2013-09-22 15:45:27 -07:00
fail :
2013-09-22 15:45:39 -07:00
* load_addr = 0 ;
* load_size = 0 ;
2013-09-22 15:45:27 -07:00
return status ;
}
2013-09-22 15:45:32 -07:00
/*
* Relocate a kernel image , either compressed or uncompressed .
* In the ARM64 case , all kernel images are currently
* uncompressed , and as such when we relocate it we need to
* allocate additional space for the BSS segment . Any low
* memory that this function should avoid needs to be
* unavailable in the EFI memory map , as if the preferred
* address is not available the lowest available address will
* be used .
*/
static efi_status_t efi_relocate_kernel ( efi_system_table_t * sys_table_arg ,
unsigned long * image_addr ,
unsigned long image_size ,
unsigned long alloc_size ,
unsigned long preferred_addr ,
unsigned long alignment )
2013-09-22 15:45:31 -07:00
{
2013-09-22 15:45:32 -07:00
unsigned long cur_image_addr ;
unsigned long new_addr = 0 ;
2013-09-22 15:45:31 -07:00
efi_status_t status ;
2013-09-22 15:45:32 -07:00
unsigned long nr_pages ;
efi_physical_addr_t efi_addr = preferred_addr ;
if ( ! image_addr | | ! image_size | | ! alloc_size )
return EFI_INVALID_PARAMETER ;
if ( alloc_size < image_size )
return EFI_INVALID_PARAMETER ;
cur_image_addr = * image_addr ;
2013-09-22 15:45:31 -07:00
/*
* The EFI firmware loader could have placed the kernel image
2013-09-22 15:45:32 -07:00
* anywhere in memory , but the kernel has restrictions on the
* max physical address it can run at . Some architectures
* also have a prefered address , so first try to relocate
* to the preferred address . If that fails , allocate as low
* as possible while respecting the required alignment .
2013-09-22 15:45:31 -07:00
*/
2013-09-22 15:45:32 -07:00
nr_pages = round_up ( alloc_size , EFI_PAGE_SIZE ) / EFI_PAGE_SIZE ;
status = efi_call_phys4 ( sys_table_arg - > boottime - > allocate_pages ,
2013-09-22 15:45:31 -07:00
EFI_ALLOCATE_ADDRESS , EFI_LOADER_DATA ,
2013-09-22 15:45:32 -07:00
nr_pages , & efi_addr ) ;
new_addr = efi_addr ;
/*
* If preferred address allocation failed allocate as low as
* possible .
*/
2013-09-22 15:45:31 -07:00
if ( status ! = EFI_SUCCESS ) {
2013-09-22 15:45:32 -07:00
status = efi_low_alloc ( sys_table_arg , alloc_size , alignment ,
& new_addr ) ;
}
if ( status ! = EFI_SUCCESS ) {
efi_printk ( sys_table_arg , " ERROR: Failed to allocate usable memory for kernel. \n " ) ;
return status ;
2013-09-22 15:45:31 -07:00
}
2013-09-22 15:45:32 -07:00
/*
* We know source / dest won ' t overlap since both memory ranges
* have been allocated by UEFI , so we can safely use memcpy .
*/
memcpy ( ( void * ) new_addr , ( void * ) cur_image_addr , image_size ) ;
2013-09-22 15:45:31 -07:00
2013-09-22 15:45:32 -07:00
/* Return the new address of the relocated image. */
* image_addr = new_addr ;
2013-09-22 15:45:31 -07:00
return status ;
}
2013-09-22 15:45:33 -07:00
/*
* Convert the unicode UEFI command line to ASCII to pass to kernel .
* Size of memory allocated return in * cmd_line_len .
* Returns NULL on error .
*/
static char * efi_convert_cmdline_to_ascii ( efi_system_table_t * sys_table_arg ,
efi_loaded_image_t * image ,
int * cmd_line_len )
{
u16 * s2 ;
u8 * s1 = NULL ;
unsigned long cmdline_addr = 0 ;
int load_options_size = image - > load_options_size / 2 ; /* ASCII */
void * options = image - > load_options ;
int options_size = 0 ;
efi_status_t status ;
int i ;
u16 zero = 0 ;
if ( options ) {
s2 = options ;
while ( * s2 & & * s2 ! = ' \n ' & & options_size < load_options_size ) {
s2 + + ;
options_size + + ;
}
}
if ( options_size = = 0 ) {
/* No command line options, so return empty string*/
options_size = 1 ;
options = & zero ;
}
options_size + + ; /* NUL termination */
# ifdef CONFIG_ARM
/*
* For ARM , allocate at a high address to avoid reserved
* regions at low addresses that we don ' t know the specfics of
* at the time we are processing the command line .
*/
status = efi_high_alloc ( sys_table_arg , options_size , 0 ,
& cmdline_addr , 0xfffff000 ) ;
# else
status = efi_low_alloc ( sys_table_arg , options_size , 0 ,
& cmdline_addr ) ;
# endif
if ( status ! = EFI_SUCCESS )
return NULL ;
s1 = ( u8 * ) cmdline_addr ;
s2 = ( u16 * ) options ;
for ( i = 0 ; i < options_size - 1 ; i + + )
* s1 + + = * s2 + + ;
* s1 = ' \0 ' ;
* cmd_line_len = options_size ;
return ( char * ) cmdline_addr ;
}