        PAGE    ,132
TITLE   SYSSERV - DOSSYSTEMSERVICE functions
NAME    SYSSERV

SCCSID  equ     "@(#)sysserv.asm        6.4 92/03/15"

;*      IBM/Microsoft Confidential
;*
;*      Copyright (c) IBM Corporation 1987, 1989
;*      Copyright (c) Microsoft Corporation 1987, 1989
;*
;*      All Rights Reserved
;*
;*  Title:
;*      SYSSERV
;*
;*
;*  Author:
;*      Pete Stewart
;*
;*
;*  Description:
;*
;*      SYSSERV contains the worker for the DOSSYSTEMSERVICE function,
;*      as well as other functions associated with System Services.
;*
;*
;*  Modification History:
;*
;*     11 Jun 1986 - BWS
;*              Allow multiple threads from same process to enter a given
;*              category; always do ProcRun.
;*
;*     05 Dec 1986  - JPH
;*              change SysServWaitQ to treat mouse + keyboard hot keys
;*              as a special case where data item in queue is decompressed
;*              into two data items
;*
;*     05 Dec 1986  - MM
;*              add new subfunction 4 - get 3xbox pid - to Session Manager
;*              Services
;*
;*     04 Mar 1987  - IDB
;*              Changed SySServWait/Q to block interruptably so that
;*              DOSSYSTEMSERVICE can be interrupted by signal
;*
;*     30 Oct 1987   - IS
;*              Implemented DCR 64 DOSSYSTEMSERVICE changes: add function
;*              4 to Category 0, which would allow the adoption of a
;*              child.
;*
;*     20 Nov 1987   - JSF
;*              Changed SysServSM adoption process to call AdoptTask to
;*              handle relinking with new PTDA links.
;*
;*     24 Feb 1989   - JH
;*              Changed call to AdoptTask to _TKAdoptTask
;*
;*     23-Mar-1989   - DAN
;*              Disabled subfunction 4 - get 3xbox pid - in Session Manager
;*              Services
;*
;*     09 Jan 1990 - LMT
;*              Added Category 3 for VideoPause sevices.  See 1.2 DCR 607
;*
;*     12 Aug 1993 - G.L.Fulk                                           ;72098;
;*              Add jump-carry if WaitQ calls fail.                     ;72098;
;*                                                                      ;72098;
;*     18-Nov-95   - MLM
;*              Defect 72417, moved find.inc after tkexport.inc
;*
;*     05-May-96   - Frank J. Schroeder
;*              Added test for POWEROFF_EVENT to SysServWaitQ routine. 153441 

INCL_ERROR_H    EQU     1       ; for bseerr.inc
INCL_ERROR2_H   EQU     1       ; for bseerr.inc
.xlist
include fnotask.inc
include dosseg.inc
include basemaca.inc
include osconst.inc
include osmaca.inc
include bseerr.inc
include harderr.inc
include dossymc.inc
include except.inc
include sigdef.inc
include curdir.inc
include dirent.inc
include screen.inc
include sem.inc
include infoseg.inc
include mi.inc
include pmode.inc
include kmode.inc
include sysserv.inc
include sched.inc
include tkexport.inc
include find.inc
include pgexport.inc
include vmexport.inc
include selxport.inc
include tkptda.inc
include demsmg.inc                                                      ;26159;
.list

        CpuMode 386
        ModName sysserv,FNO_SYSSERV_ASM

        ReferFlat       _pPTDACur,DWORD
        ReferFlat       _smHardErrPID,WORD              ; b777777

        EXTRN           VectorReboot:DWORD
        EXTRN           ProcRun:NEAR

        EXTRNFAR        FuBuff
        EXTRNFAR        FuWord
        EXTRNFAR        HEAction
        EXTRNFAR        ProcBlock
        EXTRNFAR        SuBuff
        EXTRNFAR        SuWord

        EXTRN32         _SELVirtToLin
;        EXTRN32         _SCHSetState
        EXTRN32         _TKUpdateState
        EXTRN32         _TKAdoptTask
        EXTRN32         _VMLinToPhys
        EXTRN32         _VMGetOwner
        EXTRNF32        PhysToUVirt
        EXTRN32         _TKScanTasks

CONSTANTS       SEGMENT
                EVEN

;       Response packet queues:
;
;       Session Manager Services

; Moved to sdata.asm for System Anchor Block - f122427
        extrn   SMHotKeyQ:word 
        extrn   CtrlNumLkQ:word
        extrn   SMDosSessionQ:word
        extrn   HardErrPkt:word
        extrn   CtrlPrtScQ:word
        extrn   VideoPauseFlag:byte

                EVEN

SysServData struc
        SysServId       dw      0               ; Daemon i.d.
        SysServFunc     dw      ?               ; Processing function
SysServData ends

SysServScale    equ     2
        .errnz  ((1 SHL SysServScale) - (SIZE SysServData))

SysServInfo label SysServData

         .errnz (SysServ_SM - (($ - SysServInfo) / (SIZE SysServData)))
         SysServData <,DOSHIGH3CODE:SysServSM>

         .errnz (SysServ_HardErr - (($ - SysServInfo) / (SIZE SysServData)))
         SysServData <,DOSHIGH3CODE:SysServHE>

         .errnz (SysServ_PrtSc - (($ - SysServInfo) / (SIZE SysServData)))
         SysServData <,DOSHIGH3CODE:SysServPS>

         .errnz (SysServ_VidPse - (($ - SysServInfo) / (SIZE SysServData)))
         SysServData <,DOSHIGH3CODE:SysServVP>

         .errnz (SysServ_VDMSta - (($ - SysServInfo) / (SIZE SysServData)));26159;
         SysServData <,DOSHIGH3CODE:SysServVDM>                         ;26159;
                                                                        ;26159;
SysServMax equ  (($ - SysServInfo) / (SIZE SysServData))

HotKeyQClient   dw      0               ; Non-zero if someone is waiting
                                        ; or has waited on HotKeyQ

CONSTANTS       ENDS

DATA segment                    ;
; Moved to sdata.asm for System Anchor Block - f122427
        extrn VPUserSelector:word 
        extrn VPUserOffset:word 
DATA ends                       ;

        FARCODE HIGH3
HIGH3CODE       SEGMENT


;***    w_SystemService - System Service dispatcher
;
;       This function passes control to the appropriate handler
;       and then blocks the thread until the specified event for
;       which to wait occurs.
;
;       ENTRY   (DI) = Category
;                       0 - Session Manager Services
;                       1 - Hard Error Daemon Services
;                       2 - Print Screen Services
;                       3 - Video Pause
;                       4 - Session Manager VDM Start Session Services  ;26159;
;               (BX:SI) = Address of ActionPacket
;               (DX:AX) = Address of ResponsePacket
;
;       EXIT    Carry
;                   Clear if no error
;                       AX = 0
;                   Set
;                       Error code in AX
;
;       USES    AX, BX, CX, DX, DI, SI, DS, ES, Flags

Procedure w_SystemService,faronly
        ASSUME  DS:NOTHING, ES:NOTHING, SS:TASKAREA

;       Validate ServiceCategory

        cmp     di,SysServMax           ; Valid ServiceCategory?
        jae     w_DS2                   ;  no, return an error

;       Check for existing server

        DosContext ds                   ; Make DS:BX point to array member
        shl     di,SysServScale
        add     di,offset DOSGROUP:SysServInfo
        mov     cx,ss:[TKOPTDA.ptda_Pid]; Get process i.d.
        cmp     [di].SysServId,0        ; Does a server exist?
        jnz     w_DS0                   ;  yes, skip to test
        mov     [di].SysServId,cx       ; We have a new server
        ;
        ;  Need HardErr Pid number for swapper
        ;
; b7777777 start
        sub     di,offset DOSGROUP:SysServInfo
        shr     di,SysServScale
        cmp     di, 1
        jne     w_DS00
        FlatContext ds
        mov     [_smHardErrPID], cx    ; save Harderr.exe pid nmmber
        DosContext ds
w_DS00:
        shl     di,SysServScale
        add     di,offset DOSGROUP:SysServInfo
; b7777777 end
        jmp     short w_DS1
w_DS0:  cmp     cx,[di].SysServId       ; Is this guy the official server?
        stc                             ;  (assume no)
        jne     w_DS2                   ;  no, return error

;*  Dispatch based upon ServiceCategory

w_DS1:  call    [di].SysServFunc        ; Invoke handler
        jnc     w_DS3

;       Return error code.  If not interrupted system call, return
;       generic "user error" reply.

w_DS2:  cmp     ax,ERROR_INTERRUPT
        stc
        jz      w_DS3
        mov     ax,ERROR_INVALID_FUNCTION ; Assume error in params
w_DS3:  ret

EndProc w_SystemService

;***    SysServVDM - Session Manager Dos Session services               ;26159;
;                                                                       ;26159;
;       This function processes Session Manager Dos Session services.   ;26159;
;                                                                       ;26159;
;       ENTRY   (BX:SI) = RequestPacket address  UNDEFINED              ;26159;
;               (DX:AX) = ResponsePacket address                        ;26159;
;                                                                       ;26159;
;       EXIT    Carry set                                               ;26159;
;                   Error                                               ;26159;
;               Carry clear                                             ;26159;
;                   No error                                            ;26159;
;                                                                       ;26159;
;       USES    AX, BX, CX, DX, DI, SI, DS, ES, Flags                   ;26159;
                                                                        ;26159;
Procedure SysServVDM,near                                               ;26159;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:TASKAREA                     ;26159;
                                                                        ;26159;
;LocalVar ssvdm_req,DWORD        ; Request packet address = (BX:SI)     ;26159;
;LocalVar ssvdm_resp,DWORD       ; Response packet address = (DX:AX)    ;26159;
;LocalVar ssvdm_temp,DWORD                                              ;26159;
;                                                                       ;26159;
;        EnterProc  <bx,si,dx,ax,dx,ax>  ; Set frame, initialize locals ;26159;
                                                                        ;26159;
        push    bp                                                      ;26159;
        mov     bp,sp                                                   ;26159;
        push    bx   ;\                                                 ;26159;
        push    si   ;/  bp-4                                           ;26159;
        push    dx   ;\                                                 ;26159;
        push    ax   ;/  bp-8                                           ;26159;
        push    dx   ;\                                                 ;26159;
        push    ax   ;/  bp-0Ch                                         ;26159;
                                                                        ;26159;
                                                                        ;26159;
        DosContext ds                   ; (DS:BX) = queue to wait on    ;26159;
        mov     bx,offset DOSGROUP:SMDosSessionQ ; DosSession Queue     ;26159;
                                                                        ;26159;
; (DX:AX) = response packet address                                     ;26159;
; (DS:BX) = queue to wait on                                            ;26159;
                                                                        ;26159;
        push    ss                                                      ;26159;
        pop     dx                                                      ;26159;
        lea     ax,[bp-0Ch]                                             ;26159;
        call    SysServWaitQ            ; Wait for VDM start session    ;26159;
        jc      glf6                                                    ;72098;
                                                                        ;26159;
        DosContext ds                   ; (DS:BX) = queue to wait on    ;26159;
        mov     bx,offset DOSGROUP:SMDosSessionQ ; DosSession Queue     ;26159;
        push    ss                                                      ;26159;
        pop     dx                                                      ;26159;
        lea     ax,[bp-0Ch+2]                                           ;26159;
        mov     bx,offset DOSGROUP:SMDosSessionQ ; DosSession Queue     ;26159;
        call    SysServWaitQ            ; get the 2nd 16-bit value      ;26159;
        jc      glf6                                                    ;72098;
                                                                        ;26159;
;At this point we have read both of the 16-bit messages sent by DEM.    ;26159;
;Load DS:ESI with a pointer to the DEM data and ES:EDI with a pointer   ;26159;
;to Session Manager's data area (to be filled in).                      ;26159;
                                                                        ;26159;
;Session manager sends us a base address (moved into EDX below).  It is ;26159;
;used to fixup the pointers within the StartData so that they point to  ;26159;
;Session manager's area.                                                ;26159;
                                                                        ;26159;
        FlatContext ds                                                  ;26159;
        mov     esi,[bp-0Ch]            ;ds:esi=32bit DEM.C address     ;26159;
        LES     di,[bp-8]                                               ;26159;
        movzx   edi,di                                                  ;26159;
        mov     edx,es:[edi]            ;edx=base address of SMG data   ;26159;
        add     edi,4                   ;es:edi=16:16 tiled SMG address ;26159;
        push    edi                                                     ;26159;
        mov     ecx,SIZE DEMSTARTDATA                                   ;26159;
        cld                                                             ;26159;
glf1:                                   ;This loop copies all the data. ;26159;
        mov     al,[esi]                                                ;26159;
        inc     esi                                                     ;26159;
        stosb                                                           ;26159;
        loop    glf1                                                    ;26159;
                                                                        ;26159;
        push    es                                                      ;26159;
        pop     ds                                                      ;26159;
        pop     edi                                                     ;26159;
        mov     ecx,3                                                   ;26159;
        add     edi,demSS_PgmTitle                                      ;26159;
.errnz  demSS_PgmName - demSS_PgmTitle - 4                              ;26159;
.errnz  demSS_PgmInputs - demSS_PgmName - 4                             ;26159;
glf2:                                   ;This loop performs fix-ups.    ;26159;
        mov     eax,[edi]                                               ;26159;
        or      eax,eax                                                 ;26159;
        jz      glf3                                                    ;26159;
        add     eax,edx                                                 ;26159;
glf3:                                                                   ;26159;
        mov     [edi],eax                                               ;26159;
        add     edi,4                                                   ;26159;
        loop    glf2                                                    ;26159;
                                                                        ;65622;
        add     edi, demSS_Environment - demSS_PgmInputs - 4            ;65622;
        mov     eax,[edi]                                               ;65622;
        or      eax,eax                                                 ;65622;
        jz      glf5                                                    ;65622;
        add     eax,edx                                                 ;65622;
glf5:                                                                   ;65622;
        mov     [edi],eax                                               ;65622;
        add     edi,4                                                   ;65622;
                                                                        ;26159;
        add     edi, demSS_IconFile - demSS_Environment - 4             ;65622;
        mov     eax,[edi]                                               ;26159;
        or      eax,eax                                                 ;26159;
        jz      glf4                                                    ;26159;
        add     eax,edx                                                 ;26159;
glf4:                                                                   ;26159;
        mov     [edi],eax                                               ;26159;
                                                                        ;26159;
        clc                             ;success: NC, eax=0             ;72098;
glf6:   mov     eax,0                   ;failure: CY, eax=-1            ;72098;
        sbb     eax,0                                                   ;72098;
                                                                        ;26159;
        leave                                                           ;26159;
        ret                                                             ;26159;
                                                                        ;26159;
EndProc SysServVDM                                                      ;26159;

;***    SysServSM - Session Manager services
;
;       This function processes Session Manager services.
;
;       ENTRY   (BX:SI) = RequestPacket address
;                               First word of packet = subfunction number:
;                                       0 - Wait for hot key event
;                                       1 - Perform freeze/thaw action
;                                       2 - Wait for Ctrl-NumLock (pause) event
;                                       3 - Get 3xBox pid
;                                       4 - Adopt child process
;                                       5 - Reboot machine
;               (DX:AX) = ResponsePacket address
;
;       EXIT    Carry set
;                   Error
;               Carry clear
;                   No error
;
;       USES    AX, BX, CX, DX, DI, SI, DS, ES, Flags

Procedure SysServSM,near
        ASSUME  DS:NOTHING, ES:NOTHING, SS:TASKAREA

        LocalVar sssm_req,DWORD         ; Request packet address = (BX:SI)
        LocalVar sssm_resp,DWORD        ; Response packet address = (DX:AX)

        EnterProc <bx,si,dx,ax>         ; Set frame, initialize locals

;       Session Manager Hot Key event?

        .errnz  srvhk_type
        .errnz  srvft_type
        .errnz  srvp_type
        .errnz  srva_type
        CALLFAR FuWord                  ; (AX) = subfunction code
        jc      sssm6                   ;  branch on GP fault
        mov     bx,offset DOSGROUP:SMHotKeyQ ; Assume hotkey event
        or      ax,ax                   ; Hotkey event (subfunction 0)?
        jz      sssm2                   ;  yes, branch

;       Freeze/Thaw request?

        dec     ax                      ; Subfunction 1?
        jnz     sssm1                   ;  no, keep looking
        mov     bx,sssm_reqh            ; (BX:SI) = freeze/thaw code pointer
        .errnz  (srvft_func - 2)
        CALLFAR FuWord                  ; (AX) = freeze/thaw subfunction code
        jc      sssm6                   ;  branch on GP fault
        mov     bx,sssm_reqh            ; (BX:SI) = sg/pid pointer
        push    ax
        .errnz  (srvft_pidsg - 4)
        CALLFAR FuWord                  ; (AX) = Screen group or Pid
        pop     bx                      ; (BX) = freeze/thaw subfunction code
        jc      sssm6                   ;  branch on GP fault
        mov     cx,ax                   ; (CX) = PID/Screen group
        call    Sys_FreezeThaw          ; Freeze/thaw process/screen group
        jmp     short sssm6

;       Pause event?

sssm1:  dec     ax                      ; Subfunction 2?
        jnz     sssm3                   ; no, keep looking
        mov     bx,offset DOSGROUP:CtrlNumLkQ ; Ctrl-NumLk event
sssm2:  mov     ax,sssm_respl           ; (DX:AX) = response packet address
        DosContext ds                   ; (DS:BX) = queue to wait on
        call    SysServWaitQ            ; Wait for hot key event
        jmp     short sssm6
    ASSUME      DS:NOTHING

;       Get 3xBox Pid

sssm3:  dec     ax                      ; Subfunction 3? (Get 3xBox Pid)
        jnz     sssm4                   ;  no, keep looking
        stc                             ; BUGBUG danno 23-Mar-1989
        jmp     sssm6                   ; no longer supported

;       adopt a child

sssm4:  dec     ax                      ; Subfunction 4?
        jnz     sssm5                   ;  no, keep looking

;       Adopt child process. The child process being adopted is unlinked
;        from its current PTDA chain and linked into the adopter's
;        PTDA chain.

        mov     bx,sssm_reqh            ; (BX:SI) -> PID of proc being adopted
        .errnz  (srva_pid - 2)
        CALLFAR FuWord                  ; (AX) = PID of proc being adopted
        jc      sssm6                   ;  branch on GP fault

;       Adopt child process. Routine returns cy set if error, and
;        ERROR_INVALID_PROCID in AX

        FlatContext <ds,es>,dx
        movzx   eax,ax
        CCALL32 _TKAdoptTask, <eax>     ; Adopt child process, ret
        cmp     eax,1
        cmc
        jmp     sssm6

;       reboot machine

sssm5:  dec     ax                      ; Subfunction 5?
        stc                             ;  (assume invalid function)
        jnz     sssm6                   ; if not, return error

Entry SysServReboot,far16,,nocheck      ; USED ONLY FROM CADHandler
Entry SysServReboot,faronly,,nocheck
        DosContext      ds,ax
        call    DWORD PTR VectorReboot  ; doesn't return
        InternalError <SysServSM: reboot returned>

;       Clean up and exit

sssm6:  LeaveProc
        ret

EndProc SysServSM


;***    SysServHE - hard error system service
;
;       This function processes hard error events.
;
;       ENTRY   (BX:SI) = RequestPacket address
;               (DX:AX) = ResponsePacket address
;
;       EXIT    Carry clear
;                   Response packet filled in
;               Carry set
;                   Invalid response packet
;
;       USES    AX, BX, CX, DX, DI, SI, DS, ES, Flags

Procedure SysServHE,near
        ASSUME  DS:DOSGROUP, ES:NOTHING, SS:TASKAREA

        LocalVar she_resp,DWORD         ; Response packet pointer

        EnterProc <dx,ax>               ; she_resp = (DX:AX)
        CALLFAR HEAction                ; Process the RequestPacket
    ASSUME      DS:NOTHING
        mov     bx,she_resph            ; (BX:SI) = user response packet
        mov     si,she_respl
        add     si,HE_cbBuf             ; (BX:SI) = address of buffer size word
        CALLFAR FuWord                  ; AX = buffer size
        jc      she0                    ;  GP fault if carry set
        DosContext ds                   ; (DS:BX) = DOS response packet
        mov     bx,offset DOSGROUP:HardErrPkt
        lea     si,[bx].ssrp_pkt        ; (DS:SI) = packet after header
        mov     [si].HE_cbBuf,ax        ; Set buffer size in DOS packet
        mov     dx,she_resph            ; (DX:AX) = user response packet
        mov     ax,she_respl
        call    SysServWait             ; Wait for next hard error
she0:   LeaveProc
        ret

EndProc SysServHE


;***    SysServPS - PrtSc services
;
;       This function waits for PrtSc keyboard events.
;
;       ENTRY   (DS:DI) = SysServInfo array member
;               (DX:AX) = ResponsePacket address
;
;       EXIT    Carry clear
;                   Response packet filled in
;               Carry set
;                   Invalid response packet
;
;       USES    AX, BX, CX, DX, DI, SI, DS, ES, Flags

Procedure SysServPS,near
        ASSUME  DS:DOSGROUP, ES:NOTHING, SS:TASKAREA

        mov     bx,offset DOSGROUP:CtrlPrtScQ ; (DS:BX) = queue pointer
        call    SysServWaitQ            ; Wait for next PrtSc event
        ret

EndProc SysServPS


;***    SysServWait - wait for daemon event
;
;       This function blocks daemons until the specified event, or
;       abnormal wakeup to handle a signal, occurs.
;
;       ENTRY   (DX:AX) = Address of ResponsePacket
;               (DS:BX) = Pointer to DOS response packet (DS = DOSGROUP)
;
;       EXIT    Carry clear
;                   ResponsePacket filled in
;               Carry set
;                   Invalid response packet in user space, or
;                   Abnormal wakeup (ERROR_INTERRUPT)
;
;       USES    AX, BX, CX, DX, DI, SI, DS, ES, Flags

Procedure SysServWait,near,local
        ASSUME  DS:DOSGROUP, ES:NOTHING, SS:TASKAREA

        push    dx                      ; Save ResponsePacket pointer
        push    ax

;       Wait for next event

sd0:    cli                             ; Critical section
        test    [bx].ssrp_sem,1         ; Is the semaphore set?
        jz      sd1                     ;  exit loop if semaphore available
        mov     ax,ds                   ; Use struc address as event i.d.
        mov     cx,-1                   ; Never time out
        mov     di,cx
        mov     dh,0                    ; Interruptible
        CALLFAR ProcBlock               ; Wait for something to happen
        jnc     sd0                     ; Loop if normal awakening, else
        pop     ax                      ;  clear response packet address
        pop     ax                      ;  off the stack
        mov     ax,ERROR_INTERRUPT      ; Return abnormal awakening
        jmp     sd2

;       The semaphore is available.  This indicates that
;       an event has occurred.  Copy the DOS response packet
;       to the user response packet (if any).

sd1:    or      [bx].ssrp_sem,1         ; Set the semaphore
        sti                             ; is safe as harderror packet is not
                                        ; changed at interrupt time
        lea     si,[bx].ssrp_pkt        ; (DS:SI) = packet in DOS
        mov     cx,[bx].ssrp_len        ; CX = packet length
        pop     di                      ; BX:DI = ResponsePacket address
        pop     bx
        cld                             ; To be safe
        CALLFAR SuBuff                  ; Copy to user space
                                        ;  carry set if copy faults

sd2:    sti                             ; Now enable interrupts
        ret

EndProc SysServWait


;***    SysServWaitQ - wait for queued event
;
;       This function blocks daemons until the specified event queue
;       is non-empty.
;
;       ENTRY   (DX:AX) = Address of ResponsePacket
;               (DS:BX) = Pointer to event queue (DS = DOSGROUP)
;
;       EXIT    Carry clear
;                   ResponsePacket filled in
;               Carry set
;                   Invalid ResponsePacket
;
;       USES    AX, BX, CX, DX, DI, SI, DS, ES, Flags
;       Note:    ResponsePacket may be 1 or 2 words long

Procedure SysServWaitQ,near,local
        ASSUME  DS:DOSGROUP, ES:NOTHING, SS:TASKAREA

        cmp     bx,OFFSET DOSGROUP:SMHotKeyQ    ; Waiting for HotKey Q
        jne     sswq0a
        mov     HotKeyQClient,sp        ; Mark client non-zero

sswq0a: push    dx                      ; Save ResponsePacket pointer
        push    ax

;       Check queue

sswq0:  cli                             ; Critical section
        mov     ax,[bx].ssq_front       ; Is queue empty?
        cmp     ax,[bx].ssq_rear
        jne     sswq1                   ;  no, exit loop
        mov     ax,ds                   ; Use struc address as event i.d.
        mov     cx,-1                   ; Never time out
        mov     di,cx
        mov     dh,0                    ; Interruptable wait
        CALLFAR ProcBlock               ; Wait for something to happen
        jnc     sswq0                   ; loop if normal awakening

;       Abnormal awakening by signal.  Return interrupted system call
;       response

        pop     ax                      ; Clear response packet
        pop     ax                      ; off the stack
        mov     ax,ERROR_INTERRUPT      ; Interrupted system call
        jmp     short sswq4

;       The queue is not empty.  This indicates that
;       an event has occurred.  Copy the event at the front of the
;       queue to the user response packet.  We leave interrupts
;       off until the packet has been copied to prevent an interrupt
;       from invalidating its contents.

sswq1:  cld                             ; To be safe
        mov     si,ax                   ; (DS:SI) = pointer to queued packet
        add     ax,qelsize              ; Increment front pointer by el size
        cmp     ax,[bx].ssq_qlimit      ; Past end of queue?
        jb      sswq2                   ;  no, skip ahead
        lea     ax,[bx+(size SysServQueue)] ; Put address of queue in ax
sswq2:  mov     [bx].ssq_front,ax       ; Update front pointer
        mov     cx,bx                   ; save queue address for identity
        lodsw                           ; Get word from queue
        sti                             ; Now enable interrupts
        pop     di                      ; Put ResponsePacket address in BX:DI
        pop     bx

;       If and only if queue is SMHotKeyQ, we have two word response
;       packet to fill, unless argument is CTL-ALT-DEL, in which case we
;       have only the hot key device packet to set up.

        cmp     cx,offset DOSGROUP:SMHotKeyQ ; Session Manager Hot Key queue?
        jnz     sswq3                   ;  no, skip ahead
        cmp     ax,CAD_EVENT+KEY_EVENT  ; CTL-ALT-DEL typed?
        jne     sswq2a                  ;  no, skip
        mov     ax,HOT_KEY_CAD          ;  yes, put correct code in response
        jmp     short sswq3             ;  packet and exit

sswq2a: cmp     ax, POWER_EVENT         ; If power event, go send
        je      sswq3

        cmp     ax, POWEROFF_EVENT      ; If power off event, go send ;d153441
        je      sswq3                   ; d153441


        mov     dx,ax                   ; get data in dx also
        and     ax,1                    ; isolate last bit
        jz      sswqmo                  ; go if mouse - dx ok to send now
        shr     dx,1                    ; for kbd - shift hot key id back
sswqmo:                                 ; start decompression for keybd
        CALLFAR SuWord                  ; Copy to user space
        jc      sswq3                   ;  carry set if copy faults
        mov     ax,dx                   ; next word to send is in dx
sswq3:  CALLFAR SuWord                  ; Copy to user space
sswq4:  ret

EndProc SysServWaitQ

;***    SysServVP - Video Pause system service
;
;       This function is used with others to perform Video Pause.
;
;       ENTRY   (BX:SI) = RequestPacket address
;               (DX:AX) = ResponsePacket address
;
;       EXIT    Carry clear
;                   Response packet filled in
;               Carry set
;                   Invalid response packet
;
;       USES    AX, BX, CX, DX, DI, DI, DS, ES, FLAGS
;
Procedure SysServVP,near                ;
        ASSUME  DS:DOSGROUP, ES:NOTHING, SS:TASKAREA
        LocalVar sVP_resp,DWORD         ; Response packet pointer
        LocalVar sVP_paddr,DWORD        ; physical address
                                        ;
        EnterProc   <dx,ax>             ; sVP_resp = (DX:AX)
        DosContext es           ;
        cmp     es:VPUserSelector,0     ; see if generated user selector
        jnz     VPchkFlag               ;

        FlatContext <ds,es>,ax
        CCALL32 _SELVirtToLin, <offset DOSGROUP:VideoPauseFlag, DOSGROUP>
        cmp     eax,-1
        je      VPerror
        SSToDS  ecx, sVP_paddr
        CCALL32 _VMLinToPhys <eax, ecx>
        or      eax,eax
        jnz     VPerror

        mov     edi,[_pTCBCur]
        mov     edi,[edi].TCB_pFrameBase
        movzx   eax,[edi].ssf_cs
        CCALL32 _VMGetOwner <eax, [edi].ssf_eip>

;       PhysToUVirt (physaddr, 1 byte, read/write, owner)
        mov     ebx,1
        CALLF32 PhysToUVirt, <[sVP_paddr], ebx, ebx, eax>  ; ES:BX = valid virtual address

        DosContext      ds
        jc      VPerror                 ; error in call
        mov     ax,es                   ; save it
        DosContext es           ;
        mov     es:VPUserOffset,BX      ; save offset
        mov     es:VPUserSelector,AX    ; save selector
VPchkFlag:                              ;
        cli                             ; Crit sec
        cmp     VideoPauseFlag,0        ; look at flag
        jnz     VPawake                 ; Daemon active
                                        ; Sleep until activated by DevHelp
        mov     ax,ds                   ; event id flag address
        mov     bx,offset DOSGROUP:VideoPauseFlag   ;
        mov     cx,-1                   ; Never time out
        mov     di,cx                   ;
        mov     dh,1                    ; Noninterruptable wait
        CALLFAR ProcBlock               ; Wait for DevHelp
        jmp short VPchkFlag             ; Make sure not "accidently" woken up
VPawake:                                ;
        sti                             ;
        DosContext es           ;
        ASSUME  DS:NOTHING              ;
        mov     bx,sVP_resph            ; (BX:DI) = user response packet
        mov     di,sVP_respl            ;
        mov     ax,es:VPUserOffset      ; put offset in packet
        CALLFAR SuWord                  ;
        jc      short VPerror           ; error in call
        DosContext es           ;
        mov     ax,es:VPUserSelector    ; save selector
        CALLFAR SuWord                  ;
        jc      short VPerror           ; error in call
VPdone:                                 ;
        LeaveProc                       ;
        ret                             ;
VPerror:                                ;
        mov ax,ERROR_INVALID_FUNCTION   ; error code carry should be set
        jmp     VPdone
EndProc SysServVP                       ;


;***LP  Sys_FreezeThaw - Freeze/Thaw process or screen group
;
;
;       ENTRY   (BX) = action to perform:
;                       0 freeze PID in CX
;                       1 thaw PID in CX
;                       2 freeze SG in CX
;                       3 thaw SG in CX
;
;               (CX) = PID or screen group
;
;       USES    ALL except BP
;
;       EFFECTS SWITCHES CONTEXT
;
    ASSUME      DS:NOTHING,ES:NOTHING,SS:TASKAREA

Procedure Sys_FreezeThaw,near
LocalVar  ftAction,WORD                 ; Caller's BX

        EnterProc
        mov     ftAction,bx             ; Save action for TKScanTasks worker

        cmp     bx,TK_TG_ALL            ; valid function?
        jae     short sfte              ; not valid, return immediately

        or      bl,1                    ; Convert to TKScanTasks function
        .erre   (TK_TG_ONE AND 1)
        .erre   (TK_TG_SCRN AND 1)
        xor     bh,bh
        movzx   ebx,bx                  ; ScanFlags
        movzx   ecx,cx                  ; Group Id
        movzx   eax,ftAction
        FlatContext <ds,es>,dx
        CCALL32 _TKScanTasks,<ebx, ecx, <offset FLAT:_tkSysFrzThwWrkr>, eax>
        or      eax,eax
        .errnz  NO_ERROR
        jz      short sftx
sfte:   mov     ax,ERROR_INVALID_DATA
        stc
sftx:   LeaveProc
        ret
EndProc Sys_FreezeThaw


HIGH3CODE       ENDS

        FARCODE HIGH32
_TEXT   SEGMENT

;***    _SysServTerm - Check if a System Service process is terminating
;
;       This function scans the list of System Service processes
;       looking for a match for the currently exiting thread.  If
;       a match is found, the matching entry in the System Service
;       list is cleared.
;
;       void _SysServTerm ();
;
;       ENTRY   C Calling Convention; no parameters.
;
;       EXIT    NONE
;
;       USES    EAX, ECX, EDX, Flags

Procedure _SysServTerm,near
        ASSUME  DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:TASKAREA
        movzx   eax,ss:[TKOPTDA.ptda_Pid]; Get current process's i.d.

        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING

        mov     edx,offset FLAT:SysServInfo     ; (EDX) = pSysServData
        mov     ecx,SysServMax          ; Size of pSysServData
        .errnz  (SysServMax EQ 0)       ; ECX can't be zero.

dt0:    cmp     ax,[edx].SysServId      ; I.d. match found?
        jne     short dt1               ;  no, keep looking

        mov     [edx].SysServId,0       ; No more server
dt1:    add     edx,SIZE SysServData    ; Increment paSysServData
        loop    short dt0

        RETC
EndProc _SysServTerm

_TEXT   ENDS


        FARCODE LOW
CODE    SEGMENT

;       The following procedures must be in low memory since
;       they may be called at interrupt time.


;***    SysServWake - Wake up a Daemon process
;
;       This function verifies that the given function number is
;       valid and that a daemon exists for the given function.
;       It clears the semaphore for the daemon and does a ProcRun
;       to wake the daemon up.
;
;       ENTRY   (DS:BX) = DOS Response packet (DS = DOSGROUP)
;
;       EXIT    NONE
;
;       USES    AX, BX, CX, DX, Flags

Procedure SysServWake,<faronly,far16>                                   ;26159;
        ASSUME  DS:DOSGROUP, ES:NOTHING, SS:NOTHING

        and     [bx].ssrp_sem,NOT 1     ; Clear the semaphore
        mov     ax,ds                   ; Event I.D. in AX:BX
        call    ProcRun                 ; Wake up daemon
        ret

EndProc SysServWake


;***    SysServQueueEvent - Queue event and wake daemon
;
;       This function verifies that the given function number is
;       valid and that a daemon exists for the given function.
;       It queues the given event and does a ProcRun
;       to wake the daemon up.
;
;       ENTRY   (BX) = Daemon function number
;               (SI) = Offset of queue (queue must be in DOSGROUP)
;               (AX) = Event datum1 to queue
;
;       EXIT    Carry set
;                   No daemon
;               Carry clear
;                   No error
;
;       USES    AX, BX, CX, DX, DS, Flags

Procedure SysServQueueEvent,<NEAR,FAR16>                                ;26159;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

        cmp     bx,SysServMax           ; Valid function number?
        jae     ssqe5                   ;  no, internal error
        DosContext ds                   ; Make DS:BX point to array element
        cmp     bx,SysServ_SM           ; Session manager function?
        jne     ssqe0a                  ; No, skip
        cmp     si,OFFSET DOSGROUP:SMHotKeyQ ; Is it for hotkeyQ?
        jne     ssqe0a                  ; No, skip
        cmp     HotKeyQClient,0         ; Is there a client for HotKeyQ?
        je      ssqe0b                  ; No, error exit
ssqe0a: shl     bx,SysServScale
        add     bx,offset DOSGROUP:SysServInfo
        cmp     [bx].SysServId,0        ; Is there a daemon?
ssqe0b: stc                             ;  assume no
        je      ssqe4                   ;  if not, exit
        pushf                           ; Critical section
        cli
        mov     bx,[si].ssq_rear        ; Get pointer to rear of queue
        mov     [bx],ax                 ; Place datum in queue
        add     bx,qelsize              ; Increment by  q element size
        cmp     bx,[si].ssq_qlimit      ; Past end of queue?
        jb      ssqe0                   ;  no, skip ahead
        lea     bx,[si+(size SysServQueue)] ; BX points to front of queue
ssqe0:  mov     [si].ssq_rear,bx        ; Update rear pointer
        mov     dx,[si].ssq_front       ; Get pointer to front
        cmp     bx,dx                   ; Queue full?
        jne     ssqe2                   ;  no, skip ahead
        add     dx,qelsize              ; Increment front pointer (event lost)
        cmp     dx,[si].ssq_qlimit      ; Past end of queue?
        jb      ssqe1                   ;  no, skip ahead
        lea     dx,[si+(size SysServQueue)] ; DX points to front of queue
ssqe1:  mov     [si].ssq_front,dx       ; Update front pointer
ssqe2:  popf                            ; End critical section
        mov     bx,si                   ; Event I.D. in AX:BX
        mov     ax,ds
        call    ProcRun                 ; Wake up daemon
        clc                             ; no error
ssqe4:  ret

ssqe5:  Panic <"SysServQueueEvent">
EndProc SysServQueueEvent


;***    SysServChkDaemon - check if a daemon exists
;
;       Given a service number, this function returns carry set
;       if there is no daemon for that service.
;
;       ENTRY   (BX) = System Service function number
;
;       EXIT    Carry set
;                   No server
;
;       USES    ES, Flags

Procedure SysServChkDaemon,faronly
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

ifdef MISCSTRICT
        cmp     bx,SysServMax           ; Function number too high?
        jae     ssgp0                   ;  yes, internal error
endif
        push    bx
        DosContext es                   ; Make ES:BX point to struc
        shl     bx,SysServScale
        add     bx,offset DOSGROUP:SysServInfo
        cmp     es:[bx].SysServId,1     ; Set carry if no daemon
        pop     bx
        ret

ifdef MISCSTRICT
ssgp0:  Panic <"SysServChkDaemon">
endif

EndProc SysServChkDaemon

CODE    ENDS

        FARCODE HIGH32
HIGH32CODE      SEGMENT

;***LP  _tkSysFrzThwWrkr - Called by TKScanTasks for each child
;
;       Freeze/Thaw pid or screen group
;
;       ENTRY   pptda           PTDA pointer to this child
;               ftAction        action number
;
;       EXIT    NONE
;
;       USES    EAX, ECX, EDX, EFlags

        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING

Procedure _tkSysFrzThwWrkr,near
ArgVar  pptda,DWORD
ArgVar  ftAction,DWORD
        EnterProc
        SaveReg <ebx>
        mov     ebx,pptda
        mov     ebx,[ebx].ptda_pTCBHead
        test    [ftAction],1            ; thaw pid or group?
        jnz     short sftw20            ; yes

;       FREEZE PROCESS : Set TK_FF_ICE on all threads.

sftw10: or      [ebx].TCBForcedActions,TK_FF_ICE; set TK_FF_ICE
        mov     ebx,[ebx].TCBpTCBNext   ; get next thread
        or      ebx,ebx                 ; end of list?
        jnz     short sftw10            ; no - continue
        jmp     short sftwx             ; done.

;       THAW PROCESS : Clear TK_FF_ICE on all threads, and make them
;       runnable again if they actually froze.

sftw20: and     [ebx].TCBForcedActions,not(TK_FF_ICE); Mark thread thawed
        cmp     [ebx].TCBState,STATE_FROZEN
        jne     short sftw30            ; Not frozen, so don't thaw

;        CCALL32 _SCHSetState,<ebx,STATE_READY>; Move thread to ready state
        mov     [ebx].TCBState,STATE_READY
        CCALL32 _TKUpdateState,<ebx>

sftw30: mov     ebx,[ebx].TCBpTCBNext   ; get next thread
        or      ebx,ebx                 ; more threads to go?
        jnz     short sftw20            ; yes - continue.

sftwx:  RestoreReg <ebx>
        xor     eax,eax
        .errnz  NO_ERROR
        LeaveProc
        ret
EndProc _tkSysFrzThwWrkr
HIGH32CODE      ENDS

        END
