| 
									
										
										
										
											2014-04-15 22:47:52 -04:00
										 |  |  | /* | 
					
						
							|  |  |  |  * EFI entry point. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2013, 2014 Red Hat, Inc. | 
					
						
							|  |  |  |  * Author: Mark Salter <msalter@redhat.com>
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #include <linux/linkage.h> | 
					
						
							|  |  |  | #include <linux/init.h> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <asm/assembler.h> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define EFI_LOAD_ERROR 0x8000000000000001 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__INIT | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* | 
					
						
							|  |  |  | 	 * We arrive here from the EFI boot manager with: | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 *    * CPU in little-endian mode | 
					
						
							|  |  |  | 	 *    * MMU on with identity-mapped RAM | 
					
						
							|  |  |  | 	 *    * Icache and Dcache on | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * We will most likely be running from some place other than where | 
					
						
							|  |  |  | 	 * we want to be. The kernel image wants to be placed at TEXT_OFFSET | 
					
						
							|  |  |  | 	 * from start of RAM. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | ENTRY(efi_stub_entry) | 
					
						
							|  |  |  | 	/* | 
					
						
							|  |  |  | 	 * Create a stack frame to save FP/LR with extra space | 
					
						
							|  |  |  | 	 * for image_addr variable passed to efi_entry(). | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	stp	x29, x30, [sp, #-32]! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* | 
					
						
							|  |  |  | 	 * Call efi_entry to do the real work. | 
					
						
							|  |  |  | 	 * x0 and x1 are already set up by firmware. Current runtime | 
					
						
							|  |  |  | 	 * address of image is calculated and passed via *image_addr. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * unsigned long efi_entry(void *handle, | 
					
						
							|  |  |  | 	 *                         efi_system_table_t *sys_table, | 
					
						
							|  |  |  | 	 *                         unsigned long *image_addr) ;
 | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	adrp	x8, _text | 
					
						
							|  |  |  | 	add	x8, x8, #:lo12:_text | 
					
						
							|  |  |  | 	add	x2, sp, 16 | 
					
						
							|  |  |  | 	str	x8, [x2] | 
					
						
							|  |  |  | 	bl	efi_entry | 
					
						
							|  |  |  | 	cmn	x0, #1 | 
					
						
							|  |  |  | 	b.eq	efi_load_fail | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* | 
					
						
							| 
									
										
										
										
											2014-11-13 12:22:01 +00:00
										 |  |  | 	 * efi_entry() will have copied the kernel image if necessary and we | 
					
						
							|  |  |  | 	 * return here with device tree address in x0 and the kernel entry | 
					
						
							|  |  |  | 	 * point stored at *image_addr. Save those values in registers which | 
					
						
							|  |  |  | 	 * are callee preserved. | 
					
						
							| 
									
										
										
										
											2014-04-15 22:47:52 -04:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	mov	x20, x0		// DTB address | 
					
						
							|  |  |  | 	ldr	x0, [sp, #16]	// relocated _text address | 
					
						
							| 
									
										
											  
											
												arm64/efi: efistub: jump to 'stext' directly, not through the header
After the EFI stub has done its business, it jumps into the kernel by
branching to offset #0 of the loaded Image, which is where it expects
to find the header containing a 'branch to stext' instruction.
However, the UEFI spec 2.1.1 states the following regarding PE/COFF
image loading:
"A UEFI image is loaded into memory through the LoadImage() Boot
Service. This service loads an image with a PE32+ format into memory.
This PE32+ loader is required to load all sections of the PE32+ image
into memory."
In other words, it is /not/ required to load parts of the image that are
not covered by a PE/COFF section, so it may not have loaded the header
at the expected offset, as it is not covered by any PE/COFF section.
So instead, jump to 'stext' directly, which is at the base of the
PE/COFF .text section, by supplying a symbol 'stext_offset' to
efi-entry.o which contains the relative offset of stext into the Image.
Also replace other open coded calculations of the same value with a
reference to 'stext_offset'
Acked-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Roy Franz <roy.franz@linaro.org>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
											
										 
											2014-10-08 16:11:27 +02:00
										 |  |  | 	ldr	x21, =stext_offset | 
					
						
							|  |  |  | 	add	x21, x0, x21 | 
					
						
							| 
									
										
										
										
											2014-04-15 22:47:52 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* | 
					
						
							| 
									
										
										
										
											2014-11-13 12:22:01 +00:00
										 |  |  | 	 * Calculate size of the kernel Image (same for original and copy). | 
					
						
							| 
									
										
										
										
											2014-04-15 22:47:52 -04:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	adrp	x1, _text | 
					
						
							|  |  |  | 	add	x1, x1, #:lo12:_text | 
					
						
							|  |  |  | 	adrp	x2, _edata | 
					
						
							|  |  |  | 	add	x2, x2, #:lo12:_edata | 
					
						
							|  |  |  | 	sub	x1, x2, x1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-13 12:22:01 +00:00
										 |  |  | 	/* | 
					
						
							|  |  |  | 	 * Flush the copied Image to the PoC, and ensure it is not shadowed by | 
					
						
							|  |  |  | 	 * stale icache entries from before relocation. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2014-04-15 22:47:52 -04:00
										 |  |  | 	bl	__flush_dcache_area | 
					
						
							|  |  |  | 	ic	ialluis | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-13 12:22:01 +00:00
										 |  |  | 	/* | 
					
						
							|  |  |  | 	 * Ensure that the rest of this function (in the original Image) is | 
					
						
							|  |  |  | 	 * visible when the caches are disabled. The I-cache can't have stale | 
					
						
							|  |  |  | 	 * entries for the VA range of the current image, so no maintenance is | 
					
						
							|  |  |  | 	 * necessary. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	adr	x0, efi_stub_entry | 
					
						
							|  |  |  | 	adr	x1, efi_stub_entry_end | 
					
						
							|  |  |  | 	sub	x1, x1, x0 | 
					
						
							|  |  |  | 	bl	__flush_dcache_area | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-15 22:47:52 -04:00
										 |  |  | 	/* Turn off Dcache and MMU */ | 
					
						
							|  |  |  | 	mrs	x0, CurrentEL | 
					
						
							| 
									
										
										
										
											2014-06-06 14:16:21 +01:00
										 |  |  | 	cmp	x0, #CurrentEL_EL2 | 
					
						
							| 
									
										
										
										
											2014-04-15 22:47:52 -04:00
										 |  |  | 	b.ne	1f | 
					
						
							|  |  |  | 	mrs	x0, sctlr_el2 | 
					
						
							|  |  |  | 	bic	x0, x0, #1 << 0	// clear SCTLR.M | 
					
						
							|  |  |  | 	bic	x0, x0, #1 << 2	// clear SCTLR.C | 
					
						
							|  |  |  | 	msr	sctlr_el2, x0 | 
					
						
							|  |  |  | 	isb | 
					
						
							|  |  |  | 	b	2f | 
					
						
							|  |  |  | 1: | 
					
						
							|  |  |  | 	mrs	x0, sctlr_el1 | 
					
						
							|  |  |  | 	bic	x0, x0, #1 << 0	// clear SCTLR.M | 
					
						
							|  |  |  | 	bic	x0, x0, #1 << 2	// clear SCTLR.C | 
					
						
							|  |  |  | 	msr	sctlr_el1, x0 | 
					
						
							|  |  |  | 	isb | 
					
						
							|  |  |  | 2: | 
					
						
							|  |  |  | 	/* Jump to kernel entry point */ | 
					
						
							|  |  |  | 	mov	x0, x20 | 
					
						
							|  |  |  | 	mov	x1, xzr | 
					
						
							|  |  |  | 	mov	x2, xzr | 
					
						
							|  |  |  | 	mov	x3, xzr | 
					
						
							|  |  |  | 	br	x21 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | efi_load_fail: | 
					
						
							|  |  |  | 	mov	x0, #EFI_LOAD_ERROR | 
					
						
							|  |  |  | 	ldp	x29, x30, [sp], #32 | 
					
						
							|  |  |  | 	ret | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-13 12:22:01 +00:00
										 |  |  | efi_stub_entry_end: | 
					
						
							| 
									
										
										
										
											2014-04-15 22:47:52 -04:00
										 |  |  | ENDPROC(efi_stub_entry) |