User:Johnburger/Demo/Exec/User/LDT

From OSDev Wiki
Jump to navigation Jump to search

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