From 418c53797e69426ba11822eda6094a1304f166bb Mon Sep 17 00:00:00 2001 From: edef Date: Thu, 16 Apr 2015 12:50:15 -0400 Subject: [PATCH] x86 support ref #1 --- benches/kernel_swap.rs | 14 +++++++++ src/arch/mod.rs | 4 +++ src/arch/x86/.syntastic_asm_config | 1 + src/arch/x86/init.s | 44 ++++++++++++++++++++++++++++ src/arch/x86/mod.rs | 47 ++++++++++++++++++++++++++++++ src/arch/x86/swap.s | 40 +++++++++++++++++++++++++ 6 files changed, 150 insertions(+) create mode 100644 src/arch/x86/.syntastic_asm_config create mode 100644 src/arch/x86/init.s create mode 100644 src/arch/x86/mod.rs create mode 100644 src/arch/x86/swap.s diff --git a/benches/kernel_swap.rs b/benches/kernel_swap.rs index b52fce37..b52b84c7 100644 --- a/benches/kernel_swap.rs +++ b/benches/kernel_swap.rs @@ -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"); + }); +} diff --git a/src/arch/mod.rs b/src/arch/mod.rs index 894a0189..7baca429 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -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; diff --git a/src/arch/x86/.syntastic_asm_config b/src/arch/x86/.syntastic_asm_config new file mode 100644 index 00000000..8c7133a9 --- /dev/null +++ b/src/arch/x86/.syntastic_asm_config @@ -0,0 +1 @@ +--32 diff --git a/src/arch/x86/init.s b/src/arch/x86/init.s new file mode 100644 index 00000000..e10d4be4 --- /dev/null +++ b/src/arch/x86/init.s @@ -0,0 +1,44 @@ +// This file is part of libfringe, a low-level green threading library. +// Copyright (c) 2015, edef +// 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 diff --git a/src/arch/x86/mod.rs b/src/arch/x86/mod.rs new file mode 100644 index 00000000..7c34191c --- /dev/null +++ b/src/arch/x86/mod.rs @@ -0,0 +1,47 @@ +// This file is part of libfringe, a low-level green threading library. +// Copyright (c) 2015, edef +// 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(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::), + "{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"); + } +} diff --git a/src/arch/x86/swap.s b/src/arch/x86/swap.s new file mode 100644 index 00000000..bee11404 --- /dev/null +++ b/src/arch/x86/swap.s @@ -0,0 +1,40 @@ +// This file is part of libfringe, a low-level green threading library. +// Copyright (c) 2015, edef +// 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: