x86 support

ref #1
This commit is contained in:
edef 2015-04-16 12:50:15 -04:00
parent 52325b07c0
commit 418c53797e
6 changed files with 150 additions and 0 deletions

View File

@ -6,6 +6,7 @@
extern crate test; extern crate test;
use test::Bencher; use test::Bencher;
#[cfg(target_arch = "x86_64")]
#[bench] #[bench]
fn kernel_swap(b: &mut Bencher) { fn kernel_swap(b: &mut Bencher) {
b.iter(|| unsafe { b.iter(|| unsafe {
@ -17,3 +18,16 @@ fn kernel_swap(b: &mut Bencher) {
: "volatile"); : "volatile");
}); });
} }
#[cfg(target_arch = "x86")]
#[bench]
fn kernel_swap(b: &mut Bencher) {
b.iter(|| unsafe {
asm!("mov $$24, %eax\n\
int $$0x80"
:
:
: "eax"
: "volatile");
});
}

View File

@ -11,3 +11,7 @@ mod common;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
#[path = "x86_64/mod.rs"] #[path = "x86_64/mod.rs"]
mod imp; mod imp;
#[cfg(target_arch = "x86")]
#[path = "x86/mod.rs"]
mod imp;

View File

@ -0,0 +1 @@
--32

44
src/arch/x86/init.s Normal file
View 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
View 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
View 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: