Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: micha am 12. April 2012, 19:55
-
Hi,
Nachdem ich jetzt das Multitasking in Ring 0 hinbekommen habe, wollte ich jetzt das genze nach ring 3 verschieben.
Nur leider kommen As bis zum nächsten Timerinterrupt und dann meldet qemu: fatal: trying to execute code outside RAM or ROM.(oder so ähnlich)
könnte da mal jemand drübergucken?
multitasking.c
#include <stdint.h>
#include "gdt.h"
#include "interrupt.h"
#include "cpu.h"
#include "console.h"
/* ---------- Globale Variablen ----------------------- */
static uint8_t stack_a[4096];
static uint8_t stack_b[4096];
static uint8_t user_stack_a[4096];
static uint8_t user_stack_b[4096];
static int current_task = -1;
static int num_tasks = 2;
static cpu_state* task_states[2];
/* --------- Tasks ------------- */
void task_a(void){
while(1){
setColor(0x02);
printf("A");
}
}
void task_b(void){
while(1){
setColor(0x06);
printf("B");
}
}
/* ---------- Task initalisieren ---------------------- */
cpu_state* init_task(uint8_t *stack, uint8_t *user_stack, void *entry){
cpu_state 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) entry,
// Ring-3 Segmentregister
.cs = 0x1b /*0x18 | 0x03*/,
.ss = 0x23 /*0x20 | 0x03*/,
// IRQs einschalten
.eflags = 0x202,
};
cpu_state *state = (void*) (stack + 4096 - sizeof(new_state));
*state = new_state;
return state;
}
/* ---------- Multitasking initalisieren -------------- */
void init_multitasking(void){
task_states[0] = init_task(stack_a, user_stack_a, task_a);
task_states[1] = init_task(stack_b, user_stack_b, task_b);
cpu_dump(task_states[0]);
cpu_dump(task_states[1]);
}
/* ---------- Scheduler ------------------------------- */
cpu_state* schedule(cpu_state *cpu){
// Alten zustand des Tasks sichern
if(current_task >= 0){
task_states[current_task] = cpu;
}
// Nächsten Task auswählen
current_task++;
current_task %= num_tasks;
// Neuen Task aktivieren
cpu = task_states[current_task];
return cpu;
}
timer_irq_handler.c
#include <stdint.h>
#include "cpu.h"
#include "gdt.h"
#include "multitasking.h"
static uint32_t tss[TSS_SIZE];
cpu_state* timer_irq_handler(cpu_state *cpu){
cpu_state *new_cpu = schedule(cpu);
tss[1] = (uint32_t) (new_cpu + 1);
send_eoi(0);
return new_cpu;
}
irq handler:
// Gemeinsamer interrupt handler
.extern common_intrpt_handler
.extern common_intrpt_handler_with_new_cpu
// IRQ - Handler
.extern timer_irq_handler
.extern keyboard_irq_handler
.macro irq_empty nr
.global int_handler\nr
int_handler\nr:
iret
.endm
.macro irq nr isr
.global int_handler\nr
int_handler\nr:
push $0
push $\nr
push $\isr
jmp common_intrpt_handler
.endm
.macro irq_with_new_cpu nr isr
.global int_handler\nr
int_handler\nr:
push $0
push $\nr
push $\isr
jmp common_intrpt_handler_with_new_cpu
.endm
irq_with_new_cpu 0x20 timer_irq_handler
irq 0x21 keyboard_irq_handler
irq_empty 0x22
irq_empty 0x23
irq_empty 0x24
irq_empty 0x25
irq_empty 0x26
irq_empty 0x27
irq_empty 0x28
irq_empty 0x29
irq_empty 0x2A
irq_empty 0x2B
irq_empty 0x2C
irq_empty 0x2D
irq_empty 0x2E
irq_empty 0x2F
//Ende - handler.S
common handler:
.global common_intrpt_handler_with_new_cpu
common_intrpt_handler_with_new_cpu:
// ISR nach eax legen
pop %ebx
push %ebp
push %edi
push %esi
push %edx
push %ecx
push %ebx
push %eax
// Kernel-Datensegmente laden
mov $0x10, %ax
mov %ax, %ds
mov %eax, %es
// ISR aufrufen
push %esp
call *%ebx
mov %eax, %esp //Neuen Stack laden
// User-Datensegmente laden
mov $0x23, %ax
mov %ax, %ds
mov %ax, %es
// Neue cpu herstellen
pop %eax
pop %ebx
pop %ecx
pop %edx
pop %esi
pop %edi
pop %ebp
// Errorcode und Interruptnummer vom Stack nehmen
add $8, %esp
iret
gdt.c
#include <stdint.h>
#include "gdt.h"
/* ---------- Globale Variablen ----------------------- */
static uint64_t gdt[GDT_ENTRIES]; //Global Deskriptor Table
static uint32_t tss[TSS_SIZE] = {0, 0, 0x10}; //Task State Segment
/* ---------- Eintrag in die GDT setzen --------------- */
void set_gdt_entry(int i, uint32_t limit, uint32_t base, uint8_t access, uint8_t flags){
gdt[i] = 0;
//untere 32-Bit
gdt[i] = (limit & 0x0ffff) | ((base & 0x0000ffff) << 16);
//obere 32-Bit
gdt[i] |=(
( (base & 0x00ff0000) >> 16 ) |
( access << 8 ) |
( flags << 16 ) |
( (limit & 0xf0000) << 4) |
( (base & 0xff000000) << 56 )
) * 0x100000000;
}
/* ---------- GDT Laden (GDTR ändern) ----------------- */
void load_gdt(void){
struct {
uint16_t size;
uint64_t *pointer;
} __attribute__((packed)) gdtp = {
.size = GDT_ENTRIES * 8 - 1,
.pointer = gdt,
};
asm volatile("lgdt %0" : : "m" (gdtp));//GDT Laden
}
/* ---------- GDT initalisieren ----------------------- */
void init_gdt(void){
//Nulldeskriptor
set_gdt_entry(0, 0, 0, 0, 0);
//Kernel - Codesegment
set_gdt_entry(1, 0xfffff, 0, //index, limit, base
GDT_CODESEG_RD | GDT_SEGMENT | GDT_RING0 | GDT_PRESENT,//Access-Byte
GDT_32_BIT | GDT_4K_GRAN); //Flags
//Kernel - Datensegment
set_gdt_entry(2, 0xfffff, 0, //index, limit, base
GDT_DATASEG_WR | GDT_SEGMENT | GDT_RING0 | GDT_PRESENT,//Access-Byte
GDT_32_BIT | GDT_4K_GRAN); //Flags
//Userspace - Codesegment
set_gdt_entry(3, 0xfffff, 0, //index, limit, base
GDT_CODESEG_RD | GDT_SEGMENT | GDT_RING3 | GDT_PRESENT,//Access-Byte
GDT_32_BIT | GDT_4K_GRAN); //Flags
//Userpsace - Datensegment
set_gdt_entry(4, 0xfffff, 0, //index, limit, base
GDT_DATASEG_WR | GDT_SEGMENT | GDT_RING3 | GDT_PRESENT,//Access-Byte
GDT_32_BIT | GDT_4K_GRAN); //Flags
//Task State Segment
set_gdt_entry(5, sizeof(tss)-1, (uint32_t) &tss, //index, limit, base
GDT_TSS | GDT_PRESENT | GDT_RING3, //Access-Byte
GDT_32_BIT | GDT_4K_GRAN); //Flags
// nach ss0 das Kernel Datensegment legen
tss[2] = 0x10;
}
/* ---------- GDT schnell initalisieren --------------- */
void init_gdt_fast(void){
gdt[0] = 0x0000000000000000;//Nulldeskriptor
gdt[1] = 0x00FC9A000000FFFF;//Kernel - Codesegment
gdt[2] = 0x00FC92000000FFFF;//Kernel - Datensegment
gdt[3] = 0x00FCFA000000FFFF;//Userspace - Codesegment
gdt[4] = 0x00FCF2000000FFFF;//Userpsace - Datensegment
// gdt[5] = 0x0000000000000000;//Task State Segment
}
/* ---------- Segmenregister neuladen ----------------- */
void reload_segment_registers(void){
asm volatile(
"ljmpl $0x08, $1f\n\t"
"1:\n\t"
"mov $0x10, %eax\n\t"
"mov %eax, %ds\n\t"
"mov %eax, %es\n\t"
"mov %eax, %fs\n\t"
"mov %eax, %gs\n\t"
"mov %eax, %ss\n\t"
);
}
/* ---------- Taskregister neuladen ------------------- */
void reload_task_registers(void){
asm volatile("ltr %%ax" : : "a" (5 << 3));
}
-
könnte es sein, dass sich jetzt der Fehler in der GDT bemerkbar macht?
Was mache ich da überhaupt für einen Fehler? (in set_gdt_entry)
LG micha
-
Ja, die GDT-Einträge setzt du nicht richtig.
//obere 32-Bit
gdt[i] |=(
( (base & 0x00ff0000) >> 16 ) |
( access << 8 ) |
( flags << 16 ) |
( (limit & 0xf0000) << 4) |
( (base & 0xff000000) << 56 )
) * 0x100000000;
Die oberen 4 Bits von Limit (Bits 16 bis 19, also limit & 0xf0000) müssen an die Bitpositionen 16 bis 19 des oberen Worts. Siehe Grafik hier: http://www.lowlevel.eu/wiki/GDT#Struktur Also bleiben die an der selben Stelle. Das heißt kein Shift um 4 nötig.
Dann müssen die oberen 8 Bits von base (Bits 24 bis 31, also base & 0xff000000) an die Bitpositionen 24 bis 31 des oberen Worts. Also bleiben die auch an der selben Stelle. Das heißt kein Shift um 56 nötig. Außerdem wäre der Shift zusammen mit der Multiplikation ein Shift um 56+32=88 Bits ...
Ob das das Problem löst, weiß ich nicht.
-
Nunja. Nur das wirds wohl nicht allein gewesen sein. Es gibt also auch noch andere Fehler.
Immerhin springt er jetzt nicht mehr irgendwo hin und versucht irgendeinen Quatsch auszuführen.....er startet neu.
Liegt das dann an dem TSS? Das sollte doch eigentlich stimmen.?
-
Die Flags für den TSS-Deskriptor sehen nach Copy&Paste aus. Da sollteste noch mal gucken.
-
Also im Wiki-Artikel TSS steht da nix über die Flags in der GDT.
hab auch mal mit 0 in den Flags probiert: kein Unterschied
-
Probier mal 0x89. Die 8 ist das present flag und die 9 ist der in http://www.lowlevel.eu/wiki/TSS erwähnte type.
-
keine Änderung :-(
qemu startet auch schon beim neuladen der Segmentregister neu
-
Also jetzt nochmal zur Zusammenfassung.
Mein Problem liegt jetzt in der GDT.
der Code:
gdt.c
#include <stdint.h>
#include "gdt.h"
//Acessbyte
#define GDT_PRESENT 0x80
#define GDT_SEGMENT 0x10
#define GDT_RING0 0x00
#define GDT_RING3 0x60
#define GDT_CODESEG_NR 0x00
#define GDT_CODESEG_RD 0x0A
#define GDT_DATASEG_RD 0x00
#define GDT_DATASEG_WR 0x02
#define GDT_TSS 0x09
//Flags
#define GDT_4K_GRAN 0x08
#define GDT_32_BIT 0x04
/* ---------- Globale Variablen ----------------------- */
static uint64_t gdt[GDT_ENTRIES]; //Global Deskriptor Table
static uint32_t tss[TSS_SIZE] = {0, 0, 0x10}; //Task State Segment
/* ---------- Eintrag in die GDT setzen --------------- */
void set_gdt_entry(int i, uint32_t limit, uint32_t base, uint8_t access, uint8_t flags){
gdt[i] = 0;
//untere 32-Bit
gdt[i] = (limit & 0x0ffff) | ((base & 0x0000ffff) << 16);
//obere 32-Bit
gdt[i] |=(
( (base & 0x00ff0000) >> 16 ) |
( access << 8 ) |
( flags << 16 ) |
( limit & 0xf0000 ) |
( base & 0xff000000 )
) * 0x100000000;
}
/* ---------- GDT Laden (GDTR ändern) ----------------- */
void load_gdt(void){
struct {
uint16_t size;
uint64_t *pointer;
} __attribute__((packed)) gdtp = {
.size = GDT_ENTRIES * 8 - 1,
.pointer = gdt,
};
asm volatile("lgdt %0" : : "m" (gdtp));//GDT Laden
}
/* ---------- GDT initalisieren ----------------------- */
void init_gdt(void){
//Nulldeskriptor
set_gdt_entry(GDT_ENTRY_NULL, 0, 0, 0, 0);
//Kernel - Codesegment
set_gdt_entry(GDT_ENTRY_KERNEL_CODE, 0xfffff, 0, //index, limit, base
GDT_CODESEG_RD | GDT_SEGMENT | GDT_RING0 | GDT_PRESENT,//Access-Byte
GDT_32_BIT | GDT_4K_GRAN); //Flags
//Kernel - Datensegment
set_gdt_entry(GDT_ENTRY_KERNEL_DATA, 0xfffff, 0, //index, limit, base
GDT_DATASEG_WR | GDT_SEGMENT | GDT_RING0 | GDT_PRESENT,//Access-Byte
GDT_32_BIT | GDT_4K_GRAN); //Flags
//Userspace - Codesegment
set_gdt_entry(GDT_ENTRY_USER_CODE, 0xfffff, 0, //index, limit, base
GDT_CODESEG_RD | GDT_SEGMENT | GDT_RING3 | GDT_PRESENT,//Access-Byte
GDT_32_BIT | GDT_4K_GRAN); //Flags
//Userpsace - Datensegment
set_gdt_entry(GDT_ENTRY_USER_DATA, 0xfffff, 0, //index, limit, base
GDT_DATASEG_WR | GDT_SEGMENT | GDT_RING3 | GDT_PRESENT,//Access-Byte
GDT_32_BIT | GDT_4K_GRAN); //Flags
//Task State Segment
set_gdt_entry(GDT_ENTRY_TSS, sizeof(tss)-1, (uint32_t) &tss,//index, limit, base
GDT_TSS | GDT_PRESENT | GDT_RING3, //Access-Byte
0); //Flags
// nach ss0 das Kernel Datensegment legen
tss[2] = 0x10;
}
/* ---------- GDT schnell initalisieren --------------- */
void init_gdt_fast(void){
gdt[0] = 0x0000000000000000;//Nulldeskriptor
gdt[1] = 0x00FC9A000000FFFF;//Kernel - Codesegment
gdt[2] = 0x00FC92000000FFFF;//Kernel - Datensegment
gdt[3] = 0x00FCFA000000FFFF;//Userspace - Codesegment
gdt[4] = 0x00FCF2000000FFFF;//Userpsace - Datensegment
set_gdt_entry(5, sizeof(tss)-1, (uint32_t) &tss, //index, limit, base
GDT_TSS | GDT_PRESENT | GDT_RING3, //Access-Byte
0); //Flags
// nach ss0 das Kernel Datensegment legen
tss[2] = 0x10;
}
/* -------Ende gdt.c ------*/
Um unnötige Fragen zu vermeiden: Ich verwende nicht init_gdt_fast sondern init_gdt!!
Wo steckt jetzt mein Fehler, dass Qemu beim beladen der Segmentregister neustertet? ( relaod_segment_registers(void) )
??? :?
Bzw. Warum startet Qemu nicht neu, wenn ich diese (falsche) Funktion verwende?:
/* ---------- Eintrag in die GDT setzen --------------- */
void set_gdt_entry(int i, uint32_t limit, uint32_t base, uint8_t access, uint8_t flags){
gdt[i] = 0;
//untere 32-Bit
gdt[i] = (limit & 0x0ffff) | ((base & 0x0000ffff) << 16);
//obere 32-Bit
gdt[i] |=(
( (base & 0x00ff0000) >> 16 ) |
( access << 8 ) |
( flags << 16 ) |
( (limit & 0xf0000) << 4) |
( base & 0xff000000 )
) * 0x100000000;
}
Micha
-
So. Das Problem mit der GDT habe ich jetzt nicht mehr (die Flags müssen um 20 geschoben werden). :-)
Allerdings hab ich jetzt ein anders problem:
Wenn ich mein Userspace-Codesegment auf ring-0 setze (das Segment für die Tasks) und in meinem init_task .cs auf 0x18 statt
0x1b setzte funktioniert das Multitasking , aber nur in Ring-0.
In Ring-3 geht das genze nicht: es kommt dann der Fehler von qemu: fatal: trying to execute code outside RAM or ROM at 0x...
d.h. er springt irgendwo hin.
könnt ihr mir da helfen?
-
Du könntest dir mal das Log von QEMU anschauen. Auch sind der Zustand der IDT und eventuell der GDT (und Segmentregister) interessant. Ansonsten könnte es auch ein Problem bei der Initialisierung des TSS bzw. Task Registers geben.
-
Mit meinem Wissen kann ich da nicht viel über den Sprung ins nichts herauslesen.
Das ist vielleicht was für die Experten
SMM: enter
EAX=00000001 EBX=80000b58 ECX=00000000 EDX=00000cfc
ESI=000e5cbd EDI=0003802d EBP=00000cf8 ESP=00006f00
EIP=000e7a31 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00cf9b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 000fce38 00000037
IDT= 000fdcf0 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=000e5c90 CCD=00000001 CCO=LOGICB
EFER=0000000000000000
SMM: after RSM
EAX=00000001 EBX=80000b58 ECX=00000000 EDX=00000cfc
ESI=000e5cbd EDI=0003802d EBP=00000cf8 ESP=00006f00
EIP=000e7a31 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 000fce38 00000037
IDT= 000fdcf0 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000000 CCD=ffffff9c CCO=EFLAGS
EFER=0000000000000000
0: v=21 e=0000 i=0 cpl=0 IP=0008:001022fd pc=001022fd SP=0010:00107f40 EAX=000000ed
EAX=000000ed EBX=0002c100 ECX=00000410 EDX=00000060
ESI=0002c276 EDI=0002c27b EBP=00107f78 ESP=00107f40
EIP=001022fd EFL=00000202 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0028 001041a0 0000007f 0000e900 DPL=3 TSS32-avl
GDT= 0010c8c0 0000002f
IDT= 00108000 000007f7
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000008 CCD=00107f30 CCO=SUBL
EFER=0000000000000000
1: v=21 e=0000 i=0 cpl=0 IP=0008:00102091 pc=00102091 SP=0010:00107fb0 EAX=00000000
EAX=00000000 EBX=0002c100 ECX=00000410 EDX=00000060
ESI=0002c276 EDI=0002c27b EBP=00107fc8 ESP=00107fb0
EIP=00102091 EFL=00000202 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0028 001041a0 0000007f 0000e900 DPL=3 TSS32-avl
GDT= 0010c8c0 0000002f
IDT= 00108000 000007f7
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000008 CCD=00107fa0 CCO=SUBL
EFER=0000000000000000
2: v=21 e=0000 i=0 cpl=0 IP=0008:001022fd pc=001022fd SP=0010:00107f40 EAX=000000f3
EAX=000000f3 EBX=0002c100 ECX=00000410 EDX=00000060
ESI=0002c276 EDI=0002c27b EBP=00107f78 ESP=00107f40
EIP=001022fd EFL=00000202 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0028 001041a0 0000007f 0000e900 DPL=3 TSS32-avl
GDT= 0010c8c0 0000002f
IDT= 00108000 000007f7
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000008 CCD=00107f30 CCO=SUBL
EFER=0000000000000000
3: v=21 e=0000 i=0 cpl=0 IP=0008:001020b1 pc=001020b1 SP=0010:00107fb0 EAX=00000000
EAX=00000000 EBX=0002c100 ECX=00000410 EDX=00000060
ESI=0002c276 EDI=0002c27b EBP=00107fc8 ESP=00107fb0
EIP=001020b1 EFL=00000202 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0028 001041a0 0000007f 0000e900 DPL=3 TSS32-avl
GDT= 0010c8c0 0000002f
IDT= 00108000 000007f7
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000008 CCD=00107fa0 CCO=SUBL
EFER=0000000000000000
4: v=21 e=0000 i=0 cpl=0 IP=0008:001022fd pc=001022fd SP=0010:00107f40 EAX=000000f4
EAX=000000f4 EBX=0002c100 ECX=00000410 EDX=00000060
ESI=0002c276 EDI=0002c27b EBP=00107f78 ESP=00107f40
EIP=001022fd EFL=00000202 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0028 001041a0 0000007f 0000e900 DPL=3 TSS32-avl
GDT= 0010c8c0 0000002f
IDT= 00108000 000007f7
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000008 CCD=00107f30 CCO=SUBL
EFER=0000000000000000
5: v=20 e=0000 i=0 cpl=0 IP=0008:001019cf pc=001019cf SP=0010:00107f90 EAX=00000001
EAX=00000001 EBX=0002c100 ECX=000006e0 EDX=000003d5
ESI=0002c276 EDI=0002c27b EBP=00107fc8 ESP=00107f90
EIP=001019cf EFL=00000202 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0028 001041a0 0000007f 0000e900 DPL=3 TSS32-avl
GDT= 0010c8c0 0000002f
IDT= 00108000 000007f7
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000004 CCD=0010caa0 CCO=EFLAGS
EFER=0000000000000000
6: v=20 e=0000 i=0 cpl=3 IP=001b:001013ba pc=001013ba SP=0023:0010b814 EAX=00000372
EAX=00000372 EBX=00000371 ECX=000b8000 EDX=000b8371
ESI=00000000 EDI=00000000 EBP=0010b84c ESP=0010b814
EIP=001013ba EFL=00000202 [-------] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
CS =001b 00000000 ffffffff 00cffa00 DPL=3 CS32 [-R-]
SS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
DS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
FS =0000 00000000 00000000 00000000
GS =0000 00000000 00000000 00000000
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0028 001041a0 0000007f 0000e900 DPL=3 TSS32-avl
GDT= 0010c8c0 0000002f
IDT= 00108000 000007f7
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000085 CCD=fffff472 CCO=EFLAGS
EFER=0000000000000000
qemu: fatal: Trying to execute code outside RAM or ROM at 0x665b6620
EAX=00000010 EBX=00000371 ECX=000b8000 EDX=000b8371
ESI=00000000 EDI=00000000 EBP=0010b84c ESP=ffffffc0
EIP=665b6620 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0000 00000000 00000000 00000000
GS =0000 00000000 00000000 00000000
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0028 001041a0 0000007f 0000e900 DPL=3 TSS32-avl
GDT= 0010c8c0 0000002f
IDT= 00108000 000007f7
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000085 CCD=fffff472 CCO=EFLAGS
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
-
qemu: fatal: Trying to execute code outside RAM or ROM at 0x665b6620
EAX=00000010 EBX=00000371 ECX=000b8000 EDX=000b8371
ESI=00000000 EDI=00000000 EBP=0010b84c ESP=ffffffc0
EIP=665b6620 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
Die interessanten Werte sind hier EIP (das ja auch in der Fehlermeldung erwähnt wird) und ESP. Der Wert in EIP sieht aus wie Maschinencode, was ich so interpretieren würde, dass in deinem Kernel (natürlich unbeabsichtigt) irgendwie ein ret ausgeführt wird, während der Stack Pointer auf Code zeigt. Dazu passt der Wert in ESP, der in einen Bereich zeigt, an dem das BIOS gemappt ist.
Meine Theorie dazu ist, dass irgendwo ESP mit 0 geladen wurde, und danach ein paar POPs/rets ausgeführt wurden. Du solltest also die Taskerzeugung, den Taskwechsler und den Scheduler genauer anschauen. Insbesondere solltest du versuchen rauszukriegen, ob der Task zu dem gewechselt wird, überhaupt gültig ist.
-
möglicherweise liegt das garnicht am Multitasking.
Wenn ich das aktivieren des neuen Tasks (cpu = task_states[current_task];) rusnehme und an das ende von init dies
while(1){
gets();
puts("\n");
}
setzte, kann man folgendes beobachten:
- wenn man ein Zeichen eingibt, geht alles
- wenn man zwei Zeichen eingibt geht alles
- wenn man drei Zeichen eingibt geht alles
- wenn man vier Zeichen eingibt kommt Invalid Opcode
- wenn man fünf und mehr eingibt kommt das problem wie beim Multitasking(trying to execute code outside RAM or ROM...)
Das image ist im Anhang
-
Okay. Das Merkwürdige Problem mit der Tastatureingabe hab ich jetzt gelöst. (ich habe den Rückgabewert von gets nicht beachtet)
Es steht aber immernoch das Problem mit den Ringen:
* in Ring-0 funktioniert das Multitasking
* in Ring-3 funktioniert es nicht. :-(
-
Meine Theorie dazu ist, dass irgendwo ESP mit 0 geladen wurde, und danach ein paar POPs/rets ausgeführt wurden. Du solltest also die Taskerzeugung, den Taskwechsler und den Scheduler genauer anschauen. Insbesondere solltest du versuchen rauszukriegen, ob der Task zu dem gewechselt wird, überhaupt gültig ist.
Frage: kann so ein Fehler nur in Assembler passieren oder geht das auch mit C?
-
Wenn du die Aufteilung C/Assembler so machst wie das Tutorial, dann ist der Fehler höchstwahrscheinlich im C-Teil und wird höchstwahrscheinlich im Assembler-Teil sichtbar.
-
Ich hab die GDT & IDT jetzt neu mit der geschickteren Variante über structs implementiert. Also daran liegts nicht.
Ich denke der Fehler müsste dann ist den Stubs liegen, eigentlich ist doch alles richtig.?!
// handle_interrupt aus common_handler.c
.extern handle_interrupt
.macro int_stub nr
.global int_handler\nr
int_handler\nr:
push $0
push $\nr
jmp common_intr_handler
.endm
//Exeptions haben extra-stubs
// (siehe: kernel/interrupt/handler/exeption/handler.S)
//IRQs
int_stub 0x20
// 0x21: direct call
int_stub 0x22
int_stub 0x23
int_stub 0x24
int_stub 0x25
int_stub 0x26
int_stub 0x27
int_stub 0x28
int_stub 0x29
int_stub 0x2A
int_stub 0x2B
int_stub 0x2C
int_stub 0x2D
int_stub 0x2E
int_stub 0x2F
//Syscalls
int_stub 0x30
common_intr_handler:
push %ebp
push %edi
push %esi
push %edx
push %ecx
push %ebx
push %eax
// Kernel-Datensegmente laden
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
// ISR aufrufen
push %esp
call handle_interrupt
mov %eax, %esp //Neuen Stack laden
// User-Datensegmente laden
mov $0x23, %ax
mov %ax, %ds
mov %ax, %es
// Neue cpu herstellen
pop %eax
pop %ebx
pop %ecx
pop %edx
pop %esi
pop %edi
pop %ebp
// Errorcode und Interruptnummer vom Stack nehmen
add $8, %esp
iret
Wo könnten andere Fehler/Ursachen für den Sprung sein?
-
Der ganze Prozessorzustand der hier geladen wird (mit den pops und am Ende u.a. esp mit iret), kommt ja aus der struct task oder wie die bei dir heißt. Wenn dein C-Code diese struct irgendwie falsch befüllt oder beim Taskswitch irgendwie kaputtmacht, dann lädt der eigentlich korrekte Assemblercode natürlich falsche Werte. Ich würde an deiner Stelle vor dem Taskswitch ein paar Debugausgaben machen, die diese Felder in der struct task ausgeben.
-
Das Problem liegt ja nicht darin, dass die Struktur falsch befüllt wird, sonder dass wenn ich in meinen Tasks cs auf 0x1b setze funktioniert es nicht mehr. Mit 0x08 gehts.
Ist das verständlicher?
-
Das Problem ist einfach, dass der Usermode nicht funktioniert.
Wenn ich in den Usermode switche, kommt der jmp ins nichs.
Kennt da jemand mögliche Fehler?
-
Da mir jetzt so niemand weiterhelfen kann, hier mal der Code https://www.dropbox.com/s/trl8nug0a91on9a/code.tar.gz (https://www.dropbox.com/s/trl8nug0a91on9a/code.tar.gz)
Um zu kompilieren einfach mkall ausfühern. Dabei wird kompiliert, gelinkt, das image erstellt und mit qemu gestartet.
ACHTUNG: So wie der Code jetzt ist, funktioniert alles wunderbar. Um den Fehler sichtbar zu machen, in /kernel/tasks/multitasking.c in init_task in der struct new_cpu .cs auf 0x1b setzten.
Ich freue mich auf Hilfe!
-
Wenn ich den Kernel bei mir ohne Änderungen boote, passiert nichts. Soll das so? Ich hab keine Möglichkeit eine ISO zu erstellen. Das funktioniert hoffentlich auch so.
Das Problem ist, dass du zwei TSS-Datenstrukturen hast. Einmal in gdt.c und einmal in common_handler.c. Die in gdt.c darf nicht static sein und die in common_handler.c sollte als extern deklariert sein.
gdt.c:
uint32_t tss[TSS_SIZE] = {0, 0, 0x10};
common_handler.c:
extern uint32_t tss[TSS_SIZE];
Das sollte zumindest einen Fehler beheben. Durch den restlichen Code steig ich dann auch nicht mehr durch. Die Initialisierung des Tastaturtreibers scheint aktivierte Interrupts zu benötigen. Zu dem Zeitpunkt ist das Multitasking allerdings noch nicht initialisiert, und du kriegst möglicherweise einen Timer IRQ. Da solltest du nochmal schauen, ob der korrekt behandelt wird.
Stört dich das eigentlich nicht, dass deine printf-Funktion nur 5 Ziffern von hexadezimalen Zahlen ausgibt?
-
Es geht! Danke!!
auf die andern fragen brauch ich ja jetzt nicht mehr zu antworten. :-D
-
Ich habe auch schon mal die Fehlermeldung "Trying to execute code outside RAM or ROM" bekommen.
Es lag daran, dass ich 6 Segmente in der GDT benutzt, aber den Array nur mit 5 deklariert habe!
Prüfe das mal!
-
Wieso es geht doch. Ich hatte den TSS nur nicht richtig benutzt.