Autor Thema: Interrupt-Stackzustand (speziell Errorcode) im Long Mode  (Gelesen 8224 mal)

tiger717

  • Beiträge: 84
    • Profil anzeigen
Gespeichert
Hallo,

folgendes Problem:
nach iretq im Interrupthandler bekomme ich einen #PF, warscheinlich durch Fehler im Stack (-> im Code).

%macro handler 1
int_stub_%1:
push qword 0x0
push qword %1

jmp handler_common
%endmacro

%macro handler_errorcode 1
int_stub_%1:
push qword %1

jmp handler_common
%endmacro

handler_common:
push rbp
push rdi
push rsi
push rdx
push rcx
push rbx
push rax

push rsp

call handle_interrupt

add rsp, 0x8

pop rax
pop rbx
pop rcx
pop rdx
pop rsi
pop rdi
pop rbp

add rsp, 0x10

iretq

QEMU-Log:
----------------
IN:
0x000000000010a07b:  lidt   0x10ac33
0x000000000010a083:  sti

----------------
IN:
0x000000000010a084:  hlt

Servicing hardware INT=0x20
     0: v=20 e=0000 i=0 cpl=0 IP=0008:000000000010a085 pc=000000000010a085 SP=0010:0000000000107454 EAX=0000000000000000
RAX=0000000000000000 RBX=deadbeefc0debeef RCX=0000000000000000 RDX=0000000000000000
RSI=0000000000000000 RDI=0000000000103454 RBP=0000000000000000 RSP=0000000000107454
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=000000000010a085 RFL=00200202 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 00000000 00009100 DPL=0 DS16 [--A]
CS =0008 0000000000000000 00000000 00209800 DPL=0 CS64 [---]
SS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 0000000000000000 00000000 00009100 DPL=0 DS16 [--A]
FS =0010 0000000000000000 00000000 00009100 DPL=0 DS16 [--A]
GS =0010 0000000000000000 00000000 00009100 DPL=0 DS16 [--A]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT=     000000000010ac11 00000017
IDT=     0000000000103144 0000030f
CR0=80000011 CR2=0000000000000000 CR3=0000000000001000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000000 CCD=0000000000103454 CCO=EFLAGS
EFER=0000000000000500
----------------
IN:
0x000000000010ab5f:  pushq  $0x0
0x000000000010ab61:  pushq  $0x20
0x000000000010ab63:  jmp    0x10abc5

----------------
IN:
0x000000000010abc5:  push   %rbp
0x000000000010abc6:  push   %rdi
0x000000000010abc7:  push   %rsi
0x000000000010abc8:  push   %rdx
0x000000000010abc9:  push   %rcx
0x000000000010abca:  push   %rbx
0x000000000010abcb:  push   %rax
0x000000000010abcc:  push   %rsp
0x000000000010abcd:  callq  0x10ad04

----------------
IN:
0x000000000010ad04:  sub    $0x8,%rsp
0x000000000010ad08:  mov    %rdi,(%rsp)
0x000000000010ad0c:  add    $0x8,%rsp
0x000000000010ad10:  retq

----------------
IN:
0x000000000010abd2:  add    $0x8,%rsp
0x000000000010abd6:  pop    %rax
0x000000000010abd7:  pop    %rbx
0x000000000010abd8:  pop    %rcx
0x000000000010abd9:  pop    %rdx
0x000000000010abda:  pop    %rsi
0x000000000010abdb:  pop    %rdi
0x000000000010abdc:  pop    %rbp
0x000000000010abdd:  add    $0x10,%rsp
0x000000000010abe1:  iretq

check_exception old: 0xffffffff new 0xd
     1: v=0d e=0010 i=0 cpl=0 IP=0008:000000000010abe1 pc=000000000010abe1 SP=0010:0000000000107428 EAX=0000000000000000
RAX=0000000000000000 RBX=deadbeefc0debeef RCX=0000000000000000 RDX=0000000000000000
RSI=0000000000000000 RDI=0000000000103454 RBP=0000000000000000 RSP=0000000000107428
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=000000000010abe1 RFL=00200002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 00000000 00009100 DPL=0 DS16 [--A]
CS =0008 0000000000000000 00000000 00209800 DPL=0 CS64 [---]
SS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 0000000000000000 00000000 00009100 DPL=0 DS16 [--A]
FS =0010 0000000000000000 00000000 00009100 DPL=0 DS16 [--A]
GS =0010 0000000000000000 00000000 00009100 DPL=0 DS16 [--A]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT=     000000000010ac11 00000017
IDT=     0000000000103144 0000030f
CR0=80000011 CR2=0000000000000000 CR3=0000000000001000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000010 CCD=0000000000107428 CCO=ADDQ
EFER=0000000000000500

Der Fehler kommt anscheinend vom Error code. Nach der Tabelle im AMD64 Manual, Volume 2 auf Seite 250 (PDF 298) ist ja alles 16-byte aligned und mit add esp, 0x10 nehm ich ja den Errorcode und Interrupt Vector vom Stack - muss ich das im Long Mode überhaupt?

Thx

PS: Ja, ich weiß, der EOI fehlt, aber auch mit bekomme ich nen #PF.

SHyx0rmZ

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 02. March 2013, 16:46 »
Du hast übersehen, dass im Long Mode ein anderes ABI zu beachten ist. Der Parameter für handle_interrupt kann nicht über den Stack übergeben werden, sondern muss in rdi übergeben werden. Siehe auch: System V Application Binary Interface AMD64 Architecture Processor Supplement.
@X="krJhbuaesrytre c a cnR.ohut";while@X[/(..)(.)/];@X=@X[3..-1]+$1;print$2;end
"Scheiß auf Perl, wir haben Kekse" - Emperor Ruby

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 02. March 2013, 16:50 »
0x0d ist ein #GP fault und kein #PF, der Auftritt weil etwas mit deinem datensegment 0x10 (e = 0x10) nicht stimmt.
Es sieht auch merkwürdig aus, das sich die Beschreibungen trotz gleicher Selektoren unterscheiden:
Zitat
SS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 0000000000000000 00000000 00009100 DPL=0 DS16 [--A]
FS =0010 0000000000000000 00000000 00009100 DPL=0 DS16 [--A]
GS =0010 0000000000000000 00000000 00009100 DPL=0 DS16 [--A]

Außerdem gibt es im LongMode noch ein paar mehr Register (r8-r15), die du evtl. sichern solltest. Ein paar werden zwar sind laut abi zwar für den caller reserviert, aber ich glaube das sind nicht alles r8-r15.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

tiger717

  • Beiträge: 84
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 02. March 2013, 17:03 »
Du hast übersehen, dass im Long Mode ein anderes ABI zu beachten ist. Der Parameter für handle_interrupt kann nicht über den Stack übergeben werden, sondern muss in rdi übergeben werden. Siehe auch: System V Application Binary Interface AMD64 Architecture Processor Supplement.
Was man nicht alles in den paar Wochen ohne os-dev vergisst. Wird gefixt.
0x0d ist ein #GP fault und kein #PF, der Auftritt weil etwas mit deinem datensegment 0x10 (e = 0x10) nicht stimmt.
Es sieht auch merkwürdig aus, das sich die Beschreibungen trotz gleicher Selektoren unterscheiden:
Zitat
SS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 0000000000000000 00000000 00009100 DPL=0 DS16 [--A]
FS =0010 0000000000000000 00000000 00009100 DPL=0 DS16 [--A]
GS =0010 0000000000000000 00000000 00009100 DPL=0 DS16 [--A]

Außerdem gibt es im LongMode noch ein paar mehr Register (r8-r15), die du evtl. sichern solltest. Ein paar werden zwar sind laut abi zwar für den caller reserviert, aber ich glaube das sind nicht alles r8-r15.
Gab vorher einige Probleme mit #PF, deshalb hab ich das wohl verwechselt, wie auch immer.
GDT guck ich mir gleich mal an.
Die anderen Register hab ich nicht vollkommen vergessen, mein Code ist nur grad ein wenig bröckelig, da warte ich lieber bis die Interrupts grundlegend funktionieren.

Edit: Den Long Mode hab ich aus einem Tut genommen, der ist aber... ääh.... Limit = 0, kein Kommentar.
« Letzte Änderung: 02. March 2013, 17:06 von tiger717 »

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 02. March 2013, 17:15 »
Edit: Den Long Mode hab ich aus einem Tut genommen, der ist aber... ääh.... Limit = 0, kein Kommentar.
Limit wird im LM ignoriert. Wenn du in den LM switchst, lädst du vermutlich DS, ES usw. ? lade da auch mal das SS neu.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

tiger717

  • Beiträge: 84
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 02. March 2013, 17:28 »
Nee neem, es passt jetzt schon. Das Tutorial gehört übrigens verboten (Create Long Mode Kernel oder sowas auf os-dev.org), ist jetzt schon der dritte schwerwiegende Fehler im Code.

Kann sich jemand einen Reim drauf machen, warum QEMU DS16 ausspuckt?

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 02. March 2013, 17:46 »
Nee neem, es passt jetzt schon.
Mich interessiert jetzt aber was genau es war. :wink: Am Limit wird es nicht gelegen haben, oder?
Zitat
Das Tutorial gehört übrigens verboten (Create Long Mode Kernel oder sowas auf os-dev.org), ist jetzt schon der dritte schwerwiegende Fehler im Code.
Ist ein Wiki oder?
Zitat
Kann sich jemand einen Reim drauf machen, warum QEMU DS16 ausspuckt?
Im LM wird der descriptor fast vollständig ignoriert, der würde im PM wohl als 16 bit daten segment interpretiert werden.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

SHyx0rmZ

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 02. March 2013, 18:23 »
Im LM wird der descriptor fast vollständig ignoriert, der würde im PM wohl als 16 bit daten segment interpretiert werden.
Um genau zu sein, wird bis auf folgende Ausnahmen alles misachtet:
  • Bei CS werden das Long Attribute Bit, Code-Segment Default-Operand Size Bit und das Descriptor Privilege-Level Field beachtet.
  • Bei FS und GS wird die Segment Base Address zur Berechnung von Adressen genutzt.
Stattdessen prüft der Prozessor im Long Mode, ob die virtuellen Adressen kanonisch sind.
@X="krJhbuaesrytre c a cnR.ohut";while@X[/(..)(.)/];@X=@X[3..-1]+$1;print$2;end
"Scheiß auf Perl, wir haben Kekse" - Emperor Ruby

tiger717

  • Beiträge: 84
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 03. March 2013, 15:29 »
Ich nehme mal an, der GDT war letztlich der Übeltäter.  Das Tutorial: http://wiki.osdev.org/User:Stephanvanschaik/Setting_Up_Long_Mode

 

Einloggen