---------------------------------------------------------------------- Patch name: patch.smp-fpu Author: Bryce Denney Date: Sat Jun 22 20:12:43 EDT 2002 Detailed description: This patch is an attempt to address the bug [ 461762 ] multiple processors but only one FPU http://sourceforge.net/tracker/?group_id=12580&atid=112580&func=detail&aid=461762 WARNING: This is highly experimental, and has no been adequately tested. WARNING: I'm assuming that ALL data specific to a single FPU is stored in the i387_t structure. I hope this assumption is valid. It's pretty clear that in an SMP simulation each CPU needs to have its own i387_t structure, so I have done that. Each CPU has a field called the_i387 which is a pointer to a i387_t structure. The pointer is declared as void* because when cpu.h is compiled it doesn't know the details of the i387_t structure. Only code in fpu/* knows about the complete i387_t structure, so it just uses a typecast to cast the "the_i387" field into a pointer to the right struct. Part of what's tricky about the FPU code is that it's all written in C, so it cannot read bochs.h or know anything about the Bochs types. The C/C++ interface is in fpu/fpu.cc and fpu/wmFPUemu_glue.cc (mostly the latter). All the C code was written with the assumption of having a global variable called i387 available, but now when Bochs is simulating multiple processors, there is a separate copy of the FPU registers in every CPU. I wanted to leave all the C code alone, so I defined the i387 expression to mean (*current_i387) which is a pointer to the i387 registers in the CPU that's being simulated. When any FPU instruction is simulated, the current_i387 pointer is set according to i387 structure associated with the CPU that's executing the instrution. Then all the C code operates on the correct i387 structure without having to know that there are others around. Only the glue code is aware of the other i387 structures. The danger of this approach is that there may be other global variables within the fpu code that I'm not aware of that represent miscellaneous FPU state. Someone who has the time and cares about correct FPU emulation under SMP should look around for such variables. Probably the easiest way to deal with them is to add them to the i387 struct. Patch was created with: cvs diff -u Apply patch to what version: cvs checked out on DATE, release version VER Instructions: To patch, go to main bochs directory. Type "patch -p0 < THIS_PATCH_FILE". ---------------------------------------------------------------------- Index: cpu/cpu.h =================================================================== RCS file: /cvsroot/bochs/bochs/cpu/cpu.h,v retrieving revision 1.22 diff -u -r1.22 cpu.h --- cpu/cpu.h 5 Jun 2002 21:51:30 -0000 1.22 +++ cpu/cpu.h 23 Jun 2002 00:31:47 -0000 @@ -1270,6 +1270,15 @@ BX_SMF void ESC6(BxInstruction_t *); BX_SMF void ESC7(BxInstruction_t *); +#if BX_SUPPORT_FPU + // This is a pointer to an actual i387_t structure defined in + // fpu/fpu_system.h. A void* is used because at present the fpu headers are + // not included when compiling the cpu or any other part of Bochs for that + // matter. The pointer is initialized to a newly allocated i387_t struct in + // BX_CPU_C::fpu_init() in fpu/wmFPUemu_glue.cc. It is only referenced + // within the fpu/* code. + void *the_i387; +#endif BX_SMF void fpu_execute(BxInstruction_t *i); BX_SMF void fpu_init(void); BX_SMF void fpu_print_regs (void); Index: fpu/fpu_system.h =================================================================== RCS file: /cvsroot/bochs/bochs/fpu/fpu_system.h,v retrieving revision 1.3 diff -u -r1.3 fpu_system.h --- fpu/fpu_system.h 6 Oct 2001 03:53:46 -0000 1.3 +++ fpu/fpu_system.h 23 Jun 2002 00:31:47 -0000 @@ -167,8 +167,15 @@ } GCC_ATTRIBUTE((aligned(16), packed)) soft; } i387_t; -extern i387_t i387; +// The global variable current_i387 points to the i387_t structure of +// the current CPU. In a multiprocessor simulation, whenever a processor +// executes an FPU instruction, the current_i387 pointer is changed to +// point to the FPU registers for that processor. +extern i387_t *current_i387; +// By defining i387 like this, all the code that expected to find a global +// variable called i387 still works. +#define i387 (*current_i387) #endif Index: fpu/wmFPUemu_glue.cc =================================================================== RCS file: /cvsroot/bochs/bochs/fpu/wmFPUemu_glue.cc,v retrieving revision 1.9 diff -u -r1.9 wmFPUemu_glue.cc --- fpu/wmFPUemu_glue.cc 15 Sep 2001 06:55:14 -0000 1.9 +++ fpu/wmFPUemu_glue.cc 23 Jun 2002 00:31:47 -0000 @@ -44,8 +44,7 @@ // will ultimately call routines here. static BxInstruction_t *fpu_iptr = NULL; static BX_CPU_C *fpu_cpu_ptr = NULL; - -i387_t i387; +i387_t *current_i387 = NULL; extern "C" void math_emulate2(fpu_addr_modes addr_modes, @@ -62,6 +61,9 @@ void BX_CPU_C::fpu_init(void) { + BX_INFO (("initialized fpu")); + BX_CPU_THIS_PTR the_i387 = new i387_t; + current_i387 = (i387_t *)BX_CPU_THIS_PTR the_i387; finit(); } @@ -76,6 +78,15 @@ fpu_iptr = i; fpu_cpu_ptr = this; +#if BX_SMP_PROCESSORS==1 + // For one processor, there's only one i387_t structure in existence, and the + // current_i387 pointer already points to it. Don't bother. +#else + // Set the current_i387 pointer according to the processor that is being + // simulated. All the FPU emulation code will use current_i387 to access + // the FPU state, using the "i387" macro in fpu_system.h. + current_i387 = (i387_t *)BX_CPU_THIS_PTR the_i387; +#endif #if 0 addr_modes.default_mode = VM86;