-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy paththread.c
147 lines (123 loc) · 4 KB
/
thread.c
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include "thread.h"
#include "memory_manager.h"
#include "string.h"
#include "utils.h"
#include "virtual_memory.h"
// for sample code
#include "user_sample.h"
static thread_struct_t boot_thread;
static thread_struct_t test_thread;
static thread_info_t thread_info_1;
void context_switch(context_t *prev, context_t *next);
void return_from_exception(void);
static size_t thread_id = 0;
static size_t get_next_thread_id(void) { return thread_id++; }
void test(void)
{
while (true)
{
__asm__ volatile("wfi");
}
}
void create_user_process(uint64_t entry_address)
{
thread_struct_t *new_thread = &test_thread;
uint64_t thread_stack = (uint64_t)kalloc_4k();
if (thread_stack == (uint64_t)NULL)
{
panic("memory is not enough\n");
}
uint64_t kernel_stack = (uint64_t)kalloc_4k();
if (kernel_stack == (uint64_t)NULL)
{
panic("memory is not enough\n");
}
uint64_t stack_top = (kernel_stack + 0x1000 - 1) & -8;
trap_frame_t *trap_frame = (trap_frame_t *)(stack_top - TF_SIZE);
memory_set(trap_frame, 0x00, sizeof(trap_frame_t));
trap_frame->sepc = entry_address;
trap_frame->sp = (thread_stack + 0x1000 - 1) & -8;
trap_frame->sstatus = 0x8000000000006020;
thread_info_1.user_stack = trap_frame->sp;
thread_info_1.cpu_id = 0;
trap_frame->sscratch = (uint64_t)&thread_info_1;
trap_frame->tp = &thread_info_1;
new_thread->id = get_next_thread_id();
memory_set(&new_thread->context, 0x00, sizeof(context_t));
new_thread->context.ra = (uint64_t)return_from_exception;
new_thread->context.sp = (uint64_t)trap_frame;
page_table_t page_table = (page_table_t)kalloc_4k();
memory_copy((void *)page_table, (void *)kernel_root_page_table, 0x1000);
bool result;
result =
virtual_memory_map(page_table, (physical_address_t)_user_sample,
(virtual_address_t)_user_sample, 0x1000, 0b11111);
if (!result)
{
// TODO
}
result =
virtual_memory_map(page_table, (physical_address_t)thread_stack,
(virtual_address_t)thread_stack, 0x1000, 0b11111);
if (!result)
{
// TODO
}
new_thread->page_table = page_table;
}
thread_struct_t *create_kernel_thread_test(uint64_t entry_address)
{
thread_struct_t *new_thread = &test_thread;
uint64_t thread_stack = (uint64_t)kalloc_4k();
if (thread_stack == (uint64_t)NULL)
{
panic("memory is not enough\n");
}
uint64_t stack_top = (thread_stack + 0x1000 - 1) & -8;
trap_frame_t *trap_frame = (trap_frame_t *)(stack_top - TF_SIZE);
memory_set(trap_frame, 0x00, sizeof(trap_frame_t));
trap_frame->sepc = entry_address;
trap_frame->sp = stack_top;
trap_frame->sstatus = 0x8000000000006120;
trap_frame->tp = &thread_info_1;
trap_frame->tp->user_stack = (uint64_t)NULL;
uint64_t kernel_stack = (uint64_t)kalloc_4k();
if (kernel_stack == (uint64_t)NULL)
{
panic("memory is not enough\n");
}
trap_frame->tp->kernel_stack = (uint64_t)kernel_stack + 0xff0;
trap_frame->tp->cpu_id = 0;
new_thread->id = get_next_thread_id();
memory_set(&new_thread->context, 0x00, sizeof(context_t));
new_thread->context.ra = (uint64_t)return_from_exception;
new_thread->context.sp = (uint64_t)trap_frame;
new_thread->page_table = NULL;
return new_thread;
}
void task_switch(thread_struct_t *prev_thread, thread_struct_t *next_thread)
{
if (next_thread->page_table)
{
write_page_table(next_thread->page_table);
}
context_switch(&prev_thread->context, &next_thread->context);
}
void thread_swap_test(void)
{
static bool is_next_boot_thread = true;
is_next_boot_thread = !is_next_boot_thread;
if (is_next_boot_thread)
{
task_switch(&test_thread, &boot_thread);
}
else
{
task_switch(&boot_thread, &test_thread);
}
}
void init_test_thread(uint64_t entry)
{
// create_kernel_thread_test(entry);
create_user_process((uint64_t)_user_sample);
}