svn commit: r247214 - projects/uefi/sys/boot/i386/efi

Benno Rice benno at FreeBSD.org
Sun Feb 24 10:55:51 UTC 2013


Author: benno
Date: Sun Feb 24 10:55:49 2013
New Revision: 247214
URL: http://svnweb.freebsd.org/changeset/base/247214

Log:
  Fix a number of problems preventing proper handover to the kernel.
  
  There were two issues at play here. Firstly, there was nothing preventing
  UEFI from placing the loader code above 1GB in RAM. This meant that when
  we switched in the page tables the kernel expects to be running on, we are
  suddenly unmapped and things no longer work. We solve this by making our
  trampoline code not dependent on being at any given position and simply
  copying it to a "safe" location before calling it.
  
  Secondly, UEFI could allocate our stack wherever it wants. As it happened on
  my PC, that was right where I was copying the kernel to. This did not cause
  happiness. The solution to this was to also switch to a temporary stack in a
  safe location before performing the final copy of the loaded kernel.

Added:
  projects/uefi/sys/boot/i386/efi/amd64_tramp.S
Modified:
  projects/uefi/sys/boot/i386/efi/Makefile
  projects/uefi/sys/boot/i386/efi/elf64_freebsd.c
  projects/uefi/sys/boot/i386/efi/x86_efi_copy.c

Modified: projects/uefi/sys/boot/i386/efi/Makefile
==============================================================================
--- projects/uefi/sys/boot/i386/efi/Makefile	Sun Feb 24 08:00:35 2013	(r247213)
+++ projects/uefi/sys/boot/i386/efi/Makefile	Sun Feb 24 10:55:49 2013	(r247214)
@@ -12,6 +12,7 @@ INTERNALPROG=
 # architecture-specific loader code
 SRCS=	main.c exec.c conf.c vers.c reloc.c elf32_freebsd.c elf64_freebsd.c
 SRCS+=	x86_efi_copy.c bootinfo.c bootinfo64.c autoload.c devicename.c efimd.c
+SRCS+=	amd64_tramp.S
 
 .PATH:	${.CURDIR}/${MACHINE_CPUARCH}
 SRCS+=	start.S

Added: projects/uefi/sys/boot/i386/efi/amd64_tramp.S
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/uefi/sys/boot/i386/efi/amd64_tramp.S	Sun Feb 24 10:55:49 2013	(r247214)
@@ -0,0 +1,34 @@
+#include <machine/asmacros.h>
+
+	.text
+	.globl	amd64_tramp
+
+/*
+ * void amd64_tramp(uint64_t stack, void *copy_finish, uint64_t kernend,
+ *		    uint64_t modulep, uint64_t pagetable, uint64_t entry)
+ */
+amd64_tramp:
+	cli			/* Make sure we don't get interrupted. */
+	movq	%rdi,%rsp	/* Switch to our temporary stack. */
+
+	movq	%rdx,%r12	/* Stash the kernel values for later. */
+	movq	%rcx,%r13
+	movq	%r8,%r14
+	movq	%r9,%r15
+
+	call	%rsi		/* Call copy_finish so we're all ready to go. */
+
+	pushq	%r12		/* Push kernend. */
+	salq	$32,%r13	/* Shift modulep and push it. */
+	pushq	%r13
+	pushq	%r15		/* Push the entry address. */
+	movq	%r14,%cr3	/* Switch page tables. */
+	ret			/* "Return" to kernel entry. */
+
+	ALIGN_TEXT
+amd64_tramp_end:
+
+	.data
+	.globl	amd64_tramp_size
+amd64_tramp_size:
+	.long	amd64_tramp_end-amd64_tramp

Modified: projects/uefi/sys/boot/i386/efi/elf64_freebsd.c
==============================================================================
--- projects/uefi/sys/boot/i386/efi/elf64_freebsd.c	Sun Feb 24 08:00:35 2013	(r247213)
+++ projects/uefi/sys/boot/i386/efi/elf64_freebsd.c	Sun Feb 24 10:55:49 2013	(r247214)
@@ -74,6 +74,13 @@ static p4_entry_t *PT4;
 static p3_entry_t *PT3;
 static p2_entry_t *PT2;
 
+static void (*trampoline)(uint64_t stack, void *copy_finish, uint64_t kernend,
+			  uint64_t modulep, p4_entry_t *pagetable,
+			  uint64_t entry);
+
+extern uintptr_t amd64_tramp;
+extern uint32_t amd64_tramp_size;
+
 /*
  * There is an ELF kernel and one or more ELF modules loaded.  
  * We wish to start executing the kernel image, so make such 
@@ -84,8 +91,7 @@ elf64_exec(struct preloaded_file *fp)
 {
     struct file_metadata	*md;
     Elf_Ehdr 			*ehdr;
-    vm_offset_t			modulep, kernend, pagetable;
-    uint32_t			mp, ke;
+    vm_offset_t			modulep, kernend, trampcode, trampstack;
     int				err, i;
     ACPI_TABLE_RSDP		*rsdp;
     char			buf[24];
@@ -121,10 +127,18 @@ elf64_exec(struct preloaded_file *fp)
         return(EFTYPE);
     ehdr = (Elf_Ehdr *)&(md->md_data);
 
-    PT4 = (p4_entry_t *)0x00000000fffff000;
+    trampcode = (vm_offset_t)0x0000000040000000;
+    err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 1,
+        (EFI_PHYSICAL_ADDRESS *)&trampcode);
+    bzero((void *)trampcode, EFI_PAGE_SIZE);
+    trampstack = trampcode + EFI_PAGE_SIZE - 8;
+    bcopy((void *)&amd64_tramp, (void *)trampcode, amd64_tramp_size);
+    trampoline = (void *)trampcode;
+
+    PT4 = (p4_entry_t *)0x0000000040000000;
     err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 3,
         (EFI_PHYSICAL_ADDRESS *)&PT4);
-    bzero(PT4, 3 * PAGE_SIZE);
+    bzero(PT4, 3 * EFI_PAGE_SIZE);
 
     PT3 = &PT4[512];
     PT2 = &PT3[512];
@@ -157,23 +171,8 @@ elf64_exec(struct preloaded_file *fp)
 
     dev_cleanup();
 
-    x86_efi_copy_finish();
-
-    mp = modulep & 0xffffffff;
-    ke = kernend & 0xffffffff;
-    pagetable = (uintptr_t)PT4;
-    __asm __volatile(
-        "movl	%0, %%eax;"
-        "pushq  %%rax;"
-        "movl	%1, %%eax;"
-        "salq   $32, %%rax;"
-        "pushq	%%rax;"
-        "movq	%2, %%rax;"
-        "pushq	%%rax;"
-        "movq	%3, %%rax;"
-        "movq	%%rax, %%cr3;"
-        "ret"
-    :: "r" (ke), "r" (mp), "r" (ehdr->e_entry), "r" (PT4));
+    trampoline(trampstack, x86_efi_copy_finish, kernend, modulep, PT4,
+        ehdr->e_entry);
 
     panic("exec returned");
 }

Modified: projects/uefi/sys/boot/i386/efi/x86_efi_copy.c
==============================================================================
--- projects/uefi/sys/boot/i386/efi/x86_efi_copy.c	Sun Feb 24 08:00:35 2013	(r247213)
+++ projects/uefi/sys/boot/i386/efi/x86_efi_copy.c	Sun Feb 24 10:55:49 2013	(r247214)
@@ -37,7 +37,7 @@ __FBSDID("$FreeBSD$");
 #include <efi.h>
 #include <efilib.h>
 
-#define	STAGE_PAGES	8000	/* 32MB */
+#define	STAGE_PAGES	8192	/* 32MB */
 
 EFI_PHYSICAL_ADDRESS	staging;
 int			stage_offset_set = 0;
@@ -92,7 +92,12 @@ x86_efi_readin(const int fd, vm_offset_t
 void
 x86_efi_copy_finish(void)
 {
+	uint64_t	*src, *dst, *last;
 
-	bcopy((void *)staging, (void *)(staging - stage_offset),
-	    STAGE_PAGES * EFI_PAGE_SIZE);
+	src = (uint64_t *)staging;
+	dst = (uint64_t *)(staging - stage_offset);
+	last = (uint64_t *)(staging + STAGE_PAGES * EFI_PAGE_SIZE);
+
+	while (src < last)
+		*dst++ = *src++;
 }


More information about the svn-src-projects mailing list