Bochs/bochs/patches/patch.smp-fpu
Bryce Denney c337f3715f - This patch creates one copy of the FPU registers and state for every CPU
in a multiprocessor simulation.  Imagine that!  Without the patch, there is
  just one FPU for all the processors, which is clearly wrong.
  See bug [ 461762 ] multiple processors but only one FPU
2002-06-23 00:35:19 +00:00

145 lines
5.6 KiB
Plaintext

----------------------------------------------------------------------
Patch name: patch.smp-fpu
Author: Bryce Denney <bryce@thedenneys.org>
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;