blob: 53a31e61c9539f4779b724d270dd030fefd2280f [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
20 asm("int $0x80");
21}
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{
swissChiliaed6ff32021-05-29 17:51:04 -070030 kpanic("_init_tasks\n");
swissChilicfd3c3c2021-04-03 15:04:24 -070031
swissChilie9289ee2021-03-20 21:54:28 -070032 processes[0] = (struct process){
33 .exists = true,
34 .id = 0,
35 .ring = 0,
36 .uid = 0,
swissChilicfd3c3c2021-04-03 15:04:24 -070037 .page_directory_p = VIRT_TO_PHYS(kernel_page_directory),
38 // Obviously this isn't the actual stack position, but we want it to
39 // grow down from 4 gb so we will pretend that the first task has its
40 // stack at exactly 4gb and work from there. Because the new stack will
41 // be mapped to any random frame, it doesn't actually matter where we
42 // put it, we just want somewhere that won't collide with any user space
43 // stuff or our heap.
44 .last_stack_pos = 0xFFFFF000,
swissChilie9289ee2021-03-20 21:54:28 -070045 };
46 strcpy(processes[0].name, "kernel");
swissChilicfd3c3c2021-04-03 15:04:24 -070047 kprintf("in _init_tasks, strlen of 'kernel' is %d\n", strlen("kernel"));
swissChilie20b79b2021-03-17 21:20:13 -070048
swissChilie9289ee2021-03-20 21:54:28 -070049 first_task = last_task = current_task = malloc(sizeof(struct ll_task_i));
swissChilie20b79b2021-03-17 21:20:13 -070050
swissChilie9289ee2021-03-20 21:54:28 -070051 first_task->next = NULL;
swissChilif01ddcc2021-04-04 11:31:34 -070052 first_task->prev = NULL;
swissChilie9289ee2021-03-20 21:54:28 -070053 first_task->task = (struct task){
54 .proc = &processes[0],
55 .esp = kernel_esp,
56 .ebp = kernel_ebp,
57 .eip = kernel_eip,
swissChilicfd3c3c2021-04-03 15:04:24 -070058 .id = next_task_id++,
swissChilie9289ee2021-03-20 21:54:28 -070059 };
swissChilie20b79b2021-03-17 21:20:13 -070060
swissChilicfd3c3c2021-04-03 15:04:24 -070061 kprintf("Returning from _init_tasks\n");
swissChiliaed6ff32021-05-29 17:51:04 -070062
63 tasks_initialized = true;
swissChilie20b79b2021-03-17 21:20:13 -070064}
65
swissChilie9289ee2021-03-20 21:54:28 -070066struct process *get_process(uint pid)
swissChilie20b79b2021-03-17 21:20:13 -070067{
swissChilie9289ee2021-03-20 21:54:28 -070068 if (pid < 1024)
69 return &processes[pid];
70 else
71 return NULL;
72}
swissChilie20b79b2021-03-17 21:20:13 -070073
swissChilie9289ee2021-03-20 21:54:28 -070074int get_task_id()
75{
76 return current_task->task.id;
77}
swissChilie20b79b2021-03-17 21:20:13 -070078
swissChilie9289ee2021-03-20 21:54:28 -070079int get_process_id()
80{
81 return current_task->task.proc->id;
82}
83
swissChilif01ddcc2021-04-04 11:31:34 -070084void spawn_thread(void (*function)(void *), void *data)
swissChilie9289ee2021-03-20 21:54:28 -070085{
swissChilicfd3c3c2021-04-03 15:04:24 -070086 asm volatile("cli");
swissChilie9289ee2021-03-20 21:54:28 -070087
swissChilicfd3c3c2021-04-03 15:04:24 -070088 struct process *proc = current_task->task.proc;
89 // Virtual address of page directory (in kernel memory)
90 uint *dir_v = PHYS_TO_VIRT(proc->page_directory_p);
swissChilif01ddcc2021-04-04 11:31:34 -070091
92 // Virtual location of new stack, with space reserved for argument and
93 // return address to kill_this_thread().
94 uint new_stack_base_v = proc->last_stack_pos;
swissChilic496cd72021-04-04 09:58:38 -070095 proc->last_stack_pos -= 0x1000;
swissChilicfd3c3c2021-04-03 15:04:24 -070096
97 // Alloc a new page in the current process mapping to the new stack
swissChilic496cd72021-04-04 09:58:38 -070098 alloc_page(dir_v, (void *)proc->last_stack_pos);
swissChilicfd3c3c2021-04-03 15:04:24 -070099
swissChilif01ddcc2021-04-04 11:31:34 -0700100 new_stack_base_v -= sizeof(uint);
101 *((uint *)new_stack_base_v) = (size_t)data;
102 new_stack_base_v -= sizeof(uint);
103 *((uint *)new_stack_base_v) = (size_t)&kill_this_thread;
swissChilicfd3c3c2021-04-03 15:04:24 -0700104
105 struct ll_task_i *ll_task = malloc(sizeof(struct ll_task_i));
106 memset(ll_task, 0, sizeof(struct ll_task_i));
107 struct task *task = &ll_task->task;
108
109 task->proc = proc;
110 task->id = next_task_id++;
111 task->ebp = task->esp = new_stack_base_v;
112 task->eip = (uint)function;
113
114 last_task->next = ll_task;
swissChilif01ddcc2021-04-04 11:31:34 -0700115 ll_task->prev = last_task;
swissChilicfd3c3c2021-04-03 15:04:24 -0700116 last_task = ll_task;
117
118 asm volatile("sti");
119}
120
swissChilif01ddcc2021-04-04 11:31:34 -0700121void kill_this_thread()
122{
123 asm volatile("cli");
124
125 if (current_task->prev == NULL && current_task->next == NULL)
126 {
127 kpanic("You may not kill the last task in the kernel");
128 }
129
130 struct ll_task_i *task = first_task,
131 *old_task = current_task;
132
133 if (current_task->prev != NULL)
134 current_task->prev->next = current_task->next;
135
136 if (current_task->next != NULL)
137 {
138 // If this is NULL, task will be first_task, which can't be the current task
139 // because we know there are more than one task, and this is the last one.
140 current_task->next->prev = current_task->prev;
141 task = current_task->next;
142 }
143
144 if (current_task == first_task)
145 first_task = current_task->next;
146
147 if (current_task == last_task)
148 last_task = current_task->prev;
149
150 current_task = task;
151 free(old_task);
152
153 switch_to_task(&current_task->task);
154
155 asm volatile("sti");
156}
157
swissChilicfd3c3c2021-04-03 15:04:24 -0700158extern void _switch_to_task(uint page_directory, uint eip, uint ebp, uint esp);
159
160void switch_to_task(struct task *task)
161{
162 _switch_to_task(task->proc->page_directory_p, task->eip, task->ebp,
163 task->esp);
164 __builtin_unreachable();
165}
166
167// WARNING: do not call this manually, it will clobber everything
168// except esp, ebp, and eip (obviously). Use switch_task in task_api.s
169// instead.
170void _do_switch_task(uint eip, uint ebp, uint esp)
171{
172 // sti is called in switch_to_task
173 asm volatile("cli");
174
swissChilicfd3c3c2021-04-03 15:04:24 -0700175 // save context for this task
176 current_task->task.ebp = ebp;
177 current_task->task.esp = esp;
178 current_task->task.eip = eip;
179
180 if (current_task->next == NULL)
181 {
swissChilicfd3c3c2021-04-03 15:04:24 -0700182 current_task = first_task;
183 }
184 else
185 {
186 // Continue the next task
187 current_task = current_task->next;
188 }
189
swissChilicfd3c3c2021-04-03 15:04:24 -0700190 switch_to_task(&current_task->task);
swissChilie20b79b2021-03-17 21:20:13 -0700191}