Skip to content

Instantly share code, notes, and snippets.

@zonyitoo
Created October 19, 2015 02:03
Show Gist options
  • Save zonyitoo/6c62018b4adb03d1d6c5 to your computer and use it in GitHub Desktop.
Save zonyitoo/6c62018b4adb03d1d6c5 to your computer and use it in GitHub Desktop.
use libc;
use simd;
use detail::{align_down, mut_offset};
use context::InitFn;
// windows requires saving more registers (both general and XMM), so the windows
// register context must be larger.
#[cfg(windows)]
#[repr(C)]
#[derive(Debug)]
pub struct Registers {
gpr: [libc::uintptr_t; 14],
_xmm: [simd::u32x4; 10]
}
#[cfg(windows)]
impl Registers {
pub fn new() -> Registers {
Registers {
gpr: [0; 14],
_xmm: [simd::u32x4::new(0,0,0,0); 10]
}
}
}
#[cfg(not(windows))]
#[repr(C)]
#[derive(Debug)]
pub struct Registers {
gpr: [libc::uintptr_t; 10],
_xmm: [simd::u32x4; 6]
}
#[cfg(not(windows))]
impl Registers {
pub fn new() -> Registers {
Registers {
gpr: [0; 10],
_xmm: [simd::u32x4::new(0,0,0,0); 6]
}
}
}
pub fn initialize_call_frame(regs: &mut Registers, fptr: InitFn, arg: usize, thunkptr: *mut libc::c_void, sp: *mut usize) {
// extern { fn rust_bootstrap_green_task(); } // use an indirection because the call contract differences between windows and linux
// TODO: use rust's condition compile attribute instead
#[cfg(not(windows))]
unsafe fn bootstrap_green_task() {
asm!("
mov %r12, %rdi
mov %r13, %rsi
mov %
");
}
// Redefinitions from rt/arch/x86_64/regs.h
static RUSTRT_RSP: usize = 1;
static RUSTRT_IP: usize = 8;
static RUSTRT_RBP: usize = 2;
static RUSTRT_R12: usize = 4;
static RUSTRT_R13: usize = 5;
static RUSTRT_R14: usize = 6;
// static RUSTRT_R15: usize = 7;
let sp = align_down(sp);
let sp = mut_offset(sp, -1);
// The final return address. 0 indicates the bottom of the stack
unsafe { *sp = 0; }
debug!("creating call framenn");
debug!("fptr {:#x}", fptr as libc::uintptr_t);
debug!("arg {:#x}", arg);
debug!("sp {:?}", sp);
// These registers are frobbed by rust_bootstrap_green_task into the right
// location so we can invoke the "real init function", `fptr`.
regs.gpr[RUSTRT_R12] = arg as libc::uintptr_t;
regs.gpr[RUSTRT_R13] = thunkptr as libc::uintptr_t;
regs.gpr[RUSTRT_R14] = fptr as libc::uintptr_t;
// These registers are picked up by the regular context switch paths. These
// will put us in "mostly the right context" except for frobbing all the
// arguments to the right place. We have the small trampoline code inside of
// rust_bootstrap_green_task to do that.
regs.gpr[RUSTRT_RSP] = mut_offset(sp, -2) as libc::uintptr_t;
regs.gpr[RUSTRT_IP] = bootstrap_green_task as libc::uintptr_t;
unsafe {
*mut_offset(sp, -2) = 0; // RBP
*mut_offset(sp, -1) = bootstrap_green_task as usize;
}
// Last base pointer on the stack should be 0
regs.gpr[RUSTRT_RBP] = 0;
}
#[cold]
#[inline(never)]
pub unsafe fn swap_registers(_out_regs: *mut Registers, _in_regs: *const Registers) {
// The first argument is in %rdi, and the second one is in %rsi
// Save registers
asm!("
// pop %rax
// mov %rax, (8*8)(%rdi)
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)
movapd %xmm0, (10*8)(%rdi)
movapd %xmm1, (12*8)(%rdi)
movapd %xmm2, (14*8)(%rdi)
movapd %xmm3, (16*8)(%rdi)
movapd %xmm4, (18*8)(%rdi)
movapd %xmm5, (20*8)(%rdi)
"
:
:
: "{rax}"
: "volatile");
// Restore registers
asm!("
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
movapd (10*8)(%rsi), %xmm0
movapd (12*8)(%rsi), %xmm1
movapd (14*8)(%rsi), %xmm2
movapd (16*8)(%rsi), %xmm3
movapd (18*8)(%rsi), %xmm4
movapd (20*8)(%rsi), %xmm5
"
:
:
:
: "volatile");
}
#[cold]
#[inline(never)]
pub unsafe fn load_registers(_in_regs: *const Registers) {
asm!("
mov (0*8)(%rdi), %rbx
mov (1*8)(%rdi), %rsp
mov (2*8)(%rdi), %rbp
mov (4*8)(%rdi), %r12
mov (5*8)(%rdi), %r13
mov (6*8)(%rdi), %r14
mov (7*8)(%rdi), %r15
movapd (10*8)(%rdi), %xmm0
movapd (12*8)(%rdi), %xmm1
movapd (14*8)(%rdi), %xmm2
movapd (16*8)(%rdi), %xmm3
movapd (18*8)(%rdi), %xmm4
movapd (20*8)(%rdi), %xmm5
");
// Just return
}
#[cold]
#[inline(never)]
pub unsafe fn save_registers(_out_regs: *mut Registers) {
// Save registers
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)
movapd %xmm0, (10*8)(%rdi)
movapd %xmm1, (12*8)(%rdi)
movapd %xmm2, (14*8)(%rdi)
movapd %xmm3, (16*8)(%rdi)
movapd %xmm4, (18*8)(%rdi)
movapd %xmm5, (20*8)(%rdi)
"
:
:
: "{rax}"
: "volatile");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment