Module Name:    src
Committed By:   nonaka
Date:           Sat Feb 11 10:23:39 UTC 2017

Modified Files:
        src/sys/arch/i386/stand/efiboot: efiboot.c efiboot.h
        src/sys/arch/i386/stand/efiboot/bootx64: efibootx64.c startprog64.S
        src/sys/arch/i386/stand/lib: exec.c

Log Message:
PR/51953: fix unable to boot on some AMD machine.

Delayed the timing to copy the kernel to actual address.
copy routine from common/lib/libc/arch/x86_64/string/bcopy.S


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/i386/stand/efiboot/efiboot.c \
    src/sys/arch/i386/stand/efiboot/efiboot.h
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/i386/stand/efiboot/bootx64/efibootx64.c
cvs rdiff -u -r1.2 -r1.3 \
    src/sys/arch/i386/stand/efiboot/bootx64/startprog64.S
cvs rdiff -u -r1.64 -r1.65 src/sys/arch/i386/stand/lib/exec.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/i386/stand/efiboot/efiboot.c
diff -u src/sys/arch/i386/stand/efiboot/efiboot.c:1.3 src/sys/arch/i386/stand/efiboot/efiboot.c:1.4
--- src/sys/arch/i386/stand/efiboot/efiboot.c:1.3	Sat Feb 11 10:15:55 2017
+++ src/sys/arch/i386/stand/efiboot/efiboot.c	Sat Feb 11 10:23:39 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: efiboot.c,v 1.3 2017/02/11 10:15:55 nonaka Exp $	*/
+/*	$NetBSD: efiboot.c,v 1.4 2017/02/11 10:23:39 nonaka Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
@@ -35,6 +35,8 @@ EFI_HANDLE IH;
 EFI_DEVICE_PATH *efi_bootdp;
 EFI_LOADED_IMAGE *efi_li;
 uintptr_t efi_main_sp;
+physaddr_t efi_loadaddr, efi_kernel_start;
+u_long efi_kernel_size;
 bool efi_cleanuped;
 
 static EFI_PHYSICAL_ADDRESS heap_start = EFI_ALLOCATE_MAX_ADDRESS;
Index: src/sys/arch/i386/stand/efiboot/efiboot.h
diff -u src/sys/arch/i386/stand/efiboot/efiboot.h:1.3 src/sys/arch/i386/stand/efiboot/efiboot.h:1.4
--- src/sys/arch/i386/stand/efiboot/efiboot.h:1.3	Sat Feb 11 10:15:55 2017
+++ src/sys/arch/i386/stand/efiboot/efiboot.h	Sat Feb 11 10:23:39 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: efiboot.h,v 1.3 2017/02/11 10:15:55 nonaka Exp $	*/
+/*	$NetBSD: efiboot.h,v 1.4 2017/02/11 10:23:39 nonaka Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
@@ -48,6 +48,8 @@ extern EFI_HANDLE IH;
 extern EFI_DEVICE_PATH *efi_bootdp;
 extern EFI_LOADED_IMAGE *efi_li;
 extern uintptr_t efi_main_sp;
+extern physaddr_t efi_loadaddr, efi_kernel_start;
+extern u_long efi_kernel_size;
 extern bool efi_cleanuped;
 void efi_cleanup(void);
 

Index: src/sys/arch/i386/stand/efiboot/bootx64/efibootx64.c
diff -u src/sys/arch/i386/stand/efiboot/bootx64/efibootx64.c:1.1 src/sys/arch/i386/stand/efiboot/bootx64/efibootx64.c:1.2
--- src/sys/arch/i386/stand/efiboot/bootx64/efibootx64.c:1.1	Tue Jan 24 11:09:14 2017
+++ src/sys/arch/i386/stand/efiboot/bootx64/efibootx64.c	Sat Feb 11 10:23:39 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: efibootx64.c,v 1.1 2017/01/24 11:09:14 nonaka Exp $	*/
+/*	$NetBSD: efibootx64.c,v 1.2 2017/02/11 10:23:39 nonaka Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
@@ -32,8 +32,10 @@
 
 struct x86_boot_params boot_params;
 
-void startprog64_start(void *, physaddr_t, physaddr_t);
-extern void (*startprog64)(void *, physaddr_t, physaddr_t);
+void startprog64_start(physaddr_t, physaddr_t, physaddr_t, u_long,
+    void *, physaddr_t);
+extern void (*startprog64)(physaddr_t, physaddr_t, physaddr_t, u_long,
+    void *, physaddr_t);
 extern u_int startprog64_size;
 
 void
@@ -64,7 +66,8 @@ startprog(physaddr_t entry, uint32_t arg
 		memcpy(newsp, argv, sizeof(*argv) * argc);
 	}
 
-	(*startprog64)(startprog64, entry, (physaddr_t)newsp);
+	(*startprog64)(efi_kernel_start, efi_kernel_start + efi_loadaddr,
+	    (physaddr_t)newsp, efi_kernel_size, startprog64, entry);
 }
 
 /* ARGSUSED */

Index: src/sys/arch/i386/stand/efiboot/bootx64/startprog64.S
diff -u src/sys/arch/i386/stand/efiboot/bootx64/startprog64.S:1.2 src/sys/arch/i386/stand/efiboot/bootx64/startprog64.S:1.3
--- src/sys/arch/i386/stand/efiboot/bootx64/startprog64.S:1.2	Sat Feb  4 16:14:27 2017
+++ src/sys/arch/i386/stand/efiboot/bootx64/startprog64.S	Sat Feb 11 10:23:39 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: startprog64.S,v 1.2 2017/02/04 16:14:27 christos Exp $	*/
+/*	$NetBSD: startprog64.S,v 1.3 2017/02/11 10:23:39 nonaka Exp $	*/
 /*	NetBSD: startprog.S,v 1.3 2003/02/01 14:48:18 dsl Exp	*/
 
 /* starts program in protected mode / flat space
@@ -78,26 +78,135 @@ _C_LABEL(startprog64_size):
 	.p2align 4,,15
 
 /*
- * startprog64(loadddr,entry,stack)
+ * startprog64(loadddr,entry,stack,kern_load,kern_start,kern_size)
  */
 ENTRY(startprog64_start)
 start:
 	/*
 	 * This function is to call the loaded kernel's start() with
 	 * 32bit segment mode from x64 mode.
-	 * %rdi: loaded start address
-	 * %rsi: kernel entry address
+	 * %rdi: kernel start address
+	 * %rsi: loaded kernel address
 	 * %rdx: stack address
+	 * %rcx: loaded kernel size
+	 * %r8 : loaded start address
+	 * %r9 : kernel entry address
 	 */
 
-	cld		# LynxOS depends on it
+	cld		/* LynxOS depends on it */
+
+	cli
+
+	/* Copy kernel */
+	mov	%rcx, %r12		/* original kernel size */
+	movq	%rdi, %r11		/* for misaligned check */
+
+#if !defined(NO_OVERLAP)
+	movq	%rdi, %r13
+	subq	%rsi, %r13
+#endif
+
+	shrq	$3, %rcx		/* count for copy by words */
+	jz	8f			/* j if less than 8 bytes */
+
+	lea	-8(%rdi, %r12), %r14	/* target address of last 8 */
+	mov	-8(%rsi, %r12), %r15	/* get last word */
+#if !defined(NO_OVERLAP)
+	cmpq	%r12, %r13		/* overlapping? */
+	jb	10f
+#endif
+
+/*
+ * Non-overlaping, copy forwards.
+ * Newer Intel cpus (Nehalem) will do 16byte read/write transfers
+ * if %ecx is more than 76.
+ * AMD might do something similar some day.
+ */
+	and	$7, %r11		/* destination misaligned ? */
+	jnz	2f
+	rep
+	movsq
+	mov	%r15, (%r14)		/* write last word */
+	jmp	.Lcopy_done
+
+/*
+ * Destination misaligned
+ * AMD say it is better to align the destination (not the source).
+ * This will also re-align copies if the source and dest are both
+ * misaligned by the same amount)
+ * (I think Nehalem will use its accelerated copy if the source
+ * and destination have the same alignment.)
+ */
+2:
+	lea	-9(%r11, %r12), %rcx	/* post re-alignment count */
+	neg	%r11			/* now -1 .. -7 */
+	mov	(%rsi), %r12		/* get first word */
+	mov	%rdi, %r13		/* target for first word */
+	lea	8(%rsi, %r11), %rsi
+	lea	8(%rdi, %r11), %rdi
+	shr	$3, %rcx
+	rep
+	movsq
+	mov	%r12, (%r13)		/* write first word */
+	mov	%r15, (%r14)		/* write last word */
+	jmp	.Lcopy_done
+
+#if !defined(NO_OVERLAP)
+/* Must copy backwards.
+ * Reverse copy is probably easy to code faster than 'rep movds'
+ * since that requires (IIRC) an extra clock every 3 iterations (AMD).
+ * However I don't suppose anything cares that much!
+ * The big cost is the std/cld pair - reputedly 50+ cycles on Netburst P4.
+ * The copy is aligned with the buffer start (more likely to
+ * be a multiple of 8 than the end).
+ */
+10:
+	lea	-8(%rsi, %rcx, 8), %rsi
+	lea	-8(%rdi, %rcx, 8), %rdi
+	std
+	rep
+	movsq
+	cld
+	mov	%r15, (%r14)	/* write last bytes */
+	jmp	.Lcopy_done
+#endif
+
+/* Less than 8 bytes to copy, copy by bytes */
+/* Intel Nehalem optimise 'rep movsb' for <= 7 bytes (9-15 clocks).
+ * For longer transfers it is 50+ !
+ */
+8:	mov	%r12, %rcx
+
+#if !defined(NO_OVERLAP)
+	cmpq	%r12, %r13	/* overlapping? */
+	jb	81f
+#endif
+
+	/* nope, copy forwards. */
+	rep
+	movsb
+	jmp	.Lcopy_done
+
+#if !defined(NO_OVERLAP)
+/* Must copy backwards */
+81:
+	lea	-1(%rsi, %rcx), %rsi
+	lea	-1(%rdi, %rcx), %rdi
+	std
+	rep
+	movsb
+	cld
+#endif
+	/* End of copy kernel */
+.Lcopy_done:
+
+	mov	%r8, %rdi	/* %rdi: loaded start address */
+	mov	%r9, %rsi	/* %rsi: kernel entry address */
 
 	/* Prepare jump address */
 	lea	(start32a - start)(%rdi), %rax
 	movl	%eax, (start32r - start)(%rdi)
 
-	cli
-
 	/* Setup GDT */
 	lea	(gdt - start)(%rdi), %rax
 	mov	%rax, (gdtrr - start)(%rdi)

Index: src/sys/arch/i386/stand/lib/exec.c
diff -u src/sys/arch/i386/stand/lib/exec.c:1.64 src/sys/arch/i386/stand/lib/exec.c:1.65
--- src/sys/arch/i386/stand/lib/exec.c:1.64	Sat Feb 11 10:18:10 2017
+++ src/sys/arch/i386/stand/lib/exec.c	Sat Feb 11 10:23:39 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: exec.c,v 1.64 2017/02/11 10:18:10 nonaka Exp $	 */
+/*	$NetBSD: exec.c,v 1.65 2017/02/11 10:23:39 nonaka Exp $	 */
 
 /*
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -112,7 +112,6 @@
 #ifdef EFIBOOT
 #include "efiboot.h"
 #undef DEBUG	/* XXX */
-static u_long efi_loadaddr;
 #endif
 
 #define BOOT_NARGS	6
@@ -460,10 +459,8 @@ exec_netbsd(const char *file, physaddr_t
 		bootinfo->entry[i] = vtophys(p);
 	}
 
-	/* Copy the kernel to original load address. */
-	memmove((void *)marks[MARK_START],
-	    (void *)(efi_loadaddr + marks[MARK_START]),
-	    marks[MARK_END] - marks[MARK_START]);
+	efi_kernel_start = marks[MARK_START];
+	efi_kernel_size = marks[MARK_END] - efi_kernel_start;
 #endif
 	startprog(marks[MARK_ENTRY], BOOT_NARGS, boot_argv,
 	    x86_trunc_page(basemem * 1024));

Reply via email to