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_asm(data: *const usize);
pub fn swap_registers(out_regs: *mut Registers, in_regs: *const Registers);
}
#[allow(dead_code)]
#[inline]
pub fn prefetch(data: *const usize) {
unsafe {
prefetch_asm(data);
}
}
#[cfg(nightly)]
mod asm {
use super::Registers;
#[inline]
pub unsafe fn prefetch_asm(data: *const usize) {
asm!("prefetcht1 $0"
: : "m"(*data)
:
: "volatile");
}
#[inline(never)]
#[naked]
pub unsafe extern "C" fn bootstrap_green_task() {
asm!("
mov %r12, %rcx // setup the function arg
mov %r13, %rdx // 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!(
""
:
: "{rcx}"(out_regs), "{rdx}"(in_regs)
:
:
);
#[naked]
unsafe extern "C" fn _swap_reg() {
asm!("
mov %rbx, (0*8)(%rcx)
mov %rsp, (1*8)(%rcx)
mov %rbp, (2*8)(%rcx)
mov %r12, (4*8)(%rcx)
mov %r13, (5*8)(%rcx)
mov %r14, (6*8)(%rcx)
mov %r15, (7*8)(%rcx)
mov %rdi, (9*8)(%rcx)
mov %rsi, (10*8)(%rcx)
// mov %rcx, %r10
// and $$0xf0, %r10b
// Save non-volatile XMM registers:
movapd %xmm6, (16*8)(%rcx)
movapd %xmm7, (18*8)(%rcx)
movapd %xmm8, (20*8)(%rcx)
movapd %xmm9, (22*8)(%rcx)
movapd %xmm10, (24*8)(%rcx)
movapd %xmm11, (26*8)(%rcx)
movapd %xmm12, (28*8)(%rcx)
movapd %xmm13, (30*8)(%rcx)
movapd %xmm14, (32*8)(%rcx)
movapd %xmm15, (34*8)(%rcx)
/* load NT_TIB */
movq %gs:(0x30), %r10
/* save current stack base */
movq 0x08(%r10), %rax
mov %rax, (11*8)(%rcx)
/* save current stack limit */
movq 0x10(%r10), %rax
mov %rax, (12*8)(%rcx)
/* save current deallocation stack */
movq 0x1478(%r10), %rax
mov %rax, (13*8)(%rcx)
/* save fiber local storage */
// movq 0x18(%r10), %rax
// mov %rax, (14*8)(%rcx)
mov %rcx, (3*8)(%rcx)
mov (0*8)(%rdx), %rbx
mov (1*8)(%rdx), %rsp
mov (2*8)(%rdx), %rbp
mov (4*8)(%rdx), %r12
mov (5*8)(%rdx), %r13
mov (6*8)(%rdx), %r14
mov (7*8)(%rdx), %r15
mov (9*8)(%rdx), %rdi
mov (10*8)(%rdx), %rsi
// Restore non-volatile XMM registers:
movapd (16*8)(%rdx), %xmm6
movapd (18*8)(%rdx), %xmm7
movapd (20*8)(%rdx), %xmm8
movapd (22*8)(%rdx), %xmm9
movapd (24*8)(%rdx), %xmm10
movapd (26*8)(%rdx), %xmm11
movapd (28*8)(%rdx), %xmm12
movapd (30*8)(%rdx), %xmm13
movapd (32*8)(%rdx), %xmm14
movapd (34*8)(%rdx), %xmm15
/* load NT_TIB */
movq %gs:(0x30), %r10
/* restore fiber local storage */
// mov (14*8)(%rdx), %rax
// movq %rax, 0x18(%r10)
/* restore deallocation stack */
mov (13*8)(%rdx), %rax
movq %rax, 0x1478(%r10)
/* restore stack limit */
mov (12*8)(%rdx), %rax
movq %rax, 0x10(%r10)
/* restore stack base */
mov (11*8)(%rdx), %rax
movq %rax, 0x8(%r10)
mov (3*8)(%rdx), %rcx
"
:
: : "memory"
: "volatile");
}
_swap_reg()
}
}
#[cfg(nightly)]
pub use self::asm::*;
#[cfg_attr(nightly, repr(simd))]
#[cfg_attr(not(nightly), repr(C))]
#[allow(non_camel_case_types)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
struct XMM(u32, u32, u32, u32);
impl XMM {
pub fn new(a: u32, b: u32, c: u32, d: u32) -> Self {
XMM(a, b, c, d)
}
}
#[repr(C)]
#[derive(Debug)]
pub struct Registers {
gpr: [usize; 16],
_xmm: [XMM; 10],
}
impl Registers {
pub fn new() -> Registers {
Registers {
gpr: [0; 16],
_xmm: [XMM::new(0, 0, 0, 0); 10],
}
}
#[inline]
pub fn prefetch(&self) {
unsafe {
prefetch_asm(self as *const _ as *const usize);
prefetch_asm(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;
const RUSTRT_STACK_BASE: usize = 11;
const RUSTRT_STACK_LIMIT: usize = 12;
const RUSTRT_STACK_DEALLOC: usize = 13;
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;
regs.gpr[RUSTRT_RBP] = 0;
regs.gpr[RUSTRT_STACK_BASE] = stack.end() as usize;
regs.gpr[RUSTRT_STACK_LIMIT] = stack.begin() as usize;
regs.gpr[RUSTRT_STACK_DEALLOC] = 0;
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;
}
}