Beiträge anzeigen

Diese Sektion erlaubt es dir alle Beiträge dieses Mitglieds zu sehen. Beachte, dass du nur solche Beiträge sehen kannst, zu denen du auch Zugriffsrechte hast.


Nachrichten - Gotbread

Seiten: [1]
1
fehler gefunden  :|

statt "IRET" muss es "IRETD" heißen, damit er auch 32Bit werte nimmt...
selbes problem wie beim PUSHA/PUSHAD.

der erste assembler (NASM) hat dabei keinen unterschied gemacht.

jetzt läuft es wie es soll :)

trotzdem danke an euch ;)
2
die funktion ist zu 100% __cdecl, und die interrupt-stubs sind alles
__declspec(naked) funktionen (es wird also kein pro oder epilog erzeugt).

ich kann ja in bochs durch meinen handler (in asm) laufen, mir fällt da
nix besonderes auf.

edit:

sogar wenn ich sofort "IRET" ausfürhe, fliegt die exception. hier mal ein trace:
http://codepad.org/68iq7TpK
3
nach langwiriges debuggen habe ich einen fehler gefunden.
pusha hat nur 16bit-register gepusht, richtig wäre pushad gewesen.
einige assembler ignorieren das, einige anscheinend nicht.

nun stimmt auch die "regs" struktur wieder :)

in den protected mode komme ich via

mov eax, cr0      ; switch-over to Protected Mode
or  eax, 1        ; set bit 0 of CR0 register
mov cr0, eax      ;

jmp 0x8:ProtectedMode

[Bits 32]

ProtectedMode:
mov    ax, 0x10
mov    ds, ax      ; data descriptor --> data, stack and extra segment
mov    ss, ax           
mov    es, ax
xor    eax, eax    ; null desriptor --> FS and GS
mov    fs, ax
mov    gs, ax
mov    esp, 0x1FFF00 ; set stack below 2 MB limit

da bochs seine address-anzeige auf 32 Bit erweitert, sieht man dass
er sich im protected-mode befindet. außerdem ist dieser teil
des codes nicht von dem compilerwechsel betroffen
(vor dem wechsel funktionierte das ganze komischerweise).

da sollte der fehler also nicht liegen.

vor dem cli (am anfang vom IRQ0 handler)

hat CS den wert 0x08 (DS, SS und ES sind 0x10). diese werte
stimmen mit der GDT überein.

Zitat von: erik.vikinger
Legst Du für die Nicht-Exception-Interrupts einen Pseudo-Error-Code auf den Stack? Viele machen das um im generischen Interrupthandler immer einen identischen Stack-Aufbau zu haben.

ja, im falle des IRQ0 lege ich zuerst 0 (fehlercode, DWORD), und dann
0x20 (nummer des interrupt, DWORD) auf den stack.

vor dem ersten push am anfang des stubs, also direkt am anfang des
interrupts zeigt esp auf 0x1ffe70. nachdem die struktur vollständig
auf dem stack liegt, und bevor sie an den C-handler übergeben wird,
enhält sie folgende werte:

gs : 00000000
fs : 00000000
es : 00000010
ds : 00000010
edi: 00008200 // basisaddresse des C-kernels, vllt hat edi solange überlebt
esi: 0000c800
ebp: 001ffe84
esp: 001ffe68
ebx: 00000000
edx: 00000013
ecx: 0000c40b
eax: 00000be4
int_nummer: 00000020 // stimmt
err_code: 00000000 // stimmt auch
eip: 0000b7af
cs : 00000008 // stimmt
flags: 00000206
useresp: 000b8000
ss : 00000be4

dieses gebilde liegt bei 0x1ffe38, d.h. der esp ist seit begin des interrupts
14 DWords gewandert. diese zahl entspricht der register (struct regs),
die manuell auf den stack gelegt werden.

bevor "IRET" ausgeführt wird, zeigt esp wieder auf 0x1ffe70.

danach fliegt sofort die exception, d.h. ich lande mit dem debugger wieder
beim "CLI" eines interrupt-stubs, (0xD -> GPF)

nach dem IRET und vor dem CLI haben die segmentregister jedoch
korrekte werte (CS = 0x8, DS, SS, ES = 0x10) ??

wenn ich im C-handler die regs-struktur dumpe, erhalte ich auch die
selben werte. verändern tue ich sie nicht...

padding ist auf 1 byte, und die größe der struktur stimmt auch
(19 DWORDs).

da ich im kernelmode bin, haben USERESP und SS keine werte vom
int bekommen...
4
hm zu wenig infos. sorry :(

das die IDT stimmt, sehe ich durch den bochs-debugger.
ich kann einen haltepunkt an der stelle des "cli" setzen,
(am anfang des interrupt-stubs)
der dann auch angesprungen wird, und zwar der IRQ0,
also der timer.

danach kann ich schritt für schritt durch den handler laufen,
bis zum iret. nach dem iret kommt sofort wieder eine exception,
nämlich eine generell protecton fault (0x0D).

auch hier kann ich wieder in den handler reinspringen. sobald
er jedoch beim iret angelangt ist, fliegt die nächste GPF.

in dieser endlos-schleife bleibt er dann, und das ausgabelog
meldet mir jedesmal "iret: return CS selector null"

da der fehler auch mit einem minimalen handler auftritt, muss
der fehler im interrupt-stub liegen.

der exceptionhandler sieht wie folgt aus: (gekürzt)
void fault_handler(regs* r)
{
    if (r->int_no < 32)
    {
        // fehler anzeigen und anhalten.
    }
}

diese bedingung < 32 tritt nie auf, int_no ist 0x10002
(obwohl der fehlercode eigentlich 0xD sein sollte).

beim anfang des interrupt-stubs, ist der stackpointer bei
0x1ffe8c, im kernel-stack.
nach den beiden push's zeigt esp auf 0x1ffe84, es wurden
wirklich 2 DWords gepusht.

danach verfolge ich das ganze bis vor den aufruf des C-handlers.
esp hat hier den wert 0x1ffe64, und wird als parameter
übergeben (mov eax, esp, push eax)

diesen wert kann ich mir auch ausgeben lassen, allerdings
enthällt CS hier komischerweise den wert 0x8A32.

ein dump der stelle 0x1ffe64 ergibt:

00000000 00000000 00000010 00000010
C8008200 FE84FE9C 00130000 0001C40B
00000020 00000000 00008BEF 00000008
00000212 000016A7 001FFED4 00008A32
0000BA84 00000000 00000000 0000CDBC

dies passt jedoch nicht in die struktur regs,
hier scheinen werte verrutscht zu sein.

struct regs
{
unsigned int gs, fs, es, ds;
unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;
unsigned int int_no, err_code;
unsigned int eip, cs, eflags, useresp, ss;
};

padding ist natürlich ausgestellt.
5
Hallo :)

ich habe ein problem mit meinem interupthandler. die
IDT ist richtig aufgesetzt, aber wenn ich die interrupts aktiviere,
bekomme ich diese meldung, und das OS hängt sich auf.

interrupt_stub für den IRQ0
cli
push 0
push 32
jmp irq_common_stub
// ....
pusha
push ds
push es
push fs
push gs

mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, esp

push eax
mov eax, irq_handler
call eax
pop eax

pop gs
pop fs
pop es
pop ds
popa
add esp, 8
iret

der dazugehörige (minimale) C-handler

unsigned irq_handler(regs* r)
{

    if (r->int_no >= 40)
        outportb(0xA0, 0x20);

    outportb(0x20, 0x20);

    return (unsigned)r;
}

komischerweise ist "r->int_no" laut bochs 0x212.
wahrscheinlich ist die regs struktur beschädigt.

mein verdacht ist, dass am anfang:
cli
push 0
push 32
jmp irq_common_stub

nur 2 Bytes statt 2 DWords gepusht werden. der disassembler sagt:

cli                     FA
push 0             6A 00 ??
push 32           6A 29 ??
mp irq_common_stub

ich nutze den msvc-inline-assembler. wie kann ich den
dazu bringen, DWORDs zu pushen? "oush dword 0" geht nicht :(

danke im voraus
Seiten: [1]

Einloggen