Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/efidev/efirt.c
/*- | /*- | ||||
* Copyright (c) 2004 Marcel Moolenaar | * Copyright (c) 2004 Marcel Moolenaar | ||||
* Copyright (c) 2001 Doug Rabson | * Copyright (c) 2001 Doug Rabson | ||||
* Copyright (c) 2016 The FreeBSD Foundation | * Copyright (c) 2016, 2018 The FreeBSD Foundation | ||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Portions of this software were developed by Konstantin Belousov | * Portions of this software were developed by Konstantin Belousov | ||||
* under sponsorship from the FreeBSD Foundation. | * under sponsorship from the FreeBSD Foundation. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
▲ Show 20 Lines • Show All 275 Lines • ▼ Show 20 Lines | if (!bcmp(&ct->ct_uuid, uuid, sizeof(*uuid))) { | ||||
*ptr = (void *)efi_phys_to_kva(ct->ct_data); | *ptr = (void *)efi_phys_to_kva(ct->ct_data); | ||||
return (0); | return (0); | ||||
} | } | ||||
ct++; | ct++; | ||||
} | } | ||||
return (ENOENT); | 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 | static int | ||||
efi_get_time_locked(struct efi_tm *tm, struct efi_tmcap *tmcap) | efi_rt_arch_call_nofault(struct efirt_callinfo *ec) | ||||
{ | { | ||||
efi_status status; | |||||
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) | |||||
{ | |||||
int error; | int error; | ||||
EFI_TIME_OWNED(); | |||||
error = efi_enter(); | error = efi_enter(); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | 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(); | 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); | 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 | int | ||||
efi_get_time(struct efi_tm *tm) | efi_get_time(struct efi_tm *tm) | ||||
{ | { | ||||
struct efi_tmcap dummy; | struct efi_tmcap dummy; | ||||
int error; | int error; | ||||
if (efi_runtime == NULL) | if (efi_runtime == NULL) | ||||
return (ENXIO); | return (ENXIO); | ||||
Show All 21 Lines | efi_get_time_capabilities(struct efi_tmcap *tmcap) | ||||
error = efi_get_time_locked(&dummy, tmcap); | error = efi_get_time_locked(&dummy, tmcap); | ||||
EFI_TIME_UNLOCK(); | EFI_TIME_UNLOCK(); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
efi_reset_system(void) | efi_reset_system(void) | ||||
{ | { | ||||
int error; | struct efirt_callinfo ec; | ||||
error = efi_enter(); | if (efi_runtime == NULL) | ||||
if (error != 0) | return (ENXIO); | ||||
return (error); | bzero(&ec, sizeof(ec)); | ||||
efi_runtime->rt_reset(EFI_RESET_WARM, 0, 0, NULL); | ec.ec_name = "rt_reset"; | ||||
efi_leave(); | ec.ec_argcnt = 4; | ||||
return (EIO); | 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 | static int | ||||
efi_set_time_locked(struct efi_tm *tm) | efi_set_time_locked(struct efi_tm *tm) | ||||
{ | { | ||||
efi_status status; | struct efirt_callinfo ec; | ||||
int error; | |||||
EFI_TIME_OWNED(); | EFI_TIME_OWNED(); | ||||
error = efi_enter(); | if (efi_runtime == NULL) | ||||
if (error != 0) | return (ENXIO); | ||||
return (error); | bzero(&ec, sizeof(ec)); | ||||
status = efi_runtime->rt_settime(tm); | ec.ec_name = "rt_settime"; | ||||
efi_leave(); | ec.ec_argcnt = 1; | ||||
error = efi_status_to_errno(status); | ec.ec_arg1 = (uintptr_t)tm; | ||||
return (error); | ec.ec_fptr = EFI_RT_METHOD_PA(rt_settime); | ||||
return (efi_call(&ec)); | |||||
} | } | ||||
int | int | ||||
efi_set_time(struct efi_tm *tm) | efi_set_time(struct efi_tm *tm) | ||||
{ | { | ||||
int error; | int error; | ||||
if (efi_runtime == NULL) | if (efi_runtime == NULL) | ||||
return (ENXIO); | return (ENXIO); | ||||
EFI_TIME_LOCK(); | EFI_TIME_LOCK(); | ||||
error = efi_set_time_locked(tm); | error = efi_set_time_locked(tm); | ||||
EFI_TIME_UNLOCK(); | EFI_TIME_UNLOCK(); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
efi_var_get(efi_char *name, struct uuid *vendor, uint32_t *attrib, | efi_var_get(efi_char *name, struct uuid *vendor, uint32_t *attrib, | ||||
size_t *datasize, void *data) | size_t *datasize, void *data) | ||||
{ | { | ||||
efi_status status; | struct efirt_callinfo ec; | ||||
int error; | |||||
error = efi_enter(); | if (efi_runtime == NULL) | ||||
if (error != 0) | return (ENXIO); | ||||
return (error); | bzero(&ec, sizeof(ec)); | ||||
status = efi_runtime->rt_getvar(name, vendor, attrib, datasize, data); | ec.ec_argcnt = 5; | ||||
efi_leave(); | ec.ec_name = "rt_getvar"; | ||||
error = efi_status_to_errno(status); | ec.ec_arg1 = (uintptr_t)name; | ||||
return (error); | 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 | int | ||||
efi_var_nextname(size_t *namesize, efi_char *name, struct uuid *vendor) | efi_var_nextname(size_t *namesize, efi_char *name, struct uuid *vendor) | ||||
{ | { | ||||
efi_status status; | struct efirt_callinfo ec; | ||||
int error; | |||||
error = efi_enter(); | if (efi_runtime == NULL) | ||||
if (error != 0) | return (ENXIO); | ||||
return (error); | bzero(&ec, sizeof(ec)); | ||||
status = efi_runtime->rt_scanvar(namesize, name, vendor); | ec.ec_argcnt = 3; | ||||
efi_leave(); | ec.ec_name = "rt_scanvar"; | ||||
error = efi_status_to_errno(status); | ec.ec_arg1 = (uintptr_t)namesize; | ||||
return (error); | 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 | int | ||||
efi_var_set(efi_char *name, struct uuid *vendor, uint32_t attrib, | efi_var_set(efi_char *name, struct uuid *vendor, uint32_t attrib, | ||||
size_t datasize, void *data) | size_t datasize, void *data) | ||||
{ | { | ||||
efi_status status; | struct efirt_callinfo ec; | ||||
int error; | |||||
error = efi_enter(); | if (efi_runtime == NULL) | ||||
if (error != 0) | return (ENXIO); | ||||
return (error); | bzero(&ec, sizeof(ec)); | ||||
status = efi_runtime->rt_setvar(name, vendor, attrib, datasize, data); | ec.ec_argcnt = 5; | ||||
efi_leave(); | ec.ec_name = "rt_setvar"; | ||||
error = efi_status_to_errno(status); | ec.ec_arg1 = (uintptr_t)name; | ||||
return (error); | 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 | static int | ||||
efirt_modevents(module_t m, int event, void *arg __unused) | efirt_modevents(module_t m, int event, void *arg __unused) | ||||
{ | { | ||||
switch (event) { | switch (event) { | ||||
case MOD_LOAD: | case MOD_LOAD: | ||||
Show All 22 Lines |