Hallo zusammen,
ich schreibe mit NASM und mein System ist Virtual PC.
Wenn man mit Call einen Taskwechsel auslöst
JMP 0x18:123456
sollte das NT Bit im EFLAG Register gesetzt werden und im Backlink Feld der neuen Task wird das TSS des aufrufenden Task's abgelegt.
Somit ist es möglich mittels IRET (nicht RET) zum alten Task zurück zukehren.
http://www.fh-zwickau.de/doc/prmo/pmtutor/text/p_spez2.htm ebenfalls im Buch von Klaus-Dieter Thies Seite 375.
Auf eine IDT habe ich der Einfachheit halber verzichtet, da ich den Sprung mit Call/IRET durchführen möchte.
Mein Code ist recht einfach aufgebaut:
Das A21 Bit ist hier im Code nicht aufgeführt wird aber gemacht
org 0x8000
cpu 486
[Bits 16]
start:
cli ;Interrupts aus
;alle Register löschen
in al, 0x60 ;Tastaturbuffer leeren
xor ax, ax
xor bx, bx
xor cx, cx
xor dx, dx
xor di, di
xor si, si
lgdt [GDT] ;GDT laden
mov eax, cr0
or ax, 1
mov cr0, eax ;In den P-Mode wechseln
jmp 0x8:pmode
[Bits 32]
pmode:
;Selectoren setzen
xor eax, eax
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 0x80000 ;Stack auf 512 KByte
mov ax, 32d
ltr ax ;OS Urtask erstellen
call getmemsize ;Speichergröße feststellen
mov [ram], eax ;und speichern
call createtables ;Paging aktivieren
call 0x28:0x123456 ;Userprogramm als Task aufrufen
push dword str_umbruch
call prints
jmp warteschleife
;######################################################
; ab hier nur ein Test ob alles geht!!!
;------------------------------------------------------------------------------------------------------------
%include "main.inc"
;#############################################
;------------------------------------------------------------------------------------------------------------
warteschleife:
nop
jmp warteschleife
meine GDT sieht so aus:
gdttabelle: ;0
dd 0
dd 0
CODE: ;8
dw 0xFFFF
dw 0
db 0
db 10011010b
db 11001111b ;DB und G Bit gesetzt
db 0
DATEN: ;16
dw 0xFFFF
dw 0
db 0
db 10010010b
db 11001111b ;DB und G Bit gesetzt
db 0
USER_TASK: ;24 ;Das USER TSS
dw 104d
dw TSS1
db 0
db 10001001b
db 10000000b
db 0
TMP_TSS: ;32 nur zur temporären Umschaltung des Tasks
dw 104d
dw tmptss
db 0
db 10001001b
db 10000000b
db 0
USER_GATE: ;40 Task Gate Userprogramm
dw 0
dw 24d
db 0
db 10000101b
dw 0
GDT:
gdt_limit dw $ - gdttabelle
gdt_base dd gdttabelle
Nachdem nun mit
call 0x28:0x123456 ;Userprogramm als Task aufrufen in den neuen Task gewechselt wurde, werden ein paar Daten ausgegeben:
Das ist nichts großes..
user:
push dword crlf
call prints
push dword crlf
call prints
push dword crlf
call prints
mov ebx, 0x804f0
mov eax, [ebx]
push eax
call itoh
push eax
call prints
push dword crlf
call prints
mov ebx, 0x804f4
mov eax, [ebx]
push eax
call itoh
push eax
call prints
push dword crlf
call prints
mov ebx, 0x804f8
mov eax, [ebx]
push eax
call itoh
push eax
call prints
push dword crlf
call prints
mov ebx, 0x804fc
mov eax, [ebx]
push eax
call itoh
push eax
call prints
push dword crlf
call prints
push dword crlf
call prints
mov ebx, USER_TASK
add ebx, 5d
push ebx
xor eax, eax
mov al, byte [ebx]
push eax
call itoh
push eax
call prints
push dword crlf
call prints
pop ebx
add ebx, 8d
xor eax, eax
mov al, byte [ebx]
push eax
call itoh
push eax
call prints
push dword crlf
call prints
;iret
;jmp 0x20:0x123456
Falls noch von Interesse hier noch die beiden TSS
TSS1 ist für das aufgerufene Programm und tmptss ist nur zur temporären Speicherung der Urtask. (Da wird später nicht mehr zurückgesprungen)
TSS1:
dw 0 ;Backlinkfeld
dw 0 ;NULL
dd 0x80000 ;ESP0
dw 0x10 ;SS0
dw 0 ;NULL
dd 0 ;ESP1
dw 0 ;SS1
dw 0 ;NULL
dd 0 ;ESP2
dw 0 ;SS2
dw 0 ;NULL
dd 0x21000 ;Cr3 = 0x21000 = 135 KByte
.eip dd user ;EIP
.eflag dd 0x2 ;EFlag
;----- allgemeine Register
dd 0 ;EAX
dd 0 ;ECX
dd 0 ;EDX
dd 0 ;EBX
dd 0x80500 ;ESP
dd 0 ;EBP
dd 0 ;ESI
dd 0 ;EDI
;-------
dw 0x10 ;ES
dw 0 ;
dw 0x8 ;CS
dw 0 ;
dw 0x10 ;SS
dw 0 ;
dw 0x10 ;DS
dw 0 ;
dw 0x10 ;FS
dw 0 ;
dw 0x10 ;GS
dw 0 ;
dw 0 ;LDT Selektor
dw 0 ;NULL
dd 0 ;
;########################################################
tmptss:
times 104 db 0
Beide Tasks benutzen die selben Segmente (Flat 4GB) aber unterschiedliche Stackzeiger (ESP). Beide laufen in Ring 0.
Das Bit 14 (0-15) wird nicht gesetzt nach Call und in beiden Stacks werden auch keine Daten abgelegt.
Falls noch was fehlt, einfach melden...
Danke für die Hilfe
Nicky