1
0
Fork 0
libfringe/src/arch.rs

103 lines
2.1 KiB
Rust
Raw Normal View History

use core::prelude::*;
use core::simd::u64x2;
use core::mem::{size_of, zeroed};
2014-12-24 13:12:39 +08:00
use stack::Stack;
extern "C" {
#[link_name = "lwt_bootstrap"]
2014-12-24 13:12:39 +08:00
pub fn bootstrap();
#[link_name = "lwt_swapcontext"]
2014-12-24 13:12:39 +08:00
pub fn swapcontext(save: *mut Registers, restore: *mut Registers);
#[link_name = "lwt_abort"]
2014-12-24 13:12:39 +08:00
pub fn abort() -> !;
}
#[allow(non_camel_case_types)]
pub type uintptr_t = u64;
#[repr(C)]
#[allow(dead_code)]
pub struct Registers {
rbx: u64,
rsp: u64,
rbp: u64,
rdi: u64,
r12: u64,
r13: u64,
r14: u64,
r15: u64,
ip: u64,
xmm0: u64x2,
xmm1: u64x2,
xmm2: u64x2,
xmm3: u64x2,
xmm4: u64x2,
xmm5: u64x2,
}
impl Registers {
pub fn new() -> Registers {
unsafe {
Registers {
2014-12-24 13:52:52 +08:00
ip: abort as uintptr_t,
2014-12-24 13:12:39 +08:00
.. zeroed()
}
}
}
}
pub fn initialise_call_frame(stack: &mut Stack, init: uintptr_t, args: &[uintptr_t]) -> Registers {
let sp = stack.top() as *mut uintptr_t;
let sp = align_down_mut(sp, 16);
let sp = offset_mut(sp, -1);
unsafe {
*sp = 0;
}
let mut regs = Registers {
rbp: 0,
rsp: sp as uintptr_t,
ip: bootstrap as uintptr_t,
rbx: init,
2014-12-24 13:12:39 +08:00
.. Registers::new()
};
match into_fields!(regs { rdi, r12, r13, r14, r15 } <- args.iter().cloned()) {
2014-12-24 13:12:39 +08:00
Some(mut args) => if args.next().is_some() {
panic!("too many arguments")
},
None => {}
}
regs
}
2014-12-25 19:24:02 +08:00
// Rust stores a stack limit at [fs:0x70]. These two functions set and retrieve
// the limit. They're marked as #[inline(always)] so that they can be used in
// situations where the stack limit is invalid.
#[inline(always)]
pub unsafe fn get_sp_limit() -> *const u8 {
let limit;
asm!("movq %fs:0x70, $0" : "=r"(limit) ::: "volatile");
limit
}
#[inline(always)]
pub unsafe fn set_sp_limit(limit: *const u8) {
asm!("movq $0, %fs:0x70" :: "r"(limit) :: "volatile");
}
2014-12-24 13:12:39 +08:00
#[inline]
2015-01-13 15:38:52 +08:00
fn align_down_mut<T>(sp: *mut T, n: usize) -> *mut T {
let sp = (sp as usize) & !(n - 1);
2014-12-24 13:12:39 +08:00
sp as *mut T
}
2014-12-25 19:25:11 +08:00
// ptr::offset_mut is positive ints only
2014-12-24 13:12:39 +08:00
#[inline]
2015-01-13 15:38:52 +08:00
pub fn offset_mut<T>(ptr: *mut T, count: isize) -> *mut T {
(ptr as isize + count * (size_of::<T>() as isize)) as *mut T
2014-12-24 13:12:39 +08:00
}