From 02bafaa573d87371ed9d3a86e3b7d4cf8ccb7dc2 Mon Sep 17 00:00:00 2001 From: Bart Oldeman Date: Mon, 23 Jan 2023 11:17:45 -0500 Subject: [PATCH 01/13] DPMI: native: only copy to/from vm86_fpu_state on demand. Similar to the KVM hooks. --- src/dosext/dpmi/dnative/dnative.c | 32 ++++++++++++++++++++----------- src/dosext/dpmi/dnative/dnative.h | 10 ++++++++++ src/dosext/dpmi/dpmi.c | 16 ++++++++++++++-- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/dosext/dpmi/dnative/dnative.c b/src/dosext/dpmi/dnative/dnative.c index 71c4b77410..fd42d3f7b5 100644 --- a/src/dosext/dpmi/dnative/dnative.c +++ b/src/dosext/dpmi/dnative/dnative.c @@ -43,6 +43,7 @@ static struct sigaction emu_tmp_act; #define DPMI_TMP_SIG SIGUSR1 static int in_dpmi_thr; static int dpmi_thr_running; +static fpregset_t scp_fpregs; static void copy_context(sigcontext_t *d, sigcontext_t *s) { @@ -105,18 +106,22 @@ static void copy_to_dpmi(sigcontext_t *scp, cpuctx_t *s) _C(trapno); _C(err); _C(cr2); + scp_fpregs = NULL; +} - if (scp->fpregs) { - void *fpregs = scp->fpregs; +void native_dpmi_enter_from_vm86(void) +{ + if (scp_fpregs) { + void *fpregs = scp_fpregs; #ifdef __x86_64__ - static_assert(sizeof(*scp->fpregs) == sizeof(vm86_fpu_state), + static_assert(sizeof(*scp_fpregs) == sizeof(vm86_fpu_state), "size mismatch"); #else /* i386: convert fxsave state to fsave state */ - convert_from_fxsr(scp->fpregs, &vm86_fpu_state); - if ((scp->fpregs->status >> 16) != EMU_X86_FXSR_MAGIC) + convert_from_fxsr(scp_fpregs, &vm86_fpu_state); + if ((scp_fpregs->status >> 16) != EMU_X86_FXSR_MAGIC) return; - fpregs = &scp->fpregs->status + 1; + fpregs = &scp_fpregs->status + 1; #endif memcpy(fpregs, &vm86_fpu_state, sizeof(vm86_fpu_state)); } @@ -144,14 +149,19 @@ static void copy_to_emu(cpuctx_t *d, sigcontext_t *scp) _D(trapno); _D(err); _D(cr2); - if (scp->fpregs) { - void *fpregs = scp->fpregs; + scp_fpregs = scp->fpregs; +} + +void native_dpmi_leave_to_vm86(void) +{ + if (scp_fpregs) { + void *fpregs = scp_fpregs; #ifdef __x86_64__ - static_assert(sizeof(*scp->fpregs) == sizeof(vm86_fpu_state), + static_assert(sizeof(*scp_fpregs) == sizeof(vm86_fpu_state), "size mismatch"); #else - if ((scp->fpregs->status >> 16) == EMU_X86_FXSR_MAGIC) - fpregs = &scp->fpregs->status + 1; + if ((scp_fpregs->status >> 16) == EMU_X86_FXSR_MAGIC) + fpregs = &scp_fpregs->status + 1; else { fsave_to_fxsave(fpregs, &vm86_fpu_state); return; diff --git a/src/dosext/dpmi/dnative/dnative.h b/src/dosext/dpmi/dnative/dnative.h index bf9894a805..d4676ef253 100644 --- a/src/dosext/dpmi/dnative/dnative.h +++ b/src/dosext/dpmi/dnative/dnative.h @@ -9,6 +9,8 @@ int native_dpmi_control(cpuctx_t *scp); int native_dpmi_exit(cpuctx_t *scp); void native_dpmi_enter(void); void native_dpmi_leave(void); +void native_dpmi_enter_from_vm86(void); +void native_dpmi_leave_to_vm86(void); void dpmi_return(sigcontext_t *scp, int retcode); #else @@ -41,6 +43,14 @@ static inline void native_dpmi_leave(void) { } +static inline void native_dpmi_enter_from_vm86(void) +{ +} + +static inline void native_dpmi_leave_to_vm86(void) +{ +} + static inline void dpmi_return(sigcontext_t *scp, int retcode) { } diff --git a/src/dosext/dpmi/dpmi.c b/src/dosext/dpmi/dpmi.c index f83aee38f2..8bf89eee88 100644 --- a/src/dosext/dpmi/dpmi.c +++ b/src/dosext/dpmi/dpmi.c @@ -420,14 +420,26 @@ static void print_ldt(void) static void leave_backend(int be, int pm) { - if (be == CPUVM_KVM) + switch(be) { + case CPUVM_KVM: kvm_leave(pm); + break; + case CPUVM_NATIVE: + native_dpmi_leave_to_vm86(); + break; + } } static void enter_backend(int be, int pm) { - if (be == CPUVM_KVM) + switch(be) { + case CPUVM_KVM: kvm_enter(pm); + break; + case CPUVM_NATIVE: + native_dpmi_enter_from_vm86(); + break; + } } static void dpmi_set_pm(int pm) From 81df683763be24f27110709a0198fcb618d2db83 Mon Sep 17 00:00:00 2001 From: Bart Oldeman Date: Mon, 23 Jan 2023 20:13:50 -0500 Subject: [PATCH 02/13] DPMI/cpuemu: save/restore FPU state when entering/leaving backend --- src/base/core/emu.c | 8 +++++++- src/base/emu-i386/simx86/codegen.h | 2 ++ src/base/emu-i386/simx86/cpu-emu.c | 18 +++++++++++++++++ src/base/emu-i386/simx86/fp87-sim.c | 30 +++++++++++++++++++++++++++++ src/dosext/dpmi/dpmi.c | 6 ++++++ src/include/cpu-emu.h | 2 ++ 6 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/base/core/emu.c b/src/base/core/emu.c index 479d7291dd..6b4da094e3 100644 --- a/src/base/core/emu.c +++ b/src/base/core/emu.c @@ -376,8 +376,14 @@ int main(int argc, char **argv, char * const *envp) set_kvm_memory_regions(); cpu_reset(); - if (config.cpu_vm == CPUVM_KVM) + switch(config.cpu_vm) { + case CPUVM_KVM: kvm_enter(0); + break; + case CPUVM_EMU: + e_enter(); + break; + } can_leavedos = 1; while (!fatalerr && !config.exitearly) { diff --git a/src/base/emu-i386/simx86/codegen.h b/src/base/emu-i386/simx86/codegen.h index e45af23b39..dfa857d838 100644 --- a/src/base/emu-i386/simx86/codegen.h +++ b/src/base/emu-i386/simx86/codegen.h @@ -276,6 +276,8 @@ extern unsigned int (*CloseAndExec)(unsigned int PC, int mode); void EndGen(void); extern void fp87_set_rounding(void); extern void fp87_save_except(void); +extern void fp87_save_fpstate(emu_fpstate *); +extern void fp87_load_fpstate(const emu_fpstate *); // extern unsigned char InterOps[]; extern char RmIsReg[]; diff --git a/src/base/emu-i386/simx86/cpu-emu.c b/src/base/emu-i386/simx86/cpu-emu.c index fe165deca7..e661e1112a 100644 --- a/src/base/emu-i386/simx86/cpu-emu.c +++ b/src/base/emu-i386/simx86/cpu-emu.c @@ -581,6 +581,24 @@ void Cpu2Reg (void) REG(eflags),get_FLAGS(TheCPU.eflags),TheCPU.eflags); } +void e_enter(void) +{ + if (CONFIG_CPUSIM) + fp87_load_fpstate(&vm86_fpu_state); + else { + // unmasked exception settings are emulated + TheCPU.fpuc = vm86_fpu_state.cwd; + vm86_fpu_state.cwd |= 0x3f; + } +} + +void e_leave(void) +{ + if (CONFIG_CPUSIM) + fp87_save_fpstate(&vm86_fpu_state); + else + vm86_fpu_state.cwd = (vm86_fpu_state.cwd & ~0x3f) | (TheCPU.fpuc & 0x3f); +} /* ======================================================================= */ diff --git a/src/base/emu-i386/simx86/fp87-sim.c b/src/base/emu-i386/simx86/fp87-sim.c index 2d68682543..5bab546692 100644 --- a/src/base/emu-i386/simx86/fp87-sim.c +++ b/src/base/emu-i386/simx86/fp87-sim.c @@ -177,6 +177,36 @@ void fp87_save_except(void) TheCPU.fpus = (fps&~FPUS_TOP)|(TheCPU.fpstt< Date: Tue, 24 Jan 2023 09:00:51 -0500 Subject: [PATCH 03/13] DPMI/VM86: save/restore FPU state when entering/leaving backend --- src/base/core/emu.c | 5 +++++ src/base/emu-i386/do_vm86.c | 25 +++++++++++++++++++++++-- src/dosext/dpmi/dpmi.c | 10 ++++++++++ src/include/cpu.h | 22 +++++++++++++++------- src/include/emu.h | 2 ++ 5 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/base/core/emu.c b/src/base/core/emu.c index 6b4da094e3..f278505209 100644 --- a/src/base/core/emu.c +++ b/src/base/core/emu.c @@ -383,6 +383,11 @@ int main(int argc, char **argv, char * const *envp) case CPUVM_EMU: e_enter(); break; +#ifdef __i386__ + case CPUVM_VM86: + true_vm86_enter(); + break; +#endif } can_leavedos = 1; diff --git a/src/base/emu-i386/do_vm86.c b/src/base/emu-i386/do_vm86.c index 8395874b9e..f3af897fda 100644 --- a/src/base/emu-i386/do_vm86.c +++ b/src/base/emu-i386/do_vm86.c @@ -441,12 +441,18 @@ static int handle_GP_hlt(void) } #ifdef __i386__ +/* avoid converting to and from fxsave when staying in vm86 */ +static struct emu_fsave true_vm86_fsave; + static int true_vm86(union vm86_union *x) { int ret; uint32_t old_flags = REG(eflags); - loadfpstate(vm86_fpu_state); + if (config.cpufxsr) + loadfxsave(vm86_fpu_state); + else + loadfsave(true_vm86_fsave); again: #if 0 ret = vm86(&x->vm86ps); @@ -464,7 +470,10 @@ static int true_vm86(union vm86_union *x) * TODO: check kernel version */ REG(eflags) |= (old_flags & VIP); - savefpstate(vm86_fpu_state); + if (config.cpufxsr) + savefxsave(vm86_fpu_state); + else + savefsave(true_vm86_fsave); /* there is no real need to save and restore the FPU state of the emulator itself: savefpstate (fnsave) also resets the current FPU state using fninit; fesetenv then restores trapping of division by @@ -474,6 +483,18 @@ static int true_vm86(union vm86_union *x) fesetenv(&dosemu_fenv); return ret; } + +void true_vm86_enter(void) +{ + if (!config.cpufxsr) + fxsave_to_fsave(&vm86_fpu_state, &true_vm86_fsave); +} + +void true_vm86_leave(void) +{ + if (!config.cpufxsr) + fsave_to_fxsave(&true_vm86_fsave, &vm86_fpu_state); +} #endif static int do_vm86(union vm86_union *x) diff --git a/src/dosext/dpmi/dpmi.c b/src/dosext/dpmi/dpmi.c index ae606f3b9e..ff91970c35 100644 --- a/src/dosext/dpmi/dpmi.c +++ b/src/dosext/dpmi/dpmi.c @@ -430,6 +430,11 @@ static void leave_backend(int be, int pm) case CPUVM_EMU: e_leave(); break; +#ifdef __i386__ + case CPUVM_VM86: + true_vm86_leave(); + break; +#endif } } @@ -445,6 +450,11 @@ static void enter_backend(int be, int pm) case CPUVM_EMU: e_enter(); break; +#ifdef __i386__ + case CPUVM_VM86: + true_vm86_enter(); + break; +#endif } } diff --git a/src/include/cpu.h b/src/include/cpu.h index 0ee5db74df..6daec4ff5d 100644 --- a/src/include/cpu.h +++ b/src/include/cpu.h @@ -304,42 +304,50 @@ extern fenv_t dosemu_fenv; asm volatile("mov %%" #reg ",%0":"=rm" (__value)); \ __value; \ }) +#define loadfsave(value) asm volatile("frstor %0\n" :: "m"(value)) +#define savefsave(value) asm volatile("fnsave %0; fwait\n" : "=m"(value)) +/* use 32bit versions */ +#define loadfxsave(value) asm volatile("fxrstor %0\n" :: "m"(value)) +#define savefxsave(value) asm volatile("fxsave %0\n" : "=m"(value)) #else #define loadflags(value) #define getflags() 0 #define loadregister(reg, value) #define getregister(reg) 0 #define getsegment(reg) 0 +#define loadfsave(value) +#define savefsave(value) +#define loadfxsave(value) +#define savefxsave(value) #endif static inline void loadfpstate_legacy(emu_fpstate *buf) { struct emu_fsave fsave; fxsave_to_fsave(buf, &fsave); - asm volatile("frstor %0\n" :: "m"(fsave)); + loadfsave(fsave); } static inline void savefpstate_legacy(emu_fpstate *buf) { struct emu_fsave fsave; - asm volatile("fnsave %0; fwait\n" : "=m"(fsave)); + savefsave(fsave); fsave_to_fxsave(&fsave, buf); } #if defined(__x86_64__) -/* use 32bit versions */ -#define loadfpstate(value) asm volatile("fxrstor %0\n" :: "m"(value)) -#define savefpstate(value) asm volatile("fxsave %0\n" : "=m"(value)) +#define loadfpstate(value) loadfxsave(value) +#define savefpstate(value) savefxsave(value) #elif defined (__i386__) #define loadfpstate(value) do { \ if (config.cpufxsr) \ - asm volatile("fxrstor %0\n" :: "m"(value)); \ + loadfxsave(value); \ else \ loadfpstate_legacy(&value); \ } while (0) #define savefpstate(value) do { \ if (config.cpufxsr) \ - asm volatile("fxsave %0\n" : "=m"(value)); \ + savefxsave(value); \ else \ savefpstate_legacy(&value); \ } while (0) diff --git a/src/include/emu.h b/src/include/emu.h index 4f05bfc229..edfe0499c6 100644 --- a/src/include/emu.h +++ b/src/include/emu.h @@ -104,6 +104,8 @@ extern FILE *real_stderr; void dos_ctrl_alt_del(void); /* disabled */ extern void vm86_helper(void); +extern void true_vm86_enter(void); +extern void true_vm86_leave(void); extern void run_vm86(void); extern void loopstep_run_vm86(void); extern int do_call_back(Bit16u cs, Bit16u ip); From 746e05935426f5147d71bbe47e03760acc496bf4 Mon Sep 17 00:00:00 2001 From: Bart Oldeman Date: Wed, 25 Jan 2023 09:46:42 -0500 Subject: [PATCH 04/13] FPU: call pic_untrigger(13) from port handler. That's the correct way, as int75 does an "out" to port f0 (idea from Bochs). --- src/base/emu-i386/cpu.c | 3 +-- src/base/emu-i386/do_vm86.c | 1 - src/base/emu-i386/kvm.c | 1 - src/dosext/dpmi/dnative/sigsegv.c | 1 - 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/base/emu-i386/cpu.c b/src/base/emu-i386/cpu.c index 7afc9cd2ac..f6f74cb4ea 100644 --- a/src/base/emu-i386/cpu.c +++ b/src/base/emu-i386/cpu.c @@ -257,8 +257,7 @@ static void fpu_io_write(ioport_t port, Bit8u val) { switch (port) { case 0xf0: - /* not sure about this */ - vm86_fpu_state.swd &= ~0x8000; + pic_untrigger(13); /* done by default via int75 handler in bios.S */ break; case 0xf1: fpu_reset(); diff --git a/src/base/emu-i386/do_vm86.c b/src/base/emu-i386/do_vm86.c index f3af897fda..bd9b632019 100644 --- a/src/base/emu-i386/do_vm86.c +++ b/src/base/emu-i386/do_vm86.c @@ -74,7 +74,6 @@ int vm86_fault(unsigned trapno, unsigned err, dosaddr_t cr2) return 0; case 0x10: /* coprocessor error */ - pic_untrigger(13); pic_request(13); /* this is the 386 way of signalling this */ return 0; diff --git a/src/base/emu-i386/kvm.c b/src/base/emu-i386/kvm.c index afcaaf5bfd..bcbdd52046 100644 --- a/src/base/emu-i386/kvm.c +++ b/src/base/emu-i386/kvm.c @@ -1166,7 +1166,6 @@ int kvm_dpmi(cpuctx_t *scp) print_exception_info(scp); #endif dbug_printf("coprocessor exception, calling IRQ13\n"); - pic_untrigger(13); pic_request(13); ret = DPMI_RET_DOSEMU; } else if (_trapno == 0x0e && diff --git a/src/dosext/dpmi/dnative/sigsegv.c b/src/dosext/dpmi/dnative/sigsegv.c index f20939a192..31cff0a547 100644 --- a/src/dosext/dpmi/dnative/sigsegv.c +++ b/src/dosext/dpmi/dnative/sigsegv.c @@ -122,7 +122,6 @@ static void dosemu_fault1(int signum, sigcontext_t *scp) if (_scp_trapno == 0x10) { dbug_printf("coprocessor exception, calling IRQ13\n"); print_exception_info(scp); - pic_untrigger(13); pic_request(13); dpmi_return(scp, DPMI_RET_DOSEMU); return; From 5984456582d5b36d0389bc0630dabddfa78c71c1 Mon Sep 17 00:00:00 2001 From: Bart Oldeman Date: Wed, 25 Jan 2023 09:54:10 -0500 Subject: [PATCH 05/13] FPU: eliminate global vm86_fpu_state. Rely on passing a temporary struct on the stack instead, state is only in backends (static for vm86, in VM for KVM, signal stack for native DPMI, TheCPU for cpu-emu). --- src/base/core/emu.c | 13 ------------ src/base/emu-i386/cpu.c | 28 ++++++++++++++++++-------- src/base/emu-i386/do_vm86.c | 27 +++++++++++++++++-------- src/base/emu-i386/kvm.c | 12 +++++------ src/base/emu-i386/simx86/cpu-emu.c | 32 +++++++++++++++++++----------- src/base/emu-i386/simx86/syncpu.h | 1 + src/dosext/dpmi/dnative/dnative.c | 19 +++++++++++------- src/dosext/dpmi/dnative/dnative.h | 13 ++++++++---- src/dosext/dpmi/dpmi.c | 25 ++++++++++++----------- src/include/cpu-emu.h | 5 +++-- src/include/cpu.h | 1 - src/include/emu.h | 5 +++-- src/include/kvm.h | 12 +++++------ 13 files changed, 112 insertions(+), 81 deletions(-) diff --git a/src/base/core/emu.c b/src/base/core/emu.c index f278505209..b99fc75e28 100644 --- a/src/base/core/emu.c +++ b/src/base/core/emu.c @@ -376,19 +376,6 @@ int main(int argc, char **argv, char * const *envp) set_kvm_memory_regions(); cpu_reset(); - switch(config.cpu_vm) { - case CPUVM_KVM: - kvm_enter(0); - break; - case CPUVM_EMU: - e_enter(); - break; -#ifdef __i386__ - case CPUVM_VM86: - true_vm86_enter(); - break; -#endif - } can_leavedos = 1; while (!fatalerr && !config.exitearly) { diff --git a/src/base/emu-i386/cpu.c b/src/base/emu-i386/cpu.c index f6f74cb4ea..22192668dc 100644 --- a/src/base/emu-i386/cpu.c +++ b/src/base/emu-i386/cpu.c @@ -35,6 +35,7 @@ #include "emudpmi.h" #include "priv.h" #include "kvm.h" +#include "dnative.h" #ifdef X86_EMULATOR #include "simx86/syncpu.h" @@ -92,8 +93,6 @@ static unsigned int TRs[2] = }; #endif -/* fpu_state needs to be paragraph aligned for fxrstor/fxsave */ -emu_fpstate vm86_fpu_state __attribute__((aligned(16))); fenv_t dosemu_fenv; static void fpu_reset(void); @@ -241,11 +240,25 @@ static void fpu_init(void) static void fpu_reset(void) { - vm86_fpu_state.cwd = 0x0040; - vm86_fpu_state.swd = 0; - vm86_fpu_state.ftw = 0x5555; //bochs - if (config.cpu_vm == CPUVM_KVM || config.cpu_vm_dpmi == CPUVM_KVM) - kvm_update_fpu(); + emu_fpstate vm86_fpu_state; + int cpu_vm; + + memset(&vm86_fpu_state, 0, sizeof vm86_fpu_state); + vm86_fpu_state.cwd = 0x0040; //bochs + vm86_fpu_state.ftw = 0xff; //all valid (-> 0x5555 in fsave tag) + cpu_vm = in_dpmi_pm() ? config.cpu_vm_dpmi : config.cpu_vm; + switch(cpu_vm) { + case CPUVM_KVM: + kvm_update_fpu(&vm86_fpu_state); + case CPUVM_EMU: + e_update_fpu(&vm86_fpu_state); + case CPUVM_NATIVE: + native_dpmi_update_fpu(&vm86_fpu_state); +#ifdef __i386__ + case CPUVM_VM86: + true_vm86_update_fpu(&vm86_fpu_state); +#endif + } } static Bit8u fpu_io_read(ioport_t port) @@ -291,7 +304,6 @@ void cpu_setup(void) io_dev.handler_name = "Math Coprocessor"; port_register_handler(io_dev, 0); - savefpstate(vm86_fpu_state); #ifdef FE_NOMASK_ENV feenableexcept(FE_DIVBYZERO | FE_OVERFLOW); #endif diff --git a/src/base/emu-i386/do_vm86.c b/src/base/emu-i386/do_vm86.c index bd9b632019..26db1e916d 100644 --- a/src/base/emu-i386/do_vm86.c +++ b/src/base/emu-i386/do_vm86.c @@ -442,6 +442,8 @@ static int handle_GP_hlt(void) #ifdef __i386__ /* avoid converting to and from fxsave when staying in vm86 */ static struct emu_fsave true_vm86_fsave; +/* this needs to be paragraph aligned for fxrstor/fxsave */ +static struct emu_fpxstate true_vm86_fxsave __attribute__((aligned(16))); static int true_vm86(union vm86_union *x) { @@ -449,7 +451,7 @@ static int true_vm86(union vm86_union *x) uint32_t old_flags = REG(eflags); if (config.cpufxsr) - loadfxsave(vm86_fpu_state); + loadfxsave(true_vm86_fxsave); else loadfsave(true_vm86_fsave); again: @@ -470,7 +472,7 @@ static int true_vm86(union vm86_union *x) REG(eflags) |= (old_flags & VIP); if (config.cpufxsr) - savefxsave(vm86_fpu_state); + savefxsave(true_vm86_fxsave); else savefsave(true_vm86_fsave); /* there is no real need to save and restore the FPU state of the @@ -483,16 +485,25 @@ static int true_vm86(union vm86_union *x) return ret; } -void true_vm86_enter(void) +void true_vm86_update_fpu(const emu_fpstate *fpstate) { - if (!config.cpufxsr) - fxsave_to_fsave(&vm86_fpu_state, &true_vm86_fsave); + if (config.cpufxsr) + true_vm86_fxsave = *fpstate; + else + fxsave_to_fsave(fpstate, &true_vm86_fsave); } -void true_vm86_leave(void) +void true_vm86_enter(const emu_fpstate *fpstate) { - if (!config.cpufxsr) - fsave_to_fxsave(&true_vm86_fsave, &vm86_fpu_state); + true_vm86_update_fpu(fpstate); +} + +void true_vm86_leave(emu_fpstate *fpstate) +{ + if (config.cpufxsr) + *fpstate = true_vm86_fxsave; + else + fsave_to_fxsave(&true_vm86_fsave, fpstate); } #endif diff --git a/src/base/emu-i386/kvm.c b/src/base/emu-i386/kvm.c index bcbdd52046..f0d9216500 100644 --- a/src/base/emu-i386/kvm.c +++ b/src/base/emu-i386/kvm.c @@ -783,12 +783,12 @@ static void set_ldt_seg(struct kvm_segment *seg, unsigned selector) seg->unusable = !desc->present; } -void kvm_update_fpu(void) +void kvm_update_fpu(const emu_fpstate *fpstate) { struct kvm_xsave fpu = {}; int ret; - memcpy(fpu.region, &vm86_fpu_state, sizeof(vm86_fpu_state)); + memcpy(fpu.region, fpstate, sizeof(*fpstate)); ret = ioctl(vcpufd, KVM_SET_XSAVE, &fpu); if (ret == -1) { perror("KVM: KVM_SET_XSAVE"); @@ -796,12 +796,12 @@ void kvm_update_fpu(void) } } -void kvm_enter(int pm) +void kvm_enter(int pm, const emu_fpstate *fpstate) { - kvm_update_fpu(); + kvm_update_fpu(fpstate); } -void kvm_leave(int pm) +void kvm_leave(int pm, emu_fpstate *fpstate) { struct kvm_xsave fpu; int ret = ioctl(vcpufd, KVM_GET_XSAVE, &fpu); @@ -809,7 +809,7 @@ void kvm_leave(int pm) perror("KVM: KVM_GET_XSAVE"); leavedos_main(99); } - memcpy(&vm86_fpu_state, fpu.region, sizeof(vm86_fpu_state)); + memcpy(fpstate, fpu.region, sizeof(*fpstate)); } static int kvm_post_run(struct vm86_regs *regs, struct kvm_regs *kregs) diff --git a/src/base/emu-i386/simx86/cpu-emu.c b/src/base/emu-i386/simx86/cpu-emu.c index e661e1112a..cdfde521e8 100644 --- a/src/base/emu-i386/simx86/cpu-emu.c +++ b/src/base/emu-i386/simx86/cpu-emu.c @@ -524,7 +524,7 @@ static void Reg2Cpu (int mode) trans_addr = LONG_CS + TheCPU.eip; /* FPU state is loaded later on demand for JIT, not used for simulator */ - TheCPU.fpstate = &vm86_fpu_state; + TheCPU.fpstate = &TheCPU._fpstate; if (debug_level('e')>1) { if (debug_level('e')==9) e_printf("Reg2Cpu< vm86=%08x dpm=%08x emu=%08x\n%s\n", REG(eflags),get_FLAGS(TheCPU.eflags),TheCPU.eflags, @@ -571,7 +571,7 @@ void Cpu2Reg (void) if (TheCPU.fpstate == NULL) { if (!CONFIG_CPUSIM) - savefpstate(vm86_fpu_state); + savefpstate(TheCPU._fpstate); else fp87_save_except(); fesetenv(&dosemu_fenv); @@ -581,23 +581,31 @@ void Cpu2Reg (void) REG(eflags),get_FLAGS(TheCPU.eflags),TheCPU.eflags); } -void e_enter(void) +void e_update_fpu(const emu_fpstate *fpstate) { if (CONFIG_CPUSIM) - fp87_load_fpstate(&vm86_fpu_state); + fp87_load_fpstate(fpstate); else { // unmasked exception settings are emulated - TheCPU.fpuc = vm86_fpu_state.cwd; - vm86_fpu_state.cwd |= 0x3f; + TheCPU.fpuc = fpstate->cwd; + TheCPU._fpstate = *fpstate; + TheCPU._fpstate.cwd |= 0x3f; } } -void e_leave(void) +void e_enter(const emu_fpstate *fpstate) +{ + e_update_fpu(fpstate); +} + +void e_leave(emu_fpstate *fpstate) { if (CONFIG_CPUSIM) - fp87_save_fpstate(&vm86_fpu_state); - else - vm86_fpu_state.cwd = (vm86_fpu_state.cwd & ~0x3f) | (TheCPU.fpuc & 0x3f); + fp87_save_fpstate(fpstate); + else { + *fpstate = TheCPU._fpstate; + fpstate->cwd = (fpstate->cwd & ~0x3f) | (TheCPU.fpuc & 0x3f); + } } /* ======================================================================= */ @@ -628,7 +636,7 @@ static void Scp2Cpu (cpuctx_t *scp) TheCPU.cr2 = _cr2; TheCPU.df_increments = (TheCPU.eflags&DF)?0xfcfeff:0x040201; - TheCPU.fpstate = &vm86_fpu_state; + TheCPU.fpstate = &TheCPU._fpstate; } /* @@ -669,7 +677,7 @@ static void Cpu2Scp (cpuctx_t *scp, int trapno) if (!TheCPU.err) _err = 0; //??? if (TheCPU.fpstate == NULL) { if (!CONFIG_CPUSIM) - savefpstate(vm86_fpu_state); + savefpstate(TheCPU._fpstate); else fp87_save_except(); /* there is no real need to save and restore the FPU state of the diff --git a/src/base/emu-i386/simx86/syncpu.h b/src/base/emu-i386/simx86/syncpu.h index 05a81fb770..22808ab165 100644 --- a/src/base/emu-i386/simx86/syncpu.h +++ b/src/base/emu-i386/simx86/syncpu.h @@ -158,6 +158,7 @@ typedef struct { if NULL, emulator uses FPU instructions, so flags that dosemu needs to restore its own FPU environment. */ emu_fpregset_t fpstate; + emu_fpstate _fpstate __attribute__((aligned(16))); } SynCPU; union _SynCPU { diff --git a/src/dosext/dpmi/dnative/dnative.c b/src/dosext/dpmi/dnative/dnative.c index fd42d3f7b5..dde6679c90 100644 --- a/src/dosext/dpmi/dnative/dnative.c +++ b/src/dosext/dpmi/dnative/dnative.c @@ -109,24 +109,29 @@ static void copy_to_dpmi(sigcontext_t *scp, cpuctx_t *s) scp_fpregs = NULL; } -void native_dpmi_enter_from_vm86(void) +void native_dpmi_update_fpu(const emu_fpstate *fpstate) { if (scp_fpregs) { void *fpregs = scp_fpregs; #ifdef __x86_64__ - static_assert(sizeof(*scp_fpregs) == sizeof(vm86_fpu_state), + static_assert(sizeof(*scp_fpregs) == sizeof(*fpstate), "size mismatch"); #else /* i386: convert fxsave state to fsave state */ - convert_from_fxsr(scp_fpregs, &vm86_fpu_state); + convert_from_fxsr(scp_fpregs, fpstate); if ((scp_fpregs->status >> 16) != EMU_X86_FXSR_MAGIC) return; fpregs = &scp_fpregs->status + 1; #endif - memcpy(fpregs, &vm86_fpu_state, sizeof(vm86_fpu_state)); + memcpy(fpregs, fpstate, sizeof(*fpstate)); } } +void native_dpmi_enter_from_vm86(const emu_fpstate *fpstate) +{ + native_dpmi_update_fpu(fpstate); +} + static void copy_to_emu(cpuctx_t *d, sigcontext_t *scp) { #define _D(x) get_##x(d) = _scp_##x @@ -152,12 +157,12 @@ static void copy_to_emu(cpuctx_t *d, sigcontext_t *scp) scp_fpregs = scp->fpregs; } -void native_dpmi_leave_to_vm86(void) +void native_dpmi_leave_to_vm86(emu_fpstate *fpstate) { if (scp_fpregs) { void *fpregs = scp_fpregs; #ifdef __x86_64__ - static_assert(sizeof(*scp_fpregs) == sizeof(vm86_fpu_state), + static_assert(sizeof(*scp_fpregs) == sizeof(*fpstate), "size mismatch"); #else if ((scp_fpregs->status >> 16) == EMU_X86_FXSR_MAGIC) @@ -167,7 +172,7 @@ void native_dpmi_leave_to_vm86(void) return; } #endif - memcpy(&vm86_fpu_state, fpregs, sizeof(vm86_fpu_state)); + memcpy(fpstate, fpregs, sizeof(*fpstate)); } } diff --git a/src/dosext/dpmi/dnative/dnative.h b/src/dosext/dpmi/dnative/dnative.h index d4676ef253..626340f982 100644 --- a/src/dosext/dpmi/dnative/dnative.h +++ b/src/dosext/dpmi/dnative/dnative.h @@ -9,8 +9,9 @@ int native_dpmi_control(cpuctx_t *scp); int native_dpmi_exit(cpuctx_t *scp); void native_dpmi_enter(void); void native_dpmi_leave(void); -void native_dpmi_enter_from_vm86(void); -void native_dpmi_leave_to_vm86(void); +void native_dpmi_enter_from_vm86(const emu_fpstate *fpstate); +void native_dpmi_leave_to_vm86(emu_fpstate *fpstate); +void native_dpmi_update_fpu(const emu_fpstate *fpstate); void dpmi_return(sigcontext_t *scp, int retcode); #else @@ -43,11 +44,15 @@ static inline void native_dpmi_leave(void) { } -static inline void native_dpmi_enter_from_vm86(void) +static inline void native_dpmi_enter_from_vm86(const emu_fpstate *fpstate) { } -static inline void native_dpmi_leave_to_vm86(void) +static inline void native_dpmi_leave_to_vm86(emu_fpstate *fpstate) +{ +} + +static inline void native_dpmi_update_fpu(const emu_fpstate *fpstate) { } diff --git a/src/dosext/dpmi/dpmi.c b/src/dosext/dpmi/dpmi.c index ff91970c35..e0ba1b6486 100644 --- a/src/dosext/dpmi/dpmi.c +++ b/src/dosext/dpmi/dpmi.c @@ -418,41 +418,41 @@ static void print_ldt(void) _print_dt(buffer, MAX_SELECTORS, 1); } -static void leave_backend(int be, int pm) +static void leave_backend(int be, int pm, emu_fpstate *fpstate) { switch(be) { case CPUVM_KVM: - kvm_leave(pm); + kvm_leave(pm, fpstate); break; case CPUVM_NATIVE: - native_dpmi_leave_to_vm86(); + native_dpmi_leave_to_vm86(fpstate); break; case CPUVM_EMU: - e_leave(); + e_leave(fpstate); break; #ifdef __i386__ case CPUVM_VM86: - true_vm86_leave(); + true_vm86_leave(fpstate); break; #endif } } -static void enter_backend(int be, int pm) +static void enter_backend(int be, int pm, const emu_fpstate *fpstate) { switch(be) { case CPUVM_KVM: - kvm_enter(pm); + kvm_enter(pm, fpstate); break; case CPUVM_NATIVE: - native_dpmi_enter_from_vm86(); + native_dpmi_enter_from_vm86(fpstate); break; case CPUVM_EMU: - e_enter(); + e_enter(fpstate); break; #ifdef __i386__ case CPUVM_VM86: - true_vm86_enter(); + true_vm86_enter(fpstate); break; #endif } @@ -468,8 +468,9 @@ static void dpmi_set_pm(int pm) } dpmi_pm = pm; if (config.cpu_vm != config.cpu_vm_dpmi) { - leave_backend(pm ? config.cpu_vm : config.cpu_vm_dpmi, !pm); - enter_backend(!pm ? config.cpu_vm : config.cpu_vm_dpmi, pm); + emu_fpstate fpstate; + leave_backend(pm ? config.cpu_vm : config.cpu_vm_dpmi, !pm, &fpstate); + enter_backend(!pm ? config.cpu_vm : config.cpu_vm_dpmi, pm, &fpstate); } } diff --git a/src/include/cpu-emu.h b/src/include/cpu-emu.h index 90723dd79a..79c9d1eecb 100644 --- a/src/include/cpu-emu.h +++ b/src/include/cpu-emu.h @@ -97,8 +97,9 @@ void reset_emu_cpu (void); int e_dpmi(cpuctx_t *scp); void e_dpmi_b0x(int op,cpuctx_t *scp); extern int in_dpmi_emu; -void e_enter(void); -void e_leave(void); +void e_enter(const emu_fpstate *fpstate); +void e_leave(emu_fpstate *fpstate); +void e_update_fpu(const emu_fpstate *fpstate); /* called from emu-ldt.c */ void InvalidateSegs(void); diff --git a/src/include/cpu.h b/src/include/cpu.h index 6daec4ff5d..a450bbd1ab 100644 --- a/src/include/cpu.h +++ b/src/include/cpu.h @@ -232,7 +232,6 @@ static inline dosaddr_t FAR2ADDR(far_t ptr) { #define peek(seg, off) (READ_WORD(SEGOFF2LINEAR(seg, off))) -extern emu_fpstate vm86_fpu_state; extern fenv_t dosemu_fenv; /* diff --git a/src/include/emu.h b/src/include/emu.h index edfe0499c6..abf7077d98 100644 --- a/src/include/emu.h +++ b/src/include/emu.h @@ -104,8 +104,9 @@ extern FILE *real_stderr; void dos_ctrl_alt_del(void); /* disabled */ extern void vm86_helper(void); -extern void true_vm86_enter(void); -extern void true_vm86_leave(void); +extern void true_vm86_enter(const emu_fpstate *fpstate); +extern void true_vm86_leave(emu_fpstate *fpstate); +extern void true_vm86_update_fpu(const emu_fpstate *fpstate); extern void run_vm86(void); extern void loopstep_run_vm86(void); extern int do_call_back(Bit16u cs, Bit16u ip); diff --git a/src/include/kvm.h b/src/include/kvm.h index 802ef12d75..13338dcf37 100644 --- a/src/include/kvm.h +++ b/src/include/kvm.h @@ -33,9 +33,9 @@ void set_kvm_memory_regions(void); void kvm_set_idt_default(int i); void kvm_set_idt(int i, uint16_t sel, uint32_t offs, int is_32, int tg); -void kvm_enter(int pm); -void kvm_leave(int pm); -void kvm_update_fpu(void); +void kvm_enter(int pm, const emu_fpstate *fpstate); +void kvm_leave(int pm, emu_fpstate *fpstate); +void kvm_update_fpu(const emu_fpstate *fpstate); void kvm_done(void); @@ -51,9 +51,9 @@ static inline void set_kvm_memory_regions(void) {} static inline void kvm_set_idt_default(int i) {} static inline void kvm_set_idt(int i, uint16_t sel, uint32_t offs, int is_32, int tg) {} -static inline void kvm_enter(int pm) {} -static inline void kvm_leave(int pm) {} -static inline void kvm_update_fpu(void) {} +static inline void kvm_enter(int pm, const emu_fpstate *fpstate) {} +static inline void kvm_leave(int pm, emu_fpstate *fpstate) {} +static inline void kvm_update_fpu(const emu_fpstate *fpstate) {} static inline void kvm_done(void) {} #endif From 71f8c9e5cb6923e7aa3c07ceeeb98484123b3ebd Mon Sep 17 00:00:00 2001 From: Bart Oldeman Date: Wed, 25 Jan 2023 14:22:11 -0500 Subject: [PATCH 06/13] FPU: convert tag word properly to fsave format. This wasn't needed for kernel consumption but is needed when the actual frstor instruction is used. --- src/base/emu-i386/cpu.c | 57 +++++++++++++++++++++++++++++++++-------- src/include/cpu.h | 8 +++++- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/base/emu-i386/cpu.c b/src/base/emu-i386/cpu.c index 22192668dc..8375004d37 100644 --- a/src/base/emu-i386/cpu.c +++ b/src/base/emu-i386/cpu.c @@ -379,24 +379,59 @@ void cpu_setup(void) #endif } +#define FP_EXP_TAG_VALID 0 +#define FP_EXP_TAG_ZERO 1 +#define FP_EXP_TAG_SPECIAL 2 +#define FP_EXP_TAG_EMPTY 3 + +static inline uint32_t twd_fxsr_to_i387(const struct emu_fpxstate *fxsave) +{ + const struct emu_fpxreg *st; + uint32_t tos = (fxsave->swd >> 11) & 7; + uint32_t twd = (unsigned long) fxsave->ftw; + uint32_t tag; + uint32_t ret = 0xffff0000u; + int i; + + for (i = 0; i < 8; i++, twd >>= 1) { + if (twd & 0x1) { + st = &fxsave->st[(i - tos) & 7]; + + switch (st->exponent & 0x7fff) { + case 0x7fff: + tag = FP_EXP_TAG_SPECIAL; + break; + case 0x0000: + if (!st->significand[0] && + !st->significand[1] && + !st->significand[2] && + !st->significand[3]) + tag = FP_EXP_TAG_ZERO; + else + tag = FP_EXP_TAG_SPECIAL; + break; + default: + if (st->significand[3] & 0x8000) + tag = FP_EXP_TAG_VALID; + else + tag = FP_EXP_TAG_SPECIAL; + break; + } + } else { + tag = FP_EXP_TAG_EMPTY; + } + ret |= tag << (2 * i); + } + return ret; +} void fxsave_to_fsave(const struct emu_fpxstate *fxsave, struct emu_fsave *fptr) { - unsigned int tmp; int i; fptr->cw = fxsave->cwd | 0xffff0000u; fptr->sw = fxsave->swd | 0xffff0000u; - /* Expand the valid bits */ - tmp = fxsave->ftw; /* 00000000VVVVVVVV */ - tmp = (tmp | (tmp << 4)) & 0x0f0f; /* 0000VVVV0000VVVV */ - tmp = (tmp | (tmp << 2)) & 0x3333; /* 00VV00VV00VV00VV */ - tmp = (tmp | (tmp << 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */ - /* Transform each bit from 1 to 00 (valid) or 0 to 11 (empty). - The kernel will convert it back, so no need to worry about zero - and special states 01 and 10. */ - tmp = ~(tmp | (tmp << 1)); - fptr->tag = tmp | 0xffff0000u; + fptr->tag = twd_fxsr_to_i387(fxsave); fptr->ipoff = fxsave->fip; fptr->cssel = (uint16_t)fxsave->fcs | ((uint32_t)fxsave->fop << 16); fptr->dataoff = fxsave->fdp; diff --git a/src/include/cpu.h b/src/include/cpu.h index a450bbd1ab..1c9c0a9a9e 100644 --- a/src/include/cpu.h +++ b/src/include/cpu.h @@ -73,6 +73,12 @@ struct emu_fsave { uint32_t status; }; +struct emu_fpxreg { + uint16_t significand[4]; + uint16_t exponent; + uint16_t reserved[3]; +}; + struct emu_fpxstate { /* 32-bit FXSAVE format in 64bit mode (same as in 32bit mode but more xmms) */ uint16_t cwd; @@ -85,7 +91,7 @@ struct emu_fpxstate { uint32_t fds; uint32_t mxcsr; uint32_t mxcr_mask; - struct { uint32_t element[4]; } st[8]; + struct emu_fpxreg st[8]; struct { uint32_t element[4]; } xmm[16]; struct { uint32_t element[4]; } reserved[3]; struct { uint32_t element[4]; } scratch[3]; From 9f6d52db69cdf1be0caffa0e71c79bab989d416f Mon Sep 17 00:00:00 2001 From: Bart Oldeman Date: Wed, 25 Jan 2023 17:32:45 -0500 Subject: [PATCH 07/13] dpmi: make temporary fpstate static This way it's zero initialized, and fsave_to_fxsave doesn't leave garbage. Fixes crash combining simulator and native DPMI. --- src/dosext/dpmi/dpmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dosext/dpmi/dpmi.c b/src/dosext/dpmi/dpmi.c index e0ba1b6486..3d036399ba 100644 --- a/src/dosext/dpmi/dpmi.c +++ b/src/dosext/dpmi/dpmi.c @@ -468,7 +468,7 @@ static void dpmi_set_pm(int pm) } dpmi_pm = pm; if (config.cpu_vm != config.cpu_vm_dpmi) { - emu_fpstate fpstate; + static emu_fpstate fpstate; leave_backend(pm ? config.cpu_vm : config.cpu_vm_dpmi, !pm, &fpstate); enter_backend(!pm ? config.cpu_vm : config.cpu_vm_dpmi, pm, &fpstate); } From f587481ce424bda3013fdf4f126330124eecd0a8 Mon Sep 17 00:00:00 2001 From: Bart Oldeman Date: Wed, 25 Jan 2023 18:37:27 -0500 Subject: [PATCH 08/13] FPU: use [backend_]{get,set}_fpu_state. Instead of enter/leave, for clarity. --- src/base/emu-i386/cpu.c | 53 +++++++++++++++++++++++------- src/base/emu-i386/do_vm86.c | 9 ++--- src/base/emu-i386/kvm.c | 9 ++--- src/base/emu-i386/simx86/cpu-emu.c | 9 ++--- src/dosext/dpmi/dnative/dnative.c | 9 ++--- src/dosext/dpmi/dnative/dnative.h | 13 +++----- src/dosext/dpmi/dpmi.c | 50 ++++------------------------ src/include/cpu-emu.h | 5 ++- src/include/cpu.h | 3 ++ src/include/emu.h | 5 ++- src/include/kvm.h | 10 +++--- 11 files changed, 70 insertions(+), 105 deletions(-) diff --git a/src/base/emu-i386/cpu.c b/src/base/emu-i386/cpu.c index 8375004d37..795c094be9 100644 --- a/src/base/emu-i386/cpu.c +++ b/src/base/emu-i386/cpu.c @@ -238,29 +238,58 @@ static void fpu_init(void) } #endif -static void fpu_reset(void) +void get_fpu_state(emu_fpstate *fpstate) { - emu_fpstate vm86_fpu_state; - int cpu_vm; - - memset(&vm86_fpu_state, 0, sizeof vm86_fpu_state); - vm86_fpu_state.cwd = 0x0040; //bochs - vm86_fpu_state.ftw = 0xff; //all valid (-> 0x5555 in fsave tag) - cpu_vm = in_dpmi_pm() ? config.cpu_vm_dpmi : config.cpu_vm; + int cpu_vm = in_dpmi_pm() ? config.cpu_vm_dpmi : config.cpu_vm; switch(cpu_vm) { case CPUVM_KVM: - kvm_update_fpu(&vm86_fpu_state); + kvm_get_fpu_state(fpstate); + break; + case CPUVM_NATIVE: + native_dpmi_get_fpu_state(fpstate); + break; case CPUVM_EMU: - e_update_fpu(&vm86_fpu_state); + e_get_fpu_state(fpstate); + break; +#ifdef __i386__ + case CPUVM_VM86: + true_vm86_get_fpu_state(fpstate); + break; +#endif + } +} + +void set_fpu_state(const emu_fpstate *fpstate) +{ + int cpu_vm = in_dpmi_pm() ? config.cpu_vm_dpmi : config.cpu_vm; + switch(cpu_vm) { + case CPUVM_KVM: + kvm_set_fpu_state(fpstate); + break; case CPUVM_NATIVE: - native_dpmi_update_fpu(&vm86_fpu_state); + native_dpmi_set_fpu_state(fpstate); + break; + case CPUVM_EMU: + e_set_fpu_state(fpstate); + break; #ifdef __i386__ case CPUVM_VM86: - true_vm86_update_fpu(&vm86_fpu_state); + true_vm86_set_fpu_state(fpstate); + break; #endif } } +static void fpu_reset(void) +{ + emu_fpstate vm86_fpu_state; + + memset(&vm86_fpu_state, 0, sizeof vm86_fpu_state); + vm86_fpu_state.cwd = 0x0040; //bochs + vm86_fpu_state.ftw = 0xff; //all valid (-> 0x5555 in fsave tag) + set_fpu_state(&vm86_fpu_state); +} + static Bit8u fpu_io_read(ioport_t port) { return 0xff; diff --git a/src/base/emu-i386/do_vm86.c b/src/base/emu-i386/do_vm86.c index 26db1e916d..30d7346e35 100644 --- a/src/base/emu-i386/do_vm86.c +++ b/src/base/emu-i386/do_vm86.c @@ -485,7 +485,7 @@ static int true_vm86(union vm86_union *x) return ret; } -void true_vm86_update_fpu(const emu_fpstate *fpstate) +void true_vm86_set_fpu_state(const emu_fpstate *fpstate) { if (config.cpufxsr) true_vm86_fxsave = *fpstate; @@ -493,12 +493,7 @@ void true_vm86_update_fpu(const emu_fpstate *fpstate) fxsave_to_fsave(fpstate, &true_vm86_fsave); } -void true_vm86_enter(const emu_fpstate *fpstate) -{ - true_vm86_update_fpu(fpstate); -} - -void true_vm86_leave(emu_fpstate *fpstate) +void true_vm86_get_fpu_state(emu_fpstate *fpstate) { if (config.cpufxsr) *fpstate = true_vm86_fxsave; diff --git a/src/base/emu-i386/kvm.c b/src/base/emu-i386/kvm.c index f0d9216500..080c3bf048 100644 --- a/src/base/emu-i386/kvm.c +++ b/src/base/emu-i386/kvm.c @@ -783,7 +783,7 @@ static void set_ldt_seg(struct kvm_segment *seg, unsigned selector) seg->unusable = !desc->present; } -void kvm_update_fpu(const emu_fpstate *fpstate) +void kvm_set_fpu_state(const emu_fpstate *fpstate) { struct kvm_xsave fpu = {}; int ret; @@ -796,12 +796,7 @@ void kvm_update_fpu(const emu_fpstate *fpstate) } } -void kvm_enter(int pm, const emu_fpstate *fpstate) -{ - kvm_update_fpu(fpstate); -} - -void kvm_leave(int pm, emu_fpstate *fpstate) +void kvm_get_fpu_state(emu_fpstate *fpstate) { struct kvm_xsave fpu; int ret = ioctl(vcpufd, KVM_GET_XSAVE, &fpu); diff --git a/src/base/emu-i386/simx86/cpu-emu.c b/src/base/emu-i386/simx86/cpu-emu.c index cdfde521e8..54e2270195 100644 --- a/src/base/emu-i386/simx86/cpu-emu.c +++ b/src/base/emu-i386/simx86/cpu-emu.c @@ -581,7 +581,7 @@ void Cpu2Reg (void) REG(eflags),get_FLAGS(TheCPU.eflags),TheCPU.eflags); } -void e_update_fpu(const emu_fpstate *fpstate) +void e_set_fpu_state(const emu_fpstate *fpstate) { if (CONFIG_CPUSIM) fp87_load_fpstate(fpstate); @@ -593,12 +593,7 @@ void e_update_fpu(const emu_fpstate *fpstate) } } -void e_enter(const emu_fpstate *fpstate) -{ - e_update_fpu(fpstate); -} - -void e_leave(emu_fpstate *fpstate) +void e_get_fpu_state(emu_fpstate *fpstate) { if (CONFIG_CPUSIM) fp87_save_fpstate(fpstate); diff --git a/src/dosext/dpmi/dnative/dnative.c b/src/dosext/dpmi/dnative/dnative.c index dde6679c90..05c5391e0c 100644 --- a/src/dosext/dpmi/dnative/dnative.c +++ b/src/dosext/dpmi/dnative/dnative.c @@ -109,7 +109,7 @@ static void copy_to_dpmi(sigcontext_t *scp, cpuctx_t *s) scp_fpregs = NULL; } -void native_dpmi_update_fpu(const emu_fpstate *fpstate) +void native_dpmi_set_fpu_state(const emu_fpstate *fpstate) { if (scp_fpregs) { void *fpregs = scp_fpregs; @@ -127,11 +127,6 @@ void native_dpmi_update_fpu(const emu_fpstate *fpstate) } } -void native_dpmi_enter_from_vm86(const emu_fpstate *fpstate) -{ - native_dpmi_update_fpu(fpstate); -} - static void copy_to_emu(cpuctx_t *d, sigcontext_t *scp) { #define _D(x) get_##x(d) = _scp_##x @@ -157,7 +152,7 @@ static void copy_to_emu(cpuctx_t *d, sigcontext_t *scp) scp_fpregs = scp->fpregs; } -void native_dpmi_leave_to_vm86(emu_fpstate *fpstate) +void native_dpmi_get_fpu_state(emu_fpstate *fpstate) { if (scp_fpregs) { void *fpregs = scp_fpregs; diff --git a/src/dosext/dpmi/dnative/dnative.h b/src/dosext/dpmi/dnative/dnative.h index 626340f982..26125a8d22 100644 --- a/src/dosext/dpmi/dnative/dnative.h +++ b/src/dosext/dpmi/dnative/dnative.h @@ -9,9 +9,8 @@ int native_dpmi_control(cpuctx_t *scp); int native_dpmi_exit(cpuctx_t *scp); void native_dpmi_enter(void); void native_dpmi_leave(void); -void native_dpmi_enter_from_vm86(const emu_fpstate *fpstate); -void native_dpmi_leave_to_vm86(emu_fpstate *fpstate); -void native_dpmi_update_fpu(const emu_fpstate *fpstate); +void native_dpmi_get_fpu_state(emu_fpstate *fpstate); +void native_dpmi_set_fpu_state(const emu_fpstate *fpstate); void dpmi_return(sigcontext_t *scp, int retcode); #else @@ -44,15 +43,11 @@ static inline void native_dpmi_leave(void) { } -static inline void native_dpmi_enter_from_vm86(const emu_fpstate *fpstate) +static inline void native_dpmi_set_fpu_state(const emu_fpstate *fpstate) { } -static inline void native_dpmi_leave_to_vm86(emu_fpstate *fpstate) -{ -} - -static inline void native_dpmi_update_fpu(const emu_fpstate *fpstate) +static inline void native_dpmi_get_fpu_state(emu_fpstate *fpstate) { } diff --git a/src/dosext/dpmi/dpmi.c b/src/dosext/dpmi/dpmi.c index 3d036399ba..e0acf3673d 100644 --- a/src/dosext/dpmi/dpmi.c +++ b/src/dosext/dpmi/dpmi.c @@ -418,60 +418,22 @@ static void print_ldt(void) _print_dt(buffer, MAX_SELECTORS, 1); } -static void leave_backend(int be, int pm, emu_fpstate *fpstate) -{ - switch(be) { - case CPUVM_KVM: - kvm_leave(pm, fpstate); - break; - case CPUVM_NATIVE: - native_dpmi_leave_to_vm86(fpstate); - break; - case CPUVM_EMU: - e_leave(fpstate); - break; -#ifdef __i386__ - case CPUVM_VM86: - true_vm86_leave(fpstate); - break; -#endif - } -} - -static void enter_backend(int be, int pm, const emu_fpstate *fpstate) -{ - switch(be) { - case CPUVM_KVM: - kvm_enter(pm, fpstate); - break; - case CPUVM_NATIVE: - native_dpmi_enter_from_vm86(fpstate); - break; - case CPUVM_EMU: - e_enter(fpstate); - break; -#ifdef __i386__ - case CPUVM_VM86: - true_vm86_enter(fpstate); - break; -#endif - } -} - static void dpmi_set_pm(int pm) { + static emu_fpstate fpstate; assert(pm <= 1); if (pm == dpmi_pm) { if (!pm) dosemu_error("DPMI: switch from real to real mode?\n"); return; } - dpmi_pm = pm; if (config.cpu_vm != config.cpu_vm_dpmi) { - static emu_fpstate fpstate; - leave_backend(pm ? config.cpu_vm : config.cpu_vm_dpmi, !pm, &fpstate); - enter_backend(!pm ? config.cpu_vm : config.cpu_vm_dpmi, pm, &fpstate); + get_fpu_state(&fpstate); + dpmi_pm = pm; + set_fpu_state(&fpstate); } + else + dpmi_pm = pm; } static dpmi_pm_block *lookup_pm_blocks_by_addr(dosaddr_t addr) diff --git a/src/include/cpu-emu.h b/src/include/cpu-emu.h index 79c9d1eecb..a01e0aded8 100644 --- a/src/include/cpu-emu.h +++ b/src/include/cpu-emu.h @@ -97,9 +97,8 @@ void reset_emu_cpu (void); int e_dpmi(cpuctx_t *scp); void e_dpmi_b0x(int op,cpuctx_t *scp); extern int in_dpmi_emu; -void e_enter(const emu_fpstate *fpstate); -void e_leave(emu_fpstate *fpstate); -void e_update_fpu(const emu_fpstate *fpstate); +void e_get_fpu_state(emu_fpstate *fpstate); +void e_set_fpu_state(const emu_fpstate *fpstate); /* called from emu-ldt.c */ void InvalidateSegs(void); diff --git a/src/include/cpu.h b/src/include/cpu.h index 1c9c0a9a9e..457394fa90 100644 --- a/src/include/cpu.h +++ b/src/include/cpu.h @@ -108,6 +108,9 @@ void fsave_to_fxsave(const struct emu_fsave *fptr, typedef struct emu_fpxstate emu_fpstate; typedef emu_fpstate *emu_fpregset_t; +void get_fpu_state(emu_fpstate *); +void set_fpu_state(const emu_fpstate *); + union g_reg { greg_t reg; #ifdef __x86_64__ diff --git a/src/include/emu.h b/src/include/emu.h index abf7077d98..5461dc61ab 100644 --- a/src/include/emu.h +++ b/src/include/emu.h @@ -104,9 +104,8 @@ extern FILE *real_stderr; void dos_ctrl_alt_del(void); /* disabled */ extern void vm86_helper(void); -extern void true_vm86_enter(const emu_fpstate *fpstate); -extern void true_vm86_leave(emu_fpstate *fpstate); -extern void true_vm86_update_fpu(const emu_fpstate *fpstate); +extern void true_vm86_get_fpu_state(emu_fpstate *fpstate); +extern void true_vm86_set_fpu_state(const emu_fpstate *fpstate); extern void run_vm86(void); extern void loopstep_run_vm86(void); extern int do_call_back(Bit16u cs, Bit16u ip); diff --git a/src/include/kvm.h b/src/include/kvm.h index 13338dcf37..ab9d0f02d7 100644 --- a/src/include/kvm.h +++ b/src/include/kvm.h @@ -33,9 +33,8 @@ void set_kvm_memory_regions(void); void kvm_set_idt_default(int i); void kvm_set_idt(int i, uint16_t sel, uint32_t offs, int is_32, int tg); -void kvm_enter(int pm, const emu_fpstate *fpstate); -void kvm_leave(int pm, emu_fpstate *fpstate); -void kvm_update_fpu(const emu_fpstate *fpstate); +void kvm_get_fpu_state(emu_fpstate *fpstate); +void kvm_set_fpu_state(const emu_fpstate *fpstate); void kvm_done(void); @@ -51,9 +50,8 @@ static inline void set_kvm_memory_regions(void) {} static inline void kvm_set_idt_default(int i) {} static inline void kvm_set_idt(int i, uint16_t sel, uint32_t offs, int is_32, int tg) {} -static inline void kvm_enter(int pm, const emu_fpstate *fpstate) {} -static inline void kvm_leave(int pm, emu_fpstate *fpstate) {} -static inline void kvm_update_fpu(const emu_fpstate *fpstate) {} +static inline void kvm_set_fpu_state(const emu_fpstate *fpstate) {} +static inline void kvm_get_fpu_state(emu_fpstate *fpstate) {} static inline void kvm_done(void) {} #endif From 99071c380cbfa4e2fafd1b6576b97fe3320388d4 Mon Sep 17 00:00:00 2001 From: Bart Oldeman Date: Thu, 26 Jan 2023 19:24:45 -0500 Subject: [PATCH 09/13] FPU: Keep SSE state in backends even if it doesn't change. --- src/base/emu-i386/do_vm86.c | 10 ++++------ src/base/emu-i386/simx86/cpu-emu.c | 7 +++---- src/dosext/dpmi/dnative/dnative.c | 14 +++++++++----- src/dosext/dpmi/dpmi.c | 2 +- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/base/emu-i386/do_vm86.c b/src/base/emu-i386/do_vm86.c index 30d7346e35..9ca935da20 100644 --- a/src/base/emu-i386/do_vm86.c +++ b/src/base/emu-i386/do_vm86.c @@ -487,17 +487,15 @@ static int true_vm86(union vm86_union *x) void true_vm86_set_fpu_state(const emu_fpstate *fpstate) { - if (config.cpufxsr) - true_vm86_fxsave = *fpstate; - else + true_vm86_fxsave = *fpstate; + if (!config.cpufxsr) fxsave_to_fsave(fpstate, &true_vm86_fsave); } void true_vm86_get_fpu_state(emu_fpstate *fpstate) { - if (config.cpufxsr) - *fpstate = true_vm86_fxsave; - else + *fpstate = true_vm86_fxsave; + if (!config.cpufxsr) fsave_to_fxsave(&true_vm86_fsave, fpstate); } #endif diff --git a/src/base/emu-i386/simx86/cpu-emu.c b/src/base/emu-i386/simx86/cpu-emu.c index 54e2270195..4e83746031 100644 --- a/src/base/emu-i386/simx86/cpu-emu.c +++ b/src/base/emu-i386/simx86/cpu-emu.c @@ -583,24 +583,23 @@ void Cpu2Reg (void) void e_set_fpu_state(const emu_fpstate *fpstate) { + TheCPU._fpstate = *fpstate; if (CONFIG_CPUSIM) fp87_load_fpstate(fpstate); else { // unmasked exception settings are emulated TheCPU.fpuc = fpstate->cwd; - TheCPU._fpstate = *fpstate; TheCPU._fpstate.cwd |= 0x3f; } } void e_get_fpu_state(emu_fpstate *fpstate) { + *fpstate = TheCPU._fpstate; if (CONFIG_CPUSIM) fp87_save_fpstate(fpstate); - else { - *fpstate = TheCPU._fpstate; + else fpstate->cwd = (fpstate->cwd & ~0x3f) | (TheCPU.fpuc & 0x3f); - } } /* ======================================================================= */ diff --git a/src/dosext/dpmi/dnative/dnative.c b/src/dosext/dpmi/dnative/dnative.c index 05c5391e0c..45f42defa4 100644 --- a/src/dosext/dpmi/dnative/dnative.c +++ b/src/dosext/dpmi/dnative/dnative.c @@ -76,6 +76,9 @@ static void convert_from_fxsr(fpregset_t fptr, "size mismatch"); fxsave_to_fsave(fxsave, (struct emu_fsave *)fptr); } + +/* since the kernel may not be able to keep SSE state, keep it here */ +static struct emu_fpxstate fxsave_state_holder_i386; #endif static void copy_to_dpmi(sigcontext_t *scp, cpuctx_t *s) @@ -119,9 +122,10 @@ void native_dpmi_set_fpu_state(const emu_fpstate *fpstate) #else /* i386: convert fxsave state to fsave state */ convert_from_fxsr(scp_fpregs, fpstate); - if ((scp_fpregs->status >> 16) != EMU_X86_FXSR_MAGIC) - return; - fpregs = &scp_fpregs->status + 1; + if ((scp_fpregs->status >> 16) == EMU_X86_FXSR_MAGIC) + fpregs = &scp_fpregs->status + 1; + else + fpregs = &fxsave_state_holder_i386; #endif memcpy(fpregs, fpstate, sizeof(*fpstate)); } @@ -163,8 +167,8 @@ void native_dpmi_get_fpu_state(emu_fpstate *fpstate) if ((scp_fpregs->status >> 16) == EMU_X86_FXSR_MAGIC) fpregs = &scp_fpregs->status + 1; else { - fsave_to_fxsave(fpregs, &vm86_fpu_state); - return; + fsave_to_fxsave(fpregs, &fxsave_state_holder_i386); + fpregs = &fxsave_state_holder_i386; } #endif memcpy(fpstate, fpregs, sizeof(*fpstate)); diff --git a/src/dosext/dpmi/dpmi.c b/src/dosext/dpmi/dpmi.c index e0acf3673d..003e70d6d6 100644 --- a/src/dosext/dpmi/dpmi.c +++ b/src/dosext/dpmi/dpmi.c @@ -420,7 +420,7 @@ static void print_ldt(void) static void dpmi_set_pm(int pm) { - static emu_fpstate fpstate; + emu_fpstate fpstate; assert(pm <= 1); if (pm == dpmi_pm) { if (!pm) From 8c33f6db6fa9f0988f5711d1194bfd6d88b9c089 Mon Sep 17 00:00:00 2001 From: Bart Oldeman Date: Thu, 26 Jan 2023 21:31:23 -0500 Subject: [PATCH 10/13] FPU: Reduce size of emu_fpstate to 288 bytes. Only use the 512 byte structure when really needed (for explicit use of fxsave and fxrstor in true_vm86 and JIT); other places just need copies of the relevant state (x87 + first 8 XMM registers only). --- src/base/emu-i386/cpu.c | 6 +++--- src/base/emu-i386/do_vm86.c | 4 ++-- src/base/emu-i386/simx86/cpu-emu.c | 6 +++--- src/base/emu-i386/simx86/syncpu.h | 4 ++-- src/dosext/dpmi/dnative/dnative.c | 8 ++++---- src/include/cpu.h | 29 +++++++++++++++++------------ 6 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/base/emu-i386/cpu.c b/src/base/emu-i386/cpu.c index 795c094be9..8aef72dc98 100644 --- a/src/base/emu-i386/cpu.c +++ b/src/base/emu-i386/cpu.c @@ -413,7 +413,7 @@ void cpu_setup(void) #define FP_EXP_TAG_SPECIAL 2 #define FP_EXP_TAG_EMPTY 3 -static inline uint32_t twd_fxsr_to_i387(const struct emu_fpxstate *fxsave) +static inline uint32_t twd_fxsr_to_i387(const struct emu_fpstate *fxsave) { const struct emu_fpxreg *st; uint32_t tos = (fxsave->swd >> 11) & 7; @@ -454,7 +454,7 @@ static inline uint32_t twd_fxsr_to_i387(const struct emu_fpxstate *fxsave) return ret; } -void fxsave_to_fsave(const struct emu_fpxstate *fxsave, struct emu_fsave *fptr) +void fxsave_to_fsave(const struct emu_fpstate *fxsave, struct emu_fsave *fptr) { int i; @@ -489,7 +489,7 @@ static unsigned short twd_i387_to_fxsr(unsigned short twd) /* NOTE: this function does NOT memset the "unused" fxsave fields. * We preserve the previous fxsave context. */ -void fsave_to_fxsave(const struct emu_fsave *fptr, struct emu_fpxstate *fxsave) +void fsave_to_fxsave(const struct emu_fsave *fptr, struct emu_fpstate *fxsave) { int i; diff --git a/src/base/emu-i386/do_vm86.c b/src/base/emu-i386/do_vm86.c index 9ca935da20..3b1d7356f2 100644 --- a/src/base/emu-i386/do_vm86.c +++ b/src/base/emu-i386/do_vm86.c @@ -487,14 +487,14 @@ static int true_vm86(union vm86_union *x) void true_vm86_set_fpu_state(const emu_fpstate *fpstate) { - true_vm86_fxsave = *fpstate; + true_vm86_fxsave.emu_fpstate = *fpstate; if (!config.cpufxsr) fxsave_to_fsave(fpstate, &true_vm86_fsave); } void true_vm86_get_fpu_state(emu_fpstate *fpstate) { - *fpstate = true_vm86_fxsave; + *fpstate = true_vm86_fxsave.emu_fpstate; if (!config.cpufxsr) fsave_to_fxsave(&true_vm86_fsave, fpstate); } diff --git a/src/base/emu-i386/simx86/cpu-emu.c b/src/base/emu-i386/simx86/cpu-emu.c index 4e83746031..a3edab9c48 100644 --- a/src/base/emu-i386/simx86/cpu-emu.c +++ b/src/base/emu-i386/simx86/cpu-emu.c @@ -583,19 +583,19 @@ void Cpu2Reg (void) void e_set_fpu_state(const emu_fpstate *fpstate) { - TheCPU._fpstate = *fpstate; + TheCPU._fpstate.emu_fpstate = *fpstate; if (CONFIG_CPUSIM) fp87_load_fpstate(fpstate); else { // unmasked exception settings are emulated TheCPU.fpuc = fpstate->cwd; - TheCPU._fpstate.cwd |= 0x3f; + TheCPU._fpstate.emu_fpstate.cwd |= 0x3f; } } void e_get_fpu_state(emu_fpstate *fpstate) { - *fpstate = TheCPU._fpstate; + *fpstate = TheCPU._fpstate.emu_fpstate; if (CONFIG_CPUSIM) fp87_save_fpstate(fpstate); else diff --git a/src/base/emu-i386/simx86/syncpu.h b/src/base/emu-i386/simx86/syncpu.h index 22808ab165..232485512c 100644 --- a/src/base/emu-i386/simx86/syncpu.h +++ b/src/base/emu-i386/simx86/syncpu.h @@ -157,8 +157,8 @@ typedef struct { /* if not NULL, points to emulated FPU state if NULL, emulator uses FPU instructions, so flags that dosemu needs to restore its own FPU environment. */ - emu_fpregset_t fpstate; - emu_fpstate _fpstate __attribute__((aligned(16))); + struct emu_fpxstate *fpstate; + struct emu_fpxstate _fpstate __attribute__((aligned(16))); } SynCPU; union _SynCPU { diff --git a/src/dosext/dpmi/dnative/dnative.c b/src/dosext/dpmi/dnative/dnative.c index 45f42defa4..7d5183b152 100644 --- a/src/dosext/dpmi/dnative/dnative.c +++ b/src/dosext/dpmi/dnative/dnative.c @@ -70,7 +70,7 @@ static void copy_context(sigcontext_t *d, sigcontext_t *s) FSAVE region. see also arch/x86/kernel/fpu/regset.c in Linux kernel */ static void convert_from_fxsr(fpregset_t fptr, - const struct emu_fpxstate *fxsave) + const struct emu_fpstate *fxsave) { static_assert(sizeof(*fptr) == sizeof(struct emu_fsave), "size mismatch"); @@ -78,7 +78,7 @@ static void convert_from_fxsr(fpregset_t fptr, } /* since the kernel may not be able to keep SSE state, keep it here */ -static struct emu_fpxstate fxsave_state_holder_i386; +static struct emu_fpstate fxsave_state_holder_i386; #endif static void copy_to_dpmi(sigcontext_t *scp, cpuctx_t *s) @@ -117,7 +117,7 @@ void native_dpmi_set_fpu_state(const emu_fpstate *fpstate) if (scp_fpregs) { void *fpregs = scp_fpregs; #ifdef __x86_64__ - static_assert(sizeof(*scp_fpregs) == sizeof(*fpstate), + static_assert(offsetof(struct _fpstate, _xmm[8]) == sizeof(*fpstate), "size mismatch"); #else /* i386: convert fxsave state to fsave state */ @@ -161,7 +161,7 @@ void native_dpmi_get_fpu_state(emu_fpstate *fpstate) if (scp_fpregs) { void *fpregs = scp_fpregs; #ifdef __x86_64__ - static_assert(sizeof(*scp_fpregs) == sizeof(*fpstate), + static_assert(offsetof(struct _fpstate, _xmm[8]) == sizeof(*fpstate), "size mismatch"); #else if ((scp_fpregs->status >> 16) == EMU_X86_FXSR_MAGIC) diff --git a/src/include/cpu.h b/src/include/cpu.h index 457394fa90..9b62f929c4 100644 --- a/src/include/cpu.h +++ b/src/include/cpu.h @@ -79,8 +79,8 @@ struct emu_fpxreg { uint16_t reserved[3]; }; -struct emu_fpxstate { - /* 32-bit FXSAVE format in 64bit mode (same as in 32bit mode but more xmms) */ +struct emu_fpstate { + /* first 288 bytes of 32-bit FXSAVE format in 64bit mode */ uint16_t cwd; uint16_t swd; uint16_t ftw; @@ -92,20 +92,25 @@ struct emu_fpxstate { uint32_t mxcsr; uint32_t mxcr_mask; struct emu_fpxreg st[8]; - struct { uint32_t element[4]; } xmm[16]; - struct { uint32_t element[4]; } reserved[3]; - struct { uint32_t element[4]; } scratch[3]; + struct { uint32_t element[4]; } xmm[8]; +}; + +struct emu_fpxstate { + /* 32-bit FXSAVE format in 64bit mode (same as in 32bit mode but more xmms) + This struct is only used with explicit fxsave/fxrstor instructions */ + struct emu_fpstate emu_fpstate; + unsigned char padding[512 - sizeof(struct emu_fpstate)]; }; static_assert(sizeof(struct emu_fpxstate) == 512, "size mismatch"); -void fxsave_to_fsave(const struct emu_fpxstate *fxsave, +void fxsave_to_fsave(const struct emu_fpstate *fxsave, struct emu_fsave *fptr); void fsave_to_fxsave(const struct emu_fsave *fptr, - struct emu_fpxstate *fxsave); + struct emu_fpstate *fxsave); /* Structure to describe FPU registers. */ -typedef struct emu_fpxstate emu_fpstate; +typedef struct emu_fpstate emu_fpstate; typedef emu_fpstate *emu_fpregset_t; void get_fpu_state(emu_fpstate *); @@ -329,18 +334,18 @@ extern fenv_t dosemu_fenv; #define savefxsave(value) #endif -static inline void loadfpstate_legacy(emu_fpstate *buf) +static inline void loadfpstate_legacy(struct emu_fpxstate *buf) { struct emu_fsave fsave; - fxsave_to_fsave(buf, &fsave); + fxsave_to_fsave(&buf->emu_fpstate, &fsave); loadfsave(fsave); } -static inline void savefpstate_legacy(emu_fpstate *buf) +static inline void savefpstate_legacy(struct emu_fpxstate *buf) { struct emu_fsave fsave; savefsave(fsave); - fsave_to_fxsave(&fsave, buf); + fsave_to_fxsave(&fsave, &buf->emu_fpstate); } #if defined(__x86_64__) From f9c32812eb179b05f20a656d8d4131951e61dfe6 Mon Sep 17 00:00:00 2001 From: Bart Oldeman Date: Fri, 27 Jan 2023 14:17:19 -0500 Subject: [PATCH 11/13] DPMI native: cache contents of FPU state instead of pointer. Eliminates static _scp_fpregs pointer to sigcontext. --- src/dosext/dpmi/dnative/dnative.c | 79 ++++++++++++++++--------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/src/dosext/dpmi/dnative/dnative.c b/src/dosext/dpmi/dnative/dnative.c index 7d5183b152..f21a4cefae 100644 --- a/src/dosext/dpmi/dnative/dnative.c +++ b/src/dosext/dpmi/dnative/dnative.c @@ -43,7 +43,10 @@ static struct sigaction emu_tmp_act; #define DPMI_TMP_SIG SIGUSR1 static int in_dpmi_thr; static int dpmi_thr_running; -static fpregset_t scp_fpregs; +static struct emu_fpstate native_dpmi_fpstate; +#ifdef __i386__ +static struct emu_fsave native_dpmi_fsave; +#endif static void copy_context(sigcontext_t *d, sigcontext_t *s) { @@ -69,16 +72,11 @@ static void copy_context(sigcontext_t *d, sigcontext_t *s) format, so we must "undo" the kernel logic and put those fields into the FSAVE region. see also arch/x86/kernel/fpu/regset.c in Linux kernel */ -static void convert_from_fxsr(fpregset_t fptr, +static void convert_from_fxsr(struct emu_fsave *fptr, const struct emu_fpstate *fxsave) { - static_assert(sizeof(*fptr) == sizeof(struct emu_fsave), - "size mismatch"); - fxsave_to_fsave(fxsave, (struct emu_fsave *)fptr); + fxsave_to_fsave(fxsave, fptr); } - -/* since the kernel may not be able to keep SSE state, keep it here */ -static struct emu_fpstate fxsave_state_holder_i386; #endif static void copy_to_dpmi(sigcontext_t *scp, cpuctx_t *s) @@ -109,28 +107,33 @@ static void copy_to_dpmi(sigcontext_t *scp, cpuctx_t *s) _C(trapno); _C(err); _C(cr2); - scp_fpregs = NULL; -} -void native_dpmi_set_fpu_state(const emu_fpstate *fpstate) -{ - if (scp_fpregs) { - void *fpregs = scp_fpregs; + if (scp->fpregs) { + void *fpregs = scp->fpregs; #ifdef __x86_64__ - static_assert(offsetof(struct _fpstate, _xmm[8]) == sizeof(*fpstate), + static_assert(offsetof(struct _fpstate, _xmm[8]) == sizeof(native_dpmi_fpstate), "size mismatch"); #else - /* i386: convert fxsave state to fsave state */ - convert_from_fxsr(scp_fpregs, fpstate); - if ((scp_fpregs->status >> 16) == EMU_X86_FXSR_MAGIC) - fpregs = &scp_fpregs->status + 1; - else - fpregs = &fxsave_state_holder_i386; + static_assert(sizeof(*scp->fpregs) == sizeof(native_dpmi_fsave), + "size mismatch"); + memcpy(fpregs, &native_dpmi_fsave, sizeof(native_dpmi_fsave)); + if ((scp->fpregs->status >> 16) != EMU_X86_FXSR_MAGIC) + return; + fpregs = &scp->fpregs->status + 1; #endif - memcpy(fpregs, fpstate, sizeof(*fpstate)); + memcpy(fpregs, &native_dpmi_fpstate, sizeof(native_dpmi_fpstate)); } } +void native_dpmi_set_fpu_state(const emu_fpstate *fpstate) +{ +#ifdef __i386__ + /* i386: convert fxsave state to fsave state */ + convert_from_fxsr(&native_dpmi_fsave, fpstate); +#endif + native_dpmi_fpstate = *fpstate; +} + static void copy_to_emu(cpuctx_t *d, sigcontext_t *scp) { #define _D(x) get_##x(d) = _scp_##x @@ -153,28 +156,30 @@ static void copy_to_emu(cpuctx_t *d, sigcontext_t *scp) _D(trapno); _D(err); _D(cr2); - scp_fpregs = scp->fpregs; -} - -void native_dpmi_get_fpu_state(emu_fpstate *fpstate) -{ - if (scp_fpregs) { - void *fpregs = scp_fpregs; + if (scp->fpregs) { + void *fpregs = scp->fpregs; #ifdef __x86_64__ - static_assert(offsetof(struct _fpstate, _xmm[8]) == sizeof(*fpstate), + static_assert(offsetof(struct _fpstate, _xmm[8]) == sizeof(native_dpmi_fpstate), "size mismatch"); #else - if ((scp_fpregs->status >> 16) == EMU_X86_FXSR_MAGIC) - fpregs = &scp_fpregs->status + 1; - else { - fsave_to_fxsave(fpregs, &fxsave_state_holder_i386); - fpregs = &fxsave_state_holder_i386; - } + memcpy(&native_dpmi_fsave, fpregs, sizeof(native_dpmi_fsave)); + if ((scp->fpregs->status >> 16) != EMU_X86_FXSR_MAGIC) + return; + fpregs = &scp->fpregs->status + 1; #endif - memcpy(fpstate, fpregs, sizeof(*fpstate)); + memcpy(&native_dpmi_fpstate, fpregs, sizeof(native_dpmi_fpstate)); } } +void native_dpmi_get_fpu_state(emu_fpstate *fpstate) +{ + *fpstate = native_dpmi_fpstate; +#ifdef __i386__ + if ((native_dpmi_fsave.status >> 16) != EMU_X86_FXSR_MAGIC) + fsave_to_fxsave(&native_dpmi_fsave, fpstate); +#endif +} + static void dpmi_thr(void *arg); static int handle_pf(cpuctx_t *scp) From 3e3d2311541c58440cd99726c20fc47d8e83df2a Mon Sep 17 00:00:00 2001 From: Bart Oldeman Date: Fri, 27 Jan 2023 23:05:23 -0500 Subject: [PATCH 12/13] Add fnclex to bios.S int75 (IRQ13, coprocessor exception) handler. This way even without an int2 FP exception handler installed an FP exception won't hang. --- src/base/bios/x86/bios.S | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/base/bios/x86/bios.S b/src/base/bios/x86/bios.S index e95aae67f7..5f7a035a10 100644 --- a/src/base/bios/x86/bios.S +++ b/src/base/bios/x86/bios.S @@ -902,7 +902,12 @@ INT75_OFF: outb %al, $0xa0 outb %al, $0x20 int $2 /* Bochs does this; RBIL says: redirected to INT 02 */ - iret /* by the BIOS, for compatibility with the PC */ + /* by the BIOS, for compatibility with the PC */ + fnclex /* Clear FP exceptions just in case a hooked + handler hasn't already done so, so we won't + get stuck (in real mode IGNNE would prevent + further exceptions but we don't emulate that) */ + iret /* ----------------------------------------------------------------- */ .globl INT08_OFF From 7aa8cf25b7602846fb21eea982777692d34bc1c8 Mon Sep 17 00:00:00 2001 From: Bart Oldeman Date: Mon, 30 Jan 2023 20:41:58 -0500 Subject: [PATCH 13/13] FPU: bios: move int 2 and fnclex before port i/o --- src/base/bios/x86/bios.S | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/base/bios/x86/bios.S b/src/base/bios/x86/bios.S index 5f7a035a10..0353a9a883 100644 --- a/src/base/bios/x86/bios.S +++ b/src/base/bios/x86/bios.S @@ -896,17 +896,17 @@ bios_text_font: _ORG(0xfea6) .globl INT75_OFF INT75_OFF: - xorb %al, %al - outb %al, $0xf0 - movb $0x20, %al - outb %al, $0xa0 - outb %al, $0x20 int $2 /* Bochs does this; RBIL says: redirected to INT 02 */ /* by the BIOS, for compatibility with the PC */ fnclex /* Clear FP exceptions just in case a hooked handler hasn't already done so, so we won't get stuck (in real mode IGNNE would prevent further exceptions but we don't emulate that) */ + xorb %al, %al + outb %al, $0xf0 + movb $0x20, %al + outb %al, $0xa0 + outb %al, $0x20 iret /* ----------------------------------------------------------------- */