瀏覽代碼

Reshaped SIGNAL_CONTEXT in preparation for ucontext.

The SIGNAL_CONTEXT structure now contains a signal mask, all general
registers, and potentially the floating point registers. This is in line
with the requirements of the ucontext structure. Saving all the registers
may also make it easier for ptrace to manipulate registers in the target
once the user mode debugger stuff is reworked.

The trouble is getting the non-volatile registers during a system call.
The check for signals is going to have to be done in the system call
assembly, once all non-volatile registers have been restored by C code.
I'll work on this once the other signal code is in.
Evan Green 7 年之前
父節點
當前提交
0860d2a88e

+ 0 - 13
apps/libc/dynamic/signals.c

@@ -1808,7 +1808,6 @@ Return Value:
 {
 
     struct sigaction *Action;
-    BOOL ChangedMask;
     int Flags;
     siginfo_t HandlerInformation;
     struct sigaction OriginalAction;
@@ -1816,7 +1815,6 @@ Return Value:
     ULONG Signal;
     SIGNAL_SET SignalMask;
 
-    ChangedMask = FALSE;
     Signal = SignalInformation->SignalNumber;
     Action = &(ClSignalHandlers[Signal]);
     Flags = Action->sa_flags;
@@ -1828,7 +1826,6 @@ Return Value:
     if ((IS_SIGNAL_SET_EMPTY(Action->sa_mask) == FALSE) ||
         ((Flags & (SA_NODEFER | SA_RESETHAND)) == 0)) {
 
-        ChangedMask = TRUE;
         SignalMask = Action->sa_mask;
         if ((Flags & (SA_NODEFER | SA_RESETHAND)) == 0) {
             ADD_SIGNAL(SignalMask, Signal);
@@ -1893,16 +1890,6 @@ Return Value:
         }
     }
 
-    //
-    // Restore the signal mask if it was changed.
-    //
-
-    if (ChangedMask != FALSE) {
-        OsSetSignalBehavior(SignalMaskBlocked,
-                            SignalMaskOperationOverwrite,
-                            &SignalMask);
-    }
-
     //
     // Report whether or not the restart flag was set so that the system can
     // restart a function if required.

+ 1 - 1
apps/osbase/armv7/osbasea.S

@@ -110,7 +110,7 @@ END_FUNCTION OsSystemCall
 ##
 ## VOID
 ## OspSignalHandler (
-##     PSIGNAL_PARAMETERS Parameters
+##     PSIGNAL_PARAMETERS Parameters,
 ##     PSIGNAL_CONTEXT Context
 ##     )
 ##

+ 2 - 2
apps/osbase/osbasep.h

@@ -199,8 +199,8 @@ Return Value:
 
 VOID
 OspSignalHandler (
-    UINTN SignalNumber,
-    UINTN SignalParameter
+    PSIGNAL_PARAMETERS Parameters,
+    PSIGNAL_CONTEXT Context
     );
 
 /*++

+ 9 - 11
apps/testapps/sigtest/sigtest.c

@@ -30,6 +30,7 @@ Environment:
 #include <errno.h>
 #include <fcntl.h>
 #include <getopt.h>
+#include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/wait.h>
@@ -160,7 +161,7 @@ TestSigchldRealtime1SignalHandler (
     void *Context
     );
 
-VOID
+PVOID
 TestThreadSpinForever (
     PVOID Parameter
     );
@@ -889,6 +890,7 @@ Return Value:
     int SignalNumber;
     union sigval SignalValue;
     int Status;
+    pthread_t Thread;
     ULONG ThreadIndex;
     struct timespec Timeout;
     pid_t WaitPid;
@@ -960,16 +962,12 @@ Return Value:
                  ThreadIndex += 1) {
 
                 ChildInitializing = 1;
-                Status = OsCreateThread(NULL,
-                                        0,
-                                        TestThreadSpinForever,
-                                        (PVOID)&ChildInitializing,
-                                        NULL,
-                                        0,
+                Status = pthread_create(&Thread,
                                         NULL,
-                                        NULL);
+                                        TestThreadSpinForever,
+                                        (PVOID)&ChildInitializing);
 
-                if (!KSUCCESS(Status)) {
+                if (Status != 0) {
                     PRINT_ERROR("Child %d failed to create thread: %d.\n",
                                 getpid(),
                                 Status);
@@ -1487,7 +1485,7 @@ Return Value:
     return;
 }
 
-VOID
+PVOID
 TestThreadSpinForever (
     PVOID Parameter
     )
@@ -1516,7 +1514,7 @@ Return Value:
         sleep(1);
     }
 
-    return;
+    return NULL;
 }
 
 ULONG

+ 0 - 28
include/minoca/kernel/arch.h

@@ -27,12 +27,6 @@ Author:
 
 #define ARCH_POOL_TAG 0x68637241 // 'hcrA'
 
-//
-// Define the signal context flags.
-//
-
-#define SIGNAL_CONTEXT_FLAG_RESTART 0x00000001
-
 //
 // ------------------------------------------------------ Data Type Definitions
 //
@@ -41,28 +35,6 @@ typedef struct _TRAP_FRAME TRAP_FRAME, *PTRAP_FRAME;
 typedef struct _PROCESSOR_CONTEXT PROCESSOR_CONTEXT, *PPROCESSOR_CONTEXT;
 typedef struct _FPU_CONTEXT FPU_CONTEXT, *PFPU_CONTEXT;
 
-/*++
-
-Structure Description:
-
-    This structure outlines the state saved by the kernel when a user mode
-    signal is dispatched. This is usually embedded within an architecture
-    specific version of the signal context.
-
-Members:
-
-    Signal - Stores the signal number that fired.
-
-    Flags - Stores a bitmask of signal context flags. See SIGNAL_CONTEXT_FLAG_*
-        for definitions.
-
---*/
-
-typedef struct _SIGNAL_CONTEXT {
-    ULONG Signal;
-    ULONG Flags;
-} PACKED SIGNAL_CONTEXT, *PSIGNAL_CONTEXT;
-
 //
 // -------------------------------------------------------------------- Globals
 //

+ 10 - 12
include/minoca/kernel/arm.h

@@ -96,7 +96,7 @@ Author:
 // the if-then state is active in any form..
 //
 
-#define PSR_IS_IT_ACTIVE(_Cpsr) (((_Cpsr) & 0x06000C00) != 0)
+#define PSR_IS_IT_ACTIVE(_Cpsr) (((_Cpsr) & PSR_FLAG_IT_STATE) != 0)
 
 //
 // This macro determines if the given if-then state is active.
@@ -188,8 +188,11 @@ Author:
 #define PSR_FLAG_SATURATION 0x08000000
 #define PSR_FLAG_JAZELLE    0x01000000
 #define PSR_FLAG_THUMB      0x00000020
-#define PSR_FLAG_IRQ        0x00000080
 #define PSR_FLAG_FIQ        0x00000040
+#define PSR_FLAG_IRQ        0x00000080
+#define PSR_FLAG_ALIGNMENT  0x00000100
+
+#define PSR_FLAG_IT_STATE   0x06000C00
 
 //
 // Interrupt vector ranges.
@@ -706,21 +709,16 @@ Members:
 
     Common - Stores the common signal context information.
 
-    Registers - Stores the previous state of the thread's registers.
+    TrapFrame - Stores the general register state.
+
+    FpuContext - Stores the FPU state.
 
 --*/
 
 typedef struct _SIGNAL_CONTEXT_ARM {
     SIGNAL_CONTEXT Common;
-    ULONG R0;
-    ULONG R1;
-    ULONG R2;
-    ULONG R3;
-    ULONG R12;
-    ULONG Sp;
-    ULONG Lr;
-    ULONG Pc;
-    ULONG Cpsr;
+    TRAP_FRAME TrapFrame;
+    FPU_CONTEXT FpuContext;
 } PACKED SIGNAL_CONTEXT_ARM, *PSIGNAL_CONTEXT_ARM;
 
 /*++

+ 68 - 0
include/minoca/kernel/ksignals.h

@@ -302,6 +302,23 @@ Author:
 
 #define SIGNAL_BAD_SYSTEM_CALL 29
 
+//
+// Define the signal context flags.
+//
+
+//
+// This flag is set if the system call the signal interrupted should be
+// restarted.
+//
+
+#define SIGNAL_CONTEXT_FLAG_RESTART 0x00000001
+
+//
+// This flag is set if the FPU context in the signal context is valid.
+//
+
+#define SIGNAL_CONTEXT_FLAG_FPU_VALID 0x00000002
+
 //
 // Define the child process signal reason codes.
 //
@@ -481,6 +498,57 @@ typedef struct _SIGNAL_PARAMETERS {
     UINTN Parameter;
 } SIGNAL_PARAMETERS, *PSIGNAL_PARAMETERS;
 
+/*++
+
+Structure Description:
+
+    This structure defines signal stack information.
+
+Members:
+
+    Base - Stores the base of the stack.
+
+    Flags - Stores a bitfield of flags about the stack. See SIGNAL_STACK_*
+        definitions.
+
+    Size - Stores the size of the stack in bytes.
+
+--*/
+
+typedef struct _SIGNAL_STACK {
+    PVOID Base;
+    ULONG Flags;
+    UINTN Size;
+} SIGNAL_STACK, *PSIGNAL_STACK;
+
+/*++
+
+Structure Description:
+
+    This structure outlines the state saved by the kernel when a user mode
+    signal is dispatched. This is usually embedded within an architecture
+    specific version of the signal context.
+
+Members:
+
+    Flags - Stores a bitmask of signal context flags. See SIGNAL_CONTEXT_FLAG_*
+        for definitions.
+
+    Next - Stores a pointer to the next signal context.
+
+    Stack - Stores the alternate signal stack information.
+
+    Mask - Stores the original signal mask when this signal was applied.
+
+--*/
+
+typedef struct _SIGNAL_CONTEXT {
+    ULONG Flags;
+    PVOID Next;
+    SIGNAL_STACK Stack;
+    SIGNAL_SET Mask;
+} PACKED SIGNAL_CONTEXT, *PSIGNAL_CONTEXT;
+
 //
 // -------------------------------------------------------------------- Globals
 //

+ 0 - 4
include/minoca/kernel/ps.h

@@ -1589,9 +1589,6 @@ Members:
     BlockedSignals - Stores a bitfield of signals that are blocked by the
         thread.
 
-    RunningSignals - Stores a bitfield of signals that are currently in progress
-        on the thread.
-
     SignalListHead - Stores the head of the list of signals that are currently
         queued for the process. The type of elements on this list will be
         SIGNAL_QUEUE_ENTRY structures. This list is protected by the process
@@ -1663,7 +1660,6 @@ struct _KTHREAD {
     PWAIT_BLOCK WaitBlock;
     SIGNAL_SET PendingSignals;
     SIGNAL_SET BlockedSignals;
-    SIGNAL_SET RunningSignals;
     LIST_ENTRY SignalListHead;
     RESOURCE_USAGE ResourceUsage;
     PFPU_CONTEXT FpuContext;

+ 13 - 7
include/minoca/kernel/x86.h

@@ -104,6 +104,14 @@ Author:
 #define IA32_EFLAG_ID 0x00200000
 #define IA32_EFLAG_ALWAYS_0 0xFFC08028
 #define IA32_EFLAG_ALWAYS_1 0x00000002
+
+#define IA32_EFLAG_STATUS \
+    (IA32_EFLAG_CF | IA32_EFLAG_PF | IA32_EFLAG_AF | IA32_EFLAG_ZF | \
+     IA32_EFLAG_SF | IA32_EFLAG_OF)
+
+#define IA32_EFLAG_USER \
+    (IA32_EFLAG_STATUS | IA32_EFLAG_DF | IA32_EFLAG_TF | IA32_EFLAG_RF)
+
 #define CR0_PAGING_ENABLE 0x80000000
 #define CR0_WRITE_PROTECT_ENABLE 0x00010000
 #define CR0_TASK_SWITCHED 0x00000008
@@ -637,18 +645,16 @@ Members:
 
     Common - Stores the common signal context information.
 
-    Registers - Stores the previous state of the thread's registers.
+    TrapFrame - Stores the general register state.
+
+    FpuContext - Stores the FPU state.
 
 --*/
 
 typedef struct _SIGNAL_CONTEXT_X86 {
     SIGNAL_CONTEXT Common;
-    ULONG Eax;
-    ULONG Ecx;
-    ULONG Edx;
-    ULONG Eflags;
-    ULONG Eip;
-    ULONG Esp;
+    TRAP_FRAME TrapFrame;
+    FPU_CONTEXT FpuContext;
 } PACKED SIGNAL_CONTEXT_X86, *PSIGNAL_CONTEXT_X86;
 
 /*++

+ 112 - 67
kernel/ps/armv7/psarch.c

@@ -163,34 +163,50 @@ Return Value:
 
 {
 
-    SIGNAL_CONTEXT_ARM Context;
+    PSIGNAL_CONTEXT_ARM Context;
+    ULONG ContextSp;
+    ULONG Flags;
+    BOOL Result;
     KSTATUS Status;
-    KSTATUS Status2;
     PKTHREAD Thread;
 
-    ASSERT(!IS_TRAP_FRAME_FROM_PRIVILEGED_MODE(TrapFrame));
-
     Thread = KeGetCurrentThread();
+    ContextSp = ALIGN_RANGE_DOWN(TrapFrame->UserSp - sizeof(SIGNAL_CONTEXT_ARM),
+                                 STACK_ALIGNMENT);
+
+    Context = (PVOID)ContextSp;
+    Flags = 0;
+    Result = MmUserWrite(&(Context->Common.Next), 0);
+    Status = MmCopyToUserMode(&(Context->Common.Mask),
+                              &(Thread->BlockedSignals),
+                              sizeof(SIGNAL_SET));
 
     //
-    // The trap frame may be incomplete if the thread is currently in a system
-    // call. Volatile registers don't matter in this case.
+    // TODO: Support alternate signal stacks.
     //
 
-    RtlZeroMemory(&Context, sizeof(SIGNAL_CONTEXT_ARM));
-    Context.Common.Signal = SignalParameters->SignalNumber;
-    Context.Pc = TrapFrame->Pc;
-    Context.Sp = TrapFrame->UserSp;
-    Context.Lr = TrapFrame->UserLink;
-    Context.Cpsr = TrapFrame->Cpsr;
-    if (ArIsTrapFrameComplete(TrapFrame) != FALSE) {
-        Context.R0 = TrapFrame->R0;
-        Context.R1 = TrapFrame->R1;
-        Context.R2 = TrapFrame->R2;
-        Context.R3 = TrapFrame->R3;
-        Context.R12 = TrapFrame->R12;
+    Result &= MmUserWrite(&(Context->Common.Stack.Base), 0);
+    Result &= MmUserWrite(&(Context->Common.Stack.Size), 0);
+    Result &= MmUserWrite32(&(Context->Common.Stack.Flags), 0);
+    Status |= MmCopyToUserMode(&(Context->TrapFrame),
+                               TrapFrame,
+                               sizeof(TRAP_FRAME));
+
+    TrapFrame->UserSp = ContextSp;
+    if ((Thread->FpuFlags & THREAD_FPU_FLAG_IN_USE) != 0) {
+        Flags |= SIGNAL_CONTEXT_FLAG_FPU_VALID;
+        if ((Thread->FpuFlags & THREAD_FPU_FLAG_OWNER) != 0) {
+            ArSaveFpuState(Thread->FpuContext);
+        }
+
+        Status |= MmCopyToUserMode(&(Context->FpuContext),
+                                   Thread->FpuContext,
+                                   sizeof(FPU_CONTEXT));
     }
 
+    Result &= MmUserWrite32(&(Context->TrapFrame.SvcSp), 0);
+    Result &= MmUserWrite32(&(Context->TrapFrame.SvcLink), 0);
+
     //
     // If this signal is being applied in the middle of a system call, preserve
     // the system call's return value.
@@ -210,46 +226,29 @@ Return Value:
         //
 
         if (IS_SYSTEM_CALL_RESTARTABLE(SystemCallNumber, SystemCallResult)) {
-            Context.R0 = STATUS_INTERRUPTED;
-            Context.R1 = SystemCallNumber;
-            Context.R2 = (ULONG)SystemCallParameter;
-            Context.Common.Flags |= SIGNAL_CONTEXT_FLAG_RESTART;
+            Result &= MmUserWrite(&(Context->TrapFrame.R0), STATUS_INTERRUPTED);
+            Result &= MmUserWrite(&(Context->TrapFrame.R1), SystemCallNumber);
+            Result &= MmUserWrite(&(Context->TrapFrame.R2),
+                                  (UINTN)SystemCallParameter);
+
+            Flags |= SIGNAL_CONTEXT_FLAG_RESTART;
 
         //
         // Otherwise just preserve the system call result.
         //
 
         } else {
-            Context.R0 = SystemCallResult;
+            Result &= MmUserWrite(&(Context->TrapFrame.R0), SystemCallResult);
         }
     }
 
-    //
-    // Mark the signal as running so that more don't come down on the thread
-    // while it's servicing this one.
-    //
-
-    ASSERT(!IS_SIGNAL_SET(Thread->RunningSignals, Context.Common.Signal));
-
-    ADD_SIGNAL(Thread->RunningSignals, Context.Common.Signal);
-
-    //
-    // Copy the signal frame onto the stack.
-    // TODO: Support an alternate signal stack.
-    //
-
-    TrapFrame->UserSp = ALIGN_RANGE_DOWN(TrapFrame->UserSp, STACK_ALIGNMENT);
-    TrapFrame->UserSp -= sizeof(SIGNAL_CONTEXT_ARM);
-    Status = MmCopyToUserMode((PVOID)(TrapFrame->UserSp),
-                              &Context,
-                              sizeof(SIGNAL_CONTEXT_ARM));
-
+    Result &= MmUserWrite32(&(Context->Common.Flags), Flags);
     TrapFrame->UserSp -= sizeof(SIGNAL_PARAMETERS);
-    Status2 = MmCopyToUserMode((PVOID)(TrapFrame->UserSp),
+    Status |= MmCopyToUserMode((PVOID)(TrapFrame->UserSp),
                                SignalParameters,
                                sizeof(SIGNAL_PARAMETERS));
 
-    if ((!KSUCCESS(Status)) || (!KSUCCESS(Status2))) {
+    if ((Status != STATUS_SUCCESS) || (Result == FALSE)) {
         PsHandleUserModeFault((PVOID)(TrapFrame->UserSp),
                               FAULT_FLAG_WRITE | FAULT_FLAG_PAGE_NOT_PRESENT,
                               TrapFrame,
@@ -259,8 +258,6 @@ Return Value:
                                                 SystemCallResult,
                                                 SystemCallParameter,
                                                 SystemCallNumber);
-
-        return;
     }
 
     TrapFrame->Pc = (ULONG)(Thread->OwningProcess->SignalHandlerRoutine);
@@ -269,6 +266,7 @@ Return Value:
         TrapFrame->Cpsr |= PSR_FLAG_THUMB;
     }
 
+    ADD_SIGNAL(Thread->BlockedSignals, SignalParameters->SignalNumber);
     return;
 }
 
@@ -299,34 +297,74 @@ Return Value:
 
 {
 
-    SIGNAL_CONTEXT_ARM Context;
+    PSIGNAL_CONTEXT_ARM Context;
+    ULONG Flags;
+    TRAP_FRAME Frame;
     INTN Result;
+    SIGNAL_SET SignalMask;
     KSTATUS Status;
     PKTHREAD Thread;
 
+    Context = (PSIGNAL_CONTEXT_ARM)UserContext;
+    Result = 0;
     Thread = KeGetCurrentThread();
-    Status = MmCopyFromUserMode(&Context,
-                                (PSIGNAL_CONTEXT_ARM)UserContext,
-                                sizeof(SIGNAL_CONTEXT_ARM));
+    Status = MmCopyFromUserMode(&Frame,
+                                &(Context->TrapFrame),
+                                sizeof(TRAP_FRAME));
+
+    Status |= MmCopyFromUserMode(&SignalMask,
+                                 &(Context->Common.Mask),
+                                 sizeof(SIGNAL_SET));
+
+    if (!MmUserRead32(&(UserContext->Flags), &Flags)) {
+        Status = STATUS_ACCESS_VIOLATION;
+    }
 
     if (!KSUCCESS(Status)) {
-        PsSignalThread(Thread, SIGNAL_ACCESS_VIOLATION, NULL, TRUE);
-        return 0;
+        goto RestorePreSignalTrapFrameEnd;
     }
 
-    ASSERT((Context.Cpsr & ARM_MODE_MASK) == ARM_MODE_USER);
+    PsSetSignalMask(&SignalMask, NULL);
+    Frame.Cpsr &= ~(ARM_MODE_MASK | PSR_FLAG_IRQ | PSR_FLAG_FIQ |
+                    PSR_FLAG_ALIGNMENT);
 
-    REMOVE_SIGNAL(Thread->RunningSignals, Context.Common.Signal);
-    TrapFrame->R0 = Context.R0;
-    TrapFrame->R1 = Context.R1;
-    TrapFrame->R2 = Context.R2;
-    TrapFrame->R3 = Context.R3;
-    TrapFrame->R12 = Context.R12;
-    TrapFrame->UserSp = Context.Sp;
-    TrapFrame->UserLink = Context.Lr;
-    TrapFrame->Pc = Context.Pc;
-    TrapFrame->Cpsr = Context.Cpsr;
-    Result = TrapFrame->R0;
+    Frame.Cpsr |= ARM_MODE_USER;
+    Frame.SvcSp = 0;
+    Frame.SvcLink = 0;
+    Frame.ExceptionCpsr = 0;
+    Result = Frame.R0;
+
+    //
+    // TODO: Restore the whole trap frame with just a copy when the system call
+    // handler can save a complete trap frame.
+    //
+
+    TrapFrame->R0 = Frame.R0;
+    TrapFrame->R1 = Frame.R1;
+    TrapFrame->R2 = Frame.R2;
+    TrapFrame->R3 = Frame.R3;
+    TrapFrame->R12 = Frame.R12;
+    TrapFrame->Cpsr = Frame.Cpsr;
+    TrapFrame->Pc = Frame.Pc;
+    TrapFrame->UserLink = Frame.UserLink;
+    TrapFrame->UserSp = Frame.UserSp;
+    if (((Flags & SIGNAL_CONTEXT_FLAG_FPU_VALID) != 0) &&
+        (Thread->FpuContext != NULL)) {
+
+        Status = MmCopyFromUserMode(Thread->FpuContext,
+                                    &(Context->FpuContext),
+                                    sizeof(FPU_CONTEXT));
+
+        if (!KSUCCESS(Status)) {
+            goto RestorePreSignalTrapFrameEnd;
+        }
+
+        Thread->FpuFlags |= THREAD_FPU_FLAG_IN_USE;
+        if ((Thread->FpuFlags & THREAD_FPU_FLAG_OWNER) != 0) {
+            ArDisableFpu();
+            Thread->FpuFlags &= ~THREAD_FPU_FLAG_OWNER;
+        }
+    }
 
     //
     // If the signal context indicates that a restart is necessary, then fire
@@ -335,8 +373,15 @@ Return Value:
     // cause the next restore to return to the signal handler.
     //
 
-    if ((Context.Common.Flags & SIGNAL_CONTEXT_FLAG_RESTART) != 0) {
-        Result = KeSystemCallHandler(Context.R1, (PVOID)Context.R2, TrapFrame);
+    if ((Flags & SIGNAL_CONTEXT_FLAG_RESTART) != 0) {
+        Result = KeSystemCallHandler(TrapFrame->R1,
+                                     (PVOID)(TrapFrame->R2),
+                                     TrapFrame);
+    }
+
+RestorePreSignalTrapFrameEnd:
+    if (!KSUCCESS(Status)) {
+        PsSignalThread(Thread, SIGNAL_ACCESS_VIOLATION, NULL, TRUE);
     }
 
     return Result;

+ 1 - 2
kernel/ps/psp.h

@@ -31,8 +31,7 @@ Author:
 //
 
 #define IS_SIGNAL_BLOCKED(_Thread, _Signal) \
-    (IS_SIGNAL_SET((_Thread)->BlockedSignals, (_Signal)) || \
-     IS_SIGNAL_SET((_Thread)->RunningSignals, (_Signal)))
+    (IS_SIGNAL_SET((_Thread)->BlockedSignals, (_Signal)))
 
 //
 // This macro evaluates to non-zero if the given signal queue entry is a child

+ 9 - 14
kernel/ps/signals.c

@@ -1683,7 +1683,6 @@ Return Value:
         ProcessSignalMask = Process->PendingSignals;
         OR_SIGNAL_SETS(CombinedSignalMask, ThreadSignalMask, ProcessSignalMask);
         REMOVE_SIGNALS_FROM_SET(CombinedSignalMask, Thread->BlockedSignals);
-        REMOVE_SIGNALS_FROM_SET(CombinedSignalMask, Thread->RunningSignals);
         if ((IS_SIGNAL_SET(CombinedSignalMask, SIGNAL_STOP)) ||
             (IS_SIGNAL_SET(CombinedSignalMask, SIGNAL_KILL))) {
 
@@ -3503,24 +3502,20 @@ Return Value:
 
         ASSERT(Thread != NULL);
 
-        REMOVE_SIGNAL(Thread->BlockedSignals, SignalNumber);
-        SignalBlocked = FALSE;
-        SignalIgnored = FALSE;
-
         //
-        // If the thread is already running one of these signals and it gets
-        // another one, just kill it.
+        // If the signal is blocked, that's the indication that it's already
+        // running. Set it back to its default disposition, which will kill
+        // the process when delivered.
         //
 
-        if (IS_SIGNAL_SET(Thread->RunningSignals, SignalNumber)) {
-            PspSetProcessExitStatusUnlocked(Process,
-                                            CHILD_SIGNAL_REASON_KILLED,
-                                            SignalNumber);
-
-            PspQueueSignalToProcess(Process, SIGNAL_KILL, NULL);
-            return;
+        if (IS_SIGNAL_SET(Thread->BlockedSignals, SignalNumber)) {
+            REMOVE_SIGNAL(Thread->BlockedSignals, SignalNumber);
+            REMOVE_SIGNAL(Process->HandledSignals, SignalNumber);
         }
 
+        SignalBlocked = FALSE;
+        SignalIgnored = FALSE;
+
     } else {
         SignalIgnored = IS_SIGNAL_SET(Process->IgnoredSignals, SignalNumber);
         SignalBlocked = FALSE;

+ 0 - 1
kernel/ps/thread.c

@@ -1122,7 +1122,6 @@ Return Value:
     //
 
     NewThread->BlockedSignals = Thread->BlockedSignals;
-    NewThread->RunningSignals = Thread->RunningSignals;
     NewThread->UserStack = Thread->UserStack;
     NewThread->UserStackSize = Thread->UserStackSize;
     PspPrepareThreadForFirstRun(NewThread, TrapFrame, FALSE);

+ 108 - 59
kernel/ps/x86/psarch.c

@@ -178,31 +178,45 @@ Return Value:
 
 {
 
-    SIGNAL_CONTEXT_X86 Context;
+    PSIGNAL_CONTEXT_X86 Context;
+    UINTN ContextSp;
+    ULONG Flags;
+    BOOL Result;
     KSTATUS Status;
-    KSTATUS Status2;
     PKTHREAD Thread;
 
     Thread = KeGetCurrentThread();
+    ContextSp = ALIGN_RANGE_DOWN(TrapFrame->Esp - sizeof(SIGNAL_CONTEXT_X86),
+                                 STACK_ALIGNMENT);
+
+    Context = (PVOID)ContextSp;
+    Flags = 0;
+    Result = MmUserWrite(&(Context->Common.Next), 0);
+    Status = MmCopyToUserMode(&(Context->Common.Mask),
+                              &(Thread->BlockedSignals),
+                              sizeof(SIGNAL_SET));
 
     //
-    // The trap frame may be incomplete if the thread is currently in a system
-    // call. Volatile registers don't matter in this case.
+    // TODO: Support alternate signal stacks.
     //
 
-    RtlZeroMemory(&Context, sizeof(SIGNAL_CONTEXT_X86));
-    Context.Common.Signal = SignalParameters->SignalNumber;
-    Context.Eip = TrapFrame->Eip;
-    Context.Esp = TrapFrame->Esp;
-    Context.Eflags = IA32_EFLAG_ALWAYS_1 | IA32_EFLAG_IF;
-    if (ArIsTrapFrameComplete(TrapFrame) != FALSE) {
+    Result &= MmUserWrite(&(Context->Common.Stack.Base), 0);
+    Result &= MmUserWrite(&(Context->Common.Stack.Size), 0);
+    Result &= MmUserWrite32(&(Context->Common.Stack.Flags), 0);
+    Status |= MmCopyToUserMode(&(Context->TrapFrame),
+                               TrapFrame,
+                               sizeof(TRAP_FRAME));
 
-        ASSERT(IS_TRAP_FRAME_FROM_PRIVILEGED_MODE(TrapFrame) == FALSE);
+    TrapFrame->Esp = ContextSp;
+    if ((Thread->FpuFlags & THREAD_FPU_FLAG_IN_USE) != 0) {
+        Flags |= SIGNAL_CONTEXT_FLAG_FPU_VALID;
+        if ((Thread->FpuFlags & THREAD_FPU_FLAG_OWNER) != 0) {
+            ArSaveFpuState(Thread->FpuContext);
+        }
 
-        Context.Eax = TrapFrame->Eax;
-        Context.Ecx = TrapFrame->Ecx;
-        Context.Edx = TrapFrame->Edx;
-        Context.Eflags = TrapFrame->Eflags;
+        Status |= MmCopyToUserMode(&(Context->FpuContext),
+                                   Thread->FpuContext,
+                                   sizeof(FPU_CONTEXT));
     }
 
     //
@@ -224,45 +238,31 @@ Return Value:
         //
 
         if (IS_SYSTEM_CALL_RESTARTABLE(SystemCallNumber, SystemCallResult)) {
-            Context.Eax = STATUS_INTERRUPTED;
-            Context.Ecx = SystemCallNumber;
-            Context.Edx = (ULONG)SystemCallParameter;
-            Context.Common.Flags |= SIGNAL_CONTEXT_FLAG_RESTART;
+            Result &= MmUserWrite(&(Context->TrapFrame.Eax),
+                                  STATUS_INTERRUPTED);
+
+            Result &= MmUserWrite(&(Context->TrapFrame.Ecx), SystemCallNumber);
+            Result &= MmUserWrite(&(Context->TrapFrame.Edx),
+                                  (UINTN)SystemCallParameter);
+
+            Flags |= SIGNAL_CONTEXT_FLAG_RESTART;
 
         //
         // Otherwise just preserve the system call result.
         //
 
         } else {
-            Context.Eax = SystemCallResult;
+            MmUserWrite(&(Context->TrapFrame.Eax), SystemCallResult);
         }
     }
 
-    //
-    // Mark the signal as running so that more don't come down on the thread
-    // while it's servicing this one.
-    //
-
-    ASSERT(!IS_SIGNAL_SET(Thread->RunningSignals, Context.Common.Signal));
-
-    ADD_SIGNAL(Thread->RunningSignals, Context.Common.Signal);
-
-    //
-    // Copy the signal frame onto the stack.
-    // TODO: Support an alternate signal stack.
-    //
-
-    TrapFrame->Esp -= sizeof(SIGNAL_CONTEXT_X86);
-    Status = MmCopyToUserMode((PVOID)(TrapFrame->Esp),
-                              &Context,
-                              sizeof(SIGNAL_CONTEXT_X86));
-
+    Result &= MmUserWrite32(&(Context->Common.Flags), Flags);
     TrapFrame->Esp -= sizeof(SIGNAL_PARAMETERS);
-    Status2 = MmCopyToUserMode((PVOID)(TrapFrame->Esp),
+    Status |= MmCopyToUserMode((PVOID)(TrapFrame->Esp),
                                SignalParameters,
                                sizeof(SIGNAL_PARAMETERS));
 
-    if ((!KSUCCESS(Status)) || (!KSUCCESS(Status2))) {
+    if ((Status != STATUS_SUCCESS) || (Result == FALSE)) {
         PsHandleUserModeFault((PVOID)(TrapFrame->Esp),
                               FAULT_FLAG_WRITE | FAULT_FLAG_PAGE_NOT_PRESENT,
                               TrapFrame,
@@ -273,10 +273,11 @@ Return Value:
                                                 SystemCallParameter,
                                                 SystemCallNumber);
 
-        return;
     }
 
     TrapFrame->Eip = (ULONG)(Thread->OwningProcess->SignalHandlerRoutine);
+    TrapFrame->Eflags &= ~IA32_EFLAG_TF;
+    ADD_SIGNAL(Thread->BlockedSignals, SignalParameters->SignalNumber);
     return;
 }
 
@@ -307,29 +308,72 @@ Return Value:
 
 {
 
-    SIGNAL_CONTEXT_X86 Context;
+    PSIGNAL_CONTEXT_X86 Context;
+    ULONG Eflags;
+    ULONG Flags;
+    TRAP_FRAME Frame;
     INTN Result;
+    SIGNAL_SET SignalMask;
     KSTATUS Status;
     PKTHREAD Thread;
 
+    Context = (PSIGNAL_CONTEXT_X86)UserContext;
+    Result = 0;
     Thread = KeGetCurrentThread();
-    Status = MmCopyFromUserMode(&Context,
-                                (PSIGNAL_CONTEXT_X86)UserContext,
-                                sizeof(SIGNAL_CONTEXT_X86));
+    Status = MmCopyFromUserMode(&Frame,
+                                &(Context->TrapFrame),
+                                sizeof(TRAP_FRAME));
+
+    Status |= MmCopyFromUserMode(&SignalMask,
+                                 &(Context->Common.Mask),
+                                 sizeof(SIGNAL_SET));
+
+    if (!MmUserRead(&(UserContext->Flags), &Flags)) {
+        Status = STATUS_ACCESS_VIOLATION;
+    }
 
     if (!KSUCCESS(Status)) {
-        PsSignalThread(Thread, SIGNAL_ACCESS_VIOLATION, NULL, TRUE);
-        return 0;
+        goto RestorePreSignalTrapFrameEnd;
     }
 
-    REMOVE_SIGNAL(Thread->RunningSignals, Context.Common.Signal);
-    TrapFrame->Eax = Context.Eax;
-    TrapFrame->Ecx = Context.Ecx;
-    TrapFrame->Edx = Context.Edx;
-    TrapFrame->Eflags = Context.Eflags;
-    TrapFrame->Eip = Context.Eip;
-    TrapFrame->Esp = Context.Esp;
-    Result = TrapFrame->Eax;
+    PsSetSignalMask(&SignalMask, NULL);
+
+    //
+    // TODO: Restore the whole trap frame when the system call handler can do
+    // a complete trap frame save.
+    //
+
+    Eflags = TrapFrame->Eflags & ~IA32_EFLAG_USER;
+    Frame.Eflags = (Frame.Eflags & IA32_EFLAG_USER) | Eflags;
+    Frame.Ds = USER_DS;
+    Frame.Es = USER_DS;
+    Result = Frame.Eax;
+    TrapFrame->Eax = Frame.Eax;
+    TrapFrame->Ecx = Frame.Ecx;
+    TrapFrame->Edx = Frame.Edx;
+    TrapFrame->Eip = Frame.Eip;
+    if (ArIsTrapFrameComplete(&Frame)) {
+        TrapFrame->Eflags = Frame.Eflags;
+    }
+
+    TrapFrame->Esp = Frame.Esp;
+    if (((Flags & SIGNAL_CONTEXT_FLAG_FPU_VALID) != 0) &&
+        (Thread->FpuContext != NULL)) {
+
+        Status = MmCopyFromUserMode(Thread->FpuContext,
+                                    &(Context->FpuContext),
+                                    sizeof(FPU_CONTEXT));
+
+        if (!KSUCCESS(Status)) {
+            goto RestorePreSignalTrapFrameEnd;
+        }
+
+        Thread->FpuFlags |= THREAD_FPU_FLAG_IN_USE;
+        if ((Thread->FpuFlags & THREAD_FPU_FLAG_OWNER) != 0) {
+            ArDisableFpu();
+            Thread->FpuFlags &= ~THREAD_FPU_FLAG_OWNER;
+        }
+    }
 
     //
     // If the signal context indicates that a restart is necessary, then fire
@@ -338,12 +382,17 @@ Return Value:
     // cause the next restore to return to the signal handler.
     //
 
-    if ((Context.Common.Flags & SIGNAL_CONTEXT_FLAG_RESTART) != 0) {
-        Result = KeSystemCallHandler(Context.Ecx,
-                                     (PVOID)Context.Edx,
+    if ((Flags & SIGNAL_CONTEXT_FLAG_RESTART) != 0) {
+        Result = KeSystemCallHandler(TrapFrame->Ecx,
+                                     (PVOID)TrapFrame->Edx,
                                      TrapFrame);
     }
 
+RestorePreSignalTrapFrameEnd:
+    if (!KSUCCESS(Status)) {
+        PsSignalThread(Thread, SIGNAL_ACCESS_VIOLATION, NULL, TRUE);
+    }
+
     return Result;
 }
 

+ 1 - 0
uefi/core/armv7/prochw.c

@@ -29,6 +29,7 @@ Environment:
 #include <minoca/kernel/mm.h>
 #include <minoca/kernel/hmod.h>
 #include <minoca/kernel/kdebug.h>
+#include <minoca/kernel/ksignals.h>
 #include <minoca/kernel/arm.h>
 
 //