blob: 2f8c3a879237f91f5afcdea40429718803234819 [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
swissChili14d0b842023-01-01 02:22:44 -05008static struct process processes[1024] = {0};
9static struct 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
swissChiliaed6ff32021-05-29 17:51:04 -070014void init_tasks()
15{
swissChilie9289ee2021-03-20 21:54:28 -070016 processes[0] = (struct process){
17 .exists = true,
18 .id = 0,
19 .ring = 0,
20 .uid = 0,
swissChilicfd3c3c2021-04-03 15:04:24 -070021 .page_directory_p = VIRT_TO_PHYS(kernel_page_directory),
swissChili1e8b7562021-12-22 21:22:57 -080022 // Obviously this isn't the actual stack position, but we want
23 // it to grow down from 4 gb so we will pretend that the first
24 // task has its stack at exactly 4gb and work from
25 // there. Because the new stack will be mapped to any random
26 // frame, it doesn't actually matter where we put it, we just
27 // want somewhere that won't collide with any user space stuff
28 // or our heap.
swissChilicfd3c3c2021-04-03 15:04:24 -070029 .last_stack_pos = 0xFFFFF000,
swissChilie9289ee2021-03-20 21:54:28 -070030 };
31 strcpy(processes[0].name, "kernel");
swissChilie20b79b2021-03-17 21:20:13 -070032
swissChilie9289ee2021-03-20 21:54:28 -070033 first_task = last_task = current_task = malloc(sizeof(struct ll_task_i));
swissChilie20b79b2021-03-17 21:20:13 -070034
swissChilie9289ee2021-03-20 21:54:28 -070035 first_task->next = NULL;
swissChilif01ddcc2021-04-04 11:31:34 -070036 first_task->prev = NULL;
swissChili1e8b7562021-12-22 21:22:57 -080037 memset(&first_task->task, 0, sizeof(struct task));
swissChili14d0b842023-01-01 02:22:44 -050038 // state will be filled in upon task switch. TODO: task switch
39 // before spawning thread (or fill in CS, etc manually) to avoid
40 // #GP on task switch. New threads based on parent task
swissChilie9289ee2021-03-20 21:54:28 -070041 first_task->task = (struct task){
42 .proc = &processes[0],
swissChili14d0b842023-01-01 02:22:44 -050043 .state = { 0 },
swissChilicfd3c3c2021-04-03 15:04:24 -070044 .id = next_task_id++,
swissChili52a03d82021-07-18 15:22:14 -070045 .waiting = false,
swissChilie9289ee2021-03-20 21:54:28 -070046 };
swissChilie20b79b2021-03-17 21:20:13 -070047
swissChiliaed6ff32021-05-29 17:51:04 -070048 tasks_initialized = true;
swissChilie20b79b2021-03-17 21:20:13 -070049}
50
swissChilie9289ee2021-03-20 21:54:28 -070051struct process *get_process(uint pid)
swissChilie20b79b2021-03-17 21:20:13 -070052{
swissChilie9289ee2021-03-20 21:54:28 -070053 if (pid < 1024)
54 return &processes[pid];
55 else
56 return NULL;
57}
swissChilie20b79b2021-03-17 21:20:13 -070058
swissChilie9289ee2021-03-20 21:54:28 -070059int get_task_id()
60{
61 return current_task->task.id;
62}
swissChilie20b79b2021-03-17 21:20:13 -070063
swissChilie9289ee2021-03-20 21:54:28 -070064int get_process_id()
65{
66 return current_task->task.proc->id;
67}
68
swissChilif01ddcc2021-04-04 11:31:34 -070069void spawn_thread(void (*function)(void *), void *data)
swissChilie9289ee2021-03-20 21:54:28 -070070{
swissChili402a3832021-05-29 21:41:31 -070071 asm("cli");
swissChilie9289ee2021-03-20 21:54:28 -070072
swissChilib58ab672022-01-17 21:18:01 -080073 kprintf(DEBUG "Spawning thread %p, data=%p\n", function, data);
74
swissChilicfd3c3c2021-04-03 15:04:24 -070075 struct process *proc = current_task->task.proc;
76 // Virtual address of page directory (in kernel memory)
77 uint *dir_v = PHYS_TO_VIRT(proc->page_directory_p);
swissChilif01ddcc2021-04-04 11:31:34 -070078
swissChilid00ec612022-01-16 21:21:29 -080079 // Virtual location of new stack, with space reserved for argument
80 // and return address to kill_this_thread().
swissChili14d0b842023-01-01 02:22:44 -050081 uint *new_stack_base_v = (uint *)proc->last_stack_pos;
swissChilic496cd72021-04-04 09:58:38 -070082 proc->last_stack_pos -= 0x1000;
swissChilicfd3c3c2021-04-03 15:04:24 -070083
84 // Alloc a new page in the current process mapping to the new stack
swissChilic496cd72021-04-04 09:58:38 -070085 alloc_page(dir_v, (void *)proc->last_stack_pos);
swissChilicfd3c3c2021-04-03 15:04:24 -070086
swissChili14d0b842023-01-01 02:22:44 -050087 kprintf(INFO "new_stack_base_v = %p, last_stack_pos = %p\n",
88 new_stack_base_v, proc->last_stack_pos);
89
90 // Write data argument and return pointer to new threads stack
91 new_stack_base_v[-1] = (size_t)data;
92 new_stack_base_v[-2] = (size_t)&kill_this_thread;
swissChilicfd3c3c2021-04-03 15:04:24 -070093
swissChilib58ab672022-01-17 21:18:01 -080094 kprintf(DEBUG "Set stack\n");
95
swissChilicfd3c3c2021-04-03 15:04:24 -070096 struct ll_task_i *ll_task = malloc(sizeof(struct ll_task_i));
97 memset(ll_task, 0, sizeof(struct ll_task_i));
98 struct task *task = &ll_task->task;
swissChili1e8b7562021-12-22 21:22:57 -080099 // New task is basically the same as the old one but with just a
100 // few changes
101 *task = current_task->task;
swissChilicfd3c3c2021-04-03 15:04:24 -0700102
swissChili1e8b7562021-12-22 21:22:57 -0800103 // Namely a new TID
swissChilicfd3c3c2021-04-03 15:04:24 -0700104 task->id = next_task_id++;
swissChili1e8b7562021-12-22 21:22:57 -0800105 // And stack, frame, and instruction pointers
swissChili14d0b842023-01-01 02:22:44 -0500106 task->state.ebp = task->state.esp = (uint)(new_stack_base_v - 2);
swissChili1e8b7562021-12-22 21:22:57 -0800107 task->state.eip = (uint)function;
swissChili52a03d82021-07-18 15:22:14 -0700108 task->waiting = false;
swissChilicfd3c3c2021-04-03 15:04:24 -0700109
110 last_task->next = ll_task;
swissChilif01ddcc2021-04-04 11:31:34 -0700111 ll_task->prev = last_task;
swissChilicfd3c3c2021-04-03 15:04:24 -0700112 last_task = ll_task;
113
swissChili402a3832021-05-29 21:41:31 -0700114 asm("sti");
swissChilicfd3c3c2021-04-03 15:04:24 -0700115}
116
swissChilif01ddcc2021-04-04 11:31:34 -0700117void kill_this_thread()
118{
swissChili402a3832021-05-29 21:41:31 -0700119 asm("cli");
swissChilif01ddcc2021-04-04 11:31:34 -0700120
121 if (current_task->prev == NULL && current_task->next == NULL)
122 {
123 kpanic("You may not kill the last task in the kernel");
124 }
125
126 struct ll_task_i *task = first_task,
127 *old_task = current_task;
128
129 if (current_task->prev != NULL)
130 current_task->prev->next = current_task->next;
131
132 if (current_task->next != NULL)
133 {
swissChili1e8b7562021-12-22 21:22:57 -0800134 // If this is NULL, task will be first_task, which can't be
135 // the current task because we know there are more than one
136 // task, and this is the last one.
swissChilif01ddcc2021-04-04 11:31:34 -0700137 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
swissChili14d0b842023-01-01 02:22:44 -0500155extern uint _get_cr3();
156
swissChili1e8b7562021-12-22 21:22:57 -0800157extern void _switch_to_task(uint page_directory, struct registers ctx);
158#if 0
159{
160 asm("mov %0, %%ecx" :: "g"(page_directory));
161 asm("mov %ecx, %cr3");
162 // "ctx" will be at the top of the stack.
163 asm("iret");
164}
165#endif
swissChilicfd3c3c2021-04-03 15:04:24 -0700166
167void switch_to_task(struct task *task)
168{
swissChili14d0b842023-01-01 02:22:44 -0500169 kprintf(DEBUG "switch_to_task cr3=0x%x\n", task->proc->page_directory_p);
170
swissChili1e8b7562021-12-22 21:22:57 -0800171 _switch_to_task(task->proc->page_directory_p, task->state);
swissChilicfd3c3c2021-04-03 15:04:24 -0700172 __builtin_unreachable();
173}
174
swissChili1e8b7562021-12-22 21:22:57 -0800175void _do_switch_task(struct registers regs)
swissChilicfd3c3c2021-04-03 15:04:24 -0700176{
swissChilib58ab672022-01-17 21:18:01 -0800177 // Resetting eflags in _switch_to_task iret will switch this back
swissChili402a3832021-05-29 21:41:31 -0700178 asm("cli");
swissChilicfd3c3c2021-04-03 15:04:24 -0700179
swissChili14d0b842023-01-01 02:22:44 -0500180 kprintf(DEBUG "switching tasks, alleged cr3=0x%x, real cr3=0x%x\n",
181 current_task->task.proc->page_directory_p,
182 _get_cr3());
swissChilib58ab672022-01-17 21:18:01 -0800183
swissChilicfd3c3c2021-04-03 15:04:24 -0700184 // save context for this task
swissChili1e8b7562021-12-22 21:22:57 -0800185 current_task->task.state = regs;
swissChilicfd3c3c2021-04-03 15:04:24 -0700186
swissChili52a03d82021-07-18 15:22:14 -0700187 struct ll_task_i *original = current_task;
188
189 do
swissChilicfd3c3c2021-04-03 15:04:24 -0700190 {
swissChili52a03d82021-07-18 15:22:14 -0700191 if (current_task->next == NULL)
192 {
193 current_task = first_task;
194 }
195 else
196 {
197 // Continue the next task
198 current_task = current_task->next;
199 }
swissChilicfd3c3c2021-04-03 15:04:24 -0700200 }
swissChili52a03d82021-07-18 15:22:14 -0700201 while (current_task->task.waiting);
202
203 if (current_task == original && original->task.waiting)
swissChilicfd3c3c2021-04-03 15:04:24 -0700204 {
swissChili52a03d82021-07-18 15:22:14 -0700205 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 -0700206 }
207
swissChilicfd3c3c2021-04-03 15:04:24 -0700208 switch_to_task(&current_task->task);
swissChilie20b79b2021-03-17 21:20:13 -0700209}
swissChili52a03d82021-07-18 15:22:14 -0700210
211void set_waiting(int tid, bool waiting)
212{
213 asm("cli");
214
215 for (struct ll_task_i *t = first_task; t != NULL; t = t->next)
216 {
217 if (t->task.id == tid)
218 {
219 t->task.waiting = waiting;
220 break;
221 }
222 }
223
224 asm("sti");
225}
swissChili1e8b7562021-12-22 21:22:57 -0800226
227void switch_task(struct registers ctx)
228{
229 if (tasks_initialized)
230 _do_switch_task(ctx);
231}