Kernel address space isolation and make the kernel heap global to all processes.
[lunaix-os.git] / lunaix-os / kernel / sched.c
1 #include <lunaix/process.h>
2 #include <lunaix/sched.h>
3 #include <lunaix/mm/vmm.h>
4 #include <hal/cpu.h>
5 #include <arch/x86/interrupts.h>
6 #include <hal/apic.h>
7
8 #include <lunaix/spike.h>
9 #include <lunaix/status.h>
10 #include <lunaix/syslog.h>
11
12 #define MAX_PROCESS 512
13
14 struct proc_info* __current;
15 struct proc_info dummy;
16
17 extern void __proc_table;
18
19 struct scheduler sched_ctx;
20
21 LOG_MODULE("SCHED")
22
23 void sched_init() {
24     size_t pg_size = ROUNDUP(sizeof(struct proc_info) * MAX_PROCESS, 0x1000);
25     assert_msg(
26         vmm_alloc_pages(KERNEL_PID, &__proc_table, pg_size, PG_PREM_RW, PP_FGPERSIST), 
27         "Fail to allocate proc table"
28     );
29     
30     sched_ctx = (struct scheduler) {
31         ._procs = (struct proc_info*) &__proc_table,
32         .ptable_len = 0,
33         .procs_index = 0
34     };
35 }
36
37 void schedule() {
38     if (!sched_ctx.ptable_len) {
39         return;
40     }
41
42     struct proc_info* next;
43     int prev_ptr = sched_ctx.procs_index;
44     int ptr = prev_ptr;
45     // round-robin scheduler
46     do {
47         ptr = (ptr + 1) % sched_ctx.ptable_len;
48         next = &sched_ctx._procs[ptr];
49     } while((next->state != PROC_STOPPED && next->state != PROC_CREATED) && ptr != prev_ptr);
50     
51     sched_ctx.procs_index = ptr;
52     
53     __current->state = PROC_STOPPED;
54     next->state = PROC_RUNNING;
55     
56     __current = next;
57
58     cpu_lcr3(__current->page_table);
59
60     apic_done_servicing();
61
62     asm volatile (
63         "pushl %0\n"
64         "jmp soft_iret\n"::"r"(&__current->intr_ctx): "memory");
65 }
66
67 pid_t alloc_pid() {
68     pid_t i = 0;
69     for (; i < sched_ctx.ptable_len && sched_ctx._procs[i].state != PROC_DESTROY; i++);
70
71     if (i == MAX_PROCESS) {
72         __current->k_status = LXPROCFULL;
73         return -1;
74     }
75     return i + 1;
76 }
77
78 void push_process(struct proc_info* process) {
79     int index = process->pid - 1;
80     if (index < 0 || index > sched_ctx.ptable_len) {
81         __current->k_status = LXINVLDPID;
82         return;
83     }
84     
85     if (index == sched_ctx.ptable_len) {
86         sched_ctx.ptable_len++;
87     }
88     
89     process->parent = __current->pid;
90     process->state = PROC_CREATED;
91
92     sched_ctx._procs[index] = *process;
93 }
94
95 void destroy_process(pid_t pid) {
96     int index = pid - 1;
97     if (index < 0 || index > sched_ctx.ptable_len) {
98         __current->k_status = LXINVLDPID;
99         return;
100     }
101
102     sched_ctx._procs[index].state = PROC_DESTROY;
103
104     // TODO: recycle the physical pages used by page tables
105 }
106
107 void terminate_process(int exit_code) {
108     __current->state = PROC_TERMNAT;
109     __current->exit_code = exit_code;
110
111     schedule();
112 }
113
114 struct proc_info* get_process(pid_t pid) {
115     int index = pid - 1;
116     if (index < 0 || index > sched_ctx.ptable_len) {
117         return NULL;
118     }
119     return &sched_ctx._procs[index];
120 }