Skip to content

Commit

Permalink
x86 support
Browse files Browse the repository at this point in the history
ref #1
  • Loading branch information
edef1c committed Apr 16, 2015
1 parent 52325b0 commit 418c537
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 0 deletions.
14 changes: 14 additions & 0 deletions benches/kernel_swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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");
});
}
4 changes: 4 additions & 0 deletions src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 change: 1 addition & 0 deletions src/arch/x86/.syntastic_asm_config
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--32
44 changes: 44 additions & 0 deletions src/arch/x86/init.s
Original file line number Diff line number Diff line change
@@ -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 changes: 47 additions & 0 deletions src/arch/x86/mod.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 40 additions & 0 deletions src/arch/x86/swap.s
Original file line number Diff line number Diff line change
@@ -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:

0 comments on commit 418c537

Please sign in to comment.