Skip to content

Commit 442f4a5

Browse files
committed
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.
1 parent 63e53b8 commit 442f4a5

File tree

3 files changed

+106
-16
lines changed

3 files changed

+106
-16
lines changed

src/libstd/rt/context.rs

+31-7
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ impl Context {
4747

4848
let fp: *c_void = task_start_wrapper as *c_void;
4949
let argp: *c_void = unsafe { transmute::<&~fn(), *c_void>(&*start) };
50+
let stack_base: *uint = stack.start();
5051
let sp: *uint = stack.end();
5152
let sp: *mut uint = unsafe { transmute_mut_unsafe(sp) };
5253
// Save and then immediately load the current context,
@@ -56,7 +57,7 @@ impl Context {
5657
swap_registers(transmute_mut_region(&mut *regs), transmute_region(&*regs));
5758
};
5859

59-
initialize_call_frame(&mut *regs, fp, argp, sp);
60+
initialize_call_frame(&mut *regs, fp, argp, sp, stack_base);
6061

6162
return Context {
6263
start: Some(start),
@@ -107,7 +108,8 @@ fn new_regs() -> ~Registers {
107108
}
108109

109110
#[cfg(target_arch = "x86")]
110-
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
111+
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
112+
sp: *mut uint, _stack_base: *uint) {
111113

112114
let sp = align_down(sp);
113115
let sp = mut_offset(sp, -4);
@@ -123,21 +125,41 @@ fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp:
123125
regs.ebp = 0;
124126
}
125127

126-
#[cfg(target_arch = "x86_64")]
128+
#[cfg(windows, target_arch = "x86_64")]
129+
type Registers = [uint, ..34];
130+
#[cfg(not(windows), target_arch = "x86_64")]
127131
type Registers = [uint, ..22];
128132

129-
#[cfg(target_arch = "x86_64")]
133+
#[cfg(windows, target_arch = "x86_64")]
134+
fn new_regs() -> ~Registers { ~([0, .. 34]) }
135+
#[cfg(not(windows), target_arch = "x86_64")]
130136
fn new_regs() -> ~Registers { ~([0, .. 22]) }
131137

132138
#[cfg(target_arch = "x86_64")]
133-
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
139+
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
140+
sp: *mut uint, stack_base: *uint) {
134141

135142
// Redefinitions from regs.h
136143
static RUSTRT_ARG0: uint = 3;
137144
static RUSTRT_RSP: uint = 1;
138145
static RUSTRT_IP: uint = 8;
139146
static RUSTRT_RBP: uint = 2;
140147

148+
#[cfg(windows)]
149+
fn initialize_tib(regs: &mut Registers, sp: *mut uint, stack_base: *uint) {
150+
// Redefinitions from regs.h
151+
static RUSTRT_ST1: uint = 11; // stack bottom
152+
static RUSTRT_ST2: uint = 12; // stack top
153+
regs[RUSTRT_ST1] = sp as uint;
154+
regs[RUSTRT_ST2] = stack_base as uint;
155+
}
156+
#[cfg(not(windows))]
157+
fn initialize_tib(_: &mut Registers, _: *mut uint, _: *uint) {
158+
}
159+
160+
// Win64 manages stack range at TIB: %gs:0x08 (top) and %gs:0x10 (bottom)
161+
initialize_tib(regs, sp, stack_base);
162+
141163
let sp = align_down(sp);
142164
let sp = mut_offset(sp, -1);
143165

@@ -164,7 +186,8 @@ type Registers = [uint, ..32];
164186
fn new_regs() -> ~Registers { ~([0, .. 32]) }
165187

166188
#[cfg(target_arch = "arm")]
167-
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
189+
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
190+
sp: *mut uint, _stack_base: *uint) {
168191
let sp = align_down(sp);
169192
// sp of arm eabi is 8-byte aligned
170193
let sp = mut_offset(sp, -2);
@@ -184,7 +207,8 @@ type Registers = [uint, ..32];
184207
fn new_regs() -> ~Registers { ~([0, .. 32]) }
185208

186209
#[cfg(target_arch = "mips")]
187-
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
210+
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
211+
sp: *mut uint, _stack_base: *uint) {
188212
let sp = align_down(sp);
189213
// sp of mips o32 is 8-byte aligned
190214
let sp = mut_offset(sp, -2);

src/rt/arch/x86_64/_context.S

+48
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,40 @@ SWAP_REGISTERS:
8686
mov %r14, (RUSTRT_R14*8)(ARG0)
8787
mov %r15, (RUSTRT_R15*8)(ARG0)
8888

89+
#if defined(__MINGW32__) || defined(_WINDOWS)
90+
mov %rdi, (RUSTRT_RDI*8)(ARG0)
91+
mov %rsi, (RUSTRT_RSI*8)(ARG0)
92+
93+
// Save stack range
94+
mov %gs:0x08, %r8
95+
mov %r8, (RUSTRT_ST1*8)(ARG0)
96+
mov %gs:0x10, %r9
97+
mov %r9, (RUSTRT_ST2*8)(ARG0)
98+
#endif
99+
89100
// Save 0th argument register:
90101
mov ARG0, (RUSTRT_ARG0*8)(ARG0)
91102

92103
// Save non-volatile XMM registers:
104+
#if defined(__MINGW32__) || defined(_WINDOWS)
105+
movapd %xmm6, (RUSTRT_XMM6*8)(ARG0)
106+
movapd %xmm7, (RUSTRT_XMM7*8)(ARG0)
107+
movapd %xmm8, (RUSTRT_XMM8*8)(ARG0)
108+
movapd %xmm9, (RUSTRT_XMM9*8)(ARG0)
109+
movapd %xmm10, (RUSTRT_XMM10*8)(ARG0)
110+
movapd %xmm11, (RUSTRT_XMM11*8)(ARG0)
111+
movapd %xmm12, (RUSTRT_XMM12*8)(ARG0)
112+
movapd %xmm13, (RUSTRT_XMM13*8)(ARG0)
113+
movapd %xmm14, (RUSTRT_XMM14*8)(ARG0)
114+
movapd %xmm15, (RUSTRT_XMM15*8)(ARG0)
115+
#else
93116
movapd %xmm0, (RUSTRT_XMM0*8)(ARG0)
94117
movapd %xmm1, (RUSTRT_XMM1*8)(ARG0)
95118
movapd %xmm2, (RUSTRT_XMM2*8)(ARG0)
96119
movapd %xmm3, (RUSTRT_XMM3*8)(ARG0)
97120
movapd %xmm4, (RUSTRT_XMM4*8)(ARG0)
98121
movapd %xmm5, (RUSTRT_XMM5*8)(ARG0)
122+
#endif
99123

100124
// Restore non-volatile integer registers:
101125
// (including RSP)
@@ -107,16 +131,40 @@ SWAP_REGISTERS:
107131
mov (RUSTRT_R14*8)(ARG1), %r14
108132
mov (RUSTRT_R15*8)(ARG1), %r15
109133

134+
#if defined(__MINGW32__) || defined(_WINDOWS)
135+
mov (RUSTRT_RDI*8)(ARG1), %rdi
136+
mov (RUSTRT_RSI*8)(ARG1), %rsi
137+
138+
// Restore stack range
139+
mov (RUSTRT_ST1*8)(ARG1), %r8
140+
mov %r8, %gs:0x08
141+
mov (RUSTRT_ST2*8)(ARG1), %r9
142+
mov %r9, %gs:0x10
143+
#endif
144+
110145
// Restore 0th argument register:
111146
mov (RUSTRT_ARG0*8)(ARG1), ARG0
112147

113148
// Restore non-volatile XMM registers:
149+
#if defined(__MINGW32__) || defined(_WINDOWS)
150+
movapd (RUSTRT_XMM6*8)(ARG1), %xmm6
151+
movapd (RUSTRT_XMM7*8)(ARG1), %xmm7
152+
movapd (RUSTRT_XMM8*8)(ARG1), %xmm8
153+
movapd (RUSTRT_XMM9*8)(ARG1), %xmm9
154+
movapd (RUSTRT_XMM10*8)(ARG1), %xmm10
155+
movapd (RUSTRT_XMM11*8)(ARG1), %xmm11
156+
movapd (RUSTRT_XMM12*8)(ARG1), %xmm12
157+
movapd (RUSTRT_XMM13*8)(ARG1), %xmm13
158+
movapd (RUSTRT_XMM14*8)(ARG1), %xmm14
159+
movapd (RUSTRT_XMM15*8)(ARG1), %xmm15
160+
#else
114161
movapd (RUSTRT_XMM0*8)(ARG1), %xmm0
115162
movapd (RUSTRT_XMM1*8)(ARG1), %xmm1
116163
movapd (RUSTRT_XMM2*8)(ARG1), %xmm2
117164
movapd (RUSTRT_XMM3*8)(ARG1), %xmm3
118165
movapd (RUSTRT_XMM4*8)(ARG1), %xmm4
119166
movapd (RUSTRT_XMM5*8)(ARG1), %xmm5
167+
#endif
120168

121169
// Jump to the instruction pointer
122170
// found in regs:

src/rt/arch/x86_64/regs.h

+27-9
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,33 @@
1818
#define RUSTRT_R14 6
1919
#define RUSTRT_R15 7
2020
#define RUSTRT_IP 8
21-
// Not used, just padding
22-
#define RUSTRT_XXX 9
23-
#define RUSTRT_XMM0 10
24-
#define RUSTRT_XMM1 12
25-
#define RUSTRT_XMM2 14
26-
#define RUSTRT_XMM3 16
27-
#define RUSTRT_XMM4 18
28-
#define RUSTRT_XMM5 20
29-
#define RUSTRT_MAX 22
21+
#if defined(__MINGW32__) || defined(_WINDOWS)
22+
#define RUSTRT_RDI 9
23+
#define RUSTRT_RSI 10
24+
#define RUSTRT_ST1 11
25+
#define RUSTRT_ST2 12
26+
#define RUSTRT_XMM6 14
27+
#define RUSTRT_XMM7 16
28+
#define RUSTRT_XMM8 18
29+
#define RUSTRT_XMM9 20
30+
#define RUSTRT_XMM10 22
31+
#define RUSTRT_XMM11 24
32+
#define RUSTRT_XMM12 26
33+
#define RUSTRT_XMM13 28
34+
#define RUSTRT_XMM14 30
35+
#define RUSTRT_XMM15 32
36+
#define RUSTRT_MAX 34
37+
#else
38+
// Not used, just padding
39+
#define RUSTRT_XXX 9
40+
#define RUSTRT_XMM0 10
41+
#define RUSTRT_XMM1 12
42+
#define RUSTRT_XMM2 14
43+
#define RUSTRT_XMM3 16
44+
#define RUSTRT_XMM4 18
45+
#define RUSTRT_XMM5 20
46+
#define RUSTRT_MAX 22
47+
#endif
3048

3149
// ARG0 is the register in which the first argument goes.
3250
// Naturally this depends on your operating system.

0 commit comments

Comments
 (0)