SimpleKernel 1.17.0
Loading...
Searching...
No Matches
task_control_block.cpp
Go to the documentation of this file.
1
6
7#include <cpu_io.h>
8#include <elf.h>
9
10#include "arch.h"
11#include "basic_info.hpp"
12#include "interrupt_base.h"
13#include "kernel.h"
14#include "kernel_log.hpp"
15#include "kstd_cstring"
16#include "sk_stdlib.h"
17#include "virtual_memory.hpp"
18
19namespace {
20
21auto LoadElf(const uint8_t* elf_data, uint64_t* page_table) -> uint64_t {
22 // Check ELF magic
23 auto* ehdr = reinterpret_cast<const Elf64_Ehdr*>(elf_data);
24 if (ehdr->e_ident[EI_MAG0] != ELFMAG0 || ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
25 ehdr->e_ident[EI_MAG2] != ELFMAG2 || ehdr->e_ident[EI_MAG3] != ELFMAG3) {
26 klog::Err("Invalid ELF magic");
27 return 0;
28 }
29
30 auto* phdr = reinterpret_cast<const Elf64_Phdr*>(elf_data + ehdr->e_phoff);
31 auto& vm = VirtualMemorySingleton::instance();
32
33 for (int i = 0; i < ehdr->e_phnum; ++i) {
34 if (phdr[i].p_type != PT_LOAD) continue;
35
36 uintptr_t vaddr = phdr[i].p_vaddr;
37 uintptr_t memsz = phdr[i].p_memsz;
38 uintptr_t filesz = phdr[i].p_filesz;
39 uintptr_t offset = phdr[i].p_offset;
40
42 (phdr[i].p_flags & PF_R) != 0, (phdr[i].p_flags & PF_W) != 0,
43 (phdr[i].p_flags & PF_X) != 0);
44
45 uintptr_t start_page = cpu_io::virtual_memory::PageAlign(vaddr);
46 uintptr_t end_page = cpu_io::virtual_memory::PageAlignUp(vaddr + memsz);
47
48 for (uintptr_t page = start_page; page < end_page;
52 if (!p_page) {
53 klog::Err("Failed to allocate page for ELF");
54 return 0;
55 }
56 kstd::memset(p_page, 0, cpu_io::virtual_memory::kPageSize);
57
58 // Mapping logic
59 uintptr_t v_start = page;
60 uintptr_t v_end = page + cpu_io::virtual_memory::kPageSize;
61
62 // Map intersection with file data
63 uintptr_t file_start = vaddr;
64 uintptr_t file_end = vaddr + filesz;
65
66 uintptr_t copy_start = std::max(v_start, file_start);
67 uintptr_t copy_end = std::min(v_end, file_end);
68
69 if (copy_end > copy_start) {
70 uintptr_t dst_off = copy_start - v_start;
71 uintptr_t src_off = (copy_start - vaddr) + offset;
72 kstd::memcpy(static_cast<uint8_t*>(p_page) + dst_off,
73 elf_data + src_off, copy_end - copy_start);
74 }
75
76 if (!vm.MapPage(page_table, reinterpret_cast<void*>(page), p_page,
77 flags)) {
78 klog::Err("MapPage failed");
79 return 0;
80 }
81 }
82 }
83 return ehdr->e_entry;
84}
85
86} // namespace
87
88auto TaskControlBlock::GetStatus() const -> etl::fsm_state_id_t {
89 return fsm.GetStateId();
90}
91
93 if (!leader || leader == this) {
94 return;
95 }
96
97 // 设置 tgid
98 aux->tgid = leader->aux->tgid;
99
100 // 在 leader 之后插入自身
101 etl::link_splice<ThreadGroupLink>(*leader, *this);
102}
103
104auto TaskControlBlock::LeaveThreadGroup() -> void { ThreadGroupLink::unlink(); }
105
107 if (aux->tgid == 0) {
108 // 未加入任何线程组
109 return 1;
110 }
111
112 size_t count = 1;
113
114 // 向前遍历至链表头
115 const ThreadGroupLink* curr = etl_previous;
116 while (curr) {
117 ++count;
118 curr = curr->etl_previous;
119 }
120
121 // 向后遍历至链表尾
122 curr = etl_next;
123 while (curr) {
124 ++count;
125 curr = curr->etl_next;
126 }
127
128 return count;
129}
130
131TaskControlBlock::TaskControlBlock(const char* _name, int priority,
132 ThreadEntry entry, void* arg)
133 : name(_name) {
134 // 分配辅助数据
135 aux = new TaskAuxData{};
136 if (!aux) {
137 klog::Err("Failed to allocate TaskAuxData for task {}", name);
138 return;
139 }
140
141 // 设置优先级
142 sched_info.priority = priority;
143 sched_info.base_priority = priority;
144
145 // 分配内核栈
146 kernel_stack = static_cast<uint8_t*>(aligned_alloc(
148 if (!kernel_stack) {
149 klog::Err("Failed to allocate kernel stack for task {}", name);
150 return;
151 }
152
153 // 设置 trap_context_ptr 指向内核栈顶预留的位置
154 trap_context_ptr = reinterpret_cast<cpu_io::TrapContext*>(
156
157 // 设置内核栈顶
158 auto stack_top =
159 reinterpret_cast<uint64_t>(kernel_stack) + kDefaultKernelStackSize;
160
161 // 初始化任务上下文
162 InitTaskContext(&task_context, entry, arg, stack_top);
163
164 fsm.Start();
165}
166
167TaskControlBlock::TaskControlBlock(const char* _name, int priority,
168 uint8_t* elf, int argc, char** argv)
169 : name(_name) {
170 // 分配辅助数据
171 aux = new TaskAuxData{};
172 if (!aux) {
173 klog::Err("Failed to allocate TaskAuxData for task {}", name);
174 return;
175 }
176
177 // 设置优先级
178 sched_info.priority = priority;
179 sched_info.base_priority = priority;
180
182 (void)_name;
183 (void)priority;
184 (void)elf;
185 (void)argc;
186 (void)argv;
187 LoadElf(nullptr, nullptr);
188
189 fsm.Start();
190}
191
193 // 从线程组中移除
195
196 // 释放内核栈
197 if (kernel_stack) {
199 kernel_stack = nullptr;
200 }
201
202 // 释放页表(如果有用户空间页表)
203 if (page_table) {
204 // 如果是私有页表(非共享),需要释放物理页
205 auto should_free_pages = !(aux->clone_flags & clone_flag::kVm);
206 VirtualMemorySingleton::instance().DestroyPageDirectory(page_table,
207 should_free_pages);
208 page_table = nullptr;
209 }
210
211 // 释放辅助数据
212 if (aux) {
213 delete aux;
214 aux = nullptr;
215 }
216}
auto InitTaskContext(cpu_io::CalleeSavedContext *task_context, void(*entry)(void *), void *arg, uint64_t stack_top) -> void
初始化内核线程的任务上下文(重载1)
Definition arch_main.cpp:77
auto Start() -> void
启动 FSM(在 TCB 完全构造后调用)
Definition task_fsm.hpp:157
auto GetStateId() const -> etl::fsm_state_id_t
获取当前状态 ID
Definition task_fsm.hpp:169
constexpr uint64_t kVm
共享地址空间
static constexpr size_t kPageSize
Definition cpu_io.h:63
auto PageAlign(uint64_t addr) -> uint64_t
Definition cpu_io.h:157
auto GetUserPagePermissions(bool readable=true, bool writable=false, bool executable=false, bool global=false) -> uint64_t
Definition cpu_io.h:79
auto PageAlignUp(uint64_t addr) -> uint64_t
Definition cpu_io.h:161
auto Err(etl::format_string< Args... > fmt, Args &&... args) -> void
以 ERROR 级别记录日志
void aligned_free(void *ptr)
Definition memory.cpp:65
void * aligned_alloc(size_t alignment, size_t size)
Definition memory.cpp:58
非调度热路径的任务辅助数据
Pid tgid
线程组 ID (主线程的 PID)
CloneFlags clone_flags
克隆标志位
int priority
优先级 (数字越小优先级越高)
int base_priority
基础优先级 (静态,用于优先级继承)
任务控制块,管理进程/线程的核心数据结构
auto JoinThreadGroup(TaskControlBlock *leader) -> void
将线程添加到线程组
struct TaskControlBlock::SchedInfo sched_info
auto LeaveThreadGroup() -> void
从线程组中移除自己
TaskFsm fsm
任务状态机
auto GetStatus() const -> etl::fsm_state_id_t
获取当前任务状态
TaskControlBlock()=default
TaskAuxData * aux
非调度热路径的辅助数据
uint8_t * kernel_stack
内核栈
uint64_t * page_table
页表
auto GetThreadGroupSize() const -> size_t
获取线程组中的线程数量
cpu_io::CalleeSavedContext task_context
任务上下文
static constexpr size_t kDefaultKernelStackSize
默认内核栈大小 (16 KB)
cpu_io::TrapContext * trap_context_ptr
Trap 上下文
const char * name
任务名称
etl::bidirectional_link< 0 > ThreadGroupLink
线程组侵入式链表节点类型
void(*)(void *) ThreadEntry
线程入口函数类型