aboutsummaryrefslogtreecommitdiff
path: root/src/core/scheduler.cc
blob: fee571672ca10c062b124f73ab5dede499f70f3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include "scheduler.hpp"
#include "boucane.hpp"
#include "core/apic.hpp"

PROC procs[MAX_TASK];
u32 nproc=0;
char show_ticks=0;
char scheduling=0;
u32 active_process=0;

extern "C" void clock(){
    if(show_ticks)
        print(".");
    if(scheduling)
        schedule();
}
void schedule(){
    // First get a pointer to the first process saved register.
    // Since this is called by clock(), %rbp contains a pointer
    // to the clock() %rbp value and then we access to the registers SAVE_REGS in int.S
    u64* stack;
    asm("mov %%rbp, %%rax;mov (%%rax), %%rbx; add $16, %%rbx; mov %%rbx,%0": "=m"(stack)::"rax","rbx");
    
    // Save current task
    PROC *t=&procs[active_process];
    t->registers.r8=stack[0];
    t->registers.r9=stack[1];
    t->registers.r10=stack[2];
    t->registers.r11=stack[3];
    t->registers.r12=stack[4];
    t->registers.r13=stack[5];
    t->registers.r14=stack[6];
    t->registers.r15=stack[7];
    t->registers.rdi=stack[8];
    t->registers.rsi=stack[9];
    t->registers.rbp=stack[10];
    t->registers.rdx=stack[11];
    t->registers.rcx=stack[12];
    t->registers.rbx=stack[13];
    t->registers.rax=stack[14];
    t->registers.rip=stack[15];
    t->registers.cs=stack[16];
    t->registers.eflags=stack[17];
    t->registers.rsp=stack[18];
    t->registers.ds=stack[19];

    // Goto next task
    active_process++;
    if(active_process>=nproc)
        active_process=0;

    t=&procs[active_process];
    kvar_tss.rsp0=t->registers.rsp0;

    // Clock acknownledgement
    apic_ack();
    
    asm volatile(
        "mov %0, %%rdi       \n\t"  
        "jmp switch          \n\t"
        :: "a" (t)
    );
}


void create_task(void* task, u32 size){
    if(nproc>=MAX_TASK){
        printk("Could not create more tasks.");
        return;
    }

    PROC *t=&procs[nproc];
    t->id=nproc;
    t->pid=nproc;
    t->size=size;

    u32 npages=size%4096 ? size/4096 + 1 : size/4096;
    // Note that paging_create_task() allocate 2 more pages (one for the user stack and
    // the other for the kernel stack)
    t->pml4=paging_create_task(npages);
    t->registers.rsp=TASK_VMA+npages*4096+4096;   // User stack
    t->registers.rsp0=TASK_VMA+npages*4096+4096*2;  // Kernel stack on the last page

    t->registers.rip=TASK_VMA;
    t->registers.cs=0x1B; // 0x18 and 0x3 privilege
    t->registers.ds=0x23; // 0x20 and 0x3 privilege

    // Load task using
    lpml4(t->pml4);
    memcpy(task, TASK_VMA, size);
    lpml4(kpml4);
    
    nproc++;
}

void scheduler_start(){
    scheduling=1;
    active_process=0;
    PROC *t=&procs[active_process];
    kvar_tss.rsp0=t->registers.rsp0;
    asm(
        "cli             \n\t"
        "mov %0, %%rdi   \n\t"    
        "jmp switch      \n\t"
        :: "r" (t)
    );
}