Skip to content

Commit 049e9ee

Browse files
committed
Add basic task switching
1 parent 9a7be3a commit 049e9ee

File tree

8 files changed

+275
-0
lines changed

8 files changed

+275
-0
lines changed

rost/core2/cast.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
use core2::intrinsics;
2+
3+
/**
4+
* Move a thing into the void
5+
*
6+
* The forget function will take ownership of the provided value but neglect
7+
* to run any required cleanup or memory-management operations on it. This
8+
* can be used for various acts of magick.
9+
*/
10+
#[inline]
11+
pub unsafe fn forget<T>(thing: T) { intrinsics::forget(thing); }

rost/core2/intrinsics.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
extern "rust-intrinsic" {
2+
/// Create an uninitialized value.
3+
pub fn uninit<T>() -> T;
4+
5+
/// Move a value out of scope without running drop glue.
6+
///
7+
/// `forget` is unsafe because the caller is responsible for
8+
/// ensuring the argument is deallocated already.
9+
pub fn forget<T>(_: T) -> ();
10+
pub fn transmute<T,U>(e: T) -> U;
11+
212
pub fn offset<T>(dst: *T, offset: int) -> *T;
313

414
pub fn volatile_load<T>(src: *T) -> T;

rost/core2/list.rs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
use core::option::{Option, Some, None};
2+
use core::iter::Iterator;
3+
use core::container::Container;
4+
5+
use core2::util;
6+
7+
type Link<T> = Option<~Node<T>>;
8+
struct Node<T> {
9+
value: T,
10+
next: Link<T>
11+
}
12+
13+
pub struct List<T> {
14+
head: Link<T>,
15+
length: uint
16+
}
17+
18+
/// Double-ended DList iterator
19+
//#[deriving(Clone)]
20+
pub struct Items<'a, T> {
21+
priv head: &'a Link<T>,
22+
priv length: uint
23+
}
24+
25+
macro_rules! count (
26+
() => (0);
27+
($head:expr $($tail:expr)*) => (
28+
1 + count!( $($tail)* )
29+
);
30+
)
31+
32+
macro_rules! link (
33+
() => (None);
34+
($head:expr $($tail:expr)*) => (
35+
Some(~Node { value: $head, next: link!( $($tail)* ) })
36+
);
37+
)
38+
39+
macro_rules! list (
40+
($($value:expr),*) => (
41+
List { head: link!( $($value)* ), length: count!( $($value)* ) }
42+
);
43+
44+
)
45+
46+
impl<T> Node<T> {
47+
fn new(value: T, next: Link<T>) -> Node<T> {
48+
Node { value: value, next: next }
49+
}
50+
}
51+
52+
impl<T> List<T> {
53+
pub fn new() -> List<T> {
54+
List { head: None, length: 0 }
55+
}
56+
57+
pub fn front<'a>(&'a self) -> Option<&'a T> {
58+
self.head.as_ref().map(|node| {
59+
&node.value
60+
})
61+
}
62+
63+
pub fn front_mut<'a>(&'a mut self) -> Option<&'a mut T> {
64+
self.head.as_mut().map(|node| {
65+
&mut node.value
66+
})
67+
}
68+
69+
pub fn add(&mut self, value: T) {
70+
let tail = util::replace(&mut self.head, None);
71+
self.head = Some(~Node::new(value, tail));
72+
self.length += 1;
73+
}
74+
75+
pub fn pop_front(&mut self) -> Option<T> {
76+
self.pop_front_node().map(|node| {
77+
node.value
78+
})
79+
}
80+
81+
fn pop_front_node(&mut self) -> Option<~Node<T>> {
82+
self.head.take().map(|mut front_node| {
83+
self.head = front_node.next.take();
84+
self.length -= 1;
85+
front_node
86+
})
87+
}
88+
89+
/// Provide a forward iterator
90+
#[inline]
91+
pub fn iter<'a>(&'a self) -> Items<'a, T> {
92+
Items { length: self.len(), head: &self.head }
93+
}
94+
}
95+
96+
impl<T> Container for List<T> {
97+
#[inline]
98+
fn is_empty(&self) -> bool {
99+
self.len() == 0
100+
}
101+
102+
#[inline]
103+
fn len(&self) -> uint {
104+
self.length
105+
}
106+
}
107+
108+
impl<'a, A> Iterator<&'a A> for Items<'a, A> {
109+
#[inline]
110+
fn next(&mut self) -> Option<&'a A> {
111+
self.head.as_ref().map(|head| {
112+
self.head = &head.next;
113+
self.length -= 1;
114+
&head.value
115+
})
116+
}
117+
118+
#[inline]
119+
fn size_hint(&self) -> (uint, Option<uint>) {
120+
(self.length, Some(self.length))
121+
}
122+
}

rost/core2/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
pub mod intrinsics;
22
pub mod ptr;
3+
pub mod cast;
4+
pub mod util;
5+
pub mod list;
36

47
pub mod global_heap;

rost/core2/util.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use core::ptr;
2+
3+
use core2::intrinsics;
4+
use core2::cast;
5+
6+
/**
7+
* Swap the values at two mutable locations of the same type, without
8+
* deinitialising or copying either one.
9+
*/
10+
#[inline]
11+
pub fn swap<T>(x: &mut T, y: &mut T) {
12+
unsafe {
13+
// Give ourselves some scratch space to work with
14+
let mut tmp: T = intrinsics::uninit();
15+
let t: *mut T = &mut tmp;
16+
17+
// Perform the swap, `&mut` pointers never alias
18+
let x_raw: *mut T = x;
19+
let y_raw: *mut T = y;
20+
ptr::copy_nonoverlapping_memory(t, x_raw as *T, 1);
21+
ptr::copy_nonoverlapping_memory(x, y_raw as *T, 1);
22+
ptr::copy_nonoverlapping_memory(y, t as *T, 1);
23+
24+
// y and t now point to the same thing, but we need to completely forget `tmp`
25+
// because it's no longer relevant.
26+
cast::forget(tmp);
27+
}
28+
}
29+
30+
/**
31+
* Replace the value at a mutable location with a new one, returning the old
32+
* value, without deinitialising or copying either one.
33+
*/
34+
#[inline]
35+
pub fn replace<T>(dest: &mut T, mut src: T) -> T {
36+
swap(dest, &mut src);
37+
src
38+
}

rost/exec/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
pub mod tasking;
12
pub mod elf;
23
pub mod syscalls;

rost/exec/tasking.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
use core::option::{Option, Some, None};
2+
use core::mem::transmute;
3+
4+
use core2::list::List;
5+
6+
use kernel::console;
7+
use memory::malloc::malloc;
8+
9+
pub struct Task {
10+
pid: uint,
11+
esp: u32,
12+
eip: u32
13+
}
14+
15+
static STACK_SIZE: u32 = 8 * 1024;
16+
17+
static mut next_pid: uint = 1;
18+
static mut tasks: List<Task> = List { head: None, length: 0 };
19+
20+
static mut current_task: Task = Task {
21+
pid: 0,
22+
esp: 0,
23+
eip: 0
24+
};
25+
26+
pub fn exec(f: fn()) {
27+
let eip: u32 = unsafe { transmute(f) };
28+
let stack: u32 = unsafe { transmute(malloc(STACK_SIZE)) };
29+
30+
let new_task = Task {
31+
pid: aquire_pid(),
32+
esp: stack + STACK_SIZE,
33+
eip: eip
34+
};
35+
36+
unsafe { tasks.add(new_task); }
37+
}
38+
39+
pub fn schedule() {
40+
let next_task = match unsafe { tasks.pop_front() } {
41+
None => return,
42+
Some(task) => task
43+
};
44+
45+
let last_task = unsafe {
46+
tasks.add(current_task);
47+
current_task = next_task;
48+
tasks.front_mut().get()
49+
};
50+
51+
unsafe { switch_to(last_task, &current_task); }
52+
}
53+
54+
#[inline(never)] // We can't inline because then the label "resume" would fail to be found
55+
unsafe fn switch_to(prev: &mut Task, next: &Task) {
56+
// These blocks are split in two because we need to guarantee that the store
57+
// into prev.esp and prev.eip happens BEFORE the jmp. Optimally we would like
58+
// to use "=m" as a constraint but rustc/llvm doesn't seem to like that.
59+
asm!(
60+
"cli;
61+
push %ebp;
62+
mov %esp, $0;
63+
lea resume, $1;"
64+
: "=r"(prev.esp), "=r"(prev.eip) ::: "volatile");
65+
asm!(
66+
"mov $0, %esp;
67+
sti;
68+
jmp *$1;
69+
resume:
70+
pop %ebp;"
71+
:: "m"(next.esp), "m"(next.eip) :: "volatile");
72+
}
73+
74+
fn aquire_pid() -> uint {
75+
unsafe {
76+
let pid = next_pid;
77+
next_pid += 1;
78+
pid
79+
}
80+
}

rost/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ mod core2;
2020

2121
mod util;
2222

23+
fn hello_again() {
24+
drivers::vga::puts("Hello again!\n");
25+
exec::tasking::schedule();
26+
loop {}
27+
}
28+
2329
#[no_mangle]
2430
pub extern fn kernel_main() {
2531
arch::gdt::init();
@@ -34,6 +40,10 @@ pub extern fn kernel_main() {
3440
drivers::vga::clear_screen();
3541
drivers::vga::puts("Hello world!\n");
3642

43+
exec::tasking::exec(hello_again);
44+
45+
exec::tasking::schedule();
46+
3747
extern { static _binary_hello_world_elf_start: u8; }
3848
let do_nothing = &_binary_hello_world_elf_start as *u8;
3949

0 commit comments

Comments
 (0)