Autor Thema: Multitasking im Usermode  (Gelesen 3600 mal)

jo2105

  • Beiträge: 58
    • Profil anzeigen
Gespeichert
« am: 23. November 2012, 21:25 »
Ok, ich komme mal wieder nicht weiter^^

Ich habe in meinen Kernel Multitasking integriert, was nach einigen Hürden auch gut geklappt hat.
Seitdem ich aber in den Ring3 umgestiegen bin, startet QEMU einfach die ganze Zeit neu.  :roll:

Das sind die Quellcodes:

#include "includes.h"

#define GDT_FLAG_DATASEGM 0x02
#define GDT_FLAG_CODESEGM 0x0a
#define GDT_FLAG_TSS 0x09

#define GDT_FLAG_SEGMENT 0x10
#define GDT_FLAG_RING0 0x00
#define GDT_FLAG_RING3 0x60
#define GDT_FLAG_PRESENT 0x80

#define GDT_FLAG_4K_GRAN 0x800
#define GDT_FLAG_32_BIT 0x400

#define GDT_ENTRIES 0x5

static uint64_t gdt[GDT_ENTRIES];

void init_gdt() 
{
  gdt_set_entry(0, 0, 0, 0);
  gdt_set_entry(1, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT | GDT_FLAG_CODESEGM | GDT_FLAG_4K_GRAN | GDT_FLAG_PRESENT);
  gdt_set_entry(2, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT | GDT_FLAG_DATASEGM | GDT_FLAG_4K_GRAN | GDT_FLAG_PRESENT);
  gdt_set_entry(3, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT | GDT_FLAG_CODESEGM | GDT_FLAG_4K_GRAN | GDT_FLAG_PRESENT | GDT_FLAG_RING3);
  gdt_set_entry(4, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT | GDT_FLAG_DATASEGM | GDT_FLAG_4K_GRAN | GDT_FLAG_PRESENT | GDT_FLAG_RING3);
  gdt_set_entry(5, (uint32_t)tss, sizeof(tss), GDT_FLAG_TSS | GDT_FLAG_PRESENT | GDT_FLAG_RING3);
 
  load_gdt();
  kprintf(P_GDT_LOADED);
}
 
void gdt_set_entry(int i, unsigned int base, unsigned int limit, int flags)
{
  gdt[i] = limit & 0xffffLL;
  gdt[i] |= (base & 0xffffffLL) << 16;
  gdt[i] |= (flags & 0xffLL) << 40;
  gdt[i] |= ((limit >> 16) & 0xfLL) << 48;
  gdt[i] |= ((flags >> 8) & 0xffLL) << 52;
  gdt[i] |= ((base >> 24) &  0xffLL) << 56;
}


void load_gdt()
{
  struct {
    uint16_t limit;
    void * pointer;
  } __attribute__((packed)) gdtp = {
    .limit = GDT_ENTRIES * 8 - 1,
    .pointer = gdt,
  };
  asm volatile("lgdt %0" : : "m" (gdtp));
  asm volatile("ltr %%ax" : : "a" (5 << 3));
 
  asm volatile("mov $0x10, %ax;"
"mov %ax, %ds;"
"mov %ax, %es;"
     "mov %ax, %ss;"
     "ljmp $0x8, $.1;"
     ".1:");
}


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 struct cpu_state* task_states[2];


void init_taskmanager()
{
  task_states[0] = init_task(stack_a, user_stack_a, task_a);
  task_states[1] = init_task(stack_b, user_stack_b, task_b);
  kprintf("Der Taskmanager wurde initialisiert\n");
}

struct cpu_state * init_task(uint8_t* stack, uint8_t* userstack, void* entry)
{
  struct cpu_state task_cpu_state = {
    .eax = 0,
    .ebx = 0,
    .ecx = 0,
    .edx = 0,
    .esi = 0,
    .edi = 0,
    .ebp = 0,
    .esp = (uint32_t)userstack + 4096,
    .eip = (uint32_t)entry,
    .cs = 0x18 | 0x03,
    .ss = 0x20 | 0x03,
    .eflags = 0x202,
  };
   
  struct cpu_state* state = (void*) (stack + 4096 - sizeof(task_cpu_state));
  *state = task_cpu_state;
  kprintf("%x\n", state->eip);
  return state;
}

struct cpu_state * schedule(struct cpu_state * cpu)
{
  if(current_task >= 0) {
    task_states[current_task] = cpu;

intr_common_handler:
    //CPU-Stand sichern 
    push %ebp
    push %edi
    push %esi
    push %edx
    push %ecx
    push %ebx
    push %eax

    mov $0x10, %ax
    mov %ax, %ds
    mov %ax, %es

    push %esp
    call handle_interrupts
    mov %eax, %esp

    mov $0x23, %ax
    mov %ax, %ds
    mov %ax, %es

    pop %eax
    pop %ebx
    pop %ecx
    pop %edx
    pop %esi
    pop %edi
    pop %ebp

    add $8, %esp
    iret

#include "includes.h" 

struct cpu_state * handle_interrupts(struct cpu_state * cpu)
{
  struct cpu_state * new_cpu = cpu;
 
  if(cpu->intr <= 0x1f) {
    clear();
    changeColor(0x1f);
    kprintf("\n Das Betriebssystem hat ein Problem festgestellt und muss beendet werden.\n\n");
   
    kprintf(" Interrupt:%v %d (Exception)\n", 15, (int)cpu->intr);
    kprintf(" Fehlercode:%v %x\n\n", 15, cpu->error);
       
    kprintf(" CPU zum Zeitpunkt des Interrupts:\n\n");
   
    kprintf("\teax:%v %x%vebx:%v%x\n", 10, cpu->eax, 25, 32, cpu->ebx);
    kprintf("\tecx:%v %x%vedx:%v%x\n", 10, cpu->ecx, 25, 32, cpu->edx);
    kprintf("\tesi:%v %x%vedi:%v%x\n", 10, cpu->esi, 25, 32, cpu->edi);
    kprintf("\tebp:%v %x%veip:%v%x\n", 10, cpu->ebp, 25, 32, cpu->eip);
    kprintf("\tesp:%v %x\n", 10, cpu->esp);
    kprintf("\tcs:%v %x%vss:%v%x\n", 10, cpu->cs, 25, 32, cpu->ss);
    kprintf("\tFlags:%v %x\n", 10, cpu->eflags);

    kprintf("\n Taste druecken um einen CPU-Reset auszufuehren...\n Mach dir keine Hoffnungen, ich komme wieder. :madcat:");
    outb(0x64, 0xFE);
   
    while(1) asm volatile("cli; hlt");
   
  } else {
    if(cpu->intr >= 0x20 && cpu->intr <= 0x2f) {
if(cpu->intr >= 0x28) {
   outb(0xa0, 0x20);
} else {
   outb(0x20, 0x20);
}
if(cpu->intr == 0x20) {
   new_cpu = schedule(cpu);
   tss[1] = (uint32_t)(new_cpu+1);
}
if(cpu->intr == 0x21) kb_irq_handler(cpu->intr);
    }
  }
 
  return new_cpu;
}

Falls ihr noch irgendwelche QEMU Logs braucht, lasst es mich hören.  :-D


Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 23. November 2012, 21:35 »
Falls ihr noch irgendwelche QEMU Logs braucht, lasst es mich hören.  :-D

Normalerweise immer das Log (ggf. auf Pastebin) posten.

Aber dein Problem hatten kürzlich erst ein paar andere: GDT_ENTRIES muss den Wert 6 haben.
Dieser Text wird unter jedem Beitrag angezeigt.

jo2105

  • Beiträge: 58
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 23. November 2012, 22:33 »
Falls ihr noch irgendwelche QEMU Logs braucht, lasst es mich hören.  :-D

Normalerweise immer das Log (ggf. auf Pastebin) posten.

Aber dein Problem hatten kürzlich erst ein paar andere: GDT_ENTRIES muss den Wert 6 haben.

Oh verdammt. :-D Das ist natürlich ein dummer Fehler.

Jetzt kriege ich folgenden Fehler:

Zitat
qemu: fatal: Trying to execute code outside RAM or ROM at 0x66671058

EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000065
ESI=00000000 EDI=00000000 EBP=8b66670c ESP=ffffff84
EIP=66671058 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 001022c0 00000080 0000e910 DPL=3 TSS32-avl
GDT=     0010a040 0000002f
IDT=     0010a080 000007ff
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=000007cf CCD=08708397 CCO=SUBL   
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

Ich werde später noch die Logdatei posten.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 24. November 2012, 02:34 »
Die CPU springt an eine Adresse, wo kein RAM mehr ist (0x66671058 ist bei etwa 1,6 GB). Das deutet auf einen kaputten Stack hin.

jo2105

  • Beiträge: 58
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 24. November 2012, 09:43 »
Die CPU springt an eine Adresse, wo kein RAM mehr ist (0x66671058 ist bei etwa 1,6 GB). Das deutet auf einen kaputten Stack hin.

Jop den Fehler hatte ich schon beim Multitasking im Ring0. Da lag es aber daran, dass ich noch keine Scrollfunktion hatte und der ganze Speicher und darüber hinaus mit a und b zu gemüllt wurden.  :-D
Dann werde ich gleich mal auf die Fehlerjagd begeben.

jo2105

  • Beiträge: 58
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 24. November 2012, 14:56 »
http://pastebin.com/3eHU8170

Ich finde irgendwie nicht die Stelle, wo die CPU auf diese Adresse springt...

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 24. November 2012, 16:41 »
Der Wert ESP=ffffff84 in dem Dump lässt vermuten, dass ESP irgendwo auf 0 gesetzt wurde. Vermutlich funktioniert die schedule-Funktion nicht richtig.
Dieser Text wird unter jedem Beitrag angezeigt.

jo2105

  • Beiträge: 58
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 24. November 2012, 18:36 »
Der Wert ESP=ffffff84 in dem Dump lässt vermuten, dass ESP irgendwo auf 0 gesetzt wurde. Vermutlich funktioniert die schedule-Funktion nicht richtig.

Ok. Es lag wohl daran, dass ich das tss Array falsch deklariert habe. Jetzt funktioniert es soweit. Allerdings kriege ich keine normale Exception, wenn ich asm("cli; hlt");  in einem der Tasks eingebe, sondern QEMU startet einfach neu...

/e: Das Problem lag am Interrupt Handler. Jetzt kriege ich zwar den Bluescreen, aber auch wenn die Tasks überhaupt nichts böses machen.
/e2: Ah ich habe nur dem cs einen falschen Wert mitgegeben. Jetzt klappt es.
« Letzte Änderung: 24. November 2012, 20:01 von jo2105 »

 

Einloggen