User:Johnburger/Demo/Exec/User/LDT
The Executive needs to perform the following to create a new LDT:
- First the Executive needs to allocate some memory for the new LDT - but since it will be writing to it, it needs to start as a Data Segment.
- Then, for each structure in the User's LDT, the Executive has to:
- Allocate some memory for it (unless it's the User Code - that's already assembled!);
- Potentially initialize its contents (don't bother for Stacks);
- Add a Descriptor to the LDT with the correct settings.
- Finally, the Data Segment can be converted into a true LDT.
I've been lazy and not called Demo/Exec/Alloc/RAM
's .Zero
routine for the allocated RAM. Not doing this is a security risk - but since I wrote the code that uses it, I promise (hand-on-heart) not to mis-use any uninitialised data I may find... Besides, to initialize it would require assigning it to a Descriptor that I can access - the LDT under construction isn't an LDT yet!
CAUTION: If you do decide to switch your own LDT, note that you must modify the LDT field in your TSS first, before immediately changing it with an LLDT
instruction. This is because the LDT is not saved during a hardware Task Switch, and if you do it the wrong way around, an inopportune interrupt may send your code into oblivion. Alternately, you can disable interrupts while the "foreign" LDT is in place - and hope that you don't get an exception!
Demo/Exec/User/LDT.inc
;
; Exec/User/LDT.inc
;
; This module creates a User-mode Program's LDT and populates it.
; For demonstration purpose, it deliberately "forgets" to mark some of the
; Segments as "Present", which should trigger the Segment Not Present exception.
Exec.User.LDT:
; Allocate an LDT
MOV ECX,User.LDT.Size ; Need this many bytes
CALL Exec.Alloc.LDT
TEST EAX,EAX ; Any left?
JZ .Failed ; Nope! Finished
MOV [%$LDT],EAX ; Want to keep this!
; Allocate Stack0
MOV ECX,User.Stack0.Size ; Get some RAM for Stack0
CALL Exec.Alloc.RAM
TEST EAX,EAX ; Any left?
JZ .Failed ; Nope!
MOV DL,Type.Mem(Stack, DPL0, RW)
MOV DH,Gran.Mem(Byte, Small)
CALL Exec.Alloc.LDT.Mem ; Allocate LDT Entry
CMP EAX,User.LDT.Stack0
JNE .Failed
; Allocate Stack3
MOV ECX,User.Stack3.Size ; Get some RAM for Stack3
CALL Exec.Alloc.RAM
TEST EAX,EAX ; Any left?
JZ .Failed ; Nope!
MOV DL,Type.Mem(Stack, DPL3, RW)
MOV DH,Gran.Mem(Byte, Small)
CALL Exec.Alloc.LDT.Mem ; Allocate LDT Entry
CMP EAX,User.LDT.Stack3
JNE .Failed
; Allocate Data
MOV ECX,User.Data.Size ; Get some RAM for Data
CALL Exec.Alloc.RAM
TEST EAX,EAX ; Any left?
JZ .Failed ; Nope!
MOV DL,Type.Mem(Data, DPL3, RW); & ~x86.Desc.Type.Present
MOV DH,Gran.Mem(Byte, Big)
CALL Exec.Alloc.LDT.Mem ; Allocate LDT Entry
CMP EAX,User.LDT.Data
JNE .Failed
; Allocate Code
MOV EAX,User.Base ; Assembled User code
MOV ECX,User.Size
MOV DL,Type.Mem(Code, DPL3, NoRW); & ~x86.Desc.Type.Present
MOV DH,Gran.Mem(Byte, Def32)
CALL Exec.Alloc.LDT.Mem ; Allocate LDT Entry
CMP EAX,User.LDT.Code
JNE .Failed
; Now enable the LDT
CALL Exec.Alloc.LDT.Enable ; Finished!
MOV EAX,[%$LDT] ; LDT descriptor
JMP .End
.Failed:
XOR EAX,EAX
.End:
RET