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