#ifndef WC_SKIP_INCLUDED_C_FILES
#include <sys/proc.h>
#include <sys/smp.h>
#include <machine/fpu.h>
#include <machine/pcb.h>
struct wolfkmod_fpu_state_t {
volatile lwpid_t td_tid;
volatile u_int nest;
};
typedef struct wolfkmod_fpu_state_t wolfkmod_fpu_state_t;
static wolfkmod_fpu_state_t * fpu_states = NULL;
#define wolfkmod_fpu_get_tid() \
atomic_load_acq_int(&fpu_states[PCPU_GET(cpuid)].td_tid)
int wolfkmod_vecreg_init(void)
{
if (mp_ncpus <= 0) {
printf("error: wolfkmod_vecreg_init: mp_ncpus = %d\n", mp_ncpus);
return (EINVAL);
}
fpu_states = malloc(mp_ncpus * sizeof(wolfkmod_fpu_state_t),
M_WOLFSSL, M_WAITOK | M_ZERO);
if (fpu_states == NULL) {
printf("error: wolfkmod_vecreg_init: malloc(%lu) failed\n",
mp_ncpus * sizeof(wolfkmod_fpu_state_t));
return (ENOMEM);
}
return (0);
}
void wolfkmod_vecreg_exit(void)
{
int i = 0;
if (fpu_states == NULL) {
return;
}
for (i = 0; i < mp_ncpus; ++i) {
#if defined(WOLFSSL_BSDKM_FPU_DEBUG)
printf("info: wolfkmod_vecreg_exit: fpu_states[%d] = %d, %d\n",
i, fpu_states[i].nest, fpu_states[i].td_tid);
#endif
if (fpu_states[i].nest != 0 || fpu_states[i].td_tid != 0) {
printf("error: wolfkmod_vecreg_exit: fpu_states[%d] = %d, %d\n",
i, fpu_states[i].nest, fpu_states[i].td_tid);
fpu_states[i].nest = 0;
}
}
free(fpu_states, M_WOLFSSL);
fpu_states = NULL;
return;
}
#if defined(WOLFSSL_BSDKM_FPU_DEBUG)
#define wolfkmod_print_curthread(what) \
printf("%s: cpuid = %d, curthread: td_tid = %d, pid = %d (%s), " \
"td_critnest = %d, kernfpu = %02x\n", \
(what), PCPU_GET(cpuid), curthread->td_tid, \
curthread->td_proc ? curthread->td_proc->p_pid : -1, \
curthread->td_proc ? curthread->td_proc->p_comm : "noproc", \
curthread->td_critnest, \
curthread->td_pcb->pcb_flags & PCB_KERNFPU);
#define wolfkmod_fpu_kern_enter() \
wolfkmod_print_curthread("fpu_kern_enter"); \
fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX);
#define wolfkmod_fpu_kern_leave() \
wolfkmod_print_curthread("fpu_kern_leave"); \
fpu_kern_leave(curthread, NULL);
#else
#define wolfkmod_fpu_kern_enter() \
fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX);
#define wolfkmod_fpu_kern_leave() \
fpu_kern_leave(curthread, NULL);
#endif
int wolfkmod_vecreg_save(int flags_unused)
{
(void)flags_unused;
#if defined(WOLFSSL_BSDKM_FPU_DEBUG)
wolfkmod_print_curthread("wolfkmod_vecreg_save");
#endif
if (is_fpu_kern_thread(0)) {
#if defined(WOLFSSL_BSDKM_FPU_DEBUG)
printf("info: wolfkmod_vecreg_save: is fpu kern thread\n");
#endif
return (0);
}
if (curthread->td_pcb->pcb_flags & PCB_KERNFPU) {
lwpid_t td_tid = wolfkmod_fpu_get_tid();
if (td_tid != curthread->td_tid) {
printf("error: wolfkmod_vecreg_save: got tid = %d, expected %d\n",
td_tid, curthread->td_tid);
return (EINVAL);
}
fpu_states[PCPU_GET(cpuid)].nest++;
}
else {
lwpid_t td_tid = 0;
wolfkmod_fpu_kern_enter();
td_tid = wolfkmod_fpu_get_tid();
if (fpu_states[PCPU_GET(cpuid)].nest != 0 || td_tid != 0) {
printf("error: wolfkmod_fpu_kern_enter() with nest: %d, %d\n",
fpu_states[PCPU_GET(cpuid)].nest, td_tid);
return (EINVAL);
}
fpu_states[PCPU_GET(cpuid)].nest++;
fpu_states[PCPU_GET(cpuid)].td_tid = curthread->td_tid;
}
return (0);
}
void wolfkmod_vecreg_restore(void)
{
#if defined(WOLFSSL_BSDKM_FPU_DEBUG)
wolfkmod_print_curthread("wolfkmod_vecreg_restore");
#endif
if (is_fpu_kern_thread(0)) {
#if defined(WOLFSSL_BSDKM_FPU_DEBUG)
printf("info: wolfkmod_vecreg_restore: is fpu kern thread\n");
#endif
return;
}
if (curthread->td_pcb->pcb_flags & PCB_KERNFPU) {
lwpid_t td_tid = wolfkmod_fpu_get_tid();
if (td_tid != curthread->td_tid) {
printf("error: wolfkmod_vecreg_restore: got tid = %d, "
"expected %d\n", td_tid, curthread->td_tid);
return;
}
if (fpu_states[PCPU_GET(cpuid)].nest > 0) {
fpu_states[PCPU_GET(cpuid)].nest--;
}
if (fpu_states[PCPU_GET(cpuid)].nest == 0) {
fpu_states[PCPU_GET(cpuid)].td_tid = 0;
wolfkmod_fpu_kern_leave();
}
}
return;
}
#endif