blob: 116e4a283fff6974ff0d709c565deb22053247ce [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"
swissChiliaed6ff32021-05-29 17:51:04 -07006#include "pic.h"
swissChilie20b79b2021-03-17 21:20:13 -07007
swissChilie9289ee2021-03-20 21:54:28 -07008struct process processes[1024] = {0};
9struct ll_task_i *first_task = NULL, *last_task = NULL, *current_task = NULL;
swissChilicfd3c3c2021-04-03 15:04:24 -070010static uint next_task_id = 0;
swissChilie9289ee2021-03-20 21:54:28 -070011
swissChiliaed6ff32021-05-29 17:51:04 -070012bool tasks_initialized = false;
13
14void _init_tasks(uint kernel_esp, uint kernel_ebp, uint kernel_eip);
15
16void init_tasks()
17{
18 add_interrupt_handler(INIT_TASKS_INTERRUPT, _sys_init_tasks_h);
19
swissChiliee6d10d2021-05-29 18:05:16 -070020 asm("int $0x81");
swissChiliaed6ff32021-05-29 17:51:04 -070021}
22
23void _sys_init_tasks_h(struct registers *regs)
24{
25 _init_tasks(regs->esp, regs->ebp, regs->eip);
26}
27
swissChilicfd3c3c2021-04-03 15:04:24 -070028void _init_tasks(uint kernel_esp, uint kernel_ebp, uint kernel_eip)
swissChilie20b79b2021-03-17 21:20:13 -070029{
swissChilie9289ee2021-03-20 21:54:28 -070030 processes[0] = (struct process){
31 .exists = true,
32 .id = 0,
33 .ring = 0,
34 .uid = 0,
swissChilicfd3c3c2021-04-03 15:04:24 -070035 .page_directory_p = VIRT_TO_PHYS(kernel_page_directory),
36 // Obviously this isn't the actual stack position, but we want it to
37 // grow down from 4 gb so we will pretend that the first task has its
38 // stack at exactly 4gb and work from there. Because the new stack will
39 // be mapped to any random frame, it doesn't actually matter where we
40 // put it, we just want somewhere that won't collide with any user space
41 // stuff or our heap.
42 .last_stack_pos = 0xFFFFF000,
swissChilie9289ee2021-03-20 21:54:28 -070043 };
44 strcpy(processes[0].name, "kernel");
swissChilie20b79b2021-03-17 21:20:13 -070045
swissChilie9289ee2021-03-20 21:54:28 -070046 first_task = last_task = current_task = malloc(sizeof(struct ll_task_i));
swissChilie20b79b2021-03-17 21:20:13 -070047
swissChilie9289ee2021-03-20 21:54:28 -070048 first_task->next = NULL;
swissChilif01ddcc2021-04-04 11:31:34 -070049 first_task->prev = NULL;
swissChilie9289ee2021-03-20 21:54:28 -070050 first_task->task = (struct task){
51 .proc = &processes[0],
52 .esp = kernel_esp,
53 .ebp = kernel_ebp,
54 .eip = kernel_eip,
swissChilicfd3c3c2021-04-03 15:04:24 -070055 .id = next_task_id++,
swissChili52a03d82021-07-18 15:22:14 -070056 .waiting = false,
swissChilie9289ee2021-03-20 21:54:28 -070057 };
swissChilie20b79b2021-03-17 21:20:13 -070058
swissChiliaed6ff32021-05-29 17:51:04 -070059 tasks_initialized = true;
swissChilie20b79b2021-03-17 21:20:13 -070060}
61
swissChilie9289ee2021-03-20 21:54:28 -070062struct process *get_process(uint pid)
swissChilie20b79b2021-03-17 21:20:13 -070063{
swissChilie9289ee2021-03-20 21:54:28 -070064 if (pid < 1024)
65 return &processes[pid];
66 else
67 return NULL;
68}
swissChilie20b79b2021-03-17 21:20:13 -070069
swissChilie9289ee2021-03-20 21:54:28 -070070int get_task_id()
71{
72 return current_task->task.id;
73}
swissChilie20b79b2021-03-17 21:20:13 -070074
swissChilie9289ee2021-03-20 21:54:28 -070075int get_process_id()
76{
77 return current_task->task.proc->id;
78}
79
swissChilif01ddcc2021-04-04 11:31:34 -070080void spawn_thread(void (*function)(void *), void *data)
swissChilie9289ee2021-03-20 21:54:28 -070081{
swissChili402a3832021-05-29 21:41:31 -070082 asm("cli");
swissChilie9289ee2021-03-20 21:54:28 -070083
swissChilicfd3c3c2021-04-03 15:04:24 -070084 struct process *proc = current_task->task.proc;
85 // Virtual address of page directory (in kernel memory)
86 uint *dir_v = PHYS_TO_VIRT(proc->page_directory_p);
swissChilif01ddcc2021-04-04 11:31:34 -070087
88 // Virtual location of new stack, with space reserved for argument and
89 // return address to kill_this_thread().
90 uint new_stack_base_v = proc->last_stack_pos;
swissChilic496cd72021-04-04 09:58:38 -070091 proc->last_stack_pos -= 0x1000;
swissChilicfd3c3c2021-04-03 15:04:24 -070092
93 // Alloc a new page in the current process mapping to the new stack
swissChilic496cd72021-04-04 09:58:38 -070094 alloc_page(dir_v, (void *)proc->last_stack_pos);
swissChilicfd3c3c2021-04-03 15:04:24 -070095
swissChilif01ddcc2021-04-04 11:31:34 -070096 new_stack_base_v -= sizeof(uint);
97 *((uint *)new_stack_base_v) = (size_t)data;
98 new_stack_base_v -= sizeof(uint);
99 *((uint *)new_stack_base_v) = (size_t)&kill_this_thread;
swissChilicfd3c3c2021-04-03 15:04:24 -0700100
101 struct ll_task_i *ll_task = malloc(sizeof(struct ll_task_i));
102 memset(ll_task, 0, sizeof(struct ll_task_i));
103 struct task *task = &ll_task->task;
104
105 task->proc = proc;
106 task->id = next_task_id++;
107 task->ebp = task->esp = new_stack_base_v;
108 task->eip = (uint)function;
swissChili52a03d82021-07-18 15:22:14 -0700109 task->waiting = false;
swissChilicfd3c3c2021-04-03 15:04:24 -0700110
111 last_task->next = ll_task;
swissChilif01ddcc2021-04-04 11:31:34 -0700112 ll_task->prev = last_task;
swissChilicfd3c3c2021-04-03 15:04:24 -0700113 last_task = ll_task;
114
swissChili402a3832021-05-29 21:41:31 -0700115 asm("sti");
swissChilicfd3c3c2021-04-03 15:04:24 -0700116}
117
swissChilif01ddcc2021-04-04 11:31:34 -0700118void kill_this_thread()
119{
swissChili402a3832021-05-29 21:41:31 -0700120 asm("cli");
swissChilif01ddcc2021-04-04 11:31:34 -0700121
122 if (current_task->prev == NULL && current_task->next == NULL)
123 {
124 kpanic("You may not kill the last task in the kernel");
125 }
126
127 struct ll_task_i *task = first_task,
128 *old_task = current_task;
129
130 if (current_task->prev != NULL)
131 current_task->prev->next = current_task->next;
132
133 if (current_task->next != NULL)
134 {
135 // If this is NULL, task will be first_task, which can't be the current task
136 // because we know there are more than one task, and this is the last one.
137 current_task->next->prev = current_task->prev;
138 task = current_task->next;
139 }
140
141 if (current_task == first_task)
142 first_task = current_task->next;
143
144 if (current_task == last_task)
145 last_task = current_task->prev;
146
147 current_task = task;
148 free(old_task);
149
150 switch_to_task(&current_task->task);
151
swissChili402a3832021-05-29 21:41:31 -0700152 asm("sti");
swissChilif01ddcc2021-04-04 11:31:34 -0700153}
154
swissChilicfd3c3c2021-04-03 15:04:24 -0700155extern void _switch_to_task(uint page_directory, uint eip, uint ebp, uint esp);
156
157void switch_to_task(struct task *task)
158{
159 _switch_to_task(task->proc->page_directory_p, task->eip, task->ebp,
160 task->esp);
161 __builtin_unreachable();
162}
163
164// WARNING: do not call this manually, it will clobber everything
165// except esp, ebp, and eip (obviously). Use switch_task in task_api.s
166// instead.
167void _do_switch_task(uint eip, uint ebp, uint esp)
168{
169 // sti is called in switch_to_task
swissChili402a3832021-05-29 21:41:31 -0700170 asm("cli");
swissChilicfd3c3c2021-04-03 15:04:24 -0700171
swissChilicfd3c3c2021-04-03 15:04:24 -0700172 // save context for this task
173 current_task->task.ebp = ebp;
174 current_task->task.esp = esp;
175 current_task->task.eip = eip;
176
swissChili52a03d82021-07-18 15:22:14 -0700177 struct ll_task_i *original = current_task;
178
179 do
swissChilicfd3c3c2021-04-03 15:04:24 -0700180 {
swissChili52a03d82021-07-18 15:22:14 -0700181 if (current_task->next == NULL)
182 {
183 current_task = first_task;
184 }
185 else
186 {
187 // Continue the next task
188 current_task = current_task->next;
189 }
swissChilicfd3c3c2021-04-03 15:04:24 -0700190 }
swissChili52a03d82021-07-18 15:22:14 -0700191 while (current_task->task.waiting);
192
193 if (current_task == original && original->task.waiting)
swissChilicfd3c3c2021-04-03 15:04:24 -0700194 {
swissChili52a03d82021-07-18 15:22:14 -0700195 kpanic("All tasks are waiting for I/O. There must be at least 1 task using CPU at all times.");
swissChilicfd3c3c2021-04-03 15:04:24 -0700196 }
197
swissChilicfd3c3c2021-04-03 15:04:24 -0700198 switch_to_task(&current_task->task);
swissChilie20b79b2021-03-17 21:20:13 -0700199}
swissChili52a03d82021-07-18 15:22:14 -0700200
201void set_waiting(int tid, bool waiting)
202{
203 asm("cli");
204
205 for (struct ll_task_i *t = first_task; t != NULL; t = t->next)
206 {
207 if (t->task.id == tid)
208 {
209 t->task.waiting = waiting;
210 break;
211 }
212 }
213
214 asm("sti");
215}