@ -22,6 +22,10 @@ struct efi_mem_list {
struct efi_mem_desc desc ;
} ;
# define EFI_CARVE_NO_OVERLAP -1
# define EFI_CARVE_LOOP_AGAIN -2
# define EFI_CARVE_OVERLAPS_NONRAM -3
/* This list contains all memory map items */
LIST_HEAD ( efi_mem ) ;
@ -76,11 +80,11 @@ static int efi_mem_carve_out(struct efi_mem_list *map,
/* check whether we're overlapping */
if ( ( carve_end < = map_start ) | | ( carve_start > = map_end ) )
return 0 ;
return EFI_CARVE_NO_OVERLAP ;
/* We're overlapping with non-RAM, warn the caller if desired */
if ( overlap_only_ram & & ( map_desc - > type ! = EFI_CONVENTIONAL_MEMORY ) )
return - 1 ;
return EFI_CARVE_OVERLAPS_NONRAM ;
/* Sanitize carve_start and carve_end to lie within our bounds */
carve_start = max ( carve_start , map_start ) ;
@ -95,7 +99,7 @@ static int efi_mem_carve_out(struct efi_mem_list *map,
map_desc - > physical_start = carve_end ;
map_desc - > num_pages = ( map_end - carve_end ) > > EFI_PAGE_SHIFT ;
return 1 ;
return ( carve_end - carve_start ) > > EFI_PAGE_SHIFT ;
}
/*
@ -115,7 +119,7 @@ static int efi_mem_carve_out(struct efi_mem_list *map,
/* Shrink the map to [ map_start ... carve_start ] */
map_desc - > num_pages = ( carve_start - map_start ) > > EFI_PAGE_SHIFT ;
return 1 ;
return EFI_CARVE_LOOP_AGAIN ;
}
uint64_t efi_add_memory_map ( uint64_t start , uint64_t pages , int memory_type ,
@ -123,7 +127,8 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
{
struct list_head * lhandle ;
struct efi_mem_list * newlist ;
bool do_carving ;
bool carve_again ;
uint64_t carved_pages = 0 ;
if ( ! pages )
return start ;
@ -150,7 +155,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
/* Add our new map */
do {
do_ carving = false ;
carve_aga in = false ;
list_for_each ( lhandle , & efi_mem ) {
struct efi_mem_list * lmem ;
int r ;
@ -158,14 +163,44 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
lmem = list_entry ( lhandle , struct efi_mem_list , link ) ;
r = efi_mem_carve_out ( lmem , & newlist - > desc ,
overlap_only_ram ) ;
if ( r < 0 ) {
switch ( r ) {
case EFI_CARVE_OVERLAPS_NONRAM :
/*
* The user requested to only have RAM overlaps ,
* but we hit a non - RAM region . Error out .
*/
return 0 ;
} else if ( r ) {
do_carving = true ;
case EFI_CARVE_NO_OVERLAP :
/* Just ignore this list entry */
break ;
case EFI_CARVE_LOOP_AGAIN :
/*
* We split an entry , but need to loop through
* the list again to actually carve it .
*/
carve_again = true ;
break ;
default :
/* We carved a number of pages */
carved_pages + = r ;
carve_again = true ;
break ;
}
if ( carve_again ) {
/* The list changed, we need to start over */
break ;
}
}
} while ( do_carving ) ;
} while ( carve_again ) ;
if ( overlap_only_ram & & ( carved_pages ! = pages ) ) {
/*
* The payload wanted to have RAM overlaps , but we overlapped
* with an unallocated region . Error out .
*/
return 0 ;
}
/* Add our new map */
list_add_tail ( & newlist - > link , & efi_mem ) ;