blob: 1ec1337995cd7e3f800563134bd5c4fb149bb620 [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
swissChili1e8b7562021-12-22 21:22:57 -080014void _init_tasks(struct registers *regs);
swissChiliaed6ff32021-05-29 17:51:04 -070015
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{
swissChili1e8b7562021-12-22 21:22:57 -080025 _init_tasks(regs);
swissChiliaed6ff32021-05-29 17:51:04 -070026}
27
swissChili1e8b7562021-12-22 21:22:57 -080028void _init_tasks(struct registers *regs)
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),
swissChili1e8b7562021-12-22 21:22:57 -080036 // Obviously this isn't the actual stack position, but we want
37 // it to grow down from 4 gb so we will pretend that the first
38 // task has its stack at exactly 4gb and work from
39 // there. Because the new stack will be mapped to any random
40 // frame, it doesn't actually matter where we put it, we just
41 // want somewhere that won't collide with any user space stuff
42 // or our heap.
swissChilicfd3c3c2021-04-03 15:04:24 -070043 .last_stack_pos = 0xFFFFF000,
swissChilie9289ee2021-03-20 21:54:28 -070044 };
45 strcpy(processes[0].name, "kernel");
swissChilie20b79b2021-03-17 21:20:13 -070046
swissChilie9289ee2021-03-20 21:54:28 -070047 first_task = last_task = current_task = malloc(sizeof(struct ll_task_i));
swissChilie20b79b2021-03-17 21:20:13 -070048
swissChilie9289ee2021-03-20 21:54:28 -070049 first_task->next = NULL;
swissChilif01ddcc2021-04-04 11:31:34 -070050 first_task->prev = NULL;
swissChili1e8b7562021-12-22 21:22:57 -080051 memset(&first_task->task, 0, sizeof(struct task));
swissChilie9289ee2021-03-20 21:54:28 -070052 first_task->task = (struct task){
53 .proc = &processes[0],
swissChili1e8b7562021-12-22 21:22:57 -080054 .state = *regs,
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
swissChilib58ab672022-01-17 21:18:01 -080084 kprintf(DEBUG "Spawning thread %p, data=%p\n", function, data);
85
swissChilicfd3c3c2021-04-03 15:04:24 -070086 struct process *proc = current_task->task.proc;
87 // Virtual address of page directory (in kernel memory)
88 uint *dir_v = PHYS_TO_VIRT(proc->page_directory_p);
swissChilif01ddcc2021-04-04 11:31:34 -070089
swissChilid00ec612022-01-16 21:21:29 -080090 // Virtual location of new stack, with space reserved for argument
91 // and return address to kill_this_thread().
swissChilif01ddcc2021-04-04 11:31:34 -070092 uint new_stack_base_v = proc->last_stack_pos;
swissChilic496cd72021-04-04 09:58:38 -070093 proc->last_stack_pos -= 0x1000;
swissChilicfd3c3c2021-04-03 15:04:24 -070094
95 // Alloc a new page in the current process mapping to the new stack
swissChilic496cd72021-04-04 09:58:38 -070096 alloc_page(dir_v, (void *)proc->last_stack_pos);
swissChilicfd3c3c2021-04-03 15:04:24 -070097
swissChilib58ab672022-01-17 21:18:01 -080098 kprintf(INFO "new_stack_base_v = %p\n", new_stack_base_v);
swissChilif01ddcc2021-04-04 11:31:34 -070099 new_stack_base_v -= sizeof(uint);
100 *((uint *)new_stack_base_v) = (size_t)data;
101 new_stack_base_v -= sizeof(uint);
102 *((uint *)new_stack_base_v) = (size_t)&kill_this_thread;
swissChilicfd3c3c2021-04-03 15:04:24 -0700103
swissChilib58ab672022-01-17 21:18:01 -0800104 kprintf(DEBUG "Set stack\n");
105
swissChilicfd3c3c2021-04-03 15:04:24 -0700106 struct ll_task_i *ll_task = malloc(sizeof(struct ll_task_i));
107 memset(ll_task, 0, sizeof(struct ll_task_i));
108 struct task *task = &ll_task->task;
swissChili1e8b7562021-12-22 21:22:57 -0800109 // New task is basically the same as the old one but with just a
110 // few changes
111 *task = current_task->task;
swissChilicfd3c3c2021-04-03 15:04:24 -0700112
swissChili1e8b7562021-12-22 21:22:57 -0800113 // Namely a new TID
swissChilicfd3c3c2021-04-03 15:04:24 -0700114 task->id = next_task_id++;
swissChili1e8b7562021-12-22 21:22:57 -0800115 // And stack, frame, and instruction pointers
116 task->state.ebp = task->state.esp = new_stack_base_v;
117 task->state.eip = (uint)function;
swissChili52a03d82021-07-18 15:22:14 -0700118 task->waiting = false;
swissChilicfd3c3c2021-04-03 15:04:24 -0700119
120 last_task->next = ll_task;
swissChilif01ddcc2021-04-04 11:31:34 -0700121 ll_task->prev = last_task;
swissChilicfd3c3c2021-04-03 15:04:24 -0700122 last_task = ll_task;
123
swissChili402a3832021-05-29 21:41:31 -0700124 asm("sti");
swissChilicfd3c3c2021-04-03 15:04:24 -0700125}
126
swissChilif01ddcc2021-04-04 11:31:34 -0700127void kill_this_thread()
128{
swissChili402a3832021-05-29 21:41:31 -0700129 asm("cli");
swissChilif01ddcc2021-04-04 11:31:34 -0700130
131 if (current_task->prev == NULL && current_task->next == NULL)
132 {
133 kpanic("You may not kill the last task in the kernel");
134 }
135
136 struct ll_task_i *task = first_task,
137 *old_task = current_task;
138
139 if (current_task->prev != NULL)
140 current_task->prev->next = current_task->next;
141
142 if (current_task->next != NULL)
143 {
swissChili1e8b7562021-12-22 21:22:57 -0800144 // If this is NULL, task will be first_task, which can't be
145 // the current task because we know there are more than one
146 // task, and this is the last one.
swissChilif01ddcc2021-04-04 11:31:34 -0700147 current_task->next->prev = current_task->prev;
148 task = current_task->next;
149 }
150
151 if (current_task == first_task)
152 first_task = current_task->next;
153
154 if (current_task == last_task)
155 last_task = current_task->prev;
156
157 current_task = task;
158 free(old_task);
159
160 switch_to_task(&current_task->task);
161
swissChili402a3832021-05-29 21:41:31 -0700162 asm("sti");
swissChilif01ddcc2021-04-04 11:31:34 -0700163}
164
swissChili1e8b7562021-12-22 21:22:57 -0800165extern void _switch_to_task(uint page_directory, struct registers ctx);
166#if 0
167{
168 asm("mov %0, %%ecx" :: "g"(page_directory));
169 asm("mov %ecx, %cr3");
170 // "ctx" will be at the top of the stack.
171 asm("iret");
172}
173#endif
swissChilicfd3c3c2021-04-03 15:04:24 -0700174
175void switch_to_task(struct task *task)
176{
swissChili1e8b7562021-12-22 21:22:57 -0800177 _switch_to_task(task->proc->page_directory_p, task->state);
swissChilicfd3c3c2021-04-03 15:04:24 -0700178 __builtin_unreachable();
179}
180
swissChili1e8b7562021-12-22 21:22:57 -0800181void _do_switch_task(struct registers regs)
swissChilicfd3c3c2021-04-03 15:04:24 -0700182{
swissChilib58ab672022-01-17 21:18:01 -0800183 // Resetting eflags in _switch_to_task iret will switch this back
swissChili402a3832021-05-29 21:41:31 -0700184 asm("cli");
swissChilicfd3c3c2021-04-03 15:04:24 -0700185
swissChilib58ab672022-01-17 21:18:01 -0800186 kprintf(DEBUG "switching tasks\n");
187
swissChilicfd3c3c2021-04-03 15:04:24 -0700188 // save context for this task
swissChili1e8b7562021-12-22 21:22:57 -0800189 current_task->task.state = regs;
swissChilicfd3c3c2021-04-03 15:04:24 -0700190
swissChili52a03d82021-07-18 15:22:14 -0700191 struct ll_task_i *original = current_task;
192
193 do
swissChilicfd3c3c2021-04-03 15:04:24 -0700194 {
swissChili52a03d82021-07-18 15:22:14 -0700195 if (current_task->next == NULL)
196 {
197 current_task = first_task;
198 }
199 else
200 {
201 // Continue the next task
202 current_task = current_task->next;
203 }
swissChilicfd3c3c2021-04-03 15:04:24 -0700204 }
swissChili52a03d82021-07-18 15:22:14 -0700205 while (current_task->task.waiting);
206
207 if (current_task == original && original->task.waiting)
swissChilicfd3c3c2021-04-03 15:04:24 -0700208 {
swissChili52a03d82021-07-18 15:22:14 -0700209 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 -0700210 }
211
swissChilicfd3c3c2021-04-03 15:04:24 -0700212 switch_to_task(&current_task->task);
swissChilie20b79b2021-03-17 21:20:13 -0700213}
swissChili52a03d82021-07-18 15:22:14 -0700214
215void set_waiting(int tid, bool waiting)
216{
217 asm("cli");
218
219 for (struct ll_task_i *t = first_task; t != NULL; t = t->next)
220 {
221 if (t->task.id == tid)
222 {
223 t->task.waiting = waiting;
224 break;
225 }
226 }
227
228 asm("sti");
229}
swissChili1e8b7562021-12-22 21:22:57 -0800230
231void switch_task(struct registers ctx)
232{
233 if (tasks_initialized)
234 _do_switch_task(ctx);
235}