aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/amd64/efirt_machdep.c3
-rw-r--r--sys/amd64/amd64/efirt_support.S116
-rw-r--r--sys/amd64/amd64/genassym.c20
-rw-r--r--sys/amd64/include/efi.h21
-rw-r--r--sys/arm64/arm64/efirt_machdep.c7
-rw-r--r--sys/arm64/include/efi.h14
-rw-r--r--sys/conf/files.amd641
-rw-r--r--sys/dev/efidev/efirt.c180
-rw-r--r--sys/modules/efirt/Makefile7
-rw-r--r--sys/sys/efi.h3
10 files changed, 323 insertions, 49 deletions
diff --git a/sys/amd64/amd64/efirt_machdep.c b/sys/amd64/amd64/efirt_machdep.c
index da7783043a24..80ffa66f5ec4 100644
--- a/sys/amd64/amd64/efirt_machdep.c
+++ b/sys/amd64/amd64/efirt_machdep.c
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <machine/vmparam.h>
#include <vm/vm.h>
#include <vm/pmap.h>
+#include <vm/vm_extern.h>
#include <vm/vm_map.h>
#include <vm/vm_object.h>
#include <vm/vm_page.h>
@@ -266,6 +267,7 @@ efi_arch_enter(void)
curpmap = PCPU_GET(curpmap);
PMAP_LOCK_ASSERT(curpmap, MA_OWNED);
+ curthread->td_md.md_efirt_dis_pf = vm_fault_disable_pagefaults();
/*
* IPI TLB shootdown handler invltlb_pcid_handler() reloads
@@ -300,6 +302,7 @@ efi_arch_leave(void)
curpmap->pm_pcids[PCPU_GET(cpuid)].pm_pcid : 0));
if (!pmap_pcid_enabled)
invltlb();
+ vm_fault_enable_pagefaults(curthread->td_md.md_efirt_dis_pf);
}
/* XXX debug stuff */
diff --git a/sys/amd64/amd64/efirt_support.S b/sys/amd64/amd64/efirt_support.S
new file mode 100644
index 000000000000..cd578eddcfb1
--- /dev/null
+++ b/sys/amd64/amd64/efirt_support.S
@@ -0,0 +1,116 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov <kib@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(efi_rt_arch_call)
+ pushq %rbp
+ movq %rsp, %rbp
+
+ movq %rbx, EC_RBX(%rdi)
+ movq %rsp, EC_RSP(%rdi)
+ movq %rbp, EC_RBP(%rdi)
+ movq %r12, EC_R12(%rdi)
+ movq %r13, EC_R13(%rdi)
+ movq %r14, EC_R14(%rdi)
+ movq %r15, EC_R15(%rdi)
+ movq PCPU(CURTHREAD), %rax
+ movq %rdi, TD_MD+MD_EFIRT_TMP(%rax)
+ movq PCPU(CURPCB), %rsi
+
+ movl EC_ARGCNT(%rdi), %ecx
+ movl %ecx, %ebx
+ movl $4, %eax
+ cmpl %eax, %ecx
+ cmovbl %eax, %ecx
+ 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
+ decl %ebx
+ jz 1f
+ movq EC_ARG5(%rdi), %rax
+ movq %rax, 4*8(%rsp)
+ decl %ebx
+ jz 1f
+ movq $efi_rt_panic_str, %rdi
+ call panic
+1: movq EC_FPTR(%rdi), %rax
+ movq $efi_rt_fault, PCB_ONFAULT(%rsi)
+ callq *%rax
+
+ movq PCPU(CURTHREAD), %rbx
+ movq TD_MD+MD_EFIRT_TMP(%rbx), %rdi
+ movq %rax, EC_EFI_STATUS(%rdi)
+ movq PCPU(CURPCB), %rsi
+ xorl %eax, %eax
+ movq %rax, PCB_ONFAULT(%rsi)
+
+efi_rt_arch_call_tail:
+ movq EC_R15(%rdi), %r15
+ movq EC_R14(%rdi), %r14
+ movq EC_R13(%rdi), %r13
+ movq EC_R12(%rdi), %r12
+ movq EC_RBP(%rdi), %rbp
+ movq EC_RSP(%rdi), %rsp
+ movq EC_RBX(%rdi), %rbx
+
+ popq %rbp
+ ret
+END(efi_rt_arch_call)
+
+ENTRY(efi_rt_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 efi_rt_arch_call_tail
+END(efi_rt_fault)
+
+efi_rt_panic_str: .asciz "efi_rt_arch_call: too many args"
diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c
index d61b5c7bb6df..4d069388ee93 100644
--- a/sys/amd64/amd64/genassym.c
+++ b/sys/amd64/amd64/genassym.c
@@ -68,6 +68,7 @@ __FBSDID("$FreeBSD$");
#include <machine/sigframe.h>
#include <machine/proc.h>
#include <machine/segments.h>
+#include <machine/efi.h>
ASSYM(P_VMSPACE, offsetof(struct proc, p_vmspace));
ASSYM(VM_PMAP, offsetof(struct vmspace, vm_pmap));
@@ -77,12 +78,15 @@ 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);
@@ -249,3 +253,19 @@ 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_ARG5, offsetof(struct efirt_callinfo, ec_arg5));
+ASSYM(EC_RBX, offsetof(struct efirt_callinfo, ec_rbx));
+ASSYM(EC_RSP, offsetof(struct efirt_callinfo, ec_rsp));
+ASSYM(EC_RBP, offsetof(struct efirt_callinfo, ec_rbp));
+ASSYM(EC_R12, offsetof(struct efirt_callinfo, ec_r12));
+ASSYM(EC_R13, offsetof(struct efirt_callinfo, ec_r13));
+ASSYM(EC_R14, offsetof(struct efirt_callinfo, ec_r14));
+ASSYM(EC_R15, offsetof(struct efirt_callinfo, ec_r15));
diff --git a/sys/amd64/include/efi.h b/sys/amd64/include/efi.h
index 9fa54ee023fb..082223792ac0 100644
--- a/sys/amd64/include/efi.h
+++ b/sys/amd64/include/efi.h
@@ -51,6 +51,27 @@
#define EFI_TIME_LOCK() mtx_lock(&atrtc_time_lock)
#define EFI_TIME_UNLOCK() mtx_unlock(&atrtc_time_lock)
#define EFI_TIME_OWNED() mtx_assert(&atrtc_time_lock, MA_OWNED)
+
+#define EFI_RT_HANDLE_FAULTS_DEFAULT 1
#endif
+struct efirt_callinfo {
+ const char *ec_name;
+ 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;
+ register_t ec_arg5;
+ register_t ec_rbx;
+ register_t ec_rsp;
+ register_t ec_rbp;
+ register_t ec_r12;
+ register_t ec_r13;
+ register_t ec_r14;
+ register_t ec_r15;
+};
+
#endif /* __AMD64_INCLUDE_EFI_H_ */
diff --git a/sys/arm64/arm64/efirt_machdep.c b/sys/arm64/arm64/efirt_machdep.c
index 44e3a04ac372..cf092ff0dab7 100644
--- a/sys/arm64/arm64/efirt_machdep.c
+++ b/sys/arm64/arm64/efirt_machdep.c
@@ -268,3 +268,10 @@ efi_arch_leave(void)
"isb \n"
: : "r"(td->td_proc->p_md.md_l0addr));
}
+
+int
+efi_rt_arch_call(struct efirt_callinfo *ec)
+{
+
+ panic("not implemented");
+}
diff --git a/sys/arm64/include/efi.h b/sys/arm64/include/efi.h
index 6673adccb34f..a8fddfad8d0f 100644
--- a/sys/arm64/include/efi.h
+++ b/sys/arm64/include/efi.h
@@ -39,6 +39,20 @@
#define EFI_TIME_LOCK()
#define EFI_TIME_UNLOCK()
#define EFI_TIME_OWNED()
+
+#define EFI_RT_HANDLE_FAULTS_DEFAULT 0
#endif
+struct efirt_callinfo {
+ const char *ec_name;
+ 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;
+ register_t ec_arg5;
+};
+
#endif /* __ARM64_INCLUDE_EFI_H_ */
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index 93bf50f9502f..0407dd30c7f1 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -134,6 +134,7 @@ amd64/amd64/db_disasm.c optional ddb
amd64/amd64/db_interface.c optional ddb
amd64/amd64/db_trace.c optional ddb
amd64/amd64/efirt_machdep.c optional efirt
+amd64/amd64/efirt_support.S optional efirt
amd64/amd64/elf_machdep.c standard
amd64/amd64/exception.S standard
amd64/amd64/fpu.c standard
diff --git a/sys/dev/efidev/efirt.c b/sys/dev/efidev/efirt.c
index b3bc24f31e0d..ec4682dca237 100644
--- a/sys/dev/efidev/efirt.c
+++ b/sys/dev/efidev/efirt.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 2004 Marcel Moolenaar
* Copyright (c) 2001 Doug Rabson
- * Copyright (c) 2016 The FreeBSD Foundation
+ * Copyright (c) 2016, 2018 The FreeBSD Foundation
* All rights reserved.
*
* Portions of this software were developed by Konstantin Belousov
@@ -293,22 +293,89 @@ efi_get_table(struct uuid *uuid, void **ptr)
return (ENOENT);
}
+static int efi_rt_handle_faults = EFI_RT_HANDLE_FAULTS_DEFAULT;
+SYSCTL_INT(_machdep, OID_AUTO, efi_rt_handle_faults, CTLFLAG_RWTUN,
+ &efi_rt_handle_faults, 0,
+ "Call EFI RT methods with fault handler wrapper around");
+
static int
-efi_get_time_locked(struct efi_tm *tm, struct efi_tmcap *tmcap)
+efi_rt_arch_call_nofault(struct efirt_callinfo *ec)
+{
+
+ switch (ec->ec_argcnt) {
+ case 0:
+ ec->ec_efi_status = ((register_t (*)(void))ec->ec_fptr)();
+ break;
+ case 1:
+ ec->ec_efi_status = ((register_t (*)(register_t))ec->ec_fptr)
+ (ec->ec_arg1);
+ break;
+ case 2:
+ ec->ec_efi_status = ((register_t (*)(register_t, register_t))
+ ec->ec_fptr)(ec->ec_arg1, ec->ec_arg2);
+ break;
+ case 3:
+ ec->ec_efi_status = ((register_t (*)(register_t, register_t,
+ register_t))ec->ec_fptr)(ec->ec_arg1, ec->ec_arg2,
+ ec->ec_arg3);
+ break;
+ case 4:
+ ec->ec_efi_status = ((register_t (*)(register_t, register_t,
+ register_t, register_t))ec->ec_fptr)(ec->ec_arg1,
+ ec->ec_arg2, ec->ec_arg3, ec->ec_arg4);
+ break;
+ case 5:
+ ec->ec_efi_status = ((register_t (*)(register_t, register_t,
+ register_t, register_t, register_t))ec->ec_fptr)(
+ ec->ec_arg1, ec->ec_arg2, ec->ec_arg3, ec->ec_arg4,
+ ec->ec_arg5);
+ break;
+ default:
+ panic("efi_rt_arch_call: %d args", (int)ec->ec_argcnt);
+ }
+
+ return (0);
+}
+
+static int
+efi_call(struct efirt_callinfo *ecp)
{
- efi_status status;
int error;
- EFI_TIME_OWNED();
error = efi_enter();
if (error != 0)
return (error);
- status = efi_runtime->rt_gettime(tm, tmcap);
+ error = efi_rt_handle_faults ? efi_rt_arch_call(ecp) :
+ efi_rt_arch_call_nofault(ecp);
efi_leave();
- error = efi_status_to_errno(status);
+ if (error == 0)
+ error = efi_status_to_errno(ecp->ec_efi_status);
+ else if (bootverbose)
+ printf("EFI %s call faulted, error %d\n", ecp->ec_name, error);
return (error);
}
+#define EFI_RT_METHOD_PA(method) \
+ ((uintptr_t)((struct efi_rt *)efi_phys_to_kva((uintptr_t) \
+ efi_runtime))->method)
+
+static int
+efi_get_time_locked(struct efi_tm *tm, struct efi_tmcap *tmcap)
+{
+ struct efirt_callinfo ec;
+
+ EFI_TIME_OWNED();
+ if (efi_runtime == NULL)
+ return (ENXIO);
+ bzero(&ec, sizeof(ec));
+ ec.ec_name = "rt_gettime";
+ ec.ec_argcnt = 2;
+ ec.ec_arg1 = (uintptr_t)tm;
+ ec.ec_arg2 = (uintptr_t)tmcap;
+ ec.ec_fptr = EFI_RT_METHOD_PA(rt_gettime);
+ return (efi_call(&ec));
+}
+
int
efi_get_time(struct efi_tm *tm)
{
@@ -346,30 +413,35 @@ efi_get_time_capabilities(struct efi_tmcap *tmcap)
int
efi_reset_system(void)
{
- int error;
+ struct efirt_callinfo ec;
- error = efi_enter();
- if (error != 0)
- return (error);
- efi_runtime->rt_reset(EFI_RESET_WARM, 0, 0, NULL);
- efi_leave();
- return (EIO);
+ if (efi_runtime == NULL)
+ return (ENXIO);
+ bzero(&ec, sizeof(ec));
+ ec.ec_name = "rt_reset";
+ ec.ec_argcnt = 4;
+ ec.ec_arg1 = (uintptr_t)EFI_RESET_WARM;
+ ec.ec_arg1 = (uintptr_t)0;
+ ec.ec_arg1 = (uintptr_t)0;
+ ec.ec_arg1 = (uintptr_t)NULL;
+ ec.ec_fptr = EFI_RT_METHOD_PA(rt_reset);
+ return (efi_call(&ec));
}
static int
efi_set_time_locked(struct efi_tm *tm)
{
- efi_status status;
- int error;
+ struct efirt_callinfo ec;
EFI_TIME_OWNED();
- error = efi_enter();
- if (error != 0)
- return (error);
- status = efi_runtime->rt_settime(tm);
- efi_leave();
- error = efi_status_to_errno(status);
- return (error);
+ if (efi_runtime == NULL)
+ return (ENXIO);
+ bzero(&ec, sizeof(ec));
+ ec.ec_name = "rt_settime";
+ ec.ec_argcnt = 1;
+ ec.ec_arg1 = (uintptr_t)tm;
+ ec.ec_fptr = EFI_RT_METHOD_PA(rt_settime);
+ return (efi_call(&ec));
}
int
@@ -389,47 +461,57 @@ int
efi_var_get(efi_char *name, struct uuid *vendor, uint32_t *attrib,
size_t *datasize, void *data)
{
- efi_status status;
- int error;
+ struct efirt_callinfo ec;
- error = efi_enter();
- if (error != 0)
- return (error);
- status = efi_runtime->rt_getvar(name, vendor, attrib, datasize, data);
- efi_leave();
- error = efi_status_to_errno(status);
- return (error);
+ if (efi_runtime == NULL)
+ return (ENXIO);
+ bzero(&ec, sizeof(ec));
+ ec.ec_argcnt = 5;
+ ec.ec_name = "rt_getvar";
+ ec.ec_arg1 = (uintptr_t)name;
+ ec.ec_arg2 = (uintptr_t)vendor;
+ ec.ec_arg3 = (uintptr_t)attrib;
+ ec.ec_arg4 = (uintptr_t)datasize;
+ ec.ec_arg5 = (uintptr_t)data;
+ ec.ec_fptr = EFI_RT_METHOD_PA(rt_getvar);
+ return (efi_call(&ec));
}
int
efi_var_nextname(size_t *namesize, efi_char *name, struct uuid *vendor)
{
- efi_status status;
- int error;
+ struct efirt_callinfo ec;
- error = efi_enter();
- if (error != 0)
- return (error);
- status = efi_runtime->rt_scanvar(namesize, name, vendor);
- efi_leave();
- error = efi_status_to_errno(status);
- return (error);
+ if (efi_runtime == NULL)
+ return (ENXIO);
+ bzero(&ec, sizeof(ec));
+ ec.ec_argcnt = 3;
+ ec.ec_name = "rt_scanvar";
+ ec.ec_arg1 = (uintptr_t)namesize;
+ ec.ec_arg2 = (uintptr_t)name;
+ ec.ec_arg3 = (uintptr_t)vendor;
+ ec.ec_fptr = EFI_RT_METHOD_PA(rt_scanvar);
+ return (efi_call(&ec));
}
int
efi_var_set(efi_char *name, struct uuid *vendor, uint32_t attrib,
size_t datasize, void *data)
{
- efi_status status;
- int error;
+ struct efirt_callinfo ec;
- error = efi_enter();
- if (error != 0)
- return (error);
- status = efi_runtime->rt_setvar(name, vendor, attrib, datasize, data);
- efi_leave();
- error = efi_status_to_errno(status);
- return (error);
+ if (efi_runtime == NULL)
+ return (ENXIO);
+ bzero(&ec, sizeof(ec));
+ ec.ec_argcnt = 5;
+ ec.ec_name = "rt_setvar";
+ ec.ec_arg1 = (uintptr_t)name;
+ ec.ec_arg2 = (uintptr_t)vendor;
+ ec.ec_arg3 = (uintptr_t)attrib;
+ ec.ec_arg4 = (uintptr_t)datasize;
+ ec.ec_arg5 = (uintptr_t)data;
+ ec.ec_fptr = EFI_RT_METHOD_PA(rt_setvar);
+ return (efi_call(&ec));
}
static int
diff --git a/sys/modules/efirt/Makefile b/sys/modules/efirt/Makefile
index 2613150db489..2e53336cf22d 100644
--- a/sys/modules/efirt/Makefile
+++ b/sys/modules/efirt/Makefile
@@ -8,4 +8,11 @@ SRCS= efirt.c efirt_machdep.c efidev.c
SRCS+= efirtc.c
SRCS+= device_if.h bus_if.h clock_if.h
+.if ${MACHINE_CPUARCH} == "amd64"
+SRCS+= efirt_support.S
+efirt_support.o: efirt_support.S assym.inc
+ ${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \
+ ${.IMPSRC} -o ${.TARGET}
+.endif
+
.include <bsd.kmod.mk>
diff --git a/sys/sys/efi.h b/sys/sys/efi.h
index 0a0699d43256..622df48e7f32 100644
--- a/sys/sys/efi.h
+++ b/sys/sys/efi.h
@@ -169,10 +169,13 @@ struct efi_systbl {
extern vm_paddr_t efi_systbl_phys;
+struct efirt_callinfo;
+
/* Internal MD EFI functions */
int efi_arch_enter(void);
void efi_arch_leave(void);
vm_offset_t efi_phys_to_kva(vm_paddr_t);
+int efi_rt_arch_call(struct efirt_callinfo *);
bool efi_create_1t1_map(struct efi_md *, int, int);
void efi_destroy_1t1_map(void);