Multitasking - [Ring 0 / 3] Crashes after a while
Posted: Wed Dec 28, 2011 12:06 pm
Hello there
I'm developing now since a while my own little operating system called cronOS. Till now, I did everything myself. I read documentations, howtos and so on and coded everything from scratch. But now I've got some really annoying problem. I've implemented PMM (physical memory management) and Multitasking.
My multitasking worked great. Task switching worked (scheduler called by PIT / Timer) great and it never crashed. That was my code then:
PIT code - pit.cpp (snippet)
Multitasking Code - tss.cpp
IRQ handler - loader.asm
That code works really great! No crashes and everything is fine. Then I added ring switching. To be specific, I changed all these files:
IRQ handler - loader.asm
As you can see, I added the code for segment loading. I also changed the tss.cpp a bit:
Multitasking - tss.cpp
I've only added the TSS and changed the function "init_task" to specify the new registers. The last change I did was in my PIT code:
PIT code - pit.cpp (snippet)
I didn't change more. Now my problem is: Multitasking still works fine. But after a while, QEMU just crashes and Bochs prints: "00520473404e[CPU0 ] read_RMW_virtual_dword_32(): segment limit violation" In my debug console (serial output via COM port 1) I can't see much more: https://www.snapserv.net/screenshots/20 ... 8_1715.png
I've got no idea where my error is. Can you see anything wrong? Thanks for your answer!
I'm developing now since a while my own little operating system called cronOS. Till now, I did everything myself. I read documentations, howtos and so on and coded everything from scratch. But now I've got some really annoying problem. I've implemented PMM (physical memory management) and Multitasking.
My multitasking worked great. Task switching worked (scheduler called by PIT / Timer) great and it never crashed. That was my code then:
PIT code - pit.cpp (snippet)
Code: Select all
struct cpu_state* handle(struct cpu_state* cpu) {
/* Increment counter */
ticks++;
if(ticks % CRONOS_PIT_HZ == 0) {
}
/* Handle multitasking */
cpu = tss::schedule(cpu);
/* Return new CPU */
return cpu;
}
Code: Select all
#include "tss.h"
#include "stdint.h"
#include "util.h"
#include "console.h"
#include "debug.h"
#include "gdt.h"
#include "pmm.h"
namespace tss {
struct task {
struct cpu_state* cpu_state;
struct task* next;
};
static struct task* first_task = (task*) NULL;
static struct task* current_task = (task*) NULL;
uint8_t init() {
/* Debug */
debug::printf("Initializing multitasking...\n");
/* Return */
return 0;
}
struct task* init_task(uint32_t entry) {
/* Get stack space from PMM */
uint32_t stack = pmm::alloc();
uint32_t user_stack = pmm::alloc();
debug::printf("Stack: %h / User stack: %h\n", sizeof(uint32_t), stack, sizeof(uint32_t), user_stack);
/* Generate new CPU state */
struct cpu_state new_state = {
new_state.eax = 0,
new_state.ebx = 0,
new_state.ecx = 0,
new_state.edx = 0,
new_state.esi = 0,
new_state.edi = 0,
new_state.ebp = 0,
new_state.intr = 0,
new_state.error = 0,
new_state.eip = (uint32_t) entry,
new_state.cs = 0x08,
new_state.eflags = 0x202,
new_state.esp = 0,
new_state.ss = 0
};
/* Copy CPU state to stack */
struct cpu_state* state = (cpu_state*) (stack + 4096 - sizeof(new_state));
*state = new_state;
/* Join new task with other tasks */
struct task* task = (struct task*) pmm::alloc();
task->cpu_state = state;
task->next = first_task;
first_task = task;
debug::printf("CPU State: %h\n", sizeof(task->cpu_state), task->cpu_state);
debug::printf("First task: %h\n", sizeof(struct task*), first_task);
debug::printf("Current task: %h\n", sizeof(struct task*), current_task);
/* Return new task */
return task;
}
struct cpu_state* schedule(struct cpu_state* cpu) {
/* No tasks available? */
if(first_task == 0) {
return cpu;
}
/* When another task is running, save CPU state */
if(current_task > 0) {
current_task->cpu_state = cpu;
}
/* First call? */
if(current_task == 0) {
current_task = first_task;
}
/* Choose next task */
if(current_task->next == 0) {
current_task = first_task;
} else {
current_task = current_task->next;
}
/* Save new state into CPU */
cpu = current_task->cpu_state;
debug::printf("Task info: ESP: %h\n", sizeof(cpu->esp), cpu->esp);
/* Return new state */
return cpu;
}
void task_a() {
while(1) {
console::printf("A");
}
}
void task_b() {
while(1) {
console::printf("B");
}
}
}
Code: Select all
; IRQ handler macro
%macro IRQ 1
global irq_handler%1
irq_handler%1:
cli
push byte 0
push byte %1+32
jmp irq_stub
%endmacro
; IRQ routines
IRQ 0 ; Timer
IRQ 1 ; Keyboard
IRQ 2 ; ???
IRQ 3 ; ???
IRQ 4 ; ???
IRQ 5 ; ???
IRQ 6 ; ???
IRQ 7 ; ???
IRQ 8 ; RTC
IRQ 9 ; ???
IRQ 10 ; ???
IRQ 11 ; ???
IRQ 12 ; ???
IRQ 13 ; ???
IRQ 14 ; ???
IRQ 15 ; ???
; IRQ stub
extern irq_handle
irq_stub:
; Save CPU state
push ebp
push edi
push esi
push edx
push ecx
push ebx
push eax
; Call handler
push esp
call irq_handle
mov esp, eax
; Restore CPU state
pop eax
pop ebx
pop ecx
pop edx
pop esi
pop edi
pop ebp
; Remove error code and interrupt number from stack
add esp, 8
; Jump back
iret
IRQ handler - loader.asm
Code: Select all
...
; Load kernel data segments
mov ax, 0x10
mov ds, ax
mov es, ax
; Call handler
push esp
call irq_handle
mov esp, eax
; Load user data segments
mov ax, 0x23
mov ds, ax
mov es, ax
...
Multitasking - tss.cpp
Code: Select all
...
static uint32_t tss[32] = {0, 0, 0x10};
...
uint8_t init() {
/* Debug */
debug::printf("Initializing multitasking...\n");
/* Init TSS */
gdt::set_entry(5, (uint32_t) tss, (uint32_t) sizeof(tss), GDT_FLAG_TSS | GDT_FLAG_PRESENT | GDT_FLAG_RING3);
__asm__ volatile("ltr %%ax" :: "a" (5 << 3));
/* Return loaded tasks */
return 0;
}
void set_tss(uint32_t cpu) {
/* Set new TSS */
tss[1] = cpu;
}
struct task* init_task(uint32_t entry) {
/* Get stack space from PMM */
uint32_t stack = pmm::alloc();
uint32_t user_stack = pmm::alloc();
debug::printf("Stack: %h / User stack: %h\n", sizeof(uint32_t), stack, sizeof(uint32_t), user_stack);
/* Generate new CPU state */
struct cpu_state new_state = {
new_state.eax = 0,
new_state.ebx = 0,
new_state.ecx = 0,
new_state.edx = 0,
new_state.esi = 0,
new_state.edi = 0,
new_state.ebp = 0,
new_state.intr = 0,
new_state.error = 0,
new_state.eip = (uint32_t) entry,
new_state.cs = 0x18 | 0x03,
new_state.eflags = 0x202,
new_state.esp = (uint32_t) user_stack + 4096,
new_state.ss = 0x20 | 0x03
};
/* Copy CPU state to stack */
struct cpu_state* state = (cpu_state*) (stack + 4096 - sizeof(new_state));
*state = new_state;
/* Join new task with other tasks */
struct task* task = (struct task*) pmm::alloc();
task->cpu_state = state;
task->next = first_task;
first_task = task;
debug::printf("CPU State: %h\n", sizeof(task->cpu_state), task->cpu_state);
debug::printf("First task: %h\n", sizeof(struct task*), first_task);
debug::printf("Current task: %h\n", sizeof(struct task*), current_task);
/* Return new task */
return task;
}
...
PIT code - pit.cpp (snippet)
Code: Select all
struct cpu_state* handle(struct cpu_state* cpu) {
/* Increment counter */
ticks++;
if(ticks % CRONOS_PIT_HZ == 0) {
}
/* Handle multitasking */
cpu = tss::schedule(cpu);
tss::set_tss((uint32_t) cpu + 1);
/* Return new CPU */
return cpu;
}
I've got no idea where my error is. Can you see anything wrong? Thanks for your answer!