Skip to content

Commit

Permalink
Merge #85 #86
Browse files Browse the repository at this point in the history
85: Remove raw-cpuid dependency and use rdrand intrinsics r=phil-opp a=64

This reduces my compile times from scratch from about 215s to 160s.

86: Update integration tests to use new testing framework r=phil-opp a=phil-opp

Use `cargo xtest` and `bootimage runner` instead of the old `bootimage test` for testing. See https://os.phil-opp.com/testing/ for more information on the approach.

Co-authored-by: Matt Taylor <mstaveleytaylor@gmail.com>
Co-authored-by: Philipp Oppermann <dev@phil-opp.com>
  • Loading branch information
3 people committed Jul 19, 2019
3 parents 1adc1dd + d21458f + 004ecc1 commit 35c2935
Show file tree
Hide file tree
Showing 14 changed files with 206 additions and 165 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ script:
- cargo build
- cargo test
- cargo build --features deny-warnings
- bootimage test --manifest-path testing/Cargo.toml
- cd testing && cargo xtest && cd ..
- cargo build --target i686-unknown-linux-gnu
- cargo build --target thumbv7em-none-eabihf

Expand Down
3 changes: 0 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ array-init = "0.0.4"
version = "0.2.2"
default-features = false

[target.'cfg(target_arch = "x86_64")'.dependencies]
raw-cpuid = "6.1.0"

[dependencies.ux]
default-features = false
version = "0.1.3"
Expand Down
3 changes: 2 additions & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,9 @@ steps:
- script: rustup component add llvm-tools-preview
displayName: "Add llvm-tools-preview Rustup Component"

- script: bootimage test --manifest-path testing/Cargo.toml
- script: cargo xtest
displayName: 'Integration Tests'
workingDirectory: 'testing'

- script: rustup component add rustfmt
displayName: 'Install Rustfmt'
Expand Down
83 changes: 48 additions & 35 deletions src/instructions/random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,64 +8,77 @@ pub struct RdRand(());
impl RdRand {
/// Creates Some(RdRand) if RDRAND is supported, None otherwise
pub fn new() -> Option<Self> {
let cpuid = raw_cpuid::CpuId::new();
let has_rdrand = match cpuid.get_feature_info() {
Some(finfo) => finfo.has_rdrand(),
None => false,
};

match has_rdrand {
true => Some(RdRand(())),
false => None,
// RDRAND support indicated by CPUID page 01h, ecx bit 30
// https://en.wikipedia.org/wiki/RdRand#Overview
let cpuid = unsafe { core::arch::x86_64::__cpuid(0x1) };
if cpuid.ecx & (1 << 30) != 0 {
Some(RdRand(()))
} else {
None
}
}

/// Uniformly sampled u64.
/// May fail in rare circumstances or heavy load.
#[inline]
pub fn get_u64(&self) -> Option<u64> {
let res: u64;
let ok: u8;
let mut res: u64 = 0;
unsafe {
asm!("rdrand %rax; setc $1;"
: "={rax}"(res) "=r"(ok)
:: "flags" : "volatile");
}
match ok {
1 => Some(res),
_ => None,
match core::arch::x86_64::_rdrand64_step(&mut res) {
1 => Some(res),
x => {
debug_assert_eq!(x, 0, "rdrand64 returned non-binary value");
None
}
}
}
}
/// Uniformly sampled u32.
/// May fail in rare circumstances or heavy load.
#[inline]
pub fn get_u32(&self) -> Option<u32> {
let res: u32;
let ok: u8;
let mut res: u32 = 0;
unsafe {
asm!("rdrand %eax; setc $1;"
: "={eax}"(res) "=r"(ok)
:: "flags" : "volatile");
}
match ok {
1 => Some(res),
_ => None,
match core::arch::x86_64::_rdrand32_step(&mut res) {
1 => Some(res),
x => {
debug_assert_eq!(x, 0, "rdrand32 returned non-binary value");
None
}
}
}
}
/// Uniformly sampled u16.
/// May fail in rare circumstances or heavy load.
#[inline]
pub fn get_u16(&self) -> Option<u16> {
let res: u16;
let ok: u8;
let mut res: u16 = 0;
unsafe {
asm!("rdrand %ax; setc $1;"
: "={ax}"(res) "=r"(ok)
:: "flags" : "volatile");
match core::arch::x86_64::_rdrand16_step(&mut res) {
1 => Some(res),
x => {
debug_assert_eq!(x, 0, "rdrand16 returned non-binary value");
None
}
}
}
match ok {
1 => Some(res),
_ => None,
}
}

#[cfg(all(test, target_arch = "x86_64"))]
mod tests {
use super::*;

#[test]
pub fn test_rdrand() {
let rand = RdRand::new();
if is_x86_feature_detected!("rdrand") {
let rand = rand.unwrap();
assert!(rand.get_u16().is_some());
assert!(rand.get_u32().is_some());
assert!(rand.get_u64().is_some());
} else {
assert!(rand.is_none());
}
}
}
5 changes: 5 additions & 0 deletions testing/.cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[build]
target = "x86_64-bare-metal.json"

[target.'cfg(target_os = "none")']
runner = "bootimage runner"
26 changes: 21 additions & 5 deletions testing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,33 @@ version = "0.1.0"
authors = ["Philipp Oppermann <dev@phil-opp.com>"]
edition = "2018"

[[test]]
name = "breakpoint_exception"
harness = false

[[test]]
name = "port_read_write"
harness = false

[[test]]
name = "double_fault_stack_overflow"
harness = false

[dependencies]
bootloader = "0.5.3"
uart_16550 = "0.1.0"
spin = "0.4.8"
bootloader = "0.6.4"
uart_16550 = "0.2.0"
spin = "0.5.0"

[dependencies.x86_64]
path = ".."

[dependencies.lazy_static]
version = "1.0"
version = "1.3.0"
features = ["spin_no_std"]

[package.metadata.bootimage]
default-target = "x86_64-bare-metal.json"
test-args = [
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-serial", "stdio",
"-display", "none"
]
test-success-exit-code = 33
34 changes: 0 additions & 34 deletions testing/src/bin/test-basic.rs

This file was deleted.

57 changes: 48 additions & 9 deletions testing/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,56 @@
#![cfg_attr(test, no_main)]
#![feature(custom_test_frameworks)]
#![test_runner(crate::test_runner)]
#![reexport_test_harness_main = "test_main"]
#![no_std]

extern crate spin;
extern crate uart_16550;
extern crate x86_64;
#[macro_use]
extern crate lazy_static;
use core::panic::PanicInfo;

#[macro_use]
pub mod serial;
pub mod gdt;
mod tests;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum QemuExitCode {
Success = 0x10,
Failed = 0x11,
}

pub fn exit_qemu(exit_code: QemuExitCode) {
use x86_64::instructions::port::Port;

unsafe {
let mut port = Port::new(0xf4);
port.write(exit_code as u32);
}
}

pub fn test_runner(tests: &[&dyn Fn()]) {
serial_println!("Running {} tests", tests.len());
for test in tests {
test();
}
exit_qemu(QemuExitCode::Success);
}

use x86_64::instructions::port::Port;
pub fn test_panic_handler(info: &PanicInfo) -> ! {
serial_println!("[failed]\n");
serial_println!("Error: {}\n", info);
exit_qemu(QemuExitCode::Failed);
loop {}
}

#[cfg(test)]
#[no_mangle]
pub extern "C" fn _start() -> ! {
test_main();
loop {}
}

pub unsafe fn exit_qemu() {
let mut port = Port::<u32>::new(0xf4);
port.write(0);
#[cfg(test)]
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
test_panic_handler(info)
}
3 changes: 2 additions & 1 deletion testing/src/serial.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use lazy_static::lazy_static;
use spin::Mutex;
use uart_16550::SerialPort;

lazy_static! {
pub static ref SERIAL1: Mutex<SerialPort> = {
let mut serial_port = SerialPort::new(0x3F8);
let mut serial_port = unsafe { SerialPort::new(0x3F8) };
serial_port.init();
Mutex::new(serial_port)
};
Expand Down
6 changes: 6 additions & 0 deletions testing/src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#[test_case]
fn example_test() {
serial_print!("example_test... ");
assert_eq!(0, 0);
serial_println!("[ok]");
}
27 changes: 27 additions & 0 deletions testing/tests/basic_boot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#![no_std]
#![no_main]
#![feature(custom_test_frameworks)]
#![reexport_test_harness_main = "test_main"]
#![test_runner(testing::test_runner)]

use core::panic::PanicInfo;
use testing::{serial_print, serial_println};

#[no_mangle] // don't mangle the name of this function
pub extern "C" fn _start() -> ! {
test_main();

loop {}
}

#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
testing::test_panic_handler(info)
}

#[test_case]
fn basic_boot() {
serial_print!("basic_boot... ");
assert_eq!(0, 0);
serial_println!("[ok]");
}
Loading

0 comments on commit 35c2935

Please sign in to comment.