about summary refs log tree commit diff
diff options
context:
space:
mode:
authorklutzy <klutzytheklutzy@gmail.com>2013-08-26 22:01:55 +0900
committerklutzy <klutzytheklutzy@gmail.com>2013-08-26 22:16:54 +0900
commit442f4a5f2ca6f7f4082c09968e0fd83601a50d2a (patch)
tree9ad67e23fcc2987c6500414796a36b4c454e7499
parent63e53b8af2f37f9eb8eda0087b02f8deba252c2f (diff)
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.
-rw-r--r--src/libstd/rt/context.rs38
-rw-r--r--src/rt/arch/x86_64/_context.S48
-rw-r--r--src/rt/arch/x86_64/regs.h36
3 files changed, 106 insertions, 16 deletions
diff --git a/src/libstd/rt/context.rs b/src/libstd/rt/context.rs
index 5aaddc68383..476554bf7f7 100644
--- a/src/libstd/rt/context.rs
+++ b/src/libstd/rt/context.rs
@@ -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);
diff --git a/src/rt/arch/x86_64/_context.S b/src/rt/arch/x86_64/_context.S
index a8af27e3e4f..857fe91c914 100644
--- a/src/rt/arch/x86_64/_context.S
+++ b/src/rt/arch/x86_64/_context.S
@@ -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:
diff --git a/src/rt/arch/x86_64/regs.h b/src/rt/arch/x86_64/regs.h
index 1aca452df10..cff47ac378a 100644
--- a/src/rt/arch/x86_64/regs.h
+++ b/src/rt/arch/x86_64/regs.h
@@ -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.