2001-07-05 17:21:16

by mdaljeet

[permalink] [raw]
Subject: floating point problem

In Linux PPC, the MSR[FP] bit (that is floating point available bit) is off
(atleast for non-SMP).

Due to this, whenever some floating point instruction is executed in 'user
mode', it leads to a exception 'FPUnavailable'. The exception handler for
this exception apart from setting the MSR[FP] bit, also sets the MSR[FE0]
and MSR[FE1] bits. These bits basically enables the floating point
exceptions so that if there are some floating point exception conditions
encountered while exeuting a floating point instruction, an appropriate
exception is raised.
But whenever some floating point instruction is executed in 'kernel mode',
'FPUnavailabe' exception handler code does not set the 'MSR[FE0] and
MSR[FE1]' bits.

The result is that when we execute a piece of code that executes floating
point instructions with some large values, we get 'floating point
exceptions for overflow etc' but we get some rounded off values when we
execute the same piece of code in a kernel module. We made a modification
in the head.S file and commented out the setting of 'MSR[FE0] and MSR[FE1]'
bits in the 'FPUnavailable' exception handler for user mode. Due to this we
are getting correct results i.e. rounded off values.

Problem is that we want to get the good results without changing the
kernel. Either by having the user mode application to interact with some
special module which can set the MSR[FP] bit before we execute the floating
point instruction or by some other trick.....Is there any solution apart
from changing the kernel?

thanks,
Daljeet.



2001-07-05 17:42:19

by Richard B. Johnson

[permalink] [raw]
Subject: Re: floating point problem

On Thu, 5 Jul 2001 [email protected] wrote:

> In Linux PPC, the MSR[FP] bit (that is floating point available bit) is off
> (atleast for non-SMP).
>

Yes, so the first FP instruction per process lets "lazy FPU" save/restore
work.


> Due to this, whenever some floating point instruction is executed in 'user
> mode', it leads to a exception 'FPUnavailable'. The exception handler for
> this exception apart from setting the MSR[FP] bit, also sets the MSR[FE0]
> and MSR[FE1] bits. These bits basically enables the floating point
> exceptions so that if there are some floating point exception conditions
> encountered while exeuting a floating point instruction, an appropriate
> exception is raised.
> But whenever some floating point instruction is executed in 'kernel mode',
> 'FPUnavailabe' exception handler code does not set the 'MSR[FE0] and
> MSR[FE1]' bits.
>

The kernel is not supposed to use floating-point.

[SNIPPED...]

I think all you need is this:

/*
* Note FPU control only exists per process. Therefore, you have
* to set up the FPU before you use it in any program.
*/
#include <i386/fpu_control.h>

#define FPU_MASK (_FPU_MASK_IM |\
_FPU_MASK_DM |\
_FPU_MASK_ZM |\
_FPU_MASK_OM |\
_FPU_MASK_UM |\
_FPU_MASK_PM)

void fpu()
{
__setfpucw(_FPU_DEFAULT & ~FPU_MASK);
}


main() {
double zero=0.0;
double one=1.0;
fpu();

one /=zero;
}



Cheers,
Dick Johnson

Penguin : Linux version 2.4.1 on an i686 machine (799.53 BogoMips).

I was going to compile a list of innovations that could be
attributed to Microsoft. Once I realized that Ctrl-Alt-Del
was handled in the BIOS, I found that there aren't any.


2001-07-06 05:54:17

by Paul Mackerras

[permalink] [raw]
Subject: Re: floating point problem

[email protected] writes:

> In Linux PPC, the MSR[FP] bit (that is floating point available bit) is off
> (atleast for non-SMP).
>
> Due to this, whenever some floating point instruction is executed in 'user
> mode', it leads to a exception 'FPUnavailable'. The exception handler for

Yes, this is so that we don't have to save and restore the floating
point registers on every context switch.

> this exception apart from setting the MSR[FP] bit, also sets the MSR[FE0]
> and MSR[FE1] bits. These bits basically enables the floating point
> exceptions so that if there are some floating point exception conditions
> encountered while exeuting a floating point instruction, an appropriate
> exception is raised.

You have control at user-level over whether the cpu will take an
exception (leading to a SIGFPE signal) or not by means of the FPSCR
register. The VE, OE, UE, ZE and XE bits in the FPSCR control whether
the cpu will take an exception on floating-point invalid operation,
overflow, underflow, divide by zero and inexact result respectively.

If the kernel cleared the FE0 and FE1 bits, there would be no way for
an application to get a signal when a floating-point error occurred.
With FE0 and FE1 set, the application can control this using the
FPSCR, and get a signal, or not, as it prefers.

> But whenever some floating point instruction is executed in 'kernel mode',
> 'FPUnavailabe' exception handler code does not set the 'MSR[FE0] and
> MSR[FE1]' bits.

Floating point is not intended to be used in the kernel except in a
couple of specific places.

> Problem is that we want to get the good results without changing the
> kernel. Either by having the user mode application to interact with some
> special module which can set the MSR[FP] bit before we execute the floating
> point instruction or by some other trick.....Is there any solution apart
> from changing the kernel?

Clear the appropriate bits in the FPSCR. There is almost certainly a
glibc interface to do this but I don't know what it would be.

Paul.