aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/efidev/efirt.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/efidev/efirt.c')
-rw-r--r--sys/dev/efidev/efirt.c180
1 files changed, 131 insertions, 49 deletions
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