📄 kernel.inc
字号:
CLI ; No interrupts
; Allocate a link block
MOV EAX,pFreeLB ; NewLB <= pFreeLB;
OR EAX,EAX ; IF pFreeLB=NIL THEN No LBs;
JNZ SHORT Send02 ;
MOV EAX,ercNoMoreLBs ; caller with error in the EAX register
JMP SHORT MReqEnd ; Go home with bad news
Send02:
MOV EBX,[EAX.NextLB] ; pFreeLB <= pFreeLB^.Next
MOV pFreeLB,EBX ;
DEC _nLBLeft ;
MOV [EAX.LBType],DATALB ; This is a Data Link Block
MOV [EAX.NextLB],NIL ; pLB^.Next <= NIL;
MOV EBX,MessageLo ; Get lower half of Msg in EBX
MOV [EAX.DataLo],EBX ; Store in lower half of pLB^.Data
MOV EBX,MessageHi ; Get upper half of Msg in EBX
MOV [EAX.DataHi],EBX ; Store in upper half of pLB^.Data
PUSH EAX ; Save pLB on the stack
CLI ; No interrupts
CALL deQueueTSS ; DeQueue a TSS on that Exch
STI
CMP EAX,NIL ; Did we get one?
JNE Send25 ; Yes, give up the message
POP EAX ; Get the pLB just saved
CLI ; No interrupts
CALL enQueueMsg ; EnQueue the Message on Exch
JMP Send04 ; And get out (Erc 0)!
Send25:
POP EBX ; Get the pLB just saved into EBX
CLI ; No interrupts
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 Send03 ; same as the Running TSS then return
JMP SHORT Send04 ; Return with ErcOk
Send03:
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
Send04:
MOV EAX,ercOk ; Return to Caller with erc ok.
SendEnd:
STI ;
MOV ESP,EBP ;
POP EBP ;
RETF 12 ;
_SendMsg ENDP
;=============================================================================
;
; ISendMsg - The OS Interrupt Send primitive.
; This procedure will provide access to the OS by allowing an
; ISR to send a message to an exchange.
; This is the same as SendMsg except NO task switch is
; performed. If a task is waiting at the exchange, the message is
; associated (linked) with it and it is moved to the RdyQ.
; It will get a chance to run the next time the RdyQ is evaluated
; by the Kernel which will probably be by the timer interrupt slicer.
; Interrupt tasks can use ISendMsg to send single or multiple messages
; to exchanges during their execution.
; Interrupts are CLEARED on entry and WILL NOT BE SET on exit!!!
; It is the responsibility of the caller to set them if desired.
; ISendMsg is intended only to be used by device drivers.
;
;
; Procedural Interface :
;
; ISendMsg(exch, dMsg1, dMsg2):ercType
;
; exch is a DWORD (4 BYTES) containing the exchange to where the
; message should be sent.
;
; dMsg1 and dMsg2 are DWORD messages.
;
;=============================================================================
; Params on stack are the same as _SendMsg.
_ISendMsg PROC FAR ;
CLI ;INTS ALWAYS CLEARED AND LEFT THAT WAY!
PUSH EBP ;
MOV EBP,ESP ;
MOV ESI,SendExchange ; Get Exchange Parameter in ESI
CMP ESI,nExch ; If the exchange is out of range
JNAE ISend00 ; then return to caller with error
MOV EAX,ercOutOfRange ; in the EAX register.
MOV ESP,EBP ;
POP EBP ;
RETF 12 ;
ISend00:
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 ISend01 ; return to the caller with error
MOV EAX,ercNotAlloc ; in the EAX register.
MOV ESP,EBP ;
POP EBP ;
RETF 12 ;
ISend01:
; Allocate a link block
MOV EAX,pFreeLB ; NewLB <= pFreeLB;
OR EAX,EAX ; IF pFreeLB=NIL THEN No LBs;
JNZ SHORT ISend02 ;
MOV EAX,ercNoMoreLBs ; caller with error in the EAX register
MOV ESP,EBP ;
POP EBP ;
RETF 12 ;
ISend02:
MOV EBX,[EAX.NextLB] ; pFreeLB <= pFreeLB^.Next
MOV pFreeLB,EBX ;
DEC _nLBLeft ;
MOV [EAX.LBType],DATALB ; This is a Data Link Block
MOV [EAX.NextLB],NIL ; pLB^.Next <= NIL;
MOV EBX,MessageLo ; Get lower half of Msg in EBX
MOV [EAX.DataLo],EBX ; Store in lower half of pLB^.Data
MOV EBX,MessageHi ; Get upper half of Msg in 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 ISend03 ; Yes, give up the message
POP EAX ; No, Get the pLB just saved
CALL enQueueMsg ; EnQueue the Message on Exch
JMP ISend04 ; And get out!
ISend03:
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
ISend04:
MOV EAX,ercOk ; Return to Caller with erc ok.
MOV ESP,EBP ;
POP EBP ;
RETF 12 ;
_ISendMsg ENDP
;=============================================================================
;
; Wait - The kernel wait primitive. This procedure provides access to
; the operating system by allowing a task to receive information
; from another task.
;
; A result code is returned in the EAX register.
;
; Procedural Interface :
;
; Wait(exch,pdqMsgRet):ercType
;
; exch is a DWORD (4 BYTES) containing the exchange to where the
; message should be sent.
;
; pMessage is a pointer to an 8 byte area where the
; message is stored.
;
WaitExchange EQU [EBP+10h]
pMessage EQU [EBP+0Ch]
;
;
_WaitMsg PROC FAR ;
PUSH EBP ;
MOV EBP,ESP ;
MOV ESI,WaitExchange ; Get Exchange Parameter in ESI
CMP ESI,nExch ; If the exchange is out of range
JNAE Wait00 ; the return to caller with error
MOV EAX,ercOutOfRange ; in the EAX register.
MOV ESP,EBP ;
POP EBP ;
RETF 8 ;
Wait00:
MOV EAX,ESI ; ExchId => EAX
MOV EBX,sEXCH ; Compute offset of ExchId in rgExch
MUL EBX ;
MOV EDX,prgExch ; Add offset of rgExch => EAX
ADD EAX,EDX ;
MOV ESI,EAX ; Put Exch in to ESI
CMP [EAX.Owner],NIL ; If the exchange is not allocated
JNE Wait01 ; return to the caller with error
MOV EAX,ercNotAlloc ; in the EAX register.
MOV ESP,EBP ;
POP EBP ;
RETF 8 ;
Wait01:
CLI ;
CALL deQueueMsg ; EAX <= pLB from pExch (ESI)
CMP EAX,NIL ; If no message (pLB = NIL) Then
JE Wait02 ; Wait for Message Else
JMP Wait05 ; Get Message and Return
Wait02:
MOV EAX,pRunTSS ; Get pRunTSS in EAX to Wait
;This next section of code Queues up the TSS pointed to
;by EAX on the exchange pointed to by ESI
; (i.e., we make the current task "wait")
MOV [EAX.NextTSS],NIL ; pTSSin^.Next <= NIL;
XCHG ESI,EAX ; pExch => EAX, pTSSin => ESI
CMP [EAX.EHead],NIL ; if ..TSSHead = NIL
JNE Wait025 ; then
MOV [EAX.EHead],ESI ; ..TSSHead <= pTSSin;
MOV [EAX.ETail],ESI ; ..TSSTail <= pTSSin;
MOV [EAX.fEMsg], 0 ; Flag it as a TSS (vice a Msg)
XCHG ESI,EAX ; Make ESI <= pExch Again
JMP SHORT Wait03 ; else
Wait025:
MOV EDX,[EAX.ETail] ; ..TSSTail^.NextTSS <= pTSSin;
MOV [EDX.NextTSS],ESI ;
MOV [EAX.ETail],ESI ; ..TSSTail <= pTSSin;
MOV [EAX.fEMsg], 0 ; Flag it as a TSS (vice a Msg)
XCHG ESI,EAX ; Make ESI <= pExch Again
;We just placed the current TSS on an exchange,
;now we get the next TSS to run (if there is one)
Wait03:
CALL deQueueRdy ; Get highest priority TSS off the RdyQ
OR EAX, EAX ; Anyone ready to run?
JNZ Wait035 ; Yes (jump to check pTSS)
STI ; No then HLT CPU until ready
HLT ; Halt CPU and wait for interrupt
CLI ; An interrupt has occured. Clear Interrupts
JMP Wait03 ; Check for a task to switch to
Wait035:
CMP EAX,pRunTSS ; Same one as before???
JE Wait04 ; You bet! NO SWITCH!!!
;Now we switch tasks by placing the address of the
;new TSS in pRunTSS and jumping to it. This forces
;a 386 task switch.
MOV pRunTSS,EAX ; Make high priority TSS Run.
MOV BX,[EAX.Tid] ;
MOV TSS_Sel,BX ;
INC _nSwitches
JMP FWORD PTR [TSS] ; JUMP TSS (Switch Tasks)
; A task has just finished "Waiting"
; We are now in the new task with its memory space
; (or the same task if he was high pri & had a msg)
; If this is a system service it may need RqBlk address aliases
; If it is an OS service we alias in OS memory!
Wait04:
MOV EDX,pRunTSS ; Put the TSS in EAX into EDX
MOV EAX,[EDX.pLBRet] ; Get the pLB in EAX
Wait05:
; if we got here, we have either switched tasks
; and we are delivering a message (or Req) to the new task,
; or the there was a message waiting at the exch of
; the first caller and we are delivering it.
; Either way, the message is already deQueued from
; the exch and the critical part of WaitMsg is over.
; We can start interrupts again except when we have
; to return the Link Block to the pool (free it up)
STI ; WE CAN RESTART INTERRUPTS HERE
CMP [EAX.LBType],REQLB ; Is the link block a Req Link Block?
JNE Wait06 ; No, Treat it as a data link block
;pLB.DataLo is RqHandle (pRqBlk)
PUSH EAX ; Save ptr to Link Block
MOV EBX,[EAX.DataLo] ; Get pRqBlk into EBX
;Now we set up to alias the memory for the service
; (Alias the 2 Pointers in the RqBlk)
;_AliasMem(pMem, dcbMem, dJobNum, ppAliasRet): dError
MOV ECX, [EBX.cbData1] ;
OR ECX, ECX ;is cbData1 0?
JZ Wait051 ;Yes
MOV EAX, [EBX.pData1] ;
OR EAX, EAX ;is pData1 NULL?
JZ Wait051 ;Yes
;Set up params for AliasMem
PUSH EAX ;pMem
PUSH ECX ;cbMem
MOV EAX, [EBX.RqOwnerJob]
PUSH EAX ;dJobNum
ADD EBX, pData1 ;Offset to pData1 in RqBlk
PUSH EBX ;Linear Address of pData1
CALL FAR PTR _AliasMem
OR EAX, EAX ;Error??
JZ Wait051 ;No, continue
POP EBX ;Make stack right
MOV ESP,EBP ;Return Error...
POP EBP ;
RETF 8 ;
Wait051: ;Second Pointer (pData2)
POP EAX ;Restore ptr to Link Block
PUSH EAX ;Save again
MOV EBX,[EAX.DataLo] ; Get pRqBlk into EBX
MOV ECX, [EBX.cbData2] ;
OR ECX, ECX ;is cbData2 0?
JZ Wait052 ;Yes
MOV EAX, [EBX.pData2] ;
OR EAX, EAX ;is pData2 NULL?
JZ Wait052 ;Yes
;Set up params for AliasMem
PUSH EAX ;pMem
PUSH ECX ;cbMem
MOV EAX, [EBX.RqOwnerJob]
PUSH EAX ;dJobNum
ADD EBX, pData2 ;Offset to pData2 in RqBlk
PUSH EBX ;Linear Address of PData1
CALL FAR PTR _AliasMem
OR EAX, EAX ;Error??
JZ Wait052 ;No, continue
POP EBX ;Make stack right
MOV ESP,EBP ;Return Error...
POP EBP ;
RETF 8 ;
Wait052:
POP EAX ;Restore ptr to Link Block
Wait06:
MOV EBX,[EAX.DataLo] ; Get pLB^.Data into ECX:EBX
MOV ECX,[EAX.DataHi] ;
MOV EDX,pMessage ; Get Storage Addr in EDX
MOV [EDX],EBX ; Put pLB^.Data in specified
MOV [EDX+4],ECX ; memory space (EDX)
;Return the LB to the pool
CLI
MOV EBX,pFreeLB ; pLBin^.Next <= pFreeLB;
MOV [EAX.NextLB],EBX ;
MOV pFreeLB,EAX ; pFreeLB <= pLBin;
INC _nLBLeft ;
STI ;
MOV EAX,ercOk ;
MOV ESP,EBP ;
POP EBP ;
RETF 8 ;
_WaitMsg ENDP
;
;
;=============================================================================
;
; CheckMsg - The kernel Check primitive. This procedure provides access
; to the operating system by allowing a task to receive information
; from another process WITHOUT BLOCKING. In other words, if no message is
; available Check returns to the caller. If a message IS available it
; is returned to the caller immediately. The caller is never placed on
; an exchange and the RdyQ is not evaluated.
;
; A result code is returned in the EAX register.
;
; Procedureal Interface :
;
; CheckMsg(exch,pdqMsg):ercType
;
; exch is a DWORD (4 BYTES) containing the exchange to where the
; message should be sent.
;
; pdqMsg is a pointer to an 8 byte area where the message is stored.
;
ChkExchange EQU [EBP+10h]
pCkMessage EQU [EBP+0Ch]
_CheckMsg PROC FAR ;
PUSH EBP ;
MOV EBP,ESP ;
MOV ESI,ChkExchange ; Get Exchange Parameter in ESI
CMP ESI,nExch ; If the exchange is out of range
JNAE Chk01 ; the return to caller with error
MOV EAX,ercOutOfRange ; in the EAX register.
MOV ESP,EBP ;
POP EBP ;
RETF 8 ;
Chk01:
MOV EAX,ESI ; Exch => EAX
MOV EBX,sEXCH ; Compute offset of Exch in rgExch
MUL EBX ;
MOV EDX,prgExch ; Add offset of rgExch => EAX
ADD EAX,EDX ;
MOV ESI,EAX ; Put pExch in to ESI
CMP [EAX.Owner],NIL ; If the exchange is not allocated
JNE Chk02 ; return to the caller with error
STI ;
MOV EAX,ercNotAlloc ; in the EAX register.
MOV ESP,EBP ;
POP EBP ;
RETF 8 ;
Chk02:
CLI ; Can't be interrupted
CALL deQueueMsg ; EAX <= pLB from pExch (ESI)
CMP EAX,NIL ; If pLB = NIL Then
JNE Chk03 ; Go to get msg and return
STI ;
MOV EAX,ercNoMsg ; return with erc no msg
MOV ESP,EBP ;
POP EBP ;
RETF 8 ;
Chk03:
CMP [EAX.LBType],REQLB ; Is the link block a Req Link Block?
JNE Chk04 ; No, Treat it as a data link block
;Code to handle Requests must be done here.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -