Autor Thema: Multitasking Versuch: CS ungültig  (Gelesen 7148 mal)

livinskull

  • Beiträge: 27
    • Profil anzeigen
    • Livinskulls site
Gespeichert
« am: 17. May 2010, 01:08 »
Huhu,

Bin dabei Multitasking einzubauen, teilweise nach dem Tutorial aus dem Wiki.
Jetzt bekomm ich dauernd ne General protection Fault und Bochs sagt
Zitat
00189211808e[CPU0 ] check_cs(0x001b): not a valid code segment !

Der GDT Code hatte davor ohne Probleme funktioniert, ich denk den kann man als fehlqerquelle ausschliessen...

GDT-Setup:
void gdt_install() {
   
    gp.limit = (sizeof(struct gdt_entry) * 6) - 1;
    gp.base = (uint32_t) &gdt;

   
    gdt_set_gate(0, 0, 0, 0, 0);

    // kernel code segment
    gdt_set_gate(1, 0, 0xFFFFFFFF, GDT_FLAG_SEGMENT | GDT_FLAG_CODESEG | GDT_FLAG_PRESENT, GDT_FLAG_32_BIT | GDT_FLAG_4K_GRAN);

    // kernel data segment
    gdt_set_gate(2, 0, 0xFFFFFFFF, GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT, GDT_FLAG_32_BIT | GDT_FLAG_4K_GRAN);

//user segments
gdt_set_gate(3, 0, 0xFFFFFFFF, GDT_FLAG_SEGMENT | GDT_FLAG_CODESEG | GDT_FLAG_PRESENT | GDT_FLAG_RING3, GDT_FLAG_32_BIT | GDT_FLAG_4K_GRAN);
gdt_set_gate(4, 0, 0xFFFFFFFF, GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT | GDT_FLAG_RING3, GDT_FLAG_32_BIT | GDT_FLAG_4K_GRAN);

//TSS
gdt_set_gate(5, (uint32_t) tss, sizeof(tss), GDT_FLAG_TSS | GDT_FLAG_PRESENT | GDT_FLAG_RING3, 0);

   
    gdt_flush();
    __asm__ __volatile__("ltr %%ax" : : "a" (5 << 3));
}

IRQ-handling:
irq0:
    cli
    push byte 0
    push byte 32
    jmp irq_common_stub


irq_common_stub:
    pusha
    push ds
    push es
    push fs
    push gs

;load kernel segments
    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
    mov esp, eax

;mov ax, 0x23
;mov ds, ax
;mov es, ax
;mov gs, ax
;mov fs, ax
    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8
    sti
    iret

irq_handler:
regs *irq_handler(regs *r) {
    void (*handler)(regs *r);
    regs *new_regs = r;
   
    handler = irq_routines[r->int_no - 32];
    if (handler)
        handler(r);
       
    if (r->int_no == 0x20) {  // INT 0x20, IRQ0, timer interrupt
    new_regs = schedule(r);
    tss[1] = (uint32_t) (new_regs + 1);
}

// EOI to slave controller
    if (r->int_no >= 40)
        outb(0xA0, 0x20);

    // EOI to master
    outb(0x20, 0x20);
   
    return new_regs;
}

uund die tasks mit scheduler
regs *schedule(regs *r) {
current_task->cpu_state = r;

if (current_task->time_left > 0) {
current_task->time_left -= TASK_TIMESLICE;
} else {
current_task->time_left = TASK_TIMESLICE * current_task->priority;
current_task->state = READY;

do {
current_task = current_task->next?current_task->next:first_task;
} while (current_task->state == BLOCKED);
current_task->state = RUNNING;
}

return current_task->cpu_state;
}

task *init_task(void *entrypoint, char *name, uint8_t priority) {
uint8_t *user_stack = (uint8_t *) pmm_alloc();
uint8_t *stack = (uint8_t *) pmm_alloc();

regs new_state = {
.eax = 0, .ebx = 0, .ecx = 0, .edx = 0, .esi = 0, .edi = 0,
.ebp = 0, .esp = (uint32_t) user_stack + 4096,
.eip = (uint32_t) entrypoint,
.cs = (0x03<<3) | 0x03, //ring 3 segments
.ss = (0x04<<3) | 0x03,
.es = (0x04<<3) | 0x03,
.fs = (0x04<<3) | 0x03,
.gs = (0x04<<3) | 0x03,
.ds = (0x04<<3) | 0x03,
.eflags = 0x200 //interrupts on
};

regs *state = (void *) (stack + 4096 - sizeof(new_state));
*state = new_state;

task* new_task = pmm_alloc();
new_task->cpu_state = state;
new_task->name = name;
new_task->priority = priority;
new_task->time_left = TASK_TIMESLICE + priority;
new_task->pid = next_pid++;
new_task->state = CREATED;
new_task->next = first_task;
first_task = new_task;

return new_task;
}

kann mir wer weiterhelfen? =)

Greetz, livinskull


Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 17. May 2010, 02:50 »
Jetzt bekomm ich dauernd ne General protection Fault und Bochs sagt
Zitat
00189211808e[CPU0 ] check_cs(0x001b): not a valid code segment !
Wann genau bekommst du diese Meldung? Ich vermute bei einem IRET (ist es das in irq_common_stub?), aber wechselst du dann gerade zum ersten mal vom Kernel Mode in den User Mode, oder von einem gerade abgelaufenen Task zu einem der schon mal (oder noch nie) gelaufen ist, oder was ganz anderes?

Ansonsten als allgemeiner Tipp, bevor du die erste Fehlerquelle, die dir einfällt, ausschließt: In Bochs einen Breakpoint davor setzen und nachschauen was wirklich in der GDT steht.

Die einzige alternative Theorie, die ich anbieten kann ist, dass RPL in CS und SS (d.h. vermutlich SS = 0x10) unterschiedlich sind. Aber darauf passt der Wortlaut der Meldung leider nicht so ganz.
« Letzte Änderung: 17. May 2010, 02:52 von PorkChicken »
Dieser Text wird unter jedem Beitrag angezeigt.

livinskull

  • Beiträge: 27
    • Profil anzeigen
    • Livinskulls site
Gespeichert
« Antwort #2 am: 17. May 2010, 03:02 »
SS ist 0x10. und CS ist zu dem Zeitpunkt 0x08
Zitat
00189211808e[CPU0 ] check_cs(0x001b): not a valid code segment !
00189590351i[CPU0 ] WARNING: HLT instruction with IF=0!
00422880000p[XGUI ] >>PANIC<< POWER button turned off.
00422880000i[CPU0 ] CPU is in protected mode (halted)
00422880000i[CPU0 ] CS.d_b = 32 bit
00422880000i[CPU0 ] SS.d_b = 32 bit
00422880000i[CPU0 ] EFER   = 0x00000000
00422880000i[CPU0 ] | RAX=000000000000000d  RBX=0000000000000000
00422880000i[CPU0 ] | RCX=0000000000000550  RDX=00000000000003d5
00422880000i[CPU0 ] | RSP=0000000001004f60  RBP=0000000001004f9c
00422880000i[CPU0 ] | RSI=0000000000000000  RDI=0000000000000000
00422880000i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00422880000i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00422880000i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00422880000i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00422880000i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf ZF af PF cf
00422880000i[CPU0 ] | SEG selector     base    limit G D
00422880000i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00422880000i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00422880000i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00422880000i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00422880000i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
00422880000i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00422880000i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00422880000i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00422880000i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00422880000i[CPU0 ] | RIP=0000000000101fce (0000000000101fce)
00422880000i[CPU0 ] | CR0=0x60000011 CR1=0x0 CR2=0x0000000000000000
00422880000i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00422880000i[CPU0 ] >> ret  : C3

Und in den Interrupthandler gehts auf jeden Fall noch rein, bis nach den Scheduler, ich vermute also das tritt erst kurz vor dem iret auf (ja genau das in der irq stub).
Und mit debugging unter Bochs kenn ich mich noch nicht so gut aus, das einzge was ich n paarmal gemacht hab war mehr debugging ausgaben rauszulassen ...

EDIT: es geht einmal in den Handler rein, beim iret crashts dann und baut nen GP-fault mit Fehlercode 0x18 was ein Zugriff auf das user-code segment mir pl0 wäre

EDIT2: Wenn ich die 2 tasks die ich zum Testen verwende weglasse und nur mti init_multitasking() einen Kernel-task erstell läuft alles wunderbar
« Letzte Änderung: 17. May 2010, 23:06 von livinskull »


livinskull

  • Beiträge: 27
    • Profil anzeigen
    • Livinskulls site
Gespeichert
« Antwort #3 am: 18. May 2010, 00:44 »
So.
Es geht genau einmal in den Interrupthandler, scheduler läuft durch alles wunderbar bis zum iret. Da sieht die Situation dann so aus:
Zitat
| STACK 0x01004fec [0x001024ed]    //EIP
 | STACK 0x01004ff0 [0x0000001b]    //CS (=user-code mit pl3)
 | STACK 0x01004ff4 [0x00000200]    //EFLAGS
 | STACK 0x01004ff8 [0x01004000]    //esp
 | STACK 0x01004ffc [0x00000023]    //ss (=user-data mit pl3)
Auch alles in Ordnung, trotzdem gibts einen Protection Fault wenn das iret dann ausgeführt wird.. evt liegts doch an der GDT o.O


Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 18. May 2010, 00:52 »
Dann kannst du dir sie ja mal zum fraglichen Zeitpunkt anschauen. Das geht im Debugger mit info gdt.
Dieser Text wird unter jedem Beitrag angezeigt.

livinskull

  • Beiträge: 27
    • Profil anzeigen
    • Livinskulls site
Gespeichert
« Antwort #5 am: 18. May 2010, 01:00 »
Oha ich bin immer direkt ind en Speicher dahin gesprungen und bin nicht draus schlau geworden =D

Tatsächlich.. der Eintrag fürs User-Code-Segment ist irgendwie verhaut o.O
Na denn mal demnächst den GDT Code auch mal re-coden...
Danke =)


livinskull

  • Beiträge: 27
    • Profil anzeigen
    • Livinskulls site
Gespeichert
« Antwort #6 am: 18. May 2010, 10:50 »
Lol... wenn man mehr Einträge in die GDT schreibt sollet man auch nicht mehr struct gdt_entry[3] schreiben....

Naja.. jetzt wird in den task gesprungen, allerdings scheint kprintf() im user mode nicht zu funktionieren -.-
Rattert ewig über den string als würde es kein '\0' finden und dann haut Bochs ab mit nem ungültigem Speicherzugriff ewig über dem Bildschirmspeicher.
Kann das daran liegen das ne Kernel-funktion im Usermode aufgerufen wird?
Müsste dann wohl erst syscalls implementieren bevor multitasking läuft o.O


Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 18. May 2010, 13:29 »
Rattert ewig über den string als würde es kein '\0' finden und dann haut Bochs ab mit nem ungültigem Speicherzugriff ewig über dem Bildschirmspeicher.
Ich denke mal das bedeutet, dass es überhaupt nicht der richtige String ist, den kprintf in die Finger bekommt. Vielleicht ist der Stack kaputt, z.B. wird überschrieben.

Kann das daran liegen das ne Kernel-funktion im Usermode aufgerufen wird?
Kann, muss aber nicht. Kommt drauf an. Ich nehme mal an, dass zur Zeit dein User Code ja noch in der Kernel Binary enthalten ist, und deswegen die korrekte Adresse von kprintf kennen müsste.
Dieser Text wird unter jedem Beitrag angezeigt.

livinskull

  • Beiträge: 27
    • Profil anzeigen
    • Livinskulls site
Gespeichert
« Antwort #8 am: 19. May 2010, 21:00 »
Der Stack ist noch in Ordnung..
hier hängts sich auf: (kprintf-code)
movzx eax, byte ptr ds:[eax]wobei an ds:[eax] der richtige String steht (auch null-terminiert!)

Dazu hab ich gefunden das es einen GP fault gibt wenn:
Zitat
GP:   If a memory operand effective address is outside the CS, DS, ES, FS, or GS segment limit. If the DS, ES, FS, or GS register contains a null segment selector.
siehe http://siyobik.info/index.php?module=x86&id=209, btw das ist eine nette Referenz ;)

ALLERDINGS:
Die Segment-limits passen alle:
Zitat
<bochs:55> info gdt
Global Descriptor Table (base=0x00125020, limit=47):
GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x01]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Accessed, 32-bit
GDT[0x02]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
GDT[0x03]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Accessed, 32-bit
GDT[0x04]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
GDT[0x05]=32-Bit TSS (Busy) at 0x00103040, length 0x00080

Und es ist auch in keinem Segment register der nulldeskriptor referenziert:
Zitat
<bochs:57> sreg
es:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=1
   Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
cs:0x0008, dh=0x00cf9b00, dl=0x0000ffff, valid=1
   Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Accessed, 32-bit
ss:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=7
   Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
ds:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=7
   Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
fs:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=1
   Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
gs:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=1
   Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1
tr:0x0028, dh=0x0000eb10, dl=0x30400080, valid=1
gdtr:base=0x00125020, limit=0x2f
idtr:base=0x00125080, limit=0x7ff
any ideas?  :?

EDIT: die tasks sind in der kernel binary, werden bloss als user-code ausgeführt...

EDIT1: oh moment die Zusatzregister inkl DS sind kernel mode ....
EDIT1: jetz gehts natürlich, allerdings nur bis der erste task abgebrochen wird -.-
« Letzte Änderung: 19. May 2010, 21:16 von livinskull »


 

Einloggen