Page 1 of 1
Kernel Threads
Posted: Thu Jul 23, 2009 6:46 pm
by xvedejas
If the only form of multiprocessing I want to implement are kernel threads (no processes, nothing in userland) is copying the kernel's address space necessary for each new thread?
I guess more specifically I'd like to know what are the exact steps to make this happen. I /have/ searched the wiki and these forums, and I'm wondering if it's as simple as this to enter a new thread:
- save stack pointers and instruction pointer
- create a new stack
- point to new stack
- set new instruction pointer equal to old one
- jump to new instruction pointer
- every 10 or so clock cycles, cycle between threads
Or is there more I need to do?
My kernel will not have a traditional usermode, so it will be the only binary ever being directly executed by the CPU. Instead, all userland application will be interpreted. For this reason, I *think* that separate processes are unnecessary. Threads ought to be able to give the illusion of multiple processes without needing to copy a bunch of code.
Re: Kernel Threads
Posted: Thu Jul 23, 2009 7:16 pm
by -m32
xvedejas wrote:is copying the kernel's address space necessary for each new thread?
No. All threads exist in the same address space as the kernel already.
Set your new instruction pointer to your thread's entry point (i.e. function pointer).
Re: Kernel Threads
Posted: Fri Jul 24, 2009 11:19 am
by xvedejas
When creating a new stack, I need to disable paging though, since the stack is accessed by physical, not virtual memory address, correct?
Re: Kernel Threads
Posted: Fri Jul 24, 2009 11:46 am
by salil_bhagurkar
No.. When you are creating a new stack, you are simply allocating a block of memory. It is similar to normal allocations and you do not need to disable paging.
Re: Kernel Threads
Posted: Fri Jul 24, 2009 3:17 pm
by xvedejas
Right, so I've written code for this, but when I try to fork, I get a triple fault when switching to the new thread. Here's the code, I wonder where the error is:
Code: Select all
#include <system.h>
extern u32int read_eip();
u32int next_thread_id = 1;
volatile thread_t *current_thread;
void threads_install()
{
current_thread = (thread_t*)kmalloc(sizeof(thread_t));
current_thread->id = next_thread_id++;
current_thread->esp = initial_esp;
current_thread->ebp = initial_esp;
current_thread->eip = 0;
current_thread->status = 0;
current_thread->stack_size = 0;
current_thread->stack_start = initial_esp;
current_thread->next = current_thread;
current_thread->previous = current_thread;
current_thread->priority = 20;
current_thread->counter = 20;
}
u32int fork()
{ // make new thread
thread_t *parent_thread = (thread_t*)current_thread;
thread_t *new_thread = (thread_t*)kmalloc(sizeof(thread_t));
new_thread->id = next_thread_id++;
new_thread->next = parent_thread->next;
new_thread->next->previous = new_thread;
parent_thread->next = new_thread;
new_thread->previous = parent_thread;
new_thread->priority = parent_thread->priority;
new_thread->counter = new_thread->priority;
// entry point
asm volatile("cli");
u32int eip = read_eip();
if (current_thread == parent_thread)
{
u32int current_esp, current_ebp;
// state of current stack
asm volatile("mov %%esp, %0" :: "r"(current_esp));
asm volatile("mov %%ebp, %0" :: "r"(current_ebp));
current_thread->stack_size = current_thread->stack_start - current_esp;
u32int size = current_thread->stack_size;
u32int *stack = kmalloc_a(0x2000); // reserve 8192 bytes for stack
// start of stack is at _end_ of allocation
new_thread->stack_start = stack + 0x2000;
u32int offset = new_thread->stack_start - current_thread->stack_start;
// find the esp and ebp for the new stack
u32int *new_esp = offset + current_esp;
u32int *new_ebp = offset + current_ebp;
// copy over the old stack to the new one
memcpy(new_esp, current_esp, size);
// make sure all else is zeros
memset(stack, 0, 0x2000 - size);
// make changes to thread stuct
new_thread->esp = new_esp;
new_thread->ebp = new_ebp;
new_thread->stack_size = size;
new_thread->eip = eip;
asm volatile("sti");
return new_thread->id;
}
else return 0;
}
void switch_thread()
{ // this function is called every timer tick
if (current_thread->counter)
{
// let thread run some more
current_thread->counter--;
}
else // time to switch
{
asm volatile("cli");
// reset counter
current_thread->counter = current_thread->priority;
// save stack
u32int esp, ebp, eip;
asm volatile("mov %%esp, %0" : "=r"(esp));
asm volatile("mov %%ebp, %0" : "=r"(ebp));
// get the eip
eip = read_eip();
if (eip == 0x12345) return;
current_thread->eip = eip;
current_thread->esp = esp;
current_thread->ebp = ebp;
// advance current_thread
current_thread = current_thread->next;
esp = current_thread->esp;
ebp = current_thread->ebp;
asm volatile(" \
mov %0, %%ecx; \
mov %1, %%esp; \
mov %2, %%ebp; \
mov $0x12345, %%eax; \
sti; \
jmp *%%ecx " :: "r"(eip), "r"(esp), "r"(ebp) : "%eax", "%ecx");
}
}
Re: Kernel Threads
Posted: Fri Jul 24, 2009 6:33 pm
by alethiophile
Do you have a double fault handler? If so, then triple faults perhaps are the result of a page fault in your stack (which, of course, repeats whenever the processor tries to call an interrupt handler).
Re: Kernel Threads
Posted: Fri Jul 24, 2009 11:31 pm
by xvedejas
I realized the reason for the triple fault was because these lines were incorrect:
Code: Select all
// state of current stack
asm volatile("mov %%esp, %0" :: "r"(current_esp));
asm volatile("mov %%ebp, %0" :: "r"(current_ebp));
they should have been:
Code: Select all
// state of current stack
asm volatile("mov %%esp, %0" : "=r"(current_esp));
asm volatile("mov %%ebp, %0" : "=r"(current_ebp));
Now, instead of a triple fault on fork(), the parent process correctly returns 0x02, but the child process is returning 0x12345 instead of 0x00. I think this is because of a stack issue, but I'm not quite sure what's going on here or how the value 0x12345 got from switch_thread() to fork()...
Re: Kernel Threads
Posted: Sat Jul 25, 2009 10:18 am
by xvedejas
Alright, one more!
Code: Select all
esp = current_thread->esp;
ebp = current_thread->ebp;
Should have been
Code: Select all
esp = current_thread->esp;
ebp = current_thread->ebp;
eip = current_thread->eip;
Now fork() seems to work, but once switch_thread() jumps to the child thread, it stops switching threads and keyboard input doesn't work...
Re: Kernel Threads
Posted: Sat Jul 25, 2009 3:26 pm
by xvedejas
On a second look, it seems like interrupt 0 isn't firing anymore... This is strange, as if "sti" isn't working...
Re: Kernel Threads
Posted: Thu Jul 30, 2009 7:39 am
by tantrikwizard
xvedejas wrote:On a second look, it seems like interrupt 0 isn't firing anymore... This is strange, as if "sti" isn't working...
dont forget to send EOI to the PIC