Bodo Stroesser wrote:
Carl wrote:

Hi,

Running the piece of code from the URL below is generating errors on
various UML kernels:

http://downloads.rimuhosting.com/memtest.c

Kernels tested are: 2.4.27, 2.4.27-bs1, 2.6.9-bb4.

Sorry for forgetting to attach the testtool.
Here it is.

Bodo

Different UML host servers have been tried too, and only UMLs running on
SMP (dual Xeon) servers seem to have the problem (P4s with HT are fine).

Can anyone else reproduce the errors? Any ideas?

Thanks, Carl


After having found a bug in SKAS-signal-handling, I modified memtest.c to
trigger that bug (attached: memtest2.c). This probably is the same problem,
Carl saw. If so, Carl's problem shouldn't happen in TT-mode.


That's the problem:

In SKAS userspace(), when the kernel is entered, all regs including fpregs
are saved by save_registers() to skas_regs and restored on exit by
restore_registers() from skas_regs.
If an signal handler has to be started, the original fpstate is saved in the
sigcontext and must be restored, when sys_sigreturn is called.
When the kernel is entered for sys_sigreturn on return from the signal handler,
the fpregs again are saved with save_registers(). Thus skas_regs hold the
fpstate from the end of the signal handler.
Now copy_sc_from_user_skas() tries to restore the original state. But the
fpstate from the sigcontext isn't written to skas_regs, but directly to the
fp-registers of the userspace process with set_fpregs().
When exit from kernel is done after that, restore_registers() overwrites
the fp-registers of the userspace-process with the fpstate from skas_regs,
which is the wrong one that comes from the signal handler!


There is another problem in UML-signal-handling, that makes the problem very
hard to reproduce:
Normally, on sighandler-entry, the fpu-registers should be cleared. But UML
doesn't clear the fpu. So, the original values in the fpu-registers stay
alive, if the signal-handler doesn't push to many new values. In most
cases, even if the sighandler uses the fpu, only the compare-result-flags
have changed after return from sighandler. If fp-values have to be compared,
AFAICS an fp-compare-instruction is used, followed immediately by a move
of the compare-result-flags to the ax-register. So, only a sighandler
hitting exactly between those two instructions, will hurt in most cases!



Solution:

I started to do a patch, but stopped, since it will need a big patch to
make this area clean (and I will be offline for about 2 weeks ...):

1) In SKAS, copy_sc_from_user_skas() should build the _fpstate in
   sigcontext from skas_regs, not from new values read in by get_fpregs().
   The current code even lacks writing i387_fsave_struct.status containing
   the magic which flags the _fpstate format.
   The "format" of the written _fpstate should depend on
   have_fpx_regs. This means, convert_fxsr_to_user_tt() should be
   modified and made generally available to help cover the case of
   (have_fpx_regs == 1), where skas_regs don't contain fsave, but
   fxsave only.
2) When having created a sigcontext, UML should clear the fpregs in
   skas_regs resp. tt_regs.sc->_fpstate, to make the sighandler see
   a cleared fpu.
3) copy_sc_from_user_skas() should copy the _fpstate from sigcontext
   to skas_regs. To handle the different formats of the _fpstate,
   convert_fxsr_from_user_tt() should be modified and made available.
   copy_sc_from_user_skas() should check sigcontext->_fpstate. If
   this is NULL, skas_regs.fp/fpx should be cleared. (SKAS doesn't
   write that NULL, but on the host or in TT, the kernel sometimes
   writes it. So, I would like to have SKAS tolerate a NULL here
   instead of segfaulting).
4) set_fpregs, get_fpregs, set_fpxregs, get_fpxregs currently support
   TT-mode only. set_fpxregs and get_fpxregs should return -EIO, if
   (!have_fpx_regs). Therefore, the check for availability of
   PTRACE_GET_FPXREGS should be done in SKAS and TT, and have_fpx_regs
   should be available in both modes.
5) get_fpregs in TT mode simply should copy the first (fp-reg) part of
   tt_regs.sc->fpstatus to user without converting. This part of fpstate
   always is written correctly by the host kernel. Also set_fpregs has to
   copy that part from user. If (have_fpx_regs == 1) the fpx-parts of
   fpstatus should be reconstructed from that, to have them available for
   the next possible get_fpxregs.
6) get_fpxregs and set_fpxregs in TT for (have_fpx_regs == 1) may work
   immediately with the fpx-part of tt_regs.sc->fpstatus, but set_fpxregs
   also has to write the fp-part accordingly.
7) get_fpregs, set_fpregs, get_fpxregs and set_fpxregs should support SKAS.
   This could be done by simply ripping code or method from i386.
   SKAS holds the data needed in skas_regs.fp or skas_regs.fpx

I hope, this helps a bit. Sorry for not having the time to do the patch
by myself.

Bodo


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now. http://productguide.itmanagersjournal.com/
_______________________________________________
User-mode-linux-devel mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/user-mode-linux-devel

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>

#define N (20*1024)

void sighdlr(int sig)
{
    double a;

    a = 256;

    double observed = a;
    double expected = 257;

    if ( observed == expected )
        printf("Error in sighdlr()\n");
}

int
main (void)
{
    size_t i, k;
    struct itimerval itimer = { { 0, 10000}, { 0, 10000} };

    signal(SIGALRM, sighdlr);
    setitimer( ITIMER_REAL, &itimer, NULL);

    for (k = 1; k < 1000; k++) {
        double *a = malloc (N * sizeof (double));
        if (a == 0) {
            printf ("malloc failed at k=%u\n", k);
            exit (1);
        }

        for (i = 0; i < N; i++) {
            a[i] = (double) i;
            double observed = a[i];
            double expected = (double) i;
            if (observed != expected) {
                printf ("failed at i=%u, k=%u (obs %.18g vs exp %.18g)\n", i, k,
                        observed, expected);
            }
        }

        for (i = 0; i < N; i++) {
            double observed = a[i];
            double expected = (double) i;
            if (observed != expected) {
                printf ("failed at i=%u, k=%u (obs %.18g vs exp %.18g)\n", i, k,
                        observed, expected);
//              exit (1);
            }
        }
        free (a);
    }
    exit (0);
}

Reply via email to