Modularized x86 math emulation PATCH against pre-2.1.104-1

Adam J. Richter (adam@yggdrasil.com)
Sun, 24 May 1998 02:48:11 -0700


Here is an untested patch that modularizes x86 math emulation.
It includes kmod support, so that the kernel can be made to automatically
load the math_emu module when a program starts executing floating point
instructions, and "kmod -a" will unload the module if no floating point
code has been run for a while.

There are two significant advantages to the modularization
of x86 math emulation:

1. Users of 386's are likely also to have limited RAM
resources. Under this arrangement, the ~100kB
used by math emulation is only occupied when a
floating point program has recently run. At other
times, the memory is free for other purposes.

2. This make it much easier to have a single standard
fully modularized kernel binary, because the math
emulation no longer occupies memory on machines
that have hardware floating point, and yet there
is no need to run a different kernel. Also,
boot floppies using this kernel can hold more loadable
modules, which was my primary motivation in making
this improvement. (Now I can get all of the scsi
drivers, all of the cdrom drives and all of the pcmcia
scsi drivers and cardmgr on one floppy again.)

Anyhow, please try this path and let me know if it
works or not.

Adam J. Richter __ ______________ 4880 Stevens Creek Blvd, Suite 205
adam@yggdrasil.com \ / San Jose, California 95129-1034
+1 408 261-6630 | g g d r a s i l United States of America
fax +1 408 261-6631 "Free Software For The Rest Of Us."
--------------------------CUT HERE----------------------------------

--- /tmp/linux-pre-2.1.104-1/./arch/i386/Makefile Fri May 8 00:09:20 1998
+++ linux/./arch/i386/Makefile Sun May 24 01:37:31 1998
@@ -55,6 +55,9 @@

ifdef CONFIG_MATH_EMULATION
SUBDIRS := $(SUBDIRS) arch/i386/math-emu
+endif
+
+ifeq ($(CONFIG_MATH_EMULATION), y)
DRIVERS := $(DRIVERS) arch/i386/math-emu/math.a
endif

@@ -86,7 +89,7 @@
bzdisk: vmlinux
@$(MAKEBOOT) BOOTIMAGE=bzImage zdisk

-install: vmlinux
+install: vmlinux modules_install
@$(MAKEBOOT) BOOTIMAGE=bzImage install

archclean:
--- /tmp/linux-pre-2.1.104-1/./arch/i386/config.in Tue Apr 28 22:41:33 1998
+++ linux/./arch/i386/config.in Sat May 23 23:41:26 1998
@@ -15,8 +15,8 @@
"386 CONFIG_M386 \
486/Cx486 CONFIG_M486 \
Pentium/K5/5x86/6x86 CONFIG_M586 \
- PPro/K6/6x86MX CONFIG_M686" Pentium
-bool 'Math emulation' CONFIG_MATH_EMULATION
+ PPro/K6/6x86MX CONFIG_M686" 386
+tristate 'Math emulation' CONFIG_MATH_EMULATION
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
fi
--- /tmp/linux-pre-2.1.104-1/./arch/i386/kernel/traps.c Tue May 19 10:00:07 1998
+++ linux/./arch/i386/kernel/traps.c Sun May 24 00:28:44 1998
@@ -32,6 +32,10 @@
asmlinkage void lcall7(void);
struct desc_struct default_ldt = { 0, 0 };

+#ifdef CONFIG_MATH_EMULATION_MODULE
+void (*math_emulate_hook)(long arg) = NULL;
+#endif
+
static inline void console_verbose(void)
{
extern int console_loglevel;
@@ -400,6 +404,16 @@

asmlinkage void math_emulate(long arg)
{
+#ifdef CONFIG_MATH_EMULATON_MODULE
+ if (math_emulate_hook == NULL) {
+ request_module("math_emu");
+ }
+ if (math_emulate_hook != NULL) {
+ /* Module has been loaded. Try again. */
+ (*math_emulate_hook)(arg);
+ return;
+ }
+#endif /* CONFIG_MATH_EMULATION_MODULE */
lock_kernel();
printk("math-emulation not enabled and no coprocessor found.\n");
printk("killing %s.\n",current->comm);
--- /tmp/linux-pre-2.1.104-1/./arch/i386/kernel/ptrace.c Wed May 6 10:56:01 1998
+++ linux/./arch/i386/kernel/ptrace.c Sun May 24 00:14:13 1998
@@ -621,7 +621,7 @@
child->tss.i387.hard.swd = 0xffff0000;
child->tss.i387.hard.twd = 0xffffffff;
}
-#ifdef CONFIG_MATH_EMULATION
+#if defined(CONFIG_MATH_EMULATION) || defined(CONFIG_MATH_EMULATION_MODULE)
if ( boot_cpu_data.hard_math ) {
#endif
if (last_task_used_math == child) {
@@ -632,7 +632,7 @@
}
__copy_to_user((void *)data, &child->tss.i387.hard,
sizeof(struct user_i387_struct));
-#ifdef CONFIG_MATH_EMULATION
+#if defined(CONFIG_MATH_EMULATION) || defined(CONFIG_MATH_EMULATION_MODULE)
} else {
save_i387_soft(&child->tss.i387.soft,
(struct _fpstate *)data);
@@ -649,7 +649,7 @@
goto out;
}
child->used_math = 1;
-#ifdef CONFIG_MATH_EMULATION
+#if defined(CONFIG_MATH_EMULATION) || defined(CONFIG_MATH_EMULATION_MODULE)
if ( boot_cpu_data.hard_math ) {
#endif
if (last_task_used_math == child) {
@@ -659,7 +659,7 @@
__copy_from_user(&child->tss.i387.hard, (void *)data,
sizeof(struct user_i387_struct));
child->flags &= ~PF_USEDFPU;
-#ifdef CONFIG_MATH_EMULATION
+#if defined(CONFIG_MATH_EMULATION) || defined(CONFIG_MATH_EMULATION_MODULE)
} else {
restore_i387_soft(&child->tss.i387.soft,
(struct _fpstate *)data);
--- /tmp/linux-pre-2.1.104-1/./arch/i386/kernel/signal.c Sun Mar 29 11:31:16 1998
+++ linux/./arch/i386/kernel/signal.c Sun May 24 00:28:18 1998
@@ -30,6 +30,13 @@
int options, unsigned long *ru);
asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);

+#ifdef CONFIG_MATH_EMULATION_MODULE
+void (*restore_i387_soft)(void *s387, struct _fpstate *buf) =
+ restore_i387_soft_absent;
+struct _fpstate * (*save_i387_soft)(void *s387, struct _fpstate * buf) =
+ save_i387_soft_absent;
+#endif /* CONFIG_MATH_EMULATION_MODULE
+
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
@@ -162,7 +169,7 @@

static inline void restore_i387(struct _fpstate *buf)
{
-#ifndef CONFIG_MATH_EMULATION
+#if !defined(CONFIG_MATH_EMULATION) && !defined(CONFIG_MATH_EMULATION_MODULE)
restore_i387_hard(buf);
#else
if (boot_cpu_data.hard_math)
@@ -173,6 +180,28 @@
current->used_math = 1;
}

+#ifdef CONFIG_MATH_EMULATION_MODULE
+void restore_i387_soft_absent(void *s387, struct _fpstate *buf) {
+ request_module("math_emu");
+ if (math_emulate_hook != NULL) {
+ /* Module has been loaded. Try again. */
+ return (*restore_i387_soft)(s387,buf);
+ }
+ return restore_i387_hard(buf);
+}
+
+struct _fpstate * save_i387_soft_absent(void *s387, struct _fpstate * buf) {
+
+ if (math_emulate_hook == NULL) {
+ request_module("math_emu");
+ }
+ if (math_emulate_hook != NULL) {
+ /* Module has been loaded. Try again. */
+ (*save_i387_soft)(s387,buf);
+ }
+}
+#endif /* CONFIG_MATH_MODULE */
+
static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
{
@@ -322,7 +351,7 @@
*/
current->used_math = 0;

-#ifndef CONFIG_MATH_EMULATION
+#if !defined(CONFIG_MATH_EMULATION) && !defined(CONFIG_MATH_EMULATION_MODULE)
return save_i387_hard(buf);
#else
return boot_cpu_data.hard_math ? save_i387_hard(buf)
--- /tmp/linux-pre-2.1.104-1/arch/i386/math-emu/Makefile Tue Dec 9 17:57:09 1997
+++ linux/arch/i386/math-emu/Makefile Sun May 24 01:55:59 1998
@@ -2,8 +2,6 @@
# Makefile for wm-FPU-emu
#

-L_TARGET := math.a
-
#DEBUG = -DDEBUGGING
DEBUG =
PARANOID = -DPARANOID
@@ -27,9 +25,19 @@
div_Xsig.o polynom_Xsig.o round_Xsig.o \
shr_Xsig.o mul_Xsig.o

-L_OBJS =$(C_OBJS) $(A_OBJS)
+ifeq ($(CONFIG_MATH_EMULATION), m)
+ MI_OBJS := $(C_OBJS) $(A_OBJS)
+ M_OBJS := math_emu.o
+else
+ L_OBJS =$(C_OBJS) $(A_OBJS)
+ L_TARGET := math.a
+endif

include $(TOPDIR)/Rules.make

proto:
cproto -e -DMAKING_PROTO *.c >fpu_proto.h
+
+# Special rule to build the composite math-emu.o module
+math_emu.o: $(MI_OBJS) $(MIX_OBJS)
+ $(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS)
--- /tmp/linux-pre-2.1.104-1/arch/i386/math-emu/fpu_entry.c Sun Jan 25 11:01:48 1998
+++ linux/arch/i386/math-emu/fpu_entry.c Sun May 24 01:38:02 1998
@@ -25,6 +25,7 @@
+---------------------------------------------------------------------------*/

#include <linux/signal.h>
+#include <linux/module.h>

#include <asm/uaccess.h>

@@ -129,7 +130,33 @@
static int valid_prefix(u_char *Byte, u_char **fpu_eip,
overrides *override);

+#ifdef MODULE
+static void math_emulate_local(long arg);
+static void restore_i387_soft_local(void *s387, struct _fpstate *buf);
+static struct _fpstate * save_i387_soft_local(void *s387, struct _fpstate * buf);
+
+int
+init_module(void) {
+ math_emulate_hook = math_emulate_local;
+ restore_i387_soft = restore_i387_soft_local;
+ save_i387_soft = save_i387_soft_local;
+ return 0;
+}
+
+void
+cleanup_module(void) {
+ math_emulate_hook = NULL;
+ restore_i387_soft = restore_i387_soft_absent;
+ save_i387_soft = save_i387_soft_absent;
+}
+
+#endif /* MODULE */
+
+#ifdef MODULE
+static void math_emulate_local(long arg)
+#else
asmlinkage void math_emulate(long arg)
+#endif
{
u_char FPU_modrm, byte1;
unsigned short code;
@@ -145,6 +172,7 @@
unsigned long code_limit = 0; /* Initialized to stop compiler warnings */
struct desc_struct code_descriptor;

+ MOD_INC_USE_COUNT;
#ifdef RE_ENTRANT_CHECKING
if ( emulating )
{
@@ -570,6 +598,7 @@
FPU_EIP -= code_base;

RE_ENTRANT_CHECK_OFF;
+ MOD_DEC_USE_COUNT;
}


@@ -677,11 +706,17 @@
#define sstatus_word() \
((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))

+#ifdef MODULE
+static void restore_i387_soft_local(void *s387, struct _fpstate *buf)
+#else
void restore_i387_soft(void *s387, struct _fpstate *buf)
+#endif
{
u_char *d = (u_char *)buf;
int offset, other, i, tags, regnr, tag, newtop;

+ MOD_INC_USE_COUNT;
+
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, d, 7*4 + 8*10);
__copy_from_user(&S387->cwd, d, 7*4);
@@ -715,15 +750,21 @@
}
}
S387->twd = tags;
-
+ MOD_DEC_USE_COUNT;
}


+#ifdef MODULE
+static struct _fpstate * save_i387_soft_local(void *s387, struct _fpstate * buf)
+#else
struct _fpstate * save_i387_soft(void *s387, struct _fpstate * buf)
+#endif
{
u_char *d = (u_char *)buf;
int offset = (S387->ftop & 7) * 10, other = 80 - offset;

+ MOD_INC_USE_COUNT;
+
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE, d, 7*4 + 8*10);
#ifdef PECULIAR_486
@@ -746,6 +787,8 @@
if ( offset )
__copy_to_user(d+other, (u_char *)&S387->st_space, offset);
RE_ENTRANT_CHECK_ON;
+
+ MOD_DEC_USE_COUNT;

return buf;
}
--- /tmp/linux-pre-2.1.104-1/arch/i386/math-emu/reg_round.S Tue Dec 9 17:57:09 1997
+++ linux/arch/i386/math-emu/reg_round.S Sun May 24 02:17:30 1998
@@ -10,7 +10,7 @@
| |
| This code has four possible entry points. |
| The following must be entered by a jmp instruction: |
- | fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit. |
+ | fpu_reg_round and fpu_Arith_exit. |
| |
| The FPU_round entry point is intended to be used by C code. |
| From C, call as: |
@@ -27,14 +27,14 @@
/*---------------------------------------------------------------------------+
| Four entry points. |
| |
- | Needed by both the fpu_reg_round and fpu_reg_round_sqrt entry points: |
+ | Needed by the fpu_reg_round entry point: |
| %eax:%ebx 64 bit significand |
| %edx 32 bit extension of the significand |
| %edi pointer to an FPU_REG for the result to be stored |
| stack calling function must have set up a C stack frame and |
| pushed %esi, %edi, and %ebx |
| |
- | Needed just for the fpu_reg_round_sqrt entry point: |
+ | Previously needed just for the (deleted) fpu_reg_round_sqrt entry point: |
| %cx A control word in the same format as the FPU control word. |
| Otherwise, PARAM4 must give such a value. |
| |
@@ -105,7 +105,6 @@

.text
.globl fpu_reg_round
-.globl fpu_reg_round_sqrt
.globl fpu_Arith_exit

/* Entry point when called from C */

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu