Re: r336921 broke booting on MBP 2017, EFIRT related

From: Konstantin Belousov <kostikbel_at_gmail.com>
Date: Wed, 29 Aug 2018 17:19:14 +0300
On Wed, Aug 29, 2018 at 09:12:37AM -0500, Kyle Evans wrote:
> I guess this patch might do it:
> https://people.freebsd.org/~kevans/efi-bootmap.diff
> 
> Linux commit messages depict a tale in which they used to also only
> map RUNTIME entries, but they were effectively forced to back down on
> that because of buggy firmware that does exactly what you've described
> and they later reintroduced the restrictive mapping for i386-only
> where they'd not found such bugs.

Orthogonal to the loader patch, please try the following.  Even better,
try this with the stock loader.

You need to remove efirt from the kernel config for now, instead load
efirt.ko, perhaps after the system booted into single user.  I am interested
if the panic goes away.  You should see some interesting message from
kernel about EFI realtime clock.

If you have any binary modules like nvidia or vbox, do not load them
with the patched kernel.

diff --git a/sys/amd64/amd64/efirt_support.S b/sys/amd64/amd64/efirt_support.S
new file mode 100644
index 00000000000..82e5646e645
--- /dev/null
+++ b/sys/amd64/amd64/efirt_support.S
_at__at_ -0,0 +1,105 _at__at_
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib_at_FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <machine/asmacros.h>
+
+#include "assym.inc"
+
+	.text
+ENTRY(efirt_arch_call)
+	pushq	%rbp
+	movq	%rsp, %rbp
+
+	movq	%rbx, EC_STATE+TF_RBX(%rdi)
+	movq	%rsp, EC_STATE+TF_RSP(%rdi)
+	movq	%rbp, EC_STATE+TF_RBP(%rdi)
+	movq	%r12, EC_STATE+TF_R12(%rdi)
+	movq	%r13, EC_STATE+TF_R13(%rdi)
+	movq	%r14, EC_STATE+TF_R14(%rdi)
+	movq	%r15, EC_STATE+TF_R15(%rdi)
+	movq	PCPU(CURTHREAD), %rax
+	movq	%rdi, TD_MD+MD_EFIRT_TMP(%rax)
+
+	movq	PCPU(CURPCB), %rsi
+	movq	$efirt_fault, PCB_ONFAULT(%rsi)
+
+	movl	EC_ARGCNT(%rdi), %ecx
+	movl	%ecx, %ebx
+	shll	$3, %ecx
+	subq	%rcx, %rsp
+
+	cmpl	$0, %ebx
+	jz	1f
+	movq	EC_ARG1(%rdi), %rcx
+	decl	%ebx
+	jz	1f
+	movq	EC_ARG2(%rdi), %rdx
+	decl	%ebx
+	jz	1f
+	movq	EC_ARG3(%rdi), %r8
+	decl	%ebx
+	jz	1f
+	movq	EC_ARG4(%rdi), %r9
+	/* XXX on-stack regs */
+1:	movq	EC_FPTR(%rdi), %rax
+	callq	*%rax
+
+	movq	PCPU(CURTHREAD), %rbx
+	movq	TD_MD+MD_EFIRT_TMP(%rbx), %rdi
+	movq	%rax, EC_STATE(%rdi)
+	movq	PCPU(CURPCB), %rsi
+	xorl	%eax, %eax
+	movq	%rax, PCB_ONFAULT(%rsi)
+
+efirt_arch_call_tail:
+	movq	EC_STATE+TF_R15(%rdi), %r15
+	movq	EC_STATE+TF_R14(%rdi), %r14
+	movq	EC_STATE+TF_R13(%rdi), %r13
+	movq	EC_STATE+TF_R12(%rdi), %r12
+	movq	EC_STATE+TF_RBP(%rdi), %rbp
+	movq	EC_STATE+TF_RSP(%rdi), %rsp
+	movq	EC_STATE+TF_RBX(%rdi), %rbx
+
+	popq	%rbp
+	ret
+END(efirt_arch_call)
+
+ENTRY(efirt_fault)
+	xorl	%eax, %eax
+	movq	PCPU(CURPCB), %rsi
+	movq	%rax, PCB_ONFAULT(%rsi)
+	movl	$EFAULT, %eax
+	movq	PCPU(CURTHREAD), %rbx
+	movq	TD_MD+MD_EFIRT_TMP(%rbx), %rdi
+	jmp	efirt_arch_call_tail
+END(efirt_fault)
diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c
index d61b5c7bb6d..c38a596089a 100644
--- a/sys/amd64/amd64/genassym.c
+++ b/sys/amd64/amd64/genassym.c
_at__at_ -77,12 +77,15 _at__at_ ASSYM(P_MD, offsetof(struct proc, p_md));
 ASSYM(MD_LDT, offsetof(struct mdproc, md_ldt));
 ASSYM(MD_LDT_SD, offsetof(struct mdproc, md_ldt_sd));
 
+ASSYM(MD_EFIRT_TMP, offsetof(struct mdthread, md_efirt_tmp));
+
 ASSYM(TD_LOCK, offsetof(struct thread, td_lock));
 ASSYM(TD_FLAGS, offsetof(struct thread, td_flags));
 ASSYM(TD_PCB, offsetof(struct thread, td_pcb));
 ASSYM(TD_PFLAGS, offsetof(struct thread, td_pflags));
 ASSYM(TD_PROC, offsetof(struct thread, td_proc));
 ASSYM(TD_FRAME, offsetof(struct thread, td_frame));
+ASSYM(TD_MD, offsetof(struct thread, td_md));
 
 ASSYM(TDF_ASTPENDING, TDF_ASTPENDING);
 ASSYM(TDF_NEEDRESCHED, TDF_NEEDRESCHED);
_at__at_ -249,3 +252,12 _at__at_ ASSYM(__FreeBSD_version, __FreeBSD_version);
 #ifdef	HWPMC_HOOKS
 ASSYM(PMC_FN_USER_CALLCHAIN, PMC_FN_USER_CALLCHAIN);
 #endif
+
+ASSYM(EC_EFI_STATUS, offsetof(struct efirt_callinfo, ec_efi_status));
+ASSYM(EC_FPTR, offsetof(struct efirt_callinfo, ec_fptr));
+ASSYM(EC_ARGCNT, offsetof(struct efirt_callinfo, ec_argcnt));
+ASSYM(EC_ARG1, offsetof(struct efirt_callinfo, ec_arg1));
+ASSYM(EC_ARG2, offsetof(struct efirt_callinfo, ec_arg2));
+ASSYM(EC_ARG3, offsetof(struct efirt_callinfo, ec_arg3));
+ASSYM(EC_ARG4, offsetof(struct efirt_callinfo, ec_arg4));
+ASSYM(EC_STATE, offsetof(struct efirt_callinfo, ec_state));
diff --git a/sys/amd64/include/frame.h b/sys/amd64/include/frame.h
index f0a6fcf5bc9..c84ee2a2064 100644
--- a/sys/amd64/include/frame.h
+++ b/sys/amd64/include/frame.h
_at__at_ -47,4 +47,15 _at__at_ struct pti_frame {
 	register_t	pti_ss;
 };
 
+struct efirt_callinfo {
+	register_t	ec_efi_status;
+	register_t	ec_fptr;
+	register_t	ec_argcnt;
+	register_t	ec_arg1;
+	register_t	ec_arg2;
+	register_t	ec_arg3;
+	register_t	ec_arg4;
+	struct trapframe ec_state;
+};
+
 #endif
diff --git a/sys/amd64/include/proc.h b/sys/amd64/include/proc.h
index f52c71208e6..a4d6435d96c 100644
--- a/sys/amd64/include/proc.h
+++ b/sys/amd64/include/proc.h
_at__at_ -62,6 +62,7 _at__at_ struct mdthread {
 	register_t md_saved_flags;	/* (k) */
 	register_t md_spurflt_addr;	/* (k) Spurious page fault address. */
 	struct pmap_invl_gen md_invl_gen;
+	register_t md_efirt_tmp;	/* (k) */
 };
 
 struct mdproc {
diff --git a/sys/dev/efidev/efirt.c b/sys/dev/efidev/efirt.c
index d48074d72d6..348099ccc9e 100644
--- a/sys/dev/efidev/efirt.c
+++ b/sys/dev/efidev/efirt.c
_at__at_ -96,6 +96,8 _at__at_ static int efi_status2err[25] = {
 static int efi_enter(void);
 static void efi_leave(void);
 
+int efirt_arch_call(struct efirt_callinfo *);
+
 static int
 efi_status_to_errno(efi_status status)
 {
_at__at_ -296,16 +298,22 _at__at_ efi_get_table(struct uuid *uuid, void **ptr)
 static int
 efi_get_time_locked(struct efi_tm *tm, struct efi_tmcap *tmcap)
 {
-	efi_status status;
+	struct efirt_callinfo ec;
 	int error;
 
 	EFI_TIME_OWNED()
+	bzero(&ec, sizeof(ec));
+	ec.ec_argcnt = 2;
+	ec.ec_arg1 = (uintptr_t)tm;
+	ec.ec_arg2 = (uintptr_t)tmcap;
 	error = efi_enter();
 	if (error != 0)
 		return (error);
-	status = efi_runtime->rt_gettime(tm, tmcap);
+	ec.ec_fptr = (uintptr_t)(efi_runtime->rt_gettime);
+	error = efirt_arch_call(&ec);
 	efi_leave();
-	error = efi_status_to_errno(status);
+	if (error == 0)
+		error = efi_status_to_errno(ec.ec_efi_status);
 	return (error);
 }
 
diff --git a/sys/dev/efidev/efirtc.c b/sys/dev/efidev/efirtc.c
index b9e06bcc362..e5a2ec262bf 100644
--- a/sys/dev/efidev/efirtc.c
+++ b/sys/dev/efidev/efirtc.c
_at__at_ -74,7 +74,8 _at__at_ efirtc_probe(device_t dev)
 	 */
 	if ((error = efi_get_time(&tm)) != 0) {
 		if (bootverbose)
-			device_printf(dev, "cannot read EFI realtime clock\n");
+			device_printf(dev, "cannot read EFI realtime clock, "
+			    "error %d\n", error);
 		return (error);
 	}
 	device_set_desc(dev, "EFI Realtime Clock");
diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c
index 79b34dc7649..8b1b993dc58 100644
--- a/sys/kern/kern_thread.c
+++ b/sys/kern/kern_thread.c
_at__at_ -83,7 +83,7 _at__at_ _Static_assert(offsetof(struct thread, td_pflags) == 0x104,
     "struct thread KBI td_pflags");
 _Static_assert(offsetof(struct thread, td_frame) == 0x470,
     "struct thread KBI td_frame");
-_Static_assert(offsetof(struct thread, td_emuldata) == 0x518,
+_Static_assert(offsetof(struct thread, td_emuldata) == 0x520,
     "struct thread KBI td_emuldata");
 _Static_assert(offsetof(struct proc, p_flag) == 0xb0,
     "struct proc KBI p_flag");
diff --git a/sys/modules/efirt/Makefile b/sys/modules/efirt/Makefile
index 2613150db48..524d93ead93 100644
--- a/sys/modules/efirt/Makefile
+++ b/sys/modules/efirt/Makefile
_at__at_ -5,7 +5,11 _at__at_
 
 KMOD=	efirt
 SRCS=	efirt.c efirt_machdep.c efidev.c
-SRCS+=	efirtc.c
+SRCS+=	efirtc.c efirt_support.S
 SRCS+=  device_if.h bus_if.h clock_if.h
 
+efirt_support.o:	efirt_support.S assym.inc
+	${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \
+	    ${.IMPSRC} -o ${.TARGET}
+
 .include <bsd.kmod.mk>
Received on Wed Aug 29 2018 - 12:19:26 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:41:18 UTC