|
|
|
|
@@ -15,6 +15,7 @@ use std::rt::stack;
|
|
|
|
|
use std::raw;
|
|
|
|
|
#[cfg(target_arch = "x86_64")]
|
|
|
|
|
use std::simd;
|
|
|
|
|
use libc;
|
|
|
|
|
|
|
|
|
|
// FIXME #7761: Registers is boxed so that it is 16-byte aligned, for storing
|
|
|
|
|
// SSE regs. It would be marginally better not to do this. In C++ we
|
|
|
|
|
@@ -69,7 +70,7 @@ impl Context {
|
|
|
|
|
// overflow). Additionally, their coroutine stacks are listed as being
|
|
|
|
|
// zero-length, so that's how we detect what's what here.
|
|
|
|
|
let stack_base: *const uint = stack.start();
|
|
|
|
|
let bounds = if sp as uint == stack_base as uint {
|
|
|
|
|
let bounds = if sp as libc::uintptr_t == stack_base as libc::uintptr_t {
|
|
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
Some((stack_base as uint, sp as uint))
|
|
|
|
|
@@ -165,16 +166,16 @@ fn new_regs() -> Box<Registers> {
|
|
|
|
|
|
|
|
|
|
#[cfg(target_arch = "x86")]
|
|
|
|
|
fn initialize_call_frame(regs: &mut Registers, fptr: InitFn, arg: uint,
|
|
|
|
|
procedure: raw::Procedure, sp: *mut uint) {
|
|
|
|
|
procedure: raw::Procedure, sp: *mut libc::uintptr_t) {
|
|
|
|
|
|
|
|
|
|
// x86 has interesting stack alignment requirements, so do some alignment
|
|
|
|
|
// plus some offsetting to figure out what the actual stack should be.
|
|
|
|
|
let sp = align_down(sp);
|
|
|
|
|
let sp = mut_offset(sp, -4);
|
|
|
|
|
|
|
|
|
|
unsafe { *mut_offset(sp, 2) = procedure.env as uint };
|
|
|
|
|
unsafe { *mut_offset(sp, 1) = procedure.code as uint };
|
|
|
|
|
unsafe { *mut_offset(sp, 0) = arg as uint };
|
|
|
|
|
unsafe { *mut_offset(sp, 2) = procedure.env as libc::uintptr_t };
|
|
|
|
|
unsafe { *mut_offset(sp, 1) = procedure.code as libc::uintptr_t };
|
|
|
|
|
unsafe { *mut_offset(sp, 0) = arg as libc::uintptr_t };
|
|
|
|
|
let sp = mut_offset(sp, -1);
|
|
|
|
|
unsafe { *sp = 0 }; // The final return address
|
|
|
|
|
|
|
|
|
|
@@ -188,13 +189,15 @@ fn initialize_call_frame(regs: &mut Registers, fptr: InitFn, arg: uint,
|
|
|
|
|
// windows requires saving more registers (both general and XMM), so the windows
|
|
|
|
|
// register context must be larger.
|
|
|
|
|
#[cfg(windows, target_arch = "x86_64")]
|
|
|
|
|
#[repr(C)]
|
|
|
|
|
struct Registers {
|
|
|
|
|
gpr:[uint, ..14],
|
|
|
|
|
gpr:[libc::uintptr_t, ..14],
|
|
|
|
|
_xmm:[simd::u32x4, ..10]
|
|
|
|
|
}
|
|
|
|
|
#[cfg(not(windows), target_arch = "x86_64")]
|
|
|
|
|
#[repr(C)]
|
|
|
|
|
struct Registers {
|
|
|
|
|
gpr:[uint, ..10],
|
|
|
|
|
gpr:[libc::uintptr_t, ..10],
|
|
|
|
|
_xmm:[simd::u32x4, ..6]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -234,30 +237,30 @@ fn initialize_call_frame(regs: &mut Registers, fptr: InitFn, arg: uint,
|
|
|
|
|
unsafe { *sp = 0; }
|
|
|
|
|
|
|
|
|
|
rtdebug!("creating call frame");
|
|
|
|
|
rtdebug!("fptr {:#x}", fptr as uint);
|
|
|
|
|
rtdebug!("fptr {:#x}", fptr as libc::uintptr_t);
|
|
|
|
|
rtdebug!("arg {:#x}", arg);
|
|
|
|
|
rtdebug!("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 uint;
|
|
|
|
|
regs.gpr[RUSTRT_R13] = procedure.code as uint;
|
|
|
|
|
regs.gpr[RUSTRT_R14] = procedure.env as uint;
|
|
|
|
|
regs.gpr[RUSTRT_R15] = fptr as uint;
|
|
|
|
|
regs.gpr[RUSTRT_R12] = arg as libc::uintptr_t;
|
|
|
|
|
regs.gpr[RUSTRT_R13] = procedure.code as libc::uintptr_t;
|
|
|
|
|
regs.gpr[RUSTRT_R14] = procedure.env as libc::uintptr_t;
|
|
|
|
|
regs.gpr[RUSTRT_R15] = 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] = sp as uint;
|
|
|
|
|
regs.gpr[RUSTRT_IP] = rust_bootstrap_green_task as uint;
|
|
|
|
|
regs.gpr[RUSTRT_RSP] = sp as libc::uintptr_t;
|
|
|
|
|
regs.gpr[RUSTRT_IP] = rust_bootstrap_green_task as libc::uintptr_t;
|
|
|
|
|
|
|
|
|
|
// Last base pointer on the stack should be 0
|
|
|
|
|
regs.gpr[RUSTRT_RBP] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(target_arch = "arm")]
|
|
|
|
|
type Registers = [uint, ..32];
|
|
|
|
|
type Registers = [libc::uintptr_t, ..32];
|
|
|
|
|
|
|
|
|
|
#[cfg(target_arch = "arm")]
|
|
|
|
|
fn new_regs() -> Box<Registers> { box {[0, .. 32]} }
|
|
|
|
|
@@ -277,17 +280,17 @@ fn initialize_call_frame(regs: &mut Registers, fptr: InitFn, arg: uint,
|
|
|
|
|
// ARM uses the same technique as x86_64 to have a landing pad for the start
|
|
|
|
|
// of all new green tasks. Neither r1/r2 are saved on a context switch, so
|
|
|
|
|
// the shim will copy r3/r4 into r1/r2 and then execute the function in r5
|
|
|
|
|
regs[0] = arg as uint; // r0
|
|
|
|
|
regs[3] = procedure.code as uint; // r3
|
|
|
|
|
regs[4] = procedure.env as uint; // r4
|
|
|
|
|
regs[5] = fptr as uint; // r5
|
|
|
|
|
regs[13] = sp as uint; // #52 sp, r13
|
|
|
|
|
regs[14] = rust_bootstrap_green_task as uint; // #56 pc, r14 --> lr
|
|
|
|
|
regs[0] = arg as libc::uintptr_t; // r0
|
|
|
|
|
regs[3] = procedure.code as libc::uintptr_t; // r3
|
|
|
|
|
regs[4] = procedure.env as libc::uintptr_t; // r4
|
|
|
|
|
regs[5] = fptr as libc::uintptr_t; // r5
|
|
|
|
|
regs[13] = sp as libc::uintptr_t; // #52 sp, r13
|
|
|
|
|
regs[14] = rust_bootstrap_green_task as libc::uintptr_t; // #56 pc, r14 --> lr
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(target_arch = "mips")]
|
|
|
|
|
#[cfg(target_arch = "mipsel")]
|
|
|
|
|
type Registers = [uint, ..32];
|
|
|
|
|
type Registers = [libc::uintptr_t, ..32];
|
|
|
|
|
|
|
|
|
|
#[cfg(target_arch = "mips")]
|
|
|
|
|
#[cfg(target_arch = "mipsel")]
|
|
|
|
|
@@ -304,16 +307,16 @@ fn initialize_call_frame(regs: &mut Registers, fptr: InitFn, arg: uint,
|
|
|
|
|
// The final return address. 0 indicates the bottom of the stack
|
|
|
|
|
unsafe { *sp = 0; }
|
|
|
|
|
|
|
|
|
|
regs[4] = arg as uint;
|
|
|
|
|
regs[5] = procedure.code as uint;
|
|
|
|
|
regs[6] = procedure.env as uint;
|
|
|
|
|
regs[29] = sp as uint;
|
|
|
|
|
regs[25] = fptr as uint;
|
|
|
|
|
regs[31] = fptr as uint;
|
|
|
|
|
regs[4] = arg as libc::uintptr_t;
|
|
|
|
|
regs[5] = procedure.code as libc::uintptr_t;
|
|
|
|
|
regs[6] = procedure.env as libc::uintptr_t;
|
|
|
|
|
regs[29] = sp as libc::uintptr_t;
|
|
|
|
|
regs[25] = fptr as libc::uintptr_t;
|
|
|
|
|
regs[31] = fptr as libc::uintptr_t;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn align_down(sp: *mut uint) -> *mut uint {
|
|
|
|
|
let sp = (sp as uint) & !(16 - 1);
|
|
|
|
|
let sp = (sp as libc::uintptr_t) & !(16 - 1);
|
|
|
|
|
sp as *mut uint
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|