Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: livinskull 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
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
-
Jetzt bekomm ich dauernd ne General protection Fault und Bochs sagt
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.
-
SS ist 0x10. und CS ist zu dem Zeitpunkt 0x08
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
-
So.
Es geht genau einmal in den Interrupthandler, scheduler läuft durch alles wunderbar bis zum iret. Da sieht die Situation dann so aus:
| 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
-
Dann kannst du dir sie ja mal zum fraglichen Zeitpunkt anschauen. Das geht im Debugger mit info gdt.
-
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 =)
-
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
-
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.
-
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:
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:
<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:
<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 -.-