use detail::{align_down, mut_offset};
use reg_context::InitFn;
use stack::Stack;
#[cfg(not(nightly))]
#[link(name = "asm", kind = "static")]
extern "C" {
pub fn bootstrap_green_task();
pub fn prefetch(data: *const usize);
pub fn swap_registers(out_regs: *mut Registers, in_regs: *const Registers);
}
#[cfg(nightly)]
mod asm {
use super::Registers;
#[inline]
pub unsafe extern "C" fn prefetch(data: *const usize) {
asm!("
prefetcht1 $0
"
: : "m"(*data)
:
: "volatile");
}
#[inline(never)]
#[naked]
pub unsafe extern "C" fn bootstrap_green_task() {
asm!("
mov %r12, %rdi // setup the function arg
mov %r13, %rsi // setup the function arg
mov %r14, 8(%rsp) // this is the new return adrress
"
: : : "memory"
: "volatile");
}
#[inline(never)]
pub unsafe extern "C" fn swap_registers(out_regs: *mut Registers, in_regs: *const Registers) {
asm!(
""
:
: "{rdi}"(out_regs), "{rsi}"(in_regs)
:
:
);
#[naked]
unsafe extern "C" fn _swap_reg() {
asm!("
mov %rbx, (0*8)(%rdi)
mov %rsp, (1*8)(%rdi)
mov %rbp, (2*8)(%rdi)
mov %r12, (4*8)(%rdi)
mov %r13, (5*8)(%rdi)
mov %r14, (6*8)(%rdi)
mov %r15, (7*8)(%rdi)
mov %rdi, (3*8)(%rdi)
mov (0*8)(%rsi), %rbx
mov (1*8)(%rsi), %rsp
mov (2*8)(%rsi), %rbp
mov (4*8)(%rsi), %r12
mov (5*8)(%rsi), %r13
mov (6*8)(%rsi), %r14
mov (7*8)(%rsi), %r15
mov (3*8)(%rsi), %rdi
"
:
: : "memory"
: "volatile");
}
_swap_reg()
}
}
#[cfg(nightly)]
pub use self::asm::*;
#[repr(C)]
#[derive(Debug)]
pub struct Registers {
gpr: [usize; 8],
}
impl Registers {
pub fn new() -> Registers {
Registers { gpr: [0; 8] }
}
#[inline]
pub fn prefetch(&self) {
unsafe {
prefetch(self as *const _ as *const usize);
prefetch(self.gpr[1] as *const usize);
}
}
}
pub fn initialize_call_frame(
regs: &mut Registers,
fptr: InitFn,
arg: usize,
arg2: *mut usize,
stack: &Stack,
) {
const RUSTRT_RSP: usize = 1;
const RUSTRT_RBP: usize = 2;
const RUSTRT_R12: usize = 4;
const RUSTRT_R13: usize = 5;
const RUSTRT_R14: usize = 6;
let sp = align_down(stack.end());
regs.gpr[RUSTRT_R12] = arg;
regs.gpr[RUSTRT_R13] = arg2 as usize;
regs.gpr[RUSTRT_R14] = fptr as usize;
regs.gpr[RUSTRT_RSP] = mut_offset(sp, -4) as usize;
unsafe {
*mut_offset(sp, -4) = bootstrap_green_task as usize;
*mut_offset(sp, -3) = bootstrap_green_task as usize;
*mut_offset(sp, -2) = 0;
*mut_offset(sp, -1) = 0;
}
regs.gpr[RUSTRT_RBP] = 0;
}