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
|
use crate::arch::x86_64::arch_regs;
use crate::defs::*;
use crate::io::*;
use core::arch::asm;
/// currently only kernelSp and Context are important.
/// the task struct will be placed on the starting addr (low addr) of the kernel stack.
/// therefore we can retrive the task struct at anytime by masking the kernel stack
#[repr(C)]
#[repr(packed)]
pub struct Task {
pub magic: u64,
pub task_id: u32,
pub kernel_stack: u64,
// pub user_stack: u64,
pub context: arch_regs::Context64,
pub state: TaskState,
}
pub enum TaskState {
Run,
Block,
Dead,
Eating,
Purr,
Meow,
Angry,
}
#[no_mangle]
pub extern "C" fn _task_entry() -> ! {
println!("I'm Mr.Meeseeks, look at me~");
unsafe { asm!("hlt") };
panic!("shoud not reach");
}
extern "C" {
fn context_swap(from_ctx: u64, to_ctx: u64);
fn context_swap_to(to_ctx: u64);
}
impl Task {
/// create new task. This is tricky because the task struct sits at the
/// bottom of the kernel stack, so that you can get the current task by
/// masking the stack pointer.
/// 1. allocate the kernel stack with predefined size and make sure the
/// address is properly aligned
/// 2. cast a task struct onto the stack
/// 3. set whatever fields necessary in the task struct, including a magic
/// 4. create a new stack frame, and update the stack pointer in the context,
/// so that when first swapped to, the task will immediately "return to"
/// the _func_ptr
pub fn new(_id: u32, _func_ptr: u64) -> Self {
todo!()
}
}
|