forked from M-Labs/libfringe
parent
52325b07c0
commit
418c53797e
@ -6,6 +6,7 @@
|
||||
extern crate test;
|
||||
use test::Bencher;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[bench]
|
||||
fn kernel_swap(b: &mut Bencher) {
|
||||
b.iter(|| unsafe {
|
||||
@ -17,3 +18,16 @@ fn kernel_swap(b: &mut Bencher) {
|
||||
: "volatile");
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
#[bench]
|
||||
fn kernel_swap(b: &mut Bencher) {
|
||||
b.iter(|| unsafe {
|
||||
asm!("mov $$24, %eax\n\
|
||||
int $$0x80"
|
||||
:
|
||||
:
|
||||
: "eax"
|
||||
: "volatile");
|
||||
});
|
||||
}
|
||||
|
@ -11,3 +11,7 @@ mod common;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[path = "x86_64/mod.rs"]
|
||||
mod imp;
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
#[path = "x86/mod.rs"]
|
||||
mod imp;
|
||||
|
1
src/arch/x86/.syntastic_asm_config
Normal file
1
src/arch/x86/.syntastic_asm_config
Normal file
@ -0,0 +1 @@
|
||||
--32
|
44
src/arch/x86/init.s
Normal file
44
src/arch/x86/init.s
Normal file
@ -0,0 +1,44 @@
|
||||
// This file is part of libfringe, a low-level green threading library.
|
||||
// Copyright (c) 2015, edef <edef@edef.eu>
|
||||
// See the LICENSE file included in this distribution.
|
||||
|
||||
//! initialise a new context
|
||||
//! arguments:
|
||||
//! * eax: stack pointer
|
||||
//! * ebx: function pointer
|
||||
//! * ecx: data pointer
|
||||
//! * edx: stack limit
|
||||
//!
|
||||
//! return values:
|
||||
//! * eax: new stack pointer
|
||||
|
||||
// switch to the fresh stack
|
||||
xchg %esp, %eax
|
||||
|
||||
// save the data pointer, function pointer, and stack limit, respectively
|
||||
pushl %ecx
|
||||
pushl %ebx
|
||||
pushl %edx
|
||||
|
||||
// save the return address, control flow continues at label 1
|
||||
call 1f
|
||||
// we arrive here once this context is reactivated (see swap.s)
|
||||
|
||||
// restore the stack limit, data pointer, and function pointer, respectively
|
||||
// TODO: this stack limit location is specific to Linux/FreeBSD.
|
||||
popl %gs:0x30
|
||||
popl %eax
|
||||
|
||||
// initialise the frame pointer
|
||||
movl $$0, %ebp
|
||||
|
||||
// call the function pointer with the data pointer (top of the stack is the first argument)
|
||||
call *%eax
|
||||
|
||||
// crash if it ever returns
|
||||
ud2
|
||||
|
||||
1:
|
||||
// save our neatly-setup new stack
|
||||
xchg %esp, %eax
|
||||
// back into Rust-land we go
|
47
src/arch/x86/mod.rs
Normal file
47
src/arch/x86/mod.rs
Normal file
@ -0,0 +1,47 @@
|
||||
// This file is part of libfringe, a low-level green threading library.
|
||||
// Copyright (c) 2015, edef <edef@edef.eu>
|
||||
// See the LICENSE file included in this distribution.
|
||||
use core::prelude::*;
|
||||
|
||||
use stack::Stack;
|
||||
use super::common::{push, rust_trampoline};
|
||||
|
||||
pub const STACK_ALIGN: usize = 16;
|
||||
|
||||
#[allow(raw_pointer_derive)]
|
||||
#[derive(Debug)]
|
||||
pub struct Registers {
|
||||
esp: *mut usize
|
||||
}
|
||||
|
||||
impl Registers {
|
||||
#[inline]
|
||||
pub unsafe fn new<S, F>(stack: &mut S, f: F) -> Registers where S: Stack, F: FnOnce() {
|
||||
let sp_limit = stack.limit();
|
||||
let mut sp = stack.top() as *mut usize;
|
||||
let f_ptr = push(&mut sp, f);
|
||||
|
||||
asm!(include_str!("init.s")
|
||||
: "={eax}"(sp)
|
||||
: "{eax}" (sp),
|
||||
"{ebx}" (rust_trampoline::<F>),
|
||||
"{ecx}" (f_ptr),
|
||||
"{edx}" (sp_limit)
|
||||
:
|
||||
: "volatile");
|
||||
|
||||
Registers { esp: sp }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn swap(&mut self) {
|
||||
asm!(include_str!("swap.s")
|
||||
:
|
||||
: "{eax}" (&mut self.esp)
|
||||
: "eax", "ebx", "ecx", "edx", "esi", "edi", //"ebp", "esp",
|
||||
"mmx0", "mmx1", "mmx2", "mmx3", "mmx4", "mmx5", "mmx6", "mmx7",
|
||||
"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
|
||||
"cc"
|
||||
: "volatile");
|
||||
}
|
||||
}
|
40
src/arch/x86/swap.s
Normal file
40
src/arch/x86/swap.s
Normal file
@ -0,0 +1,40 @@
|
||||
// This file is part of libfringe, a low-level green threading library.
|
||||
// Copyright (c) 2015, edef <edef@edef.eu>
|
||||
// See the LICENSE file included in this distribution.
|
||||
|
||||
//! switch to a new context
|
||||
//! arguments:
|
||||
//! * eax: stack pointer pointer
|
||||
|
||||
// save the Rust stack limit and the frame pointer, respectively
|
||||
// TODO: this stack limit location is specific to Linux/FreeBSD.
|
||||
pushl %gs:0x30
|
||||
pushl %ebp
|
||||
|
||||
// save the return address to the stack, control flow continues at label 1
|
||||
call 1f
|
||||
// we arrive here once this context is reactivated
|
||||
|
||||
// restore the frame pointer and the Rust stack limit, respectively
|
||||
popl %ebp
|
||||
// TODO: this stack limit location is specific to Linux/FreeBSD.
|
||||
popl %gs:0x30
|
||||
|
||||
// and we merrily go on our way, back into Rust-land
|
||||
jmp 2f
|
||||
|
||||
1:
|
||||
// retrieve the new stack pointer
|
||||
movl (%eax), %ebx
|
||||
// save the old stack pointer
|
||||
movl %esp, (%eax)
|
||||
// switch to the new stack pointer
|
||||
movl %ebx, %esp
|
||||
|
||||
// jump into the new context (return to the call point)
|
||||
// doing this instead of a straight `ret` is 8ns slower,
|
||||
// presumably because the branch predictor tries to be clever about it
|
||||
popl %eax
|
||||
jmpl *%eax
|
||||
|
||||
2:
|
Loading…
Reference in New Issue
Block a user