Да, конечно... Вот часть исходников:
task.h
Код:
#ifndef _TASK_H
#define _TASK_H
#include <types.h>
#include <paging.h>
#define KERNEL_STACK_SIZE 2048 // Use a 2kb kernel stack.
typedef struct task
{
int id;
uint32 esp, ebp;
uint32 eip;
page_directory_t *page_directory;
uint32 kernel_stack; // Kernel stack location.
struct task *next;
} task_t;
void init_tasking();
void switch_task();
int fork();
void move_stack(void *new_stack_start, uint32 size);
int getpid();
#endif
task.c
Код:
#include <task.h>
#include <paging.h>
volatile task_t *current_task;
volatile task_t *ready_queue;
extern page_directory_t *kernel_directory;
extern page_directory_t *current_directory;
extern void alloc_frame(page_t*,int,int);
extern uint32 initial_esp;
extern uint32 read_eip();
uint32 next_pid = 1;
void initialise_tasking()
{
asm volatile("cli");
move_stack((void*)0xE0000000, 0x2000);
current_task = ready_queue = (task_t*)kmalloc(sizeof(task_t));
current_task->id = next_pid++;
current_task->esp = current_task->ebp = 0;
current_task->eip = 0;
current_task->page_directory = current_directory;
current_task->next = 0;
current_task->kernel_stack = kmalloc/*_a*/(KERNEL_STACK_SIZE);
asm volatile("sti");
}
void move_stack(void *new_stack_start, uint32 size)
{
uint32 i;
// Выделяем немного места для нового стека.
for( i = (uint32)new_stack_start;
i >= ((uint32)new_stack_start-size);
i -= 0x1000)
{
alloc_frame( get_page(i, 1, current_directory), 0 /* User mode */, 1 /* Is writable */ );
}
uint32 pd_addr;
asm volatile("mov %%cr3, %0" : "=r" (pd_addr));
asm volatile("mov %0, %%cr3" : : "r" (pd_addr));
uint32 old_stack_pointer; asm volatile("mov %%esp, %0" : "=r" (old_stack_pointer));
uint32 old_base_pointer; asm volatile("mov %%ebp, %0" : "=r" (old_base_pointer));
uint32 offset = (uint32)new_stack_start - initial_esp;
uint32 new_stack_pointer = old_stack_pointer + offset;
uint32 new_base_pointer = old_base_pointer + offset;
memcpy((void*)new_stack_pointer, (void*)old_stack_pointer, initial_esp-old_stack_pointer);
for(i = (uint32)new_stack_start; i > (uint32)new_stack_start-size; i -= 4)
{
uint32 tmp = * (uint32*)i;
if (( old_stack_pointer < tmp) && (tmp < initial_esp))
{
tmp = tmp + offset;
uint32 *tmp2 = (uint32*)i;
*tmp2 = tmp;
}
}
asm volatile("mov %0, %%esp" : : "r" (new_stack_pointer));
asm volatile("mov %0, %%ebp" : : "r" (new_base_pointer));
}
void switch_task()
{
if (!current_task)
return;
uint32 esp, ebp, eip;
asm volatile("mov %%esp, %0" : "=r"(esp));
asm volatile("mov %%ebp, %0" : "=r"(ebp));
eip = read_eip();
if (eip == 0x12345)
return;
current_task->eip = eip;
current_task->esp = esp;
current_task->ebp = ebp;
current_task = current_task->next;
if (!current_task) current_task = ready_queue;
eip = current_task->eip;
esp = current_task->esp;
ebp = current_task->ebp;
current_directory = current_task->page_directory;
kprintf ("eip = 0x%x, esp = 0x%x, ebp = 0x%x, cda = 0x%x\n",eip,esp,ebp,current_directory->physicalAddr);
// Change our kernel stack over.
set_kernel_stack(current_task->kernel_stack+KERNEL_STACK_SIZE);
asm volatile(" \
cli; \
mov %0, %%ecx; \
mov %1, %%esp; \
mov %2, %%ebp; \
mov %3, %%cr3; \
mov $0x12345, %%eax; \
sti; \
jmp *%%ecx "
: : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr));
}
int fork()
{
asm volatile("cli");
task_t *parent_task = (task_t*)current_task;
page_directory_t *directory = clone_directory(current_directory);
task_t *new_task = (task_t*)kmalloc(sizeof(task_t));
new_task->id = next_pid++;
new_task->esp = new_task->ebp = 0;
new_task->eip = 0;
new_task->page_directory = directory;
current_task->kernel_stack = kmalloc_a(KERNEL_STACK_SIZE);
new_task->next = 0;
task_t *tmp_task = (task_t*)ready_queue;
while (tmp_task->next)
tmp_task = tmp_task->next;
tmp_task->next = new_task;
uint32 eip = read_eip();
if (current_task == parent_task)
{
uint32 esp; asm volatile("mov %%esp, %0" : "=r"(esp));
uint32 ebp; asm volatile("mov %%ebp, %0" : "=r"(ebp));
new_task->esp = esp;
new_task->ebp = ebp;
new_task->eip = eip;
asm volatile("sti");
return new_task->id;
}
else
{
return 0;
}
}
...
void switch_to_user_mode()
{
// Set up our kernel stack.
set_kernel_stack(current_task->kernel_stack+KERNEL_STACK_SIZE);
asm volatile(" \
cli; \
mov $0x23, %ax; \
mov %ax, %ds; \
mov %ax, %es; \
mov %ax, %fs; \
mov %ax, %gs; \
\
mov %esp, %eax; \
pushl $0x23; \
pushl %esp; \
pushf; \
\
pop %eax; \
or $0x200, %eax; \
push %eax; \
\
pushl $0x1B; \
push $1f; \
iret; \
1: \
");
}