Support Win64 context switching

This patch saves and restores win64's nonvolatile registers.
This patch also saves stack information of thread environment
block (TEB), which is at %gs:0x08 and %gs:0x10.
This commit is contained in:
klutzy 2013-08-26 22:01:55 +09:00
parent 63e53b8af2
commit 442f4a5f2c
3 changed files with 106 additions and 16 deletions

View File

@ -47,6 +47,7 @@ impl Context {
let fp: *c_void = task_start_wrapper as *c_void;
let argp: *c_void = unsafe { transmute::<&~fn(), *c_void>(&*start) };
let stack_base: *uint = stack.start();
let sp: *uint = stack.end();
let sp: *mut uint = unsafe { transmute_mut_unsafe(sp) };
// Save and then immediately load the current context,
@ -56,7 +57,7 @@ impl Context {
swap_registers(transmute_mut_region(&mut *regs), transmute_region(&*regs));
};
initialize_call_frame(&mut *regs, fp, argp, sp);
initialize_call_frame(&mut *regs, fp, argp, sp, stack_base);
return Context {
start: Some(start),
@ -107,7 +108,8 @@ fn new_regs() -> ~Registers {
}
#[cfg(target_arch = "x86")]
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
sp: *mut uint, _stack_base: *uint) {
let sp = align_down(sp);
let sp = mut_offset(sp, -4);
@ -123,14 +125,19 @@ fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp:
regs.ebp = 0;
}
#[cfg(target_arch = "x86_64")]
#[cfg(windows, target_arch = "x86_64")]
type Registers = [uint, ..34];
#[cfg(not(windows), target_arch = "x86_64")]
type Registers = [uint, ..22];
#[cfg(target_arch = "x86_64")]
#[cfg(windows, target_arch = "x86_64")]
fn new_regs() -> ~Registers { ~([0, .. 34]) }
#[cfg(not(windows), target_arch = "x86_64")]
fn new_regs() -> ~Registers { ~([0, .. 22]) }
#[cfg(target_arch = "x86_64")]
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
sp: *mut uint, stack_base: *uint) {
// Redefinitions from regs.h
static RUSTRT_ARG0: uint = 3;
@ -138,6 +145,21 @@ fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp:
static RUSTRT_IP: uint = 8;
static RUSTRT_RBP: uint = 2;
#[cfg(windows)]
fn initialize_tib(regs: &mut Registers, sp: *mut uint, stack_base: *uint) {
// Redefinitions from regs.h
static RUSTRT_ST1: uint = 11; // stack bottom
static RUSTRT_ST2: uint = 12; // stack top
regs[RUSTRT_ST1] = sp as uint;
regs[RUSTRT_ST2] = stack_base as uint;
}
#[cfg(not(windows))]
fn initialize_tib(_: &mut Registers, _: *mut uint, _: *uint) {
}
// Win64 manages stack range at TIB: %gs:0x08 (top) and %gs:0x10 (bottom)
initialize_tib(regs, sp, stack_base);
let sp = align_down(sp);
let sp = mut_offset(sp, -1);
@ -164,7 +186,8 @@ type Registers = [uint, ..32];
fn new_regs() -> ~Registers { ~([0, .. 32]) }
#[cfg(target_arch = "arm")]
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
sp: *mut uint, _stack_base: *uint) {
let sp = align_down(sp);
// sp of arm eabi is 8-byte aligned
let sp = mut_offset(sp, -2);
@ -184,7 +207,8 @@ type Registers = [uint, ..32];
fn new_regs() -> ~Registers { ~([0, .. 32]) }
#[cfg(target_arch = "mips")]
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
sp: *mut uint, _stack_base: *uint) {
let sp = align_down(sp);
// sp of mips o32 is 8-byte aligned
let sp = mut_offset(sp, -2);

View File

@ -86,16 +86,40 @@ SWAP_REGISTERS:
mov %r14, (RUSTRT_R14*8)(ARG0)
mov %r15, (RUSTRT_R15*8)(ARG0)
#if defined(__MINGW32__) || defined(_WINDOWS)
mov %rdi, (RUSTRT_RDI*8)(ARG0)
mov %rsi, (RUSTRT_RSI*8)(ARG0)
// Save stack range
mov %gs:0x08, %r8
mov %r8, (RUSTRT_ST1*8)(ARG0)
mov %gs:0x10, %r9
mov %r9, (RUSTRT_ST2*8)(ARG0)
#endif
// Save 0th argument register:
mov ARG0, (RUSTRT_ARG0*8)(ARG0)
// Save non-volatile XMM registers:
#if defined(__MINGW32__) || defined(_WINDOWS)
movapd %xmm6, (RUSTRT_XMM6*8)(ARG0)
movapd %xmm7, (RUSTRT_XMM7*8)(ARG0)
movapd %xmm8, (RUSTRT_XMM8*8)(ARG0)
movapd %xmm9, (RUSTRT_XMM9*8)(ARG0)
movapd %xmm10, (RUSTRT_XMM10*8)(ARG0)
movapd %xmm11, (RUSTRT_XMM11*8)(ARG0)
movapd %xmm12, (RUSTRT_XMM12*8)(ARG0)
movapd %xmm13, (RUSTRT_XMM13*8)(ARG0)
movapd %xmm14, (RUSTRT_XMM14*8)(ARG0)
movapd %xmm15, (RUSTRT_XMM15*8)(ARG0)
#else
movapd %xmm0, (RUSTRT_XMM0*8)(ARG0)
movapd %xmm1, (RUSTRT_XMM1*8)(ARG0)
movapd %xmm2, (RUSTRT_XMM2*8)(ARG0)
movapd %xmm3, (RUSTRT_XMM3*8)(ARG0)
movapd %xmm4, (RUSTRT_XMM4*8)(ARG0)
movapd %xmm5, (RUSTRT_XMM5*8)(ARG0)
#endif
// Restore non-volatile integer registers:
// (including RSP)
@ -107,16 +131,40 @@ SWAP_REGISTERS:
mov (RUSTRT_R14*8)(ARG1), %r14
mov (RUSTRT_R15*8)(ARG1), %r15
#if defined(__MINGW32__) || defined(_WINDOWS)
mov (RUSTRT_RDI*8)(ARG1), %rdi
mov (RUSTRT_RSI*8)(ARG1), %rsi
// Restore stack range
mov (RUSTRT_ST1*8)(ARG1), %r8
mov %r8, %gs:0x08
mov (RUSTRT_ST2*8)(ARG1), %r9
mov %r9, %gs:0x10
#endif
// Restore 0th argument register:
mov (RUSTRT_ARG0*8)(ARG1), ARG0
// Restore non-volatile XMM registers:
#if defined(__MINGW32__) || defined(_WINDOWS)
movapd (RUSTRT_XMM6*8)(ARG1), %xmm6
movapd (RUSTRT_XMM7*8)(ARG1), %xmm7
movapd (RUSTRT_XMM8*8)(ARG1), %xmm8
movapd (RUSTRT_XMM9*8)(ARG1), %xmm9
movapd (RUSTRT_XMM10*8)(ARG1), %xmm10
movapd (RUSTRT_XMM11*8)(ARG1), %xmm11
movapd (RUSTRT_XMM12*8)(ARG1), %xmm12
movapd (RUSTRT_XMM13*8)(ARG1), %xmm13
movapd (RUSTRT_XMM14*8)(ARG1), %xmm14
movapd (RUSTRT_XMM15*8)(ARG1), %xmm15
#else
movapd (RUSTRT_XMM0*8)(ARG1), %xmm0
movapd (RUSTRT_XMM1*8)(ARG1), %xmm1
movapd (RUSTRT_XMM2*8)(ARG1), %xmm2
movapd (RUSTRT_XMM3*8)(ARG1), %xmm3
movapd (RUSTRT_XMM4*8)(ARG1), %xmm4
movapd (RUSTRT_XMM5*8)(ARG1), %xmm5
#endif
// Jump to the instruction pointer
// found in regs:

View File

@ -18,15 +18,33 @@
#define RUSTRT_R14 6
#define RUSTRT_R15 7
#define RUSTRT_IP 8
// Not used, just padding
#define RUSTRT_XXX 9
#define RUSTRT_XMM0 10
#define RUSTRT_XMM1 12
#define RUSTRT_XMM2 14
#define RUSTRT_XMM3 16
#define RUSTRT_XMM4 18
#define RUSTRT_XMM5 20
#define RUSTRT_MAX 22
#if defined(__MINGW32__) || defined(_WINDOWS)
#define RUSTRT_RDI 9
#define RUSTRT_RSI 10
#define RUSTRT_ST1 11
#define RUSTRT_ST2 12
#define RUSTRT_XMM6 14
#define RUSTRT_XMM7 16
#define RUSTRT_XMM8 18
#define RUSTRT_XMM9 20
#define RUSTRT_XMM10 22
#define RUSTRT_XMM11 24
#define RUSTRT_XMM12 26
#define RUSTRT_XMM13 28
#define RUSTRT_XMM14 30
#define RUSTRT_XMM15 32
#define RUSTRT_MAX 34
#else
// Not used, just padding
#define RUSTRT_XXX 9
#define RUSTRT_XMM0 10
#define RUSTRT_XMM1 12
#define RUSTRT_XMM2 14
#define RUSTRT_XMM3 16
#define RUSTRT_XMM4 18
#define RUSTRT_XMM5 20
#define RUSTRT_MAX 22
#endif
// ARG0 is the register in which the first argument goes.
// Naturally this depends on your operating system.