maybe i'm close to fixing multitasking
This commit is contained in:
+52
-9
@@ -3,6 +3,17 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Сегменты для ядра и пользователя
|
||||
#define SEG_KCODE 1 // Сегмент кода ядра
|
||||
#define SEG_KDATA 2 // Сегмент данных ядра
|
||||
#define SEG_UCODE 3 // Сегмент кода пользователя
|
||||
#define SEG_UDATA 4 // Сегмент данных пользователя
|
||||
#define DPL_KERNEL 0 // Уровень привилегий ring 0
|
||||
#define DPL_USER 3 // Уровень привилегий ring 3
|
||||
|
||||
// Флаги процессора
|
||||
#define FL_IF 0x202 // Разрешить прерывания
|
||||
|
||||
typedef enum TaskState
|
||||
{
|
||||
Ready,
|
||||
@@ -13,22 +24,54 @@ typedef enum TaskState
|
||||
|
||||
typedef void (*EntryPoint)(void);
|
||||
|
||||
// Структура контекста для переключения между процессами
|
||||
typedef struct Context {
|
||||
uint32_t edi;
|
||||
uint32_t esi;
|
||||
uint32_t ebx;
|
||||
uint32_t ebp;
|
||||
uint32_t eip;
|
||||
} Context;
|
||||
|
||||
// Структура trap frame для перехода в ring 3
|
||||
typedef struct TrapFrame {
|
||||
uint32_t edi;
|
||||
uint32_t esi;
|
||||
uint32_t ebp;
|
||||
uint32_t oesp;
|
||||
uint32_t ebx;
|
||||
uint32_t edx;
|
||||
uint32_t ecx;
|
||||
uint32_t eax;
|
||||
uint16_t gs;
|
||||
uint16_t fs;
|
||||
uint16_t es;
|
||||
uint16_t ds;
|
||||
uint32_t trapno;
|
||||
uint32_t err;
|
||||
uint32_t eip;
|
||||
uint32_t cs;
|
||||
uint32_t eflags;
|
||||
uint32_t esp;
|
||||
uint32_t ss;
|
||||
} TrapFrame;
|
||||
|
||||
typedef struct Process
|
||||
{
|
||||
uint32_t pid; // Process ID
|
||||
TaskState state; // Process state
|
||||
uintptr_t programCounter; // Program Counter
|
||||
uintptr_t* stackBase; // Top of the stack
|
||||
uintptr_t* stackPointer; // Stack Pointer
|
||||
uint32_t flags; // Status/Flags register
|
||||
struct Process* next; // Pointer to the next task in the list
|
||||
|
||||
uint32_t* page_directory;
|
||||
TaskState state; // Состояние процесса
|
||||
char* kstack; // Стек ядра
|
||||
Context* context; // Контекст для переключения
|
||||
TrapFrame* tf; // Trap frame (только для ring 3)
|
||||
uint32_t ring; // Уровень привилегий (0 или 3)
|
||||
struct Process* next; // Следующий процесс
|
||||
uint32_t* page_directory; // Директория страниц
|
||||
} Process;
|
||||
|
||||
Process* task_create(EntryPoint func, void** args, uint32_t arg_count);
|
||||
Process* task_create(EntryPoint func, void** args, uint32_t arg_count, uint32_t ring);
|
||||
void scheduler_init();
|
||||
void schedule();
|
||||
void scheduler_lock();
|
||||
void scheduler_unlock();
|
||||
|
||||
#endif
|
||||
+36
-89
@@ -1,117 +1,64 @@
|
||||
extern current
|
||||
global switchProcess
|
||||
|
||||
struc PCB
|
||||
.PID resd 1 ; Offset: 0
|
||||
.STATE resd 1 ; Offset: 4
|
||||
.PROGRAM_COUNTER resd 1 ; Offset: 8
|
||||
.STACK_BASE resd 1 ; Offset: 12
|
||||
.STACK_POINTER resd 1 ; Offset: 16
|
||||
.KSTACK resd 1 ; Offset: 8
|
||||
.CONTEXT resd 1 ; Offset: 12
|
||||
.TF resd 1 ; Offset: 16
|
||||
.FLAGS resd 1 ; Offset: 20
|
||||
.NEXT resd 1 ; Offset: 24
|
||||
.PAGE_DIRECTORY resd 1 ; Offset: 28
|
||||
endstruc
|
||||
|
||||
section .text
|
||||
|
||||
|
||||
; void switchProcess(Process* next)
|
||||
switchProcess:
|
||||
; __________Stack___________
|
||||
; |------------------------|
|
||||
; | Return Address (EIP) | +0
|
||||
; |------------------------|
|
||||
; | Process* next | +4
|
||||
; |------------------------|
|
||||
section .text
|
||||
global switchProcess
|
||||
extern current
|
||||
extern trapret
|
||||
|
||||
; Push volatile registers (per the 32-bit System V ABI)
|
||||
switchProcess:
|
||||
; Сохраняем регистры текущего процесса
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
push ebp
|
||||
|
||||
; __________Stack___________
|
||||
; |------------------------|
|
||||
; | EBP | +0
|
||||
; |------------------------|
|
||||
; | EDI | +4
|
||||
; |------------------------|
|
||||
; | ESI | +8
|
||||
; |------------------------|
|
||||
; | EBX | +12
|
||||
; |-------- ---------------|
|
||||
; | Return Address (EIP) | +16
|
||||
; |------------------------|
|
||||
; | Process* next | +20
|
||||
; |------------------------|
|
||||
|
||||
; Save current process' state
|
||||
; Сохраняем указатель стека в current->context
|
||||
mov edi, [current]
|
||||
; EDI now contains the pointer to [Process* current]
|
||||
; |-----|
|
||||
; | EDI | <== [Process* current]
|
||||
; |-----|
|
||||
mov [edi + 12], esp ; PCB.CONTEXT находится по смещению 12
|
||||
|
||||
; Set [current->PCB.STACK_POINTER] to the value in ESP
|
||||
; Process* current->PCB.STACK_POINTER <== ESP
|
||||
mov [edi + PCB.STACK_POINTER], esp
|
||||
|
||||
|
||||
; Load next process' state
|
||||
; ESP has been decremented by 16, so instead of +4,
|
||||
; we need to do +20. 4 pushes, 1 return address, 4
|
||||
; bytes each.
|
||||
mov esi, [esp + 20]
|
||||
; ESI now contains the pointer to [Process* next]
|
||||
; __________Stack___________
|
||||
; |------------------------|
|
||||
; | Return Address (EIP) | +16
|
||||
; |-----| |------------------------|
|
||||
; | ESI | <== | Process* next | +20
|
||||
; |-----| |------------------------|
|
||||
|
||||
|
||||
; Set [EXTERN Process* current] to the value in ESI
|
||||
; Process* current <== ESI (Process* next)
|
||||
; Загружаем следующий процесс
|
||||
mov esi, [esp + 20] ; next (первый аргумент)
|
||||
mov [current], esi
|
||||
mov esp, [esi + 12] ; Загружаем esp из next->context
|
||||
|
||||
mov esp, [esi + PCB.STACK_POINTER]
|
||||
; |-----| |-----|
|
||||
; | ESP | <== | ESI |
|
||||
; |-----| |-----|
|
||||
|
||||
; Restore non-volatile registers (per the 32-bit System V ABI)
|
||||
; Восстанавливаем регистры
|
||||
pop ebp
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
|
||||
; The stack is now restored to its original state.
|
||||
; __________Stack___________
|
||||
; |------------------------|
|
||||
; | Return Address (EIP) | +0
|
||||
; |------------------------|
|
||||
; | Process* next | +4
|
||||
; |------------------------|
|
||||
; Проверяем ring процесса
|
||||
mov eax, [esi + 20] ; PCB.RING находится по смещению 20
|
||||
cmp eax, 3
|
||||
je .ring3
|
||||
ret ; Для ring 0 просто возвращаемся
|
||||
.ring3:
|
||||
jmp trapret ; Для ring 3 переходим через trapret
|
||||
|
||||
ret
|
||||
trapret:
|
||||
; Восстанавливаем общие регистры из trap frame
|
||||
popal ; edi, esi, ebp, oesp, ebx, edx, ecx, eax
|
||||
add esp, 4 ; Пропускаем oesp (не используется)
|
||||
|
||||
global jump_usermode
|
||||
extern test_user_function
|
||||
jump_usermode:
|
||||
mov ax, (4 * 8) | 3 ; ring 3 data with bottom 2 bits set for ring 3
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax ; SS is handled by iret
|
||||
; Восстанавливаем сегментные регистры
|
||||
pop gs
|
||||
pop fs
|
||||
pop es
|
||||
pop ds
|
||||
|
||||
; and eax, ~0x80000000
|
||||
; mov cr0, eax
|
||||
; Пропускаем trapno и err
|
||||
add esp, 8 ; trapno (4 байта) + err (4 байта)
|
||||
|
||||
; set up the stack frame iret expects
|
||||
mov eax, esp
|
||||
push (4 * 8) | 3 ; data selector
|
||||
push eax ; current esp
|
||||
pushf ; eflags
|
||||
push (3 * 8) | 3 ; code selector (ring 3 code with bottom 2 bits set for ring 3)
|
||||
push test_user_function ; instruction address to return to
|
||||
|
||||
; Теперь ESP указывает на eip, cs, eflags, esp, ss
|
||||
iret
|
||||
+63
-39
@@ -11,52 +11,79 @@ uint32_t irq_disable_counter = 0;
|
||||
uint32_t pid_counter;
|
||||
uint32_t task_count;
|
||||
|
||||
#define STACK_SIZE 4096
|
||||
#define KSTACKSIZE 4096
|
||||
#define USTACKSIZE 4096
|
||||
|
||||
extern void trapret(void);
|
||||
extern void switchProcess(Process* next);
|
||||
extern Process* queue;
|
||||
extern Process* current;
|
||||
extern uint32_t pid_counter;
|
||||
extern uint32_t task_count;
|
||||
|
||||
// Функция запуска процесса в ядре, после которой произойдёт переход в ring 3
|
||||
static void processStartup()
|
||||
{
|
||||
printf("startup\n");
|
||||
scheduler_unlock();
|
||||
// Возврат из этой функции приведёт к вызову trapret
|
||||
}
|
||||
|
||||
Process* task_create(EntryPoint func, void** args, uint32_t arg_count)
|
||||
Process* task_create(EntryPoint func, void** args, uint32_t arg_count, uint32_t ring)
|
||||
{
|
||||
Process* p = heap_alloc(sizeof(Process));
|
||||
Process* p = alloc_page();//heap_alloc(sizeof(Process));
|
||||
p->pid = ++pid_counter;
|
||||
p->state = Ready;
|
||||
p->programCounter = 0;
|
||||
p->stackBase = heap_alloc(STACK_SIZE);
|
||||
p->stackPointer = (uintptr_t*)((uint32_t)p->stackBase + STACK_SIZE);
|
||||
p->ring = ring;
|
||||
|
||||
//put the arguments in stack
|
||||
for(int i = arg_count-1; i >=0; i--)
|
||||
*(--p->stackPointer) = (uintptr_t)args[i];
|
||||
// Выделяем стек ядра
|
||||
p->kstack = alloc_page();//heap_alloc(KSTACKSIZE);
|
||||
uint32_t* sp = (uint32_t*)(p->kstack + KSTACKSIZE);
|
||||
|
||||
// Добавляем адрес возврата (фиктивный, для выравнивания)
|
||||
*(--p->stackPointer) = 0; // Фиктивный адрес возврата (не используется напрямую)
|
||||
if (ring == DPL_USER) {
|
||||
// Настраиваем trap frame для ring 3
|
||||
sp -= sizeof(TrapFrame) / 4;
|
||||
p->tf = (TrapFrame*)sp;
|
||||
p->tf->cs = (SEG_UCODE << 3) | DPL_USER;
|
||||
p->tf->ds = (SEG_UDATA << 3) | DPL_USER;
|
||||
p->tf->es = p->tf->ds;
|
||||
p->tf->fs = p->tf->ds;
|
||||
p->tf->gs = p->tf->ds;
|
||||
p->tf->ss = p->tf->ds;
|
||||
p->tf->eflags = FL_IF;
|
||||
p->tf->eip = (uint32_t)func;
|
||||
p->tf->esp = USTACKSIZE; // Предполагаем, что пользовательский стек настроен
|
||||
|
||||
*(--p->stackPointer) = (uintptr_t)func;
|
||||
*(--p->stackPointer) = (uintptr_t)processStartup;
|
||||
*(--p->stackPointer) = 0;//ebp
|
||||
*(--p->stackPointer) = 0;//edi
|
||||
*(--p->stackPointer) = 0;//esi
|
||||
*(--p->stackPointer) = 0;//ebx
|
||||
// Добавляем адрес возврата для trapret
|
||||
sp -= 1;
|
||||
*sp = (uint32_t)trapret;
|
||||
} else {
|
||||
// Для ring 0 не используем trap frame
|
||||
p->tf = NULL;
|
||||
}
|
||||
// Настраиваем начальный контекст
|
||||
sp -= 5; // Место для edi, esi, ebx, ebp, eip
|
||||
p->context = (Context*)sp;
|
||||
p->context->edi = 0;
|
||||
p->context->esi = 0;
|
||||
p->context->ebx = 0;
|
||||
p->context->ebp = 0;
|
||||
if (ring == DPL_USER) {
|
||||
p->context->eip = (uint32_t)processStartup;
|
||||
} else {
|
||||
p->context->eip = (uint32_t)func; // Прямо в ring 0
|
||||
}
|
||||
|
||||
p->page_directory = kernel_page_directory;
|
||||
|
||||
p->next = 0;
|
||||
|
||||
if(!queue)
|
||||
{
|
||||
if (!queue) {
|
||||
queue = p;
|
||||
current = queue;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Process* curr = queue;
|
||||
while(curr->next)
|
||||
while (curr->next)
|
||||
curr = curr->next;
|
||||
curr->next = p;
|
||||
}
|
||||
@@ -64,6 +91,7 @@ Process* task_create(EntryPoint func, void** args, uint32_t arg_count)
|
||||
return p;
|
||||
}
|
||||
|
||||
// Остальные функции остаются без изменений
|
||||
void scheduler_lock()
|
||||
{
|
||||
asm volatile("cli");
|
||||
@@ -73,19 +101,19 @@ void scheduler_lock()
|
||||
void scheduler_unlock()
|
||||
{
|
||||
irq_disable_counter--;
|
||||
if(irq_disable_counter == 0)
|
||||
if (irq_disable_counter == 0)
|
||||
asm volatile("sti");
|
||||
}
|
||||
|
||||
void schedule()
|
||||
{
|
||||
if(!current)
|
||||
if (!current)
|
||||
return;
|
||||
|
||||
Process* next = current->next;
|
||||
if(!next)
|
||||
if (!next)
|
||||
next = queue;
|
||||
if(next != current)
|
||||
if (next != current)
|
||||
{
|
||||
//loadPageDirectory(next->page_directory);
|
||||
switchProcess(next);
|
||||
@@ -94,13 +122,13 @@ void schedule()
|
||||
|
||||
void idle()
|
||||
{
|
||||
while(1){}
|
||||
while (1) {}
|
||||
}
|
||||
|
||||
void task1(int arg1, char* arg2)
|
||||
{
|
||||
while(1){
|
||||
if(arg1 == 42)
|
||||
while (1) {
|
||||
if (arg1 == 42)
|
||||
printf("task1 0x%x %s\n", arg1, arg2);
|
||||
else
|
||||
printf("ZHOPA %s\n", arg2);
|
||||
@@ -109,22 +137,18 @@ void task1(int arg1, char* arg2)
|
||||
|
||||
void task2(int arg1, int arg2)
|
||||
{
|
||||
while(1){printf("task2 %X %X\n", arg1, arg2);}
|
||||
while (1) { arg1++; printf("task2 %X %X\n", arg1, arg2); }
|
||||
}
|
||||
|
||||
void jump_usermode2(void);
|
||||
|
||||
void scheduler_init()
|
||||
{
|
||||
jump_usermode2();
|
||||
//we create this task two times because in other case it just won't start
|
||||
task_create((EntryPoint)&idle, NULL, 0);
|
||||
task_create((EntryPoint)&idle, NULL, 0);
|
||||
task_create((EntryPoint)idle, NULL, 0, 0);
|
||||
task_create((EntryPoint)idle, NULL, 0, 0);
|
||||
|
||||
void* args1[] = {(void*)42, (void*)"ebalo"};
|
||||
task_create((EntryPoint)&task1, args1, 2);
|
||||
task_create((EntryPoint)task1, args1, 2, 0);
|
||||
void* args2[] = {(void*)69, (void*)420};
|
||||
task_create((EntryPoint)&task2, args2, 2);
|
||||
task_create((EntryPoint)task2, args2, 2, 0);
|
||||
}
|
||||
|
||||
#include "../include/string.h"
|
||||
|
||||
Reference in New Issue
Block a user