| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- use core::arch::naked_asm;
- /// Necessary hardware states of task for context switch
- #[repr(C)]
- #[derive(Debug, Default)]
- pub struct TaskContext {
- r12: u64,
- r13: u64,
- r14: u64,
- r15: u64,
- rbx: u64,
- rbp: u64,
- rsp: u64,
- rip: u64, // Should we save rip here?
- rflags: u64, // Should we save rflags here?
- }
- impl TaskContext {
- /// Create a new task context with the given entry point and stack pointer.
- /// The entry point is the function to be called when the task is scheduled.
- /// The stack pointer is the address of the top of the stack.
- /// The stack pointer should be aligned to 16 bytes.
- pub const fn new() -> Self {
- Self {
- r12: 0,
- r13: 0,
- r14: 0,
- r15: 0,
- rbx: 0,
- rbp: 0,
- rsp: 0,
- rip: 0,
- rflags: 0x200, // IF = 1 by default.
- }
- }
- pub fn ip(&mut self, ip: usize) {
- self.rip = ip as u64;
- }
- pub fn sp(&mut self, sp: usize) {
- self.rsp = sp as u64;
- }
- pub fn call1(&mut self, func: unsafe extern "C" fn(usize) -> !, arg: [usize; 1]) {
- self.ip(Self::do_call as _);
- self.rbp = func as _;
- self.r12 = arg[0] as _;
- }
- pub fn call2(&mut self, func: unsafe extern "C" fn(usize, usize) -> !, arg: [usize; 2]) {
- self.ip(Self::do_call as _);
- self.rbp = func as _;
- (self.r12, self.r13) = (arg[0] as _, arg[1] as _);
- }
- pub fn call3(&mut self, func: unsafe extern "C" fn(usize, usize, usize) -> !, arg: [usize; 3]) {
- self.ip(Self::do_call as _);
- self.rbp = func as _;
- (self.r12, self.r13, self.r14) = (arg[0] as _, arg[1] as _, arg[2] as _);
- }
- pub fn call4(
- &mut self,
- func: unsafe extern "C" fn(usize, usize, usize, usize) -> !,
- arg: [usize; 4],
- ) {
- self.ip(Self::do_call as _);
- self.rbp = func as _;
- (self.r12, self.r13, self.r14, self.r15) =
- (arg[0] as _, arg[1] as _, arg[2] as _, arg[3] as _);
- }
- pub fn call5(
- &mut self,
- func: unsafe extern "C" fn(usize, usize, usize, usize, usize) -> !,
- arg: [usize; 5],
- ) {
- self.ip(Self::do_call as _);
- self.rbp = func as _;
- (self.r12, self.r13, self.r14, self.r15, self.rbx) = (
- arg[0] as _,
- arg[1] as _,
- arg[2] as _,
- arg[3] as _,
- arg[4] as _,
- );
- }
- pub fn interrupt(&mut self, is_enabled: bool) {
- if is_enabled {
- self.rflags |= 0x200; // IF = 1
- } else {
- self.rflags &= !0x200; // IF = 0
- }
- }
- #[naked]
- pub unsafe extern "C" fn switch(from: &mut Self, to: &mut Self) {
- naked_asm!(
- "pop %rax",
- "pushf",
- "pop %rcx",
- "mov %r12, (%rdi)",
- "mov %r13, 8(%rdi)",
- "mov %r14, 16(%rdi)",
- "mov %r15, 24(%rdi)",
- "mov %rbx, 32(%rdi)",
- "mov %rbp, 40(%rdi)",
- "mov %rsp, 48(%rdi)",
- "mov %rax, 56(%rdi)",
- "mov %rcx, 64(%rdi)",
- "",
- "mov (%rsi), %r12",
- "mov 8(%rsi), %r13",
- "mov 16(%rsi), %r14",
- "mov 24(%rsi), %r15",
- "mov 32(%rsi), %rbx",
- "mov 40(%rsi), %rbp",
- "mov 48(%rsi), %rdi", // store next stack pointer
- "mov 56(%rsi), %rax",
- "mov 64(%rsi), %rcx",
- "push %rcx",
- "popf",
- "xchg %rdi, %rsp", // switch to new stack
- "jmp *%rax",
- options(att_syntax),
- );
- }
- #[naked]
- /// Maximum of 5 arguments supported.
- unsafe extern "C" fn do_call() -> ! {
- naked_asm!(
- "mov %r12, %rdi",
- "mov %r13, %rsi",
- "mov %r14, %rdx",
- "mov %r15, %rcx",
- "mov %rbx, %r8",
- "mov %rbp, %rax",
- "xor %rbp, %rbp",
- "jmp *%rax",
- options(att_syntax),
- );
- }
- }
|