User:Johnburger/Demo/Exec/User/User
For each Task we want to set up, the Main Executive Task will perform the following steps:
- Prepare the LDT (
Demo/Exec/User/LDT
)- Allocate memory for an LDT, and put a descriptor for it in the GDT
- Allocate memory for a Ring0 Stack, and put a descriptor for it in the LDT
- Allocate memory for a Ring3 Stack, and put a descriptor for it in the LDT
- Allocate memory for a Data Segment, and put a descriptor for it in the LDT
- Put a descriptor for the Code Segment in the LDT (share code among all tasks!)
- Prepare the TSS (
Demo/Exec/User/TSS
)- Allocate memory for a TSS, fill it in, and put a descriptor for it in the GDT
Note that the last step will make the new TSS runnable: a new Program has been created!
Each new Task needs to be assigned a different area of the screen to modify. This information is easiest passed into the Task by altering its starting registers. We could modify the Task's Data Segment instead - that is left as an exercise for the reader!
Once all the Tasks have been created, there's nothing for the Main Task to do. It might as well simply HLT
- but an Interrupt will take it out of HLT
, so JMP
back and do it all again! Or, we could simply remove the Main Task's TSS from the run queue. (Run queue? Run queue!? What's that?)
Of course, this is also a perfect location to insert some test code: MOV ESP,1
anybody?
Demo/Exec/User/User.inc
;
; Exec/User/User.inc
;
; Now that everything is set up, we can start to generate User-mode Programs.
; Each Program is essentially the same: code that bounces a ball around its
; defined area of the screen. To fully demonstrate the features of Protected
; Mode, the following is used:
; 1) The Code runs in User Mode (Ring 3);
; 2) Every Program has its own LDT;
; 3) The CPU's Task Switching mechanism using TSSs is used;
; 4) Every Program has its own Stacks and Data, but shares the same Code.
; Once all the Tasks have been set up, the Executive merely waits for
; <Ctrl><Alt><Del> to be pressed - and then resets the computer... At least it
; would: that's been left as an exercise for the reader. At the moment, you can
; use the trusty Power button!
%push Exec.Start ; Let's not leave these %defines just lying around...
%define %$Pos EBP - 4
%define %$LDT EBP - 8
;...............................................................................
%include "Exec/User/LDT.inc" ; Creates one LDT for a User-mode Program
;...............................................................................
%include "Exec/User/TSS.inc" ; Creates one TSS for a User-mode Program
Exec.User:
ENTER 8, 0
XOR EDX,EDX ; Zero high part of EDX
; MOV DL, 0 ; Start full left
MOV DH, 1 ; Start one row low
.Loop:
MOV [%$Pos],EDX ; Store away new position
; Create a new User LDT
CALL Exec.User.LDT
TEST EAX,EAX
JZ .Finished
; Create a TSS to run that User Task
CALL Exec.User.TSS
TEST EAX,EAX
JZ .Finished
MOV EDX,[%$Pos] ; Current position
ADD DL,Window.Width ; Next Window
CMP DL,VGA.Cols-Window.Width ; Too far?
JBE .Loop ; Not yet...
MOV DL,0 ; Start at left again
ADD DH,Window.Height ; Next row
CMP DH,VGA.Rows-Window.Height ; Too far?
JBE .Loop ; Not yet...
.Finished:
HLT
; Wait for <Ctrl><Alt><Del>
JMP .Finished
%pop