Multitasking

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
eXeCuTeR
Member
Member
Posts: 63
Joined: Tue Dec 09, 2008 12:43 pm

Multitasking

Post by eXeCuTeR »

Well, I can't get multitasking work properly.
Qemu just quits (bochs restarts...bochsout: http://pastebin.com/m48c9e5ce)
here is task_t:

Code: Select all

typedef struct task_t
{
	int pid; // task id
	unsigned int stack; // stack of the task
	unsigned char state; // is task alive?
	void (*thread_start)(void); // a pointer to the first function that will executed (eip) in the task
	struct task_t *next; // pointer to the next task
} task_t;

Code: Select all

#include "task.h"
#include "mm.h"
#include "screen.h"
#include "hardware.h"

task_t *tasks;
unsigned int tasks_num, current_pid;

void initialize_multitasking(void)
{
	tasks = (task_t *)malloc(sizeof(task_t));
	tasks_num = 0;
	unsigned int divisor = 1193180 / 50;
	outport(0x43, 0x36);
	outport(0x40, divisor & 0xFF);
	outport(0x40, (divisor >> 8) & 0xFF);
	outport(0x21, 0x00); // enable interrupts from IRQ 0-7 (PIT will now start working)
	create_task(0, idle);
}

void idle(void)
{
	puts("\nIdling...\n");
	for(;;) ;
}

void clone_task(task_t *source, task_t *dest)
{
	dest->pid = source->pid;
	dest->stack = source->stack;
	dest->state = source->state;
	dest->thread_start = source->thread_start;
	dest->next = source->next;
}

void create_task(int id, void (*thread_start)(void))
{
	asm volatile("cli"); // no one should interrupt us
	task_t *temp_task = (task_t *)malloc(sizeof(task_t));
	temp_task->pid = id;
	temp_task->next = 0;
	temp_task->thread_start = thread_start;
	temp_task->stack = (unsigned int)malloc(0x1000);
	
	unsigned int *stack = (unsigned int *)(temp_task->stack + 0x1000/*stack grows downwards*/);
	/**--stack = 0; // ss 
	*--stack = 0; // useresp*/
	
	*--stack = 0x202; // eflags
	*--stack = 0x08; // cs
	*--stack = (unsigned int)thread_start; // eip
	
	unsigned int i = 0;
	for(;i<8;i++) // pusha = 0
		*--stack = 0;
	
	for(i=0;i<4;i++) // gs, fs, es, ds
		*--stack = 0x10;
	
	temp_task->state = 1; // is avaiable
	temp_task->stack = (unsigned int)stack;
	clone_task(temp_task, &tasks[id]);
	
	current_pid = id;
	tasks_num++;
}

unsigned int schedule_tasks(unsigned int context)
{
	outport(0x20, 0x20); // it's IRQ0, we should inform the slave that we've got the message.
	return tasks[0].stack; // i just want to try 1 task for now
}
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Multitasking

Post by Combuster »

Try tracking your stackpointer, its broken:
ESP=ffffffff
Bochs debugger can help you with that
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
eXeCuTeR
Member
Member
Posts: 63
Joined: Tue Dec 09, 2008 12:43 pm

Re: Multitasking

Post by eXeCuTeR »

Combuster wrote:Try tracking your stackpointer, its broken:
ESP=ffffffff
Bochs debugger can help you with that
I haven't tried the bochs debugger yet. how do I use it?
cyr1x
Member
Member
Posts: 207
Joined: Tue Aug 21, 2007 1:41 am
Location: Germany

Re: Multitasking

Post by cyr1x »

I think your problem lies in the popa(d) instruction.
eXeCuTeR wrote: unsigned int i = 0;
for(;i<8;i++) // pusha = 0
*--stack = 0;
You set everything to 0. If you execute the popa(d) instruction you overwrite esp with 0.
This is just a guess, but that is the only thing I can think of for now.
eXeCuTeR
Member
Member
Posts: 63
Joined: Tue Dec 09, 2008 12:43 pm

Re: Multitasking

Post by eXeCuTeR »

cyr1x wrote:I think your problem lies in the popa(d) instruction.
eXeCuTeR wrote: unsigned int i = 0;
for(;i<8;i++) // pusha = 0
*--stack = 0;
You set everything to 0. If you execute the popa(d) instruction you overwrite esp with 0.
This is just a guess, but that is the only thing I can think of for now.
nope, this is not the problem, thanks anyways.
how do you i use the bochs debugger then guys? :P
User avatar
djsilence
Member
Member
Posts: 70
Joined: Wed Oct 01, 2008 11:18 am
Location: Ukraine, Kiev
Contact:

Re: Multitasking

Post by djsilence »

HI, anyone.

I'm trying to implement multitasking. I read about software-trask switching. As I understand current eip value needs be stored and new eip value needs be loaded. I'm writing according to BrokenThorn.com tutorial, that is written in MSVC++. I tried to use that asm (ex.: _asm mov eax, eip) and got an error: eip - unknown symbol. Something like this. So, if anyone know, what need I do?

Thanks.
Don't think a ****, but in ukrainian schools English is TOO BAD!
giszo
Member
Member
Posts: 124
Joined: Tue Nov 06, 2007 2:37 pm
Location: Hungary

Re: Multitasking

Post by giszo »

djsilence wrote:I tried to use that asm (ex.: _asm mov eax, eip) and got an error: eip - unknown symbol. Something like this. So, if anyone know, what need I do?
You can't access the EIP register like any other general purpose register. I suggest you to check how interrupts are working and the IRET instruction (especially their effect on the stack) and after that you can easily figure out how you can change the value of EIP.

giszo
eXeCuTeR
Member
Member
Posts: 63
Joined: Tue Dec 09, 2008 12:43 pm

Re: Multitasking

Post by eXeCuTeR »

berkus wrote:Configure bochs with debugger, and run it.

This is configure line for bochs i'm using in osdev (the last 3 lines enable the debugger among other things):

Code: Select all

  # --disable-readline is for bfe2 front-end
  ./configure --prefix=/usr --enable-vbe --without-wx --enable-cpu-level=6 \
        --enable-4meg-pages --enable-global-pages --enable-pae --enable-fpu \
        --enable-mmx --disable-3dnow --enable-sse --enable-sep \
        --enable-sb16=linux \
        --enable-iodebug --enable-debugger --enable-port-e9-hack --enable-disasm \
        --enable-x86-debugger --enable-instrumentation
As you may have guessed, there are debugger front-ends for you GUI lovers out there.
After I configure this way, and then running `make` I get:

Code: Select all

cd iodev && \
	make  libiodev.a
make[1]: Entering directory `/home/executer/Desktop/bochs-20090111/iodev'
g++ -c  -I.. -I./.. -I../instrument/stubs -I./../instrument/stubs -g -O2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES    devices.cc -o devices.o
../instrument/stubs/instrument.h: In member function ‘void bx_devices_c::outp(Bit16u, Bit32u, unsigned int)’:
../instrument/stubs/instrument.h:97: error: too many arguments to function ‘void bx_instr_outp(Bit16u, unsigned int)’
devices.cc:958: error: at this point in file
make[1]: *** [devices.o] Error 1
make[1]: Leaving directory `/home/executer/Desktop/bochs-20090111/iodev'
make: *** [iodev/libiodev.a] Error 2
JohnnyTheDon
Member
Member
Posts: 524
Joined: Sun Nov 09, 2008 2:55 am
Location: Pennsylvania, USA

Re: Multitasking

Post by JohnnyTheDon »

--enable-instrumentation
Don't think you need this, I don't use it and my debugger runs fine.
eXeCuTeR
Member
Member
Posts: 63
Joined: Tue Dec 09, 2008 12:43 pm

Re: Multitasking

Post by eXeCuTeR »

JohnnyTheDon wrote:
--enable-instrumentation
Don't think you need this, I don't use it and my debugger runs fine.
Still no effect.. :( I'm also having a lot of warnings.
Anyways...does anyone has any idea why I'm getting this god damn page fault on 0xFFFFB00A?!

this is so weird they are 0xFFFFFFFF: (the eip is pointing to the interrupt_handler function)

Code: Select all

00108639062i[CPU  ] | EAX=ffffffdf  EBX=00000025  ECX=000002d9  EDX=ffffffff
00108639062i[CPU  ] | ESP=c0000004  EBP=00067ee0  ESI=ffffffff  EDI=ffffffff
00108639062i[CPU  ] | IOPL=0 id vip vif ac vm RF nt of df if tf SF zf af PF cf
00108639062i[CPU  ] | SEG selector     base    limit G D
00108639062i[CPU  ] | SEG sltr(index|ti|rpl)     base    limit G D
00108639062i[CPU  ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00108639062i[CPU  ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00108639062i[CPU  ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00108639062i[CPU  ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
00108639062i[CPU  ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00108639062i[CPU  ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00108639062i[CPU  ] | EIP=00100e15 (00100e15)
00108639062i[CPU  ] | CR0=0xe0000011 CR1=0 CR2=0xbffffffc
00108639062i[CPU  ] | CR3=0x00000000 CR4=0x00000000
00108639062i[CPU  ] >> pushad  : 60
00108639062e[CPU  ] exception(): 3rd (14) exception with no resolution, shutdown status is 00h, resetting
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Multitasking

Post by Combuster »

CR3=0x00000000
is this valid with paging enabled?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
eXeCuTeR
Member
Member
Posts: 63
Joined: Tue Dec 09, 2008 12:43 pm

Re: Multitasking

Post by eXeCuTeR »

Combuster wrote:
CR3=0x00000000
is this valid with paging enabled?
Everything is just messed up somehow, that's totally weird.
eXeCuTeR
Member
Member
Posts: 63
Joined: Tue Dec 09, 2008 12:43 pm

Re: Multitasking

Post by eXeCuTeR »

PLAESE HELP OUT distinguish the error in the code that causes a page faullt and messes the registers up!! =[

I also use these:

Code: Select all

global writeto_cr3
writeto_cr3:
	mov eax, [esp+4]
	mov cr3, eax
	ret
	
global or_cr0
or_cr0:
	mov eax, cr0
	or eax, 0x80000000
	mov cr0, eax
	ret

global readfrom_cr2 ; for page faults
readfrom_cr2:
	mov eax, cr2
	ret
and my current code (i just copied this code now for a tutorial because im so exhausted =[)

Code: Select all

#include "task.h"
#include "mm.h"
#include "screen.h"
#include "hardware.h"

typedef struct{        //Simple structure for a thread
  unsigned int esp0;   //Stack for kernel
  unsigned int esp3;   //Stack for process
} Thread;

Thread Threads[2];     //Space for our simple threads. Just 2!
int CurrentTask = -1;  //The thread currenlty running (-1 == none)
int first = 0;

void initialize_multitasking(void)
{
	CreateTask(0, idle);
	CreateTask(1, idle);
	unsigned int divisor = 1193180 / 50;
	outport(0x43, 0x36);
	outport(0x40, divisor & 0xFF);
	outport(0x40, (divisor >> 8) & 0xFF);
	outport(0x21, 0x00); // enable interrupts from IRQ 0-7 (PIT will now start working)
}

void idle()
{
	puts("IDLE");
	for(;;) ;
}

void idle2()
{
	puts("idle");
	for(;;) ;
}

//This will create a task
//It will make a stack that looks like it has all
//of the stuff of an IRQ handler 'pushed' on it
void CreateTask(int id, void (*thread)()){
 unsigned int *stack;
 
 Threads[id].esp0 = (unsigned int)malloc(0x1000) + 4096; //This allocates 4kb of memory, then puts the pointer at the end of it
 
 stack = (unsigned int* )Threads[id].esp0; //This makes a pointer to the stack for us
 
 //First, this stuff is pushed by the processor
 *--stack = 0;
 *--stack = 0;
 *--stack = 0x0202; //This is EFLAGS
 *--stack = 0x08;   //This is CS, our code segment
 *--stack = (unsigned int)thread; //This is EIP
 
 //Next, the stuff pushed by 'pusha'
 *--stack = 0; //EDI
 *--stack = 0; //ESI
 *--stack = 0; //EBP
 *--stack = 0; //Just an offset, no value
 *--stack = 0; //EBX
 *--stack = 0; //EDX
 *--stack = 0; //ECX
 *--stack = 0; //EAX
 
 //Now these are the data segments pushed by the IRQ handler
 *--stack = 0x10; //DS
 *--stack = 0x10; //ES
 *--stack = 0x10; //FS
 *--stack = 0x10; //GS
 
 Threads[id].esp0 = (unsigned int)stack; //Update the stack pointer
}

//Switch between our two tasks
//Notice how we get the old esp from the ASM code
//It's not a pointer, but we actually get the ESP value
//That way we can save it in our task structure
int TaskSwitch(unsigned int OldEsp){
 if(CurrentTask != -1){ //Were we even running a task?
  Threads[CurrentTask].esp0 = OldEsp; //Save the new esp for the thread
  
  //Now switch what task we're on
  if(CurrentTask == 0) CurrentTask = 1;
  else CurrentTask = 0;
 } else{
  CurrentTask = 0; //We just started multi-tasking, start with task 0
 }
 unsigned int a = Threads[CurrentTask].esp0;
 	outport(0x20, 0x20);
 	// return a;
 return OldEsp; //Return new stack pointer to ASM
}

Code: Select all

extern TaskSwitch
extern putdec
global IRQ0
IRQ0:
 	pusha
 	push ds
 	push es
 	push fs
 	push gs
 
 	mov ax, 0x10
 	mov ds, ax
 	mov es, ax
 	mov fs, ax
 	mov gs, ax
 
 	push esp
 	call TaskSwitch
 	
 	;push eax
 	;call putdec
 	;pop eax
 	
 	mov esp, eax
	
 	pop gs
 	pop fs
 	pop es
 	pop ds
 	popa
 	
 	iret
eXeCuTeR
Member
Member
Posts: 63
Joined: Tue Dec 09, 2008 12:43 pm

Re: Multitasking

Post by eXeCuTeR »

Got it working finally. thanks guys!
Post Reply