📄 kernel.inc
字号:
;=============================================================================
;================= BEGIN PUBLIC KERNEL PRIMITIVES ============================
;=============================================================================
;
; Request - The kernel request primitive sends a message like the Send
; primitive except this function requires several more parameters.
; A system structure called a request block is allocated and some of these
; parameters are placed in it. A request block is the basic
; structure used for Client-Server communications. The exchange where a
; request should be queued is determined by searching the system service
; array for a matching request service name specified in the request block.
; The procedural interface to Request looks like this:
;
; Request( pSvcName [EBP+56]
; wSvcCode [EBP+52]
; dRespExch [EBP+48]
; pRqHndlRet [EBP+44]
; dnpSend [EBP+40]
; pData1 [EBP+36]
; dcbData1 [EBP+32]
; pData2 [EBP+28]
; dcbData2 [EBP+24]
; dData0 [EBP+20]
; dData1 [EBP+16]
; dData2 [EBP+12] ) : dError
_Request PROC FAR ;
PUSH EBP ; Save the Previous FramePtr
MOV EBP,ESP ; Set up New FramePtr
;Validate service name from registry and get exchange
MOV EAX, [EBP+56] ;pServiceName
CALL GetExchange ;Leaves Service Exch in ESI if no errors
CMP EAX, ercOk ;Any errors?
JE SHORT Req02 ;No
JMP ReqEnd ;Yes, return error
Req02:
;Validate exchange
MOV EDX, [EBP+48] ; Get Resp Exchange in EDX
CMP EDX,nExch ; Is the exchange out of range?
JB Req03 ; No, continue
MOV EAX,ercOutOfRange ; Yes, Error in EAX register
JMP ReqEnd ;
Req03:
;Get them a request block
CLI
CALL NewRQB ;EAX has ptr to new RqBlk (or 0 if none)
STI
CMP EAX, NIL ;Did we get one? (NIL (0) means we didn't)
JNE Req04 ;Yes. EAX ptr to new RqBlk
MOV EAX, ErcNoMoreRqBlks ;No, Sorry...
JMP ReqEnd ;
Req04:
;ESI still has the exchange for the service
;EDX still has the response exchange
;EAX has pRqBlk (Handle)
MOV EBX, EAX ;EBX now pts to RqBlk
MOV [EBX.ServiceExch], ESI ;Put Svc Exch into RqBlk
MOV EAX, [EBP+52] ;Get Svc Code
MOV [EBX.ServiceCode], AX ;Put Svc Code into RqBlk
MOV [EBX.RespExch], EDX ;Put Resp Exch into RqBlk
CALL GetCrntJobNum ;Get crnt JCB (Job Num of owner)
MOV [EBX.RqOwnerJob], EAX ;put in RqBlk
MOV EAX, [EBP+20] ;Get dData0
MOV [EBX.dData0], EAX ;put in RqBlk
MOV EAX, [EBP+16] ;Get dData1
MOV [EBX.dData1], EAX ;put in RqBlk
MOV EAX, [EBP+20] ;Get dData2
MOV [EBX.dData2], EAX ;put in RqBlk
MOV EAX, [EBP+36] ;Get pData1
MOV [EBX.pData1], EAX ;put in RqBlk
MOV EAX, [EBP+32] ;Get cbData1
MOV [EBX.cbData1], EAX ;put in RqBlk
MOV EAX, [EBP+28] ;Get pData2
MOV [EBX.pData2], EAX ;put in RqBlk
MOV EAX, [EBP+24] ;Get cbData2
MOV [EBX.cbData2], EAX ;put in RqBlk
MOV EAX, [EBP+40] ;Number of Send PbCbs
CMP EAX, 3 ;Must be 2 or less
JB Req06 ;
MOV EAX, 2
Req06:
MOV [EBX.npSend], AL ;Put nSend PbCbs into RqBlk
MOV CL, 2 ;Caculate nRecv (2-nSend)
SUB CL, AL ;Leave in CL
MOV [EBX.npRecv], CL ;Put npRecv in RqBlk
;At this point the RqBlk is all filled in.
;Now we will return the RqBlkHandle to the user.
;The handle is actually a ptr to the RqBlk but they can't use
;it as one anyway (so no problem)
MOV EDI, [EBP+44] ;Ptr to return handle to
MOV [EDI], EBX ;Give it to them
MOV EDX, EBX ;Save RqBlk in EDX
CLI ; No interruptions from here on
;Now we allocate a Link block to use
MOV EAX,pFreeLB ; EAX <= pFreeLB;
OR EAX,EAX ; Is pFreeLB NIL? (out of LBs)
JNZ Req08 ;
CALL DisposeRQB ; NO... free up RqBlk
MOV EAX,ercNoMoreLBs ; Move error in the EAX register
JMP ReqEnd ; Go home with bad news
Req08:
MOV EBX,[EAX.NextLB] ; pFreeLB <= pFreeLB^.Next
MOV pFreeLB,EBX ;
DEC _nLBLeft ;
MOV [EAX.LBType],REQLB ; This is a Request Link Block
MOV [EAX.NextLB],NIL ; pLB^.Next <= NIL;
MOV [EAX.DataLo],EDX ; RqHandle into Lower 1/2 of Msg
MOV [EAX.DataHi], 0 ; Store zero in upper half of pLB^.Data
PUSH EAX ; Save pLB on the stack
;ESI still has the exchange Number for the service.
;The ptr to the exch is required for deQueueTSS so we get it.
MOV EAX,ESI ; Exch => EAX
MOV EDX, sEXCH ; Compute offset of Exch in rgExch
MUL EDX ;
MOV EDX,prgExch ; Add offset of rgExch => EAX
ADD EAX,EDX ;
MOV ESI,EAX ; MAKE ESI <= pExch
;ESI now points to the exchange
CALL deQueueTSS ; DeQueue a TSS on that Exch
CMP EAX,NIL ; Did we get one?
JNE Req10 ; Yes, give up the message
POP EAX ; No, Get the pLB just saved
CALL enQueueMsg ; EnQueue the Message on Exch
XOR EAX,EAX ; No Error
JMP SHORT ReqEnd ; And get out!
Req10:
POP EBX ; Get the pLB just saved into EBX
MOV [EAX.pLBRet],EBX ; and put it in the TSS
CALL enQueueRdy ; EnQueue the TSS on the RdyQ
MOV EAX,pRunTSS ; Get the Ptr To the Running TSS
CALL enQueueRdy ; and put him on the RdyQ
CALL deQueueRdy ; Get high priority TSS off the RdyQ
CMP EAX,pRunTSS ; If the high priority TSS is the
JNE Req12 ; same as the Running TSS then return
XOR EAX,EAX ; Return to Caller with erc ok.
JMP SHORT ReqEnd
Req12:
MOV pRunTSS,EAX ; Make the TSS in EAX the Running TSS
MOV BX,[EAX.Tid] ; Get the task Id (TR)
MOV TSS_Sel,BX ; Put it in the JumpAddr for Task Swtich
INC _nSwitches ; Keep track of how many swtiches for stats
JMP FWORD PTR [TSS] ; JMP TSS (This is the task swtich)
XOR EAX,EAX ; Return to Caller with erc ok.
ReqEnd:
STI ;
MOV ESP,EBP ;
POP EBP ;
RETF 48 ; Rtn to Caller & Remove Params from stack
_Request ENDP ;
;=============================================================================
; The response primitive is used by system services to respond to a
; Request received at their service exchange. The RqBlk handle must be
; supplied along with the error/status code to be returned to the
; caller. This is very similar to Send except is dealiases addresses
; in the RqBlk and then deallocates it. The exchange to respond to
; is located inside the RqBlk.
;
; Respond(dRqHndl, dStatRet): dError
;
;
dRqHndl EQU DWORD PTR [EBP+16]
dStatRet EQU DWORD PTR [EBP+12]
_Respond PROC FAR ;
PUSH EBP ; Save Callers Frame
MOV EBP,ESP ; Setup Local Frame
MOV EAX, dRqHndl ; pRqBlk into EAX
MOV ESI, [EAX.RespExch] ; Response Exchange into ESI
CMP ESI,nExch ; Is the exchange out of range?
JNAE Resp02 ; No, continue
MOV EAX,ercOutOfRange ; Error into the EAX register.
JMP RespEnd ; Get out
Resp02:
MOV EAX,ESI ; Exch => EAX
MOV EDX,sEXCH ; Compute offset of Exch in rgExch
MUL EDX ;
MOV EDX,prgExch ; Add offset of rgExch => EAX
ADD EAX,EDX ;
MOV ESI,EAX ; MAKE ESI <= pExch
CMP [EAX.Owner],NIL ; If the exchange is not allocated
JNE Resp04 ; return to the caller with error
MOV EAX,ercNotAlloc ; in the EAX register.
JMP RespEnd ;
Resp04:
MOV EAX, dRqHndl ; Get Request handle into EBX (pRqBlk)
MOV EBX, [EAX.RqOwnerJob]
CALL GetCrntJobNum
CMP EAX, EBX
JE Resp06 ;Same job - no DeAlias needed
MOV EAX, dRqHndl ; Get Request handle into EBX (pRqBlk)
MOV EBX, [EAX.cbData1] ;
OR EBX, EBX
JZ Resp05 ;No need to dealias (zero bytes)
MOV EDX, [EAX.pData1]
OR EDX, EDX
JZ Resp05 ;Null pointer!
PUSH ESI ;Save pExch across call
PUSH EDX ;pMem
PUSH EBX ;cbMem
CALL GetCrntJobNum
PUSH EAX
CALL FAR PTR _DeAliasMem ;DO it and ignore errors
POP ESI ;get pExch back
Resp05:
MOV EAX, dRqHndl ; Get Request handle into EBX (pRqBlk)
MOV EBX, [EAX.cbData2] ;
OR EBX, EBX
JZ Resp06 ;No need to dealias (zero bytes)
MOV EDX, [EAX.pData2]
OR EDX, EDX
JZ Resp06 ;Null pointer!
PUSH ESI ;Save pExch across call
PUSH EDX ;pMem
PUSH EBX ;cbMem
CALL GetCrntJobNum ;
PUSH EAX
CALL FAR PTR _DeAliasMem ;DO it and ignore errors
POP ESI ;get pExch back
Resp06:
MOV EAX, dRqHndl ; Get Request handle into EBX (pRqBlk)
CLI ; No interruptions
CALL DisposeRQB ; Return Rqb to pool. Not needed anymore
; Allocate a link block
MOV EAX,pFreeLB ; NewLB <= pFreeLB;
OR EAX,EAX ; IF pFreeLB=NIL THEN No LBs;
JNZ Resp07 ;
MOV EAX,ercNoMoreLBs ; caller with error in the EAX register
JMP RespEnd
Resp07:
MOV EBX,[EAX.NextLB] ; pFreeLB <= pFreeLB^.Next
MOV pFreeLB,EBX ;
DEC _nLBLeft ;
MOV [EAX.LBType],RESPLB ; This is a Response Link Block
MOV [EAX.NextLB],NIL ; pLB^.Next <= NIL;
MOV EBX, dRqHndl ; Get Request handle into EBX
MOV [EAX.DataLo],EBX ; Store in lower half of pLB^.Data
MOV EBX, dStatRet ; Get Status/Error into EBX
MOV [EAX.DataHi],EBX ; Store in upper half of pLB^.Data
PUSH EAX ; Save pLB on the stack
CALL deQueueTSS ; DeQueue a TSS on that Exch
CMP EAX,NIL ; Did we get one?
JNE Resp08 ; Yes, give up the message
POP EAX ; Get the pLB just saved
CALL enQueueMsg ; EnQueue the Message on Exch
XOR EAX, EAX ; No Error
JMP SHORT RespEnd ; And get out!
Resp08:
POP EBX ; Get the pLB just saved into EBX
MOV [EAX.pLBRet],EBX ; and put it in the TSS
CALL enQueueRdy ; EnQueue the TSS on the RdyQ
MOV EAX,pRunTSS ; Get the Ptr To the Running TSS
CALL enQueueRdy ; and put him on the RdyQ
CALL deQueueRdy ; Get high priority TSS off the RdyQ
CMP EAX,pRunTSS ; If the high priority TSS is the
JNE Resp10 ; same as the Running TSS then return
XOR EAX,EAX ; Return to Caller with erc ok.
JMP SHORT RespEnd ;
Resp10:
MOV pRunTSS,EAX ; Make the TSS in EAX the Running TSS
MOV BX,[EAX.Tid] ; Get the task Id (TR)
MOV TSS_Sel,BX ; Put it in the JumpAddr
INC _nSwitches
JMP FWORD PTR [TSS] ; JMP TSS
MOV EAX,ercOk ; Return to Caller with erc ok.
RespEnd:
STI
MOV ESP,EBP ;
POP EBP ;
RETF 8 ; Rtn to Caller & Remove Params
_Respond ENDP ;
;=============================================================================
;
; MoveRequest - The kernel Move Request primitive.
; This allows a service to move a request to another exchange it owns.
; This can not be used to forward a request to another service or Job.
; It is very similar to send except it checks to ensure the destination
; Exchange is owned by the sender.
;
; Procedural Interface :
;
; MoveRequest(dRqBlkHndl, DestExch):ercType
;
; dqMsg is the handle of the RqBlk to forward.
; DestExch the exchange to where the Request should be sent.
;
;
;dRqBlkHndl EQU [EBP+16]
;DestExch EQU [EBP+12]
_MoveRequest PROC FAR ;
PUSH EBP ;
MOV EBP,ESP ;
MOV ESI, [EBP+12] ; Get Exchange Parameter in ESI
CMP ESI,nExch ; Is the exchange is out of range
JNAE MReq02 ; No, continue
MOV EAX,ercOutOfRange ; in the EAX register.
JMP MReqEnd ; Get out
MReq02:
MOV EAX,ESI ; Exch => EAX
MOV EDX,sEXCH ; Compute offset of Exch in rgExch
MUL EDX ;
MOV EDX,prgExch ; Add offset of rgExch => EAX
ADD EAX,EDX ;
MOV ESI,EAX ; MAKE ESI <= pExch
MOV EDX, [EAX.Owner] ; Put exch owner into EDX (pJCB)
CALL GetpCrntJCB ; Leaves it in EAX (uses only EAX)
CMP EDX, EAX ; If the exchange is not owned by sender
JE MReq04 ; return to the caller with error
MOV EAX, ErcNotOwner ; in the EAX register.
JMP MReqEnd ; Get out
MReq04:
CLI ; No interruptions from here on
; Allocate a link block
MOV EAX,pFreeLB ; NewLB <= pFreeLB;
OR EAX,EAX ; IF pFreeLB=NIL THEN No LBs;
JNZ MReq08 ;
MOV EAX,ercNoMoreLBs ; caller with error in the EAX register
JMP MReqEnd ; Go home with bad news
MReq08:
MOV EBX,[EAX.NextLB] ; pFreeLB <= pFreeLB^.Next
MOV pFreeLB,EBX ;
DEC _nLBLeft ;
MOV [EAX.LBType],REQLB ; This is a Request Link Block
MOV [EAX.NextLB],NIL ; pLB^.Next <= NIL;
MOV EBX, [EBP+16] ; RqHandle
MOV [EAX.DataLo],EBX ; RqHandle into Lower 1/2 of Msg
MOV [EAX.DataHi], 0 ; Store zero in upper half of pLB^.Data
PUSH EAX ; Save pLB on the stack
CALL deQueueTSS ; DeQueue a TSS on that Exch
CMP EAX,NIL ; Did we get one?
JNE MReq10 ; Yes, give up the message
POP EAX ; Get the pLB just saved
CALL enQueueMsg ; EnQueue the Message on Exch
JMP SHORT MReqEnd ; And get out!
MReq10:
POP EBX ; Get the pLB just saved into EBX
MOV [EAX.pLBRet],EBX ; and put it in the TSS
CALL enQueueRdy ; EnQueue the TSS on the RdyQ
MOV EAX,pRunTSS ; Get the Ptr To the Running TSS
CALL enQueueRdy ; and put him on the RdyQ
CALL deQueueRdy ; Get high priority TSS off the RdyQ
CMP EAX,pRunTSS ; If the high priority TSS is the
JNE MReq12 ; same as the Running TSS then return
MOV EAX,ercOk ; Return to Caller with erc ok.
JMP SHORT MReqEnd
MReq12:
MOV pRunTSS,EAX ; Make the TSS in EAX the Running TSS
MOV BX,[EAX.Tid] ; Get the task Id (TR)
MOV TSS_Sel,BX ; Put it in the JumpAddr for Task Swtich
INC _nSwitches ; Keep track of how many swtiches for stats
JMP FWORD PTR [TSS] ; JMP TSS (This is the task swtich)
MOV EAX,ercOk ; Return to Caller with erc ok.
MReqEnd:
STI ;
MOV ESP,EBP ;
POP EBP ;
RETF 8 ;
_MoveRequest ENDP
;=============================================================================
;
; SendMsg - The kernel send primitive. This sends a non-specific message
; from a running task to an exchange. This may cause a task swtich if
; a task is waiting at the exchange and it is of equal or higher priority
; that the task that sent the message.
;
; Procedural Interface :
;
; SendMsg(exch, dMsg1, dMsg2):ercType
;
; exch is a DWORD (4 BYTES) containing the exchange to where the
; message should be sent.
;
; dMsg1 & dMsg2 are DWord values defined and understood
; only by the sending and receiving tasks.
;
SendExchange EQU [EBP+14h]
MessageHi EQU DWORD PTR [EBP+10h]
MessageLo EQU DWORD PTR [EBP+0Ch]
_SendMsg PROC FAR ;
PUSH EBP ;
MOV EBP,ESP ;
MOV ESI,SendExchange ; Get Exchange Parameter in ESI
CMP ESI,nExch ; If the exchange is out of range
JNAE Send00 ; the return to caller with error
MOV EAX,ercOutOfRange ; in the EAX register.
JMP SendEnd
Send00:
MOV EAX,ESI ; Exch => EAX
MOV EDX,sEXCH ; Compute offset of Exch in rgExch
MUL EDX ;
MOV EDX,prgExch ; Add offset of rgExch => EAX
ADD EAX,EDX ;
MOV ESI,EAX ; MAKE ESI <= pExch
CMP [EAX.Owner],NIL ; If the exchange is not allocated
JNE Send01 ; return to the caller with error
MOV EAX,ercNotAlloc ; in the EAX register.
JMP SendEnd ;
Send01:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -