Selaa lähdekoodia

Unified "full/sparse" system calls into one type.

This change unifies the "full" vs "fast" system call flavors into a single
flavor (equivalent to what used to be "fast"). Full system calls used to
be required by RestoreSignalContext and Exec so that they could restore
all trap frame registers. The full system call variant was also used by
Fork in order to be able to copy the full trap frame out to the child.

RestoreSignalContext and Exec are easy to solve by upgrading the trap
frame to "full" within the system call, and then checking in the system
call assembly and doing a slow full restore if the trap frame got upgraded
to full.

Fork was more complicated, since we needed to read, not write, the full
state. One option would be to check for fork explicitly in the assembly
and do a full save, but this seemed brittle if another system call comes
along with the same requirement. So instead we now ask user mode to
explictly save and restore the non-volatile registers across fork. This
means converting the OsForkProcess function into assembly so the
non-volatiles can be saved and reloaded across the system call.

On x86, I cheated and used the "full" system call mechanism anyway. Since
sysenter might not be supported, this mechanism is around anyway. The
assembly would have been ugly with __get_pc_thunk, _GOT_TABLE_OFFSET and
friends to get to the OsSystemCall global function pointer.

There's another reason to make the fork path assembly: vfork. When vfork
is implemented, the parent and child temporarily share the same stack.
Traditionally that means you cannot touch the stack in between making the
system call and returning all the way back to vfork's caller (because the
child will call other functions from vfork and trash that region). I've
added plumbing in the form of an extra fork parameter to be able to have
the kernel temporarily save and restore that particular region of user
stack. Getting this stack frame base difference requires assembly anyway.

I also rearranged the signal dispatch code and how it relates to system
call restarts. It turns out we don't need to pass around the system call
number and parameter to a bunch of functions. We can pull it out of the
trap frame.

Doing this all simplified the system call assembly significantly, and made
a lot more sense for x64, where the "full" concept was more awkward and
costly to pull off.
Evan Green 6 vuotta sitten
vanhempi
commit
cf1d4e9275

+ 7 - 8
apps/libc/dynamic/pid.c

@@ -391,13 +391,12 @@ Return Value:
 
 {
 
-    PROCESS_ID NewProcess;
-    KSTATUS Status;
+    INTN Result;
 
     ClpRunAtforkPrepareRoutines();
     fflush(NULL);
-    Status = OsForkProcess(0, &NewProcess);
-    if (NewProcess == 0) {
+    Result = OsForkProcess(0, NULL);
+    if (Result == 0) {
         ClpRunAtforkChildRoutines();
 
     //
@@ -409,12 +408,12 @@ Return Value:
         ClpRunAtforkParentRoutines();
     }
 
-    if (!KSUCCESS(Status)) {
-        errno = ClConvertKstatusToErrorNumber(Status);
-        return -1;
+    if (Result >= 0) {
+        return Result;
     }
 
-    return NewProcess;
+    errno = ClConvertKstatusToErrorNumber(Result);
+    return -1;
 }
 
 LIBC_API

+ 37 - 17
apps/osbase/armv7/osbasea.S

@@ -32,7 +32,7 @@ Environment:
 #include <minoca/kernel/arm.inc>
 
 //
-// --------------------------------------------------------------- Definitions
+// ---------------------------------------------------------------- Definitions
 //
 
 //
@@ -42,10 +42,11 @@ Environment:
 ASSEMBLY_FILE_HEADER
 
 //
+// OS_API
 // INTN
-// OspSystemCallFull (
-//     ULONG SystemCallNumber,
-//     PVOID SystemCallParameter
+// OsForkProcess (
+//     ULONG Flags,
+//     PVOID FrameRestoreBase
 //     )
 //
 
@@ -53,29 +54,49 @@ ASSEMBLY_FILE_HEADER
 
 Routine Description:
 
-    This routine executes a system call which performs a full register
-    save/restore.
+    This routine forks the current process into two separate processes. The
+    child process begins executing in the middle of this function.
 
 Arguments:
 
-    SystemCallNumber - Supplies the system call number.
+    Flags - Supplies a bitfield of flags governing the behavior of the newly
+        forked process. See FORK_FLAG_* definitions.
 
-    SystemCallParameter - Supplies the system call parameter.
+    FrameRestoreBase - Supplies an optional pointer to a region of recent
+        stack. On vfork operations, the kernel will copy the stack region from
+        the supplied pointer up to the current stack pointer into a temporary
+        buffer. After the child execs or exits, the kernel will copy that
+        region back into the parent process' stack. This is needed so that the
+        stack can be used in between the C library and the final system call.
 
 Return Value:
 
-    STATUS_SUCCESS or positive integer on success.
+    In the child, returns 0 indicating success.
 
-    Error status code on failure.
+    In the parent, returns the process ID of the child on success, which is
+    always a positive value.
+
+    On failure, returns a KSTATUS code, which is a negative value.
 
 --*/
 
-FUNCTION OspSystemCallFull
-    mov     %r2, #1                 @ Set "full" flag for complete save/restore.
-    swi     #0x0                    @ Perform system call.
-    bx      %lr                     @ Return.
+EXPORTED_FUNCTION OsForkProcess
+
+    //
+    // Push the two arguments into an OS_FORK_PROCESS structure on the stack.
+    // Also Save all non-volatiles because in the child process they will all
+    // be zeroed.
+    //
+
+    stmdb %sp!, {%r0-%r1, %r4-%r11, %lr}     @ Save args and non-volatiles.
+    CFI_ADJUST_CFA_OFFSET(44)                @ Let the debugger know.
+    mov   %r1, %sp                           @ Pass pointer as parameter.
+    ldr   %r0, =SystemCallForkProcess        @ Pass system call number.
+    bl    OsSystemCall                       @ Go make that system call.
+    add   %sp, #8                            @ Pop off the params structure.
+    ldmia %sp!, {%r4-%r11, %pc}              @ Restore non-volatiles and return.
 
-END_FUNCTION OspSystemCallFull
+END_FUNCTION OsForkProcess
 
 //
 // INTN
@@ -106,7 +127,6 @@ Return Value:
 --*/
 
 FUNCTION OsSystemCall
-    eor     %r2, %r2, %r2           @ Clear "full" flag for fast system calls.
     swi     #0x0                    @ Perform system call.
     bx      %lr                     @ Return.
 
@@ -167,7 +187,7 @@ FUNCTION OspSignalHandler
     CFI_ADJUST_CFA_OFFSET(-SIGNAL_PARAMETERS_SIZE)
     mov     %r1, %sp            @ Pass a pointer to the signal context.
     mov     %r0, #SystemCallRestoreContext  @ Set up the system call number.
-    bl      OspSystemCallFull   @ Execute the system call to restore.
+    bl      OsSystemCall        @ Execute the system call to restore.
     DEBUGGER_BREAK              @ Execution should never get here.
 
 END_FUNCTION OspSignalHandler

+ 0 - 66
apps/osbase/osbase.c

@@ -701,58 +701,6 @@ Return Value:
     return OsSystemCall(SystemCallCreateThread, &Parameters);
 }
 
-OS_API
-KSTATUS
-OsForkProcess (
-    ULONG Flags,
-    PPROCESS_ID NewProcessId
-    )
-
-/*++
-
-Routine Description:
-
-    This routine forks the current process into two separate processes. The
-    child process begins executing in the middle of this function.
-
-Arguments:
-
-    Flags - Supplies a bitfield of flags governing the behavior of the newly
-        forked process. See FORK_FLAG_* definitions.
-
-    NewProcessId - Supplies a pointer that on success contains the process ID
-        of the child process in the parent, and 0 in the child. This value
-        contains -1 if the new process failed to spawn.
-
-Return Value:
-
-    STATUS_SUCCESS in both the parent and child on success.
-
-    Other status codes are returned to the parent if the child failed to spawn.
-
---*/
-
-{
-
-    SYSTEM_CALL_FORK Parameters;
-    INTN Result;
-
-    //
-    // Fork returns the process ID of the child to the parent and 0 to the
-    // child. Or a negative status code to the parent if the fork failed.
-    //
-
-    Parameters.Flags = Flags;
-    Result = OspSystemCallFull(SystemCallForkProcess, &Parameters);
-    if (Result < 0) {
-        *NewProcessId = -1;
-        return (KSTATUS)Result;
-    }
-
-    *NewProcessId = Result;
-    return STATUS_SUCCESS;
-}
-
 OS_API
 KSTATUS
 OsExecuteImage (
@@ -792,21 +740,7 @@ Return Value:
     ASSERT(FIELD_OFFSET(SYSTEM_CALL_EXECUTE_IMAGE, Environment) == 0);
 
     Parameters = (PSYSTEM_CALL_EXECUTE_IMAGE)Environment;
-
-    //
-    // TODO: Remove SystemCallFull, then these can be unified.
-    //
-
-#if defined(__amd64)
-
     return OsSystemCall(SystemCallExecuteImage, Parameters);
-
-#else
-
-    return OspSystemCallFull(SystemCallExecuteImage, Parameters);
-
-#endif
-
 }
 
 OS_API

+ 3 - 1
apps/osbase/osbasep.h

@@ -153,6 +153,8 @@ extern UINTN OsPageSize;
 // -------------------------------------------------------- Function Prototypes
 //
 
+#if defined(__i386)
+
 INTN
 OspSystemCallFull (
     ULONG SystemCallNumber,
@@ -182,7 +184,7 @@ Return Value:
 
 --*/
 
-#if defined (__arm__) || defined(__amd64)
+#elif defined (__arm__) || defined(__amd64)
 
 INTN
 OsSystemCall (

+ 58 - 22
apps/osbase/x64/osbasea.S

@@ -42,10 +42,11 @@ Environment:
 ASSEMBLY_FILE_HEADER
 
 //
+// OS_API
 // INTN
-// OsSystemCall (
-//     ULONG SystemCallNumber,
-//     PVOID SystemCallParameter
+// OsForkProcess (
+//     ULONG Flags,
+//     PVOID FrameRestoreBase
 //     )
 //
 
@@ -53,32 +54,71 @@ ASSEMBLY_FILE_HEADER
 
 Routine Description:
 
-    This routine executes a regular system call.
+    This routine forks the current process into two separate processes. The
+    child process begins executing in the middle of this function.
 
 Arguments:
 
-    SystemCallNumber - Supplies the system call number.
+    Flags - Supplies a bitfield of flags governing the behavior of the newly
+        forked process. See FORK_FLAG_* definitions.
 
-    SystemCallParameter - Supplies the system call parameter.
+    FrameRestoreBase - Supplies an optional pointer to a region of recent
+        stack. On vfork operations, the kernel will copy the stack region from
+        the supplied pointer up to the current stack pointer into a temporary
+        buffer. After the child execs or exits, the kernel will copy that
+        region back into the parent process' stack. This is needed so that the
+        stack can be used in between the C library and the final system call.
 
 Return Value:
 
-    STATUS_SUCCESS or positive integer on success.
+    In the child, returns 0 indicating success.
 
-    Error status code on failure.
+    In the parent, returns the process ID of the child on success, which is
+    always a positive value.
 
---*/
+    On failure, returns a KSTATUS code, which is a negative value.
 
-FUNCTION(OsSystemCall)
-    xorl    %edx, %edx          # Do a non-full system call.
-    syscall                     # Just do that system call, params in rdi, rsi.
-    ret                         # Return.
+--*/
 
-END_FUNCTION(OsSystemCall)
+EXPORTED_FUNCTION(OsForkProcess)
+
+    //
+    // Save non-volatiles, since in the child process they're all zeroed out.
+    //
+
+    pushq   %rbp                # Preserve non-volatile.
+    pushq   %rbx                # Preserve non-volatile.
+    pushq   %r12                # Preserve non-volatile.
+    pushq   %r13                # Preserve non-volatile.
+    pushq   %r14                # Preserve non-volatile.
+    pushq   %r15                # Preserve non-volatile.
+
+    //
+    // Create the SYSTEM_CALL_FORK structure, and pass a pointer to it.
+    //
+
+    pushq   %rsi                # Push frame restore base parameter.
+    pushq   %rdi                # Push flags parameter.
+    movq    %rsp, %rsi          # Pass pointer to "structure" as parameter 2.
+    subq    $8, %rsp            # Align stack.
+    CFI_ADJUST_CFA_OFFSET(72)   # Let the debugger know about the stack change.
+    movl    $SystemCallForkProcess, %edi    # Pass system call number param 1.
+    callq   OsSystemCall        # Perform the system call.
+    addq    $24, %rsp           # Pop structure and alignment.
+    CFI_ADJUST_CFA_OFFSET(-24)  # Let the debugger know about the stack change.
+    popq    %r15                # Restore non-volatile.
+    popq    %r14                # Restore non-volatile.
+    popq    %r13                # Restore non-volatile.
+    popq    %r12                # Restore non-volatile.
+    popq    %rbx                # Restore non-volatile.
+    popq    %rbp                # Restore non-volatile.
+    retq
+
+END_FUNCTION(OsForkProcess)
 
 //
 // INTN
-// OspSystemCallFull (
+// OsSystemCall (
 //     ULONG SystemCallNumber,
 //     PVOID SystemCallParameter
 //     )
@@ -88,10 +128,7 @@ END_FUNCTION(OsSystemCall)
 
 Routine Description:
 
-    This routine executes a system call, saving all non-volatile registers
-    along the way. This type of system call is needed for operations that will
-    need access to all non-volatile registers, such as fork or restoring after
-    a signal.
+    This routine executes a regular system call.
 
 Arguments:
 
@@ -107,12 +144,11 @@ Return Value:
 
 --*/
 
-FUNCTION(OspSystemCallFull)
-    movl    $1, %edx            # Indicate a full system call.
+FUNCTION(OsSystemCall)
     syscall                     # Just do that system call, params in rdi, rsi.
     ret                         # Return.
 
-END_FUNCTION(OspSystemCallFull)
+END_FUNCTION(OsSystemCall)
 
 //
 // VOID

+ 53 - 0
apps/osbase/x86/syscall.c

@@ -93,6 +93,59 @@ Return Value:
     return;
 }
 
+OS_API
+INTN
+OsForkProcess (
+    ULONG Flags,
+    PVOID FrameRestoreBase
+    )
+
+/*++
+
+Routine Description:
+
+    This routine forks the current process into two separate processes. The
+    child process begins executing in the middle of this function.
+
+Arguments:
+
+    Flags - Supplies a bitfield of flags governing the behavior of the newly
+        forked process. See FORK_FLAG_* definitions.
+
+    FrameRestoreBase - Supplies an optional pointer to a region of recent
+        stack. On vfork operations, the kernel will copy the stack region from
+        the supplied pointer up to the current stack pointer into a temporary
+        buffer. After the child execs or exits, the kernel will copy that
+        region back into the parent process' stack. This is needed so that the
+        stack can be used in between the C library and the final system call.
+
+Return Value:
+
+    In the child, returns 0 indicating success.
+
+    In the parent, returns the process ID of the child on success, which is
+    always a positive value.
+
+    On failure, returns a KSTATUS code, which is a negative value.
+
+--*/
+
+{
+
+    SYSTEM_CALL_FORK Parameters;
+    INTN Result;
+
+    //
+    // Perform a full system call to avoid the need to save/restore the
+    // non-volatiles.
+    //
+
+    Parameters.Flags = Flags;
+    Parameters.FrameRestoreBase = FrameRestoreBase;
+    Result = OspSystemCallFull(SystemCallForkProcess, &Parameters);
+    return Result;
+}
+
 //
 // --------------------------------------------------------- Internal Functions
 //

+ 2 - 1
include/minoca/kernel/arm.h

@@ -1281,7 +1281,8 @@ ArpSoftwareInterruptEntry (
 Routine Description:
 
     This routine directly handles an exception generated by a software
-    interrupt (a system call).
+    interrupt (a system call). Upon entry, R0 holds the system call number,
+    and R1 holds the system call parameter.
 
 Arguments:
 

+ 3 - 1
include/minoca/kernel/arm.inc

@@ -245,10 +245,12 @@ Environment:
 #endif
 
 //
-// Define the system call number for resuming after a signal.
+// Define the system call number for resuming after a signal and
+// forking a process, operations which happen from assembly.
 //
 
 #define SystemCallRestoreContext 1
+#define SystemCallForkProcess 2
 #define SIGNAL_PARAMETERS_SIZE 24
 #define SIGNAL_CONTEXT_SIZE 32
 

+ 34 - 27
include/minoca/kernel/ps.h

@@ -91,10 +91,10 @@ Author:
 // This macro dispatches pending signals on the given thread if there are any.
 //
 
-#define PsDispatchPendingSignals(_Thread, _TrapFrame)     \
-    ((_Thread)->SignalPending == ThreadNoSignalPending) ? \
-    FALSE :                                               \
-    PsDispatchPendingSignalsOnCurrentThread(_TrapFrame, SystemCallInvalid, NULL)
+#define PsDispatchPendingSignals(_Thread, _TrapFrame)        \
+    if ((_Thread)->SignalPending != ThreadNoSignalPending) { \
+        PsApplyPendingSignals(_TrapFrame);                   \
+    }
 
 //
 // This macro performs a quick inline check to see if any of the runtime timers
@@ -2840,11 +2840,9 @@ Return Value:
 
 --*/
 
-BOOL
-PsDispatchPendingSignalsOnCurrentThread (
-    PTRAP_FRAME TrapFrame,
-    ULONG SystemCallNumber,
-    PVOID SystemCallParameter
+VOID
+PsApplyPendingSignals (
+    PTRAP_FRAME TrapFrame
     );
 
 /*++
@@ -2859,19 +2857,33 @@ Arguments:
     TrapFrame - Supplies a pointer to the current trap frame. If this trap frame
         is not destined for user mode, this function exits immediately.
 
-    SystemCallNumber - Supplies the number of the system call that is
-        attempting to dispatch a pending signal. Supply SystemCallInvalid if
-        the caller is not a system call.
+Return Value:
 
-    SystemCallParameter - Supplies a pointer to the parameters supplied with
-        the system call that is attempting to dispatch a signal. Supply NULL if
-        the caller is not a system call.
+    None.
 
-Return Value:
+--*/
+
+VOID
+PsApplyPendingSignalsOrRestart (
+    PTRAP_FRAME TrapFrame
+    );
+
+/*++
+
+Routine Description:
+
+    This routine dispatches any pending signals that should be run on the
+    current thread. If no signals were dispatched, it attempts to restart a
+    system call.
 
-    FALSE if no signals are pending.
+Arguments:
 
-    TRUE if a signal was applied.
+    TrapFrame - Supplies a pointer to the current trap frame. If this trap frame
+        is not destined for user mode, this function exits immediately.
+
+Return Value:
+
+    None.
 
 --*/
 
@@ -2908,8 +2920,7 @@ VOID
 PsApplySynchronousSignal (
     PTRAP_FRAME TrapFrame,
     PSIGNAL_PARAMETERS SignalParameters,
-    ULONG SystemCallNumber,
-    PVOID SystemCallParameter
+    BOOL InSystemCall
     );
 
 /*++
@@ -2927,13 +2938,9 @@ Arguments:
 
     SignalParameters - Supplies a pointer to the signal information to apply.
 
-    SystemCallNumber - Supplies the number of the system call that is
-        attempting to dispatch a pending signal. Supply SystemCallInvalid if
-        the caller is not a system call.
-
-    SystemCallParameter - Supplies a pointer to the parameters supplied with
-        the system call that is attempting to dispatch a signal. Supply NULL if
-        the caller is not a system call.
+    InSystemCall - Supplies a boolean indicating if the trap frame came from
+        a system call, in which case this routine will look inside to
+        potentially prepare restart information.
 
 Return Value:
 

+ 34 - 19
include/minoca/kernel/syscall.h

@@ -278,16 +278,23 @@ Author:
 // ------------------------------------------------------ Data Type Definitions
 //
 
+//
+// Define the system call numbers. Note that the first few are defined in
+// assmebly as well, so if the top of this table changes arrangement those
+// first few would need upkeep as well. Please move any system call numbers
+// referenced from assembly to the top.
+//
+
 typedef enum _SYSTEM_CALL_NUMBER {
     SystemCallInvalid,
     SystemCallRestoreContext,
+    SystemCallForkProcess,
     SystemCallExitThread,
     SystemCallOpen,
     SystemCallClose,
     SystemCallPerformIo,
     SystemCallCreatePipe,
     SystemCallCreateThread,
-    SystemCallForkProcess,
     SystemCallExecuteImage,
     SystemCallChangeDirectory,
     SystemCallSetSignalHandler,
@@ -434,6 +441,30 @@ typedef enum _RESOURCE_USAGE_REQUEST {
 
 /*++
 
+Structure Description:
+
+    This structure defines the system call parameters for the fork call.
+
+Members:
+
+    Flags - Stores a bitfield of flags governing the behavior of the child.
+
+    FrameRestoreBase - Stores an optional pointer that is only used if the
+        VFORK flag is set in the child. In this case, the kernel will copy a
+        region of the stack from this supplied pointer to the current stack
+        pointer into temporary storage. When the child execs or exits, the
+        kernel will copy this region back into the process, "restoring" that
+        region of the stack after the child trashed it.
+
+--*/
+
+typedef struct _SYSTEM_CALL_FORK {
+    ULONG Flags;
+    PVOID FrameRestoreBase;
+} SYSCALL_STRUCT SYSTEM_CALL_FORK, *PSYSTEM_CALL_FORK;
+
+/*++
+
 Structure Description:
 
     This structure defines the system call parameters for exiting the current
@@ -657,22 +688,6 @@ typedef struct _SYSTEM_CALL_CREATE_THREAD {
 
 /*++
 
-Structure Description:
-
-    This structure defines the system call parameters for the fork call.
-
-Members:
-
-    Flags - Supplies a bitfield of flags governing the behavior of the child.
-
---*/
-
-typedef struct _SYSTEM_CALL_FORK {
-    ULONG Flags;
-} SYSCALL_STRUCT SYSTEM_CALL_FORK, *PSYSTEM_CALL_FORK;
-
-/*++
-
 Structure Description:
 
     This structure defines the system call parameters for the execute image
@@ -680,7 +695,7 @@ Structure Description:
 
 Members:
 
-    Environment - Supplies the image name, arguments, and environment.
+    Environment - Stores the image name, arguments, and environment.
 
 --*/
 
@@ -2510,13 +2525,13 @@ Members:
 --*/
 
 typedef union _SYSTEM_CALL_PARAMETER_UNION {
+    SYSTEM_CALL_FORK Fork;
     SYSTEM_CALL_EXIT_THREAD ExitThread;
     SYSTEM_CALL_OPEN Open;
     SYSTEM_CALL_PERFORM_IO PerformIo;
     SYSTEM_CALL_PERFORM_VECTORED_IO PerformVectoredIo;
     SYSTEM_CALL_CREATE_PIPE CreatePipe;
     SYSTEM_CALL_CREATE_THREAD CreateThread;
-    SYSTEM_CALL_FORK Fork;
     SYSTEM_CALL_EXECUTE_IMAGE ExecuteImage;
     SYSTEM_CALL_CHANGE_DIRECTORY ChangeDirectory;
     SYSTEM_CALL_SET_SIGNAL_HANDLER SetSignalHandler;

+ 2 - 0
include/minoca/kernel/x64.inc

@@ -114,6 +114,8 @@ Environment:
 // TODO: Fix these sizes.
 //
 
+#define SystemCallRestoreContext 1
+#define SystemCallForkProcess 2
 #define PROCESSOR_CONTEXT_SIZE 284
 #define SIGNAL_CONTEXT_SIZE 28
 

+ 8 - 5
include/minoca/lib/minocaos.h

@@ -655,10 +655,10 @@ Return Value:
 --*/
 
 OS_API
-KSTATUS
+INTN
 OsForkProcess (
     ULONG Flags,
-    PPROCESS_ID NewProcessId
+    PVOID FrameRestoreBase
     );
 
 /*++
@@ -673,9 +673,12 @@ Arguments:
     Flags - Supplies a bitfield of flags governing the behavior of the newly
         forked process. See FORK_FLAG_* definitions.
 
-    NewProcessId - Supplies a pointer that on success contains the process ID
-        of the child process in the parent, and 0 in the child. This value
-        contains -1 if the new process failed to spawn.
+    FrameRestoreBase - Supplies an optional pointer to a region of recent
+        stack. On vfork operations, the kernel will copy the stack region from
+        the supplied pointer up to the current stack pointer into a temporary
+        buffer. After the child execs or exits, the kernel will copy that
+        region back into the parent process' stack. This is needed so that the
+        stack can be used in between the C library and the final system call.
 
 Return Value:
 

+ 52 - 161
kernel/armv7/trap.S

@@ -174,9 +174,11 @@ FUNCTION ArpUndefinedInstructionEntry
     mov     %sp, %r4
 
     //
-    // Restore state and return.
+    // Restore state and return. The label below is used by the software
+    // interrupt code, not this function, to reuse a bit of code.
     //
 
+ArpFullRestore:
     ARM_EXIT_INTERRUPT
 
 END_FUNCTION ArpUndefinedInstructionEntry
@@ -193,7 +195,8 @@ END_FUNCTION ArpUndefinedInstructionEntry
 Routine Description:
 
     This routine directly handles an exception generated by a software
-    interrupt (a system call).
+    interrupt (a system call). Upon entry, R0 holds the system call number,
+    and R1 holds the system call parameter.
 
 Arguments:
 
@@ -209,8 +212,6 @@ Return Value:
 
 FUNCTION ArpSoftwareInterruptEntry
     srsdb   %sp!, #ARM_MODE_SVC                 @ Push lr and spsr.
-    tst     %r2, %r2                            @ See if "full" is zero.
-    bne     ArpSoftwareInterruptEntrySlow       @ Go to slow path if non-zero.
     sub     %sp, #(TRAP_FRAME_SIZE - 8)         @ Make space for rest of frame.
     mov     %r2, %sp                            @ Get stack/trap frame param.
     cps     #ARM_MODE_SYSTEM                    @ Switch to system mode.
@@ -219,14 +220,15 @@ FUNCTION ArpSoftwareInterruptEntry
     cpsie   i, #ARM_MODE_SVC                    @ Enable interrupts, svc mode.
 
     //
-    // Save R0 and R1. These are needed by the signal dispatcher and if the
-    // system call gets restarted.
+    // Save R0 and R1. These are needed if the system call gets restarted.
+    // Save R0 into R2 since R0 is used for the return value.
     //
 
-    stmdb   %sp!, {%r0, %r1}                    @ Save the parameters.
+    str     %r0, [%r2, #TRAP_R2]
+    str     %r1, [%r2, #TRAP_R1]
 
-    CFI_OFFSET(r0, 0)
-    CFI_OFFSET(r1, 4)
+    CFI_OFFSET(r1, TRAP_R1)
+    CFI_OFFSET(r0, TRAP_R2)
     CFI_OFFSET(sp, TRAP_USERSP + 8)
     CFI_OFFSET(lr, TRAP_USERLR + 8)
     CFI_OFFSET(pc, TRAP_PC + 8)
@@ -241,10 +243,9 @@ FUNCTION ArpSoftwareInterruptEntry
 
     //
     // The system call routine takes three parameters: the system call number,
-    // system call parameter, and a pointer to the trap frame. User-mode
-    // already set up the first two parameters in R0 and R1, and they were
-    // preserved throughout the context save process. R2 already holds the trap
-    // frame from above.
+    // system call parameter, and a pointer to the trap frame. The number was
+    // moved from R2 into R0 early in the function, the parameter is in R1 from
+    // user mode, and R2 == SP == trap frame.
     //
 
     bl      KeSystemCallHandler                 @ Handle system call.
@@ -262,24 +263,36 @@ FUNCTION ArpSoftwareInterruptEntry
     eor     %r12, %r12                          @ Scrub volatile R12.
     ldr     %r1, [%r1, #THREAD_SIGNAL_PENDING]  @ Load signal pending status.
     cmp     %r1, #ThreadSignalPending           @ Compare to signal pending.
-    beq     ArpSoftwareInterruptFastSignal      @ Jump to dispatch signal.
+    beq     ArpSoftwareInterruptSignalCheck     @ Jump to dispatch signal.
+
+ArpSoftwareInterruptRestore:
+
+    //
+    // See if the trap frame was upgraded to a complete one. If so, go do the
+    // slow restore. Add 1 to the exception CPSR to see if it was -1 (the
+    // magic value indicating an incomplete trap frame).
+    //
+
+    ldr     %r1, [%sp, #TRAP_EXCEPTION_CPSR]    @ Get hint about frame complete.
+    adds    %r1, %r1, #1                        @ Add 1 and set flags.
+    bne     ArpFullRestore                      @ Do a full restore if needed.
 
     //
     // Restore the user mode stack and link registers. Do not restore or
     // clobber R0 as it holds the system call's return value.
     //
 
-    add     %r1, %sp, #8                        @ Get trap frame pointer.
+    mov     %r1, %sp                            @ Get trap frame pointer.
     cpsid   i, #ARM_MODE_SYSTEM                 @ Switch to system mode.
     ldr     %sp, [%r1, #TRAP_USERSP]            @ Restore usermode SP.
     ldr     %lr, [%r1, #TRAP_USERLR]            @ Restore usermode LR.
     cpsid   i, #ARM_MODE_SVC                    @ Switch back to svc mode.
 
     //
-    // Pop off the saved R0 and R1 and most of the trap frame.
+    // Pop off most of the trap frame.
     //
 
-    add     %sp, #TRAP_FRAME_SIZE               @ Pop up to PC/Cpsr.
+    add     %sp, #(TRAP_FRAME_SIZE - 8)         @ Pop up to PC/Cpsr.
     CFI_UNDEFINED(r0)
     CFI_UNDEFINED(r1)
     CFI_UNDEFINED(sp)
@@ -293,162 +306,40 @@ FUNCTION ArpSoftwareInterruptEntry
     eor     %r1, %r1
     rfeia   %sp!                                @ Restore PC and CPSR. Bye!
 
-    //
-    // Save the full trap frame. The CPSR, PC, user SP, user LR and exception
-    // CPSR are the only values saved in the trap frame. The exception CPSR is
-    // a dummy value, but keep it so that the signal dispatcher knows this trap
-    // frame came from the fast path. R0 currently holds the system call's
-    // return value. Do not scrub it. Just save it in the trap frame.
-    //
-
-ArpSoftwareInterruptFastSignal:
-    CFI_UNDEFINED(lr)
-    eor     %lr, %lr                            @ Zero SVC link register.
-    eor     %r1, %r1                            @ Scrub volatile R1.
-    str     %r0, [%sp, #(TRAP_R0 + 8)]          @ Save the return value in R0.
-    mrs     %r0, cpsr                           @ Get the "exception" CPSR.
-    str     %r0, [%sp, #(TRAP_EXCEPTION_CPSR + 8)] @ Save "exception" CPSR.
-    add     %r0, %sp, #(TRAP_PC + 8)            @ Get location after SVC LR.
-    stmdb   %r0!, {%r1-%r12, %lr}               @ Push registers and CPSR.
-    str     %sp, [%sp, #8]                      @ Save SP.
+ArpSoftwareInterruptSignalCheck:
 
     //
-    // Jump down to the slow signal path which starts an IT block. The compare
-    // that dropped the fast path to dispatch a signal should have set the zero
-    // flag and none of the instructions above should have changed the flags,
-    // making the IT block safe to jump to.
+    // See if the trap frame is already complete as a result of the system
+    // call operation (like restore from signal).
     //
 
-    b       ArpSoftwareInterruptSlowSignal
+    ldr     %r1, [%sp, #TRAP_EXCEPTION_CPSR]    @ Get hint about frame complete.
+    adds    %r1, %r1, #1                        @ Add 1 and set flags.
+    bne     ArpSoftwareInterruptSignalDispatch  @ Skip the save if zero now.
 
     //
-    // Perform the slow version of the system call that builds up a complete
-    // trap frame. This is used for system calls like fork and exec, where the
-    // trap frame is used in the system call.
+    // Save the full trap frame. The CPSR, PC, user SP, user LR, exception CPSR,
+    // R1, and R2 are the only values saved in the trap frame. R0 currently
+    // holds the system call's return value. Save it in the trap frame.
     //
 
-ArpSoftwareInterruptEntrySlow:
-    mov     %lr, #0                              @ Zero SVC link register.
-    stmdb   %sp!, {%r1-%r12, %lr}                @ Push general registers.
-    mrs     %r2, cpsr                            @ Get the "exception" CPSR.
-    stmdb   %sp!, {%r0, %r2}                     @ Push exception CPSR and R0.
-    sub     %sp, #12                             @ Account for pushes.
-    mov     %r2, %sp                             @ Get stack/trap frame.
-    cps     #ARM_MODE_SYSTEM                     @ Switch to system mode.
-    str     %lr, [%r2, #TRAP_USERLR]             @ Save usermode SP.
-    str     %sp, [%r2, #TRAP_USERSP]             @ Save usermode LR.
-    cpsie   i, #ARM_MODE_SVC                     @ Enable interrupts, svc mode.
-
-    //
-    // Save R0 and R1. These are needed by the signal dispatcher if the system
-    // call gets restarted. It is not good enough to have them saved in the
-    // trap frame as KeSystemCallHandler may restore an old trap frame.
-    //
-
-    stmdb   %sp!, {%r0, %r1}                     @ Save the parameters.
-    str     %sp, [%r2]                           @ Save SP in the trap frame.
-
-    CFI_DEF_CFA_OFFSET(8)
-    CFI_OFFSET(r0, 0)
-    CFI_OFFSET(r1, TRAP_R1)
-    CFI_OFFSET(r2, TRAP_R2)
-    CFI_OFFSET(r3, TRAP_R3)
-    CFI_OFFSET(r4, TRAP_R4)
-    CFI_OFFSET(r5, TRAP_R5)
-    CFI_OFFSET(r6, TRAP_R6)
-    CFI_OFFSET(r7, TRAP_R7)
-    CFI_OFFSET(r8, TRAP_R8)
-    CFI_OFFSET(r9, TRAP_R9)
-    CFI_OFFSET(r10, TRAP_R10)
-    CFI_OFFSET(r11, TRAP_R11)
-    CFI_OFFSET(r12, TRAP_R12)
-    CFI_OFFSET(sp, TRAP_USERSP)
-    CFI_OFFSET(lr, TRAP_USERLR)
-    CFI_OFFSET(pc, TRAP_PC)
-
-    //
-    // Just like in the fast case, R0 and R1 are preserved as the first two
-    // parameters and R2 gets a pointer to the trap frame during the save.
-    //
-
-    bl      KeSystemCallHandler
-
-    //
-    // Save the return value in the trap frame. It will either get restored on
-    // exit or preserved for later if a signal is applied.
-    //
-
-    str     %r0, [%sp, #(TRAP_R0 + 8)]
-
-    //
-    // Determine whether or not a signal is pending on the thread.
-    //
-
-    ARM_GET_CURRENT_THREAD                       @ Get current thread in R1.
-    ldr     %r1, [%r1, #THREAD_SIGNAL_PENDING]   @ Load signal pending status.
-    cmp     %r1, #ThreadSignalPending            @ Compare to signal pending.
-
-ArpSoftwareInterruptSlowSignal:
-
-    //
-    // The dispatch routine takes the trap frame, system call number and
-    // system call parameter.
-    //
-
-    ITTTT   EQ                                   @ If the zero flag is set...
-    ldreq   %r2, [%sp, #4]                       @ Get system call parameter.
-    ldreq   %r1, [%sp]                           @ Get system call number.
-    addeq   %r0, %sp, #8                         @ Get trap frame.
-    bleq    PsDispatchPendingSignalsOnCurrentThread @ Dispatch signal.
-
-    //
-    // A slow exit or an exit from a signal dispatch restores the full trap
-    // frame.
-    //
-
-ArpSoftwareInterruptEntrySlowEnd:
-
-    //
-    // Pop off the saved system call number and parameter and the SVC stack
-    // pointer. The stack pointer should be the location of the saved system
-    // call number, which isn't needed.
-    //
-
-    add     %sp, %sp, #12
-    CFI_ADJUST_CFA_OFFSET(-12)
+    CFI_UNDEFINED(lr)
+    eor     %lr, %lr                            @ Zero SVC link register.
+    str     %r0, [%sp, #TRAP_R0]                @ Save the return value in R0.
+    str     %lr, [%sp, #TRAP_EXCEPTION_CPSR]    @ Indicate frame is complete.
+    add     %r0, %sp, #TRAP_PC                  @ Get location after SVC LR.
+    stmdb   %r0!, {%r3-%r12, %lr}               @ Push registers and CPSR.
+    str     %sp, [%sp]                          @ Save SP.
 
     //
-    // Restore the user mode stack and link registers.
+    // The dispatch routine takes the trap frame and either dispatches a signal
+    // or tinkers with the trap frame to restart the system call.
     //
 
-    mov     %r0, %sp                            @ Get SVC stack pointer.
-    cpsid   i, #ARM_MODE_SYSTEM                 @ Switch to system mode.
-    ldr     %sp, [%r0, #(TRAP_USERSP - 4)]      @ Restore usermode SP.
-    ldr     %lr, [%r0, #(TRAP_USERLR - 4)]      @ Resotre usermode LR.
-    cpsid   i, #ARM_MODE_SVC                    @ Switch back to svc mode.
-    ldr     %r0, [%sp, #(TRAP_R0 - 4)]          @ Restore R0.
-    add     %sp, %sp, #16                       @ Pop up to R1.
-    ldmia   %sp!, {%r1-%r12, %lr}               @ Restore general registers.
-
-    CFI_DEF_CFA_OFFSET(0)
-    CFI_SAME_VALUE(r0)
-    CFI_SAME_VALUE(r1)
-    CFI_SAME_VALUE(r2)
-    CFI_SAME_VALUE(r3)
-    CFI_SAME_VALUE(r4)
-    CFI_SAME_VALUE(r5)
-    CFI_SAME_VALUE(r6)
-    CFI_SAME_VALUE(r7)
-    CFI_SAME_VALUE(r8)
-    CFI_SAME_VALUE(r9)
-    CFI_SAME_VALUE(r10)
-    CFI_SAME_VALUE(r11)
-    CFI_SAME_VALUE(r12)
-    CFI_UNDEFINED(sp)
-    CFI_SAME_VALUE(lr)
-    CFI_OFFSET(pc, 0)
-
-    rfeia   %sp!                                @ Restore PC and CPSR.
+ArpSoftwareInterruptSignalDispatch:
+    mov     %r0, %sp                            @ Pass the trap frame.
+    bl      PsApplyPendingSignalsOrRestart      @ Dispatch or restart.
+    b       ArpSoftwareInterruptRestore         @ Jump in the line.
 
 END_FUNCTION ArpSoftwareInterruptEntry
 

+ 1 - 1
kernel/ke/syscall.c

@@ -88,6 +88,7 @@ KepTestSystemCall (
 SYSTEM_CALL_TABLE_ENTRY KeSystemCallTable[SystemCallCount] = {
     {KepTestSystemCall, 0, 0},
     {PsSysRestoreContext, 0, 0},
+    {PsSysForkProcess, sizeof(SYSTEM_CALL_FORK), 0},
     {PsSysExitThread, sizeof(SYSTEM_CALL_EXIT_THREAD), 0},
     {IoSysOpen, sizeof(SYSTEM_CALL_OPEN), sizeof(SYSTEM_CALL_OPEN)},
     {IoSysClose, 0, 0},
@@ -98,7 +99,6 @@ SYSTEM_CALL_TABLE_ENTRY KeSystemCallTable[SystemCallCount] = {
     {PsSysCreateThread,
         sizeof(SYSTEM_CALL_CREATE_THREAD),
         sizeof(SYSTEM_CALL_CREATE_THREAD)},
-    {PsSysForkProcess, sizeof(SYSTEM_CALL_FORK), 0},
     {PsSysExecuteImage, sizeof(SYSTEM_CALL_EXECUTE_IMAGE), 0},
     {IoSysChangeDirectory, sizeof(SYSTEM_CALL_CHANGE_DIRECTORY), 0},
     {PsSysSetSignalHandler,

+ 5 - 17
kernel/mm/testmm/stubs.c

@@ -747,11 +747,9 @@ Return Value:
     return;
 }
 
-BOOL
-PsDispatchPendingSignalsOnCurrentThread (
-    PTRAP_FRAME TrapFrame,
-    ULONG SystemCallNumber,
-    PVOID SystemCallParameter
+VOID
+PsApplyPendingSignals (
+    PTRAP_FRAME TrapFrame
     )
 
 /*++
@@ -766,25 +764,15 @@ Arguments:
     TrapFrame - Supplies a pointer to the current trap frame. If this trap frame
         is not destined for user mode, this function exits immediately.
 
-    SystemCallNumber - Supplies the number of the system call that is
-        attempting to dispatch a pending signal. Supply SystemCallInvalid if
-        the caller is not a system call.
-
-    SystemCallParameter - Supplies a pointer to the parameters supplied with
-        the system call that is attempting to dispatch a signal. Supply NULL if
-        the caller is not a system call.
-
 Return Value:
 
-    FALSE if no signals are pending.
-
-    TRUE if a signal was applied.
+    None.
 
 --*/
 
 {
 
-    return FALSE;
+    return;
 }
 
 VOID

+ 30 - 54
kernel/ps/armv7/psarch.c

@@ -40,22 +40,16 @@ Environment:
 //
 
 //
-// Define the length of thumb instructions used to execute full and fast system
-// calls.
+// Define the length of thumb instructions used to execute system calls.
 //
 
 #define THUMB_SWI_INSTRUCTION_LENGTH THUMB16_INSTRUCTION_LENGTH
-#define THUMB_EOR_INSTRUCTION_LENGTH THUMB32_INSTRUCTION_LENGTH
-#define THUMB_MOV_INSTRUCTION_LENGTH THUMB32_INSTRUCTION_LENGTH
 
 //
 // Define the length of the required PC back-up when restarting a system call.
-// Luckily, both eor and mov are the same size, so full and fast system calls
-// have the same back-up length.
 //
 
-#define THUMB_RESTART_PC_BACKUP_LENGTH \
-    (THUMB_SWI_INSTRUCTION_LENGTH + THUMB_EOR_INSTRUCTION_LENGTH)
+#define THUMB_RESTART_PC_BACKUP_LENGTH THUMB_SWI_INSTRUCTION_LENGTH
 
 //
 // ------------------------------------------------------ Data Type Definitions
@@ -149,8 +143,7 @@ VOID
 PsApplySynchronousSignal (
     PTRAP_FRAME TrapFrame,
     PSIGNAL_PARAMETERS SignalParameters,
-    ULONG SystemCallNumber,
-    PVOID SystemCallParameter
+    BOOL InSystemCall
     )
 
 /*++
@@ -168,13 +161,9 @@ Arguments:
 
     SignalParameters - Supplies a pointer to the signal information to apply.
 
-    SystemCallNumber - Supplies the number of the system call that is
-        attempting to dispatch a pending signal. Supply SystemCallInvalid if
-        the caller is not a system call.
-
-    SystemCallParameter - Supplies a pointer to the parameters supplied with
-        the system call that is attempting to dispatch a signal. Supply NULL if
-        the caller is not a system call.
+    InSystemCall - Supplies a boolean indicating if the trap frame came from
+        a system call, in which case this routine will look inside to
+        potentially prepare restart information.
 
 Return Value:
 
@@ -210,6 +199,13 @@ Return Value:
                               RestoreSignals,
                               sizeof(SIGNAL_SET));
 
+    //
+    // The trap frame had better be complete or else kernel data might be being
+    // leaked.
+    //
+
+    ASSERT(ArIsTrapFrameComplete(TrapFrame));
+
     //
     // TODO: Support alternate signal stacks.
     //
@@ -243,22 +239,18 @@ Return Value:
     //
 
     SystemCallResult = (INTN)TrapFrame->R0;
-    if ((SystemCallNumber != SystemCallInvalid) &&
-        (IS_SYSTEM_CALL_NUMBER_RESTARTABLE(SystemCallNumber) != FALSE) &&
+    if ((InSystemCall != FALSE) &&
+        (IS_SYSTEM_CALL_NUMBER_RESTARTABLE(TrapFrame->R2) != FALSE) &&
         (IS_SYSTEM_CALL_RESULT_RESTARTABLE(SystemCallResult) != FALSE)) {
 
         //
         // If the result indicates that the system call is restartable after a
         // signal is applied, then let user mode know by setting the restart
-        // flag in the context. Also save the system call number and parameters
-        // in volatile registers so that they can be placed in the correct
-        // registers for restart.
+        // flag in the context.
         //
 
         if (IS_SYSTEM_CALL_RESULT_RESTARTABLE_AFTER_SIGNAL(SystemCallResult)) {
             Flags |= SIGNAL_CONTEXT_FLAG_RESTART;
-            MmUserWrite32(&(Context->TrapFrame.R1), (UINTN)SystemCallParameter);
-            MmUserWrite32(&(Context->TrapFrame.R2), SystemCallNumber);
         }
 
         //
@@ -281,9 +273,7 @@ Return Value:
                               TrapFrame,
                               Thread->OwningProcess);
 
-        PsDispatchPendingSignalsOnCurrentThread(TrapFrame,
-                                                SystemCallNumber,
-                                                SystemCallParameter);
+        PsApplyPendingSignals(TrapFrame);
     }
 
     TrapFrame->Pc = (ULONG)(Thread->OwningProcess->SignalHandlerRoutine);
@@ -363,7 +353,7 @@ Return Value:
     Frame.Cpsr |= ARM_MODE_USER;
     Frame.SvcSp = TrapFrame->SvcSp;
     Frame.SvcLink = TrapFrame->SvcLink;
-    Frame.ExceptionCpsr = TrapFrame->ExceptionCpsr;
+    Frame.ExceptionCpsr = 0;
     RtlCopyMemory(TrapFrame, &Frame, sizeof(TRAP_FRAME));
     if (((Flags & SIGNAL_CONTEXT_FLAG_FPU_VALID) != 0) &&
         (Thread->FpuContext != NULL)) {
@@ -385,9 +375,8 @@ Return Value:
 
     //
     // If a restart is necessary, back up the PC so that the system call
-    // gets executed again when the trap frame gets restored. Also make sure
-    // that the system call number and parameters are in R0 and R1, which just
-    // requires copying R2 to R0, as the system call number was saved in R2.
+    // gets executed again when the trap frame gets restored. The original R0
+    // was saved in R2.
     //
 
     if ((Flags & SIGNAL_CONTEXT_FLAG_RESTART) != 0) {
@@ -405,9 +394,7 @@ RestorePreSignalTrapFrameEnd:
 
 VOID
 PspArchRestartSystemCall (
-    PTRAP_FRAME TrapFrame,
-    ULONG SystemCallNumber,
-    PVOID SystemCallParameter
+    PTRAP_FRAME TrapFrame
     )
 
 /*++
@@ -423,14 +410,6 @@ Arguments:
     TrapFrame - Supplies a pointer to the full trap frame saved by a system
         call in order to attempt dispatching a signal.
 
-    SystemCallNumber - Supplies the number of the system call that is
-        attempting to dispatch a pending signal. Supplied SystemCallInvalid if
-        the caller is not a system call.
-
-    SystemCallParameter - Supplies a pointer to the parameters supplied with
-        the system call that is attempting to dispatch a signal. Supply NULL if
-        the caller is not a system call.
-
 Return Value:
 
     None.
@@ -445,20 +424,19 @@ Return Value:
     // exit without modifying the trap frame.
     //
 
-    if (!IS_SYSTEM_CALL_NUMBER_RESTARTABLE(SystemCallNumber) ||
+    if (!IS_SYSTEM_CALL_NUMBER_RESTARTABLE(TrapFrame->R2) ||
         !IS_SYSTEM_CALL_RESULT_RESTARTABLE_NO_SIGNAL((INTN)TrapFrame->R0)) {
 
         return;
     }
 
     //
-    // This system call needs to be restarted. Back up the PC. And restore the
-    // system call number and parameter into R0 and R1.
+    // This system call needs to be restarted. Back up the PC. The original R0
+    // (system call number) was stashed away in R2 since R0 is the return value.
     //
 
     TrapFrame->Pc -= THUMB_RESTART_PC_BACKUP_LENGTH;
-    TrapFrame->R0 = SystemCallNumber;
-    TrapFrame->R1 = (ULONG)(UINTN)SystemCallParameter;
+    TrapFrame->R0 = TrapFrame->R2;
     return;
 }
 
@@ -559,9 +537,8 @@ Return Value:
         } else {
 
             //
-            // User mode tried to pull a fast one by forking with the fast
-            // system call handler path. Joke's on them; zero out the registers
-            // that didn't get saved.
+            // The trap frame isn't complete, so forking clears most of the
+            // registers.
             //
 
             RtlZeroMemory(StackTrapFrame, sizeof(TRAP_FRAME));
@@ -631,6 +608,7 @@ Return Value:
     TrapFrame->UserSp = (UINTN)UserStackPointer;
     TrapFrame->Cpsr = ARM_MODE_USER;
     TrapFrame->Pc = (UINTN)Thread->ThreadRoutine;
+    TrapFrame->R0 = (UINTN)(Thread->ThreadParameter);
     if ((TrapFrame->Pc & ARM_THUMB_BIT) != 0) {
         TrapFrame->Cpsr |= PSR_FLAG_THUMB;
     }
@@ -803,10 +781,10 @@ Return Value:
     Break->Registers.Arm.Cpsr = TrapFrame->Cpsr;
     Break->Registers.Arm.R13Sp = TrapFrame->UserSp;
     Break->Registers.Arm.R14Lr = TrapFrame->UserLink;
+    Break->Registers.Arm.R1 = TrapFrame->R1;
+    Break->Registers.Arm.R2 = TrapFrame->R2;
     if (ArIsTrapFrameComplete(TrapFrame) != FALSE) {
         Break->Registers.Arm.R0 = TrapFrame->R0;
-        Break->Registers.Arm.R1 = TrapFrame->R1;
-        Break->Registers.Arm.R2 = TrapFrame->R2;
         Break->Registers.Arm.R3 = TrapFrame->R3;
         Break->Registers.Arm.R4 = TrapFrame->R4;
         Break->Registers.Arm.R5 = TrapFrame->R5;
@@ -820,8 +798,6 @@ Return Value:
 
     } else {
         Break->Registers.Arm.R0 = 0;
-        Break->Registers.Arm.R1 = 0;
-        Break->Registers.Arm.R2 = 0;
         Break->Registers.Arm.R3 = 0;
         Break->Registers.Arm.R4 = 0;
         Break->Registers.Arm.R5 = 0;

+ 1 - 11
kernel/ps/psp.h

@@ -871,9 +871,7 @@ Return Value:
 
 VOID
 PspArchRestartSystemCall (
-    PTRAP_FRAME TrapFrame,
-    ULONG SystemCallNumber,
-    PVOID SystemCallParameter
+    PTRAP_FRAME TrapFrame
     );
 
 /*++
@@ -889,14 +887,6 @@ Arguments:
     TrapFrame - Supplies a pointer to the full trap frame saved by a system
         call in order to attempt dispatching a signal.
 
-    SystemCallNumber - Supplies the number of the system call that is
-        attempting to dispatch a pending signal. Supplied SystemCallInvalid if
-        the caller is not a system call.
-
-    SystemCallParameter - Supplies a pointer to the parameters supplied with
-        the system call that is attempting to dispatch a signal. Supply NULL if
-        the caller is not a system call.
-
 Return Value:
 
     None.

+ 86 - 64
kernel/ps/signals.c

@@ -1467,65 +1467,49 @@ Return Value:
     return;
 }
 
-KSTATUS
-PspCancelQueuedSignal (
-    PKPROCESS Process,
-    PSIGNAL_QUEUE_ENTRY SignalQueueEntry
+VOID
+PsApplyPendingSignals (
+    PTRAP_FRAME TrapFrame
     )
 
 /*++
 
 Routine Description:
 
-    This routine attempts to cancel a queued signal. This only works in
-    specific circumstances where it's known that the signal queue entry cannot
-    be freed or queued to a different process during this time.
+    This routine dispatches any pending signals that should be run on the
+    current thread.
 
 Arguments:
 
-    Process - Supplies a pointer to the process the signal is on.
-
-    SignalQueueEntry - Supplies a pointer to the entry to attempt to remove.
+    TrapFrame - Supplies a pointer to the current trap frame. If this trap frame
+        is not destined for user mode, this function exits immediately.
 
 Return Value:
 
-    STATUS_SUCCESS if the signal was successfully removed. The completion
-    routine will be run in this case.
-
-    STATUS_TOO_LATE if the signal is already in service or was previously
-    serviced.
+    None.
 
 --*/
 
 {
 
-    KSTATUS Status;
-
-    ASSERT(KeGetRunLevel() == RunLevelLow);
-
-    Status = STATUS_TOO_LATE;
-    KeAcquireQueuedLock(Process->QueuedLock);
-    if (SignalQueueEntry->ListEntry.Next != NULL) {
-        LIST_REMOVE(&(SignalQueueEntry->ListEntry));
-        SignalQueueEntry->ListEntry.Next = NULL;
-        Status = STATUS_SUCCESS;
-    }
+    ULONG SignalNumber;
+    SIGNAL_PARAMETERS SignalParameters;
 
-    KeReleaseQueuedLock(Process->QueuedLock);
-    if (KSUCCESS(Status)) {
-        if (SignalQueueEntry->CompletionRoutine != NULL) {
-            SignalQueueEntry->CompletionRoutine(SignalQueueEntry);
+    while (TRUE) {
+        SignalNumber = PsDequeuePendingSignal(&SignalParameters, TrapFrame);
+        if (SignalNumber == (ULONG)-1) {
+            break;
         }
+
+        PsApplySynchronousSignal(TrapFrame, &SignalParameters, FALSE);
     }
 
-    return Status;
+    return;
 }
 
-BOOL
-PsDispatchPendingSignalsOnCurrentThread (
-    PTRAP_FRAME TrapFrame,
-    ULONG SystemCallNumber,
-    PVOID SystemCallParameter
+VOID
+PsApplyPendingSignalsOrRestart (
+    PTRAP_FRAME TrapFrame
     )
 
 /*++
@@ -1533,26 +1517,17 @@ PsDispatchPendingSignalsOnCurrentThread (
 Routine Description:
 
     This routine dispatches any pending signals that should be run on the
-    current thread.
+    current thread. If no signals were dispatched, it attempts to restart a
+    system call.
 
 Arguments:
 
     TrapFrame - Supplies a pointer to the current trap frame. If this trap frame
         is not destined for user mode, this function exits immediately.
 
-    SystemCallNumber - Supplies the number of the system call that is
-        attempting to dispatch a pending signal. Supply SystemCallInvalid if
-        the caller is not a system call.
-
-    SystemCallParameter - Supplies a pointer to the parameters supplied with
-        the system call that is attempting to dispatch a signal. Supply NULL if
-        the caller is not a system call.
-
 Return Value:
 
-    FALSE if no signals are pending.
-
-    TRUE if a signal was applied.
+    None.
 
 --*/
 
@@ -1566,15 +1541,12 @@ Return Value:
     Applied = FALSE;
     while (TRUE) {
         SignalNumber = PsDequeuePendingSignal(&SignalParameters, TrapFrame);
-        if (SignalNumber == -1) {
+        if (SignalNumber == (ULONG)-1) {
             break;
         }
 
         Applied = TRUE;
-        PsApplySynchronousSignal(TrapFrame,
-                                 &SignalParameters,
-                                 SystemCallNumber,
-                                 SystemCallParameter);
+        PsApplySynchronousSignal(TrapFrame, &SignalParameters, TRUE);
     }
 
     //
@@ -1582,21 +1554,71 @@ Return Value:
     // and potentially restart the system call.
     //
 
-    if (SystemCallNumber != SystemCallInvalid) {
-        if (Applied == FALSE) {
-            Thread = KeGetCurrentThread();
-            if ((Thread->Flags & THREAD_FLAG_RESTORE_SIGNALS) != 0) {
-                Thread->Flags &= ~THREAD_FLAG_RESTORE_SIGNALS;
-                PsSetSignalMask(&(Thread->RestoreSignals), NULL);
-            }
+    if (Applied == FALSE) {
+        Thread = KeGetCurrentThread();
+        if ((Thread->Flags & THREAD_FLAG_RESTORE_SIGNALS) != 0) {
+            Thread->Flags &= ~THREAD_FLAG_RESTORE_SIGNALS;
+            PsSetSignalMask(&(Thread->RestoreSignals), NULL);
+        }
+
+        PspArchRestartSystemCall(TrapFrame);
+    }
+
+    return;
+}
+
+KSTATUS
+PspCancelQueuedSignal (
+    PKPROCESS Process,
+    PSIGNAL_QUEUE_ENTRY SignalQueueEntry
+    )
+
+/*++
+
+Routine Description:
+
+    This routine attempts to cancel a queued signal. This only works in
+    specific circumstances where it's known that the signal queue entry cannot
+    be freed or queued to a different process during this time.
+
+Arguments:
+
+    Process - Supplies a pointer to the process the signal is on.
+
+    SignalQueueEntry - Supplies a pointer to the entry to attempt to remove.
+
+Return Value:
+
+    STATUS_SUCCESS if the signal was successfully removed. The completion
+    routine will be run in this case.
+
+    STATUS_TOO_LATE if the signal is already in service or was previously
+    serviced.
+
+--*/
+
+{
+
+    KSTATUS Status;
+
+    ASSERT(KeGetRunLevel() == RunLevelLow);
+
+    Status = STATUS_TOO_LATE;
+    KeAcquireQueuedLock(Process->QueuedLock);
+    if (SignalQueueEntry->ListEntry.Next != NULL) {
+        LIST_REMOVE(&(SignalQueueEntry->ListEntry));
+        SignalQueueEntry->ListEntry.Next = NULL;
+        Status = STATUS_SUCCESS;
+    }
 
-            PspArchRestartSystemCall(TrapFrame,
-                                     SystemCallNumber,
-                                     SystemCallParameter);
+    KeReleaseQueuedLock(Process->QueuedLock);
+    if (KSUCCESS(Status)) {
+        if (SignalQueueEntry->CompletionRoutine != NULL) {
+            SignalQueueEntry->CompletionRoutine(SignalQueueEntry);
         }
     }
 
-    return Applied;
+    return Status;
 }
 
 ULONG

+ 18 - 36
kernel/ps/x64/psarch.c

@@ -142,8 +142,7 @@ VOID
 PsApplySynchronousSignal (
     PTRAP_FRAME TrapFrame,
     PSIGNAL_PARAMETERS SignalParameters,
-    ULONG SystemCallNumber,
-    PVOID SystemCallParameter
+    BOOL InSystemCall
     )
 
 /*++
@@ -161,13 +160,9 @@ Arguments:
 
     SignalParameters - Supplies a pointer to the signal information to apply.
 
-    SystemCallNumber - Supplies the number of the system call that is
-        attempting to dispatch a pending signal. Supply SystemCallInvalid if
-        the caller is not a system call.
-
-    SystemCallParameter - Supplies a pointer to the parameters supplied with
-        the system call that is attempting to dispatch a signal. Supply NULL if
-        the caller is not a system call.
+    InSystemCall - Supplies a boolean indicating if the trap frame came from
+        a system call, in which case this routine will look inside to
+        potentially prepare restart information.
 
 Return Value:
 
@@ -208,6 +203,13 @@ Return Value:
                               RestoreSignals,
                               sizeof(SIGNAL_SET));
 
+    //
+    // The trap frame had better be complete or else kernel data might be being
+    // leaked.
+    //
+
+    ASSERT(ArIsTrapFrameComplete(TrapFrame));
+
     //
     // TODO: Support alternate signal stacks.
     //
@@ -241,22 +243,18 @@ Return Value:
     //
 
     SystemCallResult = (INTN)TrapFrame->Rax;
-    if ((SystemCallNumber != SystemCallInvalid) &&
-        (IS_SYSTEM_CALL_NUMBER_RESTARTABLE(SystemCallNumber) != FALSE) &&
+    if ((InSystemCall != FALSE) &&
+        (IS_SYSTEM_CALL_NUMBER_RESTARTABLE(TrapFrame->Rdi)) &&
         (IS_SYSTEM_CALL_RESULT_RESTARTABLE(SystemCallResult) != FALSE)) {
 
         //
         // If the result indicates that the system call is restartable after a
         // signal is applied, then let user mode know by setting the restart
-        // flag in the context. Also save the system call number and parameters
-        // in volatile registers so that they can be placed in the correct
-        // registers for restart.
+        // flag in the context.
         //
 
         if (IS_SYSTEM_CALL_RESULT_RESTARTABLE_AFTER_SIGNAL(SystemCallResult)) {
             Flags |= SIGNAL_CONTEXT_FLAG_RESTART;
-            MmUserWrite(&(Context->TrapFrame.Rdi), SystemCallNumber);
-            MmUserWrite(&(Context->TrapFrame.Rsi), (UINTN)SystemCallParameter);
         }
 
         //
@@ -279,9 +277,7 @@ Return Value:
                               TrapFrame,
                               Thread->OwningProcess);
 
-        PsDispatchPendingSignalsOnCurrentThread(TrapFrame,
-                                                SystemCallNumber,
-                                                SystemCallParameter);
+        PsApplyPendingSignals(TrapFrame);
     }
 
     TrapFrame->Rip = (UINTN)(Thread->OwningProcess->SignalHandlerRoutine);
@@ -398,9 +394,7 @@ RestorePreSignalTrapFrameEnd:
 
 VOID
 PspArchRestartSystemCall (
-    PTRAP_FRAME TrapFrame,
-    ULONG SystemCallNumber,
-    PVOID SystemCallParameter
+    PTRAP_FRAME TrapFrame
     )
 
 /*++
@@ -416,14 +410,6 @@ Arguments:
     TrapFrame - Supplies a pointer to the full trap frame saved by a system
         call in order to attempt dispatching a signal.
 
-    SystemCallNumber - Supplies the number of the system call that is
-        attempting to dispatch a pending signal. Supplied SystemCallInvalid if
-        the caller is not a system call.
-
-    SystemCallParameter - Supplies a pointer to the parameters supplied with
-        the system call that is attempting to dispatch a signal. Supply NULL if
-        the caller is not a system call.
-
 Return Value:
 
     None.
@@ -437,19 +423,16 @@ Return Value:
     // to see if the system call can be restarted. If not, exit.
     //
 
-    if (!IS_SYSTEM_CALL_NUMBER_RESTARTABLE(SystemCallNumber) ||
+    if (!IS_SYSTEM_CALL_NUMBER_RESTARTABLE(TrapFrame->Rdi) ||
         !IS_SYSTEM_CALL_RESULT_RESTARTABLE_NO_SIGNAL((INTN)TrapFrame->Rax)) {
 
         return;
     }
 
     //
-    // Back up over the syscall or int $N instruction, and reset the
-    // number/parameter to restart the call.
+    // Back up over the syscall instruction.
     //
 
-    TrapFrame->Rdi = SystemCallNumber;
-    TrapFrame->Rsi = (UINTN)SystemCallParameter;
     TrapFrame->Rip -= X86_SYSCALL_INSTRUCTION_LENGTH;
     return;
 }
@@ -567,7 +550,6 @@ Return Value:
             //
 
             StackTrapFrame->Rax = 0;
-            TrapFrame->Rax = Thread->OwningProcess->Identifiers.ProcessId;
 
         } else {
 

+ 21 - 46
kernel/ps/x86/psarch.c

@@ -153,8 +153,7 @@ VOID
 PsApplySynchronousSignal (
     PTRAP_FRAME TrapFrame,
     PSIGNAL_PARAMETERS SignalParameters,
-    ULONG SystemCallNumber,
-    PVOID SystemCallParameter
+    BOOL InSystemCall
     )
 
 /*++
@@ -172,13 +171,9 @@ Arguments:
 
     SignalParameters - Supplies a pointer to the signal information to apply.
 
-    SystemCallNumber - Supplies the number of the system call that is
-        attempting to dispatch a pending signal. Supply SystemCallInvalid if
-        the caller is not a system call.
-
-    SystemCallParameter - Supplies a pointer to the parameters supplied with
-        the system call that is attempting to dispatch a signal. Supply NULL if
-        the caller is not a system call.
+    InSystemCall - Supplies a boolean indicating if the trap frame came from
+        a system call, in which case this routine will look inside to
+        potentially prepare restart information.
 
 Return Value:
 
@@ -222,7 +217,12 @@ Return Value:
     Result &= MmUserWrite(&(Context->Common.Stack.Size), 0);
     Result &= MmUserWrite32(&(Context->Common.Stack.Flags), 0);
 
-    ASSERT(ArIsTrapFrameComplete(TrapFrame) != FALSE);
+    //
+    // The trap frame had better be complete or else kernel data might be being
+    // leaked.
+    //
+
+    ASSERT(ArIsTrapFrameComplete(TrapFrame));
 
     Status |= MmCopyToUserMode(&(Context->TrapFrame),
                                TrapFrame,
@@ -247,22 +247,18 @@ Return Value:
     //
 
     SystemCallResult = (INTN)TrapFrame->Eax;
-    if ((SystemCallNumber != SystemCallInvalid) &&
-        (IS_SYSTEM_CALL_NUMBER_RESTARTABLE(SystemCallNumber) != FALSE) &&
+    if ((InSystemCall != FALSE) &&
+        (IS_SYSTEM_CALL_NUMBER_RESTARTABLE(Context->TrapFrame.Ecx)) &&
         (IS_SYSTEM_CALL_RESULT_RESTARTABLE(SystemCallResult) != FALSE)) {
 
         //
         // If the result indicates that the system call is restartable after a
         // signal is applied, then let user mode know by setting the restart
-        // flag in the context. Also save the system call number and parameters
-        // in volatile registers so that they can be placed in the correct
-        // registers for restart.
+        // flag in the context.
         //
 
         if (IS_SYSTEM_CALL_RESULT_RESTARTABLE_AFTER_SIGNAL(SystemCallResult)) {
             Flags |= SIGNAL_CONTEXT_FLAG_RESTART;
-            MmUserWrite(&(Context->TrapFrame.Ecx), SystemCallNumber);
-            MmUserWrite(&(Context->TrapFrame.Edx), (UINTN)SystemCallParameter);
         }
 
         //
@@ -285,9 +281,7 @@ Return Value:
                               TrapFrame,
                               Thread->OwningProcess);
 
-        PsDispatchPendingSignalsOnCurrentThread(TrapFrame,
-                                                SystemCallNumber,
-                                                SystemCallParameter);
+        PsApplyPendingSignals(TrapFrame);
     }
 
     TrapFrame->Eip = (ULONG)(Thread->OwningProcess->SignalHandlerRoutine);
@@ -426,9 +420,7 @@ RestorePreSignalTrapFrameEnd:
 
 VOID
 PspArchRestartSystemCall (
-    PTRAP_FRAME TrapFrame,
-    ULONG SystemCallNumber,
-    PVOID SystemCallParameter
+    PTRAP_FRAME TrapFrame
     )
 
 /*++
@@ -444,14 +436,6 @@ Arguments:
     TrapFrame - Supplies a pointer to the full trap frame saved by a system
         call in order to attempt dispatching a signal.
 
-    SystemCallNumber - Supplies the number of the system call that is
-        attempting to dispatch a pending signal. Supplied SystemCallInvalid if
-        the caller is not a system call.
-
-    SystemCallParameter - Supplies a pointer to the parameters supplied with
-        the system call that is attempting to dispatch a signal. Supply NULL if
-        the caller is not a system call.
-
 Return Value:
 
     None.
@@ -468,7 +452,7 @@ Return Value:
     // to see if the system call can be restarted. If not, exit.
     //
 
-    if (!IS_SYSTEM_CALL_NUMBER_RESTARTABLE(SystemCallNumber) ||
+    if (!IS_SYSTEM_CALL_NUMBER_RESTARTABLE(TrapFrame->Ecx) ||
         !IS_SYSTEM_CALL_RESULT_RESTARTABLE_NO_SIGNAL((INTN)TrapFrame->Eax)) {
 
         return;
@@ -488,28 +472,21 @@ Return Value:
                        NULL,
                        TRUE);
 
-        PsDispatchPendingSignalsOnCurrentThread(TrapFrame,
-                                                SystemCallNumber,
-                                                SystemCallParameter);
-
+        PsApplyPendingSignals(TrapFrame);
         return;
     }
 
     //
     // If the trap frame was from a full system call (not sysenter), only back
-    // up over the INT instruction. Store the system call number and parameter
-    // in ECX and EDX so that only the INT instruction needs to be replayed.
+    // up over the INT instruction.
     //
 
     if (FromSysenter == FALSE) {
-        TrapFrame->Ecx = SystemCallNumber;
-        TrapFrame->Edx = (ULONG)(UINTN)SystemCallParameter;
         TrapFrame->Eip -= X86_INT_INSTRUCTION_LENGTH;
 
     //
     // A sysenter trap frame's EIP points to the instruction after the dummy
-    // call to OspSysenter. Back up over that. It will replay enough to gather
-    // the system call number and parameter from the stack.
+    // call to OspSysenter. Back up over that.
     //
 
     } else {
@@ -831,12 +808,12 @@ Return Value:
 
     Break->Registers.X86.Eip = TrapFrame->Eip;
     Break->Registers.X86.Esp = TrapFrame->Esp;
+    Break->Registers.X86.Ecx = TrapFrame->Ecx;
+    Break->Registers.X86.Edx = TrapFrame->Edx;
     if (ArIsTrapFrameComplete(TrapFrame) != FALSE) {
         Break->ErrorCode = TrapFrame->ErrorCode;
         Break->Registers.X86.Eax = TrapFrame->Eax;
         Break->Registers.X86.Ebx = TrapFrame->Ebx;
-        Break->Registers.X86.Ecx = TrapFrame->Ecx;
-        Break->Registers.X86.Edx = TrapFrame->Edx;
         Break->Registers.X86.Ebp = TrapFrame->Ebp;
         Break->Registers.X86.Esi = TrapFrame->Esi;
         Break->Registers.X86.Edi = TrapFrame->Edi;
@@ -852,8 +829,6 @@ Return Value:
         Break->ErrorCode = 0;
         Break->Registers.X86.Eax = 0;
         Break->Registers.X86.Ebx = 0;
-        Break->Registers.X86.Ecx = 0;
-        Break->Registers.X86.Edx = 0;
         Break->Registers.X86.Ebp = 0;
         Break->Registers.X86.Esi = 0;
         Break->Registers.X86.Edi = 0;

+ 42 - 76
kernel/x64/trap.S

@@ -441,13 +441,11 @@ FUNCTION(ArSyscallHandlerAsm)
     movq    %r10, TRAP_RSP(%rsp)    # Save the user RSP.
     movq    %rdi, TRAP_RDI(%rsp)    # Save first parameter in case of restart.
     movq    %rsi, TRAP_RSI(%rsp)    # Save second parameter in case of restart.
-    movq    %rdx, TRAP_RDX(%rsp)    # Save third parameter in case of restart.
     CFI_DEF_CFA(%rsp, 0)
     CFI_OFFSET(%rip, TRAP_RIP)
     CFI_OFFSET(%rsp, TRAP_RSP)
     CFI_OFFSET(%rdi, TRAP_RDI)
     CFI_OFFSET(%rsi, TRAP_RSI)
-    CFI_OFFSET(%rdx, TRAP_RDX)
 
     //
     // Move user DS (rather than user CS) into the trap frame to indicate
@@ -455,17 +453,6 @@ FUNCTION(ArSyscallHandlerAsm)
     //
 
     movq    $USER_DS, TRAP_CS(%rsp)
-
-    //
-    // See if a slower and more rare full-save is necessary. If not, just let
-    // the C functions maintain the non-volatile registers.
-    //
-
-    testl   %edx, %edx              # See if the user wants the full save.
-    jz      ArSyscallCallHandler    # Jump out in the unlikely full save case.
-    call    ArSyscallFullSave       # Perform a "call" to save the rest.
-
-ArSyscallCallHandler:
     movq    %rsp, %rdx              # Move fake trap frame to 3rd parameter.
     call    KeSystemCallHandler     # Call out to the handler.
 
@@ -481,41 +468,50 @@ ArSyscallCallHandler:
     jne     ArSyscallHandlerFastRestore # Exit via the fast restore path.
 
     //
-    // Save RAX into the trap frame in case the full save was already done.
-    // TODO: Remove this once user mode stops doing "full save" system calls.
+    // See if the trap frame is already complete from being upgraded by the
+    // system call itself. Avoid the save if so, as that might undo useful
+    // work (like restoring pre-signal context).
     //
 
-    movq    %rax, TRAP_RAX(%rsp)
+    cmpl    $USER_DS, TRAP_CS(%rsp) # Compare CS hint against non-full value.
+    jne     ArSyscallFullRestore    # Go back and do a full restoration maybe.
 
     //
-    // See if the trap frame has been saved already or not. Save it if it has
-    // not.
+    // Perform a full trap frame save.
     //
 
-    movl    TRAP_CS(%rsp), %edx     # Get whether or not the trap frame is full.
-    cmpl    $USER_DS, %edx          # Compare against the non-full value.
-    jnz     ArSyscallDispatchSignals   # Go straight to signal dispatch if full.
-    call    ArSyscallFullSave       # Save the remainder if not done.
+    movq    $USER64_CS, TRAP_CS(%rsp)   # Indicate trap frame is complete.
+    movq    %rax, TRAP_RAX(%rsp)    # Save RAX.
+    movl    $USER_DS, %eax          # Get USER_DS in a register.
+    movl    %eax, TRAP_SS(%rsp)     # Set SS.
+    movl    %eax, TRAP_DS(%rsp)     # Set DS.
+    movl    %eax, TRAP_ES(%rsp)     # Set ES.
+    movl    %eax, TRAP_FS(%rsp)     # Set FS.
+    movl    %eax, TRAP_GS(%rsp)     # Set GS.
+    xorl    %eax, %eax              # Get a zero register.
+    movq    %rax, TRAP_PADDING(%rsp)# Clear padding.
+    movq    $USER64_CS, TRAP_CS(%rsp)   # Save CS, and indicate completeness.
+    movq    %rax, TRAP_ERRORCODE(%rsp)  # Clear error code.
+    movq    %r15, TRAP_R15(%rsp)    # Save R15.
+    movq    %r14, TRAP_R14(%rsp)    # Save R14.
+    movq    %r13, TRAP_R13(%rsp)    # Save R13.
+    movq    %r12, TRAP_R12(%rsp)    # Save R12.
+    movq    %rax, TRAP_R11(%rsp)    # Clear volatile R11.
+    movq    %rax, TRAP_R10(%rsp)    # Clear volatile R10.
+    movq    %rax, TRAP_RDX(%rsp)    # Clear volatile RDX.
+    movq    %rax, TRAP_R9(%rsp)     # Clear volatile R9.
+    movq    %rax, TRAP_R8(%rsp)     # Clear volatile R8.
+    movq    %rbp, TRAP_RBP(%rsp)    # Save RBP.
+    movq    %rax, TRAP_RCX(%rsp)    # Clear RCX.
+    movq    %rbx, TRAP_RBX(%rsp)    # Save RBX.
     CFI_TRAP_FRAME_PUSHED           # Inform the unwinder of the full frame.
 
-ArSyscallDispatchSignals:
+ArSyscallSignalDispatch:
     movq    %rsp, %rdi              # Set the trap frame as the first parameter.
-    movq    TRAP_RDI(%rsp), %rsi    # Set the system call number as the second.
-    movq    TRAP_RSI(%rsp), %rdx    # Set the call parameter as the third.
-    call    PsDispatchPendingSignalsOnCurrentThread # Dispatch signals.
-
-    //
-    // Do a full trap frame restore if a signal was applied in case the
-    // debugger changed registers.
-    //
-
-ArSyscallFullRestore:
-    call    ArRestoreTrapFrame      # Restore the full context.
-    iretq                           # Jump out the old way.
+    call    PsApplyPendingSignalsOrRestart # Dispatch signals or restart.
 
 ArSyscallHandlerFastRestore:
-    movl    TRAP_CS(%rsp), %edx     # Get whether or not the trap frame is full.
-    cmpl    $USER_DS, %edx          # Compare against the non-full value.
+    cmpl    $USER_DS, TRAP_CS(%rsp) # Compare CS hint against non-full value.
     jne     ArSyscallFullRestore    # Go back and do a full restoration maybe.
 
     //
@@ -529,53 +525,23 @@ ArSyscallHandlerFastRestore:
     andq    %rdx, %rcx              # Canonicalize rip.
     movq    TRAP_RFLAGS(%rsp), %r11 # Prepare rflags in rcx for sysret.
     xorl    %edx, %edx              # Clear volatile to avoid leaking data.
-    movl    %edx, %esi              # Clear volatile.
-    movl    %edx, %r8d              # Clear volatile.
-    movl    %edx, %r9d              # Clear volatile.
-    movl    %edx, %r10d             # Clear volatile.
-
-    //
-    // Restore rdi unconditionally. This is done so that an exec even with the
-    // fast call mechanism (inappropriate) will have its parameter set up.
-    //
-
-    movq    TRAP_RDI(%rsp), %rdi    # Restore rdi (maybe a parameter).
+    xorl    %esi, %esi              # Clear volatile.
+    xorl    %r8d, %r8d              # Clear volatile.
+    xorl    %r9d, %r9d              # Clear volatile.
+    xorl    %r10d, %r10d            # Clear volatile.
     cli                             # Disable interrupts to go off-stack.
     movq    TRAP_RSP(%rsp), %rsp    # Restore user mode stack.
     swapgs                          # Go back to user land.
     sysretq                         # Return to user mode, slickly.
 
     //
-    // This out of line "function" implements the full save, which saves a
-    // complete trap frame. It assumes the trap frame is right above the return
-    // address, and it destroys rax and rcx.
+    // The out of line code to do a full trap frame restore.
     //
 
-ArSyscallFullSave:
-    popq    %rcx                    # Pop the return addr, stack frame at rsp.
-    movq    %rax, TRAP_RAX(%rsp)    # Save RAX.
-    movl    $USER_DS, %eax          # Get USER_DS in a register.
-    movl    %eax, TRAP_SS(%rsp)     # Set SS.
-    movl    %eax, TRAP_DS(%rsp)     # Set DS.
-    movl    %eax, TRAP_ES(%rsp)     # Set ES.
-    movl    %eax, TRAP_FS(%rsp)     # Set FS.
-    movl    %eax, TRAP_GS(%rsp)     # Set GS.
-    xorl    %eax, %eax              # Get a zero register.
-    movq    %rax, TRAP_PADDING(%rsp)# Clear padding.
-    movq    $USER64_CS, TRAP_CS(%rsp)   # Save CS, and indicate completeness.
-    movq    %rax, TRAP_ERRORCODE(%rsp)  # Clear error code.
-    movq    %r15, TRAP_R15(%rsp)    # Save R15.
-    movq    %r14, TRAP_R14(%rsp)    # Save R14.
-    movq    %r13, TRAP_R13(%rsp)    # Save R13.
-    movq    %r12, TRAP_R12(%rsp)    # Save R12.
-    movq    %rax, TRAP_R11(%rsp)    # Clear volatile R11.
-    movq    %rax, TRAP_R10(%rsp)    # Clear volatile R10.
-    movq    %r9, TRAP_R9(%rsp)      # Save volatile R9 unnecessarily.
-    movq    %r8, TRAP_R8(%rsp)      # Save volatile R8 unnecessarily.
-    movq    %rbp, TRAP_RBP(%rsp)    # Save RBP.
-    movq    %rax, TRAP_RCX(%rsp)    # Clear RCX.
-    movq    %rbx, TRAP_RBX(%rsp)    # Save RBX.
-    jmp     *%rcx                   # Return.
+ArSyscallFullRestore:
+    call    ArRestoreTrapFrame      # Restore the full context.
+    CFI_TRAP_FRAME_POPPED           # Let the debugger know.
+    iretq                           # Jump out the old way.
 
 END_FUNCTION(ArSyscallHandlerAsm)
 

+ 45 - 77
kernel/x86/trap.S

@@ -541,22 +541,18 @@ Return Value:
 
 FUNCTION(ArSystemCallHandlerAsm)
     pushl   $0                      # Push a dummy error code.
-    call    ArGenerateTrapFrame     # Create a local trap frame.
-    CFI_TRAP_FRAME_PUSHED           # Set unwind info for the debugger.
-
-ArSystemCallHandlerAfterTrapSave:
-    mov     TRAP_ECX(%ebx), %ecx    # Get ecx, containing the call number.
-    mov     TRAP_EDX(%ebx), %edx    # Get edx, containing the parameter.
 
     //
-    // Dispatching the signal takes the system call number, system call
-    // parameter and trap frame as arguments. This means that the system call
-    // number and parameter need to be saved across the call to
-    // KeSystemCallHandler.
+    // Save the complete trap frame. This routine is aware that
+    // ArGenerateTrapFrame doesn't clobber ecx and edx, which hold the system
+    // call number and parameter. If ArGenerateTrapFrame did clobber those
+    // registers, they'd need to be reloaded after this.
     //
 
-    pushl   %edx                    # Push system call parameter for dispatch.
-    pushl   %ecx                    # Push system call number for dispatch.
+    call    ArGenerateTrapFrame     # Create a local trap frame.
+    CFI_TRAP_FRAME_PUSHED           # Set unwind info for the debugger.
+
+ArSystemCallHandlerAfterTrapSave:
 
     //
     // Push the parameters for the system call handler. The compiler is free to
@@ -567,7 +563,7 @@ ArSystemCallHandlerAfterTrapSave:
     pushl   %ebx                    # Push a pointer to the trap frame.
     pushl   %edx                    # Push system call parameter.
     pushl   %ecx                    # Push system call number.
-    CFI_ADJUST_CFA_OFFSET(20)       # Tell the debugger.
+    CFI_ADJUST_CFA_OFFSET(12)       # Tell the debugger.
     call    KeSystemCallHandler     # Call the main exception handler.
     addl    $0xC, %esp              # Pop the parameters.
     CFI_ADJUST_CFA_OFFSET(-12)      # Tell the debugger.
@@ -589,13 +585,11 @@ ArSystemCallHandlerAfterTrapSave:
 
     pushl   %ebx                    # Push trap frame.
     CFI_ADJUST_CFA_OFFSET(4)        # Notify about the push.
-    call    PsDispatchPendingSignalsOnCurrentThread # Dispatch signals.
+    call    PsApplyPendingSignalsOrRestart  # Apply signals or restart the call.
     addl    $0x4, %esp              # Pop the trap frame.
     CFI_ADJUST_CFA_OFFSET(-4)       # Notify about the pop.
 
 ArSystemCallHandlerExit:
-    addl    $0x8, %esp              # Pop the system call number and parameter.
-    CFI_ADJUST_CFA_OFFSET(-8)       # Notify about the pop.
     call    ArRestoreTrapFrame      # Restore the trap frame
     CFI_TRAP_FRAME_POPPED           # Let the debugger know.
     addl    $0x4, %esp              # Pop the error code.
@@ -633,16 +627,17 @@ FUNCTION(ArSysenterHandlerAsm)
 
     //
     // ESP is currently pointing at the processor double fault stack, which
-    // is also the main TSS. Switch to the thread stack.
+    // is also the main TSS. Switch to the thread stack. Make room on the stack
+    // as if the hardware has pushed SS, ESP, EFLAGS, CS, EIP, and an error
+    // code, since the return path might go out with a full iret.
     //
 
     movl    TSS_ESP0(%esp), %esp    # Load the stack.
+    subl    $24, %esp               # Fake the hardware pushes.
 
     //
     // Make a fake trap frame but fill in the bare minimum: Eip and Esp.
-    // These are needed so they can be saved if a signal is dispatched. CS is
-    // also needed so kernel code can determine whether the trap frame is
-    // from user or kernel mode.
+    // These are needed so they can be saved if a signal is dispatched.
     //
 
     pushl   %eax                    # Save user ESP in trap frame.
@@ -651,6 +646,8 @@ FUNCTION(ArSysenterHandlerAsm)
     subl    $(TRAP_FRAME_SIZE - 4), %esp  # Allocate the rest of the trap frame.
     movl    %ebx, TRAP_EIP(%esp)    # EBX contains the return address.
     movl    %esp, %ebx              # Save the trap frame in EBX.
+    movl    %ecx, TRAP_ECX(%esp)    # Save system call number for restarts.
+    movl    %edx, TRAP_EDX(%esp)    # Save system call parameter for restarts.
 
     //
     // There's a trap frame at ebx, which is nice since it won't require
@@ -660,6 +657,8 @@ FUNCTION(ArSysenterHandlerAsm)
     CFI_DEF_CFA(%ebx, 0)
     CFI_OFFSET(%eip, TRAP_EIP)
     CFI_OFFSET(%esp, TRAP_ESP)
+    CFI_OFFSET(%ecx, TRAP_ECX)
+    CFI_OFFSET(%edx, TRAP_EDX)
 
     //
     // Move user DS (rather than user CS) into the trap frame to indicate
@@ -668,16 +667,6 @@ FUNCTION(ArSysenterHandlerAsm)
 
     movl    $USER_DS, TRAP_CS(%ebx) # Indicate a user mode trap frame.
 
-    //
-    // Dispatching the signal takes the system call number, system call
-    // parameter and trap frame as arguments. This means that the system call
-    // number and parameter need to be saved across the call to
-    // KeSystemCallHandler.
-    //
-
-    pushl   %edx                    # Push system call parameter for dispatch.
-    pushl   %ecx                    # Push system call number for dispatch.
-
     //
     // Push the parameters for the system call handler and execute it.
     //
@@ -697,11 +686,21 @@ FUNCTION(ArSysenterHandlerAsm)
 
     movl    %fs:(PROCESSOR_BLOCK_RUNNING_THREAD), %ecx # Get current thread.
     cmpl    $ThreadSignalPending, THREAD_SIGNAL_PENDING(%ecx) # Signal test.
-    jnz     ArSysenterHandlerFastRestore # Exit via the fast restore path.
+    jnz     ArSysenterHandlerRestore # Skip the expensive signal stuff.
+
+    //
+    // See if the trap frame is already complete, as a result perhaps of the
+    // system call itself. If so, skip the full save part, as it might undo
+    // useful work (like restoring pre-signal context).
+    //
+
+    cmpl    $USER32_CS, TRAP_CS(%ebx)   # See if the trap frame is complete.
+    je      ArSysenterSignalDispatch    # Skip the save if complete already.
 
     //
-    // Save the default user mode segment selectors. Update user CS as the trap
-    // frame is about to become full.
+    // Upgrade the trap frame to a complete one. Update user CS to indicate the
+    // trap frame is complete. This will also mean the expensive iret exit path
+    // is used.
     //
 
     movl    $USER32_CS, TRAP_CS(%ebx)  # Save CS.
@@ -717,76 +716,45 @@ FUNCTION(ArSysenterHandlerAsm)
 
     movl    %eax, TRAP_EAX(%ebx) # Save the return value in the trap frame.
     movl    $0x0, TRAP_EBX(%ebx) # Zero EBX. It holds the kernel trap pointer.
-    movl    $0x0, TRAP_ECX(%ebx) # Zero ECX. It is volatile.
-    movl    $0x0, TRAP_EDX(%ebx) # Zero EDX. It is volatile.
     movl    %esi, TRAP_ESI(%ebx) # Save ESI. It is non-volatile.
     movl    %edi, TRAP_EDI(%ebx) # Save EDI. It is non-volatile.
     movl    %ebp, TRAP_EBP(%ebx) # Save EBP. It is non-volatile.
     movl    $0x0, TRAP_ERRORCODE(%ebx) # Scrub the error code.
     movl    $0x0, TRAP_EFLAGS(%ebx) # Scrub the EFLAGS.
 
-    //
-    // Push the trap frame as the first parameter. The system call number and
-    // system call paramter were saved on the stack earlier for this call.
-    //
-
-    pushl   %ebx                    # Pass the trap frame.
-    call    PsDispatchPendingSignalsOnCurrentThread # Dispatch signals.
-    addl    $0xC, %esp              # Pop all three parameters.
-
-    //
-    // Restore the non-volatile registers in case they were modified by the
-    // trap frame.
-    //
-
-    movl    TRAP_ESI(%esp), %esi
-    movl    TRAP_EDI(%esp), %edi
-    movl    TRAP_EBP(%esp), %ebp
+ArSysenterSignalDispatch:
 
     //
-    // Restore EAX in case the return value was modified. The other volatiles
-    // (ECX and EDX) are used specifically by sysexit to restore the stack and
-    // instruction pointer.
+    // Push the trap frame as the first parameter, either apply signals now
+    // that a full trap frame is available, or potentially restart the system
+    // call if no signals were applied (maybe a process-wide signal got
+    // serviced by another thread).
     //
 
-    movl    TRAP_EAX(%esp), %eax
-
-    //
-    // Restore the segment registers. SS and CS are restored by sysexit. Once
-    // DS is restored then only memory accesses through ESP are allowed.
-    //
+    pushl   %ebx                    # Pass the trap frame.
+    call    PsApplyPendingSignalsOrRestart  # Dispatch signals or restart.
+    addl    $0x4, %esp              # Pop the parameter.
 
-    movl    TRAP_DS(%esp), %ecx  # Restore DS.
-    movw    %cx, %ds             #
-    movl    TRAP_ES(%esp), %ecx  # Restore ES.
-    movw    %cx, %es             #
-    movl    TRAP_FS(%esp), %ecx  # Restore FS.
-    movw    %cx, %fs             #
-    movl    TRAP_GS(%esp), %ecx  # Restore GS.
-    movw    %cx, %gs             #
+ArSysenterHandlerRestore:
 
     //
-    // Upon sysenter ebx held the return address, making it effectively
-    // volatile.
+    // See if the trap frame is complete. If it is, then go do the slower
+    // complete restore.
     //
 
-    xorl    %ebx, %ebx
-    jmp     ArSysenterHandlerExit
+    cmpl    $USER32_CS, TRAP_CS(%ebx)   # See if the trap frame is complete.
+    je      ArSystemCallHandlerExit     # Do a full restore if so.
 
     //
     // Reset the segment registers to user mode and return.
     //
 
-ArSysenterHandlerFastRestore:
     mov     $USER_DS, %cx           # Get the user mode DS.
     mov     %cx, %ds                # Move to DS.
     mov     %cx, %es                # Move to ES.
     mov     $GDT_THREAD, %cx        # Get the user-mode GS.
     mov     %cx, %fs                # Move to FS.
     mov     %cx, %gs                # Move to GS.
-    addl    $0x8, %esp              # Pop the system call number and parameter.
-
-ArSysenterHandlerExit:
     CFI_DEF_CFA(%esp, 0)            # The trap frame is at ESP, EBX is gone.
 
     //