⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kernel.inc

📁 MMURTL(tm) Computer Operating System Ver x0.8, source code.
💻 INC
📖 第 1 页 / 共 4 页
字号:
		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 + -