diff options
Diffstat (limited to 'arch/x86/boot/compressed/misc.c')
| -rw-r--r-- | arch/x86/boot/compressed/misc.c | 14 | 
1 files changed, 13 insertions, 1 deletions
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 30dd59a9f0b4..dcc1c536cc21 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -260,7 +260,7 @@ static void handle_relocations(void *output, unsigned long output_len)  	/*  	 * Process relocations: 32 bit relocations first then 64 bit after. -	 * Two sets of binary relocations are added to the end of the kernel +	 * Three sets of binary relocations are added to the end of the kernel  	 * before compression. Each relocation table entry is the kernel  	 * address of the location which needs to be updated stored as a  	 * 32-bit value which is sign extended to 64 bits. @@ -270,6 +270,8 @@ static void handle_relocations(void *output, unsigned long output_len)  	 * kernel bits...  	 * 0 - zero terminator for 64 bit relocations  	 * 64 bit relocation repeated +	 * 0 - zero terminator for inverse 32 bit relocations +	 * 32 bit inverse relocation repeated  	 * 0 - zero terminator for 32 bit relocations  	 * 32 bit relocation repeated  	 * @@ -286,6 +288,16 @@ static void handle_relocations(void *output, unsigned long output_len)  		*(uint32_t *)ptr += delta;  	}  #ifdef CONFIG_X86_64 +	while (*--reloc) { +		long extended = *reloc; +		extended += map; + +		ptr = (unsigned long)extended; +		if (ptr < min_addr || ptr > max_addr) +			error("inverse 32-bit relocation outside of kernel!\n"); + +		*(int32_t *)ptr -= delta; +	}  	for (reloc--; *reloc; reloc--) {  		long extended = *reloc;  		extended += map;  |