1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
| #![no_std]
#![no_main]
#![feature(custom_test_frameworks)]
#![test_runner(rust_kernel::test_runner)]
#![reexport_test_harness_main = "test_main"]
use bootloader::{BootInfo, entry_point};
use core::panic::PanicInfo;
use core::sync::atomic::Ordering;
use rust_kernel::errno::Errno;
use rust_kernel::interrupts::TICKS;
use rust_kernel::memory::{self, BootInfoFrameAllocator, USER_START};
use rust_kernel::process::{self, ExitStatus};
use rust_kernel::{allocator, elf, fs, syscall, user_programs};
use x86_64::VirtAddr;
entry_point!(main);
fn main(boot_info: &'static BootInfo) -> ! {
rust_kernel::init();
let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset);
let mut mapper = unsafe { memory::init(phys_mem_offset) };
let mut frame_allocator = unsafe { BootInfoFrameAllocator::init(&boot_info.memory_map) };
allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap initialization failed");
memory::init_frame_allocator(frame_allocator);
fs::init();
test_main();
rust_kernel::hlt_loop();
}
#[test_case]
fn hello_program_passes_its_syscall_checks() {
let p = process::spawn("hello", user_programs::HELLO).expect("spawn hello");
assert_eq!(process::wait(&p), ExitStatus::Exited(0));
let inode = fs::lookup("/tmp/note.txt").expect("hello's file is missing");
assert_eq!(inode.size(), 19);
}
#[test_case]
fn kernel_memory_access_kills_only_the_process() {
let p = process::spawn("evil", user_programs::EVIL).expect("spawn evil");
assert_eq!(process::wait(&p), ExitStatus::Killed("page fault"));
}
#[test_case]
fn spinning_process_is_preempted() {
let p = process::spawn("spin", user_programs::SPIN).expect("spawn spin");
let start = TICKS.load(Ordering::Relaxed);
let mut samples_while_spinning = 0;
while p.status().is_none() {
if TICKS.load(Ordering::Relaxed) > start + 3 {
samples_while_spinning += 1;
}
assert!(TICKS.load(Ordering::Relaxed) < start + 18 * 30, "spin didn't finish");
core::hint::spin_loop();
}
assert_eq!(p.status(), Some(ExitStatus::Exited(0)));
assert!(samples_while_spinning > 0, "never ran while spin was running");
}
#[test_case]
fn elf_loader_rejects_garbage() {
assert_eq!(elf::check(&[b'x'; 128]), Err(elf::ElfError::NotElf));
assert_eq!(elf::check(b"\x7fELF"), Err(elf::ElfError::TooShort));
let entry = elf::check(user_programs::HELLO).expect("hello should parse");
assert!(entry >= USER_START);
assert!(elf::check(&user_programs::HELLO[..70]).is_err());
}
#[test_case]
fn user_pointers_are_validated() {
assert_eq!(syscall::user_slice(0x20_0000, 16).err(), Some(Errno::EFAULT));
assert_eq!(syscall::user_slice(USER_START, 16).err(), Some(Errno::EFAULT));
assert_eq!(syscall::user_slice(u64::MAX - 4, 16).err(), Some(Errno::EFAULT));
assert!(!memory::user_range_ok(USER_START - 8, 16, false));
}
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
rust_kernel::test_panic_handler(info)
}
|