blob: 1285a44c20971e6d07d1131a7f067c669f2d571f [file] [log] [blame]
swissChilie20b79b2021-03-17 21:20:13 -07001#include "task.h"
2#include "alloc.h"
3#include "io.h"
swissChilicfd3c3c2021-04-03 15:04:24 -07004#include "log.h"
swissChilie20b79b2021-03-17 21:20:13 -07005#include "paging.h"
6
swissChilie9289ee2021-03-20 21:54:28 -07007struct process processes[1024] = {0};
8struct ll_task_i *first_task = NULL, *last_task = NULL, *current_task = NULL;
swissChilicfd3c3c2021-04-03 15:04:24 -07009static uint next_task_id = 0;
swissChilie9289ee2021-03-20 21:54:28 -070010
swissChilicfd3c3c2021-04-03 15:04:24 -070011void _init_tasks(uint kernel_esp, uint kernel_ebp, uint kernel_eip)
swissChilie20b79b2021-03-17 21:20:13 -070012{
swissChilicfd3c3c2021-04-03 15:04:24 -070013 kprintf("_init_tasks\n");
14
swissChilie9289ee2021-03-20 21:54:28 -070015 processes[0] = (struct process){
16 .exists = true,
17 .id = 0,
18 .ring = 0,
19 .uid = 0,
swissChilicfd3c3c2021-04-03 15:04:24 -070020 .page_directory_p = VIRT_TO_PHYS(kernel_page_directory),
21 // Obviously this isn't the actual stack position, but we want it to
22 // grow down from 4 gb so we will pretend that the first task has its
23 // stack at exactly 4gb and work from there. Because the new stack will
24 // be mapped to any random frame, it doesn't actually matter where we
25 // put it, we just want somewhere that won't collide with any user space
26 // stuff or our heap.
27 .last_stack_pos = 0xFFFFF000,
swissChilie9289ee2021-03-20 21:54:28 -070028 };
29 strcpy(processes[0].name, "kernel");
swissChilicfd3c3c2021-04-03 15:04:24 -070030 kprintf("in _init_tasks, strlen of 'kernel' is %d\n", strlen("kernel"));
swissChilie20b79b2021-03-17 21:20:13 -070031
swissChilie9289ee2021-03-20 21:54:28 -070032 first_task = last_task = current_task = malloc(sizeof(struct ll_task_i));
swissChilie20b79b2021-03-17 21:20:13 -070033
swissChilie9289ee2021-03-20 21:54:28 -070034 first_task->next = NULL;
swissChilif01ddcc2021-04-04 11:31:34 -070035 first_task->prev = NULL;
swissChilie9289ee2021-03-20 21:54:28 -070036 first_task->task = (struct task){
37 .proc = &processes[0],
38 .esp = kernel_esp,
39 .ebp = kernel_ebp,
40 .eip = kernel_eip,
swissChilicfd3c3c2021-04-03 15:04:24 -070041 .id = next_task_id++,
swissChilie9289ee2021-03-20 21:54:28 -070042 };
swissChilie20b79b2021-03-17 21:20:13 -070043
swissChilicfd3c3c2021-04-03 15:04:24 -070044 kprintf("Returning from _init_tasks\n");
swissChilie20b79b2021-03-17 21:20:13 -070045}
46
swissChilie9289ee2021-03-20 21:54:28 -070047struct process *get_process(uint pid)
swissChilie20b79b2021-03-17 21:20:13 -070048{
swissChilie9289ee2021-03-20 21:54:28 -070049 if (pid < 1024)
50 return &processes[pid];
51 else
52 return NULL;
53}
swissChilie20b79b2021-03-17 21:20:13 -070054
swissChilie9289ee2021-03-20 21:54:28 -070055int get_task_id()
56{
57 return current_task->task.id;
58}
swissChilie20b79b2021-03-17 21:20:13 -070059
swissChilie9289ee2021-03-20 21:54:28 -070060int get_process_id()
61{
62 return current_task->task.proc->id;
63}
64
swissChilif01ddcc2021-04-04 11:31:34 -070065void spawn_thread(void (*function)(void *), void *data)
swissChilie9289ee2021-03-20 21:54:28 -070066{
swissChilicfd3c3c2021-04-03 15:04:24 -070067 asm volatile("cli");
swissChilie9289ee2021-03-20 21:54:28 -070068
swissChilicfd3c3c2021-04-03 15:04:24 -070069 struct process *proc = current_task->task.proc;
70 // Virtual address of page directory (in kernel memory)
71 uint *dir_v = PHYS_TO_VIRT(proc->page_directory_p);
swissChilif01ddcc2021-04-04 11:31:34 -070072
73 // Virtual location of new stack, with space reserved for argument and
74 // return address to kill_this_thread().
75 uint new_stack_base_v = proc->last_stack_pos;
swissChilic496cd72021-04-04 09:58:38 -070076 proc->last_stack_pos -= 0x1000;
swissChilicfd3c3c2021-04-03 15:04:24 -070077
78 // Alloc a new page in the current process mapping to the new stack
swissChilic496cd72021-04-04 09:58:38 -070079 alloc_page(dir_v, (void *)proc->last_stack_pos);
swissChilicfd3c3c2021-04-03 15:04:24 -070080
swissChilif01ddcc2021-04-04 11:31:34 -070081 new_stack_base_v -= sizeof(uint);
82 *((uint *)new_stack_base_v) = (size_t)data;
83 new_stack_base_v -= sizeof(uint);
84 *((uint *)new_stack_base_v) = (size_t)&kill_this_thread;
swissChilicfd3c3c2021-04-03 15:04:24 -070085
86 struct ll_task_i *ll_task = malloc(sizeof(struct ll_task_i));
87 memset(ll_task, 0, sizeof(struct ll_task_i));
88 struct task *task = &ll_task->task;
89
90 task->proc = proc;
91 task->id = next_task_id++;
92 task->ebp = task->esp = new_stack_base_v;
93 task->eip = (uint)function;
94
95 last_task->next = ll_task;
swissChilif01ddcc2021-04-04 11:31:34 -070096 ll_task->prev = last_task;
swissChilicfd3c3c2021-04-03 15:04:24 -070097 last_task = ll_task;
98
99 asm volatile("sti");
100}
101
swissChilif01ddcc2021-04-04 11:31:34 -0700102void kill_this_thread()
103{
104 asm volatile("cli");
105
106 if (current_task->prev == NULL && current_task->next == NULL)
107 {
108 kpanic("You may not kill the last task in the kernel");
109 }
110
111 struct ll_task_i *task = first_task,
112 *old_task = current_task;
113
114 if (current_task->prev != NULL)
115 current_task->prev->next = current_task->next;
116
117 if (current_task->next != NULL)
118 {
119 // If this is NULL, task will be first_task, which can't be the current task
120 // because we know there are more than one task, and this is the last one.
121 current_task->next->prev = current_task->prev;
122 task = current_task->next;
123 }
124
125 if (current_task == first_task)
126 first_task = current_task->next;
127
128 if (current_task == last_task)
129 last_task = current_task->prev;
130
131 current_task = task;
132 free(old_task);
133
134 switch_to_task(&current_task->task);
135
136 asm volatile("sti");
137}
138
swissChilicfd3c3c2021-04-03 15:04:24 -0700139extern void _switch_to_task(uint page_directory, uint eip, uint ebp, uint esp);
140
141void switch_to_task(struct task *task)
142{
143 _switch_to_task(task->proc->page_directory_p, task->eip, task->ebp,
144 task->esp);
145 __builtin_unreachable();
146}
147
148// WARNING: do not call this manually, it will clobber everything
149// except esp, ebp, and eip (obviously). Use switch_task in task_api.s
150// instead.
151void _do_switch_task(uint eip, uint ebp, uint esp)
152{
153 // sti is called in switch_to_task
154 asm volatile("cli");
155
156 kprintf("\nin _do_switch_task(%d, %d, %d)\n", eip, ebp, esp);
157
158 // save context for this task
159 current_task->task.ebp = ebp;
160 current_task->task.esp = esp;
161 current_task->task.eip = eip;
162
163 if (current_task->next == NULL)
164 {
165 // Start from the first task if there are more tasks, or just return
166 if (current_task == first_task)
167 return; // No context switch necessary
168
169 current_task = first_task;
170 }
171 else
172 {
173 // Continue the next task
174 current_task = current_task->next;
175 }
176
177 kprintf("Will switch to task id %d\n", current_task->task.id);
178
179 switch_to_task(&current_task->task);
swissChilie20b79b2021-03-17 21:20:13 -0700180}