blob: 09156d4ae4341e887d52cfadd2571ef722c7bf53 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
#include "task.h"
#include "timer.h"
#include "memory.h"
#include "panic.h"
#include "cpu.h"
#include "kprint.h"
struct kc_thread *current_task = NULL;
struct kc_thread *first_ready_task = NULL;
struct kc_thread *last_ready_task = NULL;
static int schedule_lock_cnt = 0;
static void lock_scheduler(void);
static void unlock_scheduler(void);
static void set_thread_status(enum kc_thread_status status);
static void idle_task_thread(void);
extern uint64_t *get_tss_rsp0(void);
static uint64_t last_count = 0;
void update_time_used(void)
{
uint64_t current_count = timer_ticks();
uint64_t elapsed = current_count - last_count;
last_count = current_count;
current_task->time_elapsed += elapsed;
}
void task_set_thread(struct kc_thread *task)
{
// wrapper around cpu_set_thread
uint64_t *rsp0 = get_tss_rsp0();
cpu_set_thread(¤t_task->state, &task->state, rsp0);
}
void task_schedule(void)
{
kprintf("task_schedule() called @%lu ticks\n", last_count);
update_time_used();
if (first_ready_task)
{
struct kc_thread *task = first_ready_task;
first_ready_task = task->next;
task_set_thread(task);
}
}
static void lock_scheduler(void)
{
__asm__ volatile ("cli;");
schedule_lock_cnt++;
}
static void unlock_scheduler(void)
{
if (schedule_lock_cnt >= 1)
{
schedule_lock_cnt--;
}
if (schedule_lock_cnt == 0)
{
__asm__ volatile ("sti;");
}
}
static void unblock_thread(struct kc_thread *thread)
{
lock_scheduler();
if (!first_ready_task)
{
task_set_thread(thread);
}
else
{
first_ready_task->next = thread;
first_ready_task = thread;
}
unlock_scheduler();
}
static void set_thread_status(enum kc_thread_status status)
{
lock_scheduler();
current_task->status = status;
task_schedule();
unlock_scheduler();
}
static void idle_task_thread(void)
{
kputs("in idle thread\n");
while (1)
{
__asm__ volatile ("hlt;");
lock_scheduler();
task_schedule();
unlock_scheduler();
}
}
noreturn void task_init(void)
{
lock_scheduler();
char *kernel_rsp0 = vm_alloc(4096);
// TODO: make it so this isn't demand-allocated.
kernel_rsp0[1] = 0;
*get_tss_rsp0() = (uintptr_t)kernel_rsp0;
char *first_task = vm_alloc(16384);
struct kc_thread *idle_thread =
(struct kc_thread *)(first_task + 16384 - sizeof(*idle_thread));
idle_thread->state.stack = (uintptr_t)idle_thread;
idle_thread->state.stack_top = (uintptr_t)kernel_rsp0;
__asm__ volatile
(
"mov %%cr3, %%rax\n\t"
"mov %%rax, 0(%%rsi)\n\t"
"mov %%rcx, %%rsp\n\t"
"call unlock_scheduler\n\t"
"jmp idle_task_thread\n\t"
: "=m"(idle_thread->state.page_map)
: "S"(&idle_thread->state.page_map),
"c"(idle_thread)
: "rax"
);
// shouldn't ever get here
panic(GENERAL_PANIC);
}
|